Skip to content

A @Hook decorator would be great #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
natesilva opened this issue Aug 9, 2017 · 10 comments
Closed

A @Hook decorator would be great #88

natesilva opened this issue Aug 9, 2017 · 10 comments
Assignees

Comments

@natesilva
Copy link
Contributor

There are several ways to add hooks, but they need your Model to be added to a Sequelize instance first. It isn’t very declarative.

It would be great if there was a @Hook decorator. Something like:

@Table
class Book extends Model<Book> {
  // (bunch of @Columns etc.)

  @Hook('beforeCreate')
  static reticulateSplines(instance: Book) {
    // do beforeCreate hook stuff here
  }

  @Hook('afterDestroy')
  static herdLlamas(instance: Book) {
    // do afterDestroy hook stuff here
  }
}

Is this in the works? I could try to write something. The decorator would store information using the reflect-metadata system and then something like initializeHooks would be called from the addModels method.

@RobinBuschmann
Copy link
Member

@natesilva Currently there is no implementation of hook decorators in progress from my side. But yeah, sounds great. I would be pleased to see this implemented :)
But I would suggest to use @BeforeCreateHook or simply @BeforeCreate (and so on) instead of or at least in addition to the @Hook(...) decorator. Passing strings could lead to typos. @BeforeCreate is more type safe. What do you think?

@natesilva
Copy link
Contributor Author

I was thinking the argument to Hook(…) would be a string literal type, so it would be safe from typos — and I wouldn’t have to create ~20 named decorators. But having individual decorators is more in keeping with the existing style, especially the Hooks class functions. So let’s do a named decorator for each type of hook.

@RobinBuschmann
Copy link
Member

Perfect :) Can I assign this feature to you?

@natesilva
Copy link
Contributor Author

Yes.

natesilva added a commit to natesilva/sequelize-typescript that referenced this issue Aug 10, 2017
@natesilva
Copy link
Contributor Author

This works, but there are no tests yet. (yeah I know) Typical usage would be:

@Table
class Person extends Model<Person> {
  @Column
  name: string;

  @BeforeUpdate
  @BeforeCreate
  static capitalizeName(instance: Person) {
    instance.name = instance.name.toLocaleUpperCase();
  }

  @BeforeCreate
  static addUnicorn(instance: Person) {
    instance.name += ' 🦄';
  }
}

If a hook decorator is applied to a non-static method, an informative error will be thrown.

It’s possible to name a hook: @AfterDestroy({ name: 'myHook' }) and then you can remove it: Person.removeHook('afterDestroy', 'myHook'). However this doesn’t work correctly in all cases, still working on it.

@natesilva
Copy link
Contributor Author

The removeHook issue was a bug in Sequelize. sequelize/sequelize#8095

After tests are written I’ll submit this PR.

@RobinBuschmann
Copy link
Member

Looks great! 🎉

@chanlito
Copy link
Contributor

Hi do we really need to pass the instance? Can't it be just "this"?

@RobinBuschmann
Copy link
Member

The context of a static function is the reference to the class itself. Therefore this shouldn't be manipulated to be something else than Person in natesilva's example.

@natesilva
Copy link
Contributor Author

natesilva commented Aug 11, 2017

The arguments depend on which hook you are implementing. For some hooks Sequelize passes an instance, for others an array of instances (beforeBulkCreate), or no instance (beforeBulkDestroy). So it can’t be an instance method.

I can imagine a future enhancement where the subset of hooks that receive a single instance create a wrapper function to be the actual hook, which then calls a method on the instance -- allowing you to use this. But that’s well beyond what I’m doing here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants