waterline
Advanced tools
Comparing version 0.13.3 to 0.13.4
@@ -238,2 +238,6 @@ /** | ||
// Declare var to flag whether or not an attribute should have validation rules applied. | ||
// This will typically be the case for primary keys and generic attributes under certain conditions. | ||
var doCheckForRuleViolations = false; | ||
// If this value is `undefined`, then bail early, indicating that it should be ignored. | ||
@@ -282,2 +286,7 @@ if (_.isUndefined(value)) { | ||
// Primary key attributes should have validation rules applied if they have any. | ||
if (!_.isUndefined(correspondingAttrDef.validations)) { | ||
doCheckForRuleViolations = true; | ||
} | ||
try { | ||
@@ -547,59 +556,61 @@ value = normalizePkValue(value, correspondingAttrDef.type); | ||
// ┌─┐┬ ┬┌─┐┌─┐┬┌─ ┌─┐┌─┐┬─┐ ╦═╗╦ ╦╦ ╔═╗ ╦ ╦╦╔═╗╦ ╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ | ||
// │ ├─┤├┤ │ ├┴┐ ├┤ │ │├┬┘ ╠╦╝║ ║║ ║╣ ╚╗╔╝║║ ║║ ╠═╣ ║ ║║ ║║║║╚═╗ | ||
// └─┘┴ ┴└─┘└─┘┴ ┴ └ └─┘┴└─ ╩╚═╚═╝╩═╝╚═╝ ╚╝ ╩╚═╝╩═╝╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ | ||
// If appropriate, strictly enforce our (potentially-mildly-coerced) value | ||
// vs. the validation ruleset defined on the corresponding attribute. | ||
// Then, if there are any rule violations, stick them in an Error and throw it. | ||
// Decide whether validation rules should be checked for this attribute. | ||
// | ||
// > • High-level validation rules are ALWAYS skipped for `null`. | ||
// > • If there is no `validations` attribute key, then there's nothing for us to do here. | ||
// > • If there is no `validations` attribute key, then there's nothing for us to check. | ||
doCheckForRuleViolations = !_.isNull(value) && !_.isUndefined(correspondingAttrDef.validations); | ||
}//</else (i.e. corresponding attr def is just a normal attr--not an association or primary key)> | ||
// ┌─┐┬ ┬┌─┐┌─┐┬┌─ ┌─┐┌─┐┬─┐ ╦═╗╦ ╦╦ ╔═╗ ╦ ╦╦╔═╗╦ ╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ | ||
// │ ├─┤├┤ │ ├┴┐ ├┤ │ │├┬┘ ╠╦╝║ ║║ ║╣ ╚╗╔╝║║ ║║ ╠═╣ ║ ║║ ║║║║╚═╗ | ||
// └─┘┴ ┴└─┘└─┘┴ ┴ └ └─┘┴└─ ╩╚═╚═╝╩═╝╚═╝ ╚╝ ╩╚═╝╩═╝╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ | ||
// If appropriate, strictly enforce our (potentially-mildly-coerced) value | ||
// vs. the validation ruleset defined on the corresponding attribute. | ||
// Then, if there are any rule violations, stick them in an Error and throw it. | ||
if (doCheckForRuleViolations) { | ||
var ruleset = correspondingAttrDef.validations; | ||
var doCheckForRuleViolations = !_.isNull(value) && !_.isUndefined(ruleset); | ||
if (doCheckForRuleViolations) { | ||
var isRulesetDictionary = _.isObject(ruleset) && !_.isArray(ruleset) && !_.isFunction(ruleset); | ||
if (!isRulesetDictionary) { | ||
throw new Error('Consistency violation: If set, an attribute\'s validations ruleset (`validations`) should always be a dictionary (plain JavaScript object). But for the `'+modelIdentity+'` model\'s `'+supposedAttrName+'` attribute, it somehow ended up as this instead: '+util.inspect(correspondingAttrDef.validations,{depth:5})+''); | ||
} | ||
var isRulesetDictionary = _.isObject(ruleset) && !_.isArray(ruleset) && !_.isFunction(ruleset); | ||
if (!isRulesetDictionary) { | ||
throw new Error('Consistency violation: If set, an attribute\'s validations ruleset (`validations`) should always be a dictionary (plain JavaScript object). But for the `'+modelIdentity+'` model\'s `'+supposedAttrName+'` attribute, it somehow ended up as this instead: '+util.inspect(correspondingAttrDef.validations,{depth:5})+''); | ||
} | ||
var ruleViolations; | ||
try { | ||
ruleViolations = anchor(value, ruleset); | ||
// e.g. | ||
// [ { rule: 'isEmail', message: 'Value was not a valid email address.' }, ... ] | ||
} catch (e) { | ||
throw new Error( | ||
'Consistency violation: Unexpected error occurred when attempting to apply '+ | ||
'high-level validation rules from `'+modelIdentity+'` model\'s `'+supposedAttrName+'` '+ | ||
'attribute. '+e.stack | ||
); | ||
}//</ catch > | ||
var ruleViolations; | ||
try { | ||
ruleViolations = anchor(value, ruleset); | ||
// e.g. | ||
// [ { rule: 'isEmail', message: 'Value was not a valid email address.' }, ... ] | ||
} catch (e) { | ||
throw new Error( | ||
'Consistency violation: Unexpected error occurred when attempting to apply '+ | ||
'high-level validation rules from `'+modelIdentity+'` model\'s `'+supposedAttrName+'` '+ | ||
'attribute. '+e.stack | ||
); | ||
}//</ catch > | ||
if (ruleViolations.length > 0) { | ||
if (ruleViolations.length > 0) { | ||
// Format rolled-up summary for use in our error message. | ||
// e.g. | ||
// ``` | ||
// • Value was not in the configured whitelist (delinquent, new, paid) | ||
// • Value was an empty string. | ||
// ``` | ||
var summary = _.reduce(ruleViolations, function (memo, violation){ | ||
memo += ' • '+violation.message+'\n'; | ||
return memo; | ||
}, ''); | ||
// Format rolled-up summary for use in our error message. | ||
// e.g. | ||
// ``` | ||
// • Value was not in the configured whitelist (delinquent, new, paid) | ||
// • Value was an empty string. | ||
// ``` | ||
var summary = _.reduce(ruleViolations, function (memo, violation){ | ||
memo += ' • '+violation.message+'\n'; | ||
return memo; | ||
}, ''); | ||
throw flaverr({ | ||
code: 'E_VIOLATES_RULES', | ||
ruleViolations: ruleViolations | ||
}, new Error( | ||
'Violated one or more validation rules:\n'+ | ||
summary | ||
)); | ||
}//-• | ||
throw flaverr({ | ||
code: 'E_VIOLATES_RULES', | ||
ruleViolations: ruleViolations | ||
}, new Error( | ||
'Violated one or more validation rules:\n'+ | ||
summary | ||
)); | ||
}//-• | ||
}//>-• </if (doCheckForRuleViolations) > | ||
}//>-• </if (doCheckForRuleViolations) > | ||
}//</else (i.e. corresponding attr def is just a normal attr--not an association or primary key)> | ||
// ███████╗███╗ ██╗ ██████╗██████╗ ██╗ ██╗██████╗ ████████╗ ██████╗ █████╗ ████████╗ █████╗ | ||
@@ -606,0 +617,0 @@ // ██╔════╝████╗ ██║██╔════╝██╔══██╗╚██╗ ██╔╝██╔══██╗╚══██╔══╝ ██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗ |
{ | ||
"name": "waterline", | ||
"description": "An ORM for Node.js and the Sails framework", | ||
"version": "0.13.3", | ||
"version": "0.13.4", | ||
"homepage": "http://waterlinejs.org", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
@@ -9,2 +9,3 @@ var assert = require('assert'); | ||
var person; | ||
var car; | ||
@@ -35,3 +36,19 @@ before(function(done) { | ||
var Car = Waterline.Model.extend({ | ||
identity: 'car', | ||
datastore: 'foo', | ||
primaryKey: 'id', | ||
attributes: { | ||
id: { | ||
type: 'string', | ||
required: true, | ||
validations: { | ||
minLength: 6 | ||
} | ||
} | ||
} | ||
}); | ||
waterline.registerModel(Person); | ||
waterline.registerModel(Car); | ||
@@ -44,3 +61,3 @@ var datastores = { | ||
waterline.initialize({ adapters: { foobar: { update: function(con, query, cb) { return cb(); } } }, datastores: datastores }, function(err, orm) { | ||
waterline.initialize({ adapters: { foobar: { update: function(con, query, cb) { return cb(); }, create: function(con, query, cb) { return cb(); } } }, datastores: datastores }, function(err, orm) { | ||
if (err) { | ||
@@ -50,2 +67,3 @@ return done(err); | ||
person = orm.collections.person; | ||
car = orm.collections.car; | ||
done(); | ||
@@ -55,2 +73,9 @@ }); | ||
it('should not return any errors when no validation rules are violated', function(done) { | ||
person.create({ sex: 'male' }).exec(function(err) { | ||
assert(!err); | ||
return done(); | ||
}); | ||
}); | ||
it('should return an Error with name `UsageError` when a required field is not present in a `create`', function(done) { | ||
@@ -99,3 +124,3 @@ person.create({}).exec(function(err) { | ||
it('should return an Error with name `UsageError` when a required string field is set to empty string in a `create`', function(done) { | ||
it('should return an Error with name `UsageError` when a required string field is set to empty string in a `update`', function(done) { | ||
person.update({}, { sex: '' }).exec(function(err) { | ||
@@ -109,3 +134,3 @@ assert(err); | ||
it('should return an Error with name `UsageError` when a field is set to the wrong type in a `create`', function(done) { | ||
it('should return an Error with name `UsageError` when a field is set to the wrong type in a `update`', function(done) { | ||
person.update({}, { age: 'bar' }).exec(function(err) { | ||
@@ -119,3 +144,3 @@ assert(err); | ||
it('should return an Error with name `UsageError` when a field fails a validation rule in a `create`', function(done) { | ||
it('should return an Error with name `UsageError` when a field fails a validation rule in a `update`', function(done) { | ||
person.update({}, { sex: 'bar' }).exec(function(err) { | ||
@@ -129,3 +154,20 @@ assert(err); | ||
it('should not return any errors when a primary key does not violate any validations.', function(done) { | ||
car.create({ id: 'foobarbax' }).exec(function(err) { | ||
assert(!err); | ||
return done(); | ||
}); | ||
}); | ||
it('should return an Error with name `UsageError` when a primary key fails a validation rule in a `create`', function(done) { | ||
car.create({ id: 'foo' }).exec(function(err) { | ||
assert(err); | ||
assert.equal(err.name, 'UsageError'); | ||
assert(err.message.match(/rule/)); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
}); |
1251050
21700