July 3, 2013

Play! 2.1 RowParsers and LEFT JOINs

If you've used Play! Framework version 2.1, and you've tried out the RowParser API, you may have wondered, as I have, how to handle LEFT JOIN queries, since the rows from the left table will appear at least once and the rows from the right table may or may not appear. If the right table does appear, you want to parse the data using an existing RowParser, rather than having some custom parser and case class which has all Option fields.

In my initial approach, inspired by this question on the Play! Framework Google Group, was a bit parentheses-heavy.
// Parser for "foo" table
val foo = get[Long]("foo.id")

// Parser for "bar" table
val bar = get[Long]("bar.id")

// Combined parser
val combo = foo ~ (bar ?)

// Results as List[~[Long, Option[Long]]]
val results = SQL("SELECT * FROM foo LEFT JOIN bar ON foo.id = bar.foo_id").as(combo *)

Since the parentheses bothered me a bit, I enriched the RowParser class to provide a convenience method ~? which combines the two functions.
implicit def enrichRowParser[A](a: RowParser[A]) = new RichRowParser(a)

class RichRowParser[A](val delegate: RowParser[A]) extends AnyVal {

def ~?[B](p: RowParser[B]) = {
delegate ~ (p ?)
}

}

The declaration for combo can then be redefined without the parentheses which seems a bit more readable.
val combo = foo ~? bar

No comments:

Post a Comment