what is doobie? - database access for scala -
TRANSCRIPT
What is doobie ?- database access for scala -
2016-10-1第十七回 #渋谷java
Me島本 多可子(@chibochibo03)
株式会社ビズリーチ CTO室
普段はScalaを書いてます
直近の著書です →
Today's topic
doobieでできることをざっくり紹介
functional programming的な話はしません
scalazの細かい話はしません
Background
● Slick○ ScalaでメジャーなDBアクセスライブラリ
● 色々な意見があるが・・・
弁解できないのが
Performance
Hard!!
● whole query preparation timehttp://stackoverflow.com/questions/39725886/typical-performance-in-slick-ver-3-1-1
● join explain
(´・ω・`)ショボーン
他を模索してみる・・・
doobie
https://github.com/tpolecat/doobie
● ScalaのDBアクセスライブラリ
● ORMではない(重要)
● JDBCを使ったプログラムを書く手段を提供
doobie
キーワードは
pure FP SQLI/O
Supported releases
● 0.3.x (最新は0.3.0)○ JDK 1.8+○ Scala 2.10, 2.11, 2.12
● 0.2.x (最新は0.2.4)○ JDK 1.7+○ Scala 2.10, 2.11
doobie is pre-1.0
● 開発が活発
● 大きな変更もありえる
○ マイナーリリース(0.x)で非推奨になることも
Setup
● build.sbt
libraryDependencies ++= Seq( "org.tpolecat" %% "doobie-core" % 0.3.0)
Setup
● 必要なimport
import doobie.imports._import scalaz._, Scalaz._, concurrent.Task
Setup
● 接続情報
val xa = DriverManagerTransactor[Task]( "org.h2.Driver", "url", "user", "password")
Select
val id = 1val res = sql"select * from user where uid = $id" .query[User] .unique .transact(xa)
Select
val id = 1val res = sql"select * from user where uid = $id" .query[User] .unique .transact(xa)
(注)まだ実行されてないよ!
// Query0[User]
// ConnectionIO[User]
// Task[User]
Benefit
● actually constructing PreparedStatement○ SQLはPreparedStatementで実行
○ パラメータはsetString, setIntなどで設定される
● 破壊的なSQLにならない
● ソースコードだけで完結する
○ 別ファイルを行き来しなくてよい
Benefit
● 非同期が前提のものとの相性がよい
○ たとえばhttp4s
val service = HttpService { case req @ GET -> Root / "users"/ IntVar(uid) => Ok(findUser(uid))}
def findUser(uid: Int): Task[User] = ...
EntityEncoderを定義すればcase classをそのまま返せる
Insert
sql"insert into user (name, age) values (${u.name}, ${u.age})".update.run // ConnectionIO[Int]
Insert
for { id <- sql"insert into ...".update .withUniqueGeneratedKeys[Int]("uid") _ <- sql"insert into ... values ($id, ...)".update .run} yield id
特徴的な機能
What is YOLO mode ?
● REPLで便利な機能
○ transact(xa)してforeach(println)するのは煩雑
● 面倒な呼び出しをショートカットできる
○ quick・・結果を標準出力に
○ check・・Typecheckingを行う(後述)
YOLO - quick
import xa.yolo._
sql"select * from user where uid = $id" .query[User] .quick .unsafePerformSync
必要
// Task[Unit]
Typechecking (experimental)
● DBスキーマに対してクエリを検証
○ マッピングする型が正しいか
● run-time check
YOLO - check
import xa.yolo._
sql"select * from user where uid = $id" .query[User] .check .unsafePerformSync
必要
YOLO - check
✓ SQL Compiles and Typechecks✕ C01 UID INTEGER (INTEGER) NOT NULL → String - INTEGER (INTEGER) is ostensibly coercible to String according to the JDBC specification but is not a recommended target type. Fix this by changing the schema type to CHAR or VARCHAR; or the Scala type to Int or JdbcType.✓ C02 NAME VARCHAR (VARCHAR) NOT NULL → String...
Unit Testing (experimental)
● UTでクエリの検証をサポート
○ 現在はSpecs2のみ
● doobie-contrib-specs2を依存関係に追加
○ doobie.contrib.specs2.analysisspec.AnalysisSpecをミッ
クスイン
Unit Testing (experimental)
object xxx extends Specification with AnalysisSpec { val transactor = DriverManagerTransactor[Task]( "org.mysql.jdbc.Driver", "url", "user", "password" ) check(sql"select * from user".query[User])}
(注)存在するスキーマに対して実行
yoloのインポートは不要
まとめ
Conclusion
● スタイル
○ SQLを書く
○ functional programming● SQLの妥当性はテストで行う
● scalazを扱うものと相性がよい
○ http4sとか
Conclusion
● 前述したことがデメリットとなるケースも
● 機能が大きく変わる可能性あり
○ 1.0まで遠い・・・
● 吟味してから使いましょう