import type { AfterAssociateEventData, AssociationOptions, BeforeAssociateEventData } from './associations/index.js'; import type { AsyncHookReturn } from './hooks.js'; import { HookHandlerBuilder } from './hooks.js'; import type { ValidationOptions } from './instance-validator.js'; import type { BulkCreateOptions, CountOptions, CreateOptions, DestroyOptions, FindOptions, InstanceDestroyOptions, InstanceRestoreOptions, InstanceUpdateOptions, Model, ModelStatic, RestoreOptions, UpdateOptions, UpsertOptions, } from './model.js'; import type { SyncOptions } from './sequelize.js'; export interface ModelHooks { beforeValidate(instance: M, options: ValidationOptions): AsyncHookReturn; afterValidate(instance: M, options: ValidationOptions): AsyncHookReturn; validationFailed(instance: M, options: ValidationOptions, error: unknown): AsyncHookReturn; beforeCreate(attributes: M, options: CreateOptions): AsyncHookReturn; afterCreate(attributes: M, options: CreateOptions): AsyncHookReturn; beforeDestroy(instance: M, options: InstanceDestroyOptions): AsyncHookReturn; afterDestroy(instance: M, options: InstanceDestroyOptions): AsyncHookReturn; beforeRestore(instance: M, options: InstanceRestoreOptions): AsyncHookReturn; afterRestore(instance: M, options: InstanceRestoreOptions): AsyncHookReturn; beforeUpdate(instance: M, options: InstanceUpdateOptions): AsyncHookReturn; afterUpdate(instance: M, options: InstanceUpdateOptions): AsyncHookReturn; beforeUpsert(attributes: M, options: UpsertOptions): AsyncHookReturn; afterUpsert(attributes: [ M, boolean | null ], options: UpsertOptions): AsyncHookReturn; beforeSave( instance: M, options: InstanceUpdateOptions | CreateOptions ): AsyncHookReturn; afterSave( instance: M, options: InstanceUpdateOptions | CreateOptions ): AsyncHookReturn; beforeBulkCreate(instances: M[], options: BulkCreateOptions): AsyncHookReturn; afterBulkCreate(instances: readonly M[], options: BulkCreateOptions): AsyncHookReturn; beforeBulkDestroy(options: DestroyOptions): AsyncHookReturn; afterBulkDestroy(options: DestroyOptions): AsyncHookReturn; beforeBulkRestore(options: RestoreOptions): AsyncHookReturn; afterBulkRestore(options: RestoreOptions): AsyncHookReturn; beforeBulkUpdate(options: UpdateOptions): AsyncHookReturn; afterBulkUpdate(options: UpdateOptions): AsyncHookReturn; /** * A hook that is run at the start of {@link Model.count} */ beforeCount(options: CountOptions): AsyncHookReturn; /** * A hook that is run before a find (select) query */ beforeFind(options: FindOptions): AsyncHookReturn; /** * A hook that is run before a find (select) query, after any `{ include: {all: ...} }` options are expanded * * @deprecated use `beforeFind` instead */ beforeFindAfterExpandIncludeAll(options: FindOptions): AsyncHookReturn; /** * A hook that is run before a find (select) query, after all option have been normalized * * @deprecated use `beforeFind` instead */ beforeFindAfterOptions(options: FindOptions): AsyncHookReturn; /** * A hook that is run after a find (select) query */ afterFind(instancesOrInstance: readonly M[] | M | null, options: FindOptions): AsyncHookReturn; /** * A hook that is run at the start of {@link Model.sync} */ beforeSync(options: SyncOptions): AsyncHookReturn; /** * A hook that is run at the end of {@link Model.sync} */ afterSync(options: SyncOptions): AsyncHookReturn; beforeAssociate(data: BeforeAssociateEventData, options: AssociationOptions): AsyncHookReturn; afterAssociate(data: AfterAssociateEventData, options: AssociationOptions): AsyncHookReturn; /** * Runs before the definition of the model changes because {@link ModelDefinition#refreshAttributes} was called. */ beforeDefinitionRefresh(): void; /** * Runs after the definition of the model has changed because {@link ModelDefinition#refreshAttributes} was called. */ afterDefinitionRefresh(): void; } export const validModelHooks: Array = [ 'beforeValidate', 'afterValidate', 'validationFailed', 'beforeCreate', 'afterCreate', 'beforeDestroy', 'afterDestroy', 'beforeRestore', 'afterRestore', 'beforeUpdate', 'afterUpdate', 'beforeUpsert', 'afterUpsert', 'beforeSave', 'afterSave', 'beforeBulkCreate', 'afterBulkCreate', 'beforeBulkDestroy', 'afterBulkDestroy', 'beforeBulkRestore', 'afterBulkRestore', 'beforeBulkUpdate', 'afterBulkUpdate', 'beforeCount', 'beforeFind', 'beforeFindAfterExpandIncludeAll', 'beforeFindAfterOptions', 'afterFind', 'beforeSync', 'afterSync', 'beforeAssociate', 'afterAssociate', 'beforeDefinitionRefresh', 'afterDefinitionRefresh', ]; export const staticModelHooks = new HookHandlerBuilder(validModelHooks, async ( eventTarget, isAsync, hookName: keyof ModelHooks, args, ) => { // This forwards hooks run on Models to the Sequelize instance's hooks. const model = eventTarget as ModelStatic; if (!model.sequelize) { throw new Error('Model must be initialized before running hooks on it.'); } if (isAsync) { await model.sequelize.hooks.runAsync(hookName, ...args); } else { model.sequelize.hooks.runSync(hookName, ...args); } });