[Play] AnormでダイナミックSQL

Anorm面倒ですね。
静的なパラメータクエリは簡単にできますが、動的にwhere句・パラメータを生成しなければならない場合もあるわけで。。

SQLのwhereについては単なる文字列なのでどうとでもなりますが、問題はon{・・}に記述するパラメータです。
これにはすっごく悩みましたが下記の方法にて動的にwhereの生成とパラメータの設定を行う事が可能です。

val datamap = { //(省略)マッピング定義 }

def selectBooks(offset: Int, pageSize: Int, orderBy: String
    , filterTitle: Option[String] = None,filterAuthor:Option[Int] = None):List[Book] = {
  DB.withTransaction { implicit connection => 
  
    // 条件をtupleで定義する(項目ID,条件演算子,値)
	// 無視する条件は値にNoneを設定
    val conditions = Seq(
      ("title", "like",filterTitle),
      ("author_id", "=",filterAuthor)
    )
	
    // Someな値を抽出してwhere句を生成
    val filterString = conditions.filter(_._3.isDefined).map(flt => {
      "%s %s {%s}".format(flt._1,flt._2,flt._1)
    }).mkString(" where "," and ","")
    
	// 同じくSomeな値に対してのパラメータリストを作成
    val filterParams = conditions.filter(_._3.isDefined).map(flt => { 
      flt._1 -> toParameterValue(flt._3)
    })       
	
	// 常に設定するパラメータを作成
    val baseParams =  Seq(
      "pageSize" -> toParameterValue(Option(pageSize)),
      "offset" -> toParameterValue(Option(offset))
    )
	// パラメータのリストを結合
    val params = baseParams ++ filterParams

    // queryを実行
    SQL("""
        select * from books
        %s order by %s limit {pageSize} offset {offset}         
        """.format(filterString,orderBy))        
        .on(params: _* )
        .as(datamap *)
  }
}

条件項目をOptionで受け取り、Someな項目のみを条件として設定しています。
もうちょっと綺麗に書きたいのですが、イマイチscala的な書き方が良くわかっていないので。。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です