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

dao-validator.js 4.21 KB
var Validator = require("validator")
  , Utils     = require("./utils")

var DaoValidator = module.exports = function(model) {
  this.model   = model
  this.chainer = new Utils.QueryChainer()
}

DaoValidator.prototype.validate = function() {
  return new Utils.CustomEventEmitter(function(emitter) {
    validateAttributes.call(this)
    validateModel.call(this)

    this
      .chainer
      .run()
      .success(function () {
        emitter.emit('success')
      })
      .error(function(err) {
        var errors = {}

        Utils._.each(err, function (value) {
          Utils._.extend(errors, value)
        })

        emitter.emit('success', errors)
      })
  }.bind(this)).run()
}

// private

var validateModel = function() {
  Utils._.each(this.model.__options.validate, function(_validator, validatorType) {
    var validator = prepareValidationOfAttribute.call(this, undefined, _validator, validatorType, { omitValue: true })

    this.chainer.add(new Utils.CustomEventEmitter(function(emitter) {
      var next = function(err) {
        if (err) {
          var error = {}
          error[validatorType] = [err]
          emitter.emit('error', error)
        } else {
          emitter.emit('success')
        }
      }
      validator.args.unshift(next);
      validator.fn.apply(null, validator.args)
    }.bind(this)).run())
  }.bind(this))
}

var validateAttributes = function() {
  var errors = {}

  // for each field and value
  Utils._.each(this.model.values, function(value, field) {
    var rawAttribute   = this.model.rawAttributes[field]
      , hasAllowedNull = ((rawAttribute.allowNull === true) && ((value === null) || (value === undefined)))

    if (this.model.validators.hasOwnProperty(field) && !hasAllowedNull) {
      errors = Utils._.merge(errors, validateAttribute.call(this, value, field))
    }
  }.bind(this)) // for each field

  return errors
}

var validateAttribute = function(value, field) {
  // for each validator
  Utils._.each(this.model.validators[field], function(details, validatorType) {
    var validator = prepareValidationOfAttribute.call(this, value, details, validatorType)

    this.chainer.add(new Utils.CustomEventEmitter(function(emitter) {
      var next = function(err) {
        if (err) {
          var error = {}
          error[field] = [err]
          emitter.emit('error', error)
        } else {
          emitter.emit('success')
        }
      }
      validator.args.unshift(next);
      validator.fn.apply(null, validator.args)
    }.bind(this)).run())
  }.bind(this)) // for each validator for this field
}

var prepareValidationOfAttribute = function(value, details, validatorType, options) {
  var isCustomValidator = false // if true then it's a custom validation method
    , validatorFunction = null  // the validation function to call
    , validatorArgs     = []    // extra arguments to pass to validation function
    , errorMessage      = ""    // the error message to return if validation fails

  if (typeof details === 'function') {
    // it is a custom validator function?
    isCustomValidator = true
    validatorFunction = function(next) {
      details.apply(this.model, ((options || {}).omitValue) ? [next] : [value, next])
    }.bind(this)
  } else {
    // it is a validator module function?

    // extract extra arguments for the validator
    validatorArgs = details.hasOwnProperty("args") ? details.args : details

    if (!Array.isArray(validatorArgs)) {
      validatorArgs = [validatorArgs]
    }

    // extract the error msg
    errorMessage = details.hasOwnProperty("msg") ? details.msg : false

    // check method exists
    var validator = Validator.check(value, errorMessage)

    // check if Validator knows that kind of validation test
    if (!Utils._.isFunction(validator[validatorType])) {
      throw new Error("Invalid validator function: " + validatorType)
    }

    // bind to validator obj
    validatorFunction = function(next) {
      var args = Array.prototype.slice.call(arguments, 1)

      try {
        validator[validatorType].apply(validator, args)
        next()
      } catch (err) {
        next(err.message)
      }
    }
  }

  return {
    fn:       validatorFunction,
    msg:      errorMessage,
    args:     validatorArgs,
    isCustom: isCustomValidator
  }
}