概要
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で定義することで共通化することができます。