-
Notifications
You must be signed in to change notification settings - Fork 1
Extracting Results
Defining and executing queries is one part of the story. The other is mapping query results to Scala types.
Once we can use the as
method on a ScalaPreparedStatement
to define what's
the output type for that statement. By default, this type is Row
.
The as
method requires an implicit RowMapper
available, but we only need to
define one for complex types, such as case classes, and these can be derived.
There are three scenarios we have to consider:
- Simple types: When we want to query only one column from the table.
- Tuples: When we want to query multiple columns, but we don't want to create a specialized
record for this (ie.
case class
). Order is important here. - Case Class: When we want to query multiple columns and each row can be mapped to a case class. Order is not important here.
Only for the last case we have to define an implicit RowMapper
, in all other cases
Helenus will provide an implicit instance on its own.
For simple types, we can use the as
method like this:
val countryHotel =
"SELECT country FROM hotels WHERE name = ?".toCQL
.prepare[String]
.as[String]
// countryHotel: internal.cql.ScalaPreparedStatement1[String, String] = net.nmoncho.helenus.internal.cql.ScalaPreparedStatement1@19c6be47
countryHotel.execute("Rotterdam Marriott").nextOption()
// res3: Option[String] = Some(value = "NL")
For tuples, we can use the as
method like this:
val countryAndCapacityHotel =
"SELECT country, capacity FROM hotels WHERE name = ?".toCQL
.prepare[String]
.as[(String, Int)]
// countryAndCapacityHotel: internal.cql.ScalaPreparedStatement1[String, (String, Int)] = net.nmoncho.helenus.internal.cql.ScalaPreparedStatement1@705d2b85
countryAndCapacityHotel.execute("Rotterdam Marriott").nextOption()
// res4: Option[(String, Int)] = Some(value = ("NL", 1000))
Notice that the order of the element types tuple in the tuple must match the order of the select column types.
For case classes, we need to make an implicit RowMapper
available, and
then use the as
method like we have seen before:
case class Hotel(name: String, country: String, capacity: Int, occupancy: Int)
implicit val hotelRowMapper: RowMapper[Hotel] = RowMapper[Hotel] // Derive RowMapper
// hotelRowMapper: RowMapper[Hotel] = net.nmoncho.helenus.internal.CaseClassRowMapperDerivation$$anonfun$net$nmoncho$helenus$internal$CaseClassRowMapperDerivation$$$nestedInanonfun$genericCCRowMapperBuilder$1$1@68d60d9 // Derive RowMapper
val hotelsByName = "SELECT * FROM hotels WHERE name = ?".toCQL.prepare[String].as[Hotel]
// hotelsByName: internal.cql.ScalaPreparedStatement1[String, Hotel] = net.nmoncho.helenus.internal.cql.ScalaPreparedStatement1@4a53169c
hotelsByName
.execute("Rotterdam Marriott")
.nextOption()
// res5: Option[Hotel] = Some(
// value = Hotel(
// name = "Rotterdam Marriott",
// country = "NL",
// capacity = 1000,
// occupancy = 800
// )
// )
Notice we use RowMapper[Hotel]
to derive an instance without too much hassle.
Unlike with Tuples, element type order is not important. With case classes the fields are mapped by name.