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

Commit a49a7c1d by Jan Aagaard Meier

Merge pull request #5196 from skleeschulte/master

Added validationFailed hook
2 parents efc432b9 bc30943c
# Future
- [ADDED] `beforeCount` hook [#5209](https://github.com/sequelize/sequelize/pull/5209)
- [ADDED] `validationFailed` hook [#1626](https://github.com/sequelize/sequelize/issues/1626)
# 3.19.3
- [FIXED] `updatedAt` and `createdAt` values are now set before validation [#5367](https://github.com/sequelize/sequelize/pull/5367)
......
......@@ -15,6 +15,8 @@ For a full list of hooks, see [Hooks API](/api/hooks).
validate
(3)
afterValidate(instance, options, fn)
- or -
validationFailed(instance, options, error, fn)
(4)
beforeCreate(instance, options, fn)
beforeDestroy(instance, options, fn)
......@@ -159,7 +161,7 @@ The following hooks will emit whenever you're editing a single object
```
beforeValidate
afterValidate
afterValidate or validationFailed
beforeCreate / beforeUpdate / beforeDestroy
afterCreate / afterUpdate / afterDestroy
```
......
......@@ -39,6 +39,7 @@ var Utils = require('./utils')
var hookTypes = {
beforeValidate: {params: 2},
afterValidate: {params: 2},
validationFailed: {params: 3},
beforeCreate: {params: 2},
afterCreate: {params: 2},
beforeDestroy: {params: 2},
......@@ -225,6 +226,14 @@ Hooks.hasHooks = Hooks.hasHook;
*/
/**
* A hook that is run when validation fails
* @param {String} name
* @param {Function} fn A callback function that is called with instance, options, error. Error is the
* SequelizeValidationError. If the callback throws an error, it will replace the original validation error.
* @name validationFailed
*/
/**
* A hook that is run before creating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with attributes, options
......
......@@ -80,7 +80,8 @@ InstanceValidator.prototype.validate = function() {
* Invoke the Validation sequence:
* - Before Validation Model Hooks
* - Validation
* - After Validation Model Hooks
* - On validation success: After Validation Model Hooks
* - On validation failure: Validation Failed Model Hooks
*
* @return {Promise}
*/
......@@ -89,7 +90,9 @@ InstanceValidator.prototype.hookValidate = function() {
return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance, self.options).then(function() {
return self.validate().then(function(error) {
if (error) {
throw error;
return self.modelInstance.Model.runHooks('validationFailed', self.modelInstance, self.options, error).then(function(newError) {
throw newError || error;
});
}
});
}).then(function() {
......
......@@ -561,7 +561,7 @@ Sequelize.prototype.getQueryInterface = function() {
* @param {String} [options.comment]
* @param {String} [options.collate]
* @param {String} [options.initialAutoIncrement] Set the initial AUTO_INCREMENT value for the table in MySQL.
* @param {Object} [options.hooks] An object of hook function that are called before and after certain lifecycle events. The possible hooks are: beforeValidate, afterValidate, beforeBulkCreate, beforeBulkDestroy, beforeBulkUpdate, beforeCreate, beforeDestroy, beforeUpdate, afterCreate, afterDestroy, afterUpdate, afterBulkCreate, afterBulkDestory and afterBulkUpdate. See Hooks for more information about hook functions and their signatures. Each property can either be a function, or an array of functions.
* @param {Object} [options.hooks] An object of hook function that are called before and after certain lifecycle events. The possible hooks are: beforeValidate, afterValidate, validationFailed, beforeBulkCreate, beforeBulkDestroy, beforeBulkUpdate, beforeCreate, beforeDestroy, beforeUpdate, afterCreate, afterDestroy, afterUpdate, afterBulkCreate, afterBulkDestory and afterBulkUpdate. See Hooks for more information about hook functions and their signatures. Each property can either be a function, or an array of functions.
* @param {Object} [options.validate] An object of model wide validations. Validations have access to all model values via `this`. If the validator function takes an argument, it is assumed to be async, and is called with a callback that accepts an optional error.
*
* @return {Model}
......
......@@ -12,7 +12,10 @@ var chai = require('chai')
describe(Support.getTestDialectTeaser('Hooks'), function() {
beforeEach(function() {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
username: {
type: DataTypes.STRING,
allowNull: false
},
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
......@@ -36,6 +39,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
describe('#create', function() {
it('should return the user', function() {
this.User.beforeValidate(function(user, options) {
user.username = 'Bob';
user.mood = 'happy';
});
......@@ -57,7 +61,37 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
throw new Error('Whoops! Changed user.mood!');
});
return expect(this.User.create({mood: 'happy'})).to.be.rejectedWith('Whoops! Changed user.mood!');
return expect(this.User.create({username: 'Toni', mood: 'happy'})).to.be.rejectedWith('Whoops! Changed user.mood!');
});
it('should call validationFailed hook', function() {
var validationFailedHook = sinon.spy();
this.User.validationFailed(validationFailedHook);
return expect(this.User.create({mood: 'happy'})).to.be.rejected.then(function(err) {
expect(validationFailedHook).to.have.been.calledOnce;
});
});
it('should not replace the validation error in validationFailed hook by default', function() {
var validationFailedHook = sinon.stub();
this.User.validationFailed(validationFailedHook);
return expect(this.User.create({mood: 'happy'})).to.be.rejected.then(function(err) {
expect(err.name).to.equal('SequelizeValidationError');
});
});
it('should replace the validation error if validationFailed hook creates a new error', function() {
var validationFailedHook = sinon.stub().throws(new Error('Whoops!'));
this.User.validationFailed(validationFailedHook);
return expect(this.User.create({mood: 'happy'})).to.be.rejected.then(function(err) {
expect(err.message).to.equal('Whoops!');
});
});
});
});
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!