Play! Framework 2 (2.1) Scala with Slick made easy (With example)


by @mgonto, original article can be found here

Hi everyone!

First of all, I want to tell you that the original post is from here (Blogeek).

Today I’ve seen some videos about Slick and Play! Framework 2.1 and I got excited, so I thought, let’s code an app with Slick. What did I realize? It wasn’t that simple. Play! isn’t yet thought to work with Slick very well.

First of all, if you want to see this example complete you can go to

https://github.com/mgonto/slick-play2-example

In Slick, you create table definitions for the class you want to use. However, all of the imports for the Table, the columns, etc. are driver dependant. So, when you change the driver, you don’t want to change the import in the code. You just want to change a configuration in the application.conf from Play! Framework. That’s exactly what I did.

So, let’s see first how it’s implemented. Every Driver (H2, Postgres, etc) extends from a trait called ExtendedProfile. So, I needed my table classes to use some profile that was injected by me. Once I realized that I needed to make some DI I thought about Cake Pattern. For more information about the Cake Pattern please viisit Cake pattern

So, the first thing I implemented was a Trait Profile with an abstract Extended Profile value:

package models

import slick.driver.ExtendedProfile

trait Profile {
  val profile: ExtendedProfile
}

After this, I needed to create the Users table. That Users table needed the profile, so I’d create a UserModule which would need the Profile trait. Then, as I’d mix with a Profile trait, I’d import the things from the abstract ExtendedProfile field and everything would compile. Then I create the users table with an ID and a Name (pretty simple)

package models

case class User(id: Option[Int], name : String)

trait UserComponent {
  this: Profile =>

  import profile.simple._

  object Users extends Table[User]("users") {
    def id = column[Int]("id", O.PrimaryKey)
    def name =  column[String]("name", O.NotNull)
    def * = id.? ~ name <> (User, User.unapply _)

    def add(user: User)(implicit session: Session) = {
      this.insert(user)
    }

    def countByName(name: String)(implicit session: Session) = {
      (for {
        user <- Users
        if (user.name === name)
      } yield(user)).list.size
    }

  }
}

After this, I create a DataAccessLayer class (DAL) which would receive the ExtendedProfile as a constructor parameter and then would include the other traits (Profile and UserModule)

package models

import slick.driver.ExtendedProfile

class DAL(override val profile: ExtendedProfile) extends UserComponent with Profile {

  import profile.simple._

  def create(implicit session: Session): Unit = {
    Users.ddl.create //helper method to create all tables
  }
}

After this, I have everything to create a DAL from a given profile. However, now I needed a way to configure the profile, so I added a new property in the application.conf.

slick.db.driver=scala.slick.driver.H2Driver

Then, I created a trait that would import this driver from the conf and create the database to do the queries and the dal with the corresponding profile. It has two methods, getDb and getDal which will be then used by two other classes.

package models

import slick.session.Database
import play.api.db.DB
import play.api.Application
import slick.driver.ExtendedProfile

trait DBeable {

  val SLICK_DRIVER = "slick.db.driver"
  val DEFAULT_SLICK_DRIVER = "scala.slick.driver.H2Driver"

  def getDal(implicit app : Application) : DAL = {
    val driverClass = app.configuration.getString(SLICK_DRIVER).getOrElse(DEFAULT_SLICK_DRIVER)
    val driver = singleton[ExtendedProfile](driverClass)
    new DAL(driver)
  }

  def getDb(implicit app : Application) = {
    Database.forDataSource(DB.getDataSource())
  }

  private def singleton[T](name : String)(implicit man: Manifest[T]) : T =
    Class.forName(name + "$").getField("MODULE$").get(man.runtimeClass).asInstanceOf[T]

}

The only things left are creating the DB once the app starts and having a singleton object to be able to ask for the dal and the database to do the queries from a controller. This is done as following:

import models.{User, DBeable, AppDB}
import play.api.db.DB
import play.api.GlobalSettings
import play.api.Application
import slick.session.Session

object Global extends GlobalSettings with DBeable {

  override def onStart(app: Application) {
    implicit val application = app
    lazy val database = getDb
    lazy val dal = getDal
    database.withSession {
      implicit session: Session =>
        dal.create
    }
  }
}
package models
import play.api.Play.current
object AppDB extends DBeable {

  lazy val database = getDb
  lazy val dal = getDal

}

And that’s it :). Now you have everything configured to start coding. I’ve tried if everything was working with a test as following.

class UserSpec extends Specification {

  "User" should {

    "be saved" in {
      running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
        AppDB.database.withSession {
          implicit session: Session =>
            AppDB.dal.Users.add(User(Some(2), "hola"))
            AppDB.dal.Users.countByName("pepe") must beEqualTo(0)
            AppDB.dal.Users.countByName("hola") must beEqualTo(1)

        }
      }
    }
  }
}

And that’s it :) Now you have Play! configured for running with Slick.

Cya people!

About these ads

4 responses to this post.

  1. Excellent article gonto, and a great example of the cake pattern.

    I had a rough time trying to understand the self-type part, this question at SO helped me understand it

    http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclasses

    In order to follow more closely the cake pattern, I would use ProfileComponent instead of profile…

    Reply

  2. Posted by mgonto on 25 November, 2012 at 21:28

    I didn’t use ProfileComponent because it’s not really a component. A component would be something that has first a Trait or Object inside that wants to get exposed and then a val for that Trait or object. In the Profile case, it’s not a component, but a basic dependency. That’s why it’s only “Profile”.

    Bests

    Reply

  3. Thanks for sharing!
    I have one question: Of course, all applications have to deal with many DAOs objects. So, from my understanding, it implies that the DAL class inherits from many component traits (one for each DAO), isn’t it?

    Reply

    • Posted by mgonto on 30 November, 2012 at 18:46

      So, the DAL will make you have access to all of the Tables that you’ve created. Those tables are actually the queryables.

      So, you’d mix (remember that all of the components are traits) your DAL with all of the other traits that you’ve created. So for example you’d have.

      object DAL extends UserComponent with ProductComponent with ItemComponent with Profile {

      }

      and then to do a query you’d have:

      DAL.Users.filter(_.name == “mgonto”).map(_.name)

      or

      DAL.Products…..

      I hope this is clear!

      Bests!

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: