Doobie bookによると、リポジトリ レイヤーから ConnectionIO を返すことをお勧めします。これにより、呼び出しをチェーンして 1 つのトランザクションで実行することができます。素晴らしくクリア。
ここで、REST API サービスに取り組んでおり、シナリオが次のようになっているとします。
- データベースでオブジェクトを見つける
- このオブジェクトで (cats.effect.IO または monix.eval.Task を使用して) 非同期操作を実行します。
- オブジェクトをデータベースに格納します。
そして、これらすべてのステップを 1 つのトランザクション内で実行したいと考えています。問題は、 によって与えられる自然な変換がなければ、transactor.trans()
2 つのモナド内で作業していることです -Task
とConnectionIO
. それは可能ではありません。
ConnectionIO
問題は、1つのトランザクションで作業していて、世界の終わりにすべてのDBミューテーションをコミット/ロールバックできるように、1つのコンポジションでdoobieとエフェクトモナドをどのように混在させるかです?
ありがとうございました!
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)