Doobie book说,从存储库层返回ConnectionIO是一个好习惯。它提供了将呼叫链接并在一个事务中执行的功能。
很好,很清楚。

现在,让我们想象一下我们正在研究REST API服务,我们的场景是:


在数据库中查找对象
使用此对象执行一些异步操作(使用cats.effect.IO或monix.eval.Task)。
将对象存储在数据库中。


我们希望在1个事务中执行所有这些步骤。问题在于,如果没有transactor.trans()给我们的自然变换,我们将在2个monad中工作-TaskConnectionIO。那不可能

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

谢谢!

UPD:
小例子

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


UPD2:@ oleg-pyzhcov提供的正确答案是将效果数据类型提升为ConnectionIO,如下所示:

def getObject: ConnectionIO[Request]                      = ???
def saveObject(obj: Request): ConnectionIO[Request]       = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???

val transaction: ConnectionIO[Request] = for {
    obj       <- getObject                                           //ConnectionIO[Request]
    processed <- Async[ConnectionIO].liftIO(processObject(obj).toIO) //ConnectionIO[Request]
    updated   <- saveObject(processed)                               //ConnectionIO[Request]
} yield updated
val result: Task[Request] = transaction.transact(xa)

最佳答案

doobie has a ConnectionIO instance中的cats.effect.Async,除其他外,它还允许您通过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

关于scala - 1次交易中的Doobie和DB访问组合,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50472904/

10-10 22:50