概要
Slickで特定、もしくは複数のテーブルにおける共通のクエリを定義する方法です。
クラスにマップせず、できるだけQuery
の状態で引き回すことでFRMとしての特性を最大限引き出すことが可能になります。
公式に上がっているプレゼン資料を参考にしましたので、より詳しく知りたい方はこちらもお読み下さい。
解説
複数のテーブルに共通のクエリを用意する
例えば全てのテーブルにid
を定義し、table.filter(_.id === id)
といった形でアクセスしたい場合、まずは以下の様なtrait
を用意します。
trait WithId {
def id = column[Int]("id", O.PrimaryKey)
}
そしてTable
クラスを作成する際にこのWithId
をミックスインします。
class Coffees(tag: Tag) extends Table[Coffee](tag, "coffees") with WithId {
def name = column[String]("coffee_name")
def * = (id, name) <> (Coffee.tuppled, Coffee.unapply)
}
さらに、以下の様なimplicit class
を定義してやることで、全てのテーブルクラスに対してfindById
でアクセスできるようになります。
implicit class QueryExtensions[T <: WithId, E, _](val q: Query[T, E, _]) {
def findById(id: column[Int]) = q.filter(_.id === id)
}
特定のテーブルに固有のクエリを用意する
例えば、Coffees
テーブルをcoffee_name
の値でフィルターしたい場合は、以下の様にします。
implicit class CoffeesExtensions(val q: Query[Coffees, Coffee, _]) {
def findByName(name: column[String]) = q.filter(_.name === name)
}
これで、Coffees
のテーブルにfindByName
でアクセスできるようになります。
どうやって利用するか
サンプルなどにあるCakeパターンを利用するのもいいですし、以下の用にtrait
を用意して使いたい場所でミックスインすることもできます。
trait CoffeesComponent {
val coffees = TableQuery[Coffees]
implicit class CoffeesExtensions...
}
また、これらのQuery
はそれぞれ利用先でチェーンしたり、他のテーブルとjoin
することもできます。
さらには、join
そのものも他のQuery
を引数に取るメソッドを先ほどのQueryExtension
で定義することで共通化することができます。