Doobie 书说,从存储库层返回 ConnectionIO 是一个好习惯。它提供了链接调用并在一个事务中执行它们的能力。好看又清晰。
现在让我们假设我们正在开发 REST API 服务,我们的场景是:
- 在数据库中查找对象
- 对这个对象执行一些异步操作(使用cats.effect.IO 或monix.eval.Task)。
- 将对象存储在数据库中。
我们希望在 1 个事务中执行所有这些步骤。问题是,如果没有transactor.trans()
我们在 2 个 monads 中工作的自然转换 -Task
和ConnectionIO
. 那是不可能的。
问题是 - 如何ConnectionIO
在 1 个组合中将 doobie 与任何效果 monad 混合,例如我们正在处理 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)