fix(orderBy): guarantee stable sort

If a user-provided comparator fails to differentiate between two items, fall
back to the built-in comparator (using the tie-breaker predicate).

Fixes #14881

Closes #15914
This commit is contained in:
BobChao87
2017-05-14 23:09:17 -07:00
committed by Georgios Kalpakas
parent a86a3195b4
commit 762580ff34
2 changed files with 17 additions and 1 deletions
+4 -1
View File
@@ -53,6 +53,9 @@
* dummy predicate that returns the item's index as `value`.
* (If you are using a custom comparator, make sure it can handle this predicate as well.)
*
* If a custom comparator still can't distinguish between two items, then they will be sorted based
* on their index using the built-in comparator.
*
* Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
* value for an item, `orderBy` will try to convert that object to a primitive value, before passing
* it to the comparator. The following rules govern the conversion:
@@ -599,7 +602,7 @@ function orderByFilter($parse) {
}
}
return compare(v1.tieBreaker, v2.tieBreaker) * descending;
return (compare(v1.tieBreaker, v2.tieBreaker) || defaultCompare(v1.tieBreaker, v2.tieBreaker)) * descending;
}
};
+13
View File
@@ -457,6 +457,19 @@ describe('Filter: orderBy', function() {
expect(orderBy(items, expr, reverse, comparator)).toEqual(sorted);
});
it('should use the default comparator to break ties on a provided comparator', function() {
// Some list that won't be sorted "naturally", i.e. should sort to ['a', 'B', 'c']
var items = ['c', 'a', 'B'];
var expr = null;
function comparator() {
return 0;
}
var reversed = ['B', 'a', 'c'];
expect(orderBy(items, expr, false, comparator)).toEqual(items);
expect(orderBy(items, expr, true, comparator)).toEqual(reversed);
});
});
describe('(object as `value`)', function() {