Merge pull request #1441 from strongloop/memory/throw-on-malformed-types
castPropertyValue: throw on malformed types
This commit is contained in:
commit
29676f6510
|
@ -350,9 +350,17 @@ Memory.prototype.fromDb = function(model, data) {
|
|||
if (!data) return null;
|
||||
data = deserialize(data);
|
||||
var props = this._models[model].properties;
|
||||
try {
|
||||
for (var key in data) {
|
||||
data[key] = this._castPropertyValue(key, data[key], props);
|
||||
}
|
||||
} catch (err) {
|
||||
// Modify error message and re-throw
|
||||
err.message = g.f('Unable to convert to instance of "%s": %s', model,
|
||||
err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
|
@ -370,7 +378,15 @@ Memory.prototype._castPropertyValue = function(prop, val, props) {
|
|||
|
||||
var isArray = Array.isArray(props[prop].type);
|
||||
var propType = isArray ? props[prop].type[0] : props[prop].type;
|
||||
|
||||
if (!propType || !propType.name) {
|
||||
if (isArray)
|
||||
throw new Error(g.f(
|
||||
'Property definition "%s" did not specify any sub-types!', prop));
|
||||
else
|
||||
throw new Error(g.f(
|
||||
'Property definition "%s" was null or undefined!', prop
|
||||
));
|
||||
}
|
||||
switch (propType.name) {
|
||||
case 'Date':
|
||||
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
|
||||
|
@ -383,7 +399,9 @@ Memory.prototype._castPropertyValue = function(prop, val, props) {
|
|||
break;
|
||||
case 'ModelConstructor':
|
||||
for (var subProp in val) {
|
||||
val[subProp] = this._castPropertyValue(subProp, val[subProp], propType.definition.properties);
|
||||
if (propType.definition && propType.definition.properties)
|
||||
val[subProp] = this._castPropertyValue(subProp, val[subProp],
|
||||
propType.definition.properties);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var jdb = require('../');
|
||||
var DataSource = jdb.DataSource;
|
||||
var path = require('path');
|
||||
|
@ -889,6 +890,106 @@ describe('Memory connector', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_castPropertyValue', function() {
|
||||
var mem = new Memory();
|
||||
var ds = new DataSource({
|
||||
connector: mem,
|
||||
});
|
||||
|
||||
var Kwyjibo = ds.createModel('Kwyjibo', {
|
||||
modelNumber: Number,
|
||||
purpose: String,
|
||||
});
|
||||
|
||||
testHappyPath('handles strings', 'name', 'foo', 'foo');
|
||||
testHappyPath('handles numbers', 'age', '20', 20);
|
||||
var hobbies = [
|
||||
'swimming', 'biking', 'extreme bear fighting',
|
||||
];
|
||||
testHappyPath('handles boolean values', 'isAwesome', 'true', true);
|
||||
var now = new Date();
|
||||
testHappyPath('handles Dates', 'createdAt', now.toISOString(),
|
||||
new Date(now));
|
||||
testHappyPath('handles arrays', 'hobbies', hobbies, hobbies);
|
||||
|
||||
it('handles ModelConstructors', function() {
|
||||
var samoflange = {
|
||||
modelNumber: 12345,
|
||||
purpose: 'To annoy others',
|
||||
};
|
||||
var kwyjibo = new Kwyjibo();
|
||||
for (var item in samoflange) {
|
||||
kwyjibo[item] = samoflange[item];
|
||||
}
|
||||
var result = mem._castPropertyValue('samoflange', samoflange, kwyjibo);
|
||||
should.exist(result);
|
||||
should.deepEqual(result, kwyjibo.__data);
|
||||
});
|
||||
|
||||
var nullUndef = 'Property definition "%s" was null or undefined!';
|
||||
var noSubTypes = 'Property definition "%s" did not specify any sub-types!';
|
||||
testUnhappyPath('throws on empty array property def', 'hobbies', hobbies,
|
||||
g.f(noSubTypes, 'hobbies'));
|
||||
testUnhappyPath('throws on empty object property def', 'age', 20,
|
||||
g.f(nullUndef, 'age'));
|
||||
testUnhappyPath('throws on null property def', 'name', 'foo',
|
||||
g.f(nullUndef, 'name'));
|
||||
testUnhappyPath('throws on undefined property def', 'title', 'peon',
|
||||
g.f(nullUndef, 'title'));
|
||||
|
||||
function testHappyPath(testName, prop, val, expected) {
|
||||
var props = {
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
age: {
|
||||
type: Number,
|
||||
},
|
||||
hobbies: {
|
||||
type: [
|
||||
String,
|
||||
],
|
||||
},
|
||||
isAwesome: {
|
||||
type: Boolean,
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
},
|
||||
samoflange: {
|
||||
type: Kwyjibo,
|
||||
},
|
||||
};
|
||||
|
||||
it(testName, function() {
|
||||
var result = mem._castPropertyValue(prop, val, props);
|
||||
result.should.deepEqual(expected);
|
||||
});
|
||||
}
|
||||
|
||||
function testUnhappyPath(testName, prop, val, expected) {
|
||||
var props = {
|
||||
name: {
|
||||
type: null,
|
||||
},
|
||||
title: {
|
||||
type: undefined,
|
||||
},
|
||||
age: {
|
||||
type: {},
|
||||
},
|
||||
hobbies: {
|
||||
type: [],
|
||||
},
|
||||
};
|
||||
it(testName, function() {
|
||||
(function() {
|
||||
mem._castPropertyValue(prop, val, props);
|
||||
}).should.throw(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Optimized connector', function() {
|
||||
|
|
Loading…
Reference in New Issue