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)

questionAnswers(1)

yourAnswerToTheQuestion