mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 13:03:02 +12:00
improvement: Cache always selected fields and use mapsets for building select list (#1428)
* Add attribute_names function on Info that returns MapSet And use that when calculating select lists.
This commit is contained in:
parent
cdbb0c4608
commit
2c754f90a6
3 changed files with 43 additions and 32 deletions
|
@ -845,42 +845,37 @@ defmodule Ash.Query do
|
||||||
"""
|
"""
|
||||||
def select(query, fields, opts \\ []) do
|
def select(query, fields, opts \\ []) do
|
||||||
query = new(query)
|
query = new(query)
|
||||||
fields = List.wrap(fields)
|
existing_fields = Ash.Resource.Info.attribute_names(query.resource)
|
||||||
|
fields = MapSet.new(List.wrap(fields))
|
||||||
|
|
||||||
{fields, non_existent} =
|
valid_fields = MapSet.intersection(fields, existing_fields)
|
||||||
Enum.split_with(fields, &Ash.Resource.Info.attribute(query.resource, &1))
|
|
||||||
|
|
||||||
query =
|
query =
|
||||||
Enum.reduce(non_existent, query, fn field, query ->
|
if MapSet.size(valid_fields) != MapSet.size(fields) do
|
||||||
Ash.Query.add_error(
|
MapSet.difference(fields, existing_fields)
|
||||||
query,
|
|> Enum.reduce(query, fn field, query ->
|
||||||
Ash.Error.Query.NoSuchAttribute.exception(resource: query.resource, attribute: field)
|
Ash.Query.add_error(
|
||||||
)
|
query,
|
||||||
end)
|
Ash.Error.Query.NoSuchAttribute.exception(resource: query.resource, attribute: field)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
query
|
||||||
|
end
|
||||||
|
|
||||||
always_select =
|
always_select =
|
||||||
query.resource
|
valid_fields
|
||||||
|> Ash.Resource.Info.attributes()
|
|> MapSet.union(Ash.Resource.Info.always_selected_attribute_names(query.resource))
|
||||||
|> Enum.filter(& &1.always_select?)
|
|> MapSet.union(MapSet.new(Ash.Resource.Info.primary_key(query.resource)))
|
||||||
|> Enum.map(& &1.name)
|
|
||||||
|
|
||||||
if opts[:replace?] do
|
new_select =
|
||||||
%{
|
if opts[:replace?] do
|
||||||
query
|
always_select
|
||||||
| select:
|
else
|
||||||
Enum.uniq(fields ++ Ash.Resource.Info.primary_key(query.resource) ++ always_select)
|
MapSet.union(MapSet.new(query.select || []), always_select)
|
||||||
}
|
end
|
||||||
else
|
|
||||||
%{
|
%{query | select: MapSet.to_list(new_select)}
|
||||||
query
|
|
||||||
| select:
|
|
||||||
Enum.uniq(
|
|
||||||
fields ++
|
|
||||||
(query.select || []) ++
|
|
||||||
Ash.Resource.Info.primary_key(query.resource) ++ always_select
|
|
||||||
)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -649,6 +649,11 @@ defmodule Ash.Resource.Info do
|
||||||
Extension.get_entities(resource, [:attributes])
|
Extension.get_entities(resource, [:attributes])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec attribute_names(Spark.Dsl.t() | Ash.Resource.t()) :: MapSet.t()
|
||||||
|
def attribute_names(resource) do
|
||||||
|
Extension.get_persisted(resource, :attribute_names)
|
||||||
|
end
|
||||||
|
|
||||||
@doc "Returns all attributes of a resource with lazy non-matching-defaults"
|
@doc "Returns all attributes of a resource with lazy non-matching-defaults"
|
||||||
@spec lazy_non_matching_default_attributes(
|
@spec lazy_non_matching_default_attributes(
|
||||||
Spark.Dsl.t() | Ash.Resource.t(),
|
Spark.Dsl.t() | Ash.Resource.t(),
|
||||||
|
@ -769,6 +774,11 @@ defmodule Ash.Resource.Info do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec always_selected_attribute_names(Spark.Dsl.t() | Ash.Resource.t()) :: MapSet.t()
|
||||||
|
def always_selected_attribute_names(resource) do
|
||||||
|
Extension.get_persisted(resource, :always_selected_attribute_names)
|
||||||
|
end
|
||||||
|
|
||||||
@doc "Returns all attributes, aggregates, calculations and relationships of a resource"
|
@doc "Returns all attributes, aggregates, calculations and relationships of a resource"
|
||||||
@spec fields(
|
@spec fields(
|
||||||
Spark.Dsl.t() | Ash.Resource.t(),
|
Spark.Dsl.t() | Ash.Resource.t(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ defmodule Ash.Resource.Transformers.AttributesByName do
|
||||||
|> Map.put(to_string(name), attr)
|
|> Map.put(to_string(name), attr)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
attribute_names = Enum.map(attributes, & &1.name)
|
attribute_names = Enum.map(attributes, & &1.name) |> MapSet.new()
|
||||||
|
|
||||||
create_attributes_with_static_defaults =
|
create_attributes_with_static_defaults =
|
||||||
attributes
|
attributes
|
||||||
|
@ -61,6 +61,11 @@ defmodule Ash.Resource.Transformers.AttributesByName do
|
||||||
(is_function(attribute.update_default) or match?({_, _, _}, attribute.update_default))
|
(is_function(attribute.update_default) or match?({_, _, _}, attribute.update_default))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
always_selected_attribute_names =
|
||||||
|
Enum.filter(attributes, & &1.always_select?)
|
||||||
|
|> Enum.map(& &1.name)
|
||||||
|
|> MapSet.new()
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
persist(
|
persist(
|
||||||
dsl_state,
|
dsl_state,
|
||||||
|
@ -74,7 +79,8 @@ defmodule Ash.Resource.Transformers.AttributesByName do
|
||||||
update_attributes_with_static_defaults: update_attributes_with_static_defaults,
|
update_attributes_with_static_defaults: update_attributes_with_static_defaults,
|
||||||
update_attributes_with_non_matching_lazy_defaults:
|
update_attributes_with_non_matching_lazy_defaults:
|
||||||
update_attributes_with_non_matching_lazy_defaults,
|
update_attributes_with_non_matching_lazy_defaults,
|
||||||
update_attributes_with_matching_defaults: update_attributes_with_matching_defaults
|
update_attributes_with_matching_defaults: update_attributes_with_matching_defaults,
|
||||||
|
always_selected_attribute_names: always_selected_attribute_names
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue