Refactor function to remove unsafe .get calls when making doobie database queries

64 Views Asked by At

My DAO method types are:

ProductDao.getById(..): ConnectionIO[Option[Product]]
InventoryDao.getById(..): ConnectionIO[Option[Inventory]]

The function I need to refactor to make it safe is below:

def getInventoryLocation(...): IO[Either[String, Int]] = {

   (for {

    product <- EitherT.fromOptionF(ProductDao.getById(id).transact(xa), "product not found")
        inventory <- EitherT.fromOptionF((InventoryDao.getById(product.inventorySectionId.get)).transact(xa), "product not found")
   } yield inventory.location.get).value
}

There are 2 problems currently with the function, it calls .get two times. I need help removing those, when I try .map over the option that doesn't seem to work correctly.

inventory <- EitherT.fromOptionF(( product.inventorySectionId.map(InventoryDao.getById()) ).transact(xa), "product not found")

Because then I am returning a None and not a IO none I guess?

1

There are 1 best solutions below

0
On

Your for-comprehension already uses an EitherT for error handling. Assuming product.inventorySectionId and inventory.location return Options, you can use EitherT.fromOption to make them compatible and put them into separate lines in the for, so you no longer have nested errors:

(for {
  product <- EitherT.fromOptionF(ProductDao.getById(id).transact(xa), "product not found")
  sectionId <- EitherT.fromOption(product.inventorySectionId, "section not found")
  inventory <- EitherT.fromOptionF((InventoryDao.getById(sectionId)).transact(xa), "product not found")
  location <- EitherT.fromOption(inventory.location, "location not found")
} yield location).value