Skip to content

Parsers v1.0

msiebert edited this page Jun 20, 2014 · 2 revisions

Warning!

This is not the most current version of Relate! See current version

Parsers – Retrieving Data

Defining a Parser

Parsers are created by passing an anonymous function that takes a row object and returns some value to the RowParser's apply method. Within that function, values can be extracted from the row object. Here's an example:

import com.lucidchart.open.relate.RowParser

case class Pokemon(
  name: String,
  level: Short,
  trainerId: Option[Long]
)

val pokemonParser = RowParser { row =>
  Pokemon(
    row.string("name"),
    row.short("level"),
    row.longOption("trainer_id")
  )
}

In this example, the created parser takes the value from the name column of the row as a string, the value of level as a short, and the value from the trainer_id column as a long option to instantiate a Pokemon object. The row object has numerous methods to extract data from the row with the desired data type.

Some of the methods that can be called on the row object are prepended with the word "strict." These methods are faster than their non-strict counterparts, but do not do type checking, and do not handle null values in the database.

The function passed to RowParser can return any value, so it doesn't necessarily need to be an instance of a case class. A Tuple, Seq, etc. would work equally well.

Using a Parser

Applying a parser to a query only requires specifying the desired collection type to return. The following is an example using the parser created in the previous section:

SQL("""
  SELECT *
  FROM professor_oaks_pokemon
  WHERE pokemon_type={type}
""").on { implicit query =>
  string("type", "starter")
}.executeQuery()(connection).asList(pokemonParser)

This example would return a List of Pokemon. The parser can also be passed to the asSingle, asSingleOption, asSet, asSeq, asIterable, and asList methods to produce the respective collections.

Parsers that return a Tuple of size 2 can also be passed to the asMap method to get a Map. Here's an example of its use (using the case class from the previous example):

val nameToPokemonParser  = RowParser { row =>
  val pokemon = Pokemon(
    row.string("name"),
    row.short("level"),
    row.longOption("trainer_id")
  )
  (pokemon.name, pokemon)
}

SQL("""
  SELECT *
  FROM professor_oaks_pokemon
  WHERE pokemon_type={type}
""").on { implicit query =>
  string("type", "starter")
}.executeQuery()(connection).asMap(nameToPokemonParser)

Single Column Parsers

Sometimes a query retrieves only one column. Convenience methods are defined in RowParser for creating single column row parsers in these occasions. Below is an example of their use:

SQL("""
  SELECT id
  FROM trainers
  WHERE name="Red"
""").executeQuery()(connection).asList(RowParser.long("id"))

The RowParser object also contains definitions for bigInt, date, int, and string.

Single Value Parsers

In other cases, only one value is desired as the result of a query. For these scenarios, Relate provides a scalar method with which the desired type of the returned single value can be defined. The return value is wrapped as an Option. An example of its use is as follows:

SQL("""
  SELECT hp
  FROM pokemon
  WHERE name="Squirtle"
""").executeQuery().scalar[Int].get

Retrieving Auto Increment Values on Insert

The scalar method can be used to retrieve auto increment values. Given a table where the primary key was a long, here's an example:

SQL("""
  INSERT INTO badges(name)
  VALUES ("Boulder Badge")
""").executeInsert().scalar[Long].get