597 lines
15 KiB
JavaScript
597 lines
15 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const _ = require('lodash');
|
||
|
const { logger } = require('./utils/logger');
|
||
|
const debug = logger.debugContext('hooks');
|
||
|
|
||
|
const hookTypes = {
|
||
|
beforeValidate: { params: 2 },
|
||
|
afterValidate: { params: 2 },
|
||
|
validationFailed: { params: 3 },
|
||
|
beforeCreate: { params: 2 },
|
||
|
afterCreate: { params: 2 },
|
||
|
beforeDestroy: { params: 2 },
|
||
|
afterDestroy: { params: 2 },
|
||
|
beforeRestore: { params: 2 },
|
||
|
afterRestore: { params: 2 },
|
||
|
beforeUpdate: { params: 2 },
|
||
|
afterUpdate: { params: 2 },
|
||
|
beforeSave: { params: 2, proxies: ['beforeUpdate', 'beforeCreate'] },
|
||
|
afterSave: { params: 2, proxies: ['afterUpdate', 'afterCreate'] },
|
||
|
beforeUpsert: { params: 2 },
|
||
|
afterUpsert: { params: 2 },
|
||
|
beforeBulkCreate: { params: 2 },
|
||
|
afterBulkCreate: { params: 2 },
|
||
|
beforeBulkDestroy: { params: 1 },
|
||
|
afterBulkDestroy: { params: 1 },
|
||
|
beforeBulkRestore: { params: 1 },
|
||
|
afterBulkRestore: { params: 1 },
|
||
|
beforeBulkUpdate: { params: 1 },
|
||
|
afterBulkUpdate: { params: 1 },
|
||
|
beforeFind: { params: 1 },
|
||
|
beforeFindAfterExpandIncludeAll: { params: 1 },
|
||
|
beforeFindAfterOptions: { params: 1 },
|
||
|
afterFind: { params: 2 },
|
||
|
beforeCount: { params: 1 },
|
||
|
beforeDefine: { params: 2, sync: true, noModel: true },
|
||
|
afterDefine: { params: 1, sync: true, noModel: true },
|
||
|
beforeInit: { params: 2, sync: true, noModel: true },
|
||
|
afterInit: { params: 1, sync: true, noModel: true },
|
||
|
beforeAssociate: { params: 2, sync: true },
|
||
|
afterAssociate: { params: 2, sync: true },
|
||
|
beforeConnect: { params: 1, noModel: true },
|
||
|
afterConnect: { params: 2, noModel: true },
|
||
|
beforeDisconnect: { params: 1, noModel: true },
|
||
|
afterDisconnect: { params: 1, noModel: true },
|
||
|
beforeSync: { params: 1 },
|
||
|
afterSync: { params: 1 },
|
||
|
beforeBulkSync: { params: 1 },
|
||
|
afterBulkSync: { params: 1 },
|
||
|
beforeQuery: { params: 2 },
|
||
|
afterQuery: { params: 2 }
|
||
|
};
|
||
|
exports.hooks = hookTypes;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* get array of current hook and its proxies combined
|
||
|
*
|
||
|
* @param {string} hookType any hook type @see {@link hookTypes}
|
||
|
*
|
||
|
* @private
|
||
|
*/
|
||
|
const getProxiedHooks = hookType =>
|
||
|
hookTypes[hookType].proxies
|
||
|
? hookTypes[hookType].proxies.concat(hookType)
|
||
|
: [hookType]
|
||
|
;
|
||
|
|
||
|
function getHooks(hooked, hookType) {
|
||
|
return (hooked.options.hooks || {})[hookType] || [];
|
||
|
}
|
||
|
|
||
|
const Hooks = {
|
||
|
/**
|
||
|
* Process user supplied hooks definition
|
||
|
*
|
||
|
* @param {object} hooks hooks definition
|
||
|
*
|
||
|
* @private
|
||
|
* @memberof Sequelize
|
||
|
* @memberof Sequelize.Model
|
||
|
*/
|
||
|
_setupHooks(hooks) {
|
||
|
this.options.hooks = {};
|
||
|
_.map(hooks || {}, (hooksArray, hookName) => {
|
||
|
if (!Array.isArray(hooksArray)) hooksArray = [hooksArray];
|
||
|
hooksArray.forEach(hookFn => this.addHook(hookName, hookFn));
|
||
|
});
|
||
|
},
|
||
|
|
||
|
async runHooks(hooks, ...hookArgs) {
|
||
|
if (!hooks) throw new Error('runHooks requires at least 1 argument');
|
||
|
|
||
|
let hookType;
|
||
|
|
||
|
if (typeof hooks === 'string') {
|
||
|
hookType = hooks;
|
||
|
hooks = getHooks(this, hookType);
|
||
|
|
||
|
if (this.sequelize) {
|
||
|
hooks = hooks.concat(getHooks(this.sequelize, hookType));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!Array.isArray(hooks)) {
|
||
|
hooks = [hooks];
|
||
|
}
|
||
|
|
||
|
// synchronous hooks
|
||
|
if (hookTypes[hookType] && hookTypes[hookType].sync) {
|
||
|
for (let hook of hooks) {
|
||
|
if (typeof hook === 'object') {
|
||
|
hook = hook.fn;
|
||
|
}
|
||
|
|
||
|
debug(`running hook(sync) ${hookType}`);
|
||
|
hook.apply(this, hookArgs);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// asynchronous hooks (default)
|
||
|
for (let hook of hooks) {
|
||
|
if (typeof hook === 'object') {
|
||
|
hook = hook.fn;
|
||
|
}
|
||
|
|
||
|
debug(`running hook ${hookType}`);
|
||
|
await hook.apply(this, hookArgs);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Add a hook to the model
|
||
|
*
|
||
|
* @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
|
||
|
*
|
||
|
* @memberof Sequelize
|
||
|
* @memberof Sequelize.Model
|
||
|
*/
|
||
|
addHook(hookType, name, fn) {
|
||
|
if (typeof name === 'function') {
|
||
|
fn = name;
|
||
|
name = null;
|
||
|
}
|
||
|
|
||
|
debug(`adding hook ${hookType}`);
|
||
|
// check for proxies, add them too
|
||
|
hookType = getProxiedHooks(hookType);
|
||
|
|
||
|
hookType.forEach(type => {
|
||
|
const hooks = getHooks(this, type);
|
||
|
hooks.push(name ? { name, fn } : fn);
|
||
|
this.options.hooks[type] = hooks;
|
||
|
});
|
||
|
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Remove hook from the model
|
||
|
*
|
||
|
* @param {string} hookType @see {@link hookTypes}
|
||
|
* @param {string|Function} name name of hook or function reference which was attached
|
||
|
*
|
||
|
* @memberof Sequelize
|
||
|
* @memberof Sequelize.Model
|
||
|
*/
|
||
|
removeHook(hookType, name) {
|
||
|
const isReference = typeof name === 'function' ? true : false;
|
||
|
|
||
|
if (!this.hasHook(hookType)) {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
debug(`removing hook ${hookType}`);
|
||
|
|
||
|
// check for proxies, add them too
|
||
|
hookType = getProxiedHooks(hookType);
|
||
|
|
||
|
for (const type of hookType) {
|
||
|
this.options.hooks[type] = this.options.hooks[type].filter(hook => {
|
||
|
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;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Check whether the mode has any hooks of this type
|
||
|
*
|
||
|
* @param {string} hookType @see {@link hookTypes}
|
||
|
*
|
||
|
* @alias hasHooks
|
||
|
*
|
||
|
* @memberof Sequelize
|
||
|
* @memberof Sequelize.Model
|
||
|
*/
|
||
|
hasHook(hookType) {
|
||
|
return this.options.hooks[hookType] && !!this.options.hooks[hookType].length;
|
||
|
}
|
||
|
};
|
||
|
Hooks.hasHooks = Hooks.hasHook;
|
||
|
|
||
|
|
||
|
function applyTo(target, isModel = false) {
|
||
|
_.mixin(target, Hooks);
|
||
|
|
||
|
for (const hook of Object.keys(hookTypes)) {
|
||
|
if (isModel && hookTypes[hook].noModel) {
|
||
|
continue;
|
||
|
}
|
||
|
target[hook] = function(name, callback) {
|
||
|
return this.addHook(hook, name, callback);
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
exports.applyTo = applyTo;
|
||
|
|
||
|
/**
|
||
|
* 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 the config passed to connection
|
||
|
* @name afterConnect
|
||
|
* @memberof Sequelize
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* A hook that is run before a connection is disconnected
|
||
|
*
|
||
|
* @param {string} name
|
||
|
* @param {Function} fn A callback function that is called with the connection object
|
||
|
* @name beforeDisconnect
|
||
|
* @memberof Sequelize
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* A hook that is run after a connection is disconnected
|
||
|
*
|
||
|
* @param {string} name
|
||
|
* @param {Function} fn A callback function that is called with the connection object
|
||
|
* @name afterDisconnect
|
||
|
* @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
|
||
|
*/
|