読者です 読者をやめる 読者になる 読者になる

Scala用のシンプルなJDBCラッパーを作ってみた

以前からちょっとしたものを作るときに便利なIO関連のユーティリティをまとめたScalaライブラリを作っていたのですが、最近ScalaのIOライブラリはbetter-filesがよさげなのでこちらに乗り換えるのがいいかなと思ったところ、自作ライブラリにあるJDBC周りの機能がbetter-filesにはなかったので自作ライブラリから単独で使えるライブラリとして切り出してみました。

github.com

こんな感じの依存関係をbuild.sbtに追加して、

resolvers += "amateras-repo" at "http://amateras.sourceforge.jp/mvn/"

libraryDependencies += "com.github.takezoe" %% "better-jdbc" % "1.0.0"

以下のインポート文で使えるようになります。

import better.jdbc._

SELECTはこんな感じ。SQLは文字列またはsqlというString Interpolationでパラメータを埋め込んだものを渡すことができます。コールバックにResultSetが渡されるのでそこで必要な値を抽出します。DBUtilsみたいな感じですね。

val users: Seq[(Int, String)] = DB.autoClose(conn) { db =>
  db.select("SELECT * FROM USERS"){ rs =>
    (rs.getInt("USER_ID"), rs.getString("USER_NAME"))
  }
}

selectFirstで先頭の1件だけをOptionで取得できます。カウントとかを取得する場合用にselectIntとかselectStringという便利メソッドもあります。

val user: Option[(Int, String)] = DB.autoClose(conn) { db =>
  db.selectFirst(sql"SELECT * FROM USERS WHERE USER_ID = $userId"){ rs =>
    (rs.getInt("USER_ID"), rs.getString("USER_NAME"))
  }
}

ファクトリメソッドを渡してケースクラスにマッピングすることもできます。

case class User(userId: Int, userName: String)

val users: Seq[User] = DB.autoClose(conn) { db =>
  db.select("SELECT USER_ID, USER_NAME FROM USERS", User.apply)
}

更新系はupdateメソッドを使います。

DB.autoClose(conn) { db =>
  db.update(sql"INSERT INTO USERS (USER_ID, USER_NAME) VALUES ($userId, $userName)")
}

トランザクションはこんな感じ。

DB.autoClose(conn) { db =>
  db.transaction {
    db.update(sql"DELETE FROM GROUP WHERE USER_ID = $userId")
    db.update(sql"DELETE FROM USERS WHERE USER_ID = $userId")
  }
}

簡単なものですが、こういうの何度も自作している気がするのですぐに使える状態のライブラリがあると便利かなと思います。