seratch's weblog in Japanese

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

Yet Another DB Access Library for Scala

これは何?

ScalikeJDBC は私が開発している Scala で書かれた DB アクセスライブラリです。

最低限実現したいと思っていた機能は一通り実装し、実際に使いながらある程度の品質になったという感触を得たため、version 1.0.0 としてリリースしました。

https://github.com/seratch/scalikejdbc

以下のような感じで使うことができます。まずは DBSesssion インスタンスをベースに使う API の例です。

import scalikejdbc._
import org.joda.time.DateTime
case class User(id: Long, name: String, birthday: Option[DateTime])
val activeUsers: List[User] = DB readOnly { session =>
  session.list("select * from user where active = ?", true) { 
    rs => User(rs.long("id"), rs.string("name"), Option(rs.date("birthday")).map(_.toDateTime))
  }
}

こちらは最近になって追加された SQL.apply から始まる API の例です。

SQL API も DBSession とやれることは全く同じです。実装としては内部的に DBSession のメソッドを呼び出しています。

import scalikejdbc._
import org.joda.time.DateTime
case class User(id: Long, name: String, birthday: Option[DateTime])
val activeUsers: List[User] = DB readOnly { implicit session =>
  SQL("select * from user where active = ?").bind(true).map { 
    rs => User(rs.long("id"), rs.string("name"), Option(rs.date("birthday")).map(_.toDateTime))
  }.list.apply()
}

更新系やコネクション管理、トランザクションなどに関するより詳細な情報は GitHub の Wiki や BasicUsageSpec をご覧ください。

https://github.com/seratch/scalikejdbc/wiki
https://github.com/seratch/scalikejdbc/blob/master/src/test/scala/BasicUsageSpec.scala

とはいえ、全部手で書くの面倒だ・・

この手の薄いラッパーライブラリの場合、隠蔽された部分が少なく、固有の仕様の学習コストも低いというメリットがある反面、ライブラリの利用者は毎回同じようなコードをたくさん書く必要があるというデメリットはどうしても出てきます。

この問題に対処するために、コードを生成する sbt プラグインをつくりました。

https://github.com/seratch/scalikejdbc-mapper-generator

このようなテーブルに対して

create table member (
  id bigint generated always as identity,
  name varchar(30) not null,
  description varchar(1000),
  birthday date,
  created_at timestamp not null,
  primary key(id)
)

sbt "scalikejdbc-gen member" という感じでコマンドを実行するだけで、Scala のコードが自動生成されます。

既存のテーブルのカラム名、型、NOT NULL 制約、PK かどうかといった情報を取り出して、それをコードに反映します。

val member: Option[Member] = Member.find(123L)
val members: List[Member] = Member.findBy("name = ? and description is not null", "Martin")

val created: Member = Member.create(
  name = "Martin",
  description = Some("Scala Creator"),
  birthday = None,
  createdAt = new org.joda.time.DateTime
)
created.copy(name = "Martin Odersky").save()

Play20 で使うこともできます

Play framework 2.x ではデフォルトの Anorm 以外にも好きな DB アクセスライブラリを使うことができます。

ScalikeJDBC をより簡単に使えるように Play のプラグインを用意しました。

これを使えばデフォルトの conf/application.conf の設定と conf/play.plugins の追加だけですぐに動作するようになっています。

https://github.com/seratch/scalikejdbc-play-plugin

mapper-generator を project/plugins.sbt に追加すればコード生成を play コンソールでも使うことができます。

合わせて利用すれば、開発効率をあげることができると思います。


(5/11 追記)

SQL*1と実行時間をログ出力するオプション機能を追加しました。 1.0.3 から利用できます*2。GlobalSettings を書き換えると動作するようになります。

なんだかんだ開発しているとボトルネック調査でこういうのを仕込むことになるので、機能として提供されているとそれなりに便利ではないかと思います。

https://github.com/seratch/scalikejdbc/wiki/LoggingSQLAndTime


(5/13 追記)

version 1.1.0 をリリースしました。

https://github.com/seratch/scalikejdbc/issues?milestone=3&state=closed

いわゆる 2Way SQL と呼ばれているもののコメントとダミー値によるパラメータのバインディング部分のみを実装して、新しい機能として追加しました。こんな感じで使えます。

val activeUsers: List[User] = DB readOnly { implicit session =>
  SQL("select * from user where active = /*'active*/true")
    .bindByName('active -> true)
    .map { rs => User(rs.long("id"), rs.string("name"), Option(rs.date("birthday")).map(_.toDateTime))
    }.list.apply()
}

あと、適当だった Scaladoc をある程度充実させて、GitHub Pages で見られるようにしておきました。

http://seratch.github.com/scalikejdbc/api/index.html#scalikejdbc.package


自分自身が DB アクセスライブラリに欲しいと思うものは一通りそろった感があり、開発としては一段落したかな、というところです*3

もちろん、バグ修正や細かい改善は今後も続けていきます。また、フィードバックや pull request などぜひお待ちしております。

*1:実際に発行したものではなく再現イメージのレベルです

*2:1.0.1 と 1.0.2 には自動採番 ID の取得に関するバグがあったので使用しないでください

*3:あとは mapper-generator のバージョンアップが残っていますが