From 03a749caefd7b263c310ca740ed6080dabad0d34 Mon Sep 17 00:00:00 2001 From: "Teo.Mertanen" Date: Thu, 10 Apr 2025 16:29:05 +0300 Subject: [PATCH 1/3] Add syntactic sugar transactRaw to ConnectionIOOps `ConnectionIOOps` already has syntax for calling `.transact(xa)` on a query, which applies `xa.trans`, but there is no equivalent for `xa.rawTrans`. `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](https://typelevel.org/doobie/docs/14-Managing-Connections.html#about-transactors), "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`. See the discussion here: - https://github.com/typelevel/doobie/issues/1244#issuecomment-2757961204 --- modules/core/src/main/scala/doobie/syntax/connectionio.scala | 2 ++ modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/core/src/main/scala/doobie/syntax/connectionio.scala b/modules/core/src/main/scala/doobie/syntax/connectionio.scala index c74255317..62678155d 100644 --- a/modules/core/src/main/scala/doobie/syntax/connectionio.scala +++ b/modules/core/src/main/scala/doobie/syntax/connectionio.scala @@ -14,6 +14,8 @@ import doobie.hi.{connection as IHC} class ConnectionIOOps[A](ma: ConnectionIO[A]) { def transact[M[_]: MonadCancelThrow](xa: Transactor[M]): M[A] = xa.trans.apply(ma) + + def transactRaw[M[_]: MonadCancelThrow](xa: Transactor[M]): M[A] = xa.rawTrans.apply(ma) } class OptionTConnectionIOOps[A](ma: OptionT[ConnectionIO, A]) { diff --git a/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala b/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala index 31f70f0f5..375a2b044 100644 --- a/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala +++ b/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala @@ -24,10 +24,12 @@ class ConnectionIOSuite extends munit.CatsEffectSuite { test("Semigroup ConnectionIO") { val prg = Applicative[ConnectionIO].pure(List(1, 2, 3)) `combine` Applicative[ConnectionIO].pure(List(4, 5, 6)) prg.transact(xa).assertEquals(List(1, 2, 3, 4, 5, 6)) + prg.transactRaw(xa).assertEquals(List(1, 2, 3, 4, 5, 6)) } test("Monoid ConnectionIO") { Monoid[ConnectionIO[List[Int]]].empty.transact(xa).assertEquals(Nil) + Monoid[ConnectionIO[List[Int]]].empty.transactRaw(xa).assertEquals(Nil) } } From fcc053e5032c3b00a87deb3a29450282b7df8f99 Mon Sep 17 00:00:00 2001 From: "Teo.Mertanen" Date: Thu, 10 Apr 2025 16:43:12 +0300 Subject: [PATCH 2/3] Also add transactRaw to other ConnectionIO Ops Should probably keep OptionTConnectionIOOps et al. have parity with ConnectionIOOps. The repetition here could be reduced, since now the two methods are the same other than for the one method call, but I'm struggling with naming the private method that they would share. --- .../src/main/scala/doobie/syntax/connectionio.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/core/src/main/scala/doobie/syntax/connectionio.scala b/modules/core/src/main/scala/doobie/syntax/connectionio.scala index 62678155d..705f80d15 100644 --- a/modules/core/src/main/scala/doobie/syntax/connectionio.scala +++ b/modules/core/src/main/scala/doobie/syntax/connectionio.scala @@ -23,6 +23,11 @@ class OptionTConnectionIOOps[A](ma: OptionT[ConnectionIO, A]) { OptionT( xa.trans.apply(ma.orElseF(IHC.rollback.as(None)).value) ) + + def transactRaw[M[_]: MonadCancelThrow](xa: Transactor[M]): OptionT[M, A] = + OptionT( + xa.rawTrans.apply(ma.orElseF(IHC.rollback.as(None)).value) + ) } class EitherTConnectionIOOps[E, A](ma: EitherT[ConnectionIO, E, A]) { @@ -30,11 +35,19 @@ class EitherTConnectionIOOps[E, A](ma: EitherT[ConnectionIO, E, A]) { EitherT( xa.trans.apply(ma.leftSemiflatMap(IHC.rollback.as(_)).value) ) + + def transactRaw[M[_]: MonadCancelThrow](xa: Transactor[M]): EitherT[M, E, A] = + EitherT( + xa.rawTrans.apply(ma.leftSemiflatMap(IHC.rollback.as(_)).value) + ) } class KleisliConnectionIOOps[A, B](ma: Kleisli[ConnectionIO, A, B]) { def transact[M[_]: MonadCancelThrow](xa: Transactor[M]): Kleisli[M, A, B] = ma.mapK(xa.trans) + + def transactRaw[M[_]: MonadCancelThrow](xa: Transactor[M]): Kleisli[M, A, B] = + ma.mapK(xa.rawTrans) } trait ToConnectionIOOps { From eb1f5096fa4221973b5f4581f004962f7fa4cd4c Mon Sep 17 00:00:00 2001 From: "Teo.Mertanen" Date: Thu, 10 Apr 2025 17:06:26 +0300 Subject: [PATCH 3/3] Fix ConnectionIOSuite compilation warnings by splitting test cases --- .../src/test/scala/doobie/util/ConnectionIOSuite.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala b/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala index 375a2b044..74909f8d3 100644 --- a/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala +++ b/modules/core/src/test/scala/doobie/util/ConnectionIOSuite.scala @@ -24,11 +24,18 @@ class ConnectionIOSuite extends munit.CatsEffectSuite { test("Semigroup ConnectionIO") { val prg = Applicative[ConnectionIO].pure(List(1, 2, 3)) `combine` Applicative[ConnectionIO].pure(List(4, 5, 6)) prg.transact(xa).assertEquals(List(1, 2, 3, 4, 5, 6)) + } + + test("Semigroup ConnectionIO raw") { + val prg = Applicative[ConnectionIO].pure(List(1, 2, 3)) `combine` Applicative[ConnectionIO].pure(List(4, 5, 6)) prg.transactRaw(xa).assertEquals(List(1, 2, 3, 4, 5, 6)) } test("Monoid ConnectionIO") { Monoid[ConnectionIO[List[Int]]].empty.transact(xa).assertEquals(Nil) + } + + test("Monoid ConnectionIO raw") { Monoid[ConnectionIO[List[Int]]].empty.transactRaw(xa).assertEquals(Nil) }