minimongo: Implement ordinal indexing: {'foo.1.bar': 42}

This commit is contained in:
David Glasser
2012-12-17 21:03:56 -08:00
parent 4c1c6c1ca5
commit 2d2aaa8082
2 changed files with 18 additions and 5 deletions

View File

@@ -795,9 +795,12 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
match({$where: "_.isArray(this.a)"}, {a: []});
nomatch({$where: "_.isArray(this.a)"}, {a: 1});
match({"dogs.0.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
match({"dogs.1.name": "Rex"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
nomatch({"dogs.1.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
// XXX still needs tests:
// - $elemMatch
// - people.2.name
// - non-scalar arguments to $gt, $lt, etc
});

View File

@@ -291,8 +291,6 @@ LocalCollection._selectorIsId = function (selector) {
return (typeof selector === "string") || (typeof selector === "number");
};
// XXX implement ordinal indexing: 'people.2.name'
// Given an arbitrary Mongo-style query selector, return an expression
// that evaluates to true if the document in 'doc' matches the
// selector, else false.
@@ -396,19 +394,31 @@ LocalCollection._exprForKeypathPredicate = function (keypath, value, literals) {
// drilling down through the dotted parts
var ret = '';
var innermost = true;
var lastPartWasNumber = false;
while (keyparts.length) {
var part = keyparts.pop();
var thisPartIsNumber = false;
if (/^\d+/.test(part)) {
part = +part;
thisPartIsNumber = true;
}
var formal = keyparts.length ? "x" : "doc";
if (innermost) {
ret = '(function(x){return ' + predcode + ';})(' + formal + '&&' + formal + '[' +
JSON.stringify(part) + '])';
innermost = false;
} else if (lastPartWasNumber) {
// The last part was an array index, so if we find an array here we
// shouldn't search it!
ret = '(function(x){return ' + ret + ';})(' + formal + '&&' + formal + '[' +
JSON.stringify(part) + '])';
} else {
// for all but the innermost level of a dotted expression,
// if the runtime type is an array, search it
// If the runtime type is an array, search it, unless we're already at the
// innermost bit, or if the next part is a number (ie, an array index).
ret = 'f._matches(' + formal + '&&' + formal + '[' + JSON.stringify(part) +
'], function(x){return ' + ret + ';})';
}
lastPartWasNumber = thisPartIsNumber;
}
return ret;