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

Commit 28eb87ec by Jan Aagaard Meier

Merge pull request #4372 from rodrigoapereira/master

add beforeRestore/afterRestore hooks

Conflicts:
	changelog.md
2 parents 343881f9 50d9a8ae
# Next
[ADDED] beforeRestore/afterRestore hooks [#4371](https://github.com/sequelize/sequelize/issues/4371)
# 3.8.0
- [ADDED] `version` on `Sequelize` returning the current npm/package.json version [#4459](https://github.com/sequelize/sequelize/pull/4459)
......
......@@ -43,12 +43,16 @@ var hookTypes = {
afterCreate: {params: 2},
beforeDestroy: {params: 2},
afterDestroy: {params: 2},
beforeRestore: {params: 2},
afterRestore: {params: 2},
beforeUpdate: {params: 2},
afterUpdate: {params: 2},
beforeBulkCreate: {params: 2},
afterBulkCreate: {params: 2},
beforeBulkDestroy: {params: 1},
afterBulkDestroy: {params: 1},
beforeBulkRestore: {params: 1},
afterBulkRestore: {params: 1},
beforeBulkUpdate: {params: 1},
afterBulkUpdate: {params: 1},
beforeFind: {params: 1},
......@@ -248,6 +252,22 @@ Hooks.hasHooks = Hooks.hasHook;
*/
/**
* A hook that is run before restoring a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, options
*
* @name beforeRestore
*/
/**
* A hook that is run after restoring a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, options
*
* @name afterRestore
*/
/**
* A hook that is run before updating a single instance
* @param {String} name
* @param {Function} fn A callback function that is called with instance, options
......@@ -294,6 +314,22 @@ Hooks.hasHooks = Hooks.hasHook;
*/
/**
* A hook that is run before restoring instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with options
*
* @name beforeBulkRestore
*/
/**
* A hook that is run after restoring instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with options
*
* @name afterBulkRestore
*/
/**
* A hook that is run after updating instances in bulk
* @param {String} name
* @param {Function} fn A callback function that is called with options
......
......@@ -2274,9 +2274,9 @@ Model.prototype.restore = function(options) {
return self.runHooks('beforeBulkRestore', options);
}
}).then(function() {
// Get daos and run beforeDestroy hook on each record individually
// Get daos and run beforeRestore hook on each record individually
if (options.individualHooks) {
return self.findAll({where: options.where, transaction: options.transaction, logging: options.logging}).map(function(instance) {
return self.findAll({where: options.where, transaction: options.transaction, logging: options.logging, paranoid: false}).map(function(instance) {
return self.runHooks('beforeRestore', instance, options).then(function() {
return instance;
});
......
......@@ -19,7 +19,17 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
}
});
return this.User.sync({ force: true });
this.ParanoidUser = this.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
}
}, {
paranoid: true
});
return this.sequelize.sync({ force: true });
});
describe('#validate', function() {
......@@ -248,6 +258,69 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
});
});
describe('#restore', function() {
describe('on success', function() {
it('should run hooks', function() {
var beforeHook = sinon.spy()
, afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(beforeHook);
this.ParanoidUser.afterRestore(afterHook);
return this.ParanoidUser.create({username: 'Toni', mood: 'happy'}).then(function(user) {
return user.destroy().then(function() {
return user.restore().then(function(user) {
expect(beforeHook).to.have.been.calledOnce;
expect(afterHook).to.have.been.calledOnce;
});
});
});
});
});
describe('on error', function() {
it('should return an error from before', function() {
var beforeHook = sinon.spy()
, afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(function(user, options) {
beforeHook();
throw new Error('Whoops!');
});
this.ParanoidUser.afterRestore(afterHook);
return this.ParanoidUser.create({username: 'Toni', mood: 'happy'}).then(function(user) {
return user.destroy().then(function() {
return expect(user.restore()).to.be.rejected.then(function() {
expect(beforeHook).to.have.been.calledOnce;
expect(afterHook).not.to.have.been.called;
});
});
});
});
it('should return an error from after', function() {
var beforeHook = sinon.spy()
, afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(beforeHook);
this.ParanoidUser.afterRestore(function(user, options) {
afterHook();
throw new Error('Whoops!');
});
return this.ParanoidUser.create({username: 'Toni', mood: 'happy'}).then(function(user) {
return user.destroy().then(function() {
return expect(user.restore()).to.be.rejected.then(function() {
expect(beforeHook).to.have.been.calledOnce;
expect(afterHook).to.have.been.calledOnce;
});
});
});
});
});
});
describe('#bulkCreate', function() {
describe('on success', function() {
it('should run hooks', function() {
......@@ -667,6 +740,120 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
});
});
describe('#bulkRestore', function() {
beforeEach(function() {
return this.ParanoidUser.bulkCreate([
{username: 'adam', mood: 'happy'},
{username: 'joe', mood: 'sad'}
]).bind(this).then(function() {
return this.ParanoidUser.destroy({truncate: true});
});
});
describe('on success', function() {
it('should run hooks', function() {
var beforeBulk = sinon.spy()
, afterBulk = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk);
return this.ParanoidUser.restore({where: {username: 'adam', mood: 'happy'}}).then(function() {
expect(beforeBulk).to.have.been.calledOnce;
expect(afterBulk).to.have.been.calledOnce;
});
});
});
describe('on error', function() {
it('should return an error from before', function() {
this.ParanoidUser.beforeBulkRestore(function(options) {
throw new Error('Whoops!');
});
return expect(this.ParanoidUser.restore({where: {username: 'adam', mood: 'happy'}})).to.be.rejected;
});
it('should return an error from after', function() {
this.ParanoidUser.afterBulkRestore(function(options) {
throw new Error('Whoops!');
});
return expect(this.ParanoidUser.restore({where: {username: 'adam', mood: 'happy'}})).to.be.rejected;
});
});
describe('with the {individualHooks: true} option', function() {
beforeEach(function() {
this.ParanoidUser = this.sequelize.define('ParanoidUser', {
aNumber: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {
paranoid: true
});
return this.ParanoidUser.sync({ force: true });
});
it('should run the after/before functions for each item restored successfully', function() {
var self = this
, beforeBulk = sinon.spy()
, afterBulk = sinon.spy()
, beforeHook = sinon.spy()
, afterHook = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk);
this.ParanoidUser.beforeRestore(beforeHook);
this.ParanoidUser.afterRestore(afterHook);
return this.ParanoidUser.bulkCreate([
{aNumber: 1}, {aNumber: 1}, {aNumber: 1}
]).then(function() {
return self.ParanoidUser.destroy({where: {aNumber: 1}});
}).then(function() {
return self.ParanoidUser.restore({where: {aNumber: 1}, individualHooks: true});
}).then(function() {
expect(beforeBulk).to.have.been.calledOnce;
expect(afterBulk).to.have.been.calledOnce;
expect(beforeHook).to.have.been.calledThrice;
expect(afterHook).to.have.been.calledThrice;
});
});
it('should run the after/before functions for each item restored with an error', function() {
var self = this
, beforeBulk = sinon.spy()
, afterBulk = sinon.spy()
, beforeHook = sinon.spy()
, afterHook = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk);
this.ParanoidUser.beforeRestore(function(user, options, fn) {
beforeHook();
fn(new Error('You shall not pass!'));
});
this.ParanoidUser.afterRestore(afterHook);
return this.ParanoidUser.bulkCreate([{aNumber: 1}, {aNumber: 1}, {aNumber: 1}], { fields: ['aNumber'] }).then(function() {
return self.ParanoidUser.destroy({where: {aNumber: 1}});
}).then(function() {
return self.ParanoidUser.restore({where: {aNumber: 1}, individualHooks: true});
}).catch(function(err) {
expect(err).to.be.instanceOf(Error);
expect(beforeBulk).to.have.been.calledOnce;
expect(beforeHook).to.have.been.calledThrice;
expect(afterBulk).not.to.have.been.called;
expect(afterHook).not.to.have.been.called;
});
});
});
});
describe('#find', function() {
beforeEach(function() {
return this.User.bulkCreate([
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!