Current section

Files

Jump to
ash_sql lib bindings.ex
Raw

lib/bindings.ex

# SPDX-FileCopyrightText: 2024 ash_sql contributors <https://github.com/ash-project/ash_sql/graphs.contributors>
#
# SPDX-License-Identifier: MIT
defmodule AshSql.Bindings do
@moduledoc false
@doc false
def add_binding(query, data, additional_bindings \\ 0) do
current = query.__ash_bindings__.current
bindings = query.__ash_bindings__.bindings
new_ash_bindings = %{
query.__ash_bindings__
| bindings: Map.put(bindings, current, data),
current: current + 1 + additional_bindings
}
%{query | __ash_bindings__: new_ash_bindings}
end
def explicitly_set_binding(query, data, to) do
%{
query
| __ash_bindings__: %{
query.__ash_bindings__
| bindings: Map.put(query.__ash_bindings__.bindings, to, data)
}
}
end
def merge_expr_accumulator(query, acc) do
update_in(
query.__ash_bindings__.expression_accumulator,
&AshSql.Expr.merge_accumulator(&1, acc)
)
end
def default_bindings(query, resource, sql_behaviour, context \\ %{})
def default_bindings(%{__ash_bindings__: _} = query, _resource, _sql_behaviour, _context),
do: query
def default_bindings(query, resource, sql_behaviour, context) do
default_start_bindings =
if context[:data_layer][:lateral_join_source] do
500
else
0
end
requested_start = context[:data_layer][:start_bindings_at] || 0
start_bindings =
if requested_start == 0 do
default_start_bindings
else
requested_start
end
Map.put_new(query, :__ash_bindings__, %{
resource: resource,
sql_behaviour: sql_behaviour,
current: Enum.count(query.joins) + 1 + start_bindings,
expression_accumulator: %AshSql.Expr.ExprInfo{},
in_group?: false,
calculations: %{},
parent_resources: [],
aggregate_defs: %{},
current_aggregate_name: :aggregate_0,
current_calculation_name: :calculation_0,
aggregate_names: %{},
calculation_names: %{},
context: context,
root_binding: start_bindings,
bindings: %{start_bindings => %{path: [], type: :root, source: resource}}
})
end
@doc false
def get_binding(resource, candidate_path, %{__ash_bindings__: _} = query, types) do
types = List.wrap(types)
Enum.find_value(query.__ash_bindings__.bindings, fn
{binding, %{path: path, source: source, type: type}} ->
if type in types &&
Ash.Resource.Info.synonymous_relationship_paths?(
resource,
path,
candidate_path,
source
) do
binding
end
_ ->
nil
end)
end
def get_binding(_, _, _, _), do: nil
def add_parent_bindings(data_layer_query, %{data_layer: %{parent_bindings: parent_bindings}})
when not is_nil(parent_bindings) do
new_bindings =
data_layer_query.__ash_bindings__
|> Map.put(:parent_bindings, Map.put(parent_bindings, :parent?, true))
|> Map.put(:parent_resources, [
parent_bindings.resource | parent_bindings[:parent_resources] || []
])
|> Map.put(:lateral_join?, true)
%{data_layer_query | __ash_bindings__: new_bindings}
end
def add_parent_bindings(data_layer_query, _context) do
data_layer_query
end
end