Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
public
/
sequelize
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
不要怂,就是干,撸起袖子干!
Commit 10910695
authored
Mar 06, 2014
by
Thanasis Polychronakis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Major refactoring of dao-validator, faster, leaner, meaner
1 parent
04b237e7
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
158 additions
and
116 deletions
lib/dao-validator.js
lib/dao-validator.js
View file @
1091069
var
Validator
=
require
(
"validator"
)
,
Utils
=
require
(
"./utils"
)
,
sequelizeError
=
require
(
"./errors"
)
,
Promise
=
require
(
"bluebird"
)
// Backwards compat for people using old validation function
// We cannot use .extend, since it coerces the first arg to string
...
...
@@ -76,7 +77,13 @@ Validator.extend('is', function(str, pattern, modifiers) {
return
this
.
regex
(
str
,
pattern
,
modifiers
);
})
/**
* The Main DAO Validator.
*
* @param {sequelize.Model} modelInstance The model instance.
* @param {Object} options A dict with options.
* @constructor
*/
var
DaoValidator
=
module
.
exports
=
function
(
modelInstance
,
options
)
{
options
=
options
||
{}
options
.
skip
=
options
.
skip
||
[]
...
...
@@ -90,30 +97,47 @@ var DaoValidator = module.exports = function(modelInstance, options) {
* @name Validator
*/
this
.
Validator
=
Validator
/**
* All errors will be stored here from the validations.
*
* @type {Object} Will contain keys that correspond to attributes which will
* be Arrays of Errors.
*/
this
.
errors
=
{};
/** @type {boolean} Indicates if validations are in progress */
this
.
inProgress
=
false
;
}
/** @define {string} The error key for arguments as passed by custom validators */
DaoValidator
.
RAW_KEY_NAME
=
'__raw'
/**
* The main entry point for the Validation module, invoke to start the dance.
*
* @return {sequelize.Utils.CustomEventEmitter} That thing...
*/
DaoValidator
.
prototype
.
validate
=
function
()
{
var
self
=
this
if
(
this
.
inProgress
)
{
throw
new
Error
(
'Validations already in progress.'
);
}
this
.
inProgress
=
true
;
this
.
errors
=
[];
var
self
=
this
return
new
Utils
.
CustomEventEmitter
(
function
(
emitter
)
{
validateAttributes
.
call
(
self
)
validateModel
.
call
(
self
)
self
.
chainer
.
run
()
.
success
(
function
()
{
Promise
.
settle
([
self
.
_validateAttributes
(),
self
.
_validateSchema
(),
]).
then
(
function
()
{
emitter
.
emit
(
'success'
)
})
.
error
(
function
(
err
)
{
}).
catch
(
function
(
err
)
{
var
error
=
new
sequelizeError
.
ValidationError
(
'Validation error'
)
error
[
DaoValidator
.
RAW_KEY_NAME
]
=
[]
Utils
.
_
.
each
(
err
,
function
(
value
)
{
error
[
DaoValidator
.
RAW_KEY_NAME
].
push
(
value
[
DaoValidator
.
RAW_KEY_NAME
])
error
[
DaoValidator
.
RAW_KEY_NAME
].
push
(
value
[
DaoValidator
.
RAW_KEY_NAME
]);
delete
value
[
DaoValidator
.
RAW_KEY_NAME
]
Utils
.
_
.
extend
(
error
,
value
)
})
...
...
@@ -123,6 +147,14 @@ DaoValidator.prototype.validate = function() {
}).
run
()
}
/**
* Invoke the Validation sequence:
* - Before Validation Model Hooks
* - Validation
* - After Validation Model Hooks
*
* @return {sequelize.Utils.CustomEventEmitter} An eventemitter.
*/
DaoValidator
.
prototype
.
hookValidate
=
function
()
{
var
self
=
this
...
...
@@ -149,137 +181,124 @@ DaoValidator.prototype.hookValidate = function() {
}).
run
()
}
// private
var
validateModel
=
function
()
{
Utils
.
_
.
each
(
this
.
modelInstance
.
__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
[
DaoValidator
.
RAW_KEY_NAME
]
=
err
var
msg
=
((
err
instanceof
Error
)
?
err
.
message
:
err
)
error
[
validatorType
]
=
[
msg
]
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
()
{
/**
* Will validate all attributes based on their schema rules and defined validators.
*
* @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
* @private
*/
DaoValidator
.
prototype
.
_validateAttributes
=
function
()
{
var
self
=
this
,
errors
=
{}
Utils
.
_
.
each
(
this
.
modelInstance
.
rawAttributes
,
function
(
rawAttribute
,
field
)
{
// promisify all attribute invocations
var
validators
=
[];
_
.
forIn
(
this
.
modelInstance
.
rawAttributes
,
function
(
rawAttribute
,
field
)
{
var
value
=
self
.
modelInstance
.
dataValues
[
field
]
,
hasAllowedNull
=
((
rawAttribute
===
undefined
||
rawAttribute
.
allowNull
===
true
)
&&
((
value
===
null
)
||
(
value
===
undefined
)))
,
isSkipped
=
self
.
options
.
skip
.
length
>
0
&&
self
.
options
.
skip
.
indexOf
(
field
)
!==
-
1
if
(
self
.
modelInstance
.
validators
.
hasOwnProperty
(
field
))
{
validators
.
push
(
self
.
_validateAttribute
(
value
,
field
))
if
(
self
.
modelInstance
.
validators
.
hasOwnProperty
(
field
)
&&
!
hasAllowedNull
&&
!
isSkipped
)
{
errors
=
Utils
.
_
.
merge
(
errors
,
validateAttribute
.
call
(
self
,
value
,
field
))
}
})
return
errors
return
Promise
.
settle
(
validators
)
}
var
validateAttribute
=
function
(
value
,
field
)
{
// for each validator
Utils
.
_
.
each
(
this
.
modelInstance
.
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'
)
/**
* Will validate a single field against its schema definition (isnull).
*
* @param {string} field The field name.
* @param {*} value anything.
throw error;
* @return {Promise} A promise, will always resolve,
* auto populates error on this.error local object.
* @private
*/
DaoValidator
.
prototype
.
_validateSchema
=
function
(
field
,
value
)
{
var
self
=
this
;
return
new
Promise
(
function
(
resolve
)
{
var
hasAllowedNull
=
((
rawAttribute
===
undefined
||
rawAttribute
.
allowNull
===
true
)
&&
((
value
===
null
)
||
(
value
===
undefined
)))
var
isSkipped
=
self
.
options
.
skip
.
length
>
0
&&
self
.
options
.
skip
.
indexOf
(
field
)
!==
-
1
if
(
!
hasAllowedNull
&&
!
isSkipped
)
{
var
error
=
new
sequelizeError
.
ValidationError
(
field
+
' cannot be null'
)
error
.
path
=
field
error
.
value
=
value
error
.
type
=
'notNull Violation'
if
(
!
self
.
errors
[
field
])
{
self
.
errors
[
field
]
=
[];
}
self
.
errors
[
field
].
push
(
error
);
}
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
)
{
resolve
();
});
};
/**
* Validate a single attribute with all the defined validators.
*
* @param {*} value Anything.
* @param {string} field The field name.
* @return {Promise} A promise, will always resolve,
* auto populates error on this.error local object.
* @private
*/
DaoValidator
.
prototype
.
_validateAttribute
=
function
(
value
,
field
)
{
var
self
=
this
;
// Promisify each validator
var
validators
=
[];
Utils
.
_
.
forIn
(
this
.
modelInstance
.
validators
[
field
],
function
(
details
,
validatorType
)
{
var
validator
=
self
.
_prepareValidationOfAttribute
.
call
(
self
,
value
,
details
,
validatorType
);
validators
.
push
(
Promise
.
nodeify
(
validator
));
});
return
Promise
.
settle
(
validators
)
.
then
(
this
.
_handleSettledResult
.
bind
(
this
,
field
));
};
/**
* Prepare Attribute for validation.
*
* @param {*} value Anything
* @param {Function} validator The validator.
* @param {string} validatorType One of known to Sequelize validators.
* @param {Object=} optOptions Options
* @return {Object} An object with specific keys to invoke the validator.
* @private
*/
DaoValidator
.
prototype
.
_prepareValidationOfAttribute
=
function
(
value
,
validator
,
validatorType
,
optOptions
)
{
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
var
validatorArity
=
validator
.
length
;
var
callArgs
=
[]
var
validatorArity
=
details
.
length
var
options
=
optOptions
||
{}
var
omitValue
=
!!
options
.
omitValue
var
omitValue
=
!!
(
options
||
{}).
omitValue
if
(
!
omitValue
)
{
callArgs
.
push
(
value
)
}
// check if validator is async and requires a callback
var
isAsync
=
omitValue
&&
validatorArity
===
1
||
!
omitValue
&&
validatorArity
===
2
validatorFunction
=
function
(
next
)
{
if
(
isAsync
)
{
callArgs
.
push
(
next
)
}
try
{
details
.
apply
(
this
.
modelInstance
,
callArgs
)
}
catch
(
ex
)
{
return
next
(
ex
)
}
if
(
!
isAsync
)
{
next
()
}
}.
bind
(
this
)
}
else
{
// extract extra arguments for the validator
validatorArgs
=
details
.
hasOwnProperty
(
"args"
)
?
details
.
args
:
details
if
(
!
Array
.
isArray
(
validatorArgs
))
{
validatorArgs
=
[
validatorArgs
]
}
else
{
validatorArgs
=
validatorArgs
.
slice
(
0
);
var
isAsync
=
false
if
(
omitValue
&&
validatorArity
===
1
||
!
omitValue
&&
validatorArity
===
2
)
{
isAsync
=
true
;
}
// extract the error msg
errorMessage
=
details
.
hasOwnProperty
(
"msg"
)
?
details
.
msg
:
'Validation '
+
validatorType
+
' failed'
// 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
)
if
(
Validator
[
validatorType
].
apply
(
Validator
,
[
value
].
concat
(
args
)))
{
next
()
}
else
{
next
(
errorMessage
)
}
}
}
validatorFunction
=
Promise
.
nodeify
(
validator
.
bind
(
this
.
modelInstance
))
return
{
fn
:
validatorFunction
,
...
...
@@ -289,3 +308,26 @@ var prepareValidationOfAttribute = function(value, details, validatorType, optio
}
}
/**
* Handles the returned result of a Promise.settle.
*
* If errors are found it populates this.error and throws an Array of the errors.
*
* @param {string} field The attribute name.
* @param {Array.<Promise.PromiseInspection>} Promise inspection objects.
* @private
*/
DaoValidator
.
prototype
.
_handleSettleResult
=
function
(
field
,
promiseInspections
)
{
var
self
=
this
;
promiseInspections
.
forEach
(
function
(
promiseInspection
)
{
if
(
promiseInspection
.
isRejected
)
{
var
rejection
=
promiseInspection
.
error
();
var
error
=
new
sequelizeError
.
ValidationError
(
'Validation error'
)
error
[
DaoValidator
.
RAW_KEY_NAME
]
=
rejection
if
(
!
self
.
errors
[
field
])
{
self
.
errors
[
field
]
=
[];
}
self
.
errors
[
field
].
push
(
error
);
}
});
};
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment