castPropertyValue: throw on malformed types

This commit is contained in:
Kevin Delisle 2017-07-27 10:50:25 -04:00
parent e63bbcf9cd
commit f3b849bb47
2 changed files with 123 additions and 4 deletions

View File

@ -350,9 +350,17 @@ Memory.prototype.fromDb = function(model, data) {
if (!data) return null;
data = deserialize(data);
var props = this._models[model].properties;
for (var key in data) {
data[key] = this._castPropertyValue(key, data[key], props);
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;
}

View File

@ -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() {