Как написать транзакцию Дуби, когда IO застрял в середине - PullRequest
0 голосов
/ 13 декабря 2018

Я хочу написать базовую транзакцию чтения / записи Дуби, но главное, что в середине есть ответный вызов 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.Поэтому во втором случае я бы застрял на IO[ConnectionIO[Something]], что означает, что моя транзакция в конечном итоге будет выглядеть как ConnectionIO[IO[ConnectionIO[Something]].

Мне нужен ConnectionIO[IO[Something]], который я могу затем запустить в одной транзакции, получив IO[IO[Something]], которую затем легко сгладить.(Я не хочу запускать IO.) Имеет смысл?Любая идея, если это возможно осуществить?

1 Ответ

0 голосов
/ 18 декабря 2018

Теоретически вы можете использовать класс типов LiftIO, предоставленный 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].Он принимает неявный аргумент типа LiftIO, который выглядит следующим образом и в значительной степени выполняет то, что вы хотите (поднимает IO в F):

trait LiftIO[F[_]] {
  def liftIO[A](ioa: IO[A]): F[A]
}
...