LoginSignup
9
8

More than 5 years have passed since last update.

Slickで共通のクエリを定義する方法

Posted at

概要

Slickで特定、もしくは複数のテーブルにおける共通のクエリを定義する方法です。

クラスにマップせず、できるだけQueryの状態で引き回すことでFRMとしての特性を最大限引き出すことが可能になります。

公式に上がっているプレゼン資料を参考にしましたので、より詳しく知りたい方はこちらもお読み下さい。

解説

複数のテーブルに共通のクエリを用意する

例えば全てのテーブルにidを定義し、table.filter(_.id === id)といった形でアクセスしたい場合、まずは以下の様なtraitを用意します。

WithId.scala

trait WithId {

  def id = column[Int]("id", O.PrimaryKey)
}

そしてTableクラスを作成する際にこのWithIdをミックスインします。

Coffee.scala

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でアクセスできるようになります。

QueryExtensions.scala

implicit class QueryExtensions[T <: WithId, E, _](val q: Query[T, E, _]) {

  def findById(id: column[Int]) = q.filter(_.id === id)
}

特定のテーブルに固有のクエリを用意する

例えば、Coffeesテーブルをcoffee_nameの値でフィルターしたい場合は、以下の様にします。

CoffeesExtensions.scala

implicit class CoffeesExtensions(val q: Query[Coffees, Coffee, _]) {

  def findByName(name: column[String]) = q.filter(_.name === name)
}

これで、CoffeesのテーブルにfindByNameでアクセスできるようになります。

どうやって利用するか

サンプルなどにあるCakeパターンを利用するのもいいですし、以下の用にtraitを用意して使いたい場所でミックスインすることもできます。

CoffeesComponent.scala

trait CoffeesComponent {

  val coffees = TableQuery[Coffees]

  implicit class CoffeesExtensions...
}

また、これらのQueryはそれぞれ利用先でチェーンしたり、他のテーブルとjoinすることもできます。
さらには、joinそのものも他のQueryを引数に取るメソッドを先ほどのQueryExtensionで定義することで共通化することができます。

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8