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

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 # 3.8.0
- [ADDED] `version` on `Sequelize` returning the current npm/package.json version [#4459](https://github.com/sequelize/sequelize/pull/4459) - [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 = { ...@@ -43,12 +43,16 @@ var hookTypes = {
afterCreate: {params: 2}, afterCreate: {params: 2},
beforeDestroy: {params: 2}, beforeDestroy: {params: 2},
afterDestroy: {params: 2}, afterDestroy: {params: 2},
beforeRestore: {params: 2},
afterRestore: {params: 2},
beforeUpdate: {params: 2}, beforeUpdate: {params: 2},
afterUpdate: {params: 2}, afterUpdate: {params: 2},
beforeBulkCreate: {params: 2}, beforeBulkCreate: {params: 2},
afterBulkCreate: {params: 2}, afterBulkCreate: {params: 2},
beforeBulkDestroy: {params: 1}, beforeBulkDestroy: {params: 1},
afterBulkDestroy: {params: 1}, afterBulkDestroy: {params: 1},
beforeBulkRestore: {params: 1},
afterBulkRestore: {params: 1},
beforeBulkUpdate: {params: 1}, beforeBulkUpdate: {params: 1},
afterBulkUpdate: {params: 1}, afterBulkUpdate: {params: 1},
beforeFind: {params: 1}, beforeFind: {params: 1},
...@@ -248,6 +252,22 @@ Hooks.hasHooks = Hooks.hasHook; ...@@ -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 * A hook that is run before updating a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, options * @param {Function} fn A callback function that is called with instance, options
...@@ -294,6 +314,22 @@ Hooks.hasHooks = Hooks.hasHook; ...@@ -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 * A hook that is run after updating instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with options * @param {Function} fn A callback function that is called with options
......
...@@ -2274,9 +2274,9 @@ Model.prototype.restore = function(options) { ...@@ -2274,9 +2274,9 @@ Model.prototype.restore = function(options) {
return self.runHooks('beforeBulkRestore', options); return self.runHooks('beforeBulkRestore', options);
} }
}).then(function() { }).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) { 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 self.runHooks('beforeRestore', instance, options).then(function() {
return instance; return instance;
}); });
......
...@@ -19,7 +19,17 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -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() { describe('#validate', function() {
...@@ -248,6 +258,69 @@ describe(Support.getTestDialectTeaser('Hooks'), 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('#bulkCreate', function() {
describe('on success', function() { describe('on success', function() {
it('should run hooks', function() { it('should run hooks', function() {
...@@ -667,6 +740,120 @@ describe(Support.getTestDialectTeaser('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() { describe('#find', function() {
beforeEach(function() { beforeEach(function() {
return this.User.bulkCreate([ 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!