From 3df18267308823342f212fa6ab2ae127de4b99f6 Mon Sep 17 00:00:00 2001 From: nVitius Date: Fri, 28 Apr 2017 15:58:45 -0700 Subject: [PATCH] Recursively cast props on fromDb for memory conn. In the fromDb step, nested properties weren't being hydrated properly. This caused an issue with the ability to search on such properties as Dates. The properties would be hydrated as a String type, and as such, it was impossible to properly query on them. --- lib/connectors/memory.js | 54 ++++++++++++++++++++++++------------- test/memory.test.js | 58 ++++++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 586ea958..54b440fb 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -351,28 +351,46 @@ Memory.prototype.fromDb = function(model, data) { data = deserialize(data); var props = this._models[model].properties; for (var key in data) { - var val = data[key]; - if (val === undefined || val === null) { - continue; - } - if (props[key]) { - switch (props[key].type.name) { - case 'Date': - val = new Date(val.toString().replace(/GMT.*$/, 'GMT')); - break; - case 'Boolean': - val = Boolean(val); - break; - case 'Number': - val = Number(val); - break; - } - } - data[key] = val; + data[key] = this._castPropertyValue(key, data[key], props); } return data; }; +Memory.prototype._castPropertyValue = function(prop, val, props) { + var self = this; + if (val === undefined || val === null || !props[prop]) { + return val; + } + + if (Array.isArray(val)) { + return val.map(function(val) { + return self._castPropertyValue(prop, val, props); + }); + } + + var isArray = Array.isArray(props[prop].type); + var propType = isArray ? props[prop].type[0] : props[prop].type; + + switch (propType.name) { + case 'Date': + val = new Date(val.toString().replace(/GMT.*$/, 'GMT')); + break; + case 'Boolean': + val = Boolean(val); + break; + case 'Number': + val = Number(val); + break; + case 'ModelConstructor': + for (var subProp in val) { + val[subProp] = this._castPropertyValue(subProp, val[subProp], propType.definition.properties); + } + break; + } + + return val; +}; + function getValue(obj, path) { if (obj == null) { return undefined; diff --git a/test/memory.test.js b/test/memory.test.js index 8650e535..68c75ff3 100644 --- a/test/memory.test.js +++ b/test/memory.test.js @@ -157,6 +157,7 @@ describe('Memory connector', function() { city: String, state: String, zipCode: String, + since: Date, tags: [ { tag: String, @@ -166,6 +167,7 @@ describe('Memory connector', function() { friends: [ { name: String, + since: Date, }, ], }); @@ -294,8 +296,7 @@ describe('Memory connector', function() { }); }); - it('should successfully extract 2 users using implied and & and', - function(done) { + it('should successfully extract 2 users using implied and & and', function(done) { User.find({ where: { name: 'John Lennon', @@ -435,15 +436,14 @@ describe('Memory connector', function() { }); }); - it('should work when a regex is provided without the regexp operator', - function(done) { - User.find({where: {name: /John.*/i}}, function(err, users) { - should.not.exist(err); - users.length.should.equal(1); - users[0].name.should.equal('John Lennon'); - done(); - }); - }); + it('should work when a regex is provided without the regexp operator', function(done) { + User.find({where: {name: /John.*/i}}, function(err, users) { + should.not.exist(err); + users.length.should.equal(1); + users[0].name.should.equal('John Lennon'); + done(); + }); + }); it('should support the regexp operator with regex strings', function(done) { User.find({where: {name: {regexp: '^J'}}}, function(err, users) { @@ -516,6 +516,28 @@ describe('Memory connector', function() { }); }); + it('should support date as nested property in query', function(done) { + var d = new Date('2017-01-01'); + User.find({where: {'address.since': d}}, + function(err, users) { + should.not.exist(err); + users.length.should.be.equal(1); + users[0].address.since.should.be.eql(d); + done(); + }); + }); + + it('should support date as array property in query', function(done) { + var d = new Date('1960-01-01'); + User.find({where: {'friends.since': d}}, + function(err, users) { + should.not.exist(err); + users.length.should.be.equal(2); + users[0].friends[0].since.should.be.eql(d); + done(); + }); + }); + it('should deserialize values after saving in upsert', function(done) { User.findOne({where: {seq: 1}}, function(err, paul) { User.updateOrCreate({id: paul.id, name: 'Sir Paul McCartney'}, @@ -553,15 +575,16 @@ describe('Memory connector', function() { city: 'San Jose', state: 'CA', zipCode: '95131', + since: new Date('2017-01-01'), tags: [ {tag: 'business'}, {tag: 'rent'}, ], }, friends: [ - {name: 'Paul McCartney'}, - {name: 'George Harrison'}, - {name: 'Ringo Starr'}, + {name: 'Paul McCartney', since: new Date('1960-01-01')}, + {name: 'George Harrison', since: new Date('1960-01-01')}, + {name: 'Ringo Starr', since: new Date('1960-01-01')}, ], children: ['Sean', 'Julian'], }, @@ -578,11 +601,12 @@ describe('Memory connector', function() { city: 'San Mateo', state: 'CA', zipCode: '94065', + since: new Date('2017-02-01'), }, friends: [ - {name: 'John Lennon'}, - {name: 'George Harrison'}, - {name: 'Ringo Starr'}, + {name: 'John Lennon', since: new Date('1960-01-01')}, + {name: 'George Harrison', since: new Date('1960-01-01')}, + {name: 'Ringo Starr', since: new Date('1960-01-01')}, ], children: ['Stella', 'Mary', 'Heather', 'Beatrice', 'James'], },