clean-architecture-buckpal-rust icon indicating copy to clipboard operation
clean-architecture-buckpal-rust copied to clipboard

What about DB transactions?

Open frederikhors opened this issue 1 year ago • 3 comments

How are you dealing with DB transactions?

frederikhors avatar Feb 25 '24 11:02 frederikhors

Hi @frederikhors! Forgive me as it's been quite a while since I touched this repo.

There are ways with sqlx to deal with transactions I regularly dip into now in my professional work.

Here's one of their official examples: https://github.com/launchbadge/sqlx/blob/main/examples/postgres/transaction/src/main.rs

Can't quite remember what the source book did with transactions, but if you need to store / pass them around you might be able to do so with a generic that implements the Transaction trait. Maybe an Arc/Mutex to wrap it if that becomes necessary. What's your use case?

jayy-lmao avatar Feb 25 '24 22:02 jayy-lmao

Hi @jayy-lmao I'm talking about transactions across business usecases (the services layer): imagine "wallet" along with your existing "account".

Example:

  • move money from an account to another;

  • wait for each wallet during the transfer.

frederikhors avatar Feb 26 '24 11:02 frederikhors

So you would definitely need a Arc, Mutex, and an optional. You would need to be careful that you have not created a singleton, but rather a per-request.

Or you may be able to do this by making it an argument at either the service or repository layer, then passing around the tx object.

e.g.

impl AbstractWalletService for WalletService {
  fn check_wallet_balance(&self, tx: &mut Transaction<'_, Postgres>) -> anyhow::Result<bool> {
    todo!()
  }
}

Then in your handler or whichever you would do

let mut tx = db.pool.begin().await?;

let result = check_wallet_balance(&mut tx)?;

// further down once you've done all your operations
tx.commit()

Of course you may want to do this at a Service level instead, in which case it would just be the same thing with your repository functions.

Its worth being aware that you can also alternatively use the Executable trait as a trait bound if you wanted your functions to accept either a transaction or a regular pool reference.

jayy-lmao avatar Feb 27 '24 06:02 jayy-lmao