Le problème était qu'actuellement, Quill async ne prend pas en charge les opérations simultanées dans les transactions.
Il fallait donc faire l'insertion de l'animal de manière séquentielle :
ctx.transaction { implicit ec =>
for {
personId <- ctx.run(insertPersonQuery)
animals = personCreate.animals.map(Animal.apply(personId, _))
_ <- animals.foldLeft(Future.successful(0l)) {
case (fut, animal) =>
fut.flatMap(_ => insertAnimal(animal))
}
} yield personId
}
aussi, encore mieux est d'utiliser l'insertion par lots :)
Merci pour @fwbrasil et @mentegy pour l'aide !