Slick3ではクエリ(DBIOAction
)の構築と実行とが分離されていて、予めクエリを合成した上で一つの機能にしてから実行できる。
そのうちいくつか試したものを備忘録としてメモする。
存在しなければINSERTを実行 その1
アカウントテーブルのTableQuery
に対して、アプリケーション初期化時にレコードがなければINSERTを実行する方法
// class Accounts(tag: Tag) extends Table[Account]("ACCOUNTS", tag) { ... }
val accounts = TableQuery[Accounts]
val initialAccount = Account(...)
val insertIfEmpty = accounts.length.result.filter(_ == 0).flatMap(_ => accounts += initialAccount) // クエリ構築
db.run(insertIfEmpty) // 実行
-
accounts.length.result
が一つ目のクエリ。.result
によってRep[Int]
からDBIOAction[Int, NoStream, Read]
への変換が行われる。 -
DBIOAction[R,S,E]
はR
のコレクションとみなしたいくつかの操作が可能で、今回の例ではfilter
,flatMap
を用いている。 -
.filter(_ == 0)
により、レコードがない場合だけ処理を続行するようにする -
.flatMap { _ => accounts += initialAccount }
でこれまでの結果(0)はとりあえず無視して、initialAccount
の挿入を実行する。挿入処理がDBIOAction
であるため、flatMap
で合成できる。
存在しなければINSERTを実行 その2
特定のIDが存在しなければ挿入を実行し true
を返す。IDがすでに存在している場合はINSERTは実行せずに false
を返す。
val account = Account(...)
val insertIfNotExists = accounts.filter(_.id === account.id).exists.result.flatMap {
case true => DBIO.successful(false)
case false => (accounts += account).andThen(DBIO.successful(true))
}.transactionally
-
.filter(_.id === account.id).exists.result
で指定のIDが存在するかどうか試す -
true
(存在する)の場合はfalse
を返すアクションを生成して返す -
false
(存在しない)の場合は挿入を実行してからtrue
を返すアクションを生成して返す -
.transactionally
で一連のトランザクション処理にする