diff --git a/packages/minimongo/minimongo_tests.js b/packages/minimongo/minimongo_tests.js index b3713eb25c..ec3cf13f4a 100644 --- a/packages/minimongo/minimongo_tests.js +++ b/packages/minimongo/minimongo_tests.js @@ -875,6 +875,40 @@ Tinytest.add("minimongo - sort", function (test) { {a: 47, b: 1, _id: "47_1"}]); }); +Tinytest.add("minimongo - subkey sort", function (test) { + var c = new LocalCollection(); + + // normal case + c.insert({a: {b: 2}}); + c.insert({a: {b: 1}}); + c.insert({a: {b: 3}}); + test.equal( + _.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'), + [{b: 3}, {b: 2}, {b: 1}]); + + // isn't an object + c.insert({a: 1}); + test.equal( + _.pluck(c.find({}, {sort: {'a.b': 1}}).fetch(), 'a'), + [1, {b: 1}, {b: 2}, {b: 3}]); + + // complex object + c.insert({a: {b: {c: 1}}}); + test.equal( + _.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'), + [{b: {c: 1}}, {b: 3}, {b: 2}, {b: 1}, 1]); + + // no such top level prop + c.insert({c: 1}); + test.equal( + _.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'), + [{b: {c: 1}}, {b: 3}, {b: 2}, {b: 1}, 1, undefined]); + + // no such mid level prop. just test that it doesn't throw. + test.equal(c.find({}, {sort: {'a.nope.c': -1}}).count(), 6); +}); + + Tinytest.add("minimongo - modify", function (test) { var modify = function (doc, mod, result) { var copy = LocalCollection._deepcopy(doc); diff --git a/packages/minimongo/sort.js b/packages/minimongo/sort.js index 6d1d8077fe..94420cf237 100644 --- a/packages/minimongo/sort.js +++ b/packages/minimongo/sort.js @@ -11,8 +11,6 @@ // first object comes first in order, 1 if the second object comes // first, or 0 if neither object comes before the other. -// XXX sort does not yet support subkeys ('a.b') .. fix that! - LocalCollection._compileSort = function (spec) { var keys = []; var asc = []; @@ -44,14 +42,24 @@ LocalCollection._compileSort = function (spec) { var _func; var code = "_func = (function(c){return function(a,b){var x;"; for (var i = 0; i < keys.length; i++) { - if (i !== 0) + // handle dotted subpaths. Make sure to avoid dereferencing + // undefined if a subkey doesn't exist. + var splittedKeys = keys[i].split("."); + var keyString = ""; + var aCode = "a"; + var bCode = "b"; + for(var o = 0; o < splittedKeys.length; o++) { + keyString = keyString + "[" + JSON.stringify(splittedKeys[o]) + "]"; + aCode += '&&a' + keyString; + bCode += '&&b' + keyString; + } + if (i !== 0) { code += "if(x!==0)return x;"; + } code += "x=" + (asc[i] ? "" : "-") + - "c(a[" + JSON.stringify(keys[i]) + "],b[" + - JSON.stringify(keys[i]) + "]);"; + "c(" + aCode + "," + bCode + ");"; } code += "return x;};})"; - eval(code); return _func(LocalCollection._f._cmp); };