代码之家  ›  专栏  ›  技术社区  ›  Lasf

当一个IO卡在中间时,如何编写doBUI事务

  •  0
  • Lasf  · 技术社区  · 7 年前

    我想写一个基本的doobie读/写事务,但关键是有一个 IO 中间回电话。我想这样做:

    abstract class MyDAO {
    
      def readSomething(id: String): ConnectionIO[Option[Something]]
    
      def writeSomething(something: Something): ConnectionIO[Unit]
    
    }
    
    class MyService {
    
      def getNewSomething: IO[Something] = ???
    
    }
    
    class MyProgram(myDAO: MyDAO, myService: MyService, xa: DataSourceTransactor[IO]) {
    
      val transaction = myDAO.readSomething("xyz").flatMap {
        case Some(thing) => IO.pure(thing).pure[ConnectionIO] //ConnectionIO[IO[Something]]
        case None => myService.getNewSomething.map { newSomething =>
          myDAO.writeSomething(newSomething).map(_ => newSomething)
        }.sequence[ConnectionIO, Something] //can't sequence an IO! So I'm stuck with IO[ConnectionIO[Something]]
      }
    
      transaction.transact(xa)
    
    }
    

    但我不能在屏幕上排序 . 因此,在第二种情况下,我会被 IO[ConnectionIO[Something]] 这意味着我的交易会以 ConnectionIO[IO[ConnectionIO[Something]] .

    我想要的是一个 ConnectionIO[IO[Something]] 然后我可以在一个事务中运行 IO[IO[Something]] 木卫一 有道理吗?你知道这是否有可能实现吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Denis Rosca    7 年前

    理论上你可以使用 LiftIO typeclass由提供 cats-effect 由doobie实施如下:

    import cats.effect._
    import doobie._
    import doobie.implicits._
    
    def read: ConnectionIO[Int] = ???
    def write(s: String): ConnectionIO[Unit] = ???
    def transform(i: Int): IO[String] = ???
    
    val transaction: ConnectionIO[Unit] = for {
      i <- read
      s <- transform(i).to[ConnectionIO]
      _ <- write(s)
    } yield ()
    
    transaction.transact(xa)
    

    注意 to[ConnectionIO] . 它接受类型为的隐式参数 它看起来像这样,并且做了你想做的事情 IO 进入 F ):

    trait LiftIO[F[_]] {
      def liftIO[A](ioa: IO[A]): F[A]
    }
    
    推荐文章