I am trying to migrate project from cats-effect 2 to cats-effect 3, i am using doobie for interacting with database. Previously i could lift ConnectionIO
to IO
as it was described, but with the upgrade i didn't find any implementation of LiftIO[ConnectionIO]
, how can be same achieved with CE3?
CodePudding user response:
There's two approaches here. Broadly, there's the "don't do that" option (recommended), and the other way would be to use WeakAsync
"Don't do that"
Generally, it's not recommended to interleave arbitrary IO
into a ConnectionIO
program, because ConnectionIO
is transactional, and you cannot roll back an IO
. A ConnectionIO
might run multiple times, for example to retry a recoverable failure.
When possible, it's a good idea to refactor the code to not do the non-transactional operation inside a transaction, but instead to perform it afterwards
However, when that's not practical, ConnectionIO
provides a Sync
instance, and so there's a number of things you can do with it easily that don't require lifting from IO
in the first place:
- printing to the console can be done by summoning
Console[ConnectionIO]
- Getting the current time can be done with
Clock[ConnectionIO]
- You can create a log4cats
Logger[ConnectionIO]
as needed using the appropriate factory for your backend - Generating a UUID value can be done with
UUIDGen[ConnectionIO]
Using WeakAsync
Doobie's WeakAsync
provides a way to get a Resource[F, F ~> ConnectionIO]
Note that because this is a resource, you must take care to complete the transaction inside of use
- the lifecycle of the FunctionK
from the resource will be shut down once use
completes.
Usually that means something like this:
def doStuff(rows: List[Int]): F[Unit] = ???
WeakAsync.liftK[F, ConnectionIO].use { fk =>
val transaction = for {
rows <- sql"select 1".query[Int].to[List]
_ <- fk(doStuff(rows))
} yield ()
transaction.transact(xa)
}
CodePudding user response:
I found the way to achieve it by
def f()(implicit liftToConnectionIO: FunctionK[IO, ConnectionIO]): IO[Unit] = IO.unit
implicit val liftToConnectionIO = WeakAsync.liftK[IO, ConnectionIO]
liftToConnectionIO.use(implicit lift => f())