Skip to content
Browse files
Integrate the four official Activator templates into the manual.
We can use Lightbend’s Example Code Service to make pre-packaged zip
files available for download. We need to move away from Activator
because it will be shut down soon.

I updated the sample code for 3.2 and tried to integrate the tutorials
back into the manual. Some more polishing could be done in order to
retire FirstExample.scala and PlainSQL.scala from doc/code and take
all snippets on and from the sample projects.
  • Loading branch information
szeiger committed Mar 24, 2017
1 parent 7922989 commit 8b342b4a177770431223c2a2559041a009eda9f3
Show file tree
Hide file tree
Showing 61 changed files with 2,247 additions and 125 deletions.
@@ -52,7 +52,7 @@ object FirstExample extends App {
val db = Database.forConfig("h2mem1")
try {
// ...
// val resultFuture: Future[_] = { ... }

@@ -149,9 +149,9 @@ object FirstExample extends App { { case (s1, s2) => println(" " + s1 + " supplied by " + s2) })

Await.result(resultFuture, Duration.Inf)
lines.foreach(Predef.println _)
} finally db.close
@@ -58,10 +58,6 @@ extension.globalRefs.refs {
"Oracle": ""
"SQL Server": ""
"JMX": ""
"Hello Slick template": ""${shortVersion}
"Slick Plain SQL Queries template": ""${shortVersion}
"Slick Multi-DB Patterns template": ""${shortVersion}
"Slick TestKit Example template": ""${shortVersion}

extension.includeCode {
@@ -94,6 +90,8 @@ extension.externalLinks {
uri = "[all]"
text = "SI-[all]"
samplezip.uri = "[all]-"${shortVersion}
samplerepo.uri = ""${shortVersion}"/samples/[all]"

extension.highlightjs {
@@ -111,13 +111,127 @@ should therefore enable prepared statement caching in the connection pool's conf

> {.note}
> This section is based on the **MultiDB** sample ([github](samplerepo:slick-multidb),
> [zip](samplezip:slick-multidb)) which provides ready-to-run apps to demonstrate the features.
On top of the configuration syntax for `Database`, there is another layer in the form of
<api:slick.basic.DatabaseConfig> which allows you to configure a Slick profile plus a
matching `Database` together. This makes it easy to abstract over different kinds of
database systems by simply changing a configuration file.

Here is a typical `DatabaseConfig` with a Slick profile object in `profile` and the database
configuration in `db`:
You can see it in action in `SimpleExample.scala`. First we load the DatabaseConfig and then import the
Slick API from its profile:

```scala src=../../samples/slick-multidb/src/main/scala/databaseconfig/SimpleExample.scala#dc

The `JdbcProfile` type annotation specifies the profile level whose API you get. You have to configure a profile of
a matching type in the external configuration file. Since we're using the basic `forConfig` method with only a path
("h2_dc"), the configuration must be located in the global application config, usually found in `application.conf`:

```scala src=../../samples/slick-multidb/src/main/resources/application.conf#--doc-h2_db

You can use different database systems in your application by either switching out or overriding the application
config (e.g. different `application.conf` files for development and production) or by passing a config path into
the application. This way of implementing multi-database support is also used when building a Play app with Slick.

Other Multi-DB Patterns

> {.note}
> This section is based on the **MultiDB** sample ([github](samplerepo:slick-multidb),
> [zip](samplezip:slick-multidb)) which provides ready-to-run apps to demonstrate the features.
Since its addition in Slick 3.0 `DatabaseConfig` (see [above](#databaseconfig)) is the recommended solution.
More complex scenarios (for example, where you need to map custom functions differently for different database
systems, or where you cannot use the simple application.conf syntax) may require abstracting over databases in Scala
code. The following sections explain two different ways of accomplishing this.

### A DAO Class

We start with a simple DAO (data access object) class, `DAO.scala`. It contains some database-related definitions
(for a `PROPS` table that acts as a simple key/value store) and methods (for storing and reading entries).

```yaml src=../code/application.conf#tsql
The class is parameterized by a concrete `JdbcProfile` and it imports all API features from this profile's api object:

```scala src=../../samples/slick-multidb/src/main/scala/basic/DAO.scala#dao

Slick has multiple abstract profiles but in most cases you will want to use `JdbcProfile` which contains all the
features that you also get when importing directly from one of Slick's concrete profiles for JDBC databases.

Outside of the DAO class, you can still refer to its profile and the other features, but you have to get the imports
from the profile in order to work with queries. This can be seen in `DAOHelper.scala`. It defines a new method
`restrictKey` which we could have also put directly into the DAO class.

To gain access to all of the profile's features, we parameterize the `DAOHelper` with the `DAO` and import from its

```scala src=../../samples/slick-multidb/src/main/scala/basic/DAOHelper.scala#daohelper

Note the use of the type projection `DAO#Props` in the definition of `restrictKey`. This points to the `Props` type
coming from any `DAO` instance. This is less type-safe than using a path-dependent type like `dao.Props` but
generally easier to use. You still need to ensure not to mix drivers when you do this.

We are using the `DAO` and `DAOHelper` in `MultiDBExample.scala`. The `run` method is parameterized with both,
a Slick profile and a matching JDBC `Database`:

```scala src=../../samples/slick-multidb/src/main/scala/basic/MultiDBExample.scala#run

Since we don't have the convenience of a single profile's `api._` import at this point, we need to import the
`Database` and `DBIO` types directly:

```scala src=../../samples/slick-multidb/src/main/scala/basic/MultiDBExample.scala#imports

In the body of `MultiDBExample`, we create two `DAO` instances with matching `Database` objects in order to run the
same code on both, H2 and SQLite:

```scala src=../../samples/slick-multidb/src/main/scala/basic/MultiDBExample.scala#create

### The Cake Pattern

In more complex designs where you want to split up the database code into separate modules that deal with different
database entities, but still have dependencies between these modules, you can use the Cake Pattern to structure your

We are doing this here in the app `MultiDBCakeExample.scala`. From the point of view of this main app, the new
approach looks exactly like the previous one: You create a DAL (data access layer) object with a Slick profile, and
use it together with a matching `Database`.

The most basic slice of the cake is the `ProfileComponent`. It provides a `JdbcProfile` which is kept abstract at
this point:

```scala src=../../samples/slick-multidb/src/main/scala/cake/ProfileComponent.scala

Through the use of a self-type, the `PictureComponent` requires a `ProfileComponent` to me mixed in, so that it can
import the query language features from the profile:

```scala src=../../samples/slick-multidb/src/main/scala/cake/PictureComponent.scala#outline

Using the imported features, `PictureComponent` provides definitions and methods for working with `Picture` objects
in the database. `UserComponent` does the same for `User` entities. In addition to `ProfileComponent` it also
requires `PictureComponent`:

```scala src=../../samples/slick-multidb/src/main/scala/cake/UserComponent.scala#outline

The `PictureComponent` dependency allows `UserComponent` to insert a new `Picture` when needed:

```scala src=../../samples/slick-multidb/src/main/scala/cake/UserComponent.scala#insert

We put all slices of the cake together in `DAL.scala`. The `DAL` class inherits from all components and adds the
missing profile through a field in the constructor:

```scala src=../../samples/slick-multidb/src/main/scala/cake/DAL.scala

This is also a good place to add functionality that affects all components, like the `create` method.

0 comments on commit 8b342b4

Please sign in to comment.