Skip to content

Commit

Permalink
Merge pull request #1339 from strongloop/invalid-dates
Browse files Browse the repository at this point in the history
replace exception thrown for invalid dates
  • Loading branch information
dhmlau committed Apr 21, 2017
2 parents bcc5b55 + a488a71 commit ee254a1
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 30 deletions.
5 changes: 2 additions & 3 deletions lib/model-builder.js
Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}

Expand Down
15 changes: 14 additions & 1 deletion lib/validations.js
Expand Up @@ -243,6 +243,7 @@ Validatable.validateAsync = getConfigurator('custom', {async: true});
*/
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});

Validatable.validatesDateOf = getConfigurator('date');
// implementation of validators

/*!
Expand Down Expand Up @@ -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,
Expand All @@ -393,6 +404,7 @@ var validators = {
format: validateFormat,
custom: validateCustom,
uniqueness: validateUniqueness,
date: validateDate,
};

function getConfigurator(name, opts) {
Expand Down Expand Up @@ -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',
};

/**
Expand Down Expand Up @@ -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, {
Expand Down
11 changes: 0 additions & 11 deletions test/datatype.test.js
Expand Up @@ -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;

Expand Down
18 changes: 3 additions & 15 deletions test/manipulation.test.js
Expand Up @@ -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();
Expand Down Expand Up @@ -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');
});
});

Expand Down
74 changes: 74 additions & 0 deletions test/validations.test.js
Expand Up @@ -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'],
},
});
});
});
});

0 comments on commit ee254a1

Please sign in to comment.