ScalikeJDBCのSQLSyntaxProvider系まとめ

この記事は「Opt Technologies Advent Calendar 2017」の7日目です。

# はじめに

業務ではよく[ScalikeJDBC](http://scalikejdbc.org/)を使っているのですが、SQLSyntaxProvider系の挙動を中々覚えられないのでまとめてみました。

# 実験に使ったコード

ScalikeJDBC 3.1.0にて、以下のコードを用いました。

```scala
import scalikejdbc._

case class Member(id: Long, groupId: Long)
object Member extends SQLSyntaxSupport[Member] {
  override val columnNames = Seq("id", "group_id")
}
val m = Member.syntax("m")
val m2 = Member.syntax("m2")
val s = SubQuery.syntax("s").include(m, m2)
```

# 挙動
## ColumnSQLSyntaxProvider（`Member.column`）

|式|結果|コメント|
|---|---|---|
|Member.column.columns|List(sqls"id", sqls"group_id")||
|Member.column.*|sqls"id, group_id"||
|Member.column.asterisk|sqls"*"||
|Member.column.groupId <br> Member.column.field("groupId") <br> Member.column.column("group_id") | sqls"group_id" | |

## QuerySQLSyntaxProvider（`m`）

|式|結果|コメント|
|---|---|---|
|m.columns|List(sqls"id", sqls"group_id")||
|m.*|sqls"m.id, m.group_id"||
|m.asterisk|sqls"m.*"||
|m.groupId <br> m.field("groupId") <br> m.column("group_id") | sqls"m.group_id" | |

## ResultSQLSyntaxProvider（`m.result`）

|式|結果|コメント|
|---|---|---|
|m.result.columns|List(sqls"id", sqls"group_id")||
|m.result.*|sqls"m.id as i_on_m, m.group_id as gi_on_m"||
|m.result.groupId <br> m.result.field("groupId") <br> m.result.column("group_id")|sqls"m.group_id as gi_on_m"||

## PartialResultSQLSyntaxProvider(`m.result(sqls"foo")`)

|式|結果|コメント|
|---|---|---|
|m.result(sqls"foo").columns|List(sqls"id", sqls"group_id")||
|m.result(sqls"foo").groupId <br> m.result(sqls"foo").field("groupId") <br> m.result(sqls"foo").column("group_id")| sqls"foo as gi_on_m"| `min(m.id) as i_on_m` のように使う想定かと思います |

## BaseResultNameSQLSyntaxProvider（`m.resultName`）

|式|結果|コメント|
|---|---|---|
|m.resultName.columns|List(sqls"id", sqls"group_id")||
|m.resultName.namedColumns|List(sqls"i_on_m", sqls"gi_on_m")||
|m.resultName.*|sqls"i_on_m, gi_on_m"||
|m.resultName.groupId <br> m.resultName.field("groupId") <br> m.resultName.column("group_id") <br> m.resultName.namedColumn("gi_on_m")|sqls"gi_on_m"||

## SubQuerySQLSyntaxProvider（`s`）

|式|結果|コメント|
|---|---|---|
|s.*|sqls"s.i_on_m, s.gi_on_m, s.i_on_m2, s.gi_on_m2"||
|s.asterisk|sqls"s.*"||
|s(sqls"gi_on_m")|sqls"s.gi_on_m"||

## SubQueryResultSQLSyntaxProvider（`s.result`）

|式|結果|コメント|
|---|---|---|
|s.result.*|sqls"s.i_on_m as i_on_m_on_s, s.gi_on_m as gi_on_m_on_s, s.i_on_m2 as i_on_m2_on_s, s.gi_on_m2 as gi_on_m2_on_s"||
|s.result.column("gi_on_m")|InvalidColumnNameException|バグっぽかったので[PR](https://github.com/scalikejdbc/scalikejdbc/pull/787)してみました|

## SubQueryResultNameSQLSyntaxProvider（`s.resultName`）

|式|結果|コメント|
|---|---|---|
|s.resultName.columns|ArrayBuffer(sqls"i_on_m_on_s", sqls"gi_on_m_on_s", sqls"i_on_m2_on_s", sqls"gi_on_m2_on_s")|ここだけListでなかったです|
|s.resultName.*|sqls"i_on_m_on_s, gi_on_m_on_s, i_on_m2_on_s, gi_on_m2_on_s"||
|s.resultName(sqls"gi_on_m")<br>s.resultName.column("gi_on_m_on_s")|sqls"gi_on_m_on_s"||

## PartialSubQuerySQLSyntaxProvider（`s(m)`）

|式|結果|コメント|
|---|---|---|
|s(m).*|sqls"s.i_on_m_on_s, s.gi_on_m_on_s"||
|s(m).asterisk|sqls"s.*"||
|s(m).columns|List(sqls"id", sqls"group_id")||
|s(m).groupId<br>s(m).field("groupId")<br>s(m).column("group_id")<br>s(m)(sqls"gi_on_m")|sqls"s.gi_on_m"||


## PartialSubQueryResultSQLSyntaxProvider（`s(m).result`）

|式|結果|コメント|
|---|---|---|
|s(m).result.columns|List(sqls"id", sqls"group_id")||
|s(m).result.*|sqls"s.i_on_m as i_on_m_on_s, s.gi_on_m as gi_on_m_on_s"||
|s(m).result.field("gi_on_m")<br>s(m).result.column("gi_on_m")|sqls"s.gi_on_m as gi_on_m_on_s"|columnとfieldの引数が同じで少し違和感|
|s(m).result.groupId|InvalidColumnNameException|不具合かも？|

## PartialSubQueryResultNameSQLSyntaxProvider（`s(m).resultName`）

|式|結果|コメント|
|---|---|---|
|s(m).resultName.columns<br>s(m).resultName.namedColumns|List(sqls"i_on_m_on_s", sqls"gi_on_m_on_s")|columnsとnamedColumnsが一致して少し違和感|
|s(m).resultName.*|sqls"iom_on_s, gom_on_s"|バグっぽかったので[PR](https://github.com/scalikejdbc/scalikejdbc/pull/787)してみました|
|s(m).resultName.groupId<br>s(m).resultName.field("group_id")<br>s(m).resultName.column("group_id")<br>s(m).resultName(sqls"gi_on_m")|sqls"gi_on_m_on_s"|columnとfieldの引数が同じで少し違和感|
|s(m).resultName.namedColumn("gi_on_m")|sqls"gi_on_m"||

# おわりに

まとめてはみたものの、やはりSubQueryが絡むとややこしいですね。困った時に参考になればと思います。