Aliheym / typeorm-transactional

A Transactional Method Decorator for TypeORM that uses Async Local Storage or cls-hooked to handle and propagate transactions between different repositories and service methods.
MIT License
201 stars 27 forks source link

Use runInTransaction within a controller #12

Closed 0biWanKenobi closed 1 year ago

0biWanKenobi commented 1 year ago

Hi, I'm considering your awesome package for a project, and I was wondering: can we use runInTransaction or in a controller? For example, we may have some UserService and UserController and we may want to run some service methods within the same transaction:


//UserService

@Transactional()
async getUser() {...}

@Transactional()
async updateUser(id: number, name: string) {...}

//UserController
...
constructor( private userService: UserService)
...
async updateUserName(id: number, name: string) {
    // would this work?
    withTransaction(() => {
        const user = await this.userService.getUser()
        if(user.name !== name)
            await this.userService.updateUser(id, name)
    }
}
Aliheym commented 1 year ago

Hi thanks for your issue.

If short, yes you can.

That's the purpose of this library to allow you to run transactions, without the need to use not convenient ways that TypeORM provides. We hide these details from user.

If you need to run some specific code in a transaction, you can wrap it in runInTransaction as in this example:

@Patch(':id')
  async updateEntity(@Param() { id }: GetEntityById, @Body() data: unknown) {
    const entity = await runInTransaction(async () => {
      const isEntityExists = await this.entityService.exists(id);

      if (isEntityExists) {
        throw new Error();
      }

      return this.entityService.updateEntity(data);
    });

    return entity;
  }

If an error is thrown somewhere inside runInTransaction, the transaction will rollback. Also, if you want to support more complicated use cases with nested transactions you can use transaction propagation.

Of course, you can do it everywhere, not just in the controllers.

Note, this is how the @Transactional decorator works under the hood, so if you want to run all the controller code in a transaction, you can just use this decorator.

0biWanKenobi commented 1 year ago

Hi, thank you so much for replying! One thing I'm not sure about: Is withTransaction all I need, or should I also have to decorate the service methods? From your reply, I'd think the decorator would not be needed, but I wanted to be sure 😁 Thanks for your patience!

Aliheym commented 1 year ago

You don't need to use decorator, if you want to use wrapInTransaction and runIntransaction.

Decorator is just for the "Nest-like" style, but you can use library without it.

0biWanKenobi commented 1 year ago

Thanks again for the clarification, I'm going to close the issue 😊