Doobie - 将任意效果提升到 ConnectionIO

问题描述 投票:0回答:4

我正在尝试在使用 Doobie 将用户插入数据库的同一事务中发送电子邮件。
我知道我可以使用

IO
ConnectionIO
提升到
Async[ConnectionIO].liftIO(catsIO)
,其中
catsIO: IO[String]

但在我的代码中,我不对
IO
进行操作,我使用带有约束的
F
,例如
F[_]: Async
那么我就可以用我自己的 monad 替换
F
来进行测试。

是否可以在不直接使用

F[String]
类型的情况下以某种方式将
ConnectionIO[String]
提升为
IO

这是我为 IO 类型找到的答案:Doobie 和 DB 访问组合在 1 个事务中

scala scala-cats cats-effect doobie
4个回答
9
投票

现在已被更好的解决方案取代此处

Cats 有一种叫做 FunctionK 的东西,这是一种自然的变换。

我这样做了:

在世界之巅,一切都已建成,你将需要这个

val liftToConnIO: FunctionK[IO, ConnectionIO] = LiftIO.liftK[ConnectionIO]

在需要从 F[String] 转换为 G[String] 的类中(构建所有内容时,F 将是 IO,G 将是 ConnectionIO),您可以传递

liftToConnIO
并使用它将 F[A] 转换为 G[ A] 需要的地方。

不想抽象 IO 和 ConnectionIO 的类可以通过 FunctionK 来完成提升:

class Stuff[F[_], G[_]](emailer: Emailer[F], store: Store[G], liftToG: FunctionK[F, G]) {

  def sendEmail: G[Unit] =
    for {
      _ <- doDatabaseThingsReturnStuffInG
      _ <- liftToG(emailer.sendEmail)
      _ <- doMoreDatabaseThingsReturnStuffInG
     } yield ()

}

(您可能需要 F 和 G 上的上下文边界(同步?))


4
投票

钱宁答案的变体,

class Stuff[F[_] : Effect, G[_] : LiftIO](emailer: Emailer[F], store: Store[G]) {

  def sendEmail: G[Unit] =
    for {
      _ <- doDatabaseThingsReturnStuffInG
      _ <- emailer.sendEmail.toIO.to[G]
      _ <- doMoreDatabaseThingsReturnStuffInG
     } yield ()
}

Effect[F]
支持通过
F[A]
IO[A]
转换为
toIO
LiftIO[G]
支持通过
IO[A]
G[A]
转换为
to[G]


3
投票

是的,您可以轻松地将

F[String]
实例化为
ConnectionIO[String]
。 给定一个如下函数:

def foo[F[_]: Async]: F[String] = ...

要实例化到

ConnectionIO
,您可以简单地执行以下操作:

def fooCIO: ConnectionIO[String] = foo[ConnectionIO]

1
投票

自 Doobie 1.x(带有猫效应 3)以来,

LiftIO
 ConnectionIO
实例不再存在(为什么

相反,您想使用

WeakAsync.liftK
,如 Doobie - 将任意效果提升到 ConnectionIO CE3

中提到的
© www.soinside.com 2019 - 2024. All rights reserved.