Skip to content

Instantly share code, notes, and snippets.

@gakuzzzz
Created May 21, 2013 09:14
Show Gist options
  • Save gakuzzzz/5618518 to your computer and use it in GitHub Desktop.
Save gakuzzzz/5618518 to your computer and use it in GitHub Desktop.
ScalikeJDBC つれづれ
  def cond[A](value: A)(f: PartialFunction[A, SQLBuilder => SQLBuilder]): SQLBuilder

こんな感じの(実際にはSQLBuilderはサブクラス型にしないとだけど)あれば下みたいに書けるかなー

  val id: Option[Int] = ...
  val name: Option[String] = ...

  select(c.*)
    .from(Customer as c)
    .where
    .cond(id) { case Some(i) => _.eq(c.id, i) }
    .and
    .cond(name) { case Some(n) => _.eq(c.name, n) }

と思うけど、 .where とか .and とかはどうしょうもなくてぐぬぬ

@seratch
Copy link

seratch commented May 21, 2013

やはりこういうのは #map の中に閉じ込めるのが良いのではないか・・

select(c.*)
  .from(Customer as c)
  .map { sql => 
    val conditions = Seq(
      id.map(i => sqls"${c.id} = ${i}"),
      name.map(n => sqls"${c.name} = ${n}")
    ).flatten
    val clause = SQLSyntax.join(conditions, sqls"and")
    if (clause.isEmpty) sql else sql.where.clause
  }

上記を共通化したこれくらいのものはあってもよい気はする。

select(c.*)
  .from(Customer as c)
  .where
  .andConditions(
    id.map(i => sqls"${c.id} = ${i}"), 
    name.map(n => sqls"${c.name} = ${n}")
  )

andConditions は all くらいでもいいのかも。or でつなぐときは any とか。where の直後じゃなくても使える。連続パラメータの場合 Option[SQLSyntax]* と SQLSyntax* で別のメソッド名にしないとダメ。

@gakuzzzz
Copy link
Author

andConditons いいですね。

Option[SQLSyntax] の代わりに Option[SQLBuilder => SQLBuilder] 受け取れるようにしたら

select(c.*)
  .from(Customer as c)
  .where
  .andConditions(
    id.map(i => _.eq(c.id, i)), 
    name.map(n => _.eq(c.name, n))
  )

って書けませんかね?
引数型必要になっちゃいますかね…

@gakuzzzz
Copy link
Author

あ、 両方とも None だった場合に where が浮く……

@gakuzzzz
Copy link
Author

FROM句の事考えたら、 連結文字の無い版も必要なのかなー

val (c, cg) = (Customer.syntax, CustomerGroup.syntax)

val id: Option[Int] = ...
val groupName: Option[String] = ...

select(c.*)
  .from(Customer as c)
    .flatMap(sql => groupName.map(n => sql.innerJoin(CustomerGroup as cg).on(cg.id, c.groupId)))
  .where
  .andConditions(
    id.map(i => _.eq(c.id, i)), 
    groupName.map(n => _.eq(cg.name, n))
  )

@seratch
Copy link

seratch commented May 21, 2013

それってこれの前段階でチェックする話な気もするんですけどね。where なしで全件検索してそれが意図する挙動なのかという。>両方とも None だった場合に where が浮く……

@seratch
Copy link

seratch commented May 21, 2013

val sqls = scalikejdbc.interpolation.SQLSyntax

とか追加して(名前は sqls じゃなくてもいいけど)どこでも

sqls.eq((c.id, 123)
sqls.isNotNull(c.name)

とか書ければそれでいいんじゃないかと。手元ではとりあえず動く実装を確認できたし。

そうすれば

select(c.*)
  .from(Customer as c)
  .where
  .andConditions(
    id.map(i => sqls.eq(c.id, i)),
    name.map(n => sqls.eq(c.name, n))
  )

が動作します。

@gakuzzzz
Copy link
Author

それってこれの前段階でチェックする話な気もするんですけどね。where なしで全件検索してそれが意図する挙動なのかという。

一覧画面で特に条件ないときは全件(ページネイトはするけど)取得で、追加でフィルター条件が付けられる、みたいな機能のイメージしてました

val sqls = scalikejdbc.interpolation.SQLSyntax

おー、これいいですね。たしかにそれくらいの表記ならすっきりする気がします。

@gakuzzzz
Copy link
Author

ScalikeJDBC の Issue で会話した方が通知きていいような気がしたけど日本語ばんざい

@seratch
Copy link

seratch commented May 21, 2013

下地の準備はできたけど、いい名前が思いつかない。

単純に and/or もまだメソッド名としては空いているけど、直前に .and とか .or を呼ぶ場合もあり得るのでそうすると and(SQLSyntax*) は紛らわしい。.or.or(...) になっていないとシンタックスエラーとか罠すぎる。

select(o.result.id)
  .from(Order as o)
  .where.withRoundBracket(_.and(
    sqls.eq(o.productId, 1), 
    sqls.isNotNull(o.accountId)
  ))
  .or.or(sqls.isNull(o.accountId))

xxxConditions はちょっと説明的すぎる感があって微妙な気がする。

select(o.result.id)
  .from(Order as o)
  .where.withRoundBracket(_.andConditions(
    sqls.eq(o.productId, 1), 
    sqls.isNotNull(o.accountId)
  ))
  .or.orConditions(sqls.isNull(o.accountId))
  .where.withRoundBracket(_.andOptionalConditions(
    id.map(i => sqls.eq(o.productId, i)), 
    Some(sqls.isNotNull(o.accountId))
  ))
  .or.orOptionalConditions(Some(sqls.isNull(o.accountId)))

andAll/andOpt とかも考えたが、初見で意味が分かりづらいのでよくないかと。文字列の結合ということで join 何とかみたいな名前も考えたがテーブル結合と紛らわしいので避けたいし、で決まらず。

@gakuzzzz
Copy link
Author

名前むずかしい……。

僕は今上がってる中では andConditions, orConditions が良いように思ってます。

というのも、標準SQLの予約語じゃないメソッドは多少説明的で長いほうが見分けもついていいような気がするので。

@seratch
Copy link

seratch commented May 22, 2013

dynamicAndConditions / dynamicOrConditions という名前なら私はそんなに違和感ないですね。

https://github.com/seratch/scalikejdbc/blob/feature/dynamic-conditions/scalikejdbc-interpolation/src/test/scala/scalikejdbc/QueryInterfaceSpec.scala#L126-L177

@gakuzzzz
Copy link
Author

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment