先日少し試してみたquillですが、クエリを動的に変更したい場合がちょっと面倒です。マクロで処理されているためあまり自由度がなく、以下のようにfilter
の条件を分岐させることはできるのですが、Slickのようにプログラムでクエリを自由に組み立てるということはできません。
val account: Option[Account] = db.run( quote { (mailAddress: String, includeRemoved: Boolean) => query[Account].filter { t => if(includeRemoved){ t.mailAddress.toLowerCase == mailAddress.toLowerCase } else { t.mailAddress.toLowerCase == mailAddress.toLowerCase && t.removed == false } } } )(mailAddress, includeRemoved).headOption
上記のクエリは以下のようなSQLを出力します。どうやらif
がCASE
に置き換えられるようです。
SELECT ... FROM account t WHERE CASE WHEN ? THEN LOWER (t.mail_address) = LOWER (?) ELSE (LOWER (t.mail_address) = LOWER (?)) AND (t.removed = false) END
なので一応こんなこともできます。
val account: Option[Account] = db.run( quote { (mailAddress: String, includeRemoved: Boolean) => query[Account].filter { t => t.mailAddress.toLowerCase == mailAddress.toLowerCase && ( if(includeRemoved){ 1 == 1 } else { t.removed == false } ) } } )(mailAddress, includeRemoved).headOption
出力されるSQLは以下のようになります。
SELECT ... FROM account t WHERE (LOWER (t.mail_address) = LOWER (?)) AND CASE WHEN ? THEN true ELSE t.removed = false END
シンプルなケースであれば以下のようにクエリそのものをまるっと置き換えたほうが手っ取り早いかもしれません。
val accounts: List[Account] = db.run( if(includeRemoved){ quote { query[Account].sortBy(_.userName) } } else { quote { query[Account].filter(_.removed == false).sortBy(_.userName) } } )
ユーザの入力に応じて検索条件が変わるようなクエリの場合はちょっと面倒そうです。