Search code examples
javascriptnode.jstypescriptnestjstypescript-decorator

Typescript method parameter decorator only evaluated at build time, is it possible to evaluate at request time? (nodejs+nestjs)


I'm trying to write a decorator to simplify my handling of mongodb calls with transaction and without transaction from a single service method, it would save me a ton of boilerplate if it would work.

Usage key points:

• there are various consumers of a service class which has a lot of methods that write to the database • each method must optionally allow the operations to be ran transactionally • can't provide {session: null/undefined} to mongodb's QueryOptions object as it will consider it a session and the update operation will fail

My simplified solution:

export function SetDbSession(opts?: QueryOptions): ParameterDecorator {
  return (target: QueryOptions, propertyKey: string): QueryOptions => {
    let options: QueryOptions = { ...opts };

    if (target.session) {
      options.session = target.session;
    }
    console.log("DECORATOR OPTIONS", options);
    return options;
  };
}

The idea is to have methods in my services that consume it as such:

  public async write_to_database(
    _id: string,
    data: IMyData
    @SetDbSession({ new: true }) opts?: QueryOptions,
  ): Promise<Raise> {
...

This way:

• if they don't provide a session at all, opts will still be defined and I don't have to define it again in each method • I set my basic opts for a query right in the decorator, overwriting provided opts (usually it's just new:true) • I enable the consumers of my service's method to provide additional opts, although rarely necessary

The issue that I'm having is:

• the decorator solely gets evaluated at runtime, that console.log() will appear there 1 single time during build time and then do absolutely nothing when a request comes in.

How can I make this decorator work for my use case? I know it's somewhat possible as NestJS already has a bunch of other decorators for controller methods that are configurable and do similar things.

Thank you.


Solution

  • Decorators are solely a start time construct. They are evaluated as top level functions and set the required metadata. You can read that metadata at runtime, which is what Nest does making it look like they are evaluated at request time, when in reality the metadata is just being read and acted upon.

    The only way I know of to make a decorator "active" at request time is for a method decorator to modify the method it is acting upon, which in my opinion, goes beyond the scope of what decorators are for.