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

Commit 6ef449c1 by Simon Schick Committed by GitHub

refactor(hooks): remove method aliases for hooks (#10880)

* refactor(hooks): remove method aliases for hooks

BREAKING CHANGE:

In order to streamline API:

- All method style add hook functions have been removed in favor of a composition based approach.
- Hook names have been removed, you can add and remove them by function reference instead which was supported before.
- Another notable change that `this` inside of hooks no longer refers to the the the hook subject, it should not be used.

This affects `Model`, `Sequelize` and `Transaction`.

#### Composition

Before: `MyModel.beforeCreate(...)`
After: `MyModel.hooks.add('beforeCreate', ...)`

Before: `MyModel.addHook('beforeCreate', ...)`
After: `MyModel.hooks.add('beforeCreate', ...)`

Before: `MyModel.removeHook('beforeCreate', ...)`
After: `MyModel.hooks.remove('beforeCreate', ...)`

Before: `transaction.afterCommit(...)`
After: `transaction.hooks.add('afterCommit', ...)`

#### Names

Before:

```js
MyModel.addHook('beforeCreate', 'named', fn);
MyModel.removeHook('beforeCreate', 'named');
```

After:

```js
MyModel.hooks.add('beforeCreate', fn);
MyModel.hooks.remove('beforeCreate', fn);
```

#### Scope

Before: `MyModel.addHook('beforeCreate', function() { this.someMethod(); });`
After: `MyModel.hooks.add('beforeCreate', () => { MyModel.someMethod(); });`
1 parent 73b1246a
...@@ -42,7 +42,7 @@ script: ...@@ -42,7 +42,7 @@ script:
jobs: jobs:
include: include:
- stage: lint - stage: lint
node_js: '6' node_js: '10'
script: script:
- npm run lint - npm run lint
- npm run lint-docs - npm run lint-docs
......
...@@ -68,25 +68,14 @@ User.init({ ...@@ -68,25 +68,14 @@ User.init({
sequelize sequelize
}); });
// Method 2 via the .addHook() method // Method 2 via the .hooks.add() method
User.addHook('beforeValidate', (user, options) => { User.hooks.add('beforeValidate', (user, options) => {
user.mood = 'happy'; user.mood = 'happy';
}); });
User.addHook('afterValidate', 'someCustomName', (user, options) => { User.hooks.add('afterValidate', (user, options) => {
return Promise.reject(new Error("I'm afraid I can't let you do that!")); return Promise.reject(new Error("I'm afraid I can't let you do that!"));
}); });
// Method 3 via the direct method
User.beforeCreate((user, options) => {
return hashPassword(user.password).then(hashedPw => {
user.password = hashedPw;
});
});
User.afterValidate('myHookAfter', (user, options) => {
user.username = 'Toni';
});
``` ```
## Removing hooks ## Removing hooks
...@@ -99,14 +88,16 @@ Book.init({ ...@@ -99,14 +88,16 @@ Book.init({
title: DataTypes.STRING title: DataTypes.STRING
}, { sequelize }); }, { sequelize });
Book.addHook('afterCreate', 'notifyUsers', (book, options) => { function notifyUsers(book, options) {
// ...
}); }
Book.hooks.add('afterCreate', notifyUsers);
Book.removeHook('afterCreate', 'notifyUsers'); Book.hooks.remove('afterCreate', notifyUsers);
``` ```
You can have many hooks with same name. Calling `.removeHook()` will remove all of them. You can have many hooks with same name. Calling `.hooks.remove(()` will remove all of them.
## Global / universal hooks ## Global / universal hooks
...@@ -145,10 +136,10 @@ User.create() // Runs the global hook ...@@ -145,10 +136,10 @@ User.create() // Runs the global hook
Project.create() // Runs its own hook (because the global hook is overwritten) Project.create() // Runs its own hook (because the global hook is overwritten)
``` ```
### Permanent Hooks (Sequelize.addHook) ### Permanent Hooks (Sequelize.hooks.add)
```js ```js
sequelize.addHook('beforeCreate', () => { sequelize.hooks.add('beforeCreate', () => {
// Do stuff // Do stuff
}); });
``` ```
...@@ -198,7 +189,7 @@ These hooks can be useful if you need to asynchronously obtain database credenti ...@@ -198,7 +189,7 @@ These hooks can be useful if you need to asynchronously obtain database credenti
For example, we can asynchronously obtain a database password from a rotating token store, and mutate Sequelize's configuration object with the new credentials: For example, we can asynchronously obtain a database password from a rotating token store, and mutate Sequelize's configuration object with the new credentials:
```js ```js
sequelize.beforeConnect((config) => { sequelize.hooks.add('beforeConnect', (config) => {
return getAuthToken() return getAuthToken()
.then((token) => { .then((token) => {
config.password = token; config.password = token;
...@@ -221,7 +212,7 @@ afterCreate / afterUpdate / afterSave / afterDestroy ...@@ -221,7 +212,7 @@ afterCreate / afterUpdate / afterSave / afterDestroy
```js ```js
// ...define ... // ...define ...
User.beforeCreate(user => { User.hooks.add('beforeCreate', user => {
if (user.accessLevel > 10 && user.username !== "Boss") { if (user.accessLevel > 10 && user.username !== "Boss") {
throw new Error("You can't grant this user an access level above 10!") throw new Error("You can't grant this user an access level above 10!")
} }
...@@ -273,7 +264,7 @@ The `options` argument of hook method would be the second argument provided to t ...@@ -273,7 +264,7 @@ The `options` argument of hook method would be the second argument provided to t
cloned and extended version. cloned and extended version.
```js ```js
Model.beforeBulkCreate((records, {fields}) => { Model.hooks.add('beforeBulkCreate', (records, {fields}) => {
// records = the first argument sent to .bulkCreate // records = the first argument sent to .bulkCreate
// fields = one of the second argument fields sent to .bulkCreate // fields = one of the second argument fields sent to .bulkCreate
}) })
...@@ -284,14 +275,14 @@ Model.bulkCreate([ ...@@ -284,14 +275,14 @@ Model.bulkCreate([
], {fields: ['username']} // options parameter ], {fields: ['username']} // options parameter
) )
Model.beforeBulkUpdate(({attributes, where}) => { Model.hooks.add('beforeBulkUpdate', ({attributes, where}) => {
// where - in one of the fields of the clone of second argument sent to .update // where - in one of the fields of the clone of second argument sent to .update
// attributes - is one of the fields that the clone of second argument of .update would be extended with // attributes - is one of the fields that the clone of second argument of .update would be extended with
}) })
Model.update({gender: 'Male'} /*attributes argument*/, { where: {username: 'Tom'}} /*where argument*/) Model.update({gender: 'Male'} /*attributes argument*/, { where: {username: 'Tom'}} /*where argument*/)
Model.beforeBulkDestroy(({where, individualHooks}) => { Model.hooks.add('beforeBulkDestroy', ({where, individualHooks}) => {
// individualHooks - default of overridden value of extended clone of second argument sent to Model.destroy // individualHooks - default of overridden value of extended clone of second argument sent to Model.destroy
// where - in one of the fields of the clone of second argument sent to Model.destroy // where - in one of the fields of the clone of second argument sent to Model.destroy
}) })
...@@ -310,7 +301,7 @@ Users.bulkCreate([ ...@@ -310,7 +301,7 @@ Users.bulkCreate([
updateOnDuplicate: ['isMember'] updateOnDuplicate: ['isMember']
}); });
User.beforeBulkCreate((users, options) => { User.hooks.add('beforeBulkCreate', (users, options) => {
for (const user of users) { for (const user of users) {
if (user.isMember) { if (user.isMember) {
user.memberSince = new Date(); user.memberSince = new Date();
...@@ -364,7 +355,7 @@ Note that many model operations in Sequelize allow you to specify a transaction ...@@ -364,7 +355,7 @@ Note that many model operations in Sequelize allow you to specify a transaction
```js ```js
// Here we use the promise-style of async hooks rather than // Here we use the promise-style of async hooks rather than
// the callback. // the callback.
User.addHook('afterCreate', (user, options) => { User.hooks.add('afterCreate', (user, options) => {
// 'transaction' will be available in options.transaction // 'transaction' will be available in options.transaction
// This operation will be part of the same transaction as the // This operation will be part of the same transaction as the
......
...@@ -178,13 +178,13 @@ An `afterCommit` hook can be added to both managed and unmanaged transaction obj ...@@ -178,13 +178,13 @@ An `afterCommit` hook can be added to both managed and unmanaged transaction obj
```js ```js
sequelize.transaction(t => { sequelize.transaction(t => {
t.afterCommit((transaction) => { t.hooks.add('afterCommit', (transaction) => {
// Your logic // Your logic
}); });
}); });
sequelize.transaction().then(t => { sequelize.transaction().then(t => {
t.afterCommit((transaction) => { t.hooks.add('afterCommit', (transaction) => {
// Your logic // Your logic
}); });
...@@ -203,11 +203,11 @@ You can use the `afterCommit` hook in conjunction with model hooks to know when ...@@ -203,11 +203,11 @@ You can use the `afterCommit` hook in conjunction with model hooks to know when
of a transaction of a transaction
```js ```js
model.afterSave((instance, options) => { model.hooks.add('afterSave', (instance, options) => {
if (options.transaction) { if (options.transaction) {
// Save done within a transaction, wait until transaction is committed to // Save done within a transaction, wait until transaction is committed to
// notify listeners the instance has been saved // notify listeners the instance has been saved
options.transaction.afterCommit(() => /* Notify */) options.transaction.hooks.add('afterCommit', () => /* Notify */)
return; return;
} }
// Save done outside a transaction, safe for callers to fetch the updated model // Save done outside a transaction, safe for callers to fetch the updated model
......
...@@ -6,7 +6,7 @@ Sequelize v6 is the next major release after v4 ...@@ -6,7 +6,7 @@ Sequelize v6 is the next major release after v4
### Support for Node 8 and up ### Support for Node 8 and up
Sequelize v6 will only support Node 8 and up Sequelize v6 will only support Node 8 and up.
### Removed support for `operatorAliases` ### Removed support for `operatorAliases`
...@@ -57,3 +57,48 @@ db.transaction(async transaction => { ...@@ -57,3 +57,48 @@ db.transaction(async transaction => {
}, { transaction }); }, { transaction });
}); });
``` ```
### Refactored hooks
In order to streamline API:
- All method style add hook functions have been removed in favor of a composition based approach.
- Hook names have been removed, you can add and remove them by function reference instead which was supported before.
- Another notable change that `this` inside of hooks no longer refers to the the the hook subject, it should not be used.
This affects `Model`, `Sequelize` and `Transaction`.
#### Composition
Before: `MyModel.beforeCreate(...)`
After: `MyModel.hooks.add('beforeCreate', ...)`
Before: `MyModel.addHook('beforeCreate', ...)`
After: `MyModel.hooks.add('beforeCreate', ...)`
Before: `MyModel.removeHook('beforeCreate', ...)`
After: `MyModel.hooks.remove('beforeCreate', ...)`
Before: `transaction.afterCommit(...)`
After: `transaction.hooks.add('afterCommit', ...)`
#### Names
Before:
```js
MyModel.addHook('beforeCreate', 'named', fn);
MyModel.removeHook('beforeCreate', 'named');
```
After:
```js
MyModel.hooks.add('beforeCreate', fn);
MyModel.hooks.remove('beforeCreate', fn);
```
#### Scope
Before: `MyModel.addHook('beforeCreate', function() { this.someMethod(); });`
After: `MyModel.hooks.add('beforeCreate', () => { MyModel.someMethod(); });`
...@@ -27,7 +27,7 @@ const Mixin = { ...@@ -27,7 +27,7 @@ const Mixin = {
options = Object.assign(options, _.omit(source.options, ['hooks'])); options = Object.assign(options, _.omit(source.options, ['hooks']));
if (options.useHooks) { if (options.useHooks) {
this.runHooks('beforeAssociate', { source, target, type: HasMany }, options); this.hooks.run('beforeAssociate', { source, target, type: HasMany }, options);
} }
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
...@@ -38,7 +38,7 @@ const Mixin = { ...@@ -38,7 +38,7 @@ const Mixin = {
association.mixin(source.prototype); association.mixin(source.prototype);
if (options.useHooks) { if (options.useHooks) {
this.runHooks('afterAssociate', { source, target, type: HasMany, association }, options); this.hooks.run('afterAssociate', { source, target, type: HasMany, association }, options);
} }
return association; return association;
...@@ -58,7 +58,7 @@ const Mixin = { ...@@ -58,7 +58,7 @@ const Mixin = {
options = Object.assign(options, _.omit(source.options, ['hooks', 'timestamps', 'scopes', 'defaultScope'])); options = Object.assign(options, _.omit(source.options, ['hooks', 'timestamps', 'scopes', 'defaultScope']));
if (options.useHooks) { if (options.useHooks) {
this.runHooks('beforeAssociate', { source, target, type: BelongsToMany }, options); this.hooks.run('beforeAssociate', { source, target, type: BelongsToMany }, options);
} }
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
const association = new BelongsToMany(source, target, options); const association = new BelongsToMany(source, target, options);
...@@ -68,7 +68,7 @@ const Mixin = { ...@@ -68,7 +68,7 @@ const Mixin = {
association.mixin(source.prototype); association.mixin(source.prototype);
if (options.useHooks) { if (options.useHooks) {
this.runHooks('afterAssociate', { source, target, type: BelongsToMany, association }, options); this.hooks.run('afterAssociate', { source, target, type: BelongsToMany, association }, options);
} }
return association; return association;
...@@ -99,7 +99,7 @@ function singleLinked(Type) { ...@@ -99,7 +99,7 @@ function singleLinked(Type) {
options.useHooks = options.hooks; options.useHooks = options.hooks;
if (options.useHooks) { if (options.useHooks) {
source.runHooks('beforeAssociate', { source, target, type: Type }, options); source.hooks.run('beforeAssociate', { source, target, type: Type }, options);
} }
// the id is in the foreign table // the id is in the foreign table
const association = new Type(source, target, Object.assign(options, source.options)); const association = new Type(source, target, Object.assign(options, source.options));
...@@ -109,7 +109,7 @@ function singleLinked(Type) { ...@@ -109,7 +109,7 @@ function singleLinked(Type) {
association.mixin(source.prototype); association.mixin(source.prototype);
if (options.useHooks) { if (options.useHooks) {
source.runHooks('afterAssociate', { source, target, type: Type, association }, options); source.hooks.run('afterAssociate', { source, target, type: Type, association }, options);
} }
return association; return association;
......
...@@ -325,9 +325,9 @@ class ConnectionManager { ...@@ -325,9 +325,9 @@ class ConnectionManager {
* @returns {Promise<Connection>} * @returns {Promise<Connection>}
*/ */
_connect(config) { _connect(config) {
return this.sequelize.runHooks('beforeConnect', config) return this.sequelize.hooks.run('beforeConnect', config)
.then(() => this.dialect.connectionManager.connect(config)) .then(() => this.dialect.connectionManager.connect(config))
.then(connection => this.sequelize.runHooks('afterConnect', connection, config).return(connection)); .then(connection => this.sequelize.hooks.run('afterConnect', connection, config).return(connection));
} }
/** /**
......
...@@ -44,10 +44,11 @@ const hookTypes = { ...@@ -44,10 +44,11 @@ const hookTypes = {
afterConnect: { params: 2, noModel: true }, afterConnect: { params: 2, noModel: true },
beforeSync: { params: 1 }, beforeSync: { params: 1 },
afterSync: { params: 1 }, afterSync: { params: 1 },
beforeBulkSync: { params: 1 }, beforeBulkSync: { params: 1, noModel: true },
afterBulkSync: { params: 1 }, afterBulkSync: { params: 1, noModel: true },
beforeQuery: { params: 2 }, beforeQuery: { params: 2 },
afterQuery: { params: 2 } afterQuery: { params: 2 },
afterCommit: { params: 1 }
}; };
exports.hooks = hookTypes; exports.hooks = hookTypes;
...@@ -65,39 +66,40 @@ const getProxiedHooks = hookType => ...@@ -65,39 +66,40 @@ const getProxiedHooks = hookType =>
: [hookType] : [hookType]
; ;
function getHooks(hooked, hookType) { class Hooks {
return (hooked.options.hooks || {})[hookType] || []; _getHooks(hookType) {
} return this.hooks[hookType] || [];
}
const Hooks = {
/** /**
* Process user supplied hooks definition * Process user supplied hooks definition
* *
* @param {object} hooks hooks definition * @param {object} hooks hooks definition
* * @param {Hooks} parent
* @private * @private
* @memberof Sequelize
* @memberof Sequelize.Model
*/ */
_setupHooks(hooks = {}) { constructor(hooks, parent) {
this.options.hooks = {}; this.hooks = {};
this.parent = parent;
if (!hooks) {
return;
}
_.map(hooks, (hooksArray, hookName) => { _.map(hooks, (hooksArray, hookName) => {
if (!Array.isArray(hooksArray)) hooksArray = [hooksArray]; if (!Array.isArray(hooksArray)) hooksArray = [hooksArray];
hooksArray.forEach(hookFn => this.addHook(hookName, hookFn)); hooksArray.forEach(hookFn => this.add(hookName, hookFn));
}); });
}, }
runHooks(hooks, ...hookArgs) { run(hooks, ...hookArgs) {
if (!hooks) throw new Error('runHooks requires at least 1 argument'); if (!hooks) throw new Error('hooks.run requires at least 1 argument');
let hookType; let hookType;
if (typeof hooks === 'string') { if (typeof hooks === 'string') {
hookType = hooks; hookType = hooks;
hooks = getHooks(this, hookType); hooks = this._getHooks(hookType);
if (this.sequelize) { if (this.parent) {
hooks = hooks.concat(getHooks(this.sequelize, hookType)); hooks = hooks.concat(this.parent._getHooks(hookType));
} }
} }
...@@ -107,70 +109,51 @@ const Hooks = { ...@@ -107,70 +109,51 @@ const Hooks = {
// synchronous hooks // synchronous hooks
if (hookTypes[hookType] && hookTypes[hookType].sync) { if (hookTypes[hookType] && hookTypes[hookType].sync) {
for (let hook of hooks) { for (const hook of hooks) {
if (typeof hook === 'object') {
hook = hook.fn;
}
debug(`running hook(sync) ${hookType}`); debug(`running hook(sync) ${hookType}`);
hook.apply(this, hookArgs); hook.fn(...hookArgs);
} }
return; return;
} }
// asynchronous hooks (default) // asynchronous hooks (default)
return Promise.each(hooks, hook => { return Promise.each(hooks, hook => {
if (typeof hook === 'object') {
hook = hook.fn;
}
debug(`running hook ${hookType}`); debug(`running hook ${hookType}`);
return hook.apply(this, hookArgs); return hook.fn(...hookArgs);
}).return(); }).return();
}, }
/** /**
* Add a hook to the model * Add a hook to the model
* *
* @param {string} hookType hook name @see {@link hookTypes} * @param {string} hookType hook name @see {@link hookTypes}
* @param {string|Function} [name] Provide a name for the hook function. It can be used to remove the hook later or to order hooks based on some sort of priority system in the future.
* @param {Function} fn The hook function * @param {Function} fn The hook function
*
* @memberof Sequelize
* @memberof Sequelize.Model
*/ */
addHook(hookType, name, fn) { add(hookType, fn) {
if (typeof name === 'function') { if (hookTypes[hookType] && hookTypes[hookType].noModel && this.parent) {
fn = name; throw new Error(`${hookType} is only applicable on a sequelize instance or static`);
name = null;
} }
debug(`adding hook ${hookType}`); debug(`adding hook ${hookType}`);
// check for proxies, add them too // check for proxies, add them too
hookType = getProxiedHooks(hookType); hookType = getProxiedHooks(hookType);
hookType.forEach(type => { hookType.forEach(type => {
const hooks = getHooks(this, type); const hooks = this._getHooks(type);
hooks.push(name ? { name, fn } : fn); hooks.push({ fn });
this.options.hooks[type] = hooks; this.hooks[type] = hooks;
}); });
return this; return this;
}, }
/** /**
* Remove hook from the model * Remove hook from the model
* *
* @param {string} hookType @see {@link hookTypes} * @param {string} hookType @see {@link hookTypes}
* @param {string|Function} name name of hook or function reference which was attached * @param {Function} fn name of hook or function reference which was attached
*
* @memberof Sequelize
* @memberof Sequelize.Model
*/ */
removeHook(hookType, name) { remove(hookType, fn) {
const isReference = typeof name === 'function' ? true : false; if (!this.has(hookType)) {
if (!this.hasHook(hookType)) {
return this; return this;
} }
...@@ -180,360 +163,26 @@ const Hooks = { ...@@ -180,360 +163,26 @@ const Hooks = {
hookType = getProxiedHooks(hookType); hookType = getProxiedHooks(hookType);
for (const type of hookType) { for (const type of hookType) {
this.options.hooks[type] = this.options.hooks[type].filter(hook => { this.hooks[type] = this.hooks[type].filter(({ fn: hookFn }) => fn !== hookFn);
if (isReference && typeof hook === 'function') {
return hook !== name; // check if same method
}
if (!isReference && typeof hook === 'object') {
return hook.name !== name;
}
return true;
});
} }
return this; return this;
}, }
/** /**
* Check whether the mode has any hooks of this type * Check whether the mode has any hooks of this type
* *
* @param {string} hookType @see {@link hookTypes} * @param {string} hookType @see {@link hookTypes}
*
* @alias hasHooks
*
* @memberof Sequelize
* @memberof Sequelize.Model
*/ */
hasHook(hookType) { has(hookType) {
return this.options.hooks[hookType] && !!this.options.hooks[hookType].length; return this.hooks[hookType] && !!this.hooks[hookType].length;
} }
};
Hooks.hasHooks = Hooks.hasHook;
/**
function applyTo(target, isModel = false) { * Removes all hooks
_.mixin(target, Hooks); */
removeAll() {
for (const hook of Object.keys(hookTypes)) { this.hooks = {};
if (isModel && hookTypes[hook].noModel) {
continue;
}
target[hook] = function(name, callback) {
return this.addHook(hook, name, callback);
};
} }
} }
exports.applyTo = applyTo; exports.Hooks = Hooks;
/**
* A hook that is run before validation
* @param {string} name
* @param {Function} fn A callback function that is called with instance, options
* @name beforeValidate
* @memberof Sequelize.Model
*/
/**
* A hook that is run after validation
* @param {string} name
* @param {Function} fn A callback function that is called with instance, options
* @name afterValidate
* @memberof Sequelize.Model
*/
/**
* 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
* @memberof Sequelize.Model
*/
/**
* 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
* @name beforeCreate
* @memberof Sequelize.Model
*/
/**
* A hook that is run after creating a single instance
* @param {string} name
* @param {Function} fn A callback function that is called with attributes, options
* @name afterCreate
* @memberof Sequelize.Model
*/
/**
* A hook that is run before creating or updating a single instance, It proxies `beforeCreate` and `beforeUpdate`
* @param {string} name
* @param {Function} fn A callback function that is called with attributes, options
* @name beforeSave
* @memberof Sequelize.Model
*/
/**
* A hook that is run before upserting
* @param {string} name
* @param {Function} fn A callback function that is called with attributes, options
* @name beforeUpsert
* @memberof Sequelize.Model
*/
/**
* A hook that is run after upserting
* @param {string} name
* @param {Function} fn A callback function that is called with the result of upsert(), options
* @name afterUpsert
* @memberof Sequelize.Model
*/
/**
* A hook that is run after creating or updating a single instance, It proxies `afterCreate` and `afterUpdate`
* @param {string} name
* @param {Function} fn A callback function that is called with attributes, options
* @name afterSave
* @memberof Sequelize.Model
*/
/**
* A hook that is run before destroying a single instance
* @param {string} name
* @param {Function} fn A callback function that is called with instance, options
*
* @name beforeDestroy
* @memberof Sequelize.Model
*/
/**
* A hook that is run after destroying a single instance
* @param {string} name
* @param {Function} fn A callback function that is called with instance, options
*
* @name afterDestroy
* @memberof Sequelize.Model
*/
/**
* 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
* @memberof Sequelize.Model
*/
/**
* 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
* @memberof Sequelize.Model
*/
/**
* 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
* @name beforeUpdate
* @memberof Sequelize.Model
*/
/**
* A hook that is run after updating a single instance
* @param {string} name
* @param {Function} fn A callback function that is called with instance, options
* @name afterUpdate
* @memberof Sequelize.Model
*/
/**
* A hook that is run before creating instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with instances, options
* @name beforeBulkCreate
* @memberof Sequelize.Model
*/
/**
* A hook that is run after creating instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with instances, options
* @name afterBulkCreate
* @memberof Sequelize.Model
*/
/**
* A hook that is run before destroying instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with options
*
* @name beforeBulkDestroy
* @memberof Sequelize.Model
*/
/**
* A hook that is run after destroying instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with options
*
* @name afterBulkDestroy
* @memberof Sequelize.Model
*/
/**
* 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
* @memberof Sequelize.Model
*/
/**
* 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
* @memberof Sequelize.Model
*/
/**
* A hook that is run before updating instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name beforeBulkUpdate
* @memberof Sequelize.Model
*/
/**
* A hook that is run after updating instances in bulk
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name afterBulkUpdate
* @memberof Sequelize.Model
*/
/**
* A hook that is run before a find (select) query
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name beforeFind
* @memberof Sequelize.Model
*/
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name beforeFindAfterExpandIncludeAll
* @memberof Sequelize.Model
*/
/**
* A hook that is run before a find (select) query, after all option parsing is complete
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name beforeFindAfterOptions
* @memberof Sequelize.Model
*/
/**
* A hook that is run after a find (select) query
* @param {string} name
* @param {Function} fn A callback function that is called with instance(s), options
* @name afterFind
* @memberof Sequelize.Model
*/
/**
* A hook that is run before a count query
* @param {string} name
* @param {Function} fn A callback function that is called with options
* @name beforeCount
* @memberof Sequelize.Model
*/
/**
* A hook that is run before a define call
* @param {string} name
* @param {Function} fn A callback function that is called with attributes, options
* @name beforeDefine
* @memberof Sequelize
*/
/**
* A hook that is run after a define call
* @param {string} name
* @param {Function} fn A callback function that is called with factory
* @name afterDefine
* @memberof Sequelize
*/
/**
* A hook that is run before Sequelize() call
* @param {string} name
* @param {Function} fn A callback function that is called with config, options
* @name beforeInit
* @memberof Sequelize
*/
/**
* A hook that is run after Sequelize() call
* @param {string} name
* @param {Function} fn A callback function that is called with sequelize
* @name afterInit
* @memberof Sequelize
*/
/**
* A hook that is run before a connection is created
* @param {string} name
* @param {Function} fn A callback function that is called with config passed to connection
* @name beforeConnect
* @memberof Sequelize
*/
/**
* A hook that is run after a connection is created
* @param {string} name
* @param {Function} fn A callback function that is called with the connection object and thye config passed to connection
* @name afterConnect
* @memberof Sequelize
*/
/**
* A hook that is run before Model.sync call
* @param {string} name
* @param {Function} fn A callback function that is called with options passed to Model.sync
* @name beforeSync
* @memberof Sequelize
*/
/**
* A hook that is run after Model.sync call
* @param {string} name
* @param {Function} fn A callback function that is called with options passed to Model.sync
* @name afterSync
* @memberof Sequelize
*/
/**
* A hook that is run before sequelize.sync call
* @param {string} name
* @param {Function} fn A callback function that is called with options passed to sequelize.sync
* @name beforeBulkSync
* @memberof Sequelize
*/
/**
* A hook that is run after sequelize.sync call
* @param {string} name
* @param {Function} fn A callback function that is called with options passed to sequelize.sync
* @name afterBulkSync
* @memberof Sequelize
*/
...@@ -102,14 +102,14 @@ class InstanceValidator { ...@@ -102,14 +102,14 @@ class InstanceValidator {
* @private * @private
*/ */
_validateAndRunHooks() { _validateAndRunHooks() {
const runHooks = this.modelInstance.constructor.runHooks.bind(this.modelInstance.constructor); const { hooks } = this.modelInstance.constructor;
return runHooks('beforeValidate', this.modelInstance, this.options) return hooks.run('beforeValidate', this.modelInstance, this.options)
.then(() => .then(() =>
this._validate() this._validate()
.catch(error => runHooks('validationFailed', this.modelInstance, this.options, error) .catch(error => hooks.run('validationFailed', this.modelInstance, this.options, error)
.then(newError => { throw newError || error; })) .then(newError => { throw newError || error; }))
) )
.then(() => runHooks('afterValidate', this.modelInstance, this.options)) .then(() => hooks.run('afterValidate', this.modelInstance, this.options))
.return(this.modelInstance); .return(this.modelInstance);
} }
......
...@@ -15,7 +15,7 @@ const Promise = require('./promise'); ...@@ -15,7 +15,7 @@ const Promise = require('./promise');
const Association = require('./associations/base'); const Association = require('./associations/base');
const HasMany = require('./associations/has-many'); const HasMany = require('./associations/has-many');
const DataTypes = require('./data-types'); const DataTypes = require('./data-types');
const Hooks = require('./hooks'); const { Hooks } = require('./hooks');
const associationsMixin = require('./associations/mixin'); const associationsMixin = require('./associations/mixin');
const Op = require('./operators'); const Op = require('./operators');
const { noDoubleNestedGroup } = require('./utils/deprecations'); const { noDoubleNestedGroup } = require('./utils/deprecations');
...@@ -939,7 +939,7 @@ class Model { ...@@ -939,7 +939,7 @@ class Model {
schema: globalOptions.schema schema: globalOptions.schema
}, options); }, options);
this.sequelize.runHooks('beforeDefine', attributes, options); this.sequelize.hooks.run('beforeDefine', attributes, options);
if (options.modelName !== this.name) { if (options.modelName !== this.name) {
Object.defineProperty(this, 'name', { value: options.modelName }); Object.defineProperty(this, 'name', { value: options.modelName });
...@@ -967,7 +967,6 @@ class Model { ...@@ -967,7 +967,6 @@ class Model {
} }
this.associations = {}; this.associations = {};
this._setupHooks(options.hooks);
this.underscored = this.options.underscored; this.underscored = this.options.underscored;
...@@ -1050,7 +1049,9 @@ class Model { ...@@ -1050,7 +1049,9 @@ class Model {
this._scopeNames = ['defaultScope']; this._scopeNames = ['defaultScope'];
this.sequelize.modelManager.addModel(this); this.sequelize.modelManager.addModel(this);
this.sequelize.runHooks('afterDefine', this); this.sequelize.hooks.run('afterDefine', this);
this.hooks = new Hooks(this.options.hooks, this.sequelize.hooks);
return this; return this;
} }
...@@ -1275,7 +1276,7 @@ class Model { ...@@ -1275,7 +1276,7 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeSync', options); return this.hooks.run('beforeSync', options);
} }
}).then(() => { }).then(() => {
if (options.force) { if (options.force) {
...@@ -1361,7 +1362,7 @@ class Model { ...@@ -1361,7 +1362,7 @@ class Model {
)); ));
}).then(() => { }).then(() => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterSync', options); return this.hooks.run('afterSync', options);
} }
}).return(this); }).return(this);
} }
...@@ -1699,7 +1700,7 @@ class Model { ...@@ -1699,7 +1700,7 @@ class Model {
this._injectScope(options); this._injectScope(options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFind', options); return this.hooks.run('beforeFind', options);
} }
}).then(() => { }).then(() => {
this._conformIncludes(options, this); this._conformIncludes(options, this);
...@@ -1707,7 +1708,7 @@ class Model { ...@@ -1707,7 +1708,7 @@ class Model {
this._expandIncludeAll(options); this._expandIncludeAll(options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFindAfterExpandIncludeAll', options); return this.hooks.run('beforeFindAfterExpandIncludeAll', options);
} }
}).then(() => { }).then(() => {
options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes); options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes);
...@@ -1742,7 +1743,7 @@ class Model { ...@@ -1742,7 +1743,7 @@ class Model {
options = this._paranoidClause(this, options); options = this._paranoidClause(this, options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFindAfterOptions', options); return this.hooks.run('beforeFindAfterOptions', options);
} }
}).then(() => { }).then(() => {
originalOptions = Utils.cloneDeep(options); originalOptions = Utils.cloneDeep(options);
...@@ -1750,7 +1751,7 @@ class Model { ...@@ -1750,7 +1751,7 @@ class Model {
return this.QueryInterface.select(this, this.getTableName(options), options); return this.QueryInterface.select(this, this.getTableName(options), options);
}).tap(results => { }).tap(results => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterFind', results, options); return this.hooks.run('afterFind', results, options);
} }
}).then(results => { }).then(results => {
...@@ -2019,7 +2020,7 @@ class Model { ...@@ -2019,7 +2020,7 @@ class Model {
...options ...options
}; };
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeCount', options); return this.hooks.run('beforeCount', options);
} }
}).then(() => { }).then(() => {
let col = options.col || '*'; let col = options.col || '*';
...@@ -2463,7 +2464,7 @@ class Model { ...@@ -2463,7 +2464,7 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeUpsert', values, options); return this.hooks.run('beforeUpsert', values, options);
} }
}) })
.then(() => { .then(() => {
...@@ -2478,7 +2479,7 @@ class Model { ...@@ -2478,7 +2479,7 @@ class Model {
}) })
.tap(result => { .tap(result => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterUpsert', result, options); return this.hooks.run('afterUpsert', result, options);
} }
}); });
}); });
...@@ -2554,7 +2555,7 @@ class Model { ...@@ -2554,7 +2555,7 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeBulkCreate', instances, options); return this.hooks.run('beforeBulkCreate', instances, options);
} }
}).then(() => { }).then(() => {
// Validate // Validate
...@@ -2658,7 +2659,7 @@ class Model { ...@@ -2658,7 +2659,7 @@ class Model {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterBulkCreate', instances, options); return this.hooks.run('afterBulkCreate', instances, options);
} }
}).then(() => instances); }).then(() => instances);
} }
...@@ -2734,13 +2735,13 @@ class Model { ...@@ -2734,13 +2735,13 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeBulkDestroy', options); return this.hooks.run('beforeBulkDestroy', options);
} }
}).then(() => { }).then(() => {
// Get daos and run beforeDestroy hook on each record individually // Get daos and run beforeDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return this.findAll({ where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark }) return this.findAll({ where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark })
.map(instance => this.runHooks('beforeDestroy', instance, options).then(() => instance)) .map(instance => this.hooks.run('beforeDestroy', instance, options).then(() => instance))
.then(_instances => { .then(_instances => {
instances = _instances; instances = _instances;
}); });
...@@ -2766,12 +2767,12 @@ class Model { ...@@ -2766,12 +2767,12 @@ class Model {
}).tap(() => { }).tap(() => {
// Run afterDestroy hook on each record individually // Run afterDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, instance => this.runHooks('afterDestroy', instance, options)); return Promise.map(instances, instance => this.hooks.run('afterDestroy', instance, options));
} }
}).tap(() => { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterBulkDestroy', options); return this.hooks.run('afterBulkDestroy', options);
} }
}); });
} }
...@@ -2808,13 +2809,13 @@ class Model { ...@@ -2808,13 +2809,13 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeBulkRestore', options); return this.hooks.run('beforeBulkRestore', options);
} }
}).then(() => { }).then(() => {
// Get daos and run beforeRestore hook on each record individually // Get daos and run beforeRestore hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return this.findAll({ where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark, paranoid: false }) return this.findAll({ where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark, paranoid: false })
.map(instance => this.runHooks('beforeRestore', instance, options).then(() => instance)) .map(instance => this.hooks.run('beforeRestore', instance, options).then(() => instance))
.then(_instances => { .then(_instances => {
instances = _instances; instances = _instances;
}); });
...@@ -2832,12 +2833,12 @@ class Model { ...@@ -2832,12 +2833,12 @@ class Model {
}).tap(() => { }).tap(() => {
// Run afterDestroy hook on each record individually // Run afterDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, instance => this.runHooks('afterRestore', instance, options)); return Promise.map(instances, instance => this.hooks.run('afterRestore', instance, options));
} }
}).tap(() => { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterBulkRestore', options); return this.hooks.run('afterBulkRestore', options);
} }
}); });
} }
...@@ -2935,7 +2936,7 @@ class Model { ...@@ -2935,7 +2936,7 @@ class Model {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
options.attributes = values; options.attributes = values;
return this.runHooks('beforeBulkUpdate', options).then(() => { return this.hooks.run('beforeBulkUpdate', options).then(() => {
values = options.attributes; values = options.attributes;
delete options.attributes; delete options.attributes;
}); });
...@@ -2974,7 +2975,7 @@ class Model { ...@@ -2974,7 +2975,7 @@ class Model {
}); });
// Run beforeUpdate hook // Run beforeUpdate hook
return this.runHooks('beforeUpdate', instance, options).then(() => { return this.hooks.run('beforeUpdate', instance, options).then(() => {
if (!different) { if (!different) {
const thisChangedValues = {}; const thisChangedValues = {};
_.forIn(instance.dataValues, (newValue, attr) => { _.forIn(instance.dataValues, (newValue, attr) => {
...@@ -3050,7 +3051,7 @@ class Model { ...@@ -3050,7 +3051,7 @@ class Model {
}).tap(result => { }).tap(result => {
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, instance => { return Promise.map(instances, instance => {
return this.runHooks('afterUpdate', instance, options); return this.hooks.run('afterUpdate', instance, options);
}).then(() => { }).then(() => {
result[1] = instances; result[1] = instances;
}); });
...@@ -3059,7 +3060,7 @@ class Model { ...@@ -3059,7 +3060,7 @@ class Model {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
options.attributes = values; options.attributes = values;
return this.runHooks('afterBulkUpdate', options).then(() => { return this.hooks.run('afterBulkUpdate', options).then(() => {
delete options.attributes; delete options.attributes;
}); });
} }
...@@ -3729,7 +3730,7 @@ class Model { ...@@ -3729,7 +3730,7 @@ class Model {
ignoreChanged = _.without(ignoreChanged, updatedAtAttr); ignoreChanged = _.without(ignoreChanged, updatedAtAttr);
} }
return this.constructor.runHooks(`before${hook}`, this, options) return this.constructor.hooks.run(`before${hook}`, this, options)
.then(() => { .then(() => {
if (options.defaultFields && !this.isNewRecord) { if (options.defaultFields && !this.isNewRecord) {
afterHookValues = _.pick(this.dataValues, _.difference(this.changed(), ignoreChanged)); afterHookValues = _.pick(this.dataValues, _.difference(this.changed(), ignoreChanged));
...@@ -3884,7 +3885,7 @@ class Model { ...@@ -3884,7 +3885,7 @@ class Model {
.tap(result => { .tap(result => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks(`after${hook}`, result, options); return this.constructor.hooks.run(`after${hook}`, result, options);
} }
}) })
.then(result => { .then(result => {
...@@ -4012,7 +4013,7 @@ class Model { ...@@ -4012,7 +4013,7 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('beforeDestroy', this, options); return this.constructor.hooks.run('beforeDestroy', this, options);
} }
}).then(() => { }).then(() => {
const where = this.where(true); const where = this.where(true);
...@@ -4044,7 +4045,7 @@ class Model { ...@@ -4044,7 +4045,7 @@ class Model {
}).tap(() => { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('afterDestroy', this, options); return this.constructor.hooks.run('afterDestroy', this, options);
} }
}); });
} }
...@@ -4089,7 +4090,7 @@ class Model { ...@@ -4089,7 +4090,7 @@ class Model {
return Promise.try(() => { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('beforeRestore', this, options); return this.constructor.hooks.run('beforeRestore', this, options);
} }
}).then(() => { }).then(() => {
const deletedAtCol = this.constructor._timestampAttributes.deletedAt; const deletedAtCol = this.constructor._timestampAttributes.deletedAt;
...@@ -4101,7 +4102,7 @@ class Model { ...@@ -4101,7 +4102,7 @@ class Model {
}).tap(() => { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('afterRestore', this, options); return this.constructor.hooks.run('afterRestore', this, options);
} }
}); });
} }
...@@ -4338,6 +4339,5 @@ class Model { ...@@ -4338,6 +4339,5 @@ class Model {
} }
Object.assign(Model, associationsMixin); Object.assign(Model, associationsMixin);
Hooks.applyTo(Model, true);
module.exports = Model; module.exports = Model;
...@@ -17,7 +17,7 @@ const TableHints = require('./table-hints'); ...@@ -17,7 +17,7 @@ const TableHints = require('./table-hints');
const IndexHints = require('./index-hints'); const IndexHints = require('./index-hints');
const sequelizeErrors = require('./errors'); const sequelizeErrors = require('./errors');
const Promise = require('./promise'); const Promise = require('./promise');
const Hooks = require('./hooks'); const { Hooks } = require('./hooks');
const Association = require('./associations/index'); const Association = require('./associations/index');
const Validator = require('./utils/validator-extras').validator; const Validator = require('./utils/validator-extras').validator;
const Op = require('./operators'); const Op = require('./operators');
...@@ -218,8 +218,9 @@ class Sequelize { ...@@ -218,8 +218,9 @@ class Sequelize {
options = options || {}; options = options || {};
config = { database, username, password }; config = { database, username, password };
} }
this.hooks = new Hooks(options.hooks);
Sequelize.runHooks('beforeInit', config, options); Sequelize.hooks.run('beforeInit', config, options);
this.options = Object.assign({ this.options = Object.assign({
dialect: null, dialect: null,
...@@ -273,7 +274,6 @@ class Sequelize { ...@@ -273,7 +274,6 @@ class Sequelize {
this.options.logging = console.log; this.options.logging = console.log;
} }
this._setupHooks(options.hooks);
this.config = { this.config = {
database: config.database || this.options.database, database: config.database || this.options.database,
...@@ -333,7 +333,7 @@ class Sequelize { ...@@ -333,7 +333,7 @@ class Sequelize {
this.importCache = {}; this.importCache = {};
Sequelize.runHooks('afterInit', this); Sequelize.hooks.run('afterInit', this);
} }
/** /**
...@@ -624,9 +624,9 @@ class Sequelize { ...@@ -624,9 +624,9 @@ class Sequelize {
: this.connectionManager.getConnection(options); : this.connectionManager.getConnection(options);
}).then(connection => { }).then(connection => {
const query = new this.dialect.Query(connection, this, options); const query = new this.dialect.Query(connection, this, options);
return this.runHooks('beforeQuery', options, query) return this.hooks.run('beforeQuery', options, query)
.then(() => query.run(sql, bindParameters)) .then(() => query.run(sql, bindParameters))
.finally(() => this.runHooks('afterQuery', options, query)) .finally(() => this.hooks.run('afterQuery', options, query))
.finally(() => { .finally(() => {
if (!options.transaction) { if (!options.transaction) {
return this.connectionManager.releaseConnection(connection); return this.connectionManager.releaseConnection(connection);
...@@ -779,7 +779,7 @@ class Sequelize { ...@@ -779,7 +779,7 @@ class Sequelize {
return Promise.try(() => { return Promise.try(() => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeBulkSync', options); return this.hooks.run('beforeBulkSync', options);
} }
}).then(() => { }).then(() => {
if (options.force) { if (options.force) {
...@@ -804,7 +804,7 @@ class Sequelize { ...@@ -804,7 +804,7 @@ class Sequelize {
return Promise.each(models, model => model.sync(options)); return Promise.each(models, model => model.sync(options));
}).then(() => { }).then(() => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterBulkSync', options); return this.hooks.run('afterBulkSync', options);
} }
}).return(this); }).return(this);
} }
...@@ -1177,6 +1177,8 @@ class Sequelize { ...@@ -1177,6 +1177,8 @@ class Sequelize {
} }
} }
Sequelize.hooks = new Hooks();
// Aliases // Aliases
Sequelize.prototype.fn = Sequelize.fn; Sequelize.prototype.fn = Sequelize.fn;
Sequelize.prototype.col = Sequelize.col; Sequelize.prototype.col = Sequelize.col;
...@@ -1193,8 +1195,6 @@ Sequelize.prototype.validate = Sequelize.prototype.authenticate; ...@@ -1193,8 +1195,6 @@ Sequelize.prototype.validate = Sequelize.prototype.authenticate;
*/ */
Sequelize.version = require('../package.json').version; Sequelize.version = require('../package.json').version;
Sequelize.options = { hooks: {} };
/** /**
* @private * @private
*/ */
...@@ -1275,13 +1275,6 @@ Sequelize.prototype.Association = Sequelize.Association = Association; ...@@ -1275,13 +1275,6 @@ Sequelize.prototype.Association = Sequelize.Association = Association;
Sequelize.useInflection = Utils.useInflection; Sequelize.useInflection = Utils.useInflection;
/** /**
* Allow hooks to be defined on Sequelize + on sequelize instance as universal hooks to run on all models
* and on Sequelize/sequelize methods e.g. Sequelize(), Sequelize#define()
*/
Hooks.applyTo(Sequelize);
Hooks.applyTo(Sequelize.prototype);
/**
* Expose various errors available * Expose various errors available
*/ */
......
'use strict'; 'use strict';
const Promise = require('./promise'); const Promise = require('./promise');
const { Hooks } = require('./hooks');
/** /**
* The transaction object is used to identify a running transaction. * The transaction object is used to identify a running transaction.
...@@ -21,9 +22,9 @@ class Transaction { ...@@ -21,9 +22,9 @@ class Transaction {
* @param {string} options.deferrable Sets the constraints to be deferred or immediately checked. * @param {string} options.deferrable Sets the constraints to be deferred or immediately checked.
*/ */
constructor(sequelize, options = {}) { constructor(sequelize, options = {}) {
this.hooks = new Hooks();
this.sequelize = sequelize; this.sequelize = sequelize;
this.savepoints = []; this.savepoints = [];
this._afterCommitHooks = [];
// get dialect specific transaction options // get dialect specific transaction options
const generateTransactionId = this.sequelize.dialect.QueryGenerator.generateTransactionId; const generateTransactionId = this.sequelize.dialect.QueryGenerator.generateTransactionId;
...@@ -68,11 +69,7 @@ class Transaction { ...@@ -68,11 +69,7 @@ class Transaction {
return this.cleanup(); return this.cleanup();
} }
return null; return null;
}).tap( }).tap(() => this.hooks.run('afterCommit', this));
() => Promise.each(
this._afterCommitHooks,
hook => Promise.resolve(hook.apply(this, [this])))
);
} }
/** /**
...@@ -159,20 +156,6 @@ class Transaction { ...@@ -159,20 +156,6 @@ class Transaction {
} }
/** /**
* A hook that is run after a transaction is committed
*
* @param {Function} fn A callback function that is called with the committed transaction
* @name afterCommit
* @memberof Sequelize.Transaction
*/
afterCommit(fn) {
if (!fn || typeof fn !== 'function') {
throw new Error('"fn" must be a function');
}
this._afterCommitHooks.push(fn);
}
/**
* Types can be set per-transaction by passing `options.type` to `sequelize.transaction`. * Types can be set per-transaction by passing `options.type` to `sequelize.transaction`.
* Default to `DEFERRED` but you can override the default type by passing `options.transactionType` in `new Sequelize`. * Default to `DEFERRED` but you can override the default type by passing `options.transactionType` in `new Sequelize`.
* Sqlite only. * Sqlite only.
......
...@@ -60,12 +60,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -60,12 +60,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
let beforeHook = false, let beforeHook = false,
afterHook = false; afterHook = false;
this.Tasks.beforeUpdate(() => { this.Tasks.hooks.add('beforeUpdate', () => {
beforeHook = true; beforeHook = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.afterUpdate(() => { this.Tasks.hooks.add('afterUpdate', () => {
afterHook = true; afterHook = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -83,7 +83,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -83,7 +83,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('on error', function() { it('on error', function() {
this.Tasks.afterUpdate(() => { this.Tasks.hooks.add('afterUpdate', () => {
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
...@@ -120,10 +120,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -120,10 +120,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeDestroy(beforeTask); this.Tasks.hooks.add('beforeDestroy', beforeTask);
this.Tasks.afterDestroy(afterTask); this.Tasks.hooks.add('afterDestroy', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -146,22 +146,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -146,22 +146,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = false, beforeTask = false,
afterTask = false; afterTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.reject(new Error(CustomErrorText)); return Promise.reject(new Error(CustomErrorText));
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -204,8 +204,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -204,8 +204,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.Tasks.beforeUpdate(beforeHook); this.Tasks.hooks.add('beforeUpdate', beforeHook);
this.Tasks.afterUpdate(afterHook); this.Tasks.hooks.add('afterUpdate', afterHook);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -220,7 +220,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -220,7 +220,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('on error', function() { it('on error', function() {
this.Tasks.afterUpdate(() => { this.Tasks.hooks.add('afterUpdate', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -257,10 +257,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -257,10 +257,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeUpdate(beforeTask); this.Tasks.hooks.add('beforeUpdate', beforeTask);
this.Tasks.afterUpdate(afterTask); this.Tasks.hooks.add('afterUpdate', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -282,13 +282,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -282,13 +282,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeUpdate(() => { this.Tasks.hooks.add('beforeUpdate', () => {
beforeTask(); beforeTask();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.Tasks.afterUpdate(afterTask); this.Tasks.hooks.add('afterUpdate', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -332,10 +332,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -332,10 +332,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeDestroy(beforeTask); this.Tasks.hooks.add('beforeDestroy', beforeTask);
this.Tasks.afterDestroy(afterTask); this.Tasks.hooks.add('afterDestroy', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -357,22 +357,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -357,22 +357,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = false, beforeTask = false,
afterTask = false; afterTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -417,10 +417,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -417,10 +417,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeUpdate(beforeTask); this.Tasks.hooks.add('beforeUpdate', beforeTask);
this.Tasks.afterUpdate(afterTask); this.Tasks.hooks.add('afterUpdate', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -442,22 +442,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -442,22 +442,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = false, beforeTask = false,
afterTask = false; afterTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeUpdate(() => { this.Tasks.hooks.add('beforeUpdate', () => {
beforeTask = true; beforeTask = true;
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
this.Tasks.afterUpdate(() => { this.Tasks.hooks.add('afterUpdate', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -502,10 +502,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -502,10 +502,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeDestroy(beforeTask); this.Tasks.hooks.add('beforeDestroy', beforeTask);
this.Tasks.afterDestroy(afterTask); this.Tasks.hooks.add('afterDestroy', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -528,22 +528,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -528,22 +528,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = false, beforeTask = false,
afterTask = false; afterTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -587,10 +587,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -587,10 +587,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = sinon.spy(), beforeTask = sinon.spy(),
afterTask = sinon.spy(); afterTask = sinon.spy();
this.Projects.beforeCreate(beforeProject); this.Projects.hooks.add('beforeCreate', beforeProject);
this.Projects.afterCreate(afterProject); this.Projects.hooks.add('afterCreate', afterProject);
this.Tasks.beforeUpdate(beforeTask); this.Tasks.hooks.add('beforeUpdate', beforeTask);
this.Tasks.afterUpdate(afterTask); this.Tasks.hooks.add('afterUpdate', afterTask);
return this.Projects.create({ title: 'New Project' }).then(project => { return this.Projects.create({ title: 'New Project' }).then(project => {
return this.Tasks.create({ title: 'New Task' }).then(task => { return this.Tasks.create({ title: 'New Task' }).then(task => {
...@@ -612,22 +612,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -612,22 +612,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeTask = false, beforeTask = false,
afterTask = false; afterTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeUpdate(() => { this.Tasks.hooks.add('beforeUpdate', () => {
beforeTask = true; beforeTask = true;
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
this.Tasks.afterUpdate(() => { this.Tasks.hooks.add('afterUpdate', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -686,32 +686,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -686,32 +686,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeMiniTask = false, beforeMiniTask = false,
afterMiniTask = false; afterMiniTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.MiniTasks.beforeDestroy(() => { this.MiniTasks.hooks.add('beforeDestroy', () => {
beforeMiniTask = true; beforeMiniTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.MiniTasks.afterDestroy(() => { this.MiniTasks.hooks.add('afterDestroy', () => {
afterMiniTask = true; afterMiniTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -742,32 +742,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -742,32 +742,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeMiniTask = false, beforeMiniTask = false,
afterMiniTask = false; afterMiniTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.MiniTasks.beforeDestroy(() => { this.MiniTasks.hooks.add('beforeDestroy', () => {
beforeMiniTask = true; beforeMiniTask = true;
return Promise.reject(new Error('Whoops!')); return Promise.reject(new Error('Whoops!'));
}); });
this.MiniTasks.afterDestroy(() => { this.MiniTasks.hooks.add('afterDestroy', () => {
afterMiniTask = true; afterMiniTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -828,32 +828,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -828,32 +828,32 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeMiniTask = false, beforeMiniTask = false,
afterMiniTask = false; afterMiniTask = false;
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.MiniTasks.beforeDestroy(() => { this.MiniTasks.hooks.add('beforeDestroy', () => {
beforeMiniTask = true; beforeMiniTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.MiniTasks.afterDestroy(() => { this.MiniTasks.hooks.add('afterDestroy', () => {
afterMiniTask = true; afterMiniTask = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -888,28 +888,28 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -888,28 +888,28 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
afterMiniTask = false; afterMiniTask = false;
const CustomErrorText = 'Whoops!'; const CustomErrorText = 'Whoops!';
this.Projects.beforeCreate(() => { this.Projects.hooks.add('beforeCreate', () => {
beforeProject = true; beforeProject = true;
}); });
this.Projects.afterCreate(() => { this.Projects.hooks.add('afterCreate', () => {
afterProject = true; afterProject = true;
}); });
this.Tasks.beforeDestroy(() => { this.Tasks.hooks.add('beforeDestroy', () => {
beforeTask = true; beforeTask = true;
throw new Error(CustomErrorText); throw new Error(CustomErrorText);
}); });
this.Tasks.afterDestroy(() => { this.Tasks.hooks.add('afterDestroy', () => {
afterTask = true; afterTask = true;
}); });
this.MiniTasks.beforeDestroy(() => { this.MiniTasks.hooks.add('beforeDestroy', () => {
beforeMiniTask = true; beforeMiniTask = true;
}); });
this.MiniTasks.afterDestroy(() => { this.MiniTasks.hooks.add('afterDestroy', () => {
afterMiniTask = true; afterMiniTask = true;
}); });
......
...@@ -39,9 +39,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -39,9 +39,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.User.beforeBulkCreate(beforeBulk); this.User.hooks.add('beforeBulkCreate', beforeBulk);
this.User.afterBulkCreate(afterBulk); this.User.hooks.add('afterBulkCreate', afterBulk);
return this.User.bulkCreate([ return this.User.bulkCreate([
{ username: 'Cheech', mood: 'sad' }, { username: 'Cheech', mood: 'sad' },
...@@ -55,7 +55,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -55,7 +55,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('should return an error from before', function() { it('should return an error from before', function() {
this.User.beforeBulkCreate(() => { this.User.hooks.add('beforeBulkCreate', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -66,7 +66,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -66,7 +66,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should return an error from after', function() { it('should return an error from after', function() {
this.User.afterBulkCreate(() => { this.User.hooks.add('afterBulkCreate', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -101,22 +101,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -101,22 +101,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
let beforeBulkCreate = false, let beforeBulkCreate = false,
afterBulkCreate = false; afterBulkCreate = false;
this.User.beforeBulkCreate(() => { this.User.hooks.add('beforeBulkCreate', () => {
beforeBulkCreate = true; beforeBulkCreate = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterBulkCreate(() => { this.User.hooks.add('afterBulkCreate', () => {
afterBulkCreate = true; afterBulkCreate = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.beforeCreate(user => { this.User.hooks.add('beforeCreate', user => {
user.beforeHookTest = true; user.beforeHookTest = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterCreate(user => { this.User.hooks.add('afterCreate', user => {
user.username = `User${user.id}`; user.username = `User${user.id}`;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -135,21 +135,21 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -135,21 +135,21 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
let beforeBulkCreate = false, let beforeBulkCreate = false,
afterBulkCreate = false; afterBulkCreate = false;
this.User.beforeBulkCreate(() => { this.User.hooks.add('beforeBulkCreate', () => {
beforeBulkCreate = true; beforeBulkCreate = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterBulkCreate(() => { this.User.hooks.add('afterBulkCreate', () => {
afterBulkCreate = true; afterBulkCreate = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.beforeCreate(() => { this.User.hooks.add('beforeCreate', () => {
return Promise.reject(new Error('You shall not pass!')); return Promise.reject(new Error('You shall not pass!'));
}); });
this.User.afterCreate(user => { this.User.hooks.add('afterCreate', user => {
user.username = `User${user.id}`; user.username = `User${user.id}`;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -169,8 +169,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -169,8 +169,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.User.beforeBulkUpdate(beforeBulk); this.User.hooks.add('beforeBulkUpdate', beforeBulk);
this.User.afterBulkUpdate(afterBulk); this.User.hooks.add('afterBulkUpdate', afterBulk);
return this.User.bulkCreate([ return this.User.bulkCreate([
{ username: 'Cheech', mood: 'sad' }, { username: 'Cheech', mood: 'sad' },
...@@ -186,7 +186,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -186,7 +186,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('should return an error from before', function() { it('should return an error from before', function() {
this.User.beforeBulkUpdate(() => { this.User.hooks.add('beforeBulkUpdate', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -199,7 +199,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -199,7 +199,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should return an error from after', function() { it('should return an error from after', function() {
this.User.afterBulkUpdate(() => { this.User.hooks.add('afterBulkUpdate', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -236,16 +236,16 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -236,16 +236,16 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.User.beforeBulkUpdate(beforeBulk); this.User.hooks.add('beforeBulkUpdate', beforeBulk);
this.User.afterBulkUpdate(afterBulk); this.User.hooks.add('afterBulkUpdate', afterBulk);
this.User.beforeUpdate(user => { this.User.hooks.add('beforeUpdate', user => {
expect(user.changed()).to.not.be.empty; expect(user.changed()).to.not.be.empty;
user.beforeHookTest = true; user.beforeHookTest = true;
}); });
this.User.afterUpdate(user => { this.User.hooks.add('afterUpdate', user => {
user.username = `User${user.id}`; user.username = `User${user.id}`;
}); });
...@@ -264,7 +264,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -264,7 +264,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should run the after/before functions for each item created successfully changing some data before updating', function() { it('should run the after/before functions for each item created successfully changing some data before updating', function() {
this.User.beforeUpdate(user => { this.User.hooks.add('beforeUpdate', user => {
expect(user.changed()).to.not.be.empty; expect(user.changed()).to.not.be.empty;
if (user.get('id') === 1) { if (user.get('id') === 1) {
user.set('aNumber', user.get('aNumber') + 3); user.set('aNumber', user.get('aNumber') + 3);
...@@ -286,15 +286,15 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -286,15 +286,15 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.User.beforeBulkUpdate(beforeBulk); this.User.hooks.add('beforeBulkUpdate', beforeBulk);
this.User.afterBulkUpdate(afterBulk); this.User.hooks.add('afterBulkUpdate', afterBulk);
this.User.beforeUpdate(() => { this.User.hooks.add('beforeUpdate', () => {
throw new Error('You shall not pass!'); throw new Error('You shall not pass!');
}); });
this.User.afterUpdate(user => { this.User.hooks.add('afterUpdate', user => {
user.username = `User${user.id}`; user.username = `User${user.id}`;
}); });
...@@ -316,8 +316,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -316,8 +316,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.User.beforeBulkDestroy(beforeBulk); this.User.hooks.add('beforeBulkDestroy', beforeBulk);
this.User.afterBulkDestroy(afterBulk); this.User.hooks.add('afterBulkDestroy', afterBulk);
return this.User.destroy({ where: { username: 'Cheech', mood: 'sad' } }).then(() => { return this.User.destroy({ where: { username: 'Cheech', mood: 'sad' } }).then(() => {
expect(beforeBulk).to.have.been.calledOnce; expect(beforeBulk).to.have.been.calledOnce;
...@@ -328,7 +328,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -328,7 +328,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('should return an error from before', function() { it('should return an error from before', function() {
this.User.beforeBulkDestroy(() => { this.User.hooks.add('beforeBulkDestroy', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -336,7 +336,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -336,7 +336,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should return an error from after', function() { it('should return an error from after', function() {
this.User.afterBulkDestroy(() => { this.User.hooks.add('afterBulkDestroy', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -370,22 +370,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -370,22 +370,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeHook = false, beforeHook = false,
afterHook = false; afterHook = false;
this.User.beforeBulkDestroy(() => { this.User.hooks.add('beforeBulkDestroy', () => {
beforeBulk = true; beforeBulk = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterBulkDestroy(() => { this.User.hooks.add('afterBulkDestroy', () => {
afterBulk = true; afterBulk = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.beforeDestroy(() => { this.User.hooks.add('beforeDestroy', () => {
beforeHook = true; beforeHook = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterDestroy(() => { this.User.hooks.add('afterDestroy', () => {
afterHook = true; afterHook = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -408,22 +408,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -408,22 +408,22 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeHook = false, beforeHook = false,
afterHook = false; afterHook = false;
this.User.beforeBulkDestroy(() => { this.User.hooks.add('beforeBulkDestroy', () => {
beforeBulk = true; beforeBulk = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.afterBulkDestroy(() => { this.User.hooks.add('afterBulkDestroy', () => {
afterBulk = true; afterBulk = true;
return Promise.resolve(); return Promise.resolve();
}); });
this.User.beforeDestroy(() => { this.User.hooks.add('beforeDestroy', () => {
beforeHook = true; beforeHook = true;
return Promise.reject(new Error('You shall not pass!')); return Promise.reject(new Error('You shall not pass!'));
}); });
this.User.afterDestroy(() => { this.User.hooks.add('afterDestroy', () => {
afterHook = true; afterHook = true;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -456,8 +456,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -456,8 +456,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeBulk = sinon.spy(), const beforeBulk = sinon.spy(),
afterBulk = sinon.spy(); afterBulk = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk); this.ParanoidUser.hooks.add('beforeBulkRestore', beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk); this.ParanoidUser.hooks.add('afterBulkRestore', afterBulk);
return this.ParanoidUser.restore({ where: { username: 'adam', mood: 'happy' } }).then(() => { return this.ParanoidUser.restore({ where: { username: 'adam', mood: 'happy' } }).then(() => {
expect(beforeBulk).to.have.been.calledOnce; expect(beforeBulk).to.have.been.calledOnce;
...@@ -468,7 +468,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -468,7 +468,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('should return an error from before', function() { it('should return an error from before', function() {
this.ParanoidUser.beforeBulkRestore(() => { this.ParanoidUser.hooks.add('beforeBulkRestore', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -476,7 +476,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -476,7 +476,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should return an error from after', function() { it('should return an error from after', function() {
this.ParanoidUser.afterBulkRestore(() => { this.ParanoidUser.hooks.add('afterBulkRestore', () => {
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -504,10 +504,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -504,10 +504,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeHook = sinon.spy(), beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk); this.ParanoidUser.hooks.add('beforeBulkRestore', beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk); this.ParanoidUser.hooks.add('afterBulkRestore', afterBulk);
this.ParanoidUser.beforeRestore(beforeHook); this.ParanoidUser.hooks.add('beforeRestore', beforeHook);
this.ParanoidUser.afterRestore(afterHook); this.ParanoidUser.hooks.add('afterRestore', afterHook);
return this.ParanoidUser.bulkCreate([ return this.ParanoidUser.bulkCreate([
{ aNumber: 1 }, { aNumber: 1 }, { aNumber: 1 } { aNumber: 1 }, { aNumber: 1 }, { aNumber: 1 }
...@@ -529,14 +529,14 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -529,14 +529,14 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeHook = sinon.spy(), beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.ParanoidUser.beforeBulkRestore(beforeBulk); this.ParanoidUser.hooks.add('beforeBulkRestore', beforeBulk);
this.ParanoidUser.afterBulkRestore(afterBulk); this.ParanoidUser.hooks.add('afterBulkRestore', afterBulk);
this.ParanoidUser.beforeRestore(() => { this.ParanoidUser.hooks.add('beforeRestore', () => {
beforeHook(); beforeHook();
return Promise.reject(new Error('You shall not pass!')); return Promise.reject(new Error('You shall not pass!'));
}); });
this.ParanoidUser.afterRestore(afterHook); this.ParanoidUser.hooks.add('afterRestore', afterHook);
return this.ParanoidUser.bulkCreate([{ aNumber: 1 }, { aNumber: 1 }, { aNumber: 1 }], { fields: ['aNumber'] }).then(() => { return this.ParanoidUser.bulkCreate([{ aNumber: 1 }, { aNumber: 1 }, { aNumber: 1 }], { fields: ['aNumber'] }).then(() => {
return this.ParanoidUser.destroy({ where: { aNumber: 1 } }); return this.ParanoidUser.destroy({ where: { aNumber: 1 } });
......
...@@ -33,7 +33,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -33,7 +33,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('hook runs', function() { it('hook runs', function() {
let beforeHook = false; let beforeHook = false;
this.User.beforeCount(() => { this.User.hooks.add('beforeCount', () => {
beforeHook = true; beforeHook = true;
}); });
...@@ -44,7 +44,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -44,7 +44,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('beforeCount hook can change options', function() { it('beforeCount hook can change options', function() {
this.User.beforeCount(options => { this.User.hooks.add('beforeCount', options => {
options.where.username = 'adam'; options.where.username = 'adam';
}); });
...@@ -54,7 +54,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -54,7 +54,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('in beforeCount hook returns error', function() { it('in beforeCount hook returns error', function() {
this.User.beforeCount(() => { this.User.hooks.add('beforeCount', () => {
throw new Error('Oops!'); throw new Error('Oops!');
}); });
......
...@@ -31,10 +31,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -31,10 +31,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeSave = sinon.spy(), beforeSave = sinon.spy(),
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeCreate(beforeHook); this.User.hooks.add('beforeCreate', beforeHook);
this.User.afterCreate(afterHook); this.User.hooks.add('afterCreate', afterHook);
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(() => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -52,13 +52,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -52,13 +52,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
afterHook = sinon.spy(), afterHook = sinon.spy(),
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeCreate(() => { this.User.hooks.add('beforeCreate', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.afterCreate(afterHook); this.User.hooks.add('afterCreate', afterHook);
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return expect(this.User.create({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => { return expect(this.User.create({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -75,13 +75,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -75,13 +75,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeCreate(beforeHook); this.User.hooks.add('beforeCreate', beforeHook);
this.User.afterCreate(() => { this.User.hooks.add('afterCreate', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return expect(this.User.create({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => { return expect(this.User.create({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -102,7 +102,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -102,7 +102,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
let hookCalled = 0; let hookCalled = 0;
A.addHook('afterCreate', () => { A.hooks.add('afterCreate', () => {
hookCalled++; hookCalled++;
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -126,7 +126,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -126,7 +126,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeValidate', function() { it('beforeValidate', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeValidate(user => { this.User.hooks.add('beforeValidate', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
...@@ -141,7 +141,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -141,7 +141,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('afterValidate', function() { it('afterValidate', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.afterValidate(user => { this.User.hooks.add('afterValidate', user => {
user.mood = 'neutral'; user.mood = 'neutral';
hookCalled++; hookCalled++;
}); });
...@@ -156,7 +156,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -156,7 +156,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeCreate', function() { it('beforeCreate', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeCreate(user => { this.User.hooks.add('beforeCreate', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
...@@ -171,7 +171,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -171,7 +171,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeSave', function() { it('beforeSave', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeSave(user => { this.User.hooks.add('beforeSave', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
...@@ -186,12 +186,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -186,12 +186,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeSave with beforeCreate', function() { it('beforeSave with beforeCreate', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeCreate(user => { this.User.hooks.add('beforeCreate', user => {
user.mood = 'sad'; user.mood = 'sad';
hookCalled++; hookCalled++;
}); });
this.User.beforeSave(user => { this.User.hooks.add('beforeSave', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
......
...@@ -27,8 +27,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -27,8 +27,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeDestroy(beforeHook); this.User.hooks.add('beforeDestroy', beforeHook);
this.User.afterDestroy(afterHook); this.User.hooks.add('afterDestroy', afterHook);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => {
return user.destroy().then(() => { return user.destroy().then(() => {
...@@ -44,11 +44,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -44,11 +44,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeDestroy(() => { this.User.hooks.add('beforeDestroy', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.afterDestroy(afterHook); this.User.hooks.add('afterDestroy', afterHook);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => {
return expect(user.destroy()).to.be.rejected.then(() => { return expect(user.destroy()).to.be.rejected.then(() => {
...@@ -62,8 +62,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -62,8 +62,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeDestroy(beforeHook); this.User.hooks.add('beforeDestroy', beforeHook);
this.User.afterDestroy(() => { this.User.hooks.add('afterDestroy', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -107,7 +107,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -107,7 +107,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('should not throw error when a beforeDestroy hook changes a virtual column', function() { it('should not throw error when a beforeDestroy hook changes a virtual column', function() {
this.ParanoidUser.beforeDestroy(instance => instance.virtualField = 2); this.ParanoidUser.hooks.add('beforeDestroy', instance => instance.virtualField = 2);
return this.ParanoidUser.sync({ force: true }) return this.ParanoidUser.sync({ force: true })
.then(() => this.ParanoidUser.create({ username: 'user1' })) .then(() => this.ParanoidUser.create({ username: 'user1' }))
......
...@@ -30,7 +30,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -30,7 +30,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('allow changing attributes via beforeFind #5675', function() { it('allow changing attributes via beforeFind #5675', function() {
this.User.beforeFind(options => { this.User.hooks.add('beforeFind', options => {
options.attributes = { options.attributes = {
include: ['id'] include: ['id']
}; };
...@@ -45,19 +45,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -45,19 +45,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeHook3 = false, beforeHook3 = false,
afterHook = false; afterHook = false;
this.User.beforeFind(() => { this.User.hooks.add('beforeFind', () => {
beforeHook = true; beforeHook = true;
}); });
this.User.beforeFindAfterExpandIncludeAll(() => { this.User.hooks.add('beforeFindAfterExpandIncludeAll', () => {
beforeHook2 = true; beforeHook2 = true;
}); });
this.User.beforeFindAfterOptions(() => { this.User.hooks.add('beforeFindAfterOptions', () => {
beforeHook3 = true; beforeHook3 = true;
}); });
this.User.afterFind(() => { this.User.hooks.add('afterFind', () => {
afterHook = true; afterHook = true;
}); });
...@@ -71,7 +71,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -71,7 +71,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('beforeFind hook can change options', function() { it('beforeFind hook can change options', function() {
this.User.beforeFind(options => { this.User.hooks.add('beforeFind', options => {
options.where.username = 'joe'; options.where.username = 'joe';
}); });
...@@ -81,7 +81,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -81,7 +81,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('beforeFindAfterExpandIncludeAll hook can change options', function() { it('beforeFindAfterExpandIncludeAll hook can change options', function() {
this.User.beforeFindAfterExpandIncludeAll(options => { this.User.hooks.add('beforeFindAfterExpandIncludeAll', options => {
options.where.username = 'joe'; options.where.username = 'joe';
}); });
...@@ -91,7 +91,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -91,7 +91,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('beforeFindAfterOptions hook can change options', function() { it('beforeFindAfterOptions hook can change options', function() {
this.User.beforeFindAfterOptions(options => { this.User.hooks.add('beforeFindAfterOptions', options => {
options.where.username = 'joe'; options.where.username = 'joe';
}); });
...@@ -101,7 +101,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -101,7 +101,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('afterFind hook can change results', function() { it('afterFind hook can change results', function() {
this.User.afterFind(user => { this.User.hooks.add('afterFind', user => {
user.mood = 'sad'; user.mood = 'sad';
}); });
...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('in beforeFind hook returns error', function() { it('in beforeFind hook returns error', function() {
this.User.beforeFind(() => { this.User.hooks.add('beforeFind', () => {
throw new Error('Oops!'); throw new Error('Oops!');
}); });
...@@ -123,7 +123,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -123,7 +123,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('in beforeFindAfterExpandIncludeAll hook returns error', function() { it('in beforeFindAfterExpandIncludeAll hook returns error', function() {
this.User.beforeFindAfterExpandIncludeAll(() => { this.User.hooks.add('beforeFindAfterExpandIncludeAll', () => {
throw new Error('Oops!'); throw new Error('Oops!');
}); });
...@@ -133,7 +133,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -133,7 +133,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('in beforeFindAfterOptions hook returns error', function() { it('in beforeFindAfterOptions hook returns error', function() {
this.User.beforeFindAfterOptions(() => { this.User.hooks.add('beforeFindAfterOptions', () => {
throw new Error('Oops!'); throw new Error('Oops!');
}); });
...@@ -143,7 +143,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -143,7 +143,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('in afterFind hook returns error', function() { it('in afterFind hook returns error', function() {
this.User.afterFind(() => { this.User.hooks.add('afterFind', () => {
throw new Error('Oops!'); throw new Error('Oops!');
}); });
......
...@@ -37,13 +37,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -37,13 +37,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('#define', () => { describe('#define', () => {
before(function() { before(function() {
this.sequelize.addHook('beforeDefine', (attributes, options) => { this.sequelize.hooks.add('beforeDefine', (attributes, options) => {
options.modelName = 'bar'; options.modelName = 'bar';
options.name.plural = 'barrs'; options.name.plural = 'barrs';
attributes.type = DataTypes.STRING; attributes.type = DataTypes.STRING;
}); });
this.sequelize.addHook('afterDefine', factory => { this.sequelize.hooks.add('afterDefine', factory => {
factory.options.name.singular = 'barr'; factory.options.name.singular = 'barr';
}); });
...@@ -67,19 +67,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -67,19 +67,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
after(function() { after(function() {
this.sequelize.options.hooks = {}; this.sequelize.hooks.removeAll();
this.sequelize.modelManager.removeModel(this.model); this.sequelize.modelManager.removeModel(this.model);
}); });
}); });
describe('#init', () => { describe('#init', () => {
before(function() { before(function() {
Sequelize.addHook('beforeInit', (config, options) => { Sequelize.hooks.add('beforeInit', (config, options) => {
config.database = 'db2'; config.database = 'db2';
options.host = 'server9'; options.host = 'server9';
}); });
Sequelize.addHook('afterInit', sequelize => { Sequelize.hooks.add('afterInit', sequelize => {
sequelize.options.protocol = 'udp'; sequelize.options.protocol = 'udp';
}); });
...@@ -99,7 +99,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -99,7 +99,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
after(() => { after(() => {
Sequelize.options.hooks = {}; Sequelize.hooks.removeAll();
}); });
}); });
...@@ -236,8 +236,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -236,8 +236,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeSync(beforeHook); this.User.hooks.add('beforeSync', beforeHook);
this.User.afterSync(afterHook); this.User.hooks.add('afterSync', afterHook);
return this.User.sync().then(() => { return this.User.sync().then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -249,8 +249,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -249,8 +249,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeSync(beforeHook); this.User.hooks.add('beforeSync', beforeHook);
this.User.afterSync(afterHook); this.User.hooks.add('afterSync', afterHook);
return this.User.sync({ hooks: false }).then(() => { return this.User.sync({ hooks: false }).then(() => {
expect(beforeHook).to.not.have.been.called; expect(beforeHook).to.not.have.been.called;
...@@ -265,11 +265,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -265,11 +265,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeSync(() => { this.User.hooks.add('beforeSync', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.afterSync(afterHook); this.User.hooks.add('afterSync', afterHook);
return expect(this.User.sync()).to.be.rejected.then(() => { return expect(this.User.sync()).to.be.rejected.then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -281,8 +281,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -281,8 +281,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeSync(beforeHook); this.User.hooks.add('beforeSync', beforeHook);
this.User.afterSync(() => { this.User.hooks.add('afterSync', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -303,10 +303,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -303,10 +303,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
modelBeforeHook = sinon.spy(), modelBeforeHook = sinon.spy(),
modelAfterHook = sinon.spy(); modelAfterHook = sinon.spy();
this.sequelize.beforeBulkSync(beforeHook); this.sequelize.hooks.add('beforeBulkSync', beforeHook);
this.User.beforeSync(modelBeforeHook); this.User.hooks.add('beforeSync', modelBeforeHook);
this.User.afterSync(modelAfterHook); this.User.hooks.add('afterSync', modelAfterHook);
this.sequelize.afterBulkSync(afterHook); this.sequelize.hooks.add('afterBulkSync', afterHook);
return this.sequelize.sync().then(() => { return this.sequelize.sync().then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -322,10 +322,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -322,10 +322,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
modelBeforeHook = sinon.spy(), modelBeforeHook = sinon.spy(),
modelAfterHook = sinon.spy(); modelAfterHook = sinon.spy();
this.sequelize.beforeBulkSync(beforeHook); this.sequelize.hooks.add('beforeBulkSync', beforeHook);
this.User.beforeSync(modelBeforeHook); this.User.hooks.add('beforeSync', modelBeforeHook);
this.User.afterSync(modelAfterHook); this.User.hooks.add('afterSync', modelAfterHook);
this.sequelize.afterBulkSync(afterHook); this.sequelize.hooks.add('afterBulkSync', afterHook);
return this.sequelize.sync({ hooks: false }).then(() => { return this.sequelize.sync({ hooks: false }).then(() => {
expect(beforeHook).to.not.have.been.called; expect(beforeHook).to.not.have.been.called;
...@@ -336,7 +336,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -336,7 +336,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
afterEach(function() { afterEach(function() {
this.sequelize.options.hooks = {}; this.sequelize.hooks.removeAll();
}); });
}); });
...@@ -346,11 +346,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -346,11 +346,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('should return an error from before', function() { it('should return an error from before', function() {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.sequelize.beforeBulkSync(() => { this.sequelize.hooks.add('beforeBulkSync', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.sequelize.afterBulkSync(afterHook); this.sequelize.hooks.add('afterBulkSync', afterHook);
return expect(this.sequelize.sync()).to.be.rejected.then(() => { return expect(this.sequelize.sync()).to.be.rejected.then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -362,8 +362,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -362,8 +362,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.sequelize.beforeBulkSync(beforeHook); this.sequelize.hooks.add('beforeBulkSync', beforeHook);
this.sequelize.afterBulkSync(() => { this.sequelize.hooks.add('afterBulkSync', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -375,42 +375,24 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -375,42 +375,24 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
afterEach(function() { afterEach(function() {
this.sequelize.options.hooks = {}; this.sequelize.hooks.removeAll();
}); });
}); });
}); });
describe('#removal', () => { describe('#removal', () => {
it('should be able to remove by name', function() {
const sasukeHook = sinon.spy(),
narutoHook = sinon.spy();
this.User.addHook('beforeCreate', 'sasuke', sasukeHook);
this.User.addHook('beforeCreate', 'naruto', narutoHook);
return this.User.create({ username: 'makunouchi' }).then(() => {
expect(sasukeHook).to.have.been.calledOnce;
expect(narutoHook).to.have.been.calledOnce;
this.User.removeHook('beforeCreate', 'sasuke');
return this.User.create({ username: 'sendo' });
}).then(() => {
expect(sasukeHook).to.have.been.calledOnce;
expect(narutoHook).to.have.been.calledTwice;
});
});
it('should be able to remove by reference', function() { it('should be able to remove by reference', function() {
const sasukeHook = sinon.spy(), const sasukeHook = sinon.spy(),
narutoHook = sinon.spy(); narutoHook = sinon.spy();
this.User.addHook('beforeCreate', sasukeHook); this.User.hooks.add('beforeCreate', sasukeHook);
this.User.addHook('beforeCreate', narutoHook); this.User.hooks.add('beforeCreate', narutoHook);
return this.User.create({ username: 'makunouchi' }).then(() => { return this.User.create({ username: 'makunouchi' }).then(() => {
expect(sasukeHook).to.have.been.calledOnce; expect(sasukeHook).to.have.been.calledOnce;
expect(narutoHook).to.have.been.calledOnce; expect(narutoHook).to.have.been.calledOnce;
this.User.removeHook('beforeCreate', sasukeHook); this.User.hooks.remove('beforeCreate', sasukeHook);
return this.User.create({ username: 'sendo' }); return this.User.create({ username: 'sendo' });
}).then(() => { }).then(() => {
expect(sasukeHook).to.have.been.calledOnce; expect(sasukeHook).to.have.been.calledOnce;
...@@ -422,13 +404,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -422,13 +404,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const sasukeHook = sinon.spy(), const sasukeHook = sinon.spy(),
narutoHook = sinon.spy(); narutoHook = sinon.spy();
this.User.addHook('beforeSave', sasukeHook); this.User.hooks.add('beforeSave', sasukeHook);
this.User.addHook('beforeSave', narutoHook); this.User.hooks.add('beforeSave', narutoHook);
return this.User.create({ username: 'makunouchi' }).then(user => { return this.User.create({ username: 'makunouchi' }).then(user => {
expect(sasukeHook).to.have.been.calledOnce; expect(sasukeHook).to.have.been.calledOnce;
expect(narutoHook).to.have.been.calledOnce; expect(narutoHook).to.have.been.calledOnce;
this.User.removeHook('beforeSave', sasukeHook); this.User.hooks.remove('beforeSave', sasukeHook);
return user.update({ username: 'sendo' }); return user.update({ username: 'sendo' });
}).then(() => { }).then(() => {
expect(sasukeHook).to.have.been.calledOnce; expect(sasukeHook).to.have.been.calledOnce;
......
...@@ -38,8 +38,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -38,8 +38,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(beforeHook); this.ParanoidUser.hooks.add('beforeRestore', beforeHook);
this.ParanoidUser.afterRestore(afterHook); this.ParanoidUser.hooks.add('afterRestore', afterHook);
return this.ParanoidUser.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.ParanoidUser.create({ username: 'Toni', mood: 'happy' }).then(user => {
return user.destroy().then(() => { return user.destroy().then(() => {
...@@ -57,11 +57,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -57,11 +57,11 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(() => { this.ParanoidUser.hooks.add('beforeRestore', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.ParanoidUser.afterRestore(afterHook); this.ParanoidUser.hooks.add('afterRestore', afterHook);
return this.ParanoidUser.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.ParanoidUser.create({ username: 'Toni', mood: 'happy' }).then(user => {
return user.destroy().then(() => { return user.destroy().then(() => {
...@@ -77,8 +77,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -77,8 +77,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.ParanoidUser.beforeRestore(beforeHook); this.ParanoidUser.hooks.add('beforeRestore', beforeHook);
this.ParanoidUser.afterRestore(() => { this.ParanoidUser.hooks.add('afterRestore', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
......
...@@ -29,10 +29,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -29,10 +29,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeSave = sinon.spy(), beforeSave = sinon.spy(),
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeUpdate(beforeHook); this.User.hooks.add('beforeUpdate', beforeHook);
this.User.afterUpdate(afterHook); this.User.hooks.add('afterUpdate', afterHook);
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => {
return user.update({ username: 'Chong' }).then(user => { return user.update({ username: 'Chong' }).then(user => {
...@@ -53,13 +53,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -53,13 +53,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeSave = sinon.spy(), beforeSave = sinon.spy(),
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeUpdate(() => { this.User.hooks.add('beforeUpdate', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.afterUpdate(afterHook); this.User.hooks.add('afterUpdate', afterHook);
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => {
return expect(user.update({ username: 'Chong' })).to.be.rejected.then(() => { return expect(user.update({ username: 'Chong' })).to.be.rejected.then(() => {
...@@ -77,13 +77,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -77,13 +77,13 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeSave = sinon.spy(), beforeSave = sinon.spy(),
afterSave = sinon.spy(); afterSave = sinon.spy();
this.User.beforeUpdate(beforeHook); this.User.hooks.add('beforeUpdate', beforeHook);
this.User.afterUpdate(() => { this.User.hooks.add('afterUpdate', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.beforeSave(beforeSave); this.User.hooks.add('beforeSave', beforeSave);
this.User.afterSave(afterSave); this.User.hooks.add('afterSave', afterSave);
return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => { return this.User.create({ username: 'Toni', mood: 'happy' }).then(user => {
return expect(user.update({ username: 'Chong' })).to.be.rejected.then(() => { return expect(user.update({ username: 'Chong' })).to.be.rejected.then(() => {
...@@ -99,7 +99,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -99,7 +99,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('preserves changes to instance', () => { describe('preserves changes to instance', () => {
it('beforeValidate', function() { it('beforeValidate', function() {
this.User.beforeValidate(user => { this.User.hooks.add('beforeValidate', user => {
user.mood = 'happy'; user.mood = 'happy';
}); });
...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('afterValidate', function() { it('afterValidate', function() {
this.User.afterValidate(user => { this.User.hooks.add('afterValidate', user => {
user.mood = 'sad'; user.mood = 'sad';
}); });
...@@ -128,7 +128,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -128,7 +128,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeSave', function() { it('beforeSave', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeSave(user => { this.User.hooks.add('beforeSave', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
...@@ -145,12 +145,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -145,12 +145,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('beforeSave with beforeUpdate', function() { it('beforeSave with beforeUpdate', function() {
let hookCalled = 0; let hookCalled = 0;
this.User.beforeUpdate(user => { this.User.hooks.add('beforeUpdate', user => {
user.mood = 'sad'; user.mood = 'sad';
hookCalled++; hookCalled++;
}); });
this.User.beforeSave(user => { this.User.hooks.add('beforeSave', user => {
user.mood = 'happy'; user.mood = 'happy';
hookCalled++; hookCalled++;
}); });
......
...@@ -29,8 +29,8 @@ if (Support.sequelize.dialect.supports.upserts) { ...@@ -29,8 +29,8 @@ if (Support.sequelize.dialect.supports.upserts) {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeUpsert(beforeHook); this.User.hooks.add('beforeUpsert', beforeHook);
this.User.afterUpsert(afterHook); this.User.hooks.add('afterUpsert', afterHook);
return this.User.upsert({ username: 'Toni', mood: 'happy' }).then(() => { return this.User.upsert({ username: 'Toni', mood: 'happy' }).then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -44,11 +44,11 @@ if (Support.sequelize.dialect.supports.upserts) { ...@@ -44,11 +44,11 @@ if (Support.sequelize.dialect.supports.upserts) {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeUpsert(() => { this.User.hooks.add('beforeUpsert', () => {
beforeHook(); beforeHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
this.User.afterUpsert(afterHook); this.User.hooks.add('afterUpsert', afterHook);
return expect(this.User.upsert({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => { return expect(this.User.upsert({ username: 'Toni', mood: 'happy' })).to.be.rejected.then(() => {
expect(beforeHook).to.have.been.calledOnce; expect(beforeHook).to.have.been.calledOnce;
...@@ -60,8 +60,8 @@ if (Support.sequelize.dialect.supports.upserts) { ...@@ -60,8 +60,8 @@ if (Support.sequelize.dialect.supports.upserts) {
const beforeHook = sinon.spy(), const beforeHook = sinon.spy(),
afterHook = sinon.spy(); afterHook = sinon.spy();
this.User.beforeUpsert(beforeHook); this.User.hooks.add('beforeUpsert', beforeHook);
this.User.afterUpsert(() => { this.User.hooks.add('afterUpsert', () => {
afterHook(); afterHook();
throw new Error('Whoops!'); throw new Error('Whoops!');
}); });
...@@ -78,7 +78,7 @@ if (Support.sequelize.dialect.supports.upserts) { ...@@ -78,7 +78,7 @@ if (Support.sequelize.dialect.supports.upserts) {
let hookCalled = 0; let hookCalled = 0;
const valuesOriginal = { mood: 'sad', username: 'leafninja' }; const valuesOriginal = { mood: 'sad', username: 'leafninja' };
this.User.beforeUpsert(values => { this.User.hooks.add('beforeUpsert', values => {
values.mood = 'happy'; values.mood = 'happy';
hookCalled++; hookCalled++;
}); });
......
...@@ -24,12 +24,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -24,12 +24,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('#validate', () => { describe('#validate', () => {
describe('#create', () => { describe('#create', () => {
it('should return the user', function() { it('should return the user', function() {
this.User.beforeValidate(user => { this.User.hooks.add('beforeValidate', user => {
user.username = 'Bob'; user.username = 'Bob';
user.mood = 'happy'; user.mood = 'happy';
}); });
this.User.afterValidate(user => { this.User.hooks.add('afterValidate', user => {
user.username = 'Toni'; user.username = 'Toni';
}); });
...@@ -42,7 +42,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -42,7 +42,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('#3534, hooks modifications', () => { describe('#3534, hooks modifications', () => {
it('fields modified in hooks are saved', function() { it('fields modified in hooks are saved', function() {
this.User.afterValidate(user => { this.User.hooks.add('afterValidate', user => {
//if username is defined and has more than 5 char //if username is defined and has more than 5 char
user.username = user.username user.username = user.username
? user.username.length < 5 ? null : user.username ? user.username.length < 5 ? null : user.username
...@@ -51,7 +51,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -51,7 +51,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
this.User.beforeValidate(user => { this.User.hooks.add('beforeValidate', user => {
user.mood = user.mood || 'neutral'; user.mood = user.mood || 'neutral';
}); });
...@@ -108,7 +108,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -108,7 +108,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('on error', () => { describe('on error', () => {
it('should emit an error from after hook', function() { it('should emit an error from after hook', function() {
this.User.afterValidate(user => { this.User.hooks.add('afterValidate', user => {
user.mood = 'ecstatic'; user.mood = 'ecstatic';
throw new Error('Whoops! Changed user.mood!'); throw new Error('Whoops! Changed user.mood!');
}); });
...@@ -119,7 +119,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -119,7 +119,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('should call validationFailed hook', function() { it('should call validationFailed hook', function() {
const validationFailedHook = sinon.spy(); const validationFailedHook = sinon.spy();
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(() => { return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(() => {
expect(validationFailedHook).to.have.been.calledOnce; expect(validationFailedHook).to.have.been.calledOnce;
...@@ -129,7 +129,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -129,7 +129,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('should not replace the validation error in validationFailed hook by default', function() { it('should not replace the validation error in validationFailed hook by default', function() {
const validationFailedHook = sinon.stub(); const validationFailedHook = sinon.stub();
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(err => { return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(err => {
expect(err.name).to.equal('SequelizeValidationError'); expect(err.name).to.equal('SequelizeValidationError');
...@@ -139,7 +139,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -139,7 +139,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('should replace the validation error if validationFailed hook creates a new error', function() { it('should replace the validation error if validationFailed hook creates a new error', function() {
const validationFailedHook = sinon.stub().throws(new Error('Whoops!')); const validationFailedHook = sinon.stub().throws(new Error('Whoops!'));
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(err => { return expect(this.User.create({ mood: 'happy' })).to.be.rejected.then(err => {
expect(err.message).to.equal('Whoops!'); expect(err.message).to.equal('Whoops!');
......
...@@ -146,7 +146,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -146,7 +146,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
email: DataTypes.STRING email: DataTypes.STRING
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
...@@ -177,7 +177,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -177,7 +177,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
email: DataTypes.STRING email: DataTypes.STRING
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'C'); instance.set('email', 'C');
}); });
...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
} }
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
...@@ -247,7 +247,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -247,7 +247,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
} }
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
......
...@@ -206,7 +206,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -206,7 +206,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
email: DataTypes.STRING email: DataTypes.STRING
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
...@@ -237,7 +237,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -237,7 +237,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
email: DataTypes.STRING email: DataTypes.STRING
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'C'); instance.set('email', 'C');
}); });
...@@ -274,7 +274,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -274,7 +274,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
} }
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
...@@ -307,7 +307,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -307,7 +307,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
} }
}); });
User.beforeUpdate(instance => { User.hooks.add('beforeUpdate', instance => {
instance.set('email', 'B'); instance.set('email', 'B');
}); });
......
...@@ -489,7 +489,7 @@ describe(Support.getTestDialectTeaser('DAO'), () => { ...@@ -489,7 +489,7 @@ describe(Support.getTestDialectTeaser('DAO'), () => {
}); });
let changed; let changed;
User.afterUpdate(instance => { User.hooks.add('afterUpdate', instance => {
changed = instance.changed(); changed = instance.changed();
return; return;
}); });
......
...@@ -1142,7 +1142,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -1142,7 +1142,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
it('should properly set data when individualHooks are true', function() { it('should properly set data when individualHooks are true', function() {
this.User.beforeUpdate(instance => { this.User.hooks.add('beforeUpdate', instance => {
instance.set('intVal', 1); instance.set('intVal', 1);
}); });
......
...@@ -454,7 +454,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -454,7 +454,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
} }
}); });
User.beforeCreate(instance => { User.hooks.add('beforeCreate', instance => {
instance.set('username', instance.get('username').trim()); instance.set('username', instance.get('username').trim());
}); });
......
...@@ -5,10 +5,10 @@ const Support = require('../support'); ...@@ -5,10 +5,10 @@ const Support = require('../support');
const runningQueries = new Set(); const runningQueries = new Set();
before(function() { before(function() {
this.sequelize.addHook('beforeQuery', (options, query) => { this.sequelize.hooks.add('beforeQuery', (options, query) => {
runningQueries.add(query); runningQueries.add(query);
}); });
this.sequelize.addHook('afterQuery', (options, query) => { this.sequelize.hooks.add('afterQuery', (options, query) => {
runningQueries.delete(query); runningQueries.delete(query);
}); });
}); });
......
...@@ -86,7 +86,7 @@ if (current.dialect.supports.transactions) { ...@@ -86,7 +86,7 @@ if (current.dialect.supports.transactions) {
let transaction; let transaction;
return expect(this.sequelize.transaction(t => { return expect(this.sequelize.transaction(t => {
transaction = t; transaction = t;
transaction.afterCommit(hook); transaction.hooks.add('afterCommit', hook);
return this.sequelize.query('SELECT 1+1', { transaction, type: QueryTypes.SELECT }); return this.sequelize.query('SELECT 1+1', { transaction, type: QueryTypes.SELECT });
}).then(() => { }).then(() => {
expect(hook).to.have.been.calledOnce; expect(hook).to.have.been.calledOnce;
...@@ -98,7 +98,7 @@ if (current.dialect.supports.transactions) { ...@@ -98,7 +98,7 @@ if (current.dialect.supports.transactions) {
it('does not run hooks when a transaction is rolled back', function() { it('does not run hooks when a transaction is rolled back', function() {
const hook = sinon.spy(); const hook = sinon.spy();
return expect(this.sequelize.transaction(transaction => { return expect(this.sequelize.transaction(transaction => {
transaction.afterCommit(hook); transaction.hooks.add('afterCommit', hook);
return Promise.reject(new Error('Rollback')); return Promise.reject(new Error('Rollback'));
}) })
).to.eventually.be.rejected.then(() => { ).to.eventually.be.rejected.then(() => {
...@@ -217,7 +217,7 @@ if (current.dialect.supports.transactions) { ...@@ -217,7 +217,7 @@ if (current.dialect.supports.transactions) {
return expect( return expect(
this.sequelize.transaction().then(t => { this.sequelize.transaction().then(t => {
transaction = t; transaction = t;
transaction.afterCommit(hook); transaction.hooks.add('afterCommit', hook);
return t.commit().then(() => { return t.commit().then(() => {
expect(hook).to.have.been.calledOnce; expect(hook).to.have.been.calledOnce;
expect(hook).to.have.been.calledWith(t); expect(hook).to.have.been.calledWith(t);
...@@ -239,7 +239,7 @@ if (current.dialect.supports.transactions) { ...@@ -239,7 +239,7 @@ if (current.dialect.supports.transactions) {
const hook = sinon.spy(); const hook = sinon.spy();
return expect( return expect(
this.sequelize.transaction().then(t => { this.sequelize.transaction().then(t => {
t.afterCommit(hook); t.hooks.add('afterCommit', hook);
return t.rollback().then(() => { return t.rollback().then(() => {
expect(hook).to.not.have.been.called; expect(hook).to.not.have.been.called;
}); });
...@@ -247,69 +247,6 @@ if (current.dialect.supports.transactions) { ...@@ -247,69 +247,6 @@ if (current.dialect.supports.transactions) {
).to.eventually.be.fulfilled; ).to.eventually.be.fulfilled;
}); });
it('should throw an error if null is passed to afterCommit', function() {
const hook = null;
let transaction;
return expect(
this.sequelize.transaction().then(t => {
transaction = t;
transaction.afterCommit(hook);
return t.commit();
}).catch(err => {
// Cleanup this transaction so other tests don't
// fail due to an open transaction
if (!transaction.finished) {
return transaction.rollback().then(() => {
throw err;
});
}
throw err;
})
).to.eventually.be.rejectedWith('"fn" must be a function');
});
it('should throw an error if undefined is passed to afterCommit', function() {
const hook = undefined;
let transaction;
return expect(
this.sequelize.transaction().then(t => {
transaction = t;
transaction.afterCommit(hook);
return t.commit();
}).catch(err => {
// Cleanup this transaction so other tests don't
// fail due to an open transaction
if (!transaction.finished) {
return transaction.rollback().then(() => {
throw err;
});
}
throw err;
})
).to.eventually.be.rejectedWith('"fn" must be a function');
});
it('should throw an error if an object is passed to afterCommit', function() {
const hook = {};
let transaction;
return expect(
this.sequelize.transaction().then(t => {
transaction = t;
transaction.afterCommit(hook);
return t.commit();
}).catch(err => {
// Cleanup this transaction so other tests don't
// fail due to an open transaction
if (!transaction.finished) {
return transaction.rollback().then(() => {
throw err;
});
}
throw err;
})
).to.eventually.be.rejectedWith('"fn" must be a function');
});
it('does not allow commits after rollback', function() { it('does not allow commits after rollback', function() {
return expect(this.sequelize.transaction().then(t => { return expect(this.sequelize.transaction().then(t => {
return t.rollback().then(() => { return t.rollback().then(() => {
......
...@@ -663,7 +663,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => { ...@@ -663,7 +663,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
describe('beforeBelongsToManyAssociate', () => { describe('beforeBelongsToManyAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: true }); this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: true });
const beforeAssociateArgs = beforeAssociate.getCall(0).args; const beforeAssociateArgs = beforeAssociate.getCall(0).args;
...@@ -681,7 +681,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => { ...@@ -681,7 +681,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: false }); this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: false });
expect(beforeAssociate).to.not.have.been.called; expect(beforeAssociate).to.not.have.been.called;
}); });
...@@ -689,7 +689,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => { ...@@ -689,7 +689,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
describe('afterBelongsToManyAssociate', () => { describe('afterBelongsToManyAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: true }); this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: true });
const afterAssociateArgs = afterAssociate.getCall(0).args; const afterAssociateArgs = afterAssociate.getCall(0).args;
...@@ -708,7 +708,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => { ...@@ -708,7 +708,7 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: false }); this.Projects.belongsToMany(this.Tasks, { through: 'projects_and_tasks', hooks: false });
expect(afterAssociate).to.not.have.been.called; expect(afterAssociate).to.not.have.been.called;
}); });
......
...@@ -59,7 +59,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => { ...@@ -59,7 +59,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => {
describe('beforeBelongsToAssociate', () => { describe('beforeBelongsToAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.belongsTo(this.Tasks, { hooks: true }); this.Projects.belongsTo(this.Tasks, { hooks: true });
const beforeAssociateArgs = beforeAssociate.getCall(0).args; const beforeAssociateArgs = beforeAssociate.getCall(0).args;
...@@ -77,7 +77,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => { ...@@ -77,7 +77,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.belongsTo(this.Tasks, { hooks: false }); this.Projects.belongsTo(this.Tasks, { hooks: false });
expect(beforeAssociate).to.not.have.been.called; expect(beforeAssociate).to.not.have.been.called;
}); });
...@@ -85,7 +85,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => { ...@@ -85,7 +85,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => {
describe('afterBelongsToAssociate', () => { describe('afterBelongsToAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.belongsTo(this.Tasks, { hooks: true }); this.Projects.belongsTo(this.Tasks, { hooks: true });
const afterAssociateArgs = afterAssociate.getCall(0).args; const afterAssociateArgs = afterAssociate.getCall(0).args;
...@@ -105,7 +105,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => { ...@@ -105,7 +105,7 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.belongsTo(this.Tasks, { hooks: false }); this.Projects.belongsTo(this.Tasks, { hooks: false });
expect(afterAssociate).to.not.have.been.called; expect(afterAssociate).to.not.have.been.called;
}); });
......
...@@ -217,7 +217,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => { ...@@ -217,7 +217,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => {
describe('beforeHasManyAssociate', () => { describe('beforeHasManyAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.hasMany(this.Tasks, { hooks: true }); this.Projects.hasMany(this.Tasks, { hooks: true });
const beforeAssociateArgs = beforeAssociate.getCall(0).args; const beforeAssociateArgs = beforeAssociate.getCall(0).args;
...@@ -234,7 +234,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => { ...@@ -234,7 +234,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.hasMany(this.Tasks, { hooks: false }); this.Projects.hasMany(this.Tasks, { hooks: false });
expect(beforeAssociate).to.not.have.been.called; expect(beforeAssociate).to.not.have.been.called;
}); });
...@@ -242,7 +242,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => { ...@@ -242,7 +242,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => {
describe('afterHasManyAssociate', () => { describe('afterHasManyAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.hasMany(this.Tasks, { hooks: true }); this.Projects.hasMany(this.Tasks, { hooks: true });
const afterAssociateArgs = afterAssociate.getCall(0).args; const afterAssociateArgs = afterAssociate.getCall(0).args;
...@@ -261,7 +261,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => { ...@@ -261,7 +261,7 @@ describe(Support.getTestDialectTeaser('hasMany'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.hasMany(this.Tasks, { hooks: false }); this.Projects.hasMany(this.Tasks, { hooks: false });
expect(afterAssociate).to.not.have.been.called; expect(afterAssociate).to.not.have.been.called;
}); });
......
...@@ -70,7 +70,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => { ...@@ -70,7 +70,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
describe('beforeHasOneAssociate', () => { describe('beforeHasOneAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.hasOne(this.Tasks, { hooks: true }); this.Projects.hasOne(this.Tasks, { hooks: true });
const beforeAssociateArgs = beforeAssociate.getCall(0).args; const beforeAssociateArgs = beforeAssociate.getCall(0).args;
...@@ -88,7 +88,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => { ...@@ -88,7 +88,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy(); const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate); this.Projects.hooks.add('beforeAssociate', beforeAssociate);
this.Projects.hasOne(this.Tasks, { hooks: false }); this.Projects.hasOne(this.Tasks, { hooks: false });
expect(beforeAssociate).to.not.have.been.called; expect(beforeAssociate).to.not.have.been.called;
}); });
...@@ -96,7 +96,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => { ...@@ -96,7 +96,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
describe('afterHasOneAssociate', () => { describe('afterHasOneAssociate', () => {
it('should trigger', function() { it('should trigger', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.hasOne(this.Tasks, { hooks: true }); this.Projects.hasOne(this.Tasks, { hooks: true });
const afterAssociateArgs = afterAssociate.getCall(0).args; const afterAssociateArgs = afterAssociate.getCall(0).args;
...@@ -116,7 +116,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => { ...@@ -116,7 +116,7 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
}); });
it('should not trigger association hooks', function() { it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy(); const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate); this.Projects.hooks.add('afterAssociate', afterAssociate);
this.Projects.hasOne(this.Tasks, { hooks: false }); this.Projects.hasOne(this.Tasks, { hooks: false });
expect(afterAssociate).to.not.have.been.called; expect(afterAssociate).to.not.have.been.called;
}); });
......
...@@ -37,7 +37,7 @@ describe('connection manager', () => { ...@@ -37,7 +37,7 @@ describe('connection manager', () => {
const username = Math.random().toString(), const username = Math.random().toString(),
password = Math.random().toString(); password = Math.random().toString();
this.sequelize.beforeConnect(config => { this.sequelize.hooks.add('beforeConnect', config => {
config.username = username; config.username = username;
config.password = password; config.password = password;
return config; return config;
...@@ -55,7 +55,7 @@ describe('connection manager', () => { ...@@ -55,7 +55,7 @@ describe('connection manager', () => {
it('should call afterConnect', function() { it('should call afterConnect', function() {
const spy = sinon.spy(); const spy = sinon.spy();
this.sequelize.afterConnect(spy); this.sequelize.hooks.add('afterConnect', spy);
const connectionManager = new ConnectionManager(this.dialect, this.sequelize); const connectionManager = new ConnectionManager(this.dialect, this.sequelize);
......
...@@ -15,19 +15,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -15,19 +15,19 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('does not expose non-model hooks', function() { it('does not expose non-model hooks', function() {
for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeInit', 'afterInit']) { for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeInit', 'afterInit', 'beforeBulkSync', 'afterBulkSync']) {
expect(this.Model).to.not.have.property(badHook); expect(() => this.Model.hooks.add(badHook, () => {})).to.throw(/is only applicable/);
} }
}); });
describe('arguments', () => { describe('arguments', () => {
it('hooks can modify passed arguments', function() { it('hooks can modify passed arguments', function() {
this.Model.addHook('beforeCreate', options => { this.Model.hooks.add('beforeCreate', options => {
options.answer = 41; options.answer = 41;
}); });
const options = {}; const options = {};
return this.Model.runHooks('beforeCreate', options).then(() => { return this.Model.hooks.run('beforeCreate', options).then(() => {
expect(options.answer).to.equal(41); expect(options.answer).to.equal(41);
}); });
}); });
...@@ -71,7 +71,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -71,7 +71,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
}); });
describe('defined by addHook method', () => { describe('defined by hooks.add method', () => {
beforeEach(function() { beforeEach(function() {
this.beforeSaveHook = sinon.spy(); this.beforeSaveHook = sinon.spy();
this.afterSaveHook = sinon.spy(); this.afterSaveHook = sinon.spy();
...@@ -80,8 +80,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -80,8 +80,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
name: Support.Sequelize.STRING name: Support.Sequelize.STRING
}); });
this.Model.addHook('beforeSave', this.beforeSaveHook); this.Model.hooks.add('beforeSave', this.beforeSaveHook);
this.Model.addHook('afterSave', this.afterSaveHook); this.Model.hooks.add('afterSave', this.afterSaveHook);
}); });
it('calls beforeSave/afterSave', function() { it('calls beforeSave/afterSave', function() {
...@@ -101,8 +101,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -101,8 +101,8 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
name: Support.Sequelize.STRING name: Support.Sequelize.STRING
}); });
this.Model.addHook('beforeSave', this.beforeSaveHook); this.Model.hooks.add('beforeSave', this.beforeSaveHook);
this.Model.addHook('afterSave', this.afterSaveHook); this.Model.hooks.add('afterSave', this.afterSaveHook);
}); });
it('calls beforeSave/afterSave', function() { it('calls beforeSave/afterSave', function() {
...@@ -128,20 +128,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -128,20 +128,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
expect(this.hook3).to.have.been.calledOnce; expect(this.hook3).to.have.been.calledOnce;
}); });
it('using addHook', function() { it('using hooks.add', function() {
this.Model.addHook('beforeCreate', this.hook1); this.Model.hooks.add('beforeCreate', this.hook1);
this.Model.addHook('beforeCreate', this.hook2); this.Model.hooks.add('beforeCreate', this.hook2);
this.Model.addHook('beforeCreate', this.hook3); this.Model.hooks.add('beforeCreate', this.hook3);
return this.Model.runHooks('beforeCreate'); return this.Model.hooks.run('beforeCreate');
});
it('using function', function() {
this.Model.beforeCreate(this.hook1);
this.Model.beforeCreate(this.hook2);
this.Model.beforeCreate(this.hook3);
return this.Model.runHooks('beforeCreate');
}); });
it('using define', function() { it('using define', function() {
...@@ -149,7 +141,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -149,7 +141,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
hooks: { hooks: {
beforeCreate: [this.hook1, this.hook2, this.hook3] beforeCreate: [this.hook1, this.hook2, this.hook3]
} }
}).runHooks('beforeCreate'); }).hooks.run('beforeCreate');
}); });
it('using a mixture', function() { it('using a mixture', function() {
...@@ -158,36 +150,36 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -158,36 +150,36 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
beforeCreate: this.hook1 beforeCreate: this.hook1
} }
}); });
Model.beforeCreate(this.hook2); Model.hooks.add('beforeCreate', this.hook2);
Model.addHook('beforeCreate', this.hook3); Model.hooks.add('beforeCreate', this.hook3);
return Model.runHooks('beforeCreate'); return Model.hooks.run('beforeCreate');
}); });
}); });
it('stops execution when a hook throws', function() { it('stops execution when a hook throws', function() {
this.Model.beforeCreate(() => { this.Model.hooks.add('beforeCreate', () => {
this.hook1(); this.hook1();
throw new Error('No!'); throw new Error('No!');
}); });
this.Model.beforeCreate(this.hook2); this.Model.hooks.add('beforeCreate', this.hook2);
return expect(this.Model.runHooks('beforeCreate')).to.be.rejected.then(() => { return expect(this.Model.hooks.run('beforeCreate')).to.be.rejected.then(() => {
expect(this.hook1).to.have.been.calledOnce; expect(this.hook1).to.have.been.calledOnce;
expect(this.hook2).not.to.have.been.called; expect(this.hook2).not.to.have.been.called;
}); });
}); });
it('stops execution when a hook rejects', function() { it('stops execution when a hook rejects', function() {
this.Model.beforeCreate(() => { this.Model.hooks.add('beforeCreate', () => {
this.hook1(); this.hook1();
return Promise.reject(new Error('No!')); return Promise.reject(new Error('No!'));
}); });
this.Model.beforeCreate(this.hook2); this.Model.hooks.add('beforeCreate', this.hook2);
return expect(this.Model.runHooks('beforeCreate')).to.be.rejected.then(() => { return expect(this.Model.hooks.run('beforeCreate')).to.be.rejected.then(() => {
expect(this.hook1).to.have.been.calledOnce; expect(this.hook1).to.have.been.calledOnce;
expect(this.hook2).not.to.have.been.called; expect(this.hook2).not.to.have.been.called;
}); });
...@@ -195,14 +187,14 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -195,14 +187,14 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
describe('global hooks', () => { describe('global hooks', () => {
describe('using addHook', () => { describe('using hooks.add', () => {
it('invokes the global hook', function() { it('invokes the global hook', function() {
const globalHook = sinon.spy(); const globalHook = sinon.spy();
current.addHook('beforeUpdate', globalHook); current.hooks.add('beforeUpdate', globalHook);
return this.Model.runHooks('beforeUpdate').then(() => { return this.Model.hooks.run('beforeUpdate').then(() => {
expect(globalHook).to.have.been.calledOnce; expect(globalHook).to.have.been.calledOnce;
}); });
}); });
...@@ -212,7 +204,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -212,7 +204,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
globalHookAfter = sinon.spy(), globalHookAfter = sinon.spy(),
localHook = sinon.spy(); localHook = sinon.spy();
current.addHook('beforeUpdate', globalHookBefore); current.hooks.add('beforeUpdate', globalHookBefore);
const Model = current.define('m', {}, { const Model = current.define('m', {}, {
hooks: { hooks: {
...@@ -220,9 +212,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -220,9 +212,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
} }
}); });
current.addHook('beforeUpdate', globalHookAfter); current.hooks.add('beforeUpdate', globalHookAfter);
return Model.runHooks('beforeUpdate').then(() => { return Model.hooks.run('beforeUpdate').then(() => {
expect(globalHookBefore).to.have.been.calledOnce; expect(globalHookBefore).to.have.been.calledOnce;
expect(globalHookAfter).to.have.been.calledOnce; expect(globalHookAfter).to.have.been.calledOnce;
expect(localHook).to.have.been.calledOnce; expect(localHook).to.have.been.calledOnce;
...@@ -252,7 +244,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -252,7 +244,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
} }
}); });
return Model.runHooks('beforeCreate').then(() => { return Model.hooks.run('beforeCreate').then(() => {
expect(this.beforeCreate).to.have.been.calledOnce; expect(this.beforeCreate).to.have.been.calledOnce;
}); });
}); });
...@@ -265,7 +257,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -265,7 +257,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
} }
}); });
return Model.runHooks('beforeCreate').then(() => { return Model.hooks.run('beforeCreate').then(() => {
expect(this.beforeCreate).not.to.have.been.called; expect(this.beforeCreate).not.to.have.been.called;
expect(localHook).to.have.been.calledOnce; expect(localHook).to.have.been.calledOnce;
}); });
...@@ -278,20 +270,16 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -278,20 +270,16 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
const hook1 = sinon.spy(), const hook1 = sinon.spy(),
hook2 = sinon.spy(); hook2 = sinon.spy();
this.Model.addHook('beforeCreate', 'myHook', hook1); this.Model.hooks.add('beforeCreate', hook1);
this.Model.beforeCreate('myHook2', hook2);
return this.Model.runHooks('beforeCreate').then(() => { return this.Model.hooks.run('beforeCreate').then(() => {
expect(hook1).to.have.been.calledOnce; expect(hook1).to.have.been.calledOnce;
expect(hook2).to.have.been.calledOnce;
hook1.resetHistory(); hook1.resetHistory();
hook2.resetHistory();
this.Model.removeHook('beforeCreate', 'myHook'); this.Model.hooks.remove('beforeCreate', hook1);
this.Model.removeHook('beforeCreate', 'myHook2');
return this.Model.runHooks('beforeCreate'); return this.Model.hooks.run('beforeCreate');
}).then(() => { }).then(() => {
expect(hook1).not.to.have.been.called; expect(hook1).not.to.have.been.called;
expect(hook2).not.to.have.been.called; expect(hook2).not.to.have.been.called;
...@@ -304,12 +292,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -304,12 +292,12 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
hook3 = sinon.spy(), hook3 = sinon.spy(),
hook4 = sinon.spy(); hook4 = sinon.spy();
this.Model.addHook('beforeCreate', hook1); this.Model.hooks.add('beforeCreate', hook1);
this.Model.addHook('beforeCreate', 'myHook', hook2); this.Model.hooks.add('beforeCreate', hook2);
this.Model.beforeCreate('myHook2', hook3); this.Model.hooks.add('beforeCreate', hook3);
this.Model.beforeCreate(hook4); this.Model.hooks.add('beforeCreate', hook4);
return this.Model.runHooks('beforeCreate').then(() => { return this.Model.hooks.run('beforeCreate').then(() => {
expect(hook1).to.have.been.calledOnce; expect(hook1).to.have.been.calledOnce;
expect(hook2).to.have.been.calledOnce; expect(hook2).to.have.been.calledOnce;
expect(hook3).to.have.been.calledOnce; expect(hook3).to.have.been.calledOnce;
...@@ -320,9 +308,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -320,9 +308,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
hook3.resetHistory(); hook3.resetHistory();
hook4.resetHistory(); hook4.resetHistory();
this.Model.removeHook('beforeCreate', 'myHook'); this.Model.hooks.remove('beforeCreate', hook2);
return this.Model.runHooks('beforeCreate'); return this.Model.hooks.run('beforeCreate');
}).then(() => { }).then(() => {
expect(hook1).to.have.been.calledOnce; expect(hook1).to.have.been.calledOnce;
expect(hook2).not.to.have.been.called; expect(hook2).not.to.have.been.called;
...@@ -332,7 +320,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -332,7 +320,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
}); });
describe('#addHook', () => { describe('#hooks.add', () => {
it('should add additional hook when previous exists', function() { it('should add additional hook when previous exists', function() {
const hook1 = sinon.spy(), const hook1 = sinon.spy(),
hook2 = sinon.spy(); hook2 = sinon.spy();
...@@ -341,9 +329,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -341,9 +329,9 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
hooks: { beforeCreate: hook1 } hooks: { beforeCreate: hook1 }
}); });
Model.addHook('beforeCreate', hook2); Model.hooks.add('beforeCreate', hook2);
return Model.runHooks('beforeCreate').then(() => { return Model.hooks.run('beforeCreate').then(() => {
expect(hook1).to.have.been.calledOnce; expect(hook1).to.have.been.calledOnce;
expect(hook2).to.have.been.calledOnce; expect(hook2).to.have.been.calledOnce;
}); });
...@@ -352,35 +340,35 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -352,35 +340,35 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
describe('promises', () => { describe('promises', () => {
it('can return a promise', function() { it('can return a promise', function() {
this.Model.beforeBulkCreate(() => { this.Model.hooks.add('beforeBulkCreate', () => {
return Sequelize.Promise.resolve(); return Sequelize.Promise.resolve();
}); });
return expect(this.Model.runHooks('beforeBulkCreate')).to.be.fulfilled; return expect(this.Model.hooks.run('beforeBulkCreate')).to.be.fulfilled;
}); });
it('can return undefined', function() { it('can return undefined', function() {
this.Model.beforeBulkCreate(() => { this.Model.hooks.add('beforeBulkCreate', () => {
// This space intentionally left blank // This space intentionally left blank
}); });
return expect(this.Model.runHooks('beforeBulkCreate')).to.be.fulfilled; return expect(this.Model.hooks.run('beforeBulkCreate')).to.be.fulfilled;
}); });
it('can return an error by rejecting', function() { it('can return an error by rejecting', function() {
this.Model.beforeCreate(() => { this.Model.hooks.add('beforeCreate', () => {
return Promise.reject(new Error('Forbidden')); return Promise.reject(new Error('Forbidden'));
}); });
return expect(this.Model.runHooks('beforeCreate')).to.be.rejectedWith('Forbidden'); return expect(this.Model.hooks.run('beforeCreate')).to.be.rejectedWith('Forbidden');
}); });
it('can return an error by throwing', function() { it('can return an error by throwing', function() {
this.Model.beforeCreate(() => { this.Model.hooks.add('beforeCreate', () => {
throw new Error('Forbidden'); throw new Error('Forbidden');
}); });
return expect(this.Model.runHooks('beforeCreate')).to.be.rejectedWith('Forbidden'); return expect(this.Model.hooks.run('beforeCreate')).to.be.rejectedWith('Forbidden');
}); });
}); });
...@@ -393,10 +381,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -393,10 +381,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
}); });
it('runs all beforInit/afterInit hooks', function() { it('runs all beforInit/afterInit hooks', function() {
Support.Sequelize.addHook('beforeInit', 'h1', this.hook1); Support.Sequelize.hooks.add('beforeInit', this.hook1);
Support.Sequelize.addHook('beforeInit', 'h2', this.hook2); Support.Sequelize.hooks.add('beforeInit', this.hook2);
Support.Sequelize.addHook('afterInit', 'h3', this.hook3); Support.Sequelize.hooks.add('afterInit', this.hook3);
Support.Sequelize.addHook('afterInit', 'h4', this.hook4); Support.Sequelize.hooks.add('afterInit', this.hook4);
Support.createSequelizeInstance(); Support.createSequelizeInstance();
...@@ -406,10 +394,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -406,10 +394,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
expect(this.hook4).to.have.been.calledOnce; expect(this.hook4).to.have.been.calledOnce;
// cleanup hooks on Support.Sequelize // cleanup hooks on Support.Sequelize
Support.Sequelize.removeHook('beforeInit', 'h1'); Support.Sequelize.hooks.remove('beforeInit', this.hook1);
Support.Sequelize.removeHook('beforeInit', 'h2'); Support.Sequelize.hooks.remove('beforeInit', this.hook2);
Support.Sequelize.removeHook('afterInit', 'h3'); Support.Sequelize.hooks.remove('afterInit', this.hook3);
Support.Sequelize.removeHook('afterInit', 'h4'); Support.Sequelize.hooks.remove('afterInit', this.hook4);
Support.createSequelizeInstance(); Support.createSequelizeInstance();
...@@ -422,10 +410,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => { ...@@ -422,10 +410,10 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
it('runs all beforDefine/afterDefine hooks', function() { it('runs all beforDefine/afterDefine hooks', function() {
const sequelize = Support.createSequelizeInstance(); const sequelize = Support.createSequelizeInstance();
sequelize.addHook('beforeDefine', this.hook1); sequelize.hooks.add('beforeDefine', this.hook1);
sequelize.addHook('beforeDefine', this.hook2); sequelize.hooks.add('beforeDefine', this.hook2);
sequelize.addHook('afterDefine', this.hook3); sequelize.hooks.add('afterDefine', this.hook3);
sequelize.addHook('afterDefine', this.hook4); sequelize.hooks.add('afterDefine', this.hook4);
sequelize.define('Test', {}); sequelize.define('Test', {});
expect(this.hook1).to.have.been.calledOnce; expect(this.hook1).to.have.been.calledOnce;
expect(this.hook2).to.have.been.calledOnce; expect(this.hook2).to.have.been.calledOnce;
......
...@@ -89,8 +89,8 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -89,8 +89,8 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
it('should run beforeValidate and afterValidate hooks when _validate is successful', function() { it('should run beforeValidate and afterValidate hooks when _validate is successful', function() {
const beforeValidate = sinon.spy(); const beforeValidate = sinon.spy();
const afterValidate = sinon.spy(); const afterValidate = sinon.spy();
this.User.beforeValidate(beforeValidate); this.User.hooks.add('beforeValidate', beforeValidate);
this.User.afterValidate(afterValidate); this.User.hooks.add('afterValidate', afterValidate);
return expect(this.successfulInstanceValidator._validateAndRunHooks()).to.be.fulfilled.then(() => { return expect(this.successfulInstanceValidator._validateAndRunHooks()).to.be.fulfilled.then(() => {
expect(beforeValidate).to.have.been.calledOnce; expect(beforeValidate).to.have.been.calledOnce;
...@@ -103,8 +103,8 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -103,8 +103,8 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
sinon.stub(failingInstanceValidator, '_validate').rejects(new Error()); sinon.stub(failingInstanceValidator, '_validate').rejects(new Error());
const beforeValidate = sinon.spy(); const beforeValidate = sinon.spy();
const afterValidate = sinon.spy(); const afterValidate = sinon.spy();
this.User.beforeValidate(beforeValidate); this.User.hooks.add('beforeValidate', beforeValidate);
this.User.afterValidate(afterValidate); this.User.hooks.add('afterValidate', afterValidate);
return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(() => { return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(() => {
expect(beforeValidate).to.have.been.calledOnce; expect(beforeValidate).to.have.been.calledOnce;
...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -113,7 +113,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
}); });
it('should emit an error from after hook when afterValidate fails', function() { it('should emit an error from after hook when afterValidate fails', function() {
this.User.afterValidate(() => { this.User.hooks.add('afterValidate', () => {
throw new Error('after validation error'); throw new Error('after validation error');
}); });
...@@ -125,7 +125,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -125,7 +125,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
const failingInstanceValidator = new InstanceValidator(new this.User()); const failingInstanceValidator = new InstanceValidator(new this.User());
sinon.stub(failingInstanceValidator, '_validate').rejects(new Error()); sinon.stub(failingInstanceValidator, '_validate').rejects(new Error());
const validationFailedHook = sinon.spy(); const validationFailedHook = sinon.spy();
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(() => { return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(() => {
expect(validationFailedHook).to.have.been.calledOnce; expect(validationFailedHook).to.have.been.calledOnce;
...@@ -136,7 +136,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -136,7 +136,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
const failingInstanceValidator = new InstanceValidator(new this.User()); const failingInstanceValidator = new InstanceValidator(new this.User());
sinon.stub(failingInstanceValidator, '_validate').rejects(new SequelizeValidationError()); sinon.stub(failingInstanceValidator, '_validate').rejects(new SequelizeValidationError());
const validationFailedHook = sinon.stub().resolves(); const validationFailedHook = sinon.stub().resolves();
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(err => { return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(err => {
expect(err.name).to.equal('SequelizeValidationError'); expect(err.name).to.equal('SequelizeValidationError');
...@@ -147,7 +147,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => { ...@@ -147,7 +147,7 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), () => {
const failingInstanceValidator = new InstanceValidator(new this.User()); const failingInstanceValidator = new InstanceValidator(new this.User());
sinon.stub(failingInstanceValidator, '_validate').rejects(new SequelizeValidationError()); sinon.stub(failingInstanceValidator, '_validate').rejects(new SequelizeValidationError());
const validationFailedHook = sinon.stub().throws(new Error('validation failed hook error')); const validationFailedHook = sinon.stub().throws(new Error('validation failed hook error'));
this.User.validationFailed(validationFailedHook); this.User.hooks.add('validationFailed', validationFailedHook);
return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(err => { return expect(failingInstanceValidator._validateAndRunHooks()).to.be.rejected.then(err => {
expect(err.message).to.equal('validation failed hook error'); expect(err.message).to.equal('validation failed hook error');
......
...@@ -10,11 +10,25 @@ import Model, { ...@@ -10,11 +10,25 @@ import Model, {
ModelAttributes, ModelAttributes,
ModelOptions, ModelOptions,
UpdateOptions, UpdateOptions,
SaveOptions,
UpsertOptions,
RestoreOptions,
} from './model'; } from './model';
import { Config, Options, Sequelize, SyncOptions } from './sequelize'; import { Config, Options, Sequelize, SyncOptions } from './sequelize';
import { Association, AssociationOptions, Transaction } from '..';
export type HookReturn = Promise<void> | void; export type HookReturn = Promise<void> | void;
export interface AssociateBeforeData<S extends Model = Model, T extends Model = Model> {
source: S;
target: T;
type: typeof Association;
}
export interface AssociateAfterData<S extends Model = Model, T extends Model = Model> extends AssociateBeforeData<S, T> {
association: Association<S, T>;
}
/** /**
* Options for Model.init. We mostly duplicate the Hooks here, since there is no way to combine the two * Options for Model.init. We mostly duplicate the Hooks here, since there is no way to combine the two
* interfaces. * interfaces.
...@@ -22,29 +36,51 @@ export type HookReturn = Promise<void> | void; ...@@ -22,29 +36,51 @@ export type HookReturn = Promise<void> | void;
export interface ModelHooks<M extends Model = Model> { export interface ModelHooks<M extends Model = Model> {
beforeValidate(instance: M, options: ValidationOptions): HookReturn; beforeValidate(instance: M, options: ValidationOptions): HookReturn;
afterValidate(instance: M, options: ValidationOptions): HookReturn; afterValidate(instance: M, options: ValidationOptions): HookReturn;
beforeCreate(attributes: M, options: CreateOptions): HookReturn; beforeCreate(attributes: M, options: CreateOptions): HookReturn;
afterCreate(attributes: M, options: CreateOptions): HookReturn; afterCreate(attributes: M, options: CreateOptions): HookReturn;
beforeDestroy(instance: M, options: InstanceDestroyOptions): HookReturn; beforeDestroy(instance: M, options: InstanceDestroyOptions): HookReturn;
afterDestroy(instance: M, options: InstanceDestroyOptions): HookReturn; afterDestroy(instance: M, options: InstanceDestroyOptions): HookReturn;
beforeUpdate(instance: M, options: InstanceUpdateOptions): HookReturn; beforeUpdate(instance: M, options: InstanceUpdateOptions): HookReturn;
afterUpdate(instance: M, options: InstanceUpdateOptions): HookReturn; afterUpdate(instance: M, options: InstanceUpdateOptions): HookReturn;
beforeSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn; beforeSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn;
afterSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn; afterSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn;
beforeBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn; beforeBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn;
afterBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn; afterBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn;
beforeBulkDestroy(options: DestroyOptions): HookReturn; beforeBulkDestroy(options: DestroyOptions): HookReturn;
afterBulkDestroy(options: DestroyOptions): HookReturn; afterBulkDestroy(options: DestroyOptions): HookReturn;
beforeBulkUpdate(options: UpdateOptions): HookReturn; beforeBulkUpdate(options: UpdateOptions): HookReturn;
afterBulkUpdate(options: UpdateOptions): HookReturn; afterBulkUpdate(options: UpdateOptions): HookReturn;
beforeFind(options: FindOptions): HookReturn; beforeFind(options: FindOptions): HookReturn;
afterFind(instancesOrInstance: M[] | M, options: FindOptions): HookReturn;
beforeCount(options: CountOptions): HookReturn; beforeCount(options: CountOptions): HookReturn;
beforeFindAfterExpandIncludeAll(options: FindOptions): HookReturn; beforeFindAfterExpandIncludeAll(options: FindOptions): HookReturn;
beforeFindAfterOptions(options: FindOptions): HookReturn; beforeFindAfterOptions(options: FindOptions): HookReturn;
afterFind(instancesOrInstance: M[] | M | null, options: FindOptions): HookReturn; afterFind(instancesOrInstance: M[] | M | null, options: FindOptions): HookReturn;
beforeSync(options: SyncOptions): HookReturn; beforeSync(options: SyncOptions): HookReturn;
afterSync(options: SyncOptions): HookReturn; afterSync(options: SyncOptions): HookReturn;
beforeBulkSync(options: SyncOptions): HookReturn; beforeBulkSync(options: SyncOptions): HookReturn;
afterBulkSync(options: SyncOptions): HookReturn; afterBulkSync(options: SyncOptions): HookReturn;
beforeUpsert(values: object, options: UpsertOptions): HookReturn;
afterUpsert(instance: M, options: UpsertOptions): HookReturn;
beforeAssociate(assoc: AssociateBeforeData, options: AssociationOptions): HookReturn;
afterAssociate(assoc: AssociateAfterData, options: AssociationOptions): HookReturn;
beforeRestore(instance: M, options: RestoreOptions): HookReturn;
afterRestore(instance: M, options: RestoreOptions): HookReturn;
} }
export interface SequelizeHooks extends ModelHooks { export interface SequelizeHooks extends ModelHooks {
...@@ -59,50 +95,19 @@ export interface SequelizeHooks extends ModelHooks { ...@@ -59,50 +95,19 @@ export interface SequelizeHooks extends ModelHooks {
/** /**
* Virtual class for deduplication * Virtual class for deduplication
*/ */
export class Hooks { export class Hooks<H extends object> {
/** /**
* Add a hook to the model * Add a hook to the model
*
* @param name Provide a name for the hook function. It can be used to remove the hook later or to order
* hooks based on some sort of priority system in the future.
*/
public static addHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(
hookType: K,
name: string,
fn: SequelizeHooks[K]
): C;
public static addHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(
hookType: K,
fn: SequelizeHooks[K]
): C;
/**
* Remove hook from the model
*/ */
public static removeHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(hookType: K, name: string): C; add<K extends keyof H>(hookType: K, fn: H[K]): this;
/** /**
* Check whether the mode has any hooks of this type
*/
public static hasHook<K extends keyof SequelizeHooks>(hookType: K): boolean;
public static hasHooks<K extends keyof SequelizeHooks>(hookType: K): boolean;
/**
* Add a hook to the model
*
* @param name Provide a name for the hook function. It can be used to remove the hook later or to order
* hooks based on some sort of priority system in the future.
*/
public addHook<K extends keyof SequelizeHooks>(hookType: K, name: string, fn: SequelizeHooks[K]): this;
public addHook<K extends keyof SequelizeHooks>(hookType: K, fn: SequelizeHooks[K]): this;
/**
* Remove hook from the model * Remove hook from the model
*/ */
public removeHook<K extends keyof SequelizeHooks>(hookType: K, name: string): this; remove<K extends keyof H>(hookType: K, fn: Function): this;
/** /**
* Check whether the mode has any hooks of this type * Check whether the mode has any hooks of this type
*/ */
public hasHook<K extends keyof SequelizeHooks>(hookType: K): boolean; has<K extends keyof H>(hookType: K): boolean;
public hasHooks<K extends keyof SequelizeHooks>(hookType: K): boolean;
} }
...@@ -11,7 +11,7 @@ import { ...@@ -11,7 +11,7 @@ import {
} from './associations/index'; } from './associations/index';
import { DataType } from './data-types'; import { DataType } from './data-types';
import { Deferrable } from './deferrable'; import { Deferrable } from './deferrable';
import { HookReturn, Hooks, ModelHooks } from './hooks'; import { HookReturn, SequelizeHooks, ModelHooks, Hooks } from './hooks';
import { ValidationOptions } from './instance-validator'; import { ValidationOptions } from './instance-validator';
import { ModelManager } from './model-manager'; import { ModelManager } from './model-manager';
import Op = require('./operators'); import Op = require('./operators');
...@@ -1497,7 +1497,7 @@ export interface AddScopeOptions { ...@@ -1497,7 +1497,7 @@ export interface AddScopeOptions {
override: boolean; override: boolean;
} }
export abstract class Model<T = any, T2 = any> extends Hooks { export abstract class Model<T = any, T2 = any> {
/** The name of the database table */ /** The name of the database table */
public static readonly tableName: string; public static readonly tableName: string;
...@@ -1528,6 +1528,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -1528,6 +1528,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*/ */
public static readonly sequelize?: Sequelize; public static readonly sequelize?: Sequelize;
public static readonly hooks: Hooks<ModelHooks>;
/** /**
* Initialize a model, representing a table in the DB, with attributes and options. * Initialize a model, representing a table in the DB, with attributes and options.
* *
...@@ -2030,314 +2032,6 @@ export abstract class Model<T = any, T2 = any> extends Hooks { ...@@ -2030,314 +2032,6 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
public static unscoped<M extends typeof Model>(this: M): M; public static unscoped<M extends typeof Model>(this: M): M;
/** /**
* A hook that is run before validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeValidate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
public static beforeValidate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
/**
* A hook that is run after validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterValidate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
public static afterValidate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
/**
* A hook that is run before creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static beforeCreate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (attributes: M, options: CreateOptions) => HookReturn
): void;
public static beforeCreate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (attributes: M, options: CreateOptions) => HookReturn
): void;
/**
* A hook that is run after creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static afterCreate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (attributes: M, options: CreateOptions) => HookReturn
): void;
public static afterCreate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (attributes: M, options: CreateOptions) => HookReturn
): void;
/**
* A hook that is run before destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeDestroy<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
public static beforeDestroy<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: Model, options: InstanceDestroyOptions) => HookReturn
): void;
/**
* A hook that is run after destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterDestroy<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
public static afterDestroy<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
/**
* A hook that is run before updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeUpdate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: UpdateOptions) => HookReturn
): void;
public static beforeUpdate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: UpdateOptions) => HookReturn
): void;
/**
* A hook that is run after updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterUpdate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: UpdateOptions) => HookReturn
): void;
public static afterUpdate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: UpdateOptions) => HookReturn
): void;
/**
* A hook that is run before creating or updating a single instance, It proxies `beforeCreate` and `beforeUpdate`
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeSave<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
): void;
public static beforeSave<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
): void;
/**
* A hook that is run after creating or updating a single instance, It proxies `afterCreate` and `afterUpdate`
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterSave<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
): void;
public static afterSave<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
): void;
/**
* A hook that is run before creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public static beforeBulkCreate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
): void;
public static beforeBulkCreate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
): void;
/**
* A hook that is run after creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public static afterBulkCreate<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
): void;
public static afterBulkCreate<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
): void;
/**
* A hook that is run before destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => HookReturn): void;
public static beforeBulkDestroy(fn: (options: BulkCreateOptions) => HookReturn): void;
/**
* A hook that is run after destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkDestroy(name: string, fn: (options: DestroyOptions) => HookReturn): void;
public static afterBulkDestroy(fn: (options: DestroyOptions) => HookReturn): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => HookReturn): void;
public static beforeBulkUpdate(fn: (options: UpdateOptions) => HookReturn): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkUpdate(name: string, fn: (options: UpdateOptions) => HookReturn): void;
public static afterBulkUpdate(fn: (options: UpdateOptions) => HookReturn): void;
/**
* A hook that is run before a find (select) query
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFind(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFind(fn: (options: FindOptions) => HookReturn): void;
/**
* A hook that is run before a count query
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeCount(name: string, fn: (options: CountOptions) => HookReturn): void;
public static beforeCount(fn: (options: CountOptions) => HookReturn): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => HookReturn): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterOptions(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFindAfterOptions(fn: (options: FindOptions) => void): HookReturn;
/**
* A hook that is run after a find (select) query
*
* @param name
* @param fn A callback function that is called with instance(s), options
*/
public static afterFind<M extends Model>(
this: { new (): M } & typeof Model,
name: string,
fn: (instancesOrInstance: M[] | M | null, options: FindOptions) => HookReturn
): void;
public static afterFind<M extends Model>(
this: { new (): M } & typeof Model,
fn: (instancesOrInstance: M[] | M | null, options: FindOptions) => HookReturn
): void;
/**
* A hook that is run before sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public static beforeBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static beforeBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public static afterBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static afterBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run before Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public static beforeSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static beforeSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public static afterSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static afterSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* Creates an association between this (the source) and the provided target. The foreign key is added * Creates an association between this (the source) and the provided target. The foreign key is added
* on the target. * on the target.
* *
......
import * as DataTypes from './data-types'; import * as DataTypes from './data-types';
import * as Deferrable from './deferrable'; import * as Deferrable from './deferrable';
import { HookReturn, Hooks, SequelizeHooks } from './hooks'; import { HookReturn, SequelizeHooks, Hooks } from './hooks';
import { ValidationOptions } from './instance-validator'; import { ValidationOptions } from './instance-validator';
import { import {
AndOperator, AndOperator,
...@@ -346,7 +346,7 @@ export interface QueryOptionsTransactionRequired {} ...@@ -346,7 +346,7 @@ export interface QueryOptionsTransactionRequired {}
* should also be installed in your project. You don't need to import it however, as * should also be installed in your project. You don't need to import it however, as
* sequelize will take care of that. * sequelize will take care of that.
*/ */
export class Sequelize extends Hooks { export class Sequelize {
// -------------------- Utilities ------------------------------------------------------------------------ // -------------------- Utilities ------------------------------------------------------------------------
...@@ -435,279 +435,6 @@ export class Sequelize extends Hooks { ...@@ -435,279 +435,6 @@ export class Sequelize extends Hooks {
public static where: typeof where; public static where: typeof where;
/** /**
* A hook that is run before validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeValidate(name: string, fn: (instance: Model, options: ValidationOptions) => void): void;
public static beforeValidate(fn: (instance: Model, options: ValidationOptions) => void): void;
/**
* A hook that is run after validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterValidate(name: string, fn: (instance: Model, options: ValidationOptions) => void): void;
public static afterValidate(fn: (instance: Model, options: ValidationOptions) => void): void;
/**
* A hook that is run before creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public static beforeCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
/**
* A hook that is run after creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static afterCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public static afterCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
/**
* A hook that is run before destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeDestroy(name: string, fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
public static beforeDestroy(fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
/**
* A hook that is run after destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterDestroy(name: string, fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
public static afterDestroy(fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
/**
* A hook that is run before updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public static beforeUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
/**
* A hook that is run after updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public static afterUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
/**
* A hook that is run before creating or updating a single instance, It proxies `beforeCreate` and `beforeUpdate`
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeSave(name: string, fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static beforeSave(fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
/**
* A hook that is run after creating or updating a single instance, It proxies `afterCreate` and `afterUpdate`
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterSave(name: string, fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static afterSave(fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
/**
* A hook that is run before creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public static beforeBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
/**
* A hook that is run after creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public static afterBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
/**
* A hook that is run before destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => void): void;
public static beforeBulkDestroy(fn: (options: BulkCreateOptions) => void): void;
/**
* A hook that is run after destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkDestroy(name: string, fn: (options: DestroyOptions) => void): void;
public static afterBulkDestroy(fn: (options: DestroyOptions) => void): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public static beforeBulkUpdate(fn: (options: UpdateOptions) => void): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public static afterBulkUpdate(fn: (options: UpdateOptions) => void): void;
/**
* A hook that is run before a find (select) query
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFind(name: string, fn: (options: FindOptions) => void): void;
public static beforeFind(fn: (options: FindOptions) => void): void;
/**
* A hook that is run before a connection is established
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeConnect(name: string, fn: (options: Config) => void): void;
public static beforeConnect(fn: (options: Config) => void): void;
/**
* A hook that is run after a connection is established
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterConnect(name: string, fn: (connection: unknown, options: Config) => void): void;
public static afterConnect(fn: (connection: unknown, options: Config) => void): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => void): void;
public static beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => void): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterOptions(name: string, fn: (options: FindOptions) => void): void;
public static beforeFindAfterOptions(fn: (options: FindOptions) => void): void;
/**
* A hook that is run after a find (select) query
*
* @param name
* @param fn A callback function that is called with instance(s), options
*/
public static afterFind(
name: string,
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
): void;
public static afterFind(
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
): void;
/**
* A hook that is run before a define call
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static beforeDefine<M extends Model>(
name: string,
fn: (attributes: ModelAttributes, options: ModelOptions<M>) => void
): void;
public static beforeDefine<M extends Model>(
fn: (attributes: ModelAttributes, options: ModelOptions<M>) => void
): void;
/**
* A hook that is run after a define call
*
* @param name
* @param fn A callback function that is called with factory
*/
public static afterDefine(name: string, fn: (model: typeof Model) => void): void;
public static afterDefine(fn: (model: typeof Model) => void): void;
/**
* A hook that is run before Sequelize() call
*
* @param name
* @param fn A callback function that is called with config, options
*/
public static beforeInit(name: string, fn: (config: Config, options: Options) => void): void;
public static beforeInit(fn: (config: Config, options: Options) => void): void;
/**
* A hook that is run after Sequelize() call
*
* @param name
* @param fn A callback function that is called with sequelize
*/
public static afterInit(name: string, fn: (sequelize: Sequelize) => void): void;
public static afterInit(fn: (sequelize: Sequelize) => void): void;
/**
* A hook that is run before sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public static beforeBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static beforeBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public static afterBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static afterBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run before Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public static beforeSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static beforeSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public static afterSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public static afterSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A reference to Sequelize constructor from sequelize. Useful for accessing DataTypes, Errors etc. * A reference to Sequelize constructor from sequelize. Useful for accessing DataTypes, Errors etc.
*/ */
public Sequelize: typeof Sequelize; public Sequelize: typeof Sequelize;
...@@ -728,6 +455,9 @@ export class Sequelize extends Hooks { ...@@ -728,6 +455,9 @@ export class Sequelize extends Hooks {
[key: string]: typeof Model; [key: string]: typeof Model;
}; };
public readonly hooks: Hooks<SequelizeHooks>;
public static readonly hooks: Hooks<SequelizeHooks>;
/** /**
* Instantiate sequelize with name of database, username and password * Instantiate sequelize with name of database, username and password
* *
...@@ -769,235 +499,6 @@ export class Sequelize extends Hooks { ...@@ -769,235 +499,6 @@ export class Sequelize extends Hooks {
constructor(uri: string, options?: Options); constructor(uri: string, options?: Options);
/** /**
* A hook that is run before validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public beforeValidate(name: string, fn: (instance: Model, options: ValidationOptions) => void): void;
public beforeValidate(fn: (instance: Model, options: ValidationOptions) => void): void;
/**
* A hook that is run after validation
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public afterValidate(name: string, fn: (instance: Model, options: ValidationOptions) => void): void;
public afterValidate(fn: (instance: Model, options: ValidationOptions) => void): void;
/**
* A hook that is run before creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public beforeCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
/**
* A hook that is run after creating a single instance
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public afterCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public afterCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
/**
* A hook that is run before destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public beforeDestroy(name: string, fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
public beforeDestroy(fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
/**
* A hook that is run after destroying a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public afterDestroy(name: string, fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
public afterDestroy(fn: (instance: Model, options: InstanceDestroyOptions) => void): void;
/**
* A hook that is run before updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public beforeUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
/**
* A hook that is run after updating a single instance
*
* @param name
* @param fn A callback function that is called with instance, options
*/
public afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public afterUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
/**
* A hook that is run before creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public beforeBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
/**
* A hook that is run after creating instances in bulk
*
* @param name
* @param fn A callback function that is called with instances, options
*/
public afterBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
/**
* A hook that is run before destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => void): void;
public beforeBulkDestroy(fn: (options: BulkCreateOptions) => void): void;
/**
* A hook that is run after destroying instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public afterBulkDestroy(name: string, fn: (options: DestroyOptions) => void): void;
public afterBulkDestroy(fn: (options: DestroyOptions) => void): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public beforeBulkUpdate(fn: (options: UpdateOptions) => void): void;
/**
* A hook that is run after updating instances in bulk
*
* @param name
* @param fn A callback function that is called with options
*/
public afterBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public afterBulkUpdate(fn: (options: UpdateOptions) => void): void;
/**
* A hook that is run before a find (select) query
*
* @param name
* @param fn A callback function that is called with options
*/
public beforeFind(name: string, fn: (options: FindOptions) => void): void;
public beforeFind(fn: (options: FindOptions) => void): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
*
* @param name
* @param fn A callback function that is called with options
*/
public beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => void): void;
public beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => void): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
*
* @param name
* @param fn A callback function that is called with options
*/
public beforeFindAfterOptions(name: string, fn: (options: FindOptions) => void): void;
public beforeFindAfterOptions(fn: (options: FindOptions) => void): void;
/**
* A hook that is run after a find (select) query
*
* @param name
* @param fn A callback function that is called with instance(s), options
*/
public afterFind(
name: string,
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
): void;
public afterFind(fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void): void;
/**
* A hook that is run before a define call
*
* @param name
* @param fn A callback function that is called with attributes, options
*/
public beforeDefine(name: string, fn: (attributes: ModelAttributes, options: ModelOptions) => void): void;
public beforeDefine(fn: (attributes: ModelAttributes, options: ModelOptions) => void): void;
/**
* A hook that is run after a define call
*
* @param name
* @param fn A callback function that is called with factory
*/
public afterDefine(name: string, fn: (model: typeof Model) => void): void;
public afterDefine(fn: (model: typeof Model) => void): void;
/**
* A hook that is run before Sequelize() call
*
* @param name
* @param fn A callback function that is called with config, options
*/
public beforeInit(name: string, fn: (config: Config, options: Options) => void): void;
public beforeInit(fn: (config: Config, options: Options) => void): void;
/**
* A hook that is run after Sequelize() call
*
* @param name
* @param fn A callback function that is called with sequelize
*/
public afterInit(name: string, fn: (sequelize: Sequelize) => void): void;
public afterInit(fn: (sequelize: Sequelize) => void): void;
/**
* A hook that is run before sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public beforeBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public beforeBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after sequelize.sync call
* @param fn A callback function that is called with options passed to sequelize.sync
*/
public afterBulkSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public afterBulkSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run before Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public beforeSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public beforeSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* A hook that is run after Model.sync call
* @param fn A callback function that is called with options passed to Model.sync
*/
public afterSync(name: string, fn: (options: SyncOptions) => HookReturn): void;
public afterSync(fn: (options: SyncOptions) => HookReturn): void;
/**
* Returns the specified dialect. * Returns the specified dialect.
*/ */
public getDialect(): string; public getDialect(): string;
......
...@@ -2,6 +2,11 @@ import { Deferrable } from './deferrable'; ...@@ -2,6 +2,11 @@ import { Deferrable } from './deferrable';
import { Logging } from './model'; import { Logging } from './model';
import { Promise } from './promise'; import { Promise } from './promise';
import { Sequelize } from './sequelize'; import { Sequelize } from './sequelize';
import { Hooks } from './hooks';
export interface TransactionHooks {
afterCommit(): void;
}
/** /**
* The transaction object is used to identify a running transaction. It is created by calling * The transaction object is used to identify a running transaction. It is created by calling
...@@ -10,6 +15,9 @@ import { Sequelize } from './sequelize'; ...@@ -10,6 +15,9 @@ import { Sequelize } from './sequelize';
* To run a query under a transaction, you should pass the transaction in the options object. * To run a query under a transaction, you should pass the transaction in the options object.
*/ */
export class Transaction { export class Transaction {
public readonly hooks: Hooks<TransactionHooks>;
constructor(sequelize: Sequelize, options: TransactionOptions); constructor(sequelize: Sequelize, options: TransactionOptions);
/** /**
...@@ -21,11 +29,6 @@ export class Transaction { ...@@ -21,11 +29,6 @@ export class Transaction {
* Rollback (abort) the transaction * Rollback (abort) the transaction
*/ */
public rollback(): Promise<void>; public rollback(): Promise<void>;
/**
* Adds hook that is run after a transaction is committed
*/
public afterCommit(fn: (transaction: this) => void | Promise<void>): void;
} }
// tslint:disable-next-line no-namespace // tslint:disable-next-line no-namespace
......
...@@ -3,7 +3,7 @@ import { User } from 'models/User'; ...@@ -3,7 +3,7 @@ import { User } from 'models/User';
export const sequelize = new Sequelize('uri'); export const sequelize = new Sequelize('uri');
sequelize.afterBulkSync((options: SyncOptions) => { sequelize.hooks.add('afterBulkSync', (options: SyncOptions) => {
console.log('synced'); console.log('synced');
}); });
......
...@@ -5,11 +5,14 @@ import { ModelHooks } from "../lib/hooks"; ...@@ -5,11 +5,14 @@ import { ModelHooks } from "../lib/hooks";
* covers types/lib/sequelize.d.ts * covers types/lib/sequelize.d.ts
*/ */
Sequelize.beforeSave((t: TestModel, options: SaveOptions) => {}); Sequelize.hooks.add('beforeSave', (t: TestModel, options: SaveOptions) => {});
Sequelize.afterSave((t: TestModel, options: SaveOptions) => {}); Sequelize.hooks.add('afterSave', (t: TestModel, options: SaveOptions) => {});
Sequelize.afterFind((t: TestModel[] | TestModel | null, options: FindOptions) => {}); Sequelize.hooks.add('afterFind', (t: TestModel[] | TestModel | null, options: FindOptions) => {});
Sequelize.afterFind('namedAfterFind', (t: TestModel[] | TestModel | null, options: FindOptions) => {}); Sequelize.hooks.add('afterFind', (t: TestModel[] | TestModel | null, options: FindOptions) => {});
Sequelize.hooks.add('beforeSave', m => {
});
/* /*
* covers types/lib/hooks.d.ts * covers types/lib/hooks.d.ts
*/ */
...@@ -33,14 +36,7 @@ const hooks: Partial<ModelHooks> = { ...@@ -33,14 +36,7 @@ const hooks: Partial<ModelHooks> = {
TestModel.init({}, {sequelize, hooks }) TestModel.init({}, {sequelize, hooks })
TestModel.addHook('beforeSave', (t: TestModel, options: SaveOptions) => { }); TestModel.hooks.add('beforeSave', (t: TestModel, options: SaveOptions) => { });
TestModel.addHook('afterSave', (t: TestModel, options: SaveOptions) => { }); TestModel.hooks.add('afterSave', (t: TestModel, options: SaveOptions) => { });
TestModel.addHook('afterFind', (t: TestModel[] | TestModel | null, options: FindOptions) => { }); TestModel.hooks.add('afterFind', (t: TestModel[] | TestModel | null, options: FindOptions) => { });
/*
* covers types/lib/model.d.ts
*/
TestModel.beforeSave((t: TestModel, options: SaveOptions) => { });
TestModel.afterSave((t: TestModel, options: SaveOptions) => { });
TestModel.afterFind((t: TestModel | TestModel[] | null, options: FindOptions) => { });
...@@ -71,7 +71,7 @@ User.init( ...@@ -71,7 +71,7 @@ User.init(
} }
); );
User.afterSync(() => { User.hooks.add('afterSync', () => {
sequelize.getQueryInterface().addIndex(User.tableName, { sequelize.getQueryInterface().addIndex(User.tableName, {
fields: ['lastName'], fields: ['lastName'],
using: 'BTREE', using: 'BTREE',
...@@ -81,12 +81,16 @@ User.afterSync(() => { ...@@ -81,12 +81,16 @@ User.afterSync(() => {
}) })
// Hooks // Hooks
User.afterFind((users, options) => { User.hooks.add('afterFind', (users: User[], options: FindOptions) => {
console.log('found'); console.log('found');
}); });
User.hooks.add('afterBulkCreate', (users: User[]) => {
})
// TODO: VSCode shows the typing being correctly narrowed but doesn't do it correctly // TODO: VSCode shows the typing being correctly narrowed but doesn't do it correctly
User.addHook('beforeFind', 'test', (options: FindOptions) => { User.hooks.add('beforeFind', (options: FindOptions) => {
return undefined; return undefined;
}); });
......
...@@ -18,29 +18,30 @@ const conn = sequelize.connectionManager; ...@@ -18,29 +18,30 @@ const conn = sequelize.connectionManager;
// hooks // hooks
sequelize.beforeCreate('test', () => { sequelize.hooks.add('beforeCreate', () => {
// noop // noop
}); });
sequelize sequelize
.addHook('beforeConnect', (config: Config) => { .hooks.add('beforeConnect', (config: Config) => {
// noop // noop
}) })
.addHook('beforeBulkSync', () => { .add('beforeBulkSync', () => {
// noop // noop
}); });
Sequelize.addHook('beforeCreate', () => { Sequelize.hooks.add('beforeCreate', () => {
// noop // noop
}).addHook('beforeBulkCreate', () => { })
.add('beforeBulkCreate', () => {
// noop // noop
}); });
Sequelize.beforeConnect(() => { Sequelize.hooks.add('beforeConnect', () => {
}); });
Sequelize.afterConnect(() => { Sequelize.hooks.add('afterConnect', () => {
}); });
......
...@@ -5,7 +5,7 @@ export const sequelize = new Sequelize('uri'); ...@@ -5,7 +5,7 @@ export const sequelize = new Sequelize('uri');
async function trans() { async function trans() {
const a: number = await sequelize.transaction(async transaction => { const a: number = await sequelize.transaction(async transaction => {
transaction.afterCommit(() => console.log('transaction complete')); transaction.hooks.add('afterCommit', () => console.log('transaction complete'));
User.create( User.create(
{ {
data: 123, data: 123,
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!