commit
c0a778eeab
|
@ -17,10 +17,13 @@ const deprecated = require('depd')('loopback-datasource-juggler');
|
||||||
const DefaultModelBaseClass = require('./model.js');
|
const DefaultModelBaseClass = require('./model.js');
|
||||||
const List = require('./list.js');
|
const List = require('./list.js');
|
||||||
const ModelDefinition = require('./model-definition.js');
|
const ModelDefinition = require('./model-definition.js');
|
||||||
const deepMerge = require('./utils').deepMerge;
|
|
||||||
const deepMergeProperty = require('./utils').deepMergeProperty;
|
|
||||||
const rankArrayElements = require('./utils').rankArrayElements;
|
|
||||||
const MixinProvider = require('./mixins');
|
const MixinProvider = require('./mixins');
|
||||||
|
const {
|
||||||
|
deepMerge,
|
||||||
|
deepMergeProperty,
|
||||||
|
rankArrayElements,
|
||||||
|
isClass,
|
||||||
|
} = require('./utils');
|
||||||
|
|
||||||
// Set up types
|
// Set up types
|
||||||
require('./types')(ModelBuilder);
|
require('./types')(ModelBuilder);
|
||||||
|
@ -591,11 +594,15 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
||||||
this.__data[propertyName] = value;
|
this.__data[propertyName] = value;
|
||||||
} else {
|
} else {
|
||||||
if (DataType === List) {
|
if (DataType === List) {
|
||||||
this.__data[propertyName] = DataType(value, properties[propertyName].type, this.__data);
|
this.__data[propertyName] = isClass(DataType) ?
|
||||||
|
new DataType(value, properties[propertyName].type, this.__data) :
|
||||||
|
DataType(value, properties[propertyName].type, this.__data);
|
||||||
} else {
|
} else {
|
||||||
// Assume the type constructor handles Constructor() call
|
// Assume the type constructor handles Constructor() call
|
||||||
// If not, we should call new DataType(value).valueOf();
|
// If not, we should call new DataType(value).valueOf();
|
||||||
this.__data[propertyName] = (value instanceof DataType) ? value : DataType(value);
|
this.__data[propertyName] = (value instanceof DataType) ?
|
||||||
|
value :
|
||||||
|
isClass(DataType) ? new DataType(value) : DataType(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,13 @@ module.exports = ModelUtils;
|
||||||
*/
|
*/
|
||||||
const g = require('strong-globalize')();
|
const g = require('strong-globalize')();
|
||||||
const geo = require('./geo');
|
const geo = require('./geo');
|
||||||
const utils = require('./utils');
|
const {
|
||||||
const fieldsToArray = utils.fieldsToArray;
|
fieldsToArray,
|
||||||
const sanitizeQueryOrData = utils.sanitizeQuery;
|
sanitizeQuery: sanitizeQueryOrData,
|
||||||
|
isPlainObject,
|
||||||
|
isClass,
|
||||||
|
toRegExp,
|
||||||
|
} = require('./utils');
|
||||||
const BaseModel = require('./model');
|
const BaseModel = require('./model');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,7 +216,7 @@ function coerceArray(val) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!utils.isPlainObject(val)) {
|
if (!isPlainObject(val)) {
|
||||||
throw new Error(g.f('Value is not an {{array}} or {{object}} with sequential numeric indices'));
|
throw new Error(g.f('Value is not an {{array}} or {{object}} with sequential numeric indices'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +478,7 @@ ModelUtils._coerce = function(where, options) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'regexp':
|
case 'regexp':
|
||||||
val = utils.toRegExp(val);
|
val = toRegExp(val);
|
||||||
if (val instanceof Error) {
|
if (val instanceof Error) {
|
||||||
val.statusCode = 400;
|
val.statusCode = 400;
|
||||||
throw val;
|
throw val;
|
||||||
|
@ -499,7 +503,7 @@ ModelUtils._coerce = function(where, options) {
|
||||||
for (let i = 0; i < val.length; i++) {
|
for (let i = 0; i < val.length; i++) {
|
||||||
if (val[i] !== null && val[i] !== undefined) {
|
if (val[i] !== null && val[i] !== undefined) {
|
||||||
if (!(val[i] instanceof RegExp)) {
|
if (!(val[i] instanceof RegExp)) {
|
||||||
val[i] = DataType(val[i]);
|
val[i] = isClass(DataType) ? new DataType(val[i]) : DataType(val[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,7 +536,7 @@ ModelUtils._coerce = function(where, options) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val = DataType(val);
|
val = isClass(DataType) ? new DataType(val) : DataType(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ exports.collectTargetIds = collectTargetIds;
|
||||||
exports.idName = idName;
|
exports.idName = idName;
|
||||||
exports.rankArrayElements = rankArrayElements;
|
exports.rankArrayElements = rankArrayElements;
|
||||||
exports.idsHaveDuplicates = idsHaveDuplicates;
|
exports.idsHaveDuplicates = idsHaveDuplicates;
|
||||||
|
exports.isClass = isClass;
|
||||||
|
|
||||||
const g = require('strong-globalize')();
|
const g = require('strong-globalize')();
|
||||||
const traverse = require('traverse');
|
const traverse = require('traverse');
|
||||||
|
@ -801,3 +802,7 @@ function idsHaveDuplicates(ids) {
|
||||||
}
|
}
|
||||||
return hasDuplicates === true;
|
return hasDuplicates === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isClass(fn) {
|
||||||
|
return fn && fn.toString().startsWith('class ');
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,12 @@ const should = require('./init.js');
|
||||||
|
|
||||||
let db, Model;
|
let db, Model;
|
||||||
|
|
||||||
|
class NestedClass {
|
||||||
|
constructor(roleName) {
|
||||||
|
this.roleName = roleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('datatypes', function() {
|
describe('datatypes', function() {
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
db = getSchema();
|
db = getSchema();
|
||||||
|
@ -23,6 +29,7 @@ describe('datatypes', function() {
|
||||||
list: {type: [String]},
|
list: {type: [String]},
|
||||||
arr: Array,
|
arr: Array,
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
nestedClass: NestedClass,
|
||||||
};
|
};
|
||||||
Model = db.define('Model', modelTableSchema);
|
Model = db.define('Model', modelTableSchema);
|
||||||
db.automigrate(['Model'], done);
|
db.automigrate(['Model'], done);
|
||||||
|
@ -101,6 +108,30 @@ describe('datatypes', function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create nested object defined by a class when reading data from db', async () => {
|
||||||
|
const d = new Date('2015-01-01T12:00:00');
|
||||||
|
let id;
|
||||||
|
const created = await Model.create({
|
||||||
|
date: d,
|
||||||
|
list: ['test'],
|
||||||
|
arr: [1, 'str'],
|
||||||
|
nestedClass: new NestedClass('admin'),
|
||||||
|
});
|
||||||
|
created.list.should.deepEqual(['test']);
|
||||||
|
created.arr.should.deepEqual([1, 'str']);
|
||||||
|
created.date.should.be.an.instanceOf(Date);
|
||||||
|
created.date.toString().should.equal(d.toString(), 'Time must match');
|
||||||
|
created.nestedClass.should.have.property('roleName', 'admin');
|
||||||
|
|
||||||
|
const found = await Model.findById(created.id);
|
||||||
|
should.exist(found);
|
||||||
|
found.list.should.deepEqual(['test']);
|
||||||
|
found.arr.should.deepEqual([1, 'str']);
|
||||||
|
found.date.should.be.an.instanceOf(Date);
|
||||||
|
found.date.toString().should.equal(d.toString(), 'Time must match');
|
||||||
|
found.nestedClass.should.have.property('roleName', 'admin');
|
||||||
|
});
|
||||||
|
|
||||||
it('should respect data types when updating attributes', function(done) {
|
it('should respect data types when updating attributes', function(done) {
|
||||||
const d = new Date;
|
const d = new Date;
|
||||||
let id;
|
let id;
|
||||||
|
|
|
@ -48,9 +48,37 @@ describe('ModelBuilder', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('model with nested properties as function', () => {
|
||||||
|
const Role = function(roleName) {};
|
||||||
|
it('sets correct nested properties', () => {
|
||||||
|
const User = builder.define('User', {
|
||||||
|
role: {
|
||||||
|
type: typeof Role,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
should.equal(User.getPropertyType('role'), 'ModelConstructor');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('model with nested properties as class', () => {
|
||||||
|
class Role {
|
||||||
|
constructor(roleName) {}
|
||||||
|
}
|
||||||
|
it('sets correct nested properties', () => {
|
||||||
|
const User = builder.define('UserWithClass', {
|
||||||
|
role: {
|
||||||
|
type: Role,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
User.registerProperty('role');
|
||||||
|
should.equal(User.getPropertyType('role'), 'Role');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function givenModelBuilderInstance() {
|
function givenModelBuilderInstance() {
|
||||||
builder = new ModelBuilder();
|
builder = new ModelBuilder();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue