Merge pull request #1361 from nVitius/Fix/2.x/NestedProperties
Fix/2.x/nested properties
This commit is contained in:
commit
1d8ca908f6
|
@ -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;
|
||||
|
|
21
lib/dao.js
21
lib/dao.js
|
@ -1565,12 +1565,14 @@ function coerceArray(val) {
|
|||
* @returns {Object} The coerced where clause
|
||||
* @private
|
||||
*/
|
||||
DataAccessObject._coerce = function(where) {
|
||||
DataAccessObject._coerce = function(where, props) {
|
||||
var self = this;
|
||||
if (!where) {
|
||||
return where;
|
||||
}
|
||||
|
||||
props = props || self.definition.properties;
|
||||
|
||||
var err;
|
||||
if (typeof where !== 'object' || Array.isArray(where)) {
|
||||
err = new Error(g.f('The where clause %j is not an {{object}}', where));
|
||||
|
@ -1578,7 +1580,6 @@ DataAccessObject._coerce = function(where) {
|
|||
throw err;
|
||||
}
|
||||
|
||||
var props = self.definition.properties;
|
||||
for (var p in where) {
|
||||
// Handle logical operators
|
||||
if (p === 'and' || p === 'or' || p === 'nor') {
|
||||
|
@ -1597,6 +1598,22 @@ DataAccessObject._coerce = function(where) {
|
|||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p.match(/\./)) {
|
||||
var model = p.split('.')[0];
|
||||
var prop = p.split('.').slice(1);
|
||||
|
||||
if (props[model]) {
|
||||
var clause = {};
|
||||
clause[prop] = where[p];
|
||||
where[p] = Array.isArray(props[model].type) ?
|
||||
self._coerce(clause, props[model].type[0].definition.properties)[prop] :
|
||||
self._coerce(clause, props[model].type.definition.properties)[prop];
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var DataType = props[p] && props[p].type;
|
||||
if (!DataType) {
|
||||
continue;
|
||||
|
|
|
@ -1374,6 +1374,11 @@ describe('DataAccessObject', function() {
|
|||
age: Number,
|
||||
vip: Boolean,
|
||||
date: Date,
|
||||
sub: {
|
||||
date: Date,
|
||||
bool: Boolean,
|
||||
number: Number,
|
||||
},
|
||||
location: 'GeoPoint',
|
||||
scores: [Number],
|
||||
});
|
||||
|
@ -1433,6 +1438,27 @@ describe('DataAccessObject', function() {
|
|||
assert.deepEqual(where, {date: d});
|
||||
});
|
||||
|
||||
it('coerces where clause for date types in nested properties', function() {
|
||||
var d = new Date();
|
||||
where = model._coerce({'sub.date': d});
|
||||
assert.deepEqual(where, {'sub.date': d});
|
||||
|
||||
where = model._coerce({'sub.date': d.toISOString()});
|
||||
assert.deepEqual(where, {'sub.date': d});
|
||||
});
|
||||
|
||||
it('coerces where clause for Boolean types in nested properties', function() {
|
||||
var bool = 'true';
|
||||
where = model._coerce({'sub.bool': bool});
|
||||
assert.strictEqual(where['sub.bool'], true);
|
||||
});
|
||||
|
||||
it('coerces where clause for Number type in nested properties', function() {
|
||||
var number = '123';
|
||||
where = model._coerce({'sub.number': number});
|
||||
assert.strictEqual(where['sub.number'], 123);
|
||||
});
|
||||
|
||||
it('coerces where clause for boolean types', function() {
|
||||
where = model._coerce({vip: 'true'});
|
||||
assert.deepEqual(where, {vip: true});
|
||||
|
@ -1518,8 +1544,7 @@ describe('DataAccessObject', function() {
|
|||
|
||||
INVALID_CLAUSES.forEach(function(where) {
|
||||
var whereStr = JSON.stringify(where);
|
||||
it('throws an error on malformed array-like object ' + whereStr,
|
||||
function() {
|
||||
it('throws an error on malformed array-like object ' + whereStr, function() {
|
||||
assert.throws(
|
||||
function() { model._coerce(where); },
|
||||
/property has invalid clause/);
|
||||
|
@ -1694,31 +1719,28 @@ describe('DataAccessObject', function() {
|
|||
assert.deepEqual(where, {date: undefined});
|
||||
});
|
||||
|
||||
it('does not coerce to a number for a simple value that produces NaN',
|
||||
function() {
|
||||
where = model._coerce({age: 'xyz'});
|
||||
assert.deepEqual(where, {age: 'xyz'});
|
||||
});
|
||||
it('does not coerce to a number for a simple value that produces NaN', function() {
|
||||
where = model._coerce({age: 'xyz'});
|
||||
assert.deepEqual(where, {age: 'xyz'});
|
||||
});
|
||||
|
||||
it('does not coerce to a number for a simple value in an array that produces NaN',
|
||||
function() {
|
||||
where = model._coerce({age: {inq: ['xyz', '12']}});
|
||||
assert.deepEqual(where, {age: {inq: ['xyz', 12]}});
|
||||
});
|
||||
it('does not coerce to a number for a simple value in an array that produces NaN', function() {
|
||||
where = model._coerce({age: {inq: ['xyz', '12']}});
|
||||
assert.deepEqual(where, {age: {inq: ['xyz', 12]}});
|
||||
});
|
||||
|
||||
// settings
|
||||
it('gets settings in priority',
|
||||
function() {
|
||||
ds.settings.test = 'test';
|
||||
assert.equal(model._getSetting('test'), ds.settings.test, 'Should get datasource setting');
|
||||
ds.settings.test = undefined;
|
||||
it('gets settings in priority', function() {
|
||||
ds.settings.test = 'test';
|
||||
assert.equal(model._getSetting('test'), ds.settings.test, 'Should get datasource setting');
|
||||
ds.settings.test = undefined;
|
||||
|
||||
model.settings.test = 'test';
|
||||
assert.equal(model._getSetting('test'), model.settings.test, 'Should get model settings');
|
||||
model.settings.test = 'test';
|
||||
assert.equal(model._getSetting('test'), model.settings.test, 'Should get model settings');
|
||||
|
||||
ds.settings.test = 'willNotGet';
|
||||
assert.notEqual(model._getSetting('test'), ds.settings.test, 'Should not get datasource setting');
|
||||
});
|
||||
ds.settings.test = 'willNotGet';
|
||||
assert.notEqual(model._getSetting('test'), ds.settings.test, 'Should not get datasource setting');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ModelBuilder processing json files', function() {
|
||||
|
|
|
@ -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'],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue