Merge pull request #1670 from up-group/master

Enable to target ES6
This commit is contained in:
Miroslav Bajtoš 2019-01-29 15:50:56 +01:00 committed by GitHub
commit c0a778eeab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 13 deletions

View File

@ -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);
} }
} }
} }

View File

@ -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);
} }
} }
} }

View File

@ -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 ');
}

View File

@ -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;

View File

@ -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();
} }
}); });
}); });