Doobie book表示从存储库层返回ConnectionIO是一种很好的做法。它提供了链接调用并在一个事务中执行它们的能力。 很好,很清楚。
现在让我们假设我们正在开发REST API服务,我们的场景是:
我们希望在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
答案 0 :(得分:8)
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
。