diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 506b478c..2857d8e7 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -400,29 +400,39 @@ function applyFilter(filter) { } var keys = Object.keys(where); return function (obj) { - var pass = true; - keys.forEach(function(key) { + return keys.every(function(key) { if(key === 'and' || key === 'or') { if(Array.isArray(where[key])) { if(key === 'and') { - pass = where[key].every(function(cond) { + return where[key].every(function(cond) { return applyFilter({where: cond})(obj); }); - return pass; } if(key === 'or') { - pass = where[key].some(function(cond) { + return where[key].some(function(cond) { return applyFilter({where: cond})(obj); }); - return pass; } } } - if (!test(where[key], getValue(obj, key))) { - pass = false; + + if (test(where[key], getValue(obj, key))) { + return true; } + + // If we have a composed key a.b and b would resolve to a property of an object inside an array + // then, we attempt to emulate mongo db matching. Helps for embedded relations + var dotIndex = key.indexOf('.'); + var subValue = obj[key.substring(0, dotIndex)]; + if (dotIndex !== -1 && Array.isArray(subValue)) { + var subFilter = {where: {}}; + var subKey = key.substring(dotIndex+1); + subFilter.where[subKey] = where[key]; + return !!subValue.filter(applyFilter(subFilter)).length + } + + return false; }); - return pass; } function toRegExp(pattern) { @@ -467,8 +477,9 @@ function applyFilter(filter) { } if (typeof example === 'object' && example !== null) { - if (example.regexp) - return value.match(example.regexp); + if (example.regexp) { + return value ? value.match(example.regexp) : false; + } // ignore geo near filter if (example.near) { diff --git a/test/memory.test.js b/test/memory.test.js index 9280513a..07b0e17b 100644 --- a/test/memory.test.js +++ b/test/memory.test.js @@ -134,6 +134,7 @@ describe('Memory connector', function() { }); }); + // describe.only('Query for memory connector', function() { describe('Query for memory connector', function() { var ds = new DataSource({ connector: 'memory' @@ -152,7 +153,12 @@ describe('Memory connector', function() { city: String, state: String, zipCode: String - } + }, + friends: [ + { + name: String + } + ] }); before(seed); @@ -270,6 +276,23 @@ describe('Memory connector', function() { }); }); + it('should successfully extract 2 users using implied and', function(done) { + User.find({where: {role:'lead', vip:true}}, function(err, users) { + should(users.length).be.equal(2); + should(users[0].name).be.equal('John Lennon'); + should(users[1].name).be.equal('Paul McCartney'); + done(); + }); + }); + + it('should successfully extract 2 users using implied and & and', function(done) { + User.find({where: { name: 'John Lennon',and: [{role:'lead'}, {vip:true}]}}, function(err, users) { + should(users.length).be.equal(1); + should(users[0].name).be.equal('John Lennon'); + done(); + }); + }); + it('should successfully extract 2 users using date range', function(done) { User.find({where: {birthday: {between: [new Date(1940, 0).toISOString(), new Date(1990, 0).toISOString()]}}}, @@ -405,6 +428,16 @@ describe('Memory connector', function() { }); }); + it('should support nested property with regex over arrays in query', function(done) { + User.find({where: {'friends.name': {regexp: /^Ringo/}}}, function(err, users) { + should.not.exist(err); + users.length.should.be.equal(2); + users[0].name.should.be.equal('John Lennon'); + users[1].name.should.be.equal('Paul McCartney'); + done(); + }); + }); + it('should support nested property with gt in query', function(done) { User.find({where: {'address.city': {gt: 'San'}}}, function(err, users) { should.not.exist(err); @@ -454,7 +487,12 @@ describe('Memory connector', function() { city: 'San Jose', state: 'CA', zipCode: '95131' - } + }, + friends: [ + { name: 'Paul McCartney' }, + { name: 'George Harrison' }, + { name: 'Ringo Starr' }, + ] }, { seq: 1, @@ -469,7 +507,12 @@ describe('Memory connector', function() { city: 'San Mateo', state: 'CA', zipCode: '94065' - } + }, + friends: [ + { name: 'John Lennon' }, + { name: 'George Harrison' }, + { name: 'Ringo Starr' }, + ] }, {seq: 2, name: 'George Harrison', order: 5, vip: false}, {seq: 3, name: 'Ringo Starr', order: 6, vip: false},