Skip to content

Queries and Statements as Interpolated

Gustavo De Micheli edited this page Dec 23, 2024 · 8 revisions

Let's see how we can define queries as string interpolation:

Usage

First we need to mark a CqlSession implicit:

import net.nmoncho.helenus._

implicit val session: CqlSession = cqlSession

Queries as Interpolated Strings

Then we can define queries as Interpolated Strings, using the cql prefix:

val hotel = "Rotterdam Marriott"
// hotel: String = "Rotterdam Marriott"

val hotelsByName = cql"SELECT * FROM hotels_cql WHERE name = $hotel"
// hotelsByName: api.cql.WrappedBoundStatement[Row] = net.nmoncho.helenus.api.cql.WrappedBoundStatement@193c6ec2

val resultSet = hotelsByName.execute()
// resultSet: PagingIterable[Row] = com.datastax.oss.driver.internal.core.PagingIterableWrapper@766c1b8d

val result = resultSet.nextOption()
// result: Option[Row] = Some(
//   value = com.datastax.oss.driver.internal.core.cql.DefaultRow@7a1f46da
// )

After we interpolate at statement, we'll receive a ScalaBoundStatement, which we can execute when we see fit.

Interpolated values will be replaced with Named Bind Parameters, making sure the query has been sanitized.

Avoiding Boilerplate

To avoid boilerplate, it's also possible to use constants, defined with final val, in your queries:

object Keyspace {
  final val table = "hotels_cql"

  final val country = "country"
  final val name = "name"
}

val hotelsByNameWithConstants =
  cql"SELECT ${Keyspace.country}, ${Keyspace.name} FROM ${Keyspace.table} WHERE ${Keyspace.name} = $hotel".execute().nextOption()
// hotelsByNameWithConstants: Option[Row] = Some(
//   value = com.datastax.oss.driver.internal.core.cql.DefaultRow@8335989
// )

Note: Constants will be interpolated as is, even if they are in bind parameter position. This means that depending on the value of your constant, you may have to wrap it in quotes.

Asynchronous Execution

We can also define interpolated queries asynchronously with the cqlAsync prefix:

val asyncBoundStatement = cqlAsync"SELECT * FROM hotels_cql WHERE name = $hotel"
// asyncBoundStatement: concurrent.Future[api.cql.WrappedBoundStatement[Row]] = Future(Success(net.nmoncho.helenus.api.cql.WrappedBoundStatement@72036c33))

val asyncResult = for {
  query <- asyncBoundStatement
  resultSet <- query.executeAsync()
} yield resultSet.currPage.nextOption()
// asyncResult: concurrent.Future[Option[Row]] = Future(Success(Some(com.datastax.oss.driver.internal.core.cql.DefaultRow@6425a18d)))

Iterating and Extracting Results

Defining and executing queries is one part of the story. The other part is how we make sense of the Rows we get out of these queries.

We can iterate results using some extension methods, and we can map rows to a more meaningful result using RowMappers.