不要怂,就是干,撸起袖子干!

Commit 841ab0ce by Ram

Added validation to models using node-validator (https://github.com/chriso/node-validator).

To validate your models first define the validation for each field. For example:

<pre>
var User = sequelize.define 'User', {
        id: {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            primaryKey: true,
	},
        name: {
            type: Sequelize.STRING,
            allowNull: false,
            unique: true,
            validate: {
                len: {
                    args: 3,
                    msg: "Name must be atleast 3 characters in length"
		}
	    }
	},
        email: {
            type: Sequelize.STRING,
            allowNull: false,
            unique: true,
            validate: {
                len: {
                    args: [6, 128],
                    msg: "Email address must be between 6 and 128 characters in length"
		},
                isEmail: {
                    msg: "Email address must be valid"
		}
	    }
	},
        password: {
            type: Sequelize.STRING,
            allowNull: false,
            validate: {
                len: {
                    args: 3
		}
	    }
	}
}
</pre>

Any of the basic validation methods provided by the node-validation can be specified along with arguments, as shown above. The 'msg' key specifies the error message to return for a given validation if it fails. If this isn't provided then a default generic error message will be returned by the validation library.

To actually perform the validation, call the validate() method on your model instance once your model has been built. For example:

<pre>
# build user
var user = User.build({
    name : "test"
    email : "test"
    password : "test"
});

# validate
errors = user.validate();
if (errors)
    # errors is an object with the following structure:
    # { field name : [list of validation failure messages]
    for (var prop in errors) {
        if (errors.hasOwnProperty(prop))
		console.log("Errors for field " + prop + ": ");
		for (var i=0; i<errors[prop].length; ++i) {
			console.log("\t" + errors[prop][i]);
		}
    }
else
    # errors is null, which means validation succeeded
</pre>
1 parent 3e57b469
...@@ -15,6 +15,9 @@ module.exports = (function() { ...@@ -15,6 +15,9 @@ module.exports = (function() {
this.modelManager = null // defined by model-manager during addModel this.modelManager = null // defined by model-manager during addModel
this.associations = {} this.associations = {}
// extract validation
this.validate = this.options.validate || {}
addDefaultAttributes.call(this) addDefaultAttributes.call(this)
addOptionalClassMethods.call(this) addOptionalClassMethods.call(this)
findAutoIncrementField.call(this) findAutoIncrementField.call(this)
...@@ -126,12 +129,17 @@ module.exports = (function() { ...@@ -126,12 +129,17 @@ module.exports = (function() {
if(typeof instance[name] == 'undefined') { if(typeof instance[name] == 'undefined') {
var value = null var value = null
if(self.rawAttributes.hasOwnProperty(name) && self.rawAttributes[name].hasOwnProperty('defaultValue')) if(self.rawAttributes.hasOwnProperty(name) && self.rawAttributes[name].hasOwnProperty('defaultValue')) {
value = self.rawAttributes[name].defaultValue value = self.rawAttributes[name].defaultValue
}
instance[name] = value instance[name] = value
instance.addAttribute(name, value) instance.addAttribute(name, value)
} }
// add validation
if (self.rawAttributes.hasOwnProperty(name) && self.rawAttributes[name].hasOwnProperty('validate')) {
instance.setValidators(name, self.rawAttributes[name].validate)
}
}) })
Utils._.each(this.options.instanceMethods || {}, function(fct, name) { instance[name] = fct }) Utils._.each(this.options.instanceMethods || {}, function(fct, name) { instance[name] = fct })
Utils._.each(this.associations, function(association, associationName) { Utils._.each(this.associations, function(association, associationName) {
...@@ -148,6 +156,7 @@ module.exports = (function() { ...@@ -148,6 +156,7 @@ module.exports = (function() {
return this.build(values).save() return this.build(values).save()
} }
ModelFactory.prototype.__defineGetter__('primaryKeys', function() { ModelFactory.prototype.__defineGetter__('primaryKeys', function() {
var result = {} var result = {}
......
var Utils = require("./utils") var Utils = require("./utils")
, Mixin = require("./associations/mixin") , Mixin = require("./associations/mixin")
, Validator = require("validator")
module.exports = (function() { module.exports = (function() {
var Model = function(values, options) { var Model = function(values, options) {
...@@ -7,6 +8,7 @@ module.exports = (function() { ...@@ -7,6 +8,7 @@ module.exports = (function() {
this.__definition = null // will be set in Model.build this.__definition = null // will be set in Model.build
this.attributes = [] this.attributes = []
this.validators = {} // holds validation settings for each attribute
this.__options = options || {} this.__options = options || {}
initAttributes.call(this, values) initAttributes.call(this, values)
...@@ -47,6 +49,58 @@ module.exports = (function() { ...@@ -47,6 +49,58 @@ module.exports = (function() {
} }
} }
/*
* Validate this model's attribute values according to validation rules set in the model definition.
*
* @return null if and only if validation successful; otherwise an object containing { field name : [error msgs] } entries.
*/
Model.prototype.validate = function() {
var self = this
var failures = {}
// for each field and value
Utils._.each(self.values, function(value, field) {
// if field has validators
if (self.validators.hasOwnProperty(field)) {
// for each validator
Utils._.each(self.validators[field], function(details, validatorType) {
// validator arguments
var fn_args = details.hasOwnProperty("args") ? details.args : []
if (!Utils._.isArray(fn_args))
fn_args = [fn_args]
// error msg
var fn_msg = details.hasOwnProperty("msg") ? details.msg : false
var validator = Validator.check(value, fn_msg)
if (!Utils._.isFunction(validator[validatorType]))
throw new Error("Invalid validator function: " + validatorType)
try {
validator[validatorType].apply(validator, fn_args)
} catch (err) {
err = err.message
// if we didn't provide a custom error message then augment the default one returned by the validator
if (!fn_msg)
err += ": " + field
// each field can have multiple validation failures stored against it
if (failures.hasOwnProperty(field)) {
failures[field].push(err)
} else {
failures[field] = [err]
}
}
}) // for each validator for this field
} // if field has validator set
}) // for each field
return (Utils._.isEmpty(failures) ? null : failures)
}
Model.prototype.updateAttributes = function(updates) { Model.prototype.updateAttributes = function(updates) {
var self = this var self = this
...@@ -146,6 +200,10 @@ module.exports = (function() { ...@@ -146,6 +200,10 @@ module.exports = (function() {
this.attributes.push(attribute) this.attributes.push(attribute)
} }
Model.prototype.setValidators = function(attribute, validators) {
this.validators[attribute] = validators
}
// private // private
var initAttributes = function(values) { var initAttributes = function(values) {
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"mysql": "=0.9.4", "mysql": "=0.9.4",
"underscore": "=1.2.1", "underscore": "=1.2.1",
"underscore.string": "=1.2.0", "underscore.string": "=1.2.0",
"lingo": "=0.0.4" "lingo": "=0.0.4",
"validator": "=0.3.5"
}, },
"devDependencies": { "devDependencies": {
"jasmine-node": "=1.0.12", "jasmine-node": "=1.0.12",
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!