mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Rewrite sort compiler to avoid eval, too!
This commit is contained in:
@@ -13,7 +13,6 @@ Package.on_use(function (api, where) {
|
||||
api.add_files([
|
||||
'minimongo.js',
|
||||
'selector.js',
|
||||
'sort.js',
|
||||
'uuid.js',
|
||||
'modify.js',
|
||||
'diff.js'
|
||||
|
||||
@@ -543,4 +543,62 @@ LocalCollection._selectorIsId = function (selector) {
|
||||
return (typeof selector === "string") || (typeof selector === "number");
|
||||
};
|
||||
|
||||
// Give a sort spec, which can be in any of these forms:
|
||||
// {"key1": 1, "key2": -1}
|
||||
// [["key1", "asc"], ["key2", "desc"]]
|
||||
// ["key1", ["key2", "desc"]]
|
||||
//
|
||||
// (.. with the first form being dependent on the key enumeration
|
||||
// behavior of your javascript VM, which usually does what you mean in
|
||||
// this case if the key names don't look like integers ..)
|
||||
//
|
||||
// return a function that takes two objects, and returns -1 if the
|
||||
// first object comes first in order, 1 if the second object comes
|
||||
// first, or 0 if neither object comes before the other.
|
||||
|
||||
LocalCollection._compileSort = function (spec) {
|
||||
var sortSpecParts = [];
|
||||
|
||||
if (spec instanceof Array) {
|
||||
for (var i = 0; i < spec.length; i++) {
|
||||
if (typeof spec[i] === "string") {
|
||||
sortSpecParts.push({
|
||||
lookup: makeLookupFunction(spec[i]),
|
||||
ascending: true
|
||||
});
|
||||
} else {
|
||||
sortSpecParts.push({
|
||||
lookup: makeLookupFunction(spec[i][0]),
|
||||
ascending: spec[i][1] !== "desc"
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (typeof spec === "object") {
|
||||
for (var key in spec) {
|
||||
sortSpecParts.push({
|
||||
lookup: makeLookupFunction(key),
|
||||
ascending: spec[key] >= 0
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw Error("Bad sort specification: ", JSON.stringify(spec));
|
||||
}
|
||||
|
||||
if (sortSpecParts.length === 0)
|
||||
return function () {return 0;};
|
||||
|
||||
return function (a, b) {
|
||||
for (var i = 0; i < sortSpecParts.length; ++i) {
|
||||
var specPart = sortSpecParts[i];
|
||||
var aValue = specPart.lookup(a);
|
||||
var bValue = specPart.lookup(b);
|
||||
var compare = LocalCollection._f._cmp(aValue, bValue);
|
||||
if (compare !== 0)
|
||||
return specPart.ascending ? compare : -compare;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Give a sort spec, which can be in any of these forms:
|
||||
// {"key1": 1, "key2": -1}
|
||||
// [["key1", "asc"], ["key2", "desc"]]
|
||||
// ["key1", ["key2", "desc"]]
|
||||
//
|
||||
// (.. with the first form being dependent on the key enumeration
|
||||
// behavior of your javascript VM, which usually does what you mean in
|
||||
// this case if the key names don't look like integers ..)
|
||||
//
|
||||
// return a function that takes two objects, and returns -1 if the
|
||||
// first object comes first in order, 1 if the second object comes
|
||||
// first, or 0 if neither object comes before the other.
|
||||
|
||||
LocalCollection._compileSort = function (spec) {
|
||||
var keys = [];
|
||||
var asc = [];
|
||||
|
||||
if (spec instanceof Array) {
|
||||
for (var i = 0; i < spec.length; i++) {
|
||||
if (typeof spec[i] === "string") {
|
||||
keys.push(spec[i]);
|
||||
asc.push(true);
|
||||
} else {
|
||||
keys.push(spec[i][0]);
|
||||
asc.push(spec[i][1] !== "desc");
|
||||
}
|
||||
}
|
||||
} else if (typeof spec === "object") {
|
||||
for (key in spec) {
|
||||
keys.push(key);
|
||||
asc.push(!(spec[key] < 0));
|
||||
}
|
||||
} else {
|
||||
throw Error("Bad sort specification: ", JSON.stringify(spec));
|
||||
}
|
||||
|
||||
if (keys.length === 0)
|
||||
return function () {return 0;};
|
||||
|
||||
// eval() does not return a value in IE8, nor does the spec say it
|
||||
// should. Assign to a local to get the value, instead.
|
||||
var _func;
|
||||
var code = "_func = (function(c){return function(a,b){var x;";
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
// 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(" + aCode + "," + bCode + ");";
|
||||
}
|
||||
code += "return x;};})";
|
||||
eval(code);
|
||||
return _func(LocalCollection._f._cmp);
|
||||
};
|
||||
Reference in New Issue
Block a user