Nao000のぶろぐ

蝶を追っている少年になりたい

Elixir Ecto.Adapters.SQL.Query で名前付きでバインドしたいので NamedBindSql というモジュール作ってみた

Elixir Ecto.Adapters.SQL.Query で名前付きでバインドしたいので NamedBindSql というモジュール作ってみた

生SQLを使いたい

個人的にSQLは生SQLを使いたい派です。理由は最初に業務でSQLを書き始めたときにORMではなく、生SQLで書いたからです。生SQLといってもSQLインジェクション対策されたフレームワークの機能を利用しています。

Elixir Phoenix で生SQLを使う際ときは Ecto.Adapters.SQL.Query を使用します。値をバインドするときは $1 をのように記載し、リストで値を設定します。

例えば以下のようにSQLを用意します。

"SELECT * FROM table1 AS t1 WHERE t1.id = $1 AND t1.hoge_id2 = $2 AND t1.id = $1 ;"

そして、 $1, $2 には以下のように数値の順番を考慮してリストを用意します。

[1000, 2000]

順番を考慮したくない

:sample のように名前をつけて値をバインドしたい。

:sample => $1 のように変換するモジュールを作ってみました

ので、NamedBindSql というモジュールを作ってみました。名前もうちょっとどうにかしたかった。

以下を入力とすると、

sql = "SELECT * FROM table1 AS t1 WHERE t1.id = :id AND t1.t2_id = :t2_id AND t1.id = :id;"

params = %{":id" => 1000, ":t2_id" => 2000}

以下を出力します

{
  "SELECT * FROM table1 AS t1 WHERE t1.id = $1 AND t1.t2_id = $2 AND t1.id = $1 ;",
  [1000, 2000]
}

全体的に以下のような使い方を想定しています。

sql = "SELECT * FROM table1 AS t1 WHERE t1.id = :id AND t1.t2_id = :t2_id AND t1.id = :id;"

params = %{":id" => 1000, ":t2_id" => 2000}

{sql_doller, param_list} = NamedBindSql.prepare_sql_with_params(sql, params)

Ecto.Adapters.SQL.Query(Yourapp.Repo, sql_doller, param_list)