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

Commit 56237112 by Ram

Added ability to supply custom validation methods. Each custom validation method…

… recieves the field value to validate as its sole argument. It should throw an error to indicate a validation failure. For example:

<pre>
      User = sequelize.define('User', {
        name: {
          type: Sequelize.STRING,
          validate: {
              len: {
                args: 9,
		msg: "Need atleast 9 chars"
              },
              customFn1: function(val) {
                # if name doesn't start with 'joe' then fail
                if (val.substr(0,3) !== "joe")
                    throw new Error("name should start with 'joe'")
              },
              customFn2: function(val) {
                # if name doesn't end in 'bloggs' then fail
                if (val.substr(-6) !== "bloggs")
                    throw new Error("name should end with 'bloggs'")
              }
          }
        }
      });
</pre>

You still invoke validation as you normally would, i.e.:

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

# validate
errors = user.validate();
# At this point errors will contain:
#
# { name : [
#	"Need atleast 9 chars"
#	"name should start with 'joe'"
#	"name should end with 'bloggs'"
# ] }
#
</pre>
1 parent 6ae3b957
Showing with 258 additions and 212 deletions
...@@ -65,24 +65,38 @@ module.exports = (function() { ...@@ -65,24 +65,38 @@ module.exports = (function() {
// for each validator // for each validator
Utils._.each(self.validators[field], function(details, validatorType) { Utils._.each(self.validators[field], function(details, validatorType) {
// validator arguments var is_custom_fn = false // if true then it's a custom validation method
var fn_args = details.hasOwnProperty("args") ? details.args : [] var fn_method = null // the validation function to call
if (!Utils._.isArray(fn_args)) var fn_args = [] // extra arguments to pass to validation function
fn_args = [fn_args] var fn_msg = "" // the error message to return if validation fails
// error msg
var fn_msg = details.hasOwnProperty("msg") ? details.msg : false // is it a custom validator function?
if (Utils._.isFunction(details)) {
var validator = Validator.check(value, fn_msg) is_custom_fn = true
fn_method = Utils._.bind(details, self, value)
if (!Utils._.isFunction(validator[validatorType])) }
throw new Error("Invalid validator function: " + validatorType) // is it a validator module function?
else {
// extra args
fn_args = details.hasOwnProperty("args") ? details.args : []
if (!Utils._.isArray(fn_args))
fn_args = [fn_args]
// error msg
fn_msg = details.hasOwnProperty("msg") ? details.msg : false
// check method exists
var v = Validator.check(value, fn_msg)
if (!Utils._.isFunction(v[validatorType]))
throw new Error("Invalid validator function: " + validatorType)
// bind to validator obj
fn_method = Utils._.bind(v[validatorType], v)
}
try { try {
validator[validatorType].apply(validator, fn_args) fn_method.apply(null, fn_args)
} catch (err) { } catch (err) {
err = err.message err = err.message
// if we didn't provide a custom error message then augment the default one returned by the validator // if we didn't provide a custom error message then augment the default one returned by the validator
if (!fn_msg) if (!fn_msg && !is_custom_fn)
err += ": " + field err += ": " + field
// each field can have multiple validation failures stored against it // each field can have multiple validation failures stored against it
if (failures.hasOwnProperty(field)) { if (failures.hasOwnProperty(field)) {
......
...@@ -72,217 +72,249 @@ describe('Model', function() { ...@@ -72,217 +72,249 @@ describe('Model', function() {
}) })
}) })
describe('Model', function() { describe('Validations', function() {
describe('Validations', function() { var checks = {
var checks = { is : {
is : { spec : { args: [/[a-z]/,'i'] },
spec : { args: [/[a-z]/,'i'] }, fail: "0",
fail: "0", pass: "a"
pass: "a" }
} , not : {
, not : { spec: { args: [/[a-z]/,'i'] },
spec: { args: [/[a-z]/,'i'] }, fail: "a",
fail: "a", pass: "0"
pass: "0" }
} , isEmail : {
, isEmail : { fail: "a",
fail: "a", pass: "abc@abc.com"
pass: "abc@abc.com" }
} , isUrl : {
, isUrl : { fail: "abc",
fail: "abc", pass: "http://abc.com"
pass: "http://abc.com" }
} , isIP : {
, isIP : { fail: "abc",
fail: "abc", pass: "129.89.23.1"
pass: "129.89.23.1" }
} , isAlpha : {
, isAlpha : { fail: "012",
fail: "012", pass: "abc"
pass: "abc" }
} , isAlphanumeric : {
, isAlphanumeric : { fail: "_abc019",
fail: "_abc019", pass: "abc019"
pass: "abc019" }
} , isNumeric : {
, isNumeric : { fail: "abc",
fail: "abc", pass: "019"
pass: "019" }
} , isInt : {
, isInt : { fail: "9.2",
fail: "9.2", pass: "-9"
pass: "-9" }
} , isLowercase : {
, isLowercase : { fail: "AB",
fail: "AB", pass: "ab"
pass: "ab" }
} , isUppercase : {
, isUppercase : { fail: "ab",
fail: "ab", pass: "AB"
pass: "AB" }
} , isDecimal : {
, isDecimal : { fail: "a",
fail: "a", pass: "0.2"
pass: "0.2" }
} , isFloat : {
, isFloat : { fail: "a",
fail: "a", pass: "9.2"
pass: "9.2" }
} , notNull : {
, notNull : { fail: null,
fail: null, pass: 0
pass: 0 }
} , isNull : {
, isNull : { fail: 0,
fail: 0, pass: null
pass: null }
} , notEmpty : {
, notEmpty : { fail: " ",
fail: " ", pass: "a"
pass: "a" }
} , equals : {
, equals : { spec : { args : "bla bla bla" },
spec : { args : "bla bla bla" }, fail: "bla",
fail: "bla", pass: "bla bla bla"
pass: "bla bla bla" }
} , contains : {
, contains : { spec : { args : "bla" },
spec : { args : "bla" }, fail: "la",
fail: "la", pass: "0bla23"
pass: "0bla23" }
} , notContains : {
, notContains : { spec : { args : "bla" },
spec : { args : "bla" }, fail: "0bla23",
fail: "0bla23", pass: "la"
pass: "la" }
} , regex : {
, regex : { spec : { args: [/[a-z]/,'i'] },
spec : { args: [/[a-z]/,'i'] }, fail: "0",
fail: "0", pass: "a"
pass: "a" }
} , notRegex : {
, notRegex : { spec: { args: [/[a-z]/,'i'] },
spec: { args: [/[a-z]/,'i'] }, fail: "a",
fail: "a", pass: "0"
pass: "0" }
} , len : {
, len : { spec: { args: [2,4] },
spec: { args: [2,4] }, fail: ["1", "12345"],
fail: ["1", "12345"], pass: ["12", "123", "1234"],
pass: ["12", "123", "1234"], raw: true
raw: true }
} , isUUID : {
, isUUID : { spec: { args: 4 },
spec: { args: 4 }, fail: "f47ac10b-58cc-3372-a567-0e02b2c3d479",
fail: "f47ac10b-58cc-3372-a567-0e02b2c3d479", pass: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
pass: "f47ac10b-58cc-4372-a567-0e02b2c3d479" }
} , isDate : {
, isDate : { fail: "not a date",
fail: "not a date", pass: "2011-02-04"
pass: "2011-02-04" }
} , isAfter : {
, isAfter : { spec: { args: "2011-11-05" },
spec: { args: "2011-11-05" }, fail: "2011-11-04",
fail: "2011-11-04", pass: "2011-11-05"
pass: "2011-11-05" }
} , isBefore : {
, isBefore : { spec: { args: "2011-11-05" },
spec: { args: "2011-11-05" }, fail: "2011-11-06",
fail: "2011-11-06", pass: "2011-11-05"
pass: "2011-11-05" }
} , isIn : {
, isIn : { spec: { args: "abcdefghijk" },
spec: { args: "abcdefghijk" }, fail: "ghik",
fail: "ghik", pass: "ghij"
pass: "ghij" }
} , notIn : {
, notIn : { spec: { args: "abcdefghijk" },
spec: { args: "abcdefghijk" }, fail: "ghij",
fail: "ghij", pass: "ghik"
pass: "ghik" }
} , max : {
, max : { spec: { args: 23 },
spec: { args: 23 }, fail: "24",
fail: "24", pass: "23"
pass: "23" }
} , min : {
, min : { spec: { args: 23 },
spec: { args: 23 }, fail: "22",
fail: "22", pass: "23"
pass: "23" }
} , isArray : {
, isArray : { fail: 22,
fail: 22, pass: [22]
pass: [22] }
} , isCreditCard : {
, isCreditCard : { fail: "401288888888188f",
fail: "401288888888188f", pass: "4012888888881881"
pass: "4012888888881881" }
} };
};
var User, i; var User, i;
it('should correctly validate according to supplied rules', function() { it('should correctly validate using node-validator methods', function() {
Helpers.async(function(done) { Helpers.async(function(done) {
for (var validator in checks) { for (var validator in checks) {
if (checks.hasOwnProperty(validator)) { if (checks.hasOwnProperty(validator)) {
// build spec // build spec
var v = {}; var v = {};
v[validator] = checks[validator].hasOwnProperty("spec") ? checks[validator].spec : {}; v[validator] = checks[validator].hasOwnProperty("spec") ? checks[validator].spec : {};
var check = checks[validator]; var check = checks[validator];
// test for failure // test for failure
if (!check.hasOwnProperty("raw")) if (!check.hasOwnProperty("raw"))
check.fail = new Array(check.fail); check.fail = new Array(check.fail);
for (i=0; i<check.fail.length; ++i) { for (i=0; i<check.fail.length; ++i) {
v[validator].msg = validator + "(" + check.fail[i] + ")"; v[validator].msg = validator + "(" + check.fail[i] + ")";
// define user // define user
User = sequelize.define('User' + Math.random(), { User = sequelize.define('User' + Math.random(), {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: v validate: v
} }
}); });
var u_fail = User.build({ var u_fail = User.build({
name : check.fail[i] name : check.fail[i]
}); });
var errors = u_fail.validate(); var errors = u_fail.validate();
expect(errors).toNotBe(null); expect(errors).toNotBe(null);
expect(errors).toEqual({ expect(errors).toEqual({
name : [v[validator].msg] name : [v[validator].msg]
}); });
} }
// test for success // test for success
if (!check.hasOwnProperty("raw")) if (!check.hasOwnProperty("raw"))
check.pass = new Array(check.pass); check.pass = new Array(check.pass);
for (i=0; i<check.pass.length; ++i) { for (i=0; i<check.pass.length; ++i) {
v[validator].msg = validator + "(" + check.pass[i] + ")"; v[validator].msg = validator + "(" + check.pass[i] + ")";
// define user // define user
User = sequelize.define('User' + Math.random(), { User = sequelize.define('User' + Math.random(), {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: v validate: v
} }
}); });
var u_success = User.build({ var u_success = User.build({
name : check.pass[i] name : check.pass[i]
}); });
expect(u_success.validate()).toBe(null); expect(u_success.validate()).toBe(null);
}
} }
} // for each check }
} // for each check
done();
});
});
done(); it('should correctly validate using custom validation methods', function() {
Helpers.async(function(done) {
User = sequelize.define('User' + Math.random(), {
name: {
type: Sequelize.STRING,
validate: {
customFn: function(val) {
if (val !== "2")
throw new Error("name should equal '2'")
}
}
}
}); });
var u_fail = User.build({
name : "3"
});
var errors = u_fail.validate();
expect(errors).toNotBe(null);
expect(errors).toEqual({
name : ["name should equal '2'"]
});
var u_success = User.build({
name : "2"
});
expect(u_success.validate()).toBe(null);
done();
}); });
}) });
});
})
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!