Enterprise Architect in HCL Technologies a $7Billion IT services organization. My role is to work as a Technology Partner for large enterprise customers providing them low cost opensource solutions around Java, Spring and vFabric stack. I am also working on various projects involving, Cloud base solution, Mobile application and Business Analytics around Spring and vFabric space. Over 23 yrs, I have build repository of technologies and tools I liked and used extensively in my day to day work. In this blog, I am putting all these best practices and tools so that it will help the people who visit my website. Krishna is a DZone MVB and is not an employee of DZone and has posted 64 posts at DZone. You can read more from them at their website. View Full User Profile

Integrating Play 2.1 with Slick 1.0.0 Database Query DSL

03.14.2013
| 3500 views |
  • submit to reddit

For people in hurry here is the code and the steps to setup.

Refer this blog on Play 2.0: Building Web Application using Scala for details on Play and Scala.

In the next few blogs I will be writing enterprise class web application using Play and Scala. I will be covering topics like Database modelling and Security. Now officially Scala has adopted Slick as the Database query DSL. But when you create a new Play application and add Slick library as mentioned in this blog, it is not working. It gives a strange error like No suitable driver found in tests.

I also found slick-play2-example, this sample expect us to create a DAL layer, but we cannot directly play with slick in our test code.

After much further research I came across this plugin. I tried integrating this with my Play application and it worked like a charm.

We will define a Coffee class and a Supplier class. One Coffee has multiple Suppliers. The class design is as below,

case class Coffee(name: String, supID: Int, price: Double, sales: Int, total: Int)

object Coffees extends Table[Coffee]("COFFEES") {
def name = column[String]("COF_NAME", O.PrimaryKey)
def supID = column[Int]("SUP_ID")
def price = column[Double]("PRICE")
def sales = column[Int]("SALES")
def total = column[Int]("TOTAL")
def * = name ~ supID ~ price ~ sales ~ total <> (Coffee.apply _, Coffee.unapply _)
// A reified foreign key relation that can be navigated to create a join
def supplier = foreignKey("SUP_FK", supID, Suppliers)(_.id)
}

case class Supplier(id: Int, name: String, street: String, city: String, state: String, zip: String)

// Definition of the SUPPLIERS table
object Suppliers extends Table[Supplier]("SUPPLIERS") {
def id = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column
def name = column[String]("SUP_NAME")
def street = column[String]("STREET")
def city = column[String]("CITY")
def state = column[String]("STATE")
def zip = column[String]("<a class="zem_slink" title="ZIP (file format)" href="http://en.wikipedia.org/wiki/ZIP_%28file_format%29" target="_blank" rel="wikipedia">ZIP</a>")
// Every table needs a * projection with the same type as the table's type parameter
def * = id ~ name ~ street ~ city ~ state ~ zip <> (Supplier.apply _, Supplier.unapply _)
}

Below is the ScalaTest to test various capabilities of Slick,

DB.withSession{ implicit session =>

//Populate sample data
val testSuppliers = Seq(
Supplier(101, "Acme, Inc.",      "99 Market Street", "Groundsville", "CA", "95199"),
Supplier( 49, "Superior Coffee", "1 Party Place",    "Mendocino",    "CA", "95460"),
Supplier(150, "The High Ground", "100 Coffee Lane",  "Meadows",      "CA", "93966")
)
Suppliers.insertAll( testSuppliers: _*)

val testCoffees= Seq(
Coffee("Colombian",         101, 7.99, 0, 0),
Coffee("French_Roast",       49, 8.99, 0, 0),
Coffee("Espresso",          150, 9.99, 0, 0),
Coffee("Colombian_Decaf",   101, 8.99, 0, 0),
Coffee("French_Roast_Decaf", 49, 9.99, 0, 0)
)
Coffees.insertAll( testCoffees: _*)

//Assert coffee data equals to the test list of coffee
Query(Coffees).list must equalTo(testCoffees)

//List all coffee less than $10
val q1 = for { c <- Coffees if c.price < 10.0 } yield (c.name)

q1 foreach println
println("**************");

//return all suppliers for coffee less than $9.0
val q2 = for { c <- Coffees if c.price < 9.0
s <- c.supplier } yield (c.name, s.name)

q2 foreach println
println("**************");

//return all suppliers for coffee using zip
val q3 = for {
(c, s) <- Coffees zip Suppliers
} yield (c.name, s.name)

q3 foreach println
println("**************");

//Union
val q4 = Query(Coffees).filter(_.price < 8.0)
val q5 = Query(Coffees).filter(_.price > 9.0)
val unionQuery = q4 union q5
unionQuery foreach println
println("**************");

//Union second approach
val unionAllQuery = q4 unionAll q5
unionAllQuery foreach println
println("**************");

//Group by
val r = (for {
c <- Coffees
s <- c.supplier
} yield (c, s)).groupBy(_._1.supID)

//Aggregation
val r1 = r.map { case (supID, css) =>
(supID, css.length, css.map(_._1.price).avg)
}

r1 foreach println
}

In my next blog, I will take a real example and implement using Slick. I hope this blog helped.


 

Published at DZone with permission of Krishna Prasad, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)