Doobie和DB访问组合在1个事务中

时间:2018-05-22 16:55:41

标签: scala scala-cats doobie

Doobie book表示从存储库层返回ConnectionIO是一种很好的做法。它提供了链接调用并在一个事务中执行它们的能力。 很好,很清楚。

现在让我们假设我们正在开发REST API服务,我们的场景是:

  1. 在数据库中查找对象
  2. 使用此对象执行一些异步操作(使用cats.effect.IO或monix.eval.Task)。
  3. 将对象存储在数据库中。
  4. 我们希望在1个事务中执行所有这些步骤。问题是,如果没有Closure为我们提供的自然变换,我们就会在2个monad中工作 - transactor.trans()Task。那是不可能的。

    问题是 - 如何将doobie ConnectionIO与1个组合中的任何效果monad混合,例如我们在1个事务中工作并且能够在世界末尾提交/回滚所有数据库突变?

    谢谢!

    UPD: 小例子

    ConnectionIO

    UPD2:@ oleg-pyzhcov提供的正确答案是将效果数据类型提升到def getObject: ConnectionIO[Request] = ??? def saveObject(obj: Request): ConnectionIO[Request] = ??? def processObject(obj: Request): monix.eval.Task[Request] = ??? val transaction:??? = for { obj <- getObject //ConnectionIO[Request] processed <- processObject(obj) //monix.eval.Task[Request] updated <- saveObject(processed) //ConnectionIO[Request] } yield updated ,如下所示:

    ConnectionIO

1 个答案:

答案 0 :(得分:8)

doobie has a cats.effect.Async instance中的

ConnectionIO,其中包括允许您通过cats.effect.IO方法将ConnectionIO转换为liftIO

import doobie.free.connection._
import cats.effect.{IO, Async}
val catsIO: IO[String] = ???
val cio: ConnectionIO[String] = Async[ConnectionIO].liftIO(catsIO)

对于monix.eval.Task,您最好的选择是使用Task#toIO并执行相同的操作,但您需要在范围内使用monix Scheduler