更新/挿入の要件があるため、postgresストアドプロシージャを呼び出すか、共通テーブル式を使用する必要があります。また、パスワードにpgcrypto拡張機能を使用し、postgres関数(パスワードをエンコード/デコードする「暗号化」など)を使用したいと思います。
しかし、Ectoに生のSQLを部分的または全体的にプレイさせる方法を見つけることはできません。それは、ectoがelixir dslのみをサポートし、dslが十分でない場合に生のSQLへのシェルアウトを許可しないことを意図していますか?
アダプタを介してクエリを実行できることがわかりました(Rocketはアプリの名前です)
q = Ecto.Adapters.Postgres.query(Rocket.Repo,"select * from users limit 1",[])
しかし、これをモデルにどのように組み込むかはわかりません。私はエリクサーを初めて使い、Ecto.Model.Schem .schema/3を使用できるはずですが、これは失敗します
Rocket.User.__schema__(:load,q.rows |> List.first,0)
** (FunctionClauseError) no function clause matching in Rocket.User.__schema__/3
Postgresを使用したEcto 2.0(ベータ)では、Ecto.Adapters.SQL.query()
( current docs 、 2.0-beta2 docs )を使用して任意のSQLを実行できます。行自体のリスト( "rows
")に加えて、列名のリスト( "columns
")を返すこともあります。
以下の例では、私は
(おそらくquery()
バージョンを実行し(バングなし!)、{ok, res}
。)
qry = "SELECT * FROM users"
res = Ecto.Adapters.SQL.query!(Repo, qry, []) # a
cols = Enum.map res.columns, &(String.to_atom(&1)) # b
roles = Enum.map res.rows, fn(row) ->
struct(MyApp.User, Enum.Zip(cols, row)) # c
end
Ecto 2.0の修正ソリューション:
repo.exで:
def execute_and_load(sql, params, model) do
Ecto.Adapters.SQL.query!(__MODULE__, sql, params)
|> load_into(model)
end
defp load_into(response, model) do
Enum.map(response.rows, fn row ->
fields = Enum.reduce(Enum.Zip(response.columns, row), %{}, fn({key, value}, map) ->
Map.put(map, key, value)
end)
Ecto.Schema.__load__(model, nil, nil, nil, fields,
&Ecto.Type.adapter_load(__adapter__, &1, &2))
end)
end
使用法:
Repo.execute_and_load("SELECT * FROM users WHERE id = $1", [1], User)
Ecto 1.0がリリースされたので、これはしばらくの間機能するはずです。
Repo
モジュールに次の関数を追加します。
def execute_and_load(sql, params, model) do
Ecto.Adapters.SQL.query!(__MODULE__, sql, params)
|> load_into(model)
end
defp load_into(response, model) do
Enum.map response.rows, fn(row) ->
fields = Enum.reduce(Enum.Zip(response.columns, row), %{}, fn({key, value}, map) ->
Map.put(map, key, value)
end)
Ecto.Schema.__load__(model, nil, nil, [], fields, &__MODULE__.__adapter__.load/2)
end
end
そして、次のように使用します:
Repo.execute_and_load("SELECT * FROM users WHERE id = $1", [1], User)
Ecto.Adapters.SQL.query/4 に加えて、 Ecto.Query.API.fragment/1 もあります。これは、クエリ式をデータベース。たとえば、Postgresの配列関数array_upper
、使用するかもしれません
Ecto.Query.where([x], fragment("array_upper(some_array_field, 1)]" == 1)
Ecto 2.2.8はEcto.Query.load/2
ので、次のようなことができます。
use Ecto.Repo
def execute_and_load(sql, params, model) do
result = query!(sql, params)
Enum.map(result.rows, &load(model, {result.columns, &1}))
end
Ecto、少なくともバージョン〜> 0.7以降では使用する必要があります:
Ecto.Adapters.SQL.query/4
def query(repo, sql, params, opts \\ [])
指定されたリポジトリでカスタムSQLクエリを実行します。
成功した場合、少なくとも2つのキーを持つマップを含む:okタプルを返さなければなりません:
•:num_rows-影響を受ける行の数•:rows-リストとしての結果セット。コマンドが結果として行を生成しない場合、リストの代わりにnilが返される場合があります(ただし、返されない削除コマンドのように、影響を受ける行の数が生成されます)
オプション
•:timeout-コールの終了を待機する時間(ミリ秒)。:infinityは無期限に待機します(デフォルト:5000)•:log-falseの場合、クエリを記録しません
例
iex> Ecto.Adapters.SQL.query(MyRepo、 "SELECT $ 1 + $ 2"、[40、2])
%{rows:[{42}]、num_rows:1}
これは https://stackoverflow.com/users/1758892/thousandsofthem サンプルですが、少し縮小しました(クレジット:彼/彼女)
defmodule MyApp.Repo do
[...]
def execute_and_load(sql, params, schema) do
response = query!(sql, params)
Enum.map(response.rows, fn row ->
fields = Enum.Zip(response.columns, row) |> Enum.into(%{})
Ecto.Schema.__load__(schema, nil, nil, nil, fields,
&Ecto.Type.adapter_load(__adapter__(), &1, &2))
end)
end
end