Cookbook

This section of the manual is for solutions to common questions.

Mapping more than 22 fields

Problem

You have a table with more than 22 fields, and the Scala 2 compiler has told you:

too many elements for tuple: 23, allowed: 22

Solution

Switch from using a tuple in your default projection to using an HList.

First, add the HList imports:

sourceimport slick.collection.heterogeneous._
import slick.collection.heterogeneous.syntax._

Your case class and table definition are as unchanged, but your default projection ( the * method) changes:

sourcecase class Row(id: Int, name: String /* ... as many as you like */)

class MyTable(tag: Tag) extends Table[Row](tag, "ROW") {
  def id   = column[Int]("ID", O.PrimaryKey)
  def name = column[String]("NAME")
  /* ... as many as you like */

  def * = (id :: name /* as many as you like... */ :: HNil).mapTo[Row]
}

Track the Number of Query Compilations

Problem

Query compilation can be expensive. We can use the Compiled construct to avoid re-compiling queries. However, it can also be easy to accidentally forget to use this construct or revert its usage. When this happens in a high-traffic deployment, query times and CPU usage can increase drastically.

To identify this type of regression, we’d like to track the number of query compilations. We might then expose this count as an application metric and setup an alert which triggers when an abnormally high number of query compilations occur.

Solution

To track the number of query compilations, we can override the computeQueryCompiler method in our profile. The new QueryCompiler will have an additional phase, which simply increments a counter.

sourceimport slick.jdbc.JdbcProfile
import slick.compiler._
import java.util.concurrent.atomic.AtomicLong

trait MyProfile extends JdbcProfile {

  // This counter can be accessed from an instance of `MyProfile`
  // and exposed as an application metric.
  final val queryCompilationCounter: AtomicLong = new AtomicLong(0)

  // This method gets called to setup the QueryCompiler.
  // We'll attach a CompilerPhase that just increments the compilation counter
  // and leave the compiler otherwise unchanged.
  override def computeQueryCompiler: QueryCompiler = {
    val phase = new Phase {
      override type State = this.type
      override val name: String = "IncrementQueryCompilationCounter"
      override def apply(state: CompilerState): CompilerState = {
        // When this Phase gets applied, it just increments the counter and
        // passes the CompilerState through unchanged.
        queryCompilationCounter.incrementAndGet()
        state
      }
    }
    super.computeQueryCompiler + phase
  }
}
The source code for this page can be found here.