Merge pull request #986 from robinbiondi/postgresConcurency

Fix #984 Give request options(ex: transactions) to validators
This commit is contained in:
Raymond Feng 2016-06-24 14:42:50 -07:00 committed by GitHub
commit 6736d72b98
3 changed files with 93 additions and 20 deletions

View File

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

View File

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