Merge pull request #1339 from strongloop/invalid-dates

replace exception thrown for invalid dates
This commit is contained in:
Diana Lau 2017-04-21 20:13:45 +00:00 committed by GitHub
commit ee254a1812
5 changed files with 93 additions and 30 deletions

View File

@ -426,6 +426,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
var requiredOptions = typeof prop.required === 'object' ? prop.required : undefined;
ModelClass.validatesPresenceOf(propertyName, requiredOptions);
}
if (DataType === Date) ModelClass.validatesDateOf(propertyName);
Object.defineProperty(ModelClass.prototype, propertyName, {
get: function() {
@ -526,10 +527,8 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
// DataType for Date
function DateType(arg) {
if (arg === null) return null;
var d = new Date(arg);
if (isNaN(d.getTime())) {
throw new Error(g.f('Invalid date: %s', arg));
}
return d;
}

View File

@ -243,6 +243,7 @@ Validatable.validateAsync = getConfigurator('custom', {async: true});
*/
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});
Validatable.validatesDateOf = getConfigurator('date');
// implementation of validators
/*!
@ -383,6 +384,16 @@ function validateUniqueness(attr, conf, err, options, done) {
}.bind(this));
}
/*!
* Date validator
*/
function validateDate(attr, conf, err) {
if (this[attr] === null || this[attr] === undefined) return;
var date = new Date(this[attr]);
if (isNaN(date.getTime())) return err();
}
var validators = {
presence: validatePresence,
absence: validateAbsence,
@ -393,6 +404,7 @@ var validators = {
format: validateFormat,
custom: validateCustom,
uniqueness: validateUniqueness,
date: validateDate,
};
function getConfigurator(name, opts) {
@ -631,6 +643,7 @@ var defaultMessages = {
inclusion: 'is not included in the list',
exclusion: 'is reserved',
uniqueness: 'is not unique',
date: 'is not a valid date',
};
/**
@ -841,7 +854,7 @@ function formatPropertyError(propertyName, propertyValue, errorMessage) {
if (valueType === 'string') {
formattedValue = JSON.stringify(truncatePropertyString(propertyValue));
} else if (propertyValue instanceof Date) {
formattedValue = propertyValue.toISOString();
formattedValue = isNaN(propertyValue.getTime()) ? propertyValue.toString() : propertyValue.toISOString();
} else if (valueType === 'object') {
// objects and arrays
formattedValue = util.inspect(propertyValue, {

View File

@ -54,17 +54,6 @@ describe('datatypes', function() {
done();
});
it('throws an error when property of type Date is set to an invalid value',
function() {
var myModel = db.define('myModel', {
date: {type: Date},
});
(function() {
myModel.create({date: 'invalid'});
}).should.throw({message: 'Invalid date: invalid'});
});
it('should keep types when get read data from db', function(done) {
var d = new Date, id;

View File

@ -687,15 +687,6 @@ describe('manipulation', function() {
});
});
it('should fail if field validation fails', function(done) {
person.updateAttributes({'name': 'John', dob: 'notadate'},
function(err, p) {
should.exist(err);
err.message.should.equal('Invalid date: notadate');
done();
});
});
it('has an alias "patchAttributes"', function(done) {
person.updateAttributes.should.equal(person.patchAttributes);
done();
@ -2085,12 +2076,9 @@ describe('manipulation', function() {
p1 = new Person({name: 'John', dob: undefined});
p1.should.have.property('dob', undefined);
try {
p1 = new Person({name: 'John', dob: 'X'});
throw new Error('new Person() should have thrown');
} catch (e) {
e.should.be.eql(new Error('Invalid date: X'));
}
p1 = new Person({name: 'John', dob: 'X'});
p1.should.have.property('dob');
p1.dob.toString().should.be.eql('Invalid Date');
});
});

View File

@ -823,4 +823,78 @@ describe('validations', function() {
return err.message.replace(/^.*Details: /, '');
}
});
describe('date', function() {
it('should validate a date object', function() {
User.validatesDateOf('updatedAt');
var u = new User({updatedAt: new Date()});
u.isValid().should.be.true;
});
it('should validate a date string', function() {
User.validatesDateOf('updatedAt');
var u = new User({updatedAt: '2000-01-01'});
u.isValid().should.be.true;
});
it('should validate a null date', function() {
User.validatesDateOf('updatedAt');
var u = new User({updatedAt: null});
u.isValid().should.be.true;
});
it('should validate an undefined date', function() {
User.validatesDateOf('updatedAt');
var u = new User({updatedAt: undefined});
u.isValid().should.be.true;
});
it('should validate an invalid date string', function() {
User.validatesDateOf('updatedAt');
var u = new User({updatedAt: 'invalid date string'});
u.isValid().should.not.be.true;
u.errors.should.eql({
updatedAt: ['is not a valid date'],
codes: {
updatedAt: ['date'],
},
});
});
it('should attach validation by default to all date properties', function() {
var AnotherUser = db.define('User', {
email: String,
name: String,
password: String,
state: String,
age: Number,
gender: String,
domain: String,
pendingPeriod: Number,
createdByAdmin: Boolean,
createdByScript: Boolean,
updatedAt: Date,
});
var u = new AnotherUser({updatedAt: 'invalid date string'});
u.isValid().should.not.be.true;
u.errors.should.eql({
updatedAt: ['is not a valid date'],
codes: {
updatedAt: ['date'],
},
});
});
it('should overwrite default blank message with custom format message', function() {
var CUSTOM_MESSAGE = 'custom validation message';
User.validatesDateOf('updatedAt', {message: CUSTOM_MESSAGE});
var u = new User({updatedAt: 'invalid date string'});
u.isValid().should.not.be.true;
u.errors.should.eql({
updatedAt: [CUSTOM_MESSAGE],
codes: {
updatedAt: ['date'],
},
});
});
});
});