While creating my application with Play Framework 2.3, I've spent lots of time for searching some things that seemed to be easy at first glance. One of such a thing was the use of PostgreSQL specific types: hstore and enums. I found a great library for that. Slick-pg provides good covers for the most of the PostgreSQL specific data types. However, I bumped into some problems using enums, so I provide here my example of using it (+ hstore + date). Hope, it'll be helpfull.
build.sbt (Add all necessary dependencies)
build.sbt (Add all necessary dependencies)
libraryDependencies ++= Seq( cache, ws, "org.postgresql" % "postgresql" % "9.3-1100-jdbc41", "com.typesafe.slick" %% "slick" % "2.1.0", "com.typesafe.play" %% "play-slick" % "0.8.0", "com.github.tminglei" %% "slick-pg" % "0.6.3" )
First of all you need to enable Hstore and create a enum type in your database.
CREATE EXTENSION IF NOT EXISTS hstore;
CREATE TYPE pg_enum_type AS ENUM ('CREATED', 'JOINED', 'CLOSED');
app.utils.helpers.PostgresDriverPlus.scala (extend standart PostgreSQL driver with slick-pg)
package utils.helpers
import com.github.tminglei.slickpg._
import slick.driver.PostgresDriver
import models.MyTableStatus
trait WithPostgresDriver {
val driver: PostgresDriverPlus
}
trait PostgresDriverPlus extends PostgresDriver
with PgHStoreSupport
with PgEnumSupport
with PgDateSupport{
override lazy val Implicit = new ImplicitsPlus {}
override val simple = new SimpleQLPlus {}
trait EnumImplicits {
implicit val myTableStatusTypeMapper = createEnumJdbcType("pg_enum_type", MyTableStatus )
implicit val myTableStatusTypeListMapper = createEnumListJdbcType("pg_enum_type", MyTableStatus )
implicit val myTableStatusExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder(MyTableStatus)
}
trait ImplicitsPlus extends Implicits
with HStoreImplicits
with DateTimeImplicits
with EnumImplicits
trait SimpleQLPlus extends SimpleQL with ImplicitsPlus
}
object PostgresDriverPlus extends PostgresDriverPlus
app.models.MyTable.scala (all type mappers are here)
package models
import play.api.Play.current
import play.api.db.slick.{ DB, Session }
import utils.helpers.PostgresDriverPlus.simple._
import java.sql.{Timestamp, Date}
import scala.Enumeration
object MyTableStatus extends Enumeration {
type MyTableStatus = Value
val CREATED = Value("CREATED")
val JOINED = Value("JOINED")
val CLOSED = Value("CLOSED")
}
case class MyTable(id: Option[Int], date_start: Timestamp, status: MyTableStatus.MyTableStatus, date_finish: Date, spec: Map[String, String])
class MyTables(tag: Tag) extends Table[MyTable](tag, "mytable") /*Don't forget to be "mytable" in small letters!!! */ {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def date_start = column[Timestamp]("date_start", O.NotNull)
def status = column[MyTableStatus.MyTableStatus]("status", O.NotNull)
def date_finish = column[Date]("date_finish", O.NotNull)
def spec = column[Map[String, String]]("spec", O.NotNull) //hstore is mapped to Map[String, String]
def * = (id.?, date_start, status, date_finish, spec) <> (MyTable.tupled, MyTable.unapply)
}
object MyTables extends TableQuery(new MyTables(_)) {
def findById(id: Int): Option[MyTable] = {
DB withSession {
implicit session: Session =>
MyTables.filter(_.id === id).firstOption
}
}
def all = {
DB withSession {
implicit session: Session =>
MyTables.run
}
}
def create(myTable: MyTable) = {
DB withSession {
implicit session: Session =>
MyTables.insert(myTable)
}
}
}
So now you can use your model, for example, to insert data. You can run the following with "test-only InsertTestData" command.
test.InsertTestData.scala
import org.specs2.mutable.Specification
import org.specs2.runner._
import org.junit.runner._
import play.api.test._
import play.api.test.Helpers._
import play.api.Play.current
import models._
import scala.collection.immutable.HashMap
@RunWith(classOf[JUnitRunner])
class InsertTestData extends Specification {
"MyTables insert" should {
"insert test data if MyTable model is empty" in {
running(FakeApplication()) {
if (MyTables.all.isEmpty) {
import java.sql.Timestamp
import java.text.SimpleDateFormat
val sdf = new SimpleDateFormat("dd-M-yyyy")
val joinBefore = "17-12-2014"
val dateExpiry = "31-12-2014"
MyTables.create(MyTable(None, new Timestamp((new java.util.Date).getTime()), MyTableStatus.CREATED,
new java.sql.Date(sdf.parse(dateExpiry).getTime()),
HashMap("type" -> "SuperType", "bla" -> "alb", "qwerty" -> "asdf")
))
}
MyTables.all must not be empty
}
}
}
}
0 коммент.:
Отправить комментарий