doobie icon indicating copy to clipboard operation
doobie copied to clipboard

Add syntactic sugar transactRaw to ConnectionIOOps

Open mertant opened this issue 8 months ago • 4 comments

ConnectionIOOps already has syntax for calling .transact(xa) on a query, which applies xa.trans, but there is no equivalent for xa.rawTrans.

See the doobie.util.transactor.Transactor#rawTrans method which already exists here:

modules/core/src/main/scala/doobie/util/transactor.scala#L147-L158

xa.rawTrans is useful when one does not want to use the Strategy, namely when we want to keep the autoCommit setting of the underlying DB connection instead of having Doobie override it to false, which it does by default. In other words, as the Doobie documentation puts it, "This can be useful in cases where transactional handling is unsupported or undesired".

Here, we add transactRaw as a new syntax in ConnectionIOOps, paralleling the existing transact, for the sake of convenience.

See the discussion here:

  • https://github.com/typelevel/doobie/issues/1244#issuecomment-2757961204

To keep feature parity with ConnectionIOOps, we also add OptionTConnectionIOOps, EitherTConnectionIOOps, KleisliConnectionIOOps) to keep their symmetry with ConnectionIOOps. However, note that these don't have unit tests. Also, could be made a bit more DRYDRY.

mertant avatar Apr 10 '25 13:04 mertant

Just to clarify, using transactRaw would be somewhat equivalent to

xa.copy(strategy0 = Strategy.void).transact

is it correct?

satorg avatar Apr 11 '25 03:04 satorg

would be somewhat equivalent to ... Strategy.void

Yes, I believe that's the intent - this PR does not add the implementation rawTrans, only a more convenient way to call it (just like we already have for the non-raw equivalent).

See the doobie.util.transactor.Transactor#rawTrans method which already exists here: https://github.com/typelevel/doobie/blob/23623fe78930c50b99e128e4c5d1c8afef1152d9/modules/core/src/main/scala/doobie/util/transactor.scala#L147-L158

So it does not apply Strategy.void, but skips applying any Strategy at all, which are expected to be equivalent.

See also this documentation https://github.com/typelevel/doobie/blob/23623fe78930c50b99e128e4c5d1c8afef1152d9/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md?plain=1#L27-L30

mertant avatar Apr 11 '25 09:04 mertant

As for xa.copy(strategy0 = Strategy.void), for performance reasons I would only execute the .copy once per transactor, not once for every .transact call, but yeah, I think it's basically just as you said.

With the lack of convenience for raw transactions currently, that is basically what we ended up doing in our project for now:

  /** A transactor with Doobie's default Strategy, which has a hidden gotcha:
    * it will set autoCommit=false if that's not already case on the Hikari connection from the pool!
    */
  val xa = ...

  /** A transactor with a "raw" Strategy, which is more like what one would expect, i.e.
    * it keeps autoCommit=true as we have set it on our Hikari pool!
    * TODO: Start using this everywhere, except if there's some place where we explicitly NEED autocommit to be false.
    */
  val xaRaw = xa.copy(strategy0 = Strategy.void)

mertant avatar Apr 11 '25 09:04 mertant

Looks reasonable to me, thanks for the clarification. Do you think it would make sense to add similar methods to StreamOps?

satorg avatar Apr 11 '25 15:04 satorg