Thursday, March 20, 2014

Scala Migration 2.9 to 2.10 part 1 - from ScalaQuery to Slick

So , as it happens to be, migrating from scala 2.9 to 2.10 (And Akka,ScalaQuery) is not straight forward as one might think ...
for Akka upgrade I used this excellent document for migration 1.3.x to 2.0 and this on for migrating to 2.1

changing ScalaQuery to Slick is quite straight forward - changing the entities
i.e ScalaQuery (two columns as pk) :

  case class Foo_entity ( foo_id_col: String ,  foo_name_col: Long  )
  object  or_foo extends Table[Foo_entity]("foo") {
    def foo_id_col = column[String]("foo_id")
    def foo_name_col = column[Long]("foo_name")
    def pk = primaryKey("pk_foo",foo_id_col~foo_name_col)
    def * = foo_id_col ~ foo_name_col<>(Foo_entity,Foo_entity.unapply(_))
  }

in Slick turns to :

   case class Foo_entity ( foo_col: String ,  foo_name_col: Long  )
  class Foo(tag:Tag) extends Table[Foo_entity](tag,"foo") {
    def foo_col = column[String]("id")
    def foo_name_col = column[Long]("name")
    def pk = primaryKey("pk_round_player",(foo_col,foo_name_col))
    def * = (foo_col,foo_name_col)<>(Foo_entity.tupled,Foo_entity.unapply)
  }
  val or_foo = TableQuery[Foo]

or with single col as pk
case class Foo_entity ( foo_col: String ,  foo_name_col: Long  )
  class Foo(tag:Tag) extends Table[Foo_entity](tag,"foo") {
    def foo_col = column[String]("id",O.PrimaryKey)
    def foo_name_col = column[Long]("name")
       def * = (foo_col,foo_name_col)<>(Foo_entity.tupled,Foo_entity.unapply)
  }
  val or_foo = TableQuery[Foo]

writing queries with slick are more "Scalaish" and more functional so instead of writing this code with 
ScalaQuery :
  val db = Database.forDataSource(...)
 def getFooInfo(fooId: String):List[DB.foo_entity] = {
    val data = for{
      foo <- DB.or_foo if (foo.foo_id_col === fooId)
        _ <-Query.orderBy(foo.foo_order_col.asc)

    } yield foo

    db.withSession((s:Session) => {
      data.list()(s)
    })
  }

you can write in Slick :
  val db = Database.forDataSource(...)
def getFooInfo(fooId: String): List[DB.foo_entity] = {
    val data =DB.or_foo.filter(_.round_id_col === roundId).sortBy(_.foo_order_col.asc)
    db.withSession{implicit session =>
      data.list
    }
  }

also creating Transaction and getting the last id inserted is quite elegant with slick
ScalaQuery: 

  def lastInsertedId: Long = {
    val scopeIdentity = SimpleFunction.nullary[Long]("LAST_INSERT_ID")
    db.withSession((s: Session) => {
      Query(scopeIdentity).first()(s)
    })
  }

  def createTransaction(from: Long, to: Long, amount: Long): Long = {
    db.withTransaction((s: Session) => {
      DB.or_transaction.insert(DB.transaction_entity(None, from, to, amount, 0, null))(s)
      lastInsertedId
    })
  }

and Slick notice the use of the returning keyword:
def createTransaction(from: Long, to: Long, amount: Long): Long = {
    db.withTransaction{implicit session =>
      (or_transaction returning or_transaction.map(_.transaction_id_col.getOrElse(0))) +=transaction_entity(None, from, to, amount, 0, null)
    }
  }