Automatic case class marshalling

As we’ve seen earlier, SELECT queries using the finagle-postgres API must specify a function which operates on a Row and returns some type T. The resulting future is then the result of all the rows after being mapped with the given function: Future[Seq[T]].

This typically results in a pattern like this:

case class Demo(id: Int, foo: String)
// defined class Demo

val result = Await.result {
  client.prepareAndQuery("SELECT * FROM demo") {
    row => Demo(
      id = row.get[Int]("id"),
      foo = row.get[String]("foo")
    )
  }
}
// result: Seq[Demo] = List(Demo(1,foo))

As you can see, this probably gets verbose and repetitive for rows which have a larger number of columns. It looks like there must be a better way, and thanks to shapeless, there is! Importing com.twitter.finagle.postgres.generic._ enriches client with an additional operation, queryAs:

import com.twitter.finagle.postgres.generic._
// import com.twitter.finagle.postgres.generic._

val result = Await.result {
  client.queryAs[Demo]("SELECT * FROM demo")
}
// result: Seq[Demo] = List(Demo(1,foo))

This method automatically decodes the rows into the specified case class. By default, names are converted to snake case for accessing the fields in the table; this can be overridden by importing com.twitter.finagle.postgres.generic.ColumnNamer.identity._ to instead do nothing to convert column names.

Next, read about Query DSL