LoginSignup
34
18

More than 5 years have passed since last update.

golang で 2 Way SQL

Posted at

空いていたので穴埋め。

はじめに

データベースを扱うプロジェクトでは、オンコードで SQL を書く事が割と多いのですが、そういったソースコードに埋め込まれた SQL はプレースホルダを使って値を取るので直接実行する事は出来ません。

select * from foo where id = :id and bar = :bar

RDBMS によっては :変数名 ではなく ?$1 といった表記をする物もあります。こういった SQL は直接実行できない為、どうしても結果がイメージし辛くなるのですが、2 Way SQL という方法を使う事で解決できる事があります。

2 Way SQL とは

2 Way SQL は SQL のコメントに IF や ELSE、END といった制御構文を埋め込む事で、直接実行する事も出来るし、プレースホルダを使ったオンコード用の SQL としても使う事ができるといった物です。筆者が知る限り明確な仕様は見当たらないのですが、昔は Doma/S2Dao といったデータベースの抽象化レイヤと合わせて利用されて来ました。

select * from foo where id = /*id*/5 /* IF enabled */and bar = /*bar*/'foo' /*END*/

この SQL を実行するとコメントは無視される為、実際は以下が実行されます。

select * from foo where id = 5 and bar = 'foo'

このコメントに記述された IF/ELSE/END と、値の直前に書かれたコメントが 2 Way SQL です。

2 Way SQL のルール

select * from foo where id = /*id*/5 /* IF enabled */and bar = /*bar*/'foo' /*END*/

この SQL に制御パラメータ enabled を true 渡すと IF 文が有効になるため、id と bar による抽出が有効になります。また false で渡すと IF 文が無効となるため id のみの抽出となります。

select * from foo where id = :id

この様に /*bar*/'foo' はプレースホルダ bar に置き換えられます。

2 Way SQL の実装

随分前ですが golang で実装しました。

以下の様に使います。

env := make(map[string]interface{})
env["enabled"] = true

sql2way := `
select
  *
from
  foo
where
  id = /*id*/5
/* IF enabled */
  and bar = /*bar*/3
/*END*/
`

sql, err := Eval(sql2way, env, ways2go.Question)

正常に評価されると以下の SQL を得る事が出来ます。

select
  *
from
  foo
where
  id = ?
  and bar = ?

データベースによってはプレースホルダの形式が異なります。ways2go では以下の形式をサポートしています。

識別 プレースホルダ
Question ?
Dollar $1
Colon :foo

これを使えばサンプルとして実行する事もでき、プログラムから実行する事もできる SQL を同じファイルで管理する事が出来ます。

まとめ

大規模なプロジェクトで SQL が散乱する様なコードベースでは SQL を外部ファイルに切り出すことでソースコードがスッキリするかもしれません。ただし実は筆者も昔に作ったまま時間が経っており、テストは書いてあるのですが実務で使った事がありません。皆さんからの PR や機能追加をお待ちしております。

34
18
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
34
18