diff --git a/lib/etso/adapter/behaviour/schema.ex b/lib/etso/adapter/behaviour/schema.ex index 498e071..f191ecf 100644 --- a/lib/etso/adapter/behaviour/schema.ex +++ b/lib/etso/adapter/behaviour/schema.ex @@ -13,8 +13,8 @@ defmodule Etso.Adapter.Behaviour.Schema do @impl Ecto.Adapter.Schema def insert_all(%{repo: repo}, %{schema: schema}, _, entries, _, _, _, _) do {:ok, ets_table} = TableRegistry.get_table(repo, schema) - ets_field_names = TableStructure.field_names(schema) - ets_changes = TableStructure.entries_to_tuples(ets_field_names, entries) + ets_field_sources = TableStructure.field_sources(schema) + ets_changes = TableStructure.entries_to_tuples(ets_field_sources, entries) ets_result = :ets.insert_new(ets_table, ets_changes) if ets_result, do: {length(ets_changes), nil}, else: {0, nil} end @@ -22,8 +22,8 @@ defmodule Etso.Adapter.Behaviour.Schema do @impl Ecto.Adapter.Schema def insert(%{repo: repo}, %{schema: schema}, fields, _, _, _) do {:ok, ets_table} = TableRegistry.get_table(repo, schema) - ets_field_names = TableStructure.field_names(schema) - ets_changes = TableStructure.fields_to_tuple(ets_field_names, fields) + ets_field_sources = TableStructure.field_sources(schema) + ets_changes = TableStructure.fields_to_tuple(ets_field_sources, fields) ets_result = :ets.insert_new(ets_table, ets_changes) if ets_result, do: {:ok, []}, else: {:invalid, [unique: "primary_key"]} end @@ -48,11 +48,11 @@ defmodule Etso.Adapter.Behaviour.Schema do end defp build_ets_updates(schema, fields) do - ets_field_names = TableStructure.field_names(schema) + ets_field_sources = TableStructure.field_sources(schema) for {field_name, field_value} <- fields do position_fun = fn x -> x == field_name end - position = 1 + Enum.find_index(ets_field_names, position_fun) + position = 1 + Enum.find_index(ets_field_sources, position_fun) {position, field_value} end end diff --git a/lib/etso/ets/match_specification.ex b/lib/etso/ets/match_specification.ex index aebe806..96cdea9 100644 --- a/lib/etso/ets/match_specification.ex +++ b/lib/etso/ets/match_specification.ex @@ -13,20 +13,20 @@ defmodule Etso.ETS.MatchSpecification do def build(query, params) do {_, schema} = query.from.source - field_names = Etso.ETS.TableStructure.field_names(schema) - match_head = build_head(field_names) - match_conditions = build_conditions(field_names, params, query) - match_body = [build_body(field_names, query)] + field_sources = Etso.ETS.TableStructure.field_sources(schema) + match_head = build_head(field_sources) + match_conditions = build_conditions(field_sources, params, query) + match_body = [build_body(field_sources, query)] {match_head, match_conditions, match_body} end - defp build_head(field_names) do - List.to_tuple(Enum.map(1..length(field_names), fn x -> :"$#{x}" end)) + defp build_head(field_sources) do + List.to_tuple(Enum.map(1..length(field_sources), fn x -> :"$#{x}" end)) end - defp build_conditions(field_names, params, %Ecto.Query{wheres: wheres}) do + defp build_conditions(field_sources, params, %Ecto.Query{wheres: wheres}) do Enum.reduce(wheres, [], fn %Ecto.Query.BooleanExpr{expr: expression}, acc -> - [build_condition(field_names, params, expression) | acc] + [build_condition(field_sources, params, expression) | acc] end) end @@ -37,22 +37,22 @@ defmodule Etso.ETS.MatchSpecification do defmacrop guard_operator(operator), do: operator for operator <- ~w(== != < > <= >= and or)a do - defp build_condition(field_names, params, {unquote(operator), [], [lhs, rhs]}) do - lhs_condition = build_condition(field_names, params, lhs) - rhs_condition = build_condition(field_names, params, rhs) + defp build_condition(field_sources, params, {unquote(operator), [], [lhs, rhs]}) do + lhs_condition = build_condition(field_sources, params, lhs) + rhs_condition = build_condition(field_sources, params, rhs) {guard_operator(unquote(operator)), lhs_condition, rhs_condition} end end for operator <- ~w(not)a do - defp build_condition(field_names, params, {unquote(operator), [], [clause]}) do - condition = build_condition(field_names, params, clause) + defp build_condition(field_sources, params, {unquote(operator), [], [clause]}) do + condition = build_condition(field_sources, params, clause) {guard_operator(unquote(operator)), condition} end end - defp build_condition(field_names, params, {:in, [], [field, values]}) do - field_target = resolve_field_target(field_names, field) + defp build_condition(field_sources, params, {:in, [], [field, values]}) do + field_target = resolve_field_target(field_sources, field) case resolve_param_values(params, values) do [] -> [] @@ -60,16 +60,16 @@ defmodule Etso.ETS.MatchSpecification do end end - defp build_condition(field_names, params, {:is_nil, [], [field]}) do - {:==, build_condition(field_names, params, field), nil} + defp build_condition(field_sources, params, {:is_nil, [], [field]}) do + {:==, build_condition(field_sources, params, field), nil} end defp build_condition(_, params, {:^, [], [index]}) do Enum.at(params, index) end - defp build_condition(field_names, _params, field) when is_tuple(field) do - resolve_field_target(field_names, field) + defp build_condition(field_sources, _params, field) when is_tuple(field) do + resolve_field_target(field_sources, field) end defp build_condition(_, _, value) do @@ -80,19 +80,19 @@ defmodule Etso.ETS.MatchSpecification do [] end - defp build_body(field_names, %Ecto.Query{select: %{fields: fields}}) do + defp build_body(field_sources, %Ecto.Query{select: %{fields: fields}}) do for field <- fields do - resolve_field_target(field_names, field) + resolve_field_target(field_sources, field) end end - defp resolve_field_target(field_names, {:json_extract_path, [], [field, path]}) do - field_target = resolve_field_target(field_names, field) + defp resolve_field_target(field_sources, {:json_extract_path, [], [field, path]}) do + field_target = resolve_field_target(field_sources, field) resolve_field_target_path(field_target, path) end - defp resolve_field_target(field_names, {{:., _, [{:&, [], [0]}, field_name]}, [], []}) do - field_index = 1 + Enum.find_index(field_names, fn x -> x == field_name end) + defp resolve_field_target(field_sources, {{:., _, [{:&, [], [0]}, field_name]}, [], []}) do + field_index = 1 + Enum.find_index(field_sources, fn x -> x == field_name end) :"$#{field_index}" end diff --git a/lib/etso/ets/table_structure.ex b/lib/etso/ets/table_structure.ex index 1c3811c..b37720f 100644 --- a/lib/etso/ets/table_structure.ex +++ b/lib/etso/ets/table_structure.ex @@ -11,6 +11,12 @@ defmodule Etso.ETS.TableStructure do primary_key ++ (fields -- primary_key) end + def field_sources(schema) do + schema + |> field_names() + |> Enum.map(fn field -> schema.__schema__(:field_source, field) end) + end + def fields_to_tuple(field_names, fields) do field_names |> Enum.map(&Keyword.get(fields, &1, nil)) diff --git a/test/northwind/repo_test.exs b/test/northwind/repo_test.exs index 1a23291..3c22b14 100644 --- a/test/northwind/repo_test.exs +++ b/test/northwind/repo_test.exs @@ -182,7 +182,7 @@ defmodule Northwind.RepoTest do test "Delete Where" do query = Model.Employee |> where([e], e.employee_id in [1, 5]) - assert [a, b] = Repo.all(query) + assert [_a, _b] = Repo.all(query) assert {2, nil} = Repo.delete_all(query) assert [] == Repo.all(query) refute [] == Repo.all(Model.Employee) @@ -190,12 +190,12 @@ defmodule Northwind.RepoTest do test "Delete Where Select" do query = Model.Employee |> where([e], e.employee_id in [1, 5]) - assert [a, b] = Repo.all(query) + assert [_a, _b] = Repo.all(query) assert {2, list} = Repo.delete_all(query |> select([e], {e, e.employee_id})) assert is_list(list) assert Enum.any?(list, &(elem(&1, 1) == 1)) assert Enum.any?(list, &(elem(&1, 1) == 5)) - assert [] = Repo.all(query) + assert [] == Repo.all(query) refute [] == Repo.all(Model.Employee) end diff --git a/test/support/northwind/model/employee.ex b/test/support/northwind/model/employee.ex index d05b51b..1cfe5a6 100644 --- a/test/support/northwind/model/employee.ex +++ b/test/support/northwind/model/employee.ex @@ -4,7 +4,7 @@ defmodule Northwind.Model.Employee do schema "employees" do # field :employee_id, :integer - field :reports_to, :integer + field :reports_to, :integer, source: :manager_id field :first_name, :string field :last_name, :string field :title, :string