I am writing a service that can make a transactional query, (in this question I will be using GORM)
UserService
type userService struct {
UserRepository repository.IUserRepository
TokenRepository repository.ITokenRepository
}
type IUserService interface {
WithTrx() IUserService
CommitTrx() error
RollbackTrx()
Create(ctx context.Context, name string) (*model.User, error)
...
...
}
here is some implementation of the service
user.go
func (s *userService) WithTrx() IUserService {
newService := &userService{
UserRepository: s.UserRepository.WithTrx(),
TokenRepository: s.TokenRepository,
}
return newService
}
func (s *userService) Create(ctx context.Context, name string) (*model.User, error) {
...
// s.UserRepository.Create()
// then return the user, error
...
}
and for the UserRepository.WithTrx() is basically just returning the interface itself
type psqlUserRepository struct {
DB *gorm.DB
}
type IUserRepository interface {
WithTrx() IUserRepository
CommitTrx() error
RollbackTrx()
Create(ctx context.Context, u model.User) (*model.User, error)
...
}
func (r *psqlUserRepository) WithTrx() IUserRepository {
return &psqlUserRepository{DB: r.DB.Begin()}
}
So when I need user service to create a user using transactional query, I just:
trx:= userserviceInstance.WithTrx()
user, err := trx.Create(ctx, name)
// err handling and rollback
commitErr := trx.CommitTrx()
Is there any similar approach like this? What is it called? I am not sure whether this is the right pattern to create a transactional query.