Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prisma Transactions Cross Modules

Problem

I was trying to implement a clean prisma transaction architecture with a DDD architecture. My problem is that i want to be able to perform transactions cross different modules without need to pass the prisma transaction client to each repository ie:

// repository layer
@injectable()
export class UserRepository{
  constructor(@inject(PrismaClient) private prisma: PrismaClient)

  save(user: IUser): Promise<User>{
     return this.prisma.user.create({data: user});
  }
}

@injectable()
export class OrderRepository{
  constructor(@inject(PrismaClient) private prisma: PrismaClient)
  
  save(order: IOrder): Promise<Order>{
    return this.prisma.order.create({data: order});
  }
}
// service layer
export class UserService{
  constructor(@inject(UserRepository) private userRepo: UserRepository)

  create(request: CreateUserRequest){
    return this.userRepo.save(request);
  }
}

export class OrderService{
  constructor(@inject(OrderRepository) private orderRepo: OrderRepository)
  
  create(request: CreateOrderRequest){
    return this.orderRepo.save(request);
  }
}
// controller layer
export UserController{
   constructor(
    @inject(UserService) private userService: UserService,
    @inject(OrderService) private orderService: OrderService
   ){}

  placeOrder(
    userRequest: CreateUserRequest,
    orderRequest: CreateOrderRequest
  ){
    // perform transaction, if any fails go with rollback
    // !THIS ACTUALLY DOESN'T WORK
    prisma.$transaction([
       await this.userService.create(userRequest),
       await this.orderService.create(orderRequest)
    ])
  }
}

I want to figure out a clean way to achieve this, has anyone faced a similar problem before?

Thank you all!

like image 722
mikrowdev Avatar asked Jul 18 '26 21:07

mikrowdev


1 Answers

Your UserRepository.save and OrderRepository.save, should return PrismaPromises instead of a Promise(https://www.prisma.io/docs/concepts/components/prisma-client/transactions#the-transaction-api)

Also, when you await the promise returned by UserRepository.save you are passing a User not a PrismaPromise<User> which the $transaction expects.

To fix it, fix the typing from the repositories methods as commented above and then you should be able to do a transaction by inverting the order on which you await:

await prisma.$transaction([
   this.userService.create(userRequest),
   this.orderService.create(orderRequest)
])
like image 161
Henke Avatar answered Jul 20 '26 20:07

Henke