Table Of Contents

Previous topic

Lifted Embedding

Next topic

Plain SQL Queries

This Page

Direct Embedding

The direct embedding is a new, experimental front-end for writing queries. The API may change without deprecation during experimental status. Unlike the (stable) lifted embedding, the direct embedding uses macros instead of operator overloading and implicit conversions for its implementation. For a user the difference in the code is small, but queries using the direct embedding work with ordinary Scala types, which can make error messages easier to understand.

The following descriptions are anolog to the description of the lifted embedding.


import scala.slick.driver.H2Driver
import H2Driver.simple.Database
import Database.{threadLocalSession => session}

Row class and schema

The schema description is currently provided as annotations on a case class which is used for holding rows. We will later provide more flexible and customizable means of providing the schema information.

// describe schema for direct embedding
case class Coffee(
  name : String,
  price : Double


Queryable takes an annotated case class as its type argument to formulate queries agains the corresponding table.

_.price is of type Int here. The underlying, macro-based implementation takes care of that the shown arguments to map and filter are not executed on the JVM but translated to database queries instead.

// query database using direct embedding
val q1 = Queryable[Coffee]
val q2 = q1.filter( _.price > 3.0 ).map( _ .name )


To execute the queries we need to create a SlickBackend instance passing in the chosen database backend driver.

val db = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver")
db withSession {
    // execute query using a chosen db backend
    val backend = new SlickBackend( H2Driver, AnnotationMapper )
    println( backend.result( q2, session ) )
    println( backend.result( q2.length, session ) )

Alternative direct embedding bound to a driver and session

Using ImplicitQueryable, a queryable can be bound to a backend and session. The query can be further adapted and easily executed this way.

val iq1 = ImplicitQueryable( q1, backend, session )
val iq2 = iq1.filter( c => c.price > 3.0 )
println( iq2.toSeq ) //  <- triggers execution 
println( iq2.length ) // <- triggers execution


The direct embedding currently only supports database columns, which can be mapped to either String, Int, Double.

Queryable and ImplicitQueryable currently support the following methods:

map, flatMap, filter, length

The methods are all immutable meaning they leave the left-hand-side Queryable unmodified, but return a new Queryable incorporating the changes by the method call.

Within the expressions passed to the above methods, the following operators may be used:

Any: ==

Int, Double: + < >

String: +

Boolean: || &&

Other operators may type check and compile ok, if they are defined for the corresponding types. They can however currently not be translated to SQL, which makes the query fail at runtime, for example: ( c => ) ). We are evaluating ways to catch those cases at compile time in the future

Queries may result in sequences of arbitrarily nested tuples, which may also contain objects representing complete rows. E.g. c => (, (c, c.price)) )

The direct embedding currently does not feature insertion of data. Instead we can use the lifted embedding or plain SQL queries.