Doobie e DB acessam a composição em uma transação
Livro Doobie diz que é uma boa prática retornar o ConnectionIO da sua camada de repositório. Ele oferece a capacidade de encadear chamadas e executá-las em uma transação. Bonito e claro.
Agora vamos imaginar que estamos trabalhando no serviço da API REST e nosso cenário é:
Encontre um objeto no banco de dadosExecute alguma manipulação assíncrona (usando cats.effect.IO ou monix.eval.Task) com este objeto.Armazene o objeto no banco de dados.E queremos executar todas essas etapas dentro de uma transação. O problema é que sem a transformação natural que nos é dada portransactor.trans()
estamos trabalhando dentro de duas mônadas -Task
eConnectionIO
. Isso não é possível.
A questão é - como misturar doobieConnectionIO
com algum efeito mônada em 1 composição, como estamos trabalhando em 1 transação e capaz de confirmar / reverter todas as mutações de banco de dados no final do mundo?
Obrigado!
UPD: pequeno exemplo
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: A resposta correta fornecida por @ oleg-pyzhcov é elevar seus tipos de dados de efeito paraConnectionIO
como isso:
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)