なぜ作ったのか?
事の発端はSlickのこのイシューです。
GitBucketはServletベースということもあり、Slick3のDBIOは非同期実行のメリットが得られないのに複雑さだけが劇的に向上してしまうこと、プラグイン開発者にもモナディックなプログラミングを強いてしまうことなどから当面Slick3へのバージョンアップは行わず、Slick2に留まることにしていました。
しかし、Slickは場合によっては以下のような酷いSQLを生成することがあります。Slick3にはクエリコンパイラが改善されている(今後の改善も期待できる)という利点があるため、可能であるならバージョンアップしたいというのが正直なところでした。
そこで冒頭のようなイシューが上がっていたため、これはコントリビュートのチャンス、もしSlick3でSlick2互換のブロッキングAPIが利用できるようになればGitBucketをほぼ無傷でSlick3に移行でき、クエリコンパイラの改善というメリットを享受することができるという期待がありました。
というわけでプロトタイプも作って提案してみたのですが、自分のコミュ力不足もあってかあまり理解が得られず、埒が明かなそうだったので独自のライブラリとして提供することにしました。
使い方
build.sbt
に以下の依存関係を追加します。
libraryDependencies += "com.github.takezoe" %% "blocking-slick" % "0.0.1"
使っているデータベースに合わせて以下のようなオブジェクトを定義します。
package myapp.slick.driver import slick.driver.H2Driver import com.github.takezoe.slick.blocking.SlickBlockingAPI object BlockingH2Driver extends H2Driver with SlickBlockingAPI
このオブジェクトを以下のようにインポートするとブロッキングAPIが使えるようになります。
import myapp.slick.driver.BlockingH2Driver._ import myapp.slick.driver.BlockingH2Driver.api._
val db = Database.forURL("jdbc:h2:mem:test") db.withSession { implicit session => // Create tables models.Tables.schema.create // Insert Users.unsafeInsert(UsersRow(1, "takezoe")) // Select val users: Seq[UserRow] = Users.list // Select single record val user: UserRow = Users.filter(_.id === "takezoe".bind).first // Select single record with Option val user: Option[UserRow] = Users.filter(_.id === "takezoe".bind).firstOption // Update Users.filter(t => t.id === 1.bind).unsafeUpdate(UsersRow(1, "naoki")) // Delete Users.filter(t => t.id === 1.bind).unsafeDelete // Drop tables models.Tables.schema.remove }
トランザクションが必要な場合はwithSession
の代わりにwithTransaction
を使用します。
// Transaction
db.withTransaction { implicit session =>
...
}
以下にplay-slickと組み合わせてPlay2アプリケーションでこのブロッキングAPIを使った場合のサンプルもあります。
今後のScalaのORM事情
SlickはTypesafe社のプロジェクトだから使っていたというユーザも多いのではないかと思いますが、Lightbendのスタックから外れてしまった今となっては使い続けるべきなのか微妙なところではあります。クエリコンパイラも3.x系で改善されているとはいえまだ厳しいSQLになってしまうケースもあるみたいですし…。
ただ、今だと代替品に何を使うかというのが悩ましいところで、少し前から注目しているquillはマクロによる実装なので将来的にscalametaにちゃんと移行できるのか?という不安があります。ScalikeJDBCは学習コストが低く、生成されるSQLも素直なのでリスクが少ないと言えますが、国外での知名度という面でやや不安が残るところです。
そもそも海外ではSlickの厳しいSQLが問題になるようなRDBの使い方はレアケースなのか、Scalaに限らずRDB周りは昔から国内と海外の温度差を感じることが多いのですが、実際のところどうなのかというのは個人的には気になるところです。