commit
efeb59178f
|
@ -46,6 +46,20 @@ function Validatable() {
|
||||||
*/
|
*/
|
||||||
Validatable.validatesPresenceOf = getConfigurator('presence');
|
Validatable.validatesPresenceOf = getConfigurator('presence');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate absence of one or more specified properties.
|
||||||
|
* A model should not include a property to be considered valid; fails when validated field not blank.
|
||||||
|
*
|
||||||
|
* For example, validate absence of reserved
|
||||||
|
* ```
|
||||||
|
* Post.validatesAbsenceOf('reserved', { unless: 'special' });
|
||||||
|
*
|
||||||
|
* @param {String} propertyName One or more property names.
|
||||||
|
* @options {Object} errMsg Optional custom error message. Default is "can't be set"
|
||||||
|
* @property {String} message Error message to use instead of default.
|
||||||
|
*/
|
||||||
|
Validatable.validatesAbsenceOf = getConfigurator('absence');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate length. Require a property length to be within a specified range.
|
* Validate length. Require a property length to be within a specified range.
|
||||||
* Three kinds of validations: min, max, is.
|
* Three kinds of validations: min, max, is.
|
||||||
|
@ -225,6 +239,15 @@ function validatePresence(attr, conf, err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Absence validator
|
||||||
|
*/
|
||||||
|
function validateAbsence(attr, conf, err) {
|
||||||
|
if (!blank(this[attr])) {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Length validator
|
* Length validator
|
||||||
*/
|
*/
|
||||||
|
@ -305,6 +328,9 @@ function validateCustom(attr, conf, err, done) {
|
||||||
* Uniqueness validator
|
* Uniqueness validator
|
||||||
*/
|
*/
|
||||||
function validateUniqueness(attr, conf, err, done) {
|
function validateUniqueness(attr, conf, err, done) {
|
||||||
|
if (blank(this[attr])) {
|
||||||
|
return process.nextTick(done);
|
||||||
|
}
|
||||||
var cond = {where: {}};
|
var cond = {where: {}};
|
||||||
cond.where[attr] = this[attr];
|
cond.where[attr] = this[attr];
|
||||||
|
|
||||||
|
@ -331,6 +357,7 @@ function validateUniqueness(attr, conf, err, done) {
|
||||||
|
|
||||||
var validators = {
|
var validators = {
|
||||||
presence: validatePresence,
|
presence: validatePresence,
|
||||||
|
absence: validateAbsence,
|
||||||
length: validateLength,
|
length: validateLength,
|
||||||
numericality: validateNumericality,
|
numericality: validateNumericality,
|
||||||
inclusion: validateInclusion,
|
inclusion: validateInclusion,
|
||||||
|
@ -469,8 +496,11 @@ function validationFailed(inst, v, cb) {
|
||||||
|
|
||||||
// here we should check skip validation conditions (if, unless)
|
// here we should check skip validation conditions (if, unless)
|
||||||
// that can be specified in conf
|
// that can be specified in conf
|
||||||
if (skipValidation(inst, conf, 'if')) return false;
|
if (skipValidation(inst, conf, 'if')
|
||||||
if (skipValidation(inst, conf, 'unless')) return false;
|
|| skipValidation(inst, conf, 'unless')) {
|
||||||
|
if (cb) cb(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var fail = false;
|
var fail = false;
|
||||||
var validator = validators[conf.validation];
|
var validator = validators[conf.validation];
|
||||||
|
@ -478,7 +508,7 @@ function validationFailed(inst, v, cb) {
|
||||||
validatorArguments.push(attr);
|
validatorArguments.push(attr);
|
||||||
validatorArguments.push(conf);
|
validatorArguments.push(conf);
|
||||||
validatorArguments.push(function onerror(kind) {
|
validatorArguments.push(function onerror(kind) {
|
||||||
var message, code = conf.validation;
|
var message, code = conf.code || conf.validation;
|
||||||
if (conf.message) {
|
if (conf.message) {
|
||||||
message = conf.message;
|
message = conf.message;
|
||||||
}
|
}
|
||||||
|
@ -499,7 +529,7 @@ function validationFailed(inst, v, cb) {
|
||||||
message = 'is invalid';
|
message = 'is invalid';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inst.errors.add(attr, message, code);
|
if (kind !== false) inst.errors.add(attr, message, code);
|
||||||
fail = true;
|
fail = true;
|
||||||
});
|
});
|
||||||
if (cb) {
|
if (cb) {
|
||||||
|
@ -532,6 +562,7 @@ function skipValidation(inst, conf, kind) {
|
||||||
|
|
||||||
var defaultMessages = {
|
var defaultMessages = {
|
||||||
presence: 'can\'t be blank',
|
presence: 'can\'t be blank',
|
||||||
|
absence: 'can\'t be set',
|
||||||
length: {
|
length: {
|
||||||
min: 'too short',
|
min: 'too short',
|
||||||
max: 'too long',
|
max: 'too long',
|
||||||
|
|
|
@ -159,6 +159,20 @@ describe('validations', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('absence', function () {
|
||||||
|
|
||||||
|
it('should validate absence', function () {
|
||||||
|
User.validatesAbsenceOf('reserved', { if: 'locked' });
|
||||||
|
var u = new User({reserved: 'foo', locked: true});
|
||||||
|
u.isValid().should.not.be.true;
|
||||||
|
u.reserved = null;
|
||||||
|
u.isValid().should.be.true;
|
||||||
|
var u = new User({reserved: 'foo', locked: false});
|
||||||
|
u.isValid().should.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('uniqueness', function () {
|
describe('uniqueness', function () {
|
||||||
it('should validate uniqueness', function (done) {
|
it('should validate uniqueness', function (done) {
|
||||||
|
@ -227,6 +241,33 @@ describe('validations', function () {
|
||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip blank values', function (done) {
|
||||||
|
User.validatesUniquenessOf('email');
|
||||||
|
var u = new User({email: ' '});
|
||||||
|
Boolean(u.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
u.save(function () {
|
||||||
|
var u2 = new User({email: null});
|
||||||
|
u2.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})).should.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with if/unless', function (done) {
|
||||||
|
User.validatesUniquenessOf('email', {
|
||||||
|
if: function() { return true; },
|
||||||
|
unless: function() { return false; }
|
||||||
|
});
|
||||||
|
var u = new User({email: 'hello'});
|
||||||
|
Boolean(u.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
done();
|
||||||
|
})).should.be.false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('format', function () {
|
describe('format', function () {
|
||||||
|
@ -251,7 +292,40 @@ describe('validations', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('custom', function () {
|
describe('custom', function () {
|
||||||
it('should validate using custom sync validation');
|
it('should validate using custom sync validation', function() {
|
||||||
it('should validate using custom async validation');
|
User.validate('email', function (err) {
|
||||||
|
if (this.email === 'hello') err();
|
||||||
|
}, { code: 'invalid-email' });
|
||||||
|
var u = new User({email: 'hello'});
|
||||||
|
Boolean(u.isValid()).should.be.false;
|
||||||
|
u.errors.codes.should.eql({ email: ['invalid-email'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate and return detailed error messages', function() {
|
||||||
|
User.validate('global', function (err) {
|
||||||
|
if (this.email === 'hello' || this.email === 'hey') {
|
||||||
|
this.errors.add('email', 'Cannot be `' + this.email + '`', 'invalid-email');
|
||||||
|
err(false); // false: prevent global error message
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var u = new User({email: 'hello'});
|
||||||
|
Boolean(u.isValid()).should.be.false;
|
||||||
|
u.errors.should.eql({ email: ['Cannot be `hello`'] });
|
||||||
|
u.errors.codes.should.eql({ email: ['invalid-email'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should validate using custom async validation', function(done) {
|
||||||
|
User.validateAsync('email', function (err, next) {
|
||||||
|
process.nextTick(next);
|
||||||
|
}, {
|
||||||
|
if: function() { return true; },
|
||||||
|
unless: function() { return false; }
|
||||||
|
});
|
||||||
|
var u = new User({email: 'hello'});
|
||||||
|
Boolean(u.isValid(function (valid) {
|
||||||
|
valid.should.be.true;
|
||||||
|
done();
|
||||||
|
})).should.be.false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue