What is the point of writing this?
val retrieveCustomer: (Option[String], Option[Int], Option[Int]) => List[Customer] = { ( customerId : Option[String], count : Option[Int], offset : Option[Int] )
When you can write something like this:
def getCustomer(id: String, count: Option[Int], offset: Option[Int]): List[Customer]
That is obviously more concise, although likely has nothing to do with the concision you're after. I'd be inclined to go with Either Right projections on each operation in a for{...} block, "failed" Left outcomes executing the base or non-fully refined query, and successful Right outcome executing the full drop + take refinements.
def getCustomer(id: String, count: Option[Int], offset: Option[Int]): List[Customer] = {
val base = Customers.createFinder(_.id)
val q = for{
cust <- base(id) toRight( List[Customer]() )
dropped <- cust.drop(offset) toRight(cust)
taken <- dropped.take(count) toRight(dropped)
} yield taken
DBGlobal.db.withTransaction { q.list map { _.fold(_,_) } }
}
Unlikely that this compiles ;-), but the general principle is to thread through Left/Right query outcomes that both return a List of Customers.
Note: I tend to name mapper companion object in the plural form of case class, so in this case, instead of CustomerTable, I used Customers. Also, Customers.createFinder(_.id)
desugars to:
for{
id <- Parameters[String]
c <- Customers if c.id is id
} yield c
which lazily generates an efficient prepared statement for underlying DBMS.
What you have works of course, looks fine for one-off cases. Personally, I'm digging for{} + Either right projections, can have your cake and eat it too -- i.e. get both point-of-failure Left outcome and successful Right outcome, as opposed to for{...} through Option, which only yields a successful event, providing no information at all about which step actually went wrong.