2022-01-14 08:11:30 +13:00
|
|
|
defmodule AshPostgres.Calculation do
|
|
|
|
@moduledoc false
|
|
|
|
|
|
|
|
require Ecto.Query
|
|
|
|
|
|
|
|
def add_calculations(query, [], _), do: {:ok, query}
|
|
|
|
|
|
|
|
def add_calculations(query, calculations, resource) do
|
|
|
|
query = AshPostgres.DataLayer.default_bindings(query, resource)
|
|
|
|
|
2022-12-18 20:23:39 +13:00
|
|
|
aggregates =
|
|
|
|
calculations
|
|
|
|
|> Enum.flat_map(fn {_calculation, expression} ->
|
|
|
|
used_calculations =
|
|
|
|
Ash.Filter.used_calculations(
|
2022-01-14 08:11:30 +13:00
|
|
|
expression,
|
2022-12-18 20:23:39 +13:00
|
|
|
query.__ash_bindings__.resource,
|
|
|
|
[]
|
2022-01-14 08:11:30 +13:00
|
|
|
)
|
|
|
|
|
2022-12-18 20:23:39 +13:00
|
|
|
AshPostgres.Aggregate.used_aggregates(
|
|
|
|
expression,
|
|
|
|
query.__ash_bindings__.resource,
|
|
|
|
used_calculations,
|
|
|
|
[]
|
|
|
|
)
|
2022-01-14 08:11:30 +13:00
|
|
|
end)
|
2022-12-18 20:23:39 +13:00
|
|
|
|> Enum.uniq()
|
|
|
|
|
|
|
|
case AshPostgres.Aggregate.add_aggregates(
|
|
|
|
query,
|
|
|
|
aggregates,
|
|
|
|
query.__ash_bindings__.resource,
|
|
|
|
false
|
|
|
|
) do
|
|
|
|
{:ok, query} ->
|
|
|
|
query =
|
|
|
|
if query.select do
|
|
|
|
query
|
|
|
|
else
|
|
|
|
Ecto.Query.select_merge(query, %{})
|
|
|
|
end
|
|
|
|
|
|
|
|
dynamics =
|
|
|
|
Enum.map(calculations, fn {calculation, expression} ->
|
|
|
|
expr =
|
|
|
|
AshPostgres.Expr.dynamic_expr(
|
|
|
|
query,
|
|
|
|
expression,
|
|
|
|
query.__ash_bindings__,
|
|
|
|
false,
|
2022-12-29 17:11:55 +13:00
|
|
|
AshPostgres.Types.parameterized_type(
|
|
|
|
calculation.type,
|
|
|
|
Map.get(calculation, :constraints, [])
|
|
|
|
)
|
2022-12-18 20:23:39 +13:00
|
|
|
)
|
|
|
|
|
|
|
|
{calculation.load, calculation.name, expr}
|
|
|
|
end)
|
|
|
|
|
|
|
|
{:ok, add_calculation_selects(query, dynamics)}
|
2022-01-14 08:11:30 +13:00
|
|
|
|
2022-12-18 20:23:39 +13:00
|
|
|
{:error, error} ->
|
|
|
|
{:error, error}
|
|
|
|
end
|
2022-01-14 08:11:30 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
defp add_calculation_selects(query, dynamics) do
|
2022-10-06 08:06:09 +13:00
|
|
|
{in_calculations, in_body} =
|
2022-01-14 08:11:30 +13:00
|
|
|
Enum.split_with(dynamics, fn {load, _name, _dynamic} -> is_nil(load) end)
|
|
|
|
|
2022-10-08 08:50:20 +13:00
|
|
|
calcs =
|
|
|
|
in_body
|
|
|
|
|> Map.new(fn {load, _, dynamic} ->
|
|
|
|
{load, dynamic}
|
|
|
|
end)
|
|
|
|
|
|
|
|
calcs =
|
|
|
|
if Enum.empty?(in_calculations) do
|
|
|
|
calcs
|
2022-01-14 08:11:30 +13:00
|
|
|
else
|
2022-10-08 08:50:20 +13:00
|
|
|
Map.put(
|
|
|
|
calcs,
|
|
|
|
:calculations,
|
|
|
|
Map.new(in_calculations, fn {_, name, dynamic} ->
|
|
|
|
{name, dynamic}
|
|
|
|
end)
|
|
|
|
)
|
2022-01-14 08:11:30 +13:00
|
|
|
end
|
|
|
|
|
2022-10-08 08:50:20 +13:00
|
|
|
Ecto.Query.select_merge(query, ^calcs)
|
2022-01-14 08:11:30 +13:00
|
|
|
end
|
|
|
|
end
|