give options to validators #984

This commit is contained in:
RobinBiondi 2016-06-24 17:07:25 +02:00
parent baef033115
commit 35f14c38dc
3 changed files with 93 additions and 20 deletions

View File

@ -320,7 +320,7 @@ DataAccessObject.create = function(data, options, cb) {
} else {
cb(new ValidationError(obj), obj);
}
}, data);
}, data, options);
});
function create() {
@ -543,7 +543,7 @@ DataAccessObject.upsert = function(data, options, cb) {
}
}
callConnector();
}, update);
}, update, options);
}
function callConnector() {
@ -732,7 +732,7 @@ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) {
inst.isValid(function(valid) {
if (!valid) return cb(new ValidationError(inst), inst);
callConnector();
}, update);
}, update, options);
function callConnector() {
update = removeUndefined(update);
@ -1002,7 +1002,7 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
} else {
cb(new ValidationError(obj), obj);
}
}, data);
}, data, options);
});
});
} else {
@ -2189,7 +2189,7 @@ DataAccessObject.prototype.save = function(options, cb) {
}
cb(err, inst);
}
});
}, data, options);
// then save
function save() {
@ -2694,7 +2694,7 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
if (!valid) return cb(new ValidationError(inst), inst);
callConnector();
}, data);
}, data, options);
} else {
callConnector();
}
@ -2874,7 +2874,7 @@ function(data, options, cb) {
}
triggerSave();
}, data);
}, data, options);
} else {
triggerSave();
}

View File

@ -238,7 +238,7 @@ Validatable.validatesUniquenessOf = getConfigurator('uniqueness', { async: true
/*!
* Presence validator
*/
function validatePresence(attr, conf, err) {
function validatePresence(attr, conf, err, options) {
if (blank(this[attr])) {
err();
}
@ -247,7 +247,7 @@ function validatePresence(attr, conf, err) {
/*!
* Absence validator
*/
function validateAbsence(attr, conf, err) {
function validateAbsence(attr, conf, err, options) {
if (!blank(this[attr])) {
err();
}
@ -256,7 +256,7 @@ function validateAbsence(attr, conf, err) {
/*!
* Length validator
*/
function validateLength(attr, conf, err) {
function validateLength(attr, conf, err, options) {
if (nullCheck.call(this, attr, conf, err)) return;
var len = this[attr].length;
@ -274,7 +274,7 @@ function validateLength(attr, conf, err) {
/*!
* Numericality validator
*/
function validateNumericality(attr, conf, err) {
function validateNumericality(attr, conf, err, options) {
if (nullCheck.call(this, attr, conf, err)) return;
if (typeof this[attr] !== 'number') {
@ -288,7 +288,7 @@ function validateNumericality(attr, conf, err) {
/*!
* Inclusion validator
*/
function validateInclusion(attr, conf, err) {
function validateInclusion(attr, conf, err, options) {
if (nullCheck.call(this, attr, conf, err)) return;
if (!~conf.in.indexOf(this[attr])) {
@ -299,7 +299,7 @@ function validateInclusion(attr, conf, err) {
/*!
* Exclusion validator
*/
function validateExclusion(attr, conf, err) {
function validateExclusion(attr, conf, err, options) {
if (nullCheck.call(this, attr, conf, err)) return;
if (~conf.in.indexOf(this[attr])) {
@ -310,7 +310,7 @@ function validateExclusion(attr, conf, err) {
/*!
* Format validator
*/
function validateFormat(attr, conf, err) {
function validateFormat(attr, conf, err, options) {
if (nullCheck.call(this, attr, conf, err)) return;
if (typeof this[attr] === 'string') {
@ -325,14 +325,22 @@ function validateFormat(attr, conf, err) {
/*!
* Custom validator
*/
function validateCustom(attr, conf, err, done) {
function validateCustom(attr, conf, err, options, done) {
if (typeof options === 'function') {
done = options;
options = {};
}
conf.customValidator.call(this, err, done);
}
/*!
* Uniqueness validator
*/
function validateUniqueness(attr, conf, err, done) {
function validateUniqueness(attr, conf, err, options, done) {
if (typeof options === 'function') {
done = options;
options = {};
}
if (blank(this[attr])) {
return process.nextTick(done);
}
@ -349,7 +357,7 @@ function validateUniqueness(attr, conf, err, done) {
var idName = this.constructor.definition.idName();
var isNewRecord = this.isNewRecord();
this.constructor.find(cond, function(error, found) {
this.constructor.find(cond, options, function(error, found) {
if (error) {
err(error);
} else if (found.length > 1) {
@ -416,7 +424,8 @@ function getConfigurator(name, opts) {
* @param {Function} callback called with (valid)
* @returns {Boolean} True if no asynchronous validation is configured and all properties pass validation.
*/
Validatable.prototype.isValid = function(callback, data) {
Validatable.prototype.isValid = function(callback, data, options) {
options = options || {};
var valid = true, inst = this, wait = 0, async = false;
var validations = this.constructor.validations;
@ -455,7 +464,7 @@ Validatable.prototype.isValid = function(callback, data) {
async = true;
wait += 1;
process.nextTick(function() {
validationFailed(inst, attr, v, done);
validationFailed(inst, attr, v, options, done);
});
} else {
if (validationFailed(inst, attr, v)) {
@ -514,9 +523,14 @@ function cleanErrors(inst) {
});
}
function validationFailed(inst, attr, conf, cb) {
function validationFailed(inst, attr, conf, options, cb) {
var opts = conf.options || {};
if (typeof options === 'function') {
cb = options;
options = {};
}
if (typeof attr !== 'string') return false;
// here we should check skip validation conditions (if, unless)
@ -557,6 +571,7 @@ function validationFailed(inst, attr, conf, cb) {
if (kind !== false) inst.errors.add(attr, message, code);
fail = true;
});
validatorArguments.push(options);
if (cb) {
validatorArguments.push(function() {
cb(fail);

View File

@ -282,6 +282,64 @@ describe('validations', function() {
});
});
describe('validation with or without options', function() {
it('should work on update with options', function(done) {
delete User.validations;
User.validatesPresenceOf('name');
User.create({ name: 'Valid' }, function(e, d) {
d.updateAttribute('name', null, { options: 'options' }, function(e) {
should.exist(e);
e.should.be.instanceOf(Error);
e.should.be.instanceOf(ValidationError);
d.updateAttribute('name', 'Vasiliy', { options: 'options' }, function(e) {
should.not.exist(e);
done();
});
});
});
});
it('should work on update without options', function(done) {
delete User.validations;
User.validatesPresenceOf('name');
User.create({ name: 'Valid' }, function(e, d) {
d.updateAttribute('name', null, function(e) {
should.exist(e);
e.should.be.instanceOf(Error);
e.should.be.instanceOf(ValidationError);
d.updateAttribute('name', 'Vasiliy', function(e) {
should.not.exist(e);
done();
});
});
});
});
it('should work on create with options', function(done) {
delete User.validations;
User.validatesPresenceOf('name');
User.create(function(e, u) {
should.exist(e);
User.create({ name: 'Valid' }, { options: 'options' }, function(e, d) {
should.not.exist(e);
done();
});
});
});
it('should work on create without options', function(done) {
delete User.validations;
User.validatesPresenceOf('name');
User.create(function(e, u) {
should.exist(e);
User.create({ name: 'Valid' }, function(e, d) {
should.not.exist(e);
done();
});
});
});
});
describe('presence', function() {
it('should validate presence', function() {
User.validatesPresenceOf('name', 'email');