I'm writing integration tests of skunk code against postgres using scala-test-containers, munit and munit-cats-effect, using Mill and Scala 3. I'm new to Cats Effect.
The setup I'm working to achieve is:
Below is the code so far, which the compiler is ok with except for the call to rollback
, which requires an implicit skunk.util.Origin
. I don't see any reference to this type in the skunk docs and I can't figure out how I'm supposed to bring it into scope.
How can I get the call to rollback
to compile in this code? Where is the missing implicit Origin?
import cats.effect.IO
import munit.CatsEffectSuite
import org.testcontainers.utility.DockerImageName
import cats.effect.kernel.Resource
import skunk.*
import skunk.implicits.*
import natchez.Trace.Implicits.noop
import munit.catseffect.IOFixture
import cats.implicits.catsSyntaxFlatMapOps
val container: Resource[IO, PostgreSQLContainer] =
Resource.make
(for {
c <- IO(PostgreSQLContainer(
DockerImageName.parse("postgres:17-alpine")
))
_ <- IO.blocking(c.start())
} yield c)
(c => IO.blocking(c.stop()))
val sessionResource: Resource[IO, Session[IO]] =
container.flatMap { c =>
Session.single[IO](
host = "localhost",
port = 5432,
user = c.username,
password = Some(c.password),
database = c.databaseName
)
}
def useWithRollback[T](s: Session[IO])(f: Transaction[IO] => IO[T]) =
s.transaction.use { xa =>
for {
result <- f(xa)
_ <- xa.rollback() // fails compilation: needs implicit skunk.util.Origin
} yield result
}
class PgIntegrationTests extends CatsEffectSuite:
val session = ResourceSuiteLocalFixture(
"skunk session",
sessionResource
)
override def munitFixtures = List(session)
def withDb[T](f: Transaction[IO] => IO[T]) =
useWithRollback(session())(f)
The idea is that a test would look something like
test("something") {
withDb { xa =>
for {
result <- callMyCode(xa)
_ <- assertIO(result, <expected result>)
} yield ()
}
}
The above fails compilation, in useWithRollback
with
[error] 41 | _ <- xa.rollback()
[error] | ^^^^^^^^^^^
[error] | None of the overloaded alternatives of method rollback in trait Transaction with types
[error] | (implicit o: skunk.util.Origin): cats.effect.IO[skunk.data.Completion]
[error] | (savepoint: xa.Savepoint)(implicit o: skunk.util.Origin): cats.effect.IO[skunk.data.Completion]
[error] | match arguments ()
from which I gather it's looking for an Origin
in scope. How can I bring that Origin
into scope? Why doesn't the skunk Transaction page (linked above) have this issue where it calls rollback
in its example?
Thanks for your time.
P.S: The Mill build file build.sc
:
import mill._, scalalib._
object devmap extends ScalaModule {
def scalaVersion = "3.5.1"
def ivyDeps = Agg(
ivy"org.tpolecat::skunk-core:0.6.4",
ivy"org.typelevel::cats-effect:3.5.7"
)
object test extends ScalaTests with TestModule.Munit {
def ivyDeps = Agg(
ivy"org.scalameta::munit::0.7.29",
ivy"org.typelevel::munit-cats-effect:2.0.0",
ivy"com.dimafeng::testcontainers-scala-postgresql:0.41.5",
ivy"org.postgresql:postgresql:42.7.4",
ivy"com.lihaoyi::pprint:0.9.0"
)
}
}
Try with this:
def useWithRollback[T](s: Session[IO])(f: Transaction[IO] => IO[T]) =
s.transaction.use { xa =>
for {
sp <- xa.savepoint
result <- f(xa)
_ <- xa.rollback(sp)
} yield result
}