From 27352bc4106eb56714184cd0826d41402c68436f Mon Sep 17 00:00:00 2001 From: Louis Chatriot Date: Wed, 22 May 2013 21:35:25 +0200 Subject: [PATCH] Nested matching works for array fields --- lib/model.js | 40 ++++++++++++++++++++++++++++++++-------- test/model.test.js | 16 ++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/lib/model.js b/lib/model.js index 47e66a0..1f5b4d5 100644 --- a/lib/model.js +++ b/lib/model.js @@ -296,6 +296,22 @@ matcherFunctions.$eq = function (objValue, value) { }; +/** + * Match any of the subconditions + */ +matcherFunctions.$or = function (obj, query) { + var i; + + if (!util.isArray(query)) { throw "$or operator used without an array"; } + + for (i = 0; i < query.length; i += 1) { + if (match(obj, query[i])) { return true; } + } + + return false; +}; + + /** * Tell if a given document matches a query * @param {Object} obj Document to check @@ -323,16 +339,24 @@ function matchQueryKey (obj, query, queryKey) { , i ; - if (util.isArray(objValue)) { - for (i = 0; i < objValue.length; i += 1) { - if (matcherFunctions.$eq(objValue[i], queryValue)) { return true; } - } - return false; + if (queryKey[0] === '$') { + // We apply an operator like $or, $and + if (!matcherFunctions[queryKey]) { throw "Unknown query operator " + queryKey; } + + return matcherFunctions[queryKey](obj, queryValue); } else { - if (!matcherFunctions.$eq(objValue, queryValue)) { return false; } - } + // Normal field matching + if (util.isArray(objValue)) { + for (i = 0; i < objValue.length; i += 1) { + if (matcherFunctions.$eq(objValue[i], queryValue)) { return true; } + } + return false; + } else { + if (!matcherFunctions.$eq(objValue, queryValue)) { return false; } + } - return true; + return true; + } } diff --git a/test/model.test.js b/test/model.test.js index 69a1ac8..3782b93 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -414,11 +414,27 @@ describe('Model', function () { it('For field array, a match means a match on at least one element', function () { model.match({ tags: ['node', 'js', 'db'] }, { tags: 'python' }).should.equal(false); + model.match({ tags: ['node', 'js', 'db'] }, { tagss: 'js' }).should.equal(false); model.match({ tags: ['node', 'js', 'db'] }, { tags: 'js' }).should.equal(true); model.match({ tags: ['node', 'js', 'db'] }, { tags: 'js', tags: 'node' }).should.equal(true); // Mixed matching with array and non array model.match({ tags: ['node', 'js', 'db'], nedb: true }, { tags: 'js', nedb: true }).should.equal(true); + + // Nested matching + model.match({ number: 5, data: { tags: ['node', 'js', 'db'] } }, { "data.tags": 'js' }).should.equal(true); + model.match({ number: 5, data: { tags: ['node', 'js', 'db'] } }, { "data.tags": 'j' }).should.equal(false); + }); + + }); + + + describe('$or', function () { + + it('Any of the subconditions can be used', function () { + model.match({ hello: 'world' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(true); + model.match({ hello: 'pluton' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(true); + model.match({ hello: 'nope' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(false); }); });