scalacats-effectdoobie

Doobie - lifting arbitrary effect into ConnectionIO CE3


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?


Solution

  • 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:

    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)
    }