From 3a355851b64ad0ff3631582592282351e7a546fb Mon Sep 17 00:00:00 2001 From: Anatoliy Chakkaev Date: Thu, 4 Apr 2013 19:31:07 +0400 Subject: [PATCH] ValidationError instead Error --- lib/model.js | 10 ++++++---- lib/validations.js | 40 ++++++++++++++++++++++++++++++++++------ test/validations.test.js | 16 +++++++++++++++- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/lib/model.js b/lib/model.js index 9fbcee74..d7e391e0 100644 --- a/lib/model.js +++ b/lib/model.js @@ -4,7 +4,9 @@ var util = require('util'); var i8n = require('inflection'); var jutil = require('./jutil.js'); -var Validatable = require('./validations.js').Validatable; +var validations = require('./validations.js'); +var Validatable = validations.Validatable; +var ValidationError = validations.ValidationError; var List = require('./list.js'); var Hookable = require('./hooks.js').Hookable; var DEFAULT_CACHE_LIMIT = 1000; @@ -214,7 +216,7 @@ AbstractClass.create = function (data, callback) { if (valid) { create(); } else { - callback(new Error('Validation error'), obj); + callback(new ValidationError(obj), obj); } }, data); @@ -657,7 +659,7 @@ AbstractClass.prototype.save = function (options, callback) { if (valid) { save(); } else { - var err = new Error('Validation error'); + var err = new ValidationError(inst); // throws option is dangerous for async usage if (options.throws) { throw err; @@ -810,7 +812,7 @@ AbstractClass.prototype.updateAttributes = function updateAttributes(data, cb) { inst.isValid(function (valid) { if (!valid) { if (cb) { - cb(new Error('Validation error'), inst); + cb(new ValidationError(inst), inst); } } else { inst.trigger('save', function (saveDone) { diff --git a/lib/validations.js b/lib/validations.js index 33573a41..153daf01 100644 --- a/lib/validations.js +++ b/lib/validations.js @@ -1,4 +1,5 @@ exports.Validatable = Validatable; +exports.ValidationError = ValidationError; /** * Validation encapsulated in this abstract class. @@ -432,7 +433,7 @@ function validationFailed(inst, v, cb) { validatorArguments.push(attr); validatorArguments.push(conf); validatorArguments.push(function onerror(kind) { - var message; + var message, code = conf.validation; if (conf.message) { message = conf.message; } @@ -443,6 +444,7 @@ function validationFailed(inst, v, cb) { message = 'is invalid'; } if (kind) { + code += '.' + kind; if (message[kind]) { // get deeper message = message[kind]; @@ -452,7 +454,7 @@ function validationFailed(inst, v, cb) { message = 'is invalid'; } } - inst.errors.add(attr, message); + inst.errors.add(attr, message, code); fail = true; }); if (cb) { @@ -562,13 +564,39 @@ function configure(cls, validation, args, opts) { } function Errors() { + Object.defineProperty(this, 'codes', { + enumerable: false, + configurable: true, + value: {} + }); } -Errors.prototype.add = function (field, message) { +Errors.prototype.add = function (field, message, code) { + code = code || 'invalid'; if (!this[field]) { - this[field] = [message]; - } else { - this[field].push(message); + this[field] = []; + this.codes[field] = []; } + this[field].push(message); + this.codes[field].push(code); }; +function ErrorCodes(messages) { + var c = this; + Object.keys(messages).forEach(function(field) { + c[field] = messages[field].codes; + }); +} + +function ValidationError(obj) { + if (!(this instanceof ValidationError)) return new ValidationError(obj); + + this.name = 'ValidationError'; + this.message = 'Validation error'; + this.statusCode = 400; + this.codes = obj.errors && obj.errors.codes; + + Error.call(this); +}; + +ValidationError.prototype.__proto__ = Error.prototype; diff --git a/test/validations.test.js b/test/validations.test.js index bea50657..7faa9c02 100644 --- a/test/validations.test.js +++ b/test/validations.test.js @@ -1,4 +1,5 @@ var j = require('../'), db, User; +var ValidationError = require('../lib/validations.js').ValidationError; var should = require('should'); function getValidAttributes() { @@ -63,8 +64,9 @@ describe('validations', function() { describe('lifecycle', function() { it('should work on create', function(done) { + delete User._validations; User.validatesPresenceOf('name'); - User.create(function(e) { + User.create(function(e, u) { should.exist(e); User.create({name: 'Valid'}, function(e, d) { should.not.exist(e); @@ -74,11 +76,13 @@ describe('validations', function() { }); it('should work on update', 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(); @@ -87,6 +91,16 @@ describe('validations', function() { }); }); + it('should return error code', function(done) { + delete User._validations; + User.validatesPresenceOf('name'); + User.create(function(e, u) { + should.exist(e); + e.codes.name.should.eql(['presence']); + done(); + }); + }); + }); });