Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

feat(orderBy): Add null and undefined at the end of the sorted list #16376

Closed
wants to merge 1 commit into from
Closed

feat(orderBy): Add null and undefined at the end of the sorted list #16376

wants to merge 1 commit into from

Conversation

frederikprijck
Copy link
Contributor

@frederikprijck frederikprijck commented Dec 17, 2017

What is the current behavior? (You can also link to an open issue here)
null values are sorted using type string resulting in a string comparison.

What is the new behavior (if this is a feature change)?
null and undefined values are, explicitly, being put at the end of the sorted list.`

Does this PR introduce a breaking change?
Yes

Please check if the PR fulfills these requirements

  • The commit message follows our guidelines
  • Fix/Feature: Docs have been added/updated
  • Fix/Feature: Tests have been added; existing tests pass

Other information:

This fixes: #15294

@frederikprijck
Copy link
Contributor Author

frederikprijck commented Dec 18, 2017

It looks like travis is failing coz of another commit message:

Need a colon after the closing parenthesis: ):
Commit message was:
style(css) separate selectors and declarations by new lines

But it looks like this is a very old commit. I'm somewhat confused 😕

@Narretz
Copy link
Contributor

Narretz commented Dec 18, 2017

Did you fork this branch a while back, possibly in July? Because the commit that is throwing the error was merged back in July this year.

Although the commit message checker should only check commits that belong to the PR.

@frederikprijck
Copy link
Contributor Author

@Narretz I did fork it awhile back idd. Would rebasing solve it (I doubt) ?

@gkalpak
Copy link
Member

gkalpak commented Dec 18, 2017

Rebasing should solve it (it is a bug if it doesn't).

@frederikprijck
Copy link
Contributor Author

@gkalpak @Narretz Okay, I've rebased it!

Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much needed change 👍
A couple of minor coments and should be good to go 🎉

@@ -74,11 +75,13 @@
*
* The default, built-in comparator should be sufficient for most usecases. In short, it compares
* numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
* using their index in the original collection, and sorts values of different types by type.
* using their index in the original collection, sorts values of different types by type and puts `undefined` and `null` values at the end of the sorted list.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap lines at 100 chars (everywhere) 🙏

@@ -309,6 +309,14 @@ describe('Filter: orderBy', function() {

expect(orderBy(items, expr)).toEqual(sorted);
});

it('should treat `null` values bigger then all other values except `undefined`', function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change to something like:

should consider null and undefined greater than any other value

* **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e.
* `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to
* other values.
* **Note:** `null` and `undefined` values are always treated bigger than any other value, where `undefined` is treated bigger than `null`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change it to something like:

For the purpose of sorting, null and undefined are considered "greater than" any other value (with undefined "greater than" null). This effectively means that null and undefined values end up at the end of a list sorted in ascending order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also add another note about null values using 'null' as their type (to more easily distinguish them from objects).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's fine. I would just add another note here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* 1. If the compared values are of different types, compare the types themselves alphabetically.
* 1. If the compared values are of different types:
* - Explicitly check for `null` and `undefined` values and treat them bigger as any other value.
* - If both values are different from `null` and `undefined`, compare the types themselves alphabetically.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change the bullets to make the relative order of null vs undefined more explicit:

  • If one of the values is undefined, consider it "greater than" the other.
  • Else if one of the values is null, consider it "greater than" the other.
  • Else compare the types themselves aplhabetically.

var expr = null;
var sorted = [false, 999, {}, 'z', null, undefined];

expect(orderBy(items, expr)).toEqual(sorted);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure, could you also add an expectation for sorting in descending order?

@gkalpak
Copy link
Member

gkalpak commented Dec 19, 2017

BTW, we need a BREAKING CHANGE notice in the commit message.

@frederikprijck
Copy link
Contributor Author

@gkalpak I'll add the BC notice in the commit message and squash the other commits.

@frederikprijck
Copy link
Contributor Author

I've added the BC notice, unsure if it's enough or needs an example.

Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting there 😉

* other values.
* **Note:** For the purpose of sorting, null and undefined are considered "greater than"
* any other value (with undefined "greater than" null). This effectively means that null
* and undefined values end up at the end of a list sorted in ascending order.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent subsequent lines as above.

* **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e.
* `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to
* other values.
* **Note:** For the purpose of sorting, null and undefined are considered "greater than"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap "null" and "undefined" in backticks (as in other places).

@@ -690,7 +695,7 @@ function orderByFilter($parse) {
result = value1 < value2 ? -1 : 1;
}
} else {
result = type1 < type2 ? -1 : 1;
result = (type1 === 'undefined') ? 1 : (type2 === 'undefined') ? -1 : (type1 === 'null') ? 1 : (type2 === 'null') ? -1 : (type1 < type2) ? -1 : 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is still >100 chars long 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using the following instead of wrapping it at 100 :

result = (type1 === 'undefined') ? 1 :
        (type2 === 'undefined') ? -1 :
        (type1 === 'null') ? 1 :
        (type2 === 'null') ? -1 :
        (type1 < type2) ? -1 : 1;

I think it improves readability ...

Previously, `null` values where sorted using type `string` resulting in a string
comparison. `undefined` values where compared to other values by type and were
usually considered greater than other values (since their type happens to start
with a `u`), but this was coincidental.

This commit ensures that `null` and `undefined ` values are explicitly
considered greater than other values (with `undefined` > `null`) and will
effectively be put at the end of the sorted list (for ascending order sorting).

Closes #15294

BREAKING CHANGE:

When using `orderBy` to sort arrays containing `null` values, the `null` values
will be considered "greater than" all other values, except for `undefined`.
Previously, they were sorted as strings. This will result in different (but more
intuitive) sorting order.

Before:
```js
orderByFilter(['a', undefined, 'o', null, 'z']);
//--> 'a', null, 'o', 'z', undefined
```

After:
```js
orderByFilter(['a', undefined, 'o', null, 'z']);
//--> 'a', 'o', 'z', null, undefined
```
@Narretz
Copy link
Contributor

Narretz commented Jan 10, 2018

@gkalpak If you're happy with this, I will merge it

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request - 'natural' treatment of null strings in default orderBy comparator
4 participants