My join looks like this:
def byIdWithImage = for {
userId <- Parameters[Long]
(user, image) <- Users leftJoin RemoteImages on (_.imageId === _.id)
Off the top of my head, I'd use a custom mapped projection. Something like this:
case class RemoteImage(id: Long, url: URL)
def byIdWithImage = for {
userId <- Parameters[Long]
(user, image) <- Users leftJoin RemoteImages on (_.imageId === _.id) if user.id === userId
} yield (user, maybeRemoteImage(image.id.? ~ image.url.?))
def maybeRemoteImage(p: Projection2[Option[Long], Option[URL]]) = p <> (
for { id <- _: Option[Long]; url <- _: Option[URL] } yield RemoteImage(id, url),
(_: Option[RemoteImage]) map (i => (Some(i id), Some(i url)))
)
Using scalaz (and its ApplicativeBuilder
) should help reduce some of that boilerplate.