Merge pull request #1719 from strongloop/fix/primitive-datatypes-coercion-3x
Fix primitive datatypes coercion [3.x] Make sure we coerce Date values properly when creating new model instances. Also make sure we use the coerced data values for model instance for update operation.
This commit is contained in:
commit
730918f23d
|
@ -2303,6 +2303,7 @@ DataAccessObject.updateAll = function(where, data, options, cb) {
|
|||
if (!(data instanceof Model)) {
|
||||
try {
|
||||
inst = new Model(data, {applyDefaultValues: false});
|
||||
ctx.data = inst.toObject(true);
|
||||
} catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
|
10
lib/list.js
10
lib/list.js
|
@ -67,8 +67,14 @@ function List(items, itemType, parent) {
|
|||
if (isClass(this.itemType)) {
|
||||
return new this.itemType(item);
|
||||
} else {
|
||||
if (Array.isArray(item)) return item;
|
||||
else return this.itemType(item);
|
||||
if (Array.isArray(item)) {
|
||||
return item;
|
||||
} else if (this.itemType === Date) {
|
||||
if (item === null) return null;
|
||||
return new Date(item);
|
||||
} else {
|
||||
return this.itemType(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1095,21 +1095,89 @@ describe('basic-querying', function() {
|
|||
});
|
||||
});
|
||||
|
||||
context('regexp operator', function() {
|
||||
const invalidDataTypes = [0, true, {}, [], Function, null];
|
||||
describe('updateAll', function() {
|
||||
let numAndDateModel, numAndDateArrayModel;
|
||||
|
||||
before(seed);
|
||||
|
||||
it('should return an error for invalid data types', function(done) {
|
||||
// `undefined` is not tested because the `removeUndefined` function
|
||||
// in `lib/dao.js` removes it before coercion
|
||||
async.each(invalidDataTypes, function(v, cb) {
|
||||
User.find({where: {name: {regexp: v}}}, function(err, users) {
|
||||
should.exist(err);
|
||||
cb();
|
||||
});
|
||||
}, done);
|
||||
before(function() {
|
||||
numAndDateModel = db.define('numAndDateModel', {
|
||||
dateProp: Date,
|
||||
numProp: Number,
|
||||
});
|
||||
numAndDateArrayModel = db.define('numAndDateArrayModel', {
|
||||
dateArray: [Date],
|
||||
numArray: [Number],
|
||||
});
|
||||
return db.automigrate(['numAndDateModel', 'numAndDateArrayModel']);
|
||||
});
|
||||
|
||||
it('coerces primitive datatypes on update', function() {
|
||||
const createDate = new Date('2019-02-21T12:00:00').toISOString();
|
||||
const createData = {
|
||||
dateProp: createDate,
|
||||
numProp: '1',
|
||||
};
|
||||
const updateDate = new Date('2019-04-15T12:00:00').toISOString();
|
||||
const updateData = {
|
||||
dateProp: updateDate,
|
||||
numProp: '3',
|
||||
};
|
||||
let createdId;
|
||||
return numAndDateModel.create(createData)
|
||||
.then((createdInstance) => {
|
||||
createdId = createdInstance.id;
|
||||
return numAndDateModel.updateAll({id: createdId}, updateData);
|
||||
}).then(() => {
|
||||
return numAndDateModel.findById(createdId);
|
||||
}).then((found) => {
|
||||
found.dateProp.should.deepEqual(new Date(updateDate));
|
||||
found.numProp.should.equal(3);
|
||||
});
|
||||
});
|
||||
|
||||
// PostgreSQL connector does not support arrays at the moment
|
||||
bdd.itIf(connectorCapabilities.supportsArrays !== false,
|
||||
'coerces primitive array datatypes on update', function() {
|
||||
const createDate = new Date('2019-02-21T12:00:00').toISOString();
|
||||
const createData = {
|
||||
dateArray: [createDate, createDate],
|
||||
numArray: ['1', '2'],
|
||||
};
|
||||
const updateDate = new Date('2019-04-15T12:00:00').toISOString();
|
||||
const updateData = {
|
||||
dateArray: [updateDate, updateDate],
|
||||
numArray: ['3', '4'],
|
||||
};
|
||||
let createdId;
|
||||
return numAndDateArrayModel.create(createData)
|
||||
.then((createdInstance) => {
|
||||
createdId = createdInstance.id;
|
||||
return numAndDateArrayModel.updateAll({id: createdId}, updateData);
|
||||
}).then(() => {
|
||||
return numAndDateArrayModel.findById(createdId);
|
||||
}).then((found) => {
|
||||
found.dateArray[0].should.deepEqual(new Date(updateDate));
|
||||
found.dateArray[1].should.deepEqual(new Date(updateDate));
|
||||
found.numArray[0].should.equal(3);
|
||||
found.numArray[1].should.equal(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('regexp operator', function() {
|
||||
const invalidDataTypes = [0, true, {}, [], Function, null];
|
||||
|
||||
before(seed);
|
||||
|
||||
it('should return an error for invalid data types', function(done) {
|
||||
// `undefined` is not tested because the `removeUndefined` function
|
||||
// in `lib/dao.js` removes it before coercion
|
||||
async.each(invalidDataTypes, function(v, cb) {
|
||||
User.find({where: {name: {regexp: v}}}, function(err, users) {
|
||||
should.exist(err);
|
||||
cb();
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/* global getSchema:false */
|
||||
const should = require('./init.js');
|
||||
|
||||
let db, Model;
|
||||
let db, Model, modelWithDecimalArray, dateArrayModel, numArrayModel;
|
||||
|
||||
describe('datatypes', function() {
|
||||
before(function(done) {
|
||||
|
@ -25,7 +25,24 @@ describe('datatypes', function() {
|
|||
nested: Nested,
|
||||
};
|
||||
Model = db.define('Model', modelTableSchema);
|
||||
db.automigrate(['Model'], done);
|
||||
modelWithDecimalArray = db.define('modelWithDecimalArray', {
|
||||
randomReview: {
|
||||
type: [String],
|
||||
mongodb: {
|
||||
dataType: 'Decimal128',
|
||||
},
|
||||
},
|
||||
});
|
||||
dateArrayModel = db.define('dateArrayModel', {
|
||||
bunchOfDates: [Date],
|
||||
bunchOfOtherDates: {
|
||||
type: [Date],
|
||||
},
|
||||
});
|
||||
numArrayModel = db.define('numArrayModel', {
|
||||
bunchOfNums: [Number],
|
||||
});
|
||||
db.automigrate(['Model', 'modelWithDecimalArray', 'dateArrayModel', 'numArrayModel'], done);
|
||||
});
|
||||
|
||||
it('should resolve top-level "type" property correctly', function() {
|
||||
|
@ -45,6 +62,41 @@ describe('datatypes', function() {
|
|||
});
|
||||
Account.definition.properties.item.type.should.not.equal(String);
|
||||
});
|
||||
it('should resolve array prop with connector specific metadata', function() {
|
||||
const props = modelWithDecimalArray.definition.properties;
|
||||
props.randomReview.type.should.deepEqual(Array(String));
|
||||
props.randomReview.mongodb.should.deepEqual({dataType: 'Decimal128'});
|
||||
});
|
||||
|
||||
it('should coerce array of dates from string', function() {
|
||||
const dateVal = new Date('2019-02-21T12:00:00').toISOString();
|
||||
return dateArrayModel.create({
|
||||
bunchOfDates: [dateVal,
|
||||
dateVal,
|
||||
dateVal],
|
||||
bunchOfOtherDates: [dateVal,
|
||||
dateVal,
|
||||
dateVal],
|
||||
}).then((created) => {
|
||||
created.bunchOfDates[0].should.be.an.instanceOf(Date);
|
||||
created.bunchOfDates[0].should.deepEqual(new Date(dateVal));
|
||||
created.bunchOfOtherDates[0].should.be.an.instanceOf(Date);
|
||||
created.bunchOfOtherDates[0].should.deepEqual(new Date(dateVal));
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce array of numbers from string', function() {
|
||||
const dateVal = new Date('2019-02-21T12:00:00').toISOString();
|
||||
return numArrayModel.create({
|
||||
bunchOfNums: ['1',
|
||||
'2',
|
||||
'3'],
|
||||
})
|
||||
.then((created) => {
|
||||
created.bunchOfNums[0].should.be.an.instanceOf(Number);
|
||||
created.bunchOfNums[0].should.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 400 when property of type array is set to string value',
|
||||
function(done) {
|
||||
|
|
|
@ -2390,7 +2390,7 @@ describe('manipulation', function() {
|
|||
it('should not coerce invalid values provided in where conditions', function(done) {
|
||||
Person.update({name: 'Brett Boe'}, {dob: 'notadate'}, function(err) {
|
||||
should.exist(err);
|
||||
err.message.should.equal('Invalid date: notadate');
|
||||
err.message.should.equal('Invalid date: Invalid Date');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue