Current section

Files

Jump to
sorcery lib services store_adapter ecto query build_multi.ex
Raw

lib/services/store_adapter/ecto/query/build_multi.ex

defmodule Sorcery.StoreAdapter.Ecto.Query.BuildMulti do
@moduledoc false
import Ecto.Query
alias Ecto.Multi, as: M
# {{{ WIP build_multi
@doc ~s"""
Fill out ctx.multi, returning ctx.
The result can be used like App.Repo.transaction(ctx.multi)
"""
def build_multi(ctx) do
wheres = Enum.group_by(ctx.wheres, &(&1.lvar))
order = Enum.map(ctx.wheres, &(&1.lvar)) |> Enum.uniq()
multi = Enum.reduce(order, M.new(), &handle_entire_lvar(&1, &2, wheres[&1], ctx))
Map.put(ctx, :multi, multi)
end
# }}}
# {{{ WIP handle_entire_lvar
_doc = ~s"""
Given an Lvar and a multi, adds the query to the multi
"""
defp handle_entire_lvar(lvar, multi, [hd_clause | _] = clauses, ctx) do
mod = ctx.tk_map[hd_clause.tk]
M.all(multi, lvar, fn results ->
Enum.reduce(clauses, from(x in mod, as: ^lvar), &handle_single_clause(&1, &2, results))
end)
end
# }}}
# {{{ WIP handle_single_clause
_doc = ~s"""
Adds a single where clause to a query
"""
defp handle_single_clause(clause, q, results) do
clause = rewrite_fk_clause(clause, results)
%{lvar: lvar, attr: attr, right: value, op: op} = clause
case {op, value} do
{:==, nil} -> where(q, [{^lvar, x}], is_nil(field(x, ^attr)))
{:==, _} -> where(q, [{^lvar, x}], field(x, ^attr) == ^value)
{:in, _} -> where(q, [{^lvar, x}], field(x, ^attr) in ^value)
{:!=, nil} -> where(q, [{^lvar, x}], not is_nil(field(x, ^attr)))
{:!=, _} -> where(q, [{^lvar, x}], field(x, ^attr))
{:>, _} -> where(q, [{^lvar, x}], field(x, ^attr) > ^value)
{:>=, _} -> where(q, [{^lvar, x}], field(x, ^attr) >= ^value)
{:<, _} -> where(q, [{^lvar, x}], field(x, ^attr) < ^value)
{:<=, _} -> where(q, [{^lvar, x}], field(x, ^attr) <= ^value)
end
end
defp rewrite_fk_clause(%{right_type: :lvar, other_lvar: olvar, other_lvar_attr: oattr} = clause, results) do
other = results[olvar]
right = Enum.map(other, &Map.get(&1, oattr))
clause
|> Map.put(:op, :in)
|> Map.put(:right, right)
end
defp rewrite_fk_clause(clause, _), do: clause
# }}}
# {{{ dummy_results DELETE ME
def dummy_results() do
M.new()
|> M.all(:"?player", fn _ ->
from(p in Src.Schemas.Player)
|> where([p], p.id == 2)
end)
|> M.all(:"?spell_type", fn _ ->
from(s in Src.Schemas.SpellType)
|> where([s], s.power > 0)
end)
|> M.all(:"?spells", fn m ->
player_ids = Enum.map(m[:"?player"], &(&1.id))
type_ids = Enum.map(m[:"?spell_type"], &(&1.id))
from(s in Src.Schemas.SpellInstance)
|> where([s], s.player_id in ^player_ids)
|> where([s], s.type_id in ^type_ids)
end)
#|> Sorcery.Repo.transaction()
end
# }}}
end