diff --git a/History.md b/History.md index f96b92f149..34de130d71 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,8 @@ * Use "faye-websocket" (0.7.2) npm module instead of "websocket" (1.0.8) for server-to-server DDP. +* minimongo: Support {a: {$elemMatch: {x: 1, $or: [{a: 1}, {b: 1}]}}} #1875 + ## v0.7.1.2 diff --git a/packages/minimongo/helpers.js b/packages/minimongo/helpers.js index d4046124f2..ab8cc78b6f 100644 --- a/packages/minimongo/helpers.js +++ b/packages/minimongo/helpers.js @@ -16,7 +16,10 @@ isIndexable = function (x) { return isArray(x) || isPlainObject(x); }; -isOperatorObject = function (valueSelector) { +// Returns true if this is an object with at least one key and all keys begin +// with $. Unless inconsistentOK is set, throws if some keys begin with $ and +// others don't. +isOperatorObject = function (valueSelector, inconsistentOK) { if (!isPlainObject(valueSelector)) return false; @@ -26,7 +29,10 @@ isOperatorObject = function (valueSelector) { if (theseAreOperators === undefined) { theseAreOperators = thisIsOperator; } else if (theseAreOperators !== thisIsOperator) { - throw new Error("Inconsistent operator: " + valueSelector); + if (!inconsistentOK) + throw new Error("Inconsistent operator: " + + JSON.stringify(valueSelector)); + theseAreOperators = false; } }); return !!theseAreOperators; // {} has no operators diff --git a/packages/minimongo/minimongo_tests.js b/packages/minimongo/minimongo_tests.js index dd8dc6de94..6c9359761d 100644 --- a/packages/minimongo/minimongo_tests.js +++ b/packages/minimongo/minimongo_tests.js @@ -820,6 +820,12 @@ Tinytest.add("minimongo - selector_compiler", function (test) { nomatch({$or: [{a: 2}, {a: 3}], b: 2}, {a: 1, b: 2}); nomatch({$or: [{a: 1}, {a: 2}], b: 3}, {a: 1, b: 2}); + // Combining $or with equality + match({x: 1, $or: [{a: 1}, {b: 1}]}, {x: 1, b: 1}); + match({$or: [{a: 1}, {b: 1}], x: 1}, {x: 1, b: 1}); + nomatch({x: 1, $or: [{a: 1}, {b: 1}]}, {b: 1}); + nomatch({x: 1, $or: [{a: 1}, {b: 1}]}, {x: 1}); + // $or and $lt, $lte, $gt, $gte match({$or: [{a: {$lte: 1}}, {a: 2}]}, {a: 1}); nomatch({$or: [{a: {$lt: 1}}, {a: 2}]}, {a: 1}); @@ -1103,6 +1109,16 @@ Tinytest.add("minimongo - selector_compiler", function (test) { nomatch({a: {$elemMatch: {x: 5}}}, {a: {x: 5}}); match({a: {$elemMatch: {0: {$gt: 5, $lt: 9}}}}, {a: [[6]]}); match({a: {$elemMatch: {'0.b': {$gt: 5, $lt: 9}}}}, {a: [[{b:6}]]}); + match({a: {$elemMatch: {x: 1, $or: [{a: 1}, {b: 1}]}}}, + {a: [{x: 1, b: 1}]}); + match({a: {$elemMatch: {$or: [{a: 1}, {b: 1}], x: 1}}}, + {a: [{x: 1, b: 1}]}); + nomatch({a: {$elemMatch: {x: 1, $or: [{a: 1}, {b: 1}]}}}, + {a: [{b: 1}]}); + nomatch({a: {$elemMatch: {x: 1, $or: [{a: 1}, {b: 1}]}}}, + {a: [{x: 1}]}); + nomatch({a: {$elemMatch: {x: 1, $or: [{a: 1}, {b: 1}]}}}, + {a: [{x: 1}, {b: 1}]}); // $comment match({a: 5, $comment: "asdf"}, {a: 5}); diff --git a/packages/minimongo/selector.js b/packages/minimongo/selector.js index 3b68a320f9..80636bb12d 100644 --- a/packages/minimongo/selector.js +++ b/packages/minimongo/selector.js @@ -653,7 +653,7 @@ var ELEMENT_OPERATORS = { throw Error("$elemMatch need an object"); var subMatcher, isDocMatcher; - if (isOperatorObject(operand)) { + if (isOperatorObject(operand, true)) { subMatcher = compileValueSelector(operand, matcher); isDocMatcher = false; } else {