From 18250f8f758fcc7a41972a86f4ce4ecbf66ff8dc Mon Sep 17 00:00:00 2001 From: Nate Silva Date: Mon, 14 Aug 2017 15:25:28 -0700 Subject: [PATCH 1/3] feature(hooks): add decorators for declaring hooks --- README.md | 29 ++ index.ts | 34 +++ lib/annotations/hooks/AfterBulkCreate.ts | 21 ++ lib/annotations/hooks/AfterBulkDelete.ts | 21 ++ lib/annotations/hooks/AfterBulkDestroy.ts | 21 ++ lib/annotations/hooks/AfterBulkRestore.ts | 21 ++ lib/annotations/hooks/AfterBulkUpdate.ts | 21 ++ lib/annotations/hooks/AfterCreate.ts | 21 ++ lib/annotations/hooks/AfterDelete.ts | 21 ++ lib/annotations/hooks/AfterDestroy.ts | 21 ++ lib/annotations/hooks/AfterFind.ts | 21 ++ lib/annotations/hooks/AfterRestore.ts | 21 ++ lib/annotations/hooks/AfterSave.ts | 21 ++ lib/annotations/hooks/AfterUpdate.ts | 21 ++ lib/annotations/hooks/AfterUpsert.ts | 21 ++ lib/annotations/hooks/AfterValidate.ts | 21 ++ lib/annotations/hooks/BeforeBulkCreate.ts | 21 ++ lib/annotations/hooks/BeforeBulkDelete.ts | 21 ++ lib/annotations/hooks/BeforeBulkDestroy.ts | 21 ++ lib/annotations/hooks/BeforeBulkRestore.ts | 21 ++ lib/annotations/hooks/BeforeBulkUpdate.ts | 21 ++ lib/annotations/hooks/BeforeCount.ts | 21 ++ lib/annotations/hooks/BeforeCreate.ts | 21 ++ lib/annotations/hooks/BeforeDelete.ts | 21 ++ lib/annotations/hooks/BeforeDestroy.ts | 21 ++ lib/annotations/hooks/BeforeFind.ts | 21 ++ .../hooks/BeforeFindAfterExpandIncludeAll.ts | 21 ++ .../hooks/BeforeFindAfterOptions.ts | 21 ++ lib/annotations/hooks/BeforeRestore.ts | 21 ++ lib/annotations/hooks/BeforeSave.ts | 21 ++ lib/annotations/hooks/BeforeUpdate.ts | 21 ++ lib/annotations/hooks/BeforeUpsert.ts | 21 ++ lib/annotations/hooks/BeforeValidate.ts | 21 ++ lib/annotations/hooks/ValidationFailed.ts | 21 ++ lib/interfaces/IHookOptions.ts | 4 + lib/interfaces/ISequelizeHook.ts | 7 + lib/models/BaseSequelize.ts | 2 + lib/services/hooks.ts | 77 +++++ test/models/Hook.ts | 224 +++++++++++++++ test/specs/hooks/hooks.spec.ts | 266 ++++++++++++++++++ 40 files changed, 1315 insertions(+) create mode 100644 lib/annotations/hooks/AfterBulkCreate.ts create mode 100644 lib/annotations/hooks/AfterBulkDelete.ts create mode 100644 lib/annotations/hooks/AfterBulkDestroy.ts create mode 100644 lib/annotations/hooks/AfterBulkRestore.ts create mode 100644 lib/annotations/hooks/AfterBulkUpdate.ts create mode 100644 lib/annotations/hooks/AfterCreate.ts create mode 100644 lib/annotations/hooks/AfterDelete.ts create mode 100644 lib/annotations/hooks/AfterDestroy.ts create mode 100644 lib/annotations/hooks/AfterFind.ts create mode 100644 lib/annotations/hooks/AfterRestore.ts create mode 100644 lib/annotations/hooks/AfterSave.ts create mode 100644 lib/annotations/hooks/AfterUpdate.ts create mode 100644 lib/annotations/hooks/AfterUpsert.ts create mode 100644 lib/annotations/hooks/AfterValidate.ts create mode 100644 lib/annotations/hooks/BeforeBulkCreate.ts create mode 100644 lib/annotations/hooks/BeforeBulkDelete.ts create mode 100644 lib/annotations/hooks/BeforeBulkDestroy.ts create mode 100644 lib/annotations/hooks/BeforeBulkRestore.ts create mode 100644 lib/annotations/hooks/BeforeBulkUpdate.ts create mode 100644 lib/annotations/hooks/BeforeCount.ts create mode 100644 lib/annotations/hooks/BeforeCreate.ts create mode 100644 lib/annotations/hooks/BeforeDelete.ts create mode 100644 lib/annotations/hooks/BeforeDestroy.ts create mode 100644 lib/annotations/hooks/BeforeFind.ts create mode 100644 lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts create mode 100644 lib/annotations/hooks/BeforeFindAfterOptions.ts create mode 100644 lib/annotations/hooks/BeforeRestore.ts create mode 100644 lib/annotations/hooks/BeforeSave.ts create mode 100644 lib/annotations/hooks/BeforeUpdate.ts create mode 100644 lib/annotations/hooks/BeforeUpsert.ts create mode 100644 lib/annotations/hooks/BeforeValidate.ts create mode 100644 lib/annotations/hooks/ValidationFailed.ts create mode 100644 lib/interfaces/IHookOptions.ts create mode 100644 lib/interfaces/ISequelizeHook.ts create mode 100644 lib/services/hooks.ts create mode 100644 test/models/Hook.ts create mode 100644 test/specs/hooks/hooks.spec.ts diff --git a/README.md b/README.md index 6b7266f6..062678ac 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Decorators and some other extras for sequelize (v3 + v4). - [Multiple relations of same models](#multiple-relations-of-same-models) - [Model validation](#model-validation) - [Scopes](#scopes) + - [Hooks](#hooks) - [Why `() => Model`?](#user-content-why---model) - [Recommendations and limitations](#recommendations-and-limitations) @@ -552,6 +553,34 @@ export class ShoeWithScopes extends Model { } ``` +## Hooks +Hooks can be attached to your models. All Model-level hooks are supported. See [the related unit tests](test/models/Hook.ts) for a summary. + +Each hook must be a `static` method. Multiple hooks can be attached to a single method, and you can define multiple methods for a given hook. + +The name of the method cannot be the same as the name of the hook (for example, a `@BeforeCreate` hook method cannot be named `beforeCreate`). That’s because Sequelize has pre-defined methods with those names. + +```typescript +@Table +export class Person extends Model { + @Column + name: string; + + @BeforeUpdate + @BeforeCreate + static makeUpperCase(instance: Person) { + // this will be called when an instance is created or updated + instance.name = instance.name.toLocaleUpperCase(); + } + + @BeforeCreate + static addUnicorn(instance: Person) { + // this will also be called when an instance is created + instance.name += ' 🦄'; + } +} +``` + ## Why `() => Model`? `@ForeignKey(Model)` is much easier to read, so why is `@ForeignKey(() => Model)` so important? When it comes to circular-dependencies (which are in general solved by node for you) `Model` can be `undefined` diff --git a/index.ts b/index.ts index bde62901..05a3e94e 100644 --- a/index.ts +++ b/index.ts @@ -51,6 +51,40 @@ export {NotIn} from "./lib/annotations/validation/NotIn"; export {NotNull} from "./lib/annotations/validation/NotNull"; export {Validate} from "./lib/annotations/validation/Validate"; +// hooks +export {BeforeValidate} from "./lib/annotations/hooks/BeforeValidate"; +export {AfterValidate} from "./lib/annotations/hooks/AfterValidate"; +export {ValidationFailed} from "./lib/annotations/hooks/ValidationFailed"; +export {BeforeCreate} from "./lib/annotations/hooks/BeforeCreate"; +export {AfterCreate} from "./lib/annotations/hooks/AfterCreate"; +export {BeforeDestroy} from "./lib/annotations/hooks/BeforeDestroy"; +export {AfterDestroy} from "./lib/annotations/hooks/AfterDestroy"; +export {BeforeRestore} from "./lib/annotations/hooks/BeforeRestore"; +export {AfterRestore} from "./lib/annotations/hooks/AfterRestore"; +export {BeforeUpdate} from "./lib/annotations/hooks/BeforeUpdate"; +export {AfterUpdate} from "./lib/annotations/hooks/AfterUpdate"; +export {BeforeSave} from "./lib/annotations/hooks/BeforeSave"; +export {AfterSave} from "./lib/annotations/hooks/AfterSave"; +export {BeforeUpsert} from "./lib/annotations/hooks/BeforeUpsert"; +export {AfterUpsert} from "./lib/annotations/hooks/AfterUpsert"; +export {BeforeBulkCreate} from "./lib/annotations/hooks/BeforeBulkCreate"; +export {AfterBulkCreate} from "./lib/annotations/hooks/AfterBulkCreate"; +export {BeforeBulkDestroy} from "./lib/annotations/hooks/BeforeBulkDestroy"; +export {AfterBulkDestroy} from "./lib/annotations/hooks/AfterBulkDestroy"; +export {BeforeBulkRestore} from "./lib/annotations/hooks/BeforeBulkRestore"; +export {AfterBulkRestore} from "./lib/annotations/hooks/AfterBulkRestore"; +export {BeforeBulkUpdate} from "./lib/annotations/hooks/BeforeBulkUpdate"; +export {AfterBulkUpdate} from "./lib/annotations/hooks/AfterBulkUpdate"; +export {BeforeFind} from "./lib/annotations/hooks/BeforeFind"; +export {BeforeFindAfterExpandIncludeAll} from "./lib/annotations/hooks/BeforeFindAfterExpandIncludeAll"; +export {BeforeFindAfterOptions} from "./lib/annotations/hooks/BeforeFindAfterOptions"; +export {AfterFind} from "./lib/annotations/hooks/AfterFind"; +export {BeforeCount} from "./lib/annotations/hooks/BeforeCount"; +export {BeforeDelete} from "./lib/annotations/hooks/BeforeDelete"; +export {AfterDelete} from "./lib/annotations/hooks/AfterDelete"; +export {BeforeBulkDelete} from "./lib/annotations/hooks/BeforeBulkDelete"; +export {AfterBulkDelete} from "./lib/annotations/hooks/AfterBulkDelete"; + // interfaces export {IAssociationActionOptions} from "./lib/interfaces/IAssociationActionOptions"; export {IBuildOptions} from "./lib/interfaces/IBuildOptions"; diff --git a/lib/annotations/hooks/AfterBulkCreate.ts b/lib/annotations/hooks/AfterBulkCreate.ts new file mode 100644 index 00000000..79a3be4e --- /dev/null +++ b/lib/annotations/hooks/AfterBulkCreate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterBulkCreate(target: any, propertyName: string): void; +export function AfterBulkCreate(options: IHookOptions): Function; +export function AfterBulkCreate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterBulkCreate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterBulkCreate', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterBulkDelete.ts b/lib/annotations/hooks/AfterBulkDelete.ts new file mode 100644 index 00000000..e0b14c59 --- /dev/null +++ b/lib/annotations/hooks/AfterBulkDelete.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterBulkDelete(target: any, propertyName: string): void; +export function AfterBulkDelete(options: IHookOptions): Function; +export function AfterBulkDelete(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterBulkDelete', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterBulkDelete', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterBulkDestroy.ts b/lib/annotations/hooks/AfterBulkDestroy.ts new file mode 100644 index 00000000..724fc9d6 --- /dev/null +++ b/lib/annotations/hooks/AfterBulkDestroy.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterBulkDestroy(target: any, propertyName: string): void; +export function AfterBulkDestroy(options: IHookOptions): Function; +export function AfterBulkDestroy(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterBulkDestroy', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterBulkDestroy', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterBulkRestore.ts b/lib/annotations/hooks/AfterBulkRestore.ts new file mode 100644 index 00000000..706b7767 --- /dev/null +++ b/lib/annotations/hooks/AfterBulkRestore.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterBulkRestore(target: any, propertyName: string): void; +export function AfterBulkRestore(options: IHookOptions): Function; +export function AfterBulkRestore(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterBulkRestore', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterBulkRestore', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterBulkUpdate.ts b/lib/annotations/hooks/AfterBulkUpdate.ts new file mode 100644 index 00000000..770374b7 --- /dev/null +++ b/lib/annotations/hooks/AfterBulkUpdate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterBulkUpdate(target: any, propertyName: string): void; +export function AfterBulkUpdate(options: IHookOptions): Function; +export function AfterBulkUpdate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterBulkUpdate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterBulkUpdate', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterCreate.ts b/lib/annotations/hooks/AfterCreate.ts new file mode 100644 index 00000000..1815a5b7 --- /dev/null +++ b/lib/annotations/hooks/AfterCreate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterCreate(target: any, propertyName: string): void; +export function AfterCreate(options: IHookOptions): Function; +export function AfterCreate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterCreate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterCreate', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterDelete.ts b/lib/annotations/hooks/AfterDelete.ts new file mode 100644 index 00000000..ebb58e02 --- /dev/null +++ b/lib/annotations/hooks/AfterDelete.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterDelete(target: any, propertyName: string): void; +export function AfterDelete(options: IHookOptions): Function; +export function AfterDelete(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterDelete', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterDelete', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterDestroy.ts b/lib/annotations/hooks/AfterDestroy.ts new file mode 100644 index 00000000..3ea6e59d --- /dev/null +++ b/lib/annotations/hooks/AfterDestroy.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterDestroy(target: any, propertyName: string): void; +export function AfterDestroy(options: IHookOptions): Function; +export function AfterDestroy(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterDestroy', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterDestroy', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterFind.ts b/lib/annotations/hooks/AfterFind.ts new file mode 100644 index 00000000..332ce6b3 --- /dev/null +++ b/lib/annotations/hooks/AfterFind.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterFind(target: any, propertyName: string): void; +export function AfterFind(options: IHookOptions): Function; +export function AfterFind(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterFind', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterFind', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterRestore.ts b/lib/annotations/hooks/AfterRestore.ts new file mode 100644 index 00000000..2cf844c8 --- /dev/null +++ b/lib/annotations/hooks/AfterRestore.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterRestore(target: any, propertyName: string): void; +export function AfterRestore(options: IHookOptions): Function; +export function AfterRestore(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterRestore', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterRestore', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterSave.ts b/lib/annotations/hooks/AfterSave.ts new file mode 100644 index 00000000..cd788e19 --- /dev/null +++ b/lib/annotations/hooks/AfterSave.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterSave(target: any, propertyName: string): void; +export function AfterSave(options: IHookOptions): Function; +export function AfterSave(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterSave', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterSave', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterUpdate.ts b/lib/annotations/hooks/AfterUpdate.ts new file mode 100644 index 00000000..26151310 --- /dev/null +++ b/lib/annotations/hooks/AfterUpdate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterUpdate(target: any, propertyName: string): void; +export function AfterUpdate(options: IHookOptions): Function; +export function AfterUpdate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterUpdate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterUpdate', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterUpsert.ts b/lib/annotations/hooks/AfterUpsert.ts new file mode 100644 index 00000000..aa09bb3d --- /dev/null +++ b/lib/annotations/hooks/AfterUpsert.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterUpsert(target: any, propertyName: string): void; +export function AfterUpsert(options: IHookOptions): Function; +export function AfterUpsert(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterUpsert', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterUpsert', propertyName); + } +} diff --git a/lib/annotations/hooks/AfterValidate.ts b/lib/annotations/hooks/AfterValidate.ts new file mode 100644 index 00000000..72cb3ca6 --- /dev/null +++ b/lib/annotations/hooks/AfterValidate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function AfterValidate(target: any, propertyName: string): void; +export function AfterValidate(options: IHookOptions): Function; +export function AfterValidate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'afterValidate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'afterValidate', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeBulkCreate.ts b/lib/annotations/hooks/BeforeBulkCreate.ts new file mode 100644 index 00000000..e192a225 --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkCreate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeBulkCreate(target: any, propertyName: string): void; +export function BeforeBulkCreate(options: IHookOptions): Function; +export function BeforeBulkCreate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeBulkCreate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeBulkCreate', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeBulkDelete.ts b/lib/annotations/hooks/BeforeBulkDelete.ts new file mode 100644 index 00000000..4a85c25f --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkDelete.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeBulkDelete(target: any, propertyName: string): void; +export function BeforeBulkDelete(options: IHookOptions): Function; +export function BeforeBulkDelete(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeBulkDelete', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeBulkDelete', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeBulkDestroy.ts b/lib/annotations/hooks/BeforeBulkDestroy.ts new file mode 100644 index 00000000..4eed0afd --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkDestroy.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeBulkDestroy(target: any, propertyName: string): void; +export function BeforeBulkDestroy(options: IHookOptions): Function; +export function BeforeBulkDestroy(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeBulkDestroy', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeBulkDestroy', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeBulkRestore.ts b/lib/annotations/hooks/BeforeBulkRestore.ts new file mode 100644 index 00000000..13096922 --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkRestore.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeBulkRestore(target: any, propertyName: string): void; +export function BeforeBulkRestore(options: IHookOptions): Function; +export function BeforeBulkRestore(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeBulkRestore', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeBulkRestore', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeBulkUpdate.ts b/lib/annotations/hooks/BeforeBulkUpdate.ts new file mode 100644 index 00000000..3ccf38e7 --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkUpdate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeBulkUpdate(target: any, propertyName: string): void; +export function BeforeBulkUpdate(options: IHookOptions): Function; +export function BeforeBulkUpdate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeBulkUpdate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeBulkUpdate', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeCount.ts b/lib/annotations/hooks/BeforeCount.ts new file mode 100644 index 00000000..fd0ec8f9 --- /dev/null +++ b/lib/annotations/hooks/BeforeCount.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeCount(target: any, propertyName: string): void; +export function BeforeCount(options: IHookOptions): Function; +export function BeforeCount(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeCount', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeCount', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeCreate.ts b/lib/annotations/hooks/BeforeCreate.ts new file mode 100644 index 00000000..1f762a3c --- /dev/null +++ b/lib/annotations/hooks/BeforeCreate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeCreate(target: any, propertyName: string): void; +export function BeforeCreate(options: IHookOptions): Function; +export function BeforeCreate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeCreate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeCreate', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeDelete.ts b/lib/annotations/hooks/BeforeDelete.ts new file mode 100644 index 00000000..d73bf3bc --- /dev/null +++ b/lib/annotations/hooks/BeforeDelete.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeDelete(target: any, propertyName: string): void; +export function BeforeDelete(options: IHookOptions): Function; +export function BeforeDelete(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeDelete', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeDelete', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeDestroy.ts b/lib/annotations/hooks/BeforeDestroy.ts new file mode 100644 index 00000000..dfa76e9f --- /dev/null +++ b/lib/annotations/hooks/BeforeDestroy.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeDestroy(target: any, propertyName: string): void; +export function BeforeDestroy(options: IHookOptions): Function; +export function BeforeDestroy(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeDestroy', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeDestroy', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeFind.ts b/lib/annotations/hooks/BeforeFind.ts new file mode 100644 index 00000000..2ed36649 --- /dev/null +++ b/lib/annotations/hooks/BeforeFind.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeFind(target: any, propertyName: string): void; +export function BeforeFind(options: IHookOptions): Function; +export function BeforeFind(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeFind', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeFind', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts b/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts new file mode 100644 index 00000000..1ac09b06 --- /dev/null +++ b/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeFindAfterExpandIncludeAll(target: any, propertyName: string): void; +export function BeforeFindAfterExpandIncludeAll(options: IHookOptions): Function; +export function BeforeFindAfterExpandIncludeAll(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeFindAfterExpandIncludeAll', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeFindAfterExpandIncludeAll', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeFindAfterOptions.ts b/lib/annotations/hooks/BeforeFindAfterOptions.ts new file mode 100644 index 00000000..e7eb9f46 --- /dev/null +++ b/lib/annotations/hooks/BeforeFindAfterOptions.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeFindAfterOptions(target: any, propertyName: string): void; +export function BeforeFindAfterOptions(options: IHookOptions): Function; +export function BeforeFindAfterOptions(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeFindAfterOptions', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeFindAfterOptions', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeRestore.ts b/lib/annotations/hooks/BeforeRestore.ts new file mode 100644 index 00000000..12e3555f --- /dev/null +++ b/lib/annotations/hooks/BeforeRestore.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeRestore(target: any, propertyName: string): void; +export function BeforeRestore(options: IHookOptions): Function; +export function BeforeRestore(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeRestore', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeRestore', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeSave.ts b/lib/annotations/hooks/BeforeSave.ts new file mode 100644 index 00000000..b63d9311 --- /dev/null +++ b/lib/annotations/hooks/BeforeSave.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeSave(target: any, propertyName: string): void; +export function BeforeSave(options: IHookOptions): Function; +export function BeforeSave(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeSave', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeSave', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeUpdate.ts b/lib/annotations/hooks/BeforeUpdate.ts new file mode 100644 index 00000000..0b96ebe0 --- /dev/null +++ b/lib/annotations/hooks/BeforeUpdate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeUpdate(target: any, propertyName: string): void; +export function BeforeUpdate(options: IHookOptions): Function; +export function BeforeUpdate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeUpdate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeUpdate', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeUpsert.ts b/lib/annotations/hooks/BeforeUpsert.ts new file mode 100644 index 00000000..9e4bd255 --- /dev/null +++ b/lib/annotations/hooks/BeforeUpsert.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeUpsert(target: any, propertyName: string): void; +export function BeforeUpsert(options: IHookOptions): Function; +export function BeforeUpsert(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeUpsert', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeUpsert', propertyName); + } +} diff --git a/lib/annotations/hooks/BeforeValidate.ts b/lib/annotations/hooks/BeforeValidate.ts new file mode 100644 index 00000000..5b59e418 --- /dev/null +++ b/lib/annotations/hooks/BeforeValidate.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function BeforeValidate(target: any, propertyName: string): void; +export function BeforeValidate(options: IHookOptions): Function; +export function BeforeValidate(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'beforeValidate', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'beforeValidate', propertyName); + } +} diff --git a/lib/annotations/hooks/ValidationFailed.ts b/lib/annotations/hooks/ValidationFailed.ts new file mode 100644 index 00000000..731376ec --- /dev/null +++ b/lib/annotations/hooks/ValidationFailed.ts @@ -0,0 +1,21 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {addHook} from "../../services/hooks"; + +export function ValidationFailed(target: any, propertyName: string): void; +export function ValidationFailed(options: IHookOptions): Function; +export function ValidationFailed(...args: any[]): void|Function { + + if (args.length === 1) { + + const options = args[0]; + + return (target: any, propertyName: string) => + addHook(target, 'validationFailed', propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, 'validationFailed', propertyName); + } +} diff --git a/lib/interfaces/IHookOptions.ts b/lib/interfaces/IHookOptions.ts new file mode 100644 index 00000000..c4e29380 --- /dev/null +++ b/lib/interfaces/IHookOptions.ts @@ -0,0 +1,4 @@ +export interface IHookOptions { + + name?: string; +} diff --git a/lib/interfaces/ISequelizeHook.ts b/lib/interfaces/ISequelizeHook.ts new file mode 100644 index 00000000..cbcbe825 --- /dev/null +++ b/lib/interfaces/ISequelizeHook.ts @@ -0,0 +1,7 @@ +import {IHookOptions} from "./IHookOptions"; + +export interface ISequelizeHook { + hookType: string; + methodName: string; + options?: IHookOptions; +} diff --git a/lib/models/BaseSequelize.ts b/lib/models/BaseSequelize.ts index 5e68fdbd..f75a0dfc 100644 --- a/lib/models/BaseSequelize.ts +++ b/lib/models/BaseSequelize.ts @@ -3,6 +3,7 @@ import {DEFAULT_DEFINE_OPTIONS, getModels} from "../services/models"; import {getAssociations, processAssociation} from "../services/association"; import {ISequelizeConfig} from "../interfaces/ISequelizeConfig"; import {resolveScopes} from "../services/scopes"; +import {installHooks} from "../services/hooks"; import {ISequelizeValidationOnlyConfig} from "../interfaces/ISequelizeValidationOnlyConfig"; import {extend} from "../utils/object"; import {ISequelizeAssociation} from "../interfaces/ISequelizeAssociation"; @@ -61,6 +62,7 @@ export abstract class BaseSequelize { models.forEach(model => model.isInitialized = true); this.associateModels(models); resolveScopes(models); + installHooks​​(models); models.forEach(model => this._[model.name] = model); } diff --git a/lib/services/hooks.ts b/lib/services/hooks.ts new file mode 100644 index 00000000..a2b42bfc --- /dev/null +++ b/lib/services/hooks.ts @@ -0,0 +1,77 @@ +import 'reflect-metadata'; +import {Model} from "../models/Model"; +import {ISequelizeHook} from "../interfaces/ISequelizeHook"; +import {IHookOptions} from "../interfaces/IHookOptions"; + +const HOOKS_KEY = 'sequelize:hooks'; + +/** + * Installs hooks on the specified models + */ +export function installHooks(models: Array): void { + models.forEach(model => { + const hooks = getHooks(model); + + if (hooks) { + hooks.forEach(hook => { + installHook(model, hook); + }); + } + }); +} + +/** + * Adds hook meta data for specified model + * @throws if applied to a non-static method + */ +export function addHook(target: any, hookType: string, methodName: string, options: IHookOptions = {}): void { + if (typeof target !== 'function') { + throw new Error(`Hook method '${methodName}' is not a static method. ` + + `Only static methods can be used for hooks`); + } + + // make sure the hook name doesn’t conflict with Sequelize’s existing methods + if (methodName === hookType) { + throw new Error(`Hook method cannot be named '${methodName}'. That name is ` + + `reserved by Sequelize`); + } + + const hooks = getHooks(target) || []; + + hooks.push({ + hookType, + methodName, + options + }); + + setHooks(target, hooks); +} + +/** + * Install a hook + */ +function installHook(model: typeof Model, hook: ISequelizeHook): void { + if (hook.options && hook.options.name) { + model.addHook(hook.hookType, hook.options.name, model[hook.methodName]); + return; + } + + model.addHook(hook.hookType, model[hook.methodName]); +} + +/** + * Returns hooks meta data from specified class + */ +export function getHooks(target: any): ISequelizeHook[] | undefined { + const hooks = Reflect.getMetadata(HOOKS_KEY, target); + if (hooks) { + return [...hooks]; + } +} + +/** + * Saves hooks meta data for the specified class + */ +export function setHooks(target: any, hooks: ISequelizeHook[]): void { + Reflect.defineMetadata(HOOKS_KEY, hooks, target); +} diff --git a/test/models/Hook.ts b/test/models/Hook.ts new file mode 100644 index 00000000..7168c525 --- /dev/null +++ b/test/models/Hook.ts @@ -0,0 +1,224 @@ +import { AfterBulkCreate, AfterUpsert, BeforeBulkCreate, BeforeUpsert } from "../../index"; +import { AfterBulkDestroy, BeforeBulkDestroy, BeforeBulkRestore } from "../../index"; +import { AfterBulkRestore, AfterBulkUpdate, BeforeBulkUpdate } from "../../index"; +import { AfterCreate, AfterValidate, ValidationFailed } from "../../index"; +import { AfterDestroy, AfterRestore, BeforeDestroy, BeforeRestore } from "../../index"; +import { AfterFind, BeforeCount, BeforeFindAfterOptions } from "../../index"; +import { AfterSave, AfterUpdate, BeforeSave, BeforeUpdate } from "../../index"; +import { BeforeCreate, BeforeValidate, Column, Model, Table } from "../../index"; +import { BeforeFind, BeforeFindAfterExpandIncludeAll } from "../../index"; +import { BeforeBulkDelete, AfterBulkDelete, AfterDelete, BeforeDelete } from "../../index"; + +/** + * Model used to test hook decorators. Defined hooks are mocked out for testing. + */ +@Table +export class Hook extends Model { + + @Column + name: string; + + @BeforeValidate + static beforeValidateHook(instance: Hook, options: any): void {} + + @AfterValidate + static afterValidateHook(instance: Hook, options: any): void {} + + @ValidationFailed + static validationFailedHook(instance: Hook, options: any, err: any): void {} + + @BeforeCreate + static beforeCreateHook(instance: Hook, options: any): void {} + + @AfterCreate + static afterCreateHook(instance: Hook, options: any): void {} + + @BeforeDestroy + static beforeDestroyHook(instance: Hook, options: any): void {} + + @BeforeDelete + static beforeDeleteHook(instance: Hook, options: any): void {} + + @AfterDestroy + static afterDestroyHook(instance: Hook, options: any): void {} + + @AfterDelete + static afterDeleteHook(instance: Hook, options: any): void {} + + @BeforeRestore + static beforeRestoreHook(instance: Hook, options: any): void {} + + @AfterRestore + static afterRestoreHook(instance: Hook, options: any): void {} + + @BeforeUpdate + static beforeUpdateHook(instance: Hook, options: any): void {} + + @AfterUpdate + static afterUpdateHook(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @BeforeSave + static beforeSaveHook(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @AfterSave + static afterSaveHook(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @BeforeUpsert + static beforeUpsertHook(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @AfterUpsert + static afterUpsertHook(instance: Hook, options: any): void {} + + @BeforeBulkCreate + static beforeBulkCreateHook(instances: Hook[], options: any): void {} + + @AfterBulkCreate + static afterBulkCreateHook(instances: Hook[], options: any): void {} + + @BeforeBulkDestroy + static beforeBulkDestroyHook(options: any): void {} + + @BeforeBulkDelete + static beforeBulkDeleteHook(options: any): void {} + + @AfterBulkDestroy + static afterBulkDestroyHook(options: any): void {} + + @AfterBulkDelete + static afterBulkDeleteHook(options: any): void {} + + @BeforeBulkRestore + static beforeBulkRestoreHook(options: any): void {} + + @AfterBulkRestore + static afterBulkRestoreHook(options: any): void {} + + @BeforeBulkUpdate + static beforeBulkUpdateHook(options: any): void {} + + @AfterBulkUpdate + static afterBulkUpdateHook(options: any): void {} + + @BeforeFind + static beforeFindHook(options: any): void {} + + @BeforeFindAfterExpandIncludeAll + static beforeFindAfterExpandIncludeAllHook(options: any): void {} + + @BeforeFindAfterOptions + static beforeFindAfterOptionsHook(options: any): void {} + + @AfterFind + static afterFindHook(options: any): void {} + + @BeforeCount + static beforeCountHook(options: any): void {} + + // Hooks can also be named. This allows them to be removed at a later time using + // Model.removeHook('hookType', 'hookName'). Please be aware that hook removal does not + // work correctly in versions of Sequelize earlier than 4.4.10. + + @BeforeValidate({ name: 'myBeforeValidateHook' }) + static beforeValidateHookWithName(instance: Hook, options: any): void {} + + @AfterValidate({ name: 'myAfterValidateHook' }) + static afterValidateHookWithName(instance: Hook, options: any): void {} + + @ValidationFailed({ name: 'myValidationFailedHook' }) + static validationFailedHookWithName(instance: Hook, options: any, err: any): void {} + + @BeforeCreate({ name: 'myBeforeCreateHook' }) + static beforeCreateHookWithName(instance: Hook, options: any): void {} + + @AfterCreate({ name: 'myAfterCreateHook' }) + static afterCreateHookWithName(instance: Hook, options: any): void {} + + @BeforeDestroy({ name: 'myBeforeDestroyHook' }) + static beforeDestroyHookWithName(instance: Hook, options: any): void {} + + @BeforeDelete({ name: 'myBeforeDeleteHook' }) + static beforeDeleteHookWithName(instance: Hook, options: any): void {} + + @AfterDestroy({ name: 'myAfterDestroyHook' }) + static afterDestroyHookWithName(instance: Hook, options: any): void {} + + @AfterDelete({ name: 'myAfterDeleteHook' }) + static afterDeleteHookWithName(instance: Hook, options: any): void {} + + @BeforeRestore({ name: 'myBeforeRestoreHook' }) + static beforeRestoreHookWithName(instance: Hook, options: any): void {} + + @AfterRestore({ name: 'myAfterRestoreHook' }) + static afterRestoreHookWithName(instance: Hook, options: any): void {} + + @BeforeUpdate({ name: 'myBeforeUpdateHook' }) + static beforeUpdateHookWithName(instance: Hook, options: any): void {} + + @AfterUpdate({ name: 'myAfterUpdateHook' }) + static afterUpdateHookWithName(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @BeforeSave({ name: 'myBeforeSaveHook' }) + static beforeSaveHookWithName(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @AfterSave({ name: 'myAfterSaveHook' }) + static afterSaveHookWithName(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @BeforeUpsert({ name: 'myBeforeUpsertHook' }) + static beforeUpsertHookWithName(instance: Hook, options: any): void {} + + // NOTE: this hook only available in Sequelize v4 + @AfterUpsert({ name: 'myAfterUpsertHook' }) + static afterUpsertHookWithName(instance: Hook, options: any): void {} + + @BeforeBulkCreate({ name: 'myBeforeBulkCreateHook' }) + static beforeBulkCreateHookWithName(instances: Hook[], options: any): void {} + + @AfterBulkCreate({ name: 'myAfterBulkCreateHook' }) + static afterBulkCreateHookWithName(instances: Hook[], options: any): void {} + + @BeforeBulkDestroy({ name: 'myBeforeBulkDestroyHook' }) + static beforeBulkDestroyHookWithName(options: any): void {} + + @BeforeBulkDelete({name: 'myBeforeBulkDeleteHook' }) + static beforeBulkDeleteHookWithName(options: any): void {} + + @AfterBulkDestroy({ name: 'myAfterBulkDestroyHook' }) + static afterBulkDestroyHookWithName(options: any): void {} + + @AfterBulkDelete({ name: 'myAfterBulkDeleteHook' }) + static afterBulkDeleteHookWithName(options: any): void {} + + @BeforeBulkRestore({ name: 'myBeforeBulkRestoreHook' }) + static beforeBulkRestoreHookWithName(options: any): void {} + + @AfterBulkRestore({ name: 'myAfterBulkRestoreHook' }) + static afterBulkRestoreHookWithName(options: any): void {} + + @BeforeBulkUpdate({ name: 'myBeforeBulkUpdateHook' }) + static beforeBulkUpdateHookWithName(options: any): void {} + + @AfterBulkUpdate({ name: 'myAfterBulkUpdateHook' }) + static afterBulkUpdateHookWithName(options: any): void {} + + @BeforeFind({ name: 'myBeforeFindHook' }) + static beforeFindHookWithName(options: any): void {} + + @BeforeFindAfterExpandIncludeAll({ name: 'myBeforeFindAfterExpandIncludeAllHook' }) + static beforeFindAfterExpandIncludeAllHookWithName(options: any): void {} + + @BeforeFindAfterOptions({ name: 'myBeforeFindAfterOptionsHook' }) + static beforeFindAfterOptionsHookWithName(options: any): void {} + + @AfterFind({ name: 'myAfterFindHook' }) + static afterFindHookWithName(options: any): void {} + + @BeforeCount({ name: 'myBeforeCountHook' }) + static beforeCountHookWithName(options: any): void {} +} diff --git a/test/specs/hooks/hooks.spec.ts b/test/specs/hooks/hooks.spec.ts new file mode 100644 index 00000000..e9f12878 --- /dev/null +++ b/test/specs/hooks/hooks.spec.ts @@ -0,0 +1,266 @@ +import * as OriginSequelize from 'sequelize'; +import * as chai from 'chai'; +import * as sinon from 'sinon'; +import * as sinonChai from 'sinon-chai'; + +import { BeforeCreate, Sequelize } from "../../../index"; +import { Column, Model, Table } from "../../../index"; + +import { Hook } from "../../models/Hook"; +import { createSequelize } from "../../utils/sequelize"; + +const expect = chai.expect; +chai.use(sinonChai); + +describe('hook', () => { + const sequelize: Sequelize = createSequelize(false); + + before(() => { + + }); + + beforeEach(() => { + + return sequelize.sync({force: true}); + }); + + it('should throw on non-static hooks', () => { + expect(() => { + @Table + class User extends Model { + + @Column + firstName: string; + + @Column + lastName: string; + + @BeforeCreate + nonStaticHookFunction(): void {} + } + }).to.throw(Error, /not a static method/); + }); + + it('should throw on methods with reserved names', () => { + expect(() => { + // tslint:disable-next-line:max-classes-per-file + @Table + class User extends Model { + + @Column + firstName: string; + + @Column + lastName: string; + + @BeforeCreate + static beforeCreate(): void {} + } + }).to.throw(Error, /name is reserved/); + }); + + it('should install all hooks', () => { + const beforeValidateHookStub = sinon.stub(Hook, 'beforeValidateHook'); + const afterValidateHookStub = sinon.stub(Hook, 'afterValidateHook'); + const validationFailedHookStub = sinon.stub(Hook, 'validationFailedHook'); + const beforeCreateHookStub = sinon.stub(Hook, 'beforeCreateHook'); + const afterCreateHookStub = sinon.stub(Hook, 'afterCreateHook'); + const beforeDestroyHookStub = sinon.stub(Hook, 'beforeDestroyHook'); + const afterDestroyHookStub = sinon.stub(Hook, 'afterDestroyHook'); + const beforeRestoreHookStub = sinon.stub(Hook, 'beforeRestoreHook'); + const afterRestoreHookStub = sinon.stub(Hook, 'afterRestoreHook'); + const beforeUpdateHookStub = sinon.stub(Hook, 'beforeUpdateHook'); + const afterUpdateHookStub = sinon.stub(Hook, 'afterUpdateHook'); + const beforeBulkCreateHookStub = sinon.stub(Hook, 'beforeBulkCreateHook'); + const afterBulkCreateHookStub = sinon.stub(Hook, 'afterBulkCreateHook'); + const beforeBulkDestroyHookStub = sinon.stub(Hook, 'beforeBulkDestroyHook'); + const afterBulkDestroyHookStub = sinon.stub(Hook, 'afterBulkDestroyHook'); + const beforeBulkRestoreHookStub = sinon.stub(Hook, 'beforeBulkRestoreHook'); + const afterBulkRestoreHookStub = sinon.stub(Hook, 'afterBulkRestoreHook'); + const beforeBulkUpdateHookStub = sinon.stub(Hook, 'beforeBulkUpdateHook'); + const afterBulkUpdateHookStub = sinon.stub(Hook, 'afterBulkUpdateHook'); + const beforeFindHookStub = sinon.stub(Hook, 'beforeFindHook'); + const beforeFindAfterExpandIncludeAllHookStub = sinon.stub(Hook, 'beforeFindAfterExpandIncludeAllHook'); + const beforeFindAfterOptionsHookStub = sinon.stub(Hook, 'beforeFindAfterOptionsHook'); + const afterFindHookStub = sinon.stub(Hook, 'afterFindHook'); + const beforeCountHookStub = sinon.stub(Hook, 'beforeCountHook'); + + // these hooks are aliases for the equivalent “destroy” hooks + const beforeDeleteHookStub = sinon.stub(Hook, 'beforeDeleteHook'); + const afterDeleteHookStub = sinon.stub(Hook, 'afterDeleteHook'); + const beforeBulkDeleteHookStub = sinon.stub(Hook, 'beforeBulkDeleteHook'); + const afterBulkDeleteHookStub = sinon.stub(Hook, 'afterBulkDeleteHook'); + + // some hooks are only available in Sequelize v4 + let beforeSaveHookStub: sinon.SinonStub; + let afterSaveHookStub: sinon.SinonStub; + let beforeUpsertHookStub: sinon.SinonStub; + let afterUpsertHookStub: sinon.SinonStub; + if (OriginSequelize['version'].split('.')[0] === '4') { + beforeSaveHookStub = sinon.stub(Hook, 'beforeSaveHook'); + afterSaveHookStub = sinon.stub(Hook, 'afterSaveHook'); + beforeUpsertHookStub = sinon.stub(Hook, 'beforeUpsertHook'); + afterUpsertHookStub = sinon.stub(Hook, 'afterUpsertHook'); + } + + const beforeValidateHookWithNameStub = sinon.stub(Hook, 'beforeValidateHookWithName'); + const afterValidateHookWithNameStub = sinon.stub(Hook, 'afterValidateHookWithName'); + const validationFailedHookWithNameStub = sinon.stub(Hook, 'validationFailedHookWithName'); + const beforeCreateHookWithNameStub = sinon.stub(Hook, 'beforeCreateHookWithName'); + const afterCreateHookWithNameStub = sinon.stub(Hook, 'afterCreateHookWithName'); + const beforeDestroyHookWithNameStub = sinon.stub(Hook, 'beforeDestroyHookWithName'); + const afterDestroyHookWithNameStub = sinon.stub(Hook, 'afterDestroyHookWithName'); + const beforeRestoreHookWithNameStub = sinon.stub(Hook, 'beforeRestoreHookWithName'); + const afterRestoreHookWithNameStub = sinon.stub(Hook, 'afterRestoreHookWithName'); + const beforeUpdateHookWithNameStub = sinon.stub(Hook, 'beforeUpdateHookWithName'); + const afterUpdateHookWithNameStub = sinon.stub(Hook, 'afterUpdateHookWithName'); + const beforeBulkCreateHookWithNameStub = sinon.stub(Hook, 'beforeBulkCreateHookWithName'); + const afterBulkCreateHookWithNameStub = sinon.stub(Hook, 'afterBulkCreateHookWithName'); + const beforeBulkDestroyHookWithNameStub = sinon.stub(Hook, 'beforeBulkDestroyHookWithName'); + const afterBulkDestroyHookWithNameStub = sinon.stub(Hook, 'afterBulkDestroyHookWithName'); + const beforeBulkRestoreHookWithNameStub = sinon.stub(Hook, 'beforeBulkRestoreHookWithName'); + const afterBulkRestoreHookWithNameStub = sinon.stub(Hook, 'afterBulkRestoreHookWithName'); + const beforeBulkUpdateHookWithNameStub = sinon.stub(Hook, 'beforeBulkUpdateHookWithName'); + const afterBulkUpdateHookWithNameStub = sinon.stub(Hook, 'afterBulkUpdateHookWithName'); + const beforeFindHookWithNameStub = sinon.stub(Hook, 'beforeFindHookWithName'); + const beforeFindAfterExpandIncludeAllHookWithNameStub = sinon.stub(Hook, 'beforeFindAfterExpandIncludeAllHookWithName'); + const beforeFindAfterOptionsHookWithNameStub = sinon.stub(Hook, 'beforeFindAfterOptionsHookWithName'); + const afterFindHookWithNameStub = sinon.stub(Hook, 'afterFindHookWithName'); + const beforeCountHookWithNameStub = sinon.stub(Hook, 'beforeCountHookWithName'); + + // these hooks are aliases for the equivalent “destroy” hooks + const beforeDeleteHookWithNameStub = sinon.stub(Hook, 'beforeDeleteHookWithName'); + const afterDeleteHookWithNameStub = sinon.stub(Hook, 'afterDeleteHookWithName'); + const beforeBulkDeleteHookWithNameStub = sinon.stub(Hook, 'beforeBulkDeleteHookWithName'); + const afterBulkDeleteHookWithNameStub = sinon.stub(Hook, 'afterBulkDeleteHookWithName'); + + // some hooks are only available in Sequelize v4 + let beforeSaveHookWithNameStub: sinon.SinonStub; + let afterSaveHookWithNameStub: sinon.SinonStub; + let beforeUpsertHookWithNameStub: sinon.SinonStub; + let afterUpsertHookWithNameStub: sinon.SinonStub; + if (OriginSequelize['version'].split('.')[0] === '4') { + beforeSaveHookWithNameStub = sinon.stub(Hook, 'beforeSaveHookWithName'); + afterSaveHookWithNameStub = sinon.stub(Hook, 'afterSaveHookWithName'); + beforeUpsertHookWithNameStub = sinon.stub(Hook, 'beforeUpsertHookWithName'); + afterUpsertHookWithNameStub = sinon.stub(Hook, 'afterUpsertHookWithName'); + } + + sequelize.addModels([Hook]); + + // Sequelize provides no public API to retrieve existing hooks. We are relying on an + // implementation detail: that the addHook method works by adding the specified + // function to the Model’s options.hooks object. + // + // We are not testing that the hooks are called: that’s in Sequelize’s domain. Our job + // is to ensure that the hooks are installed. + + expect(Hook['options'].hooks['beforeValidate']).to.include(beforeValidateHookStub); + expect(Hook['options'].hooks['afterValidate']).to.include(afterValidateHookStub); + expect(Hook['options'].hooks['validationFailed']).to.include(validationFailedHookStub); + expect(Hook['options'].hooks['beforeCreate']).to.include(beforeCreateHookStub); + expect(Hook['options'].hooks['afterCreate']).to.include(afterCreateHookStub); + expect(Hook['options'].hooks['beforeDestroy']).to.include(beforeDestroyHookStub); + expect(Hook['options'].hooks['afterDestroy']).to.include(afterDestroyHookStub); + expect(Hook['options'].hooks['beforeRestore']).to.include(beforeRestoreHookStub); + expect(Hook['options'].hooks['afterRestore']).to.include(afterRestoreHookStub); + expect(Hook['options'].hooks['beforeUpdate']).to.include(beforeUpdateHookStub); + expect(Hook['options'].hooks['afterUpdate']).to.include(afterUpdateHookStub); + expect(Hook['options'].hooks['beforeBulkCreate']).to.include(beforeBulkCreateHookStub); + expect(Hook['options'].hooks['afterBulkCreate']).to.include(afterBulkCreateHookStub); + expect(Hook['options'].hooks['beforeBulkDestroy']).to.include(beforeBulkDestroyHookStub); + expect(Hook['options'].hooks['afterBulkDestroy']).to.include(afterBulkDestroyHookStub); + expect(Hook['options'].hooks['beforeBulkRestore']).to.include(beforeBulkRestoreHookStub); + expect(Hook['options'].hooks['afterBulkRestore']).to.include(afterBulkRestoreHookStub); + expect(Hook['options'].hooks['beforeBulkUpdate']).to.include(beforeBulkUpdateHookStub); + expect(Hook['options'].hooks['afterBulkUpdate']).to.include(afterBulkUpdateHookStub); + expect(Hook['options'].hooks['beforeFind']).to.include(beforeFindHookStub); + expect(Hook['options'].hooks['beforeFindAfterExpandIncludeAll']).to.include(beforeFindAfterExpandIncludeAllHookStub); + expect(Hook['options'].hooks['beforeFindAfterOptions']).to.include(beforeFindAfterOptionsHookStub); + expect(Hook['options'].hooks['afterFind']).to.include(afterFindHookStub); + expect(Hook['options'].hooks['beforeCount']).to.include(beforeCountHookStub); + + expect(Hook['options'].hooks['beforeDestroy']).to.include(beforeDeleteHookStub); + expect(Hook['options'].hooks['afterDestroy']).to.include(afterDeleteHookStub); + expect(Hook['options'].hooks['beforeBulkDestroy']).to.include(beforeBulkDeleteHookStub); + expect(Hook['options'].hooks['afterBulkDestroy']).to.include(afterBulkDeleteHookStub); + + if (OriginSequelize['version'].split('.')[0] === '4') { + expect(Hook['options'].hooks['beforeSave']).to.include(beforeSaveHookStub); + expect(Hook['options'].hooks['afterSave']).to.include(afterSaveHookStub); + expect(Hook['options'].hooks['beforeUpsert']).to.include(beforeUpsertHookStub); + expect(Hook['options'].hooks['afterUpsert']).to.include(afterUpsertHookStub); + } + + // Named hooks + + expect(Hook['options'].hooks['beforeValidate']) + .to.include({ name: 'myBeforeValidateHook', fn: beforeValidateHookWithNameStub }); + expect(Hook['options'].hooks['afterValidate']) + .to.include({ name: 'myAfterValidateHook', fn: afterValidateHookWithNameStub }); + expect(Hook['options'].hooks['validationFailed']) + .to.include({ name: 'myValidationFailedHook', fn: validationFailedHookWithNameStub }); + expect(Hook['options'].hooks['beforeCreate']) + .to.include({ name: 'myBeforeCreateHook', fn: beforeCreateHookWithNameStub }); + expect(Hook['options'].hooks['afterCreate']) + .to.include({ name: 'myAfterCreateHook', fn: afterCreateHookWithNameStub }); + expect(Hook['options'].hooks['beforeDestroy']) + .to.include({ name: 'myBeforeDestroyHook', fn: beforeDestroyHookWithNameStub }); + expect(Hook['options'].hooks['afterDestroy']) + .to.include({ name: 'myAfterDestroyHook', fn: afterDestroyHookWithNameStub }); + expect(Hook['options'].hooks['beforeRestore']) + .to.include({ name: 'myBeforeRestoreHook', fn: beforeRestoreHookWithNameStub }); + expect(Hook['options'].hooks['afterRestore']) + .to.include({ name: 'myAfterRestoreHook', fn: afterRestoreHookWithNameStub }); + expect(Hook['options'].hooks['beforeUpdate']) + .to.include({ name: 'myBeforeUpdateHook', fn: beforeUpdateHookWithNameStub }); + expect(Hook['options'].hooks['afterUpdate']) + .to.include({ name: 'myAfterUpdateHook', fn: afterUpdateHookWithNameStub }); + expect(Hook['options'].hooks['beforeBulkCreate']) + .to.include({ name: 'myBeforeBulkCreateHook', fn: beforeBulkCreateHookWithNameStub }); + expect(Hook['options'].hooks['afterBulkCreate']) + .to.include({ name: 'myAfterBulkCreateHook', fn: afterBulkCreateHookWithNameStub }); + expect(Hook['options'].hooks['beforeBulkDestroy']) + .to.include({ name: 'myBeforeBulkDestroyHook', fn: beforeBulkDestroyHookWithNameStub }); + expect(Hook['options'].hooks['afterBulkDestroy']) + .to.include({ name: 'myAfterBulkDestroyHook', fn: afterBulkDestroyHookWithNameStub }); + expect(Hook['options'].hooks['beforeBulkRestore']) + .to.include({ name: 'myBeforeBulkRestoreHook', fn: beforeBulkRestoreHookWithNameStub }); + expect(Hook['options'].hooks['afterBulkRestore']) + .to.include({ name: 'myAfterBulkRestoreHook', fn: afterBulkRestoreHookWithNameStub }); + expect(Hook['options'].hooks['beforeBulkUpdate']) + .to.include({ name: 'myBeforeBulkUpdateHook', fn: beforeBulkUpdateHookWithNameStub }); + expect(Hook['options'].hooks['afterBulkUpdate']) + .to.include({ name: 'myAfterBulkUpdateHook', fn: afterBulkUpdateHookWithNameStub }); + expect(Hook['options'].hooks['beforeFind']) + .to.include({ name: 'myBeforeFindHook', fn: beforeFindHookWithNameStub }); + expect(Hook['options'].hooks['beforeFindAfterExpandIncludeAll']) + .to.include({ name: 'myBeforeFindAfterExpandIncludeAllHook', fn: beforeFindAfterExpandIncludeAllHookWithNameStub }); + expect(Hook['options'].hooks['beforeFindAfterOptions']) + .to.include({ name: 'myBeforeFindAfterOptionsHook', fn: beforeFindAfterOptionsHookWithNameStub }); + expect(Hook['options'].hooks['afterFind']) + .to.include({ name: 'myAfterFindHook', fn: afterFindHookWithNameStub }); + expect(Hook['options'].hooks['beforeCount']) + .to.include({ name: 'myBeforeCountHook', fn: beforeCountHookWithNameStub }); + + expect(Hook['options'].hooks['beforeDestroy']) + .to.include({ name: 'myBeforeDeleteHook', fn: beforeDeleteHookWithNameStub }); + expect(Hook['options'].hooks['afterDestroy']) + .to.include({ name: 'myAfterDeleteHook', fn: afterDeleteHookWithNameStub }); + expect(Hook['options'].hooks['beforeBulkDestroy']) + .to.include({ name: 'myBeforeBulkDeleteHook', fn: beforeBulkDeleteHookWithNameStub }); + expect(Hook['options'].hooks['afterBulkDestroy']) + .to.include({ name: 'myAfterBulkDeleteHook', fn: afterBulkDeleteHookWithNameStub }); + + if (OriginSequelize['version'].split('.')[0] === '4') { + expect(Hook['options'].hooks['beforeSave']) + .to.include({ name: 'myBeforeSaveHook', fn: beforeSaveHookWithNameStub }); + expect(Hook['options'].hooks['afterSave']) + .to.include({ name: 'myAfterSaveHook', fn: afterSaveHookWithNameStub }); + expect(Hook['options'].hooks['beforeUpsert']) + .to.include({ name: 'myBeforeUpsertHook', fn: beforeUpsertHookWithNameStub }); + expect(Hook['options'].hooks['afterUpsert']) + .to.include({ name: 'myAfterUpsertHook', fn: afterUpsertHookWithNameStub }); + } + }); +}); From 610729ed7810f4992ed94e44c02c6d024507c99e Mon Sep 17 00:00:00 2001 From: Nate Silva Date: Mon, 14 Aug 2017 16:12:25 -0700 Subject: [PATCH 2/3] remove unused function --- test/specs/hooks/hooks.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/specs/hooks/hooks.spec.ts b/test/specs/hooks/hooks.spec.ts index e9f12878..cdd4030a 100644 --- a/test/specs/hooks/hooks.spec.ts +++ b/test/specs/hooks/hooks.spec.ts @@ -15,10 +15,6 @@ chai.use(sinonChai); describe('hook', () => { const sequelize: Sequelize = createSequelize(false); - before(() => { - - }); - beforeEach(() => { return sequelize.sync({force: true}); From 2fa0702b7ea53eb8ddadf8ae1af9d01bf115e6e3 Mon Sep 17 00:00:00 2001 From: Nate Silva Date: Thu, 17 Aug 2017 09:59:56 -0700 Subject: [PATCH 3/3] re-factor hook decorator implementation --- lib/annotations/hooks/AfterBulkCreate.ts | 17 ++------------ lib/annotations/hooks/AfterBulkDelete.ts | 17 ++------------ lib/annotations/hooks/AfterBulkDestroy.ts | 17 ++------------ lib/annotations/hooks/AfterBulkRestore.ts | 17 ++------------ lib/annotations/hooks/AfterBulkSync.ts | 8 +++++++ lib/annotations/hooks/AfterBulkUpdate.ts | 17 ++------------ lib/annotations/hooks/AfterConnect.ts | 8 +++++++ lib/annotations/hooks/AfterCreate.ts | 17 ++------------ lib/annotations/hooks/AfterDefine.ts | 8 +++++++ lib/annotations/hooks/AfterDelete.ts | 17 ++------------ lib/annotations/hooks/AfterDestroy.ts | 17 ++------------ lib/annotations/hooks/AfterFind.ts | 17 ++------------ lib/annotations/hooks/AfterInit.ts | 8 +++++++ lib/annotations/hooks/AfterRestore.ts | 17 ++------------ lib/annotations/hooks/AfterSave.ts | 17 ++------------ lib/annotations/hooks/AfterSync.ts | 8 +++++++ lib/annotations/hooks/AfterUpdate.ts | 17 ++------------ lib/annotations/hooks/AfterUpsert.ts | 17 ++------------ lib/annotations/hooks/AfterValidate.ts | 17 ++------------ lib/annotations/hooks/BeforeBulkCreate.ts | 17 ++------------ lib/annotations/hooks/BeforeBulkDelete.ts | 17 ++------------ lib/annotations/hooks/BeforeBulkDestroy.ts | 17 ++------------ lib/annotations/hooks/BeforeBulkRestore.ts | 17 ++------------ lib/annotations/hooks/BeforeBulkSync.ts | 8 +++++++ lib/annotations/hooks/BeforeBulkUpdate.ts | 17 ++------------ lib/annotations/hooks/BeforeConnect.ts | 8 +++++++ lib/annotations/hooks/BeforeCount.ts | 17 ++------------ lib/annotations/hooks/BeforeCreate.ts | 17 ++------------ lib/annotations/hooks/BeforeDefine.ts | 8 +++++++ lib/annotations/hooks/BeforeDelete.ts | 17 ++------------ lib/annotations/hooks/BeforeDestroy.ts | 17 ++------------ lib/annotations/hooks/BeforeFind.ts | 17 ++------------ .../hooks/BeforeFindAfterExpandIncludeAll.ts | 17 ++------------ .../hooks/BeforeFindAfterOptions.ts | 17 ++------------ lib/annotations/hooks/BeforeInit.ts | 8 +++++++ lib/annotations/hooks/BeforeRestore.ts | 17 ++------------ lib/annotations/hooks/BeforeSave.ts | 17 ++------------ lib/annotations/hooks/BeforeSync.ts | 8 +++++++ lib/annotations/hooks/BeforeUpdate.ts | 17 ++------------ lib/annotations/hooks/BeforeUpsert.ts | 17 ++------------ lib/annotations/hooks/BeforeValidate.ts | 17 ++------------ lib/annotations/hooks/ValidationFailed.ts | 17 ++------------ lib/services/hooks.ts | 23 +++++++++++++++++++ 43 files changed, 167 insertions(+), 480 deletions(-) create mode 100644 lib/annotations/hooks/AfterBulkSync.ts create mode 100644 lib/annotations/hooks/AfterConnect.ts create mode 100644 lib/annotations/hooks/AfterDefine.ts create mode 100644 lib/annotations/hooks/AfterInit.ts create mode 100644 lib/annotations/hooks/AfterSync.ts create mode 100644 lib/annotations/hooks/BeforeBulkSync.ts create mode 100644 lib/annotations/hooks/BeforeConnect.ts create mode 100644 lib/annotations/hooks/BeforeDefine.ts create mode 100644 lib/annotations/hooks/BeforeInit.ts create mode 100644 lib/annotations/hooks/BeforeSync.ts diff --git a/lib/annotations/hooks/AfterBulkCreate.ts b/lib/annotations/hooks/AfterBulkCreate.ts index 79a3be4e..50cf80d8 100644 --- a/lib/annotations/hooks/AfterBulkCreate.ts +++ b/lib/annotations/hooks/AfterBulkCreate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterBulkCreate(target: any, propertyName: string): void; export function AfterBulkCreate(options: IHookOptions): Function; export function AfterBulkCreate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterBulkCreate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterBulkCreate', propertyName); - } + return implementHookDecorator('afterBulkCreate', args); } diff --git a/lib/annotations/hooks/AfterBulkDelete.ts b/lib/annotations/hooks/AfterBulkDelete.ts index e0b14c59..2d151121 100644 --- a/lib/annotations/hooks/AfterBulkDelete.ts +++ b/lib/annotations/hooks/AfterBulkDelete.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterBulkDelete(target: any, propertyName: string): void; export function AfterBulkDelete(options: IHookOptions): Function; export function AfterBulkDelete(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterBulkDelete', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterBulkDelete', propertyName); - } + return implementHookDecorator('afterBulkDelete', args); } diff --git a/lib/annotations/hooks/AfterBulkDestroy.ts b/lib/annotations/hooks/AfterBulkDestroy.ts index 724fc9d6..efdde0a3 100644 --- a/lib/annotations/hooks/AfterBulkDestroy.ts +++ b/lib/annotations/hooks/AfterBulkDestroy.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterBulkDestroy(target: any, propertyName: string): void; export function AfterBulkDestroy(options: IHookOptions): Function; export function AfterBulkDestroy(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterBulkDestroy', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterBulkDestroy', propertyName); - } + return implementHookDecorator('afterBulkDestroy', args); } diff --git a/lib/annotations/hooks/AfterBulkRestore.ts b/lib/annotations/hooks/AfterBulkRestore.ts index 706b7767..1d0869c6 100644 --- a/lib/annotations/hooks/AfterBulkRestore.ts +++ b/lib/annotations/hooks/AfterBulkRestore.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterBulkRestore(target: any, propertyName: string): void; export function AfterBulkRestore(options: IHookOptions): Function; export function AfterBulkRestore(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterBulkRestore', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterBulkRestore', propertyName); - } + return implementHookDecorator('afterBulkRestore', args); } diff --git a/lib/annotations/hooks/AfterBulkSync.ts b/lib/annotations/hooks/AfterBulkSync.ts new file mode 100644 index 00000000..16699660 --- /dev/null +++ b/lib/annotations/hooks/AfterBulkSync.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function AfterBulkSync(target: any, propertyName: string): void; +export function AfterBulkSync(options: IHookOptions): Function; +export function AfterBulkSync(...args: any[]): void|Function { + return implementHookDecorator('afterBulkSync', args); +} diff --git a/lib/annotations/hooks/AfterBulkUpdate.ts b/lib/annotations/hooks/AfterBulkUpdate.ts index 770374b7..2cb08b06 100644 --- a/lib/annotations/hooks/AfterBulkUpdate.ts +++ b/lib/annotations/hooks/AfterBulkUpdate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterBulkUpdate(target: any, propertyName: string): void; export function AfterBulkUpdate(options: IHookOptions): Function; export function AfterBulkUpdate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterBulkUpdate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterBulkUpdate', propertyName); - } + return implementHookDecorator('afterBulkUpdate', args); } diff --git a/lib/annotations/hooks/AfterConnect.ts b/lib/annotations/hooks/AfterConnect.ts new file mode 100644 index 00000000..e956ac1a --- /dev/null +++ b/lib/annotations/hooks/AfterConnect.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function AfterConnect(target: any, propertyName: string): void; +export function AfterConnect(options: IHookOptions): Function; +export function AfterConnect(...args: any[]): void|Function { + return implementHookDecorator('afterConnect', args); +} diff --git a/lib/annotations/hooks/AfterCreate.ts b/lib/annotations/hooks/AfterCreate.ts index 1815a5b7..0b541260 100644 --- a/lib/annotations/hooks/AfterCreate.ts +++ b/lib/annotations/hooks/AfterCreate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterCreate(target: any, propertyName: string): void; export function AfterCreate(options: IHookOptions): Function; export function AfterCreate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterCreate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterCreate', propertyName); - } + return implementHookDecorator('afterCreate', args); } diff --git a/lib/annotations/hooks/AfterDefine.ts b/lib/annotations/hooks/AfterDefine.ts new file mode 100644 index 00000000..1c306f35 --- /dev/null +++ b/lib/annotations/hooks/AfterDefine.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function AfterDefine(target: any, propertyName: string): void; +export function AfterDefine(options: IHookOptions): Function; +export function AfterDefine(...args: any[]): void|Function { + return implementHookDecorator('afterDefine', args); +} diff --git a/lib/annotations/hooks/AfterDelete.ts b/lib/annotations/hooks/AfterDelete.ts index ebb58e02..dac29b2c 100644 --- a/lib/annotations/hooks/AfterDelete.ts +++ b/lib/annotations/hooks/AfterDelete.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterDelete(target: any, propertyName: string): void; export function AfterDelete(options: IHookOptions): Function; export function AfterDelete(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterDelete', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterDelete', propertyName); - } + return implementHookDecorator('afterDelete', args); } diff --git a/lib/annotations/hooks/AfterDestroy.ts b/lib/annotations/hooks/AfterDestroy.ts index 3ea6e59d..503cef72 100644 --- a/lib/annotations/hooks/AfterDestroy.ts +++ b/lib/annotations/hooks/AfterDestroy.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterDestroy(target: any, propertyName: string): void; export function AfterDestroy(options: IHookOptions): Function; export function AfterDestroy(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterDestroy', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterDestroy', propertyName); - } + return implementHookDecorator('afterDestroy', args); } diff --git a/lib/annotations/hooks/AfterFind.ts b/lib/annotations/hooks/AfterFind.ts index 332ce6b3..6bd0c824 100644 --- a/lib/annotations/hooks/AfterFind.ts +++ b/lib/annotations/hooks/AfterFind.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterFind(target: any, propertyName: string): void; export function AfterFind(options: IHookOptions): Function; export function AfterFind(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterFind', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterFind', propertyName); - } + return implementHookDecorator('afterFind', args); } diff --git a/lib/annotations/hooks/AfterInit.ts b/lib/annotations/hooks/AfterInit.ts new file mode 100644 index 00000000..34796ccf --- /dev/null +++ b/lib/annotations/hooks/AfterInit.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function AfterInit(target: any, propertyName: string): void; +export function AfterInit(options: IHookOptions): Function; +export function AfterInit(...args: any[]): void|Function { + return implementHookDecorator('afterInit', args); +} diff --git a/lib/annotations/hooks/AfterRestore.ts b/lib/annotations/hooks/AfterRestore.ts index 2cf844c8..6a63e49e 100644 --- a/lib/annotations/hooks/AfterRestore.ts +++ b/lib/annotations/hooks/AfterRestore.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterRestore(target: any, propertyName: string): void; export function AfterRestore(options: IHookOptions): Function; export function AfterRestore(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterRestore', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterRestore', propertyName); - } + return implementHookDecorator('afterRestore', args); } diff --git a/lib/annotations/hooks/AfterSave.ts b/lib/annotations/hooks/AfterSave.ts index cd788e19..fb1fa9ff 100644 --- a/lib/annotations/hooks/AfterSave.ts +++ b/lib/annotations/hooks/AfterSave.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterSave(target: any, propertyName: string): void; export function AfterSave(options: IHookOptions): Function; export function AfterSave(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterSave', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterSave', propertyName); - } + return implementHookDecorator('afterSave', args); } diff --git a/lib/annotations/hooks/AfterSync.ts b/lib/annotations/hooks/AfterSync.ts new file mode 100644 index 00000000..7967da2b --- /dev/null +++ b/lib/annotations/hooks/AfterSync.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function AfterSync(target: any, propertyName: string): void; +export function AfterSync(options: IHookOptions): Function; +export function AfterSync(...args: any[]): void|Function { + return implementHookDecorator('afterSync', args); +} diff --git a/lib/annotations/hooks/AfterUpdate.ts b/lib/annotations/hooks/AfterUpdate.ts index 26151310..1275215f 100644 --- a/lib/annotations/hooks/AfterUpdate.ts +++ b/lib/annotations/hooks/AfterUpdate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterUpdate(target: any, propertyName: string): void; export function AfterUpdate(options: IHookOptions): Function; export function AfterUpdate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterUpdate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterUpdate', propertyName); - } + return implementHookDecorator('afterUpdate', args); } diff --git a/lib/annotations/hooks/AfterUpsert.ts b/lib/annotations/hooks/AfterUpsert.ts index aa09bb3d..c5537476 100644 --- a/lib/annotations/hooks/AfterUpsert.ts +++ b/lib/annotations/hooks/AfterUpsert.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterUpsert(target: any, propertyName: string): void; export function AfterUpsert(options: IHookOptions): Function; export function AfterUpsert(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterUpsert', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterUpsert', propertyName); - } + return implementHookDecorator('afterUpsert', args); } diff --git a/lib/annotations/hooks/AfterValidate.ts b/lib/annotations/hooks/AfterValidate.ts index 72cb3ca6..552c9f19 100644 --- a/lib/annotations/hooks/AfterValidate.ts +++ b/lib/annotations/hooks/AfterValidate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function AfterValidate(target: any, propertyName: string): void; export function AfterValidate(options: IHookOptions): Function; export function AfterValidate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'afterValidate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'afterValidate', propertyName); - } + return implementHookDecorator('afterValidate', args); } diff --git a/lib/annotations/hooks/BeforeBulkCreate.ts b/lib/annotations/hooks/BeforeBulkCreate.ts index e192a225..9fa85763 100644 --- a/lib/annotations/hooks/BeforeBulkCreate.ts +++ b/lib/annotations/hooks/BeforeBulkCreate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeBulkCreate(target: any, propertyName: string): void; export function BeforeBulkCreate(options: IHookOptions): Function; export function BeforeBulkCreate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeBulkCreate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeBulkCreate', propertyName); - } + return implementHookDecorator('beforeBulkCreate', args); } diff --git a/lib/annotations/hooks/BeforeBulkDelete.ts b/lib/annotations/hooks/BeforeBulkDelete.ts index 4a85c25f..41c720a0 100644 --- a/lib/annotations/hooks/BeforeBulkDelete.ts +++ b/lib/annotations/hooks/BeforeBulkDelete.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeBulkDelete(target: any, propertyName: string): void; export function BeforeBulkDelete(options: IHookOptions): Function; export function BeforeBulkDelete(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeBulkDelete', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeBulkDelete', propertyName); - } + return implementHookDecorator('beforeBulkDelete', args); } diff --git a/lib/annotations/hooks/BeforeBulkDestroy.ts b/lib/annotations/hooks/BeforeBulkDestroy.ts index 4eed0afd..3a262b8c 100644 --- a/lib/annotations/hooks/BeforeBulkDestroy.ts +++ b/lib/annotations/hooks/BeforeBulkDestroy.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeBulkDestroy(target: any, propertyName: string): void; export function BeforeBulkDestroy(options: IHookOptions): Function; export function BeforeBulkDestroy(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeBulkDestroy', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeBulkDestroy', propertyName); - } + return implementHookDecorator('beforeBulkDestroy', args); } diff --git a/lib/annotations/hooks/BeforeBulkRestore.ts b/lib/annotations/hooks/BeforeBulkRestore.ts index 13096922..2851926d 100644 --- a/lib/annotations/hooks/BeforeBulkRestore.ts +++ b/lib/annotations/hooks/BeforeBulkRestore.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeBulkRestore(target: any, propertyName: string): void; export function BeforeBulkRestore(options: IHookOptions): Function; export function BeforeBulkRestore(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeBulkRestore', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeBulkRestore', propertyName); - } + return implementHookDecorator('beforeBulkRestore', args); } diff --git a/lib/annotations/hooks/BeforeBulkSync.ts b/lib/annotations/hooks/BeforeBulkSync.ts new file mode 100644 index 00000000..caa74d99 --- /dev/null +++ b/lib/annotations/hooks/BeforeBulkSync.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function BeforeBulkSync(target: any, propertyName: string): void; +export function BeforeBulkSync(options: IHookOptions): Function; +export function BeforeBulkSync(...args: any[]): void|Function { + return implementHookDecorator('beforeBulkSync', args); +} diff --git a/lib/annotations/hooks/BeforeBulkUpdate.ts b/lib/annotations/hooks/BeforeBulkUpdate.ts index 3ccf38e7..927534f3 100644 --- a/lib/annotations/hooks/BeforeBulkUpdate.ts +++ b/lib/annotations/hooks/BeforeBulkUpdate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeBulkUpdate(target: any, propertyName: string): void; export function BeforeBulkUpdate(options: IHookOptions): Function; export function BeforeBulkUpdate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeBulkUpdate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeBulkUpdate', propertyName); - } + return implementHookDecorator('beforeBulkUpdate', args); } diff --git a/lib/annotations/hooks/BeforeConnect.ts b/lib/annotations/hooks/BeforeConnect.ts new file mode 100644 index 00000000..106272c3 --- /dev/null +++ b/lib/annotations/hooks/BeforeConnect.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function BeforeConnect(target: any, propertyName: string): void; +export function BeforeConnect(options: IHookOptions): Function; +export function BeforeConnect(...args: any[]): void|Function { + return implementHookDecorator('beforeConnect', args); +} diff --git a/lib/annotations/hooks/BeforeCount.ts b/lib/annotations/hooks/BeforeCount.ts index fd0ec8f9..6311afc6 100644 --- a/lib/annotations/hooks/BeforeCount.ts +++ b/lib/annotations/hooks/BeforeCount.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeCount(target: any, propertyName: string): void; export function BeforeCount(options: IHookOptions): Function; export function BeforeCount(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeCount', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeCount', propertyName); - } + return implementHookDecorator('beforeCount', args); } diff --git a/lib/annotations/hooks/BeforeCreate.ts b/lib/annotations/hooks/BeforeCreate.ts index 1f762a3c..40adcfed 100644 --- a/lib/annotations/hooks/BeforeCreate.ts +++ b/lib/annotations/hooks/BeforeCreate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeCreate(target: any, propertyName: string): void; export function BeforeCreate(options: IHookOptions): Function; export function BeforeCreate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeCreate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeCreate', propertyName); - } + return implementHookDecorator('beforeCreate', args); } diff --git a/lib/annotations/hooks/BeforeDefine.ts b/lib/annotations/hooks/BeforeDefine.ts new file mode 100644 index 00000000..bbc8d71b --- /dev/null +++ b/lib/annotations/hooks/BeforeDefine.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function BeforeDefine(target: any, propertyName: string): void; +export function BeforeDefine(options: IHookOptions): Function; +export function BeforeDefine(...args: any[]): void|Function { + return implementHookDecorator('beforeDefine', args); +} diff --git a/lib/annotations/hooks/BeforeDelete.ts b/lib/annotations/hooks/BeforeDelete.ts index d73bf3bc..8677beff 100644 --- a/lib/annotations/hooks/BeforeDelete.ts +++ b/lib/annotations/hooks/BeforeDelete.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeDelete(target: any, propertyName: string): void; export function BeforeDelete(options: IHookOptions): Function; export function BeforeDelete(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeDelete', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeDelete', propertyName); - } + return implementHookDecorator('beforeDelete', args); } diff --git a/lib/annotations/hooks/BeforeDestroy.ts b/lib/annotations/hooks/BeforeDestroy.ts index dfa76e9f..9341cbae 100644 --- a/lib/annotations/hooks/BeforeDestroy.ts +++ b/lib/annotations/hooks/BeforeDestroy.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeDestroy(target: any, propertyName: string): void; export function BeforeDestroy(options: IHookOptions): Function; export function BeforeDestroy(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeDestroy', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeDestroy', propertyName); - } + return implementHookDecorator('beforeDestroy', args); } diff --git a/lib/annotations/hooks/BeforeFind.ts b/lib/annotations/hooks/BeforeFind.ts index 2ed36649..ebafb520 100644 --- a/lib/annotations/hooks/BeforeFind.ts +++ b/lib/annotations/hooks/BeforeFind.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeFind(target: any, propertyName: string): void; export function BeforeFind(options: IHookOptions): Function; export function BeforeFind(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeFind', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeFind', propertyName); - } + return implementHookDecorator('beforeFind', args); } diff --git a/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts b/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts index 1ac09b06..a741fe00 100644 --- a/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts +++ b/lib/annotations/hooks/BeforeFindAfterExpandIncludeAll.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeFindAfterExpandIncludeAll(target: any, propertyName: string): void; export function BeforeFindAfterExpandIncludeAll(options: IHookOptions): Function; export function BeforeFindAfterExpandIncludeAll(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeFindAfterExpandIncludeAll', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeFindAfterExpandIncludeAll', propertyName); - } + return implementHookDecorator('beforeFindAfterExpandIncludeAll', args); } diff --git a/lib/annotations/hooks/BeforeFindAfterOptions.ts b/lib/annotations/hooks/BeforeFindAfterOptions.ts index e7eb9f46..b32687f1 100644 --- a/lib/annotations/hooks/BeforeFindAfterOptions.ts +++ b/lib/annotations/hooks/BeforeFindAfterOptions.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeFindAfterOptions(target: any, propertyName: string): void; export function BeforeFindAfterOptions(options: IHookOptions): Function; export function BeforeFindAfterOptions(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeFindAfterOptions', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeFindAfterOptions', propertyName); - } + return implementHookDecorator('beforeFindAfterOptions', args); } diff --git a/lib/annotations/hooks/BeforeInit.ts b/lib/annotations/hooks/BeforeInit.ts new file mode 100644 index 00000000..db46a5b4 --- /dev/null +++ b/lib/annotations/hooks/BeforeInit.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function BeforeInit(target: any, propertyName: string): void; +export function BeforeInit(options: IHookOptions): Function; +export function BeforeInit(...args: any[]): void|Function { + return implementHookDecorator('beforeInit', args); +} diff --git a/lib/annotations/hooks/BeforeRestore.ts b/lib/annotations/hooks/BeforeRestore.ts index 12e3555f..aeab5fa6 100644 --- a/lib/annotations/hooks/BeforeRestore.ts +++ b/lib/annotations/hooks/BeforeRestore.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeRestore(target: any, propertyName: string): void; export function BeforeRestore(options: IHookOptions): Function; export function BeforeRestore(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeRestore', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeRestore', propertyName); - } + return implementHookDecorator('beforeRestore', args); } diff --git a/lib/annotations/hooks/BeforeSave.ts b/lib/annotations/hooks/BeforeSave.ts index b63d9311..3115d647 100644 --- a/lib/annotations/hooks/BeforeSave.ts +++ b/lib/annotations/hooks/BeforeSave.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeSave(target: any, propertyName: string): void; export function BeforeSave(options: IHookOptions): Function; export function BeforeSave(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeSave', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeSave', propertyName); - } + return implementHookDecorator('beforeSave', args); } diff --git a/lib/annotations/hooks/BeforeSync.ts b/lib/annotations/hooks/BeforeSync.ts new file mode 100644 index 00000000..9a1df733 --- /dev/null +++ b/lib/annotations/hooks/BeforeSync.ts @@ -0,0 +1,8 @@ +import {IHookOptions} from "../../interfaces/IHookOptions"; +import {implementHookDecorator} from "../../services/hooks"; + +export function BeforeSync(target: any, propertyName: string): void; +export function BeforeSync(options: IHookOptions): Function; +export function BeforeSync(...args: any[]): void|Function { + return implementHookDecorator('beforeSync', args); +} diff --git a/lib/annotations/hooks/BeforeUpdate.ts b/lib/annotations/hooks/BeforeUpdate.ts index 0b96ebe0..8bc54b4e 100644 --- a/lib/annotations/hooks/BeforeUpdate.ts +++ b/lib/annotations/hooks/BeforeUpdate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeUpdate(target: any, propertyName: string): void; export function BeforeUpdate(options: IHookOptions): Function; export function BeforeUpdate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeUpdate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeUpdate', propertyName); - } + return implementHookDecorator('beforeUpdate', args); } diff --git a/lib/annotations/hooks/BeforeUpsert.ts b/lib/annotations/hooks/BeforeUpsert.ts index 9e4bd255..3c653609 100644 --- a/lib/annotations/hooks/BeforeUpsert.ts +++ b/lib/annotations/hooks/BeforeUpsert.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeUpsert(target: any, propertyName: string): void; export function BeforeUpsert(options: IHookOptions): Function; export function BeforeUpsert(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeUpsert', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeUpsert', propertyName); - } + return implementHookDecorator('beforeUpsert', args); } diff --git a/lib/annotations/hooks/BeforeValidate.ts b/lib/annotations/hooks/BeforeValidate.ts index 5b59e418..3232a355 100644 --- a/lib/annotations/hooks/BeforeValidate.ts +++ b/lib/annotations/hooks/BeforeValidate.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function BeforeValidate(target: any, propertyName: string): void; export function BeforeValidate(options: IHookOptions): Function; export function BeforeValidate(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'beforeValidate', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'beforeValidate', propertyName); - } + return implementHookDecorator('beforeValidate', args); } diff --git a/lib/annotations/hooks/ValidationFailed.ts b/lib/annotations/hooks/ValidationFailed.ts index 731376ec..2bd60193 100644 --- a/lib/annotations/hooks/ValidationFailed.ts +++ b/lib/annotations/hooks/ValidationFailed.ts @@ -1,21 +1,8 @@ import {IHookOptions} from "../../interfaces/IHookOptions"; -import {addHook} from "../../services/hooks"; +import {implementHookDecorator} from "../../services/hooks"; export function ValidationFailed(target: any, propertyName: string): void; export function ValidationFailed(options: IHookOptions): Function; export function ValidationFailed(...args: any[]): void|Function { - - if (args.length === 1) { - - const options = args[0]; - - return (target: any, propertyName: string) => - addHook(target, 'validationFailed', propertyName, options); - } else { - - const target = args[0]; - const propertyName = args[1]; - - addHook(target, 'validationFailed', propertyName); - } + return implementHookDecorator('validationFailed', args); } diff --git a/lib/services/hooks.ts b/lib/services/hooks.ts index a2b42bfc..1725580c 100644 --- a/lib/services/hooks.ts +++ b/lib/services/hooks.ts @@ -20,9 +20,32 @@ export function installHooks(models: Array): void { }); } +/** + * Implementation for hook decorator functions. These are polymorphic. When + * called with a single argument (IHookOptions) they return a decorator + * factory function. When called with multiple arguments, they add the hook + * to the model’s metadata. + */ +export function implementHookDecorator(hookType: string, args: any[]): Function | void { + if (args.length === 1) { + + const options: IHookOptions = args[0]; + + return (target: any, propertyName: string) => + addHook(target, hookType, propertyName, options); + } else { + + const target = args[0]; + const propertyName = args[1]; + + addHook(target, hookType, propertyName); + } +} + /** * Adds hook meta data for specified model * @throws if applied to a non-static method + * @throws if the hook method name is reserved */ export function addHook(target: any, hookType: string, methodName: string, options: IHookOptions = {}): void { if (typeof target !== 'function') {