Doobie y composición de acceso a DB en 1 transacción
Doobie book dice que es una buena práctica devolver ConnectionIO desde su capa de repositorio. Ofrece la capacidad de encadenar llamadas y realizarlas en una sola transacción. Agradable y claro.
Ahora imaginemos que estamos trabajando en el servicio API REST y nuestro escenario es:
Encontrar un objeto en la base de datos Realice alguna manipulación asíncrona (utilizando cats.effect.IO o monix.eval.Task) con este objeto. Almacene el objeto en la base de datos. Y queremos realizar todos estos pasos dentro de 1 transacción. El problema es que sin la transformación natural que nos brindatransactor.trans()
estamos trabajando dentro de 2 mónadas -Task
yConnectionIO
. Eso no es posible
La pregunta es: cómo mezclar doobieConnectionIO
con algún efecto mónada en 1 composición, como si estuviéramos trabajando en 1 transacción y pudiéramos comprometer / revertir todas las mutaciones de DB en el fin del mundo?
¡Gracias
UPD: pequeño ejemplo
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: La respuesta correcta proporcionada por @ oleg-pyzhcov es elevar sus tipos de datos de efectos aConnectionIO
Me gusta esto
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)