Merge pull request #259 from fabien/fix/refactor-validations

Validations configuration as object
This commit is contained in:
Raymond Feng 2014-08-31 08:37:03 -07:00
commit 6527bd0605
5 changed files with 54 additions and 36 deletions

View File

@ -8,8 +8,7 @@ module.exports = DataAccessObject;
* Module dependencies * Module dependencies
*/ */
var jutil = require('./jutil'); var jutil = require('./jutil');
var validations = require('./validations.js'); var ValidationError = require('./validations').ValidationError;
var ValidationError = validations.ValidationError;
var Relation = require('./relations.js'); var Relation = require('./relations.js');
var Inclusion = require('./include.js'); var Inclusion = require('./include.js');
var List = require('./list.js'); var List = require('./list.js');

View File

@ -11,7 +11,7 @@ var util = require('util');
var jutil = require('./jutil'); var jutil = require('./jutil');
var List = require('./list'); var List = require('./list');
var Hookable = require('./hooks'); var Hookable = require('./hooks');
var validations = require('./validations.js'); var validations = require('./validations');
var _extend = util._extend; var _extend = util._extend;
// Set up an object for quick lookup // Set up an object for quick lookup

View File

@ -1,4 +1,6 @@
var util = require('util'); var util = require('util');
var extend = util._extend;
/*! /*!
* Module exports * Module exports
*/ */
@ -369,7 +371,9 @@ var validators = {
function getConfigurator(name, opts) { function getConfigurator(name, opts) {
return function () { return function () {
configure(this, name, arguments, opts); var args = Array.prototype.slice.call(arguments);
args[1] = args[1] || {};
configure(this, name, args, opts);
}; };
} }
@ -407,9 +411,10 @@ function getConfigurator(name, opts) {
*/ */
Validatable.prototype.isValid = function (callback, data) { Validatable.prototype.isValid = function (callback, data) {
var valid = true, inst = this, wait = 0, async = false; var valid = true, inst = this, wait = 0, async = false;
var validations = this.constructor.validations;
// exit with success when no errors // exit with success when no errors
if (!this.constructor._validations) { if (typeof validations !== 'object') {
cleanErrors(this); cleanErrors(this);
if (callback) { if (callback) {
this.trigger('validate', function (validationsDone) { this.trigger('validate', function (validationsDone) {
@ -431,21 +436,25 @@ Validatable.prototype.isValid = function (callback, data) {
var inst = this, var inst = this,
asyncFail = false; asyncFail = false;
this.constructor._validations.forEach(function (v) { var attrs = Object.keys(validations || {});
if (v[2] && v[2].async) {
async = true; attrs.forEach(function(attr) {
wait += 1; var attrValidations = validations[attr] || [];
process.nextTick(function () { attrValidations.forEach(function(v) {
validationFailed(inst, v, done); if (v.options && v.options.async) {
}); async = true;
} else { wait += 1;
if (validationFailed(inst, v)) { process.nextTick(function () {
valid = false; validationFailed(inst, attr, v, done);
});
} else {
if (validationFailed(inst, attr, v)) {
valid = false;
}
} }
} });
}); });
if (!async) { if (!async) {
validationsDone.call(inst, function () { validationsDone.call(inst, function () {
if (valid) cleanErrors(inst); if (valid) cleanErrors(inst);
@ -487,11 +496,9 @@ function cleanErrors(inst) {
}); });
} }
function validationFailed(inst, v, cb) { function validationFailed(inst, attr, conf, cb) {
var attr = v[0]; var opts = conf.options || {};
var conf = v[1];
var opts = v[2] || {};
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)
@ -615,12 +622,12 @@ function blank(v) {
} }
function configure(cls, validation, args, opts) { function configure(cls, validation, args, opts) {
if (!cls._validations) { if (!cls.validations) {
Object.defineProperty(cls, '_validations', { Object.defineProperty(cls, 'validations', {
writable: true, writable: true,
configurable: true, configurable: true,
enumerable: false, enumerable: false,
value: [] value: {}
}); });
} }
args = [].slice.call(args); args = [].slice.call(args);
@ -634,9 +641,13 @@ function configure(cls, validation, args, opts) {
conf.customValidator = args.pop(); conf.customValidator = args.pop();
} }
conf.validation = validation; conf.validation = validation;
args.forEach(function (attr) { var attr = args[0];
cls._validations.push([attr, conf, opts]); if (typeof attr === 'string') {
}); var validation = extend({}, conf);
validation.options = opts || {};
cls.validations[attr] = cls.validations[attr] || [];
cls.validations[attr].push(validation);
}
} }
function Errors() { function Errors() {

View File

@ -102,7 +102,7 @@ describe('manipulation', function () {
Person.validatesPresenceOf('name'); Person.validatesPresenceOf('name');
Person.create(batch,function (errors, persons) { Person.create(batch,function (errors, persons) {
delete Person._validations; delete Person.validations;
should.exist(errors); should.exist(errors);
errors.should.have.lengthOf(batch.length); errors.should.have.lengthOf(batch.length);
should.not.exist(errors[0]); should.not.exist(errors[0]);

View File

@ -39,7 +39,7 @@ describe('validations', function () {
beforeEach(function (done) { beforeEach(function (done) {
User.destroyAll(function () { User.destroyAll(function () {
delete User._validations; delete User.validations;
done(); done();
}); });
}); });
@ -67,7 +67,7 @@ describe('validations', function () {
describe('lifecycle', function () { describe('lifecycle', function () {
it('should work on create', function (done) { it('should work on create', function (done) {
delete User._validations; delete User.validations;
User.validatesPresenceOf('name'); User.validatesPresenceOf('name');
User.create(function (e, u) { User.create(function (e, u) {
should.exist(e); should.exist(e);
@ -79,7 +79,7 @@ describe('validations', function () {
}); });
it('should work on update', function (done) { it('should work on update', function (done) {
delete User._validations; delete User.validations;
User.validatesPresenceOf('name'); User.validatesPresenceOf('name');
User.create({name: 'Valid'}, function (e, d) { User.create({name: 'Valid'}, function (e, d) {
d.updateAttribute('name', null, function (e) { d.updateAttribute('name', null, function (e) {
@ -95,7 +95,7 @@ describe('validations', function () {
}); });
it('should return error code', function (done) { it('should return error code', function (done) {
delete User._validations; delete User.validations;
User.validatesPresenceOf('name'); User.validatesPresenceOf('name');
User.create(function (e, u) { User.create(function (e, u) {
should.exist(e); should.exist(e);
@ -112,7 +112,7 @@ describe('validations', function () {
}); });
it('should include validation messages in err.message', function(done) { it('should include validation messages in err.message', function(done) {
delete User._validations; delete User.validations;
User.validatesPresenceOf('name'); User.validatesPresenceOf('name');
User.create(function (e, u) { User.create(function (e, u) {
should.exist(e); should.exist(e);
@ -122,7 +122,7 @@ describe('validations', function () {
}); });
it('should include model name in err.message', function(done) { it('should include model name in err.message', function(done) {
delete User._validations; delete User.validations;
User.validatesPresenceOf('name'); User.validatesPresenceOf('name');
User.create(function (e, u) { User.create(function (e, u) {
should.exist(e); should.exist(e);
@ -130,6 +130,14 @@ describe('validations', function () {
done(); done();
}); });
}); });
it('should return validation metadata', function() {
var expected = {name:[{validation: 'presence', options: {}}]};
delete User.validations;
User.validatesPresenceOf('name');
var validations = User.validations;
validations.should.eql(expected);
});
}); });
}); });