seratch's weblog in Japanese

About Scala, Java and Ruby programming in Japaense. If you need English information, go to http://blog.seratch.net/

3 分でできる Play2 で Skinny ORM を使う手順 #play_ja

これは Play framework 2.x Scala Advent Calendar 2013 の 8 日目です。

http://www.adventar.org/calendars/114

ご存知の方もいるかと思いますが、私は Skinny Framework というフレームワークをつくっています。これのコンポーネントは基本的に Skinny Framework 以外でも使えるようにつくられていて、その一つである Skinny ORM がある程度使える ORM として育ってきました。まだドキュメントはそれほど充実していませんが、こちらをご覧ください。

http://skinny-framework.org/documentation/orm.html

この Skinny ORM は ScalikeJDBC という DB ライブラリをより ORM 的に使えるようにするために、ScalikeJDBC を土台につくられています。ScalikeJDBC と Play2 の連携は以前から実装されていて、実績もあります。

http://scalikejdbc.org/

Skinny ORM を Play ユーザの皆さんにもぜひ使っていただきたいので、今回は導入までの手順を紹介します。

Play アプリをつくる

この時点では Play 2.2.1 が最新です。私のように最近 play コマンド使ってないなーという方は brew upgrade play しておきましょう。

play new play-with-skinny-orm
cd play-with-skinny-orm

build.sbt を書き換える

build.sbt をこのように書き換えてください。

name := "play-with-skinny-orm"

version := "1.0-SNAPSHOT"

libraryDependencies ++= Seq(
  "org.skinny-framework" %% "skinny-orm"              % "0.9.29",
  "org.scalikejdbc"      %% "scalikejdbc-play-plugin" % "1.7.1",
  "com.h2database"       %  "h2"                      % "1.3.174"
)

play.Project.playScalaSettings

conf/play.plugins

Play に ScalikeJDBC ベースのコネクションマネージメントを伝えるために、ScalikeJDBC の Play プラグインを追加します。

10000:scalikejdbc.PlayPlugin

conf/application.conf

Play の DB 設定を更新します。今回の説明の都合上、H2 をファイルベースの DB に変えてください。

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:file:play"
db.default.user=sa
db.default.password=""

conf/db/migration/V1__Create_companies.sql

DB マイグレーション用ファイルをつくってください。V1__ のアンダースコアは二つなので気をつけてください。Flyway のファイルです。今回は手動でマイグレーションを実行します。

create table company (
  id bigserial not null primary key,
  name varchar(64) not null,
  url varchar(128),
  created_at timestamp not null,
  updated_at timestamp,
  deleted_at timestamp
);

app/models/Company.scala

Skinny ORM では SkinnyCRUDMapper という trait を継承すると基本的な CRUD 操作はすぐに使えるようになります。

https://github.com/skinny-framework/skinny-framework/blob/develop/orm/src/main/scala/skinny/orm/feature/CRUDFeature.scala

package models

import scalikejdbc._, SQLInterpolation._
import skinny.orm._, feature._
import org.joda.time.DateTime

case class Company(
  id: Long,
  name: String,
  url: Option[String] = None,
  createdAt: DateTime,
  updatedAt: Option[DateTime] = None,
  deletedAt: Option[DateTime] = None)

object Company extends SkinnyCRUDMapper[Company]
    with TimestampsFeature[Company]
    with SoftDeleteWithTimestampFeature[Company] {

  override val defaultAlias = createAlias("c")

  override def extract(rs: WrappedResultSet, c: ResultName[Company]): Company = new Company(
    id = rs.long(c.id),
    name = rs.string(c.name),
    url = rs.stringOpt(c.url),
    createdAt = rs.dateTime(c.createdAt),
    updatedAt = rs.dateTimeOpt(c.updatedAt)
  )
}

app/controllers/Application.scala

説明を簡略化するためにただ toString しています。

package controllers

import play.api._
import play.api.mvc._
import models.Company

object Application extends Controller {

  def index = Action {
    Ok(Company.findAll().toString)
  }
}

手動で DB マイグレーション

今回はさらっと試すだけなので play console でマイグレートしてしまいましょう。

skinny.DBSettings.initialize()
skinny.dbmigration.DBMigration.migrate()

例外がでなければ成功です。こんな感じで model が使えるようになりました。console から試してみてください。

skinny.DBSettings.initialize()
import models._
Company.count()
Company.createWithAttributes('name -> "Typesafe")
Company.findAll()

console で実行した結果を貼付けておきますね。

$ sbt console

[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> skinny.DBSettings.initialize()

scala> import models._
import models._

scala> Company.count()
res1: Long = 0

scala> Company.createWithAttributes('name -> "Typesafe")
res2: Long = 1

scala> Company.findAll()
res3: List[models.Company] = List(Company(1,Typesafe,None,2013-12-08T20:03:36.771+09:00,None,None))

play run

最後に play run で Play アプリにちゃんと組み込まれたか確認します。

play run

ブラウザから http://localhost:9000/ にアクセスして正常に表示されれば OK です。

最終的にはこのようなファイル構成となりました。

.
├── README
├── app
│   ├── controllers
│   │   └── Application.scala
│   ├── models
│   │   └── Company.scala
│   └── views
│       ├── index.scala.html
│       └── main.scala.html
├── build.sbt
├── conf
│   ├── application.conf
│   ├── db
│   │   └── migration
│   │       └── V1__Create_companies.sql
│   ├── play.plugins
│   └── routes
├── logs
│   └── application.log
├── play.h2.db
├── project
│   ├── build.properties
│   └── plugins.sbt
├── public
│   ├── images
│   │   └── favicon.png
│   ├── javascripts
│   │   └── jquery-1.9.0.min.js
│   └── stylesheets
│       └── main.css
└── test
    ├── ApplicationSpec.scala
    └── IntegrationSpec.scala

14 directories, 19 files

明日は unokazuhiko さんです。その次の日からまた空いてますけどね・・・

http://www.adventar.org/calendars/114