fix: allow sorting on aggs, w/o loading

This commit is contained in:
Zach Daniel 2021-07-01 15:22:48 -04:00
parent 45fe33c3fc
commit 4b23dd179f
2 changed files with 52 additions and 18 deletions

View file

@ -67,6 +67,9 @@ defmodule Ash.Actions.Sort do
attribute = Ash.Resource.Info.attribute(resource, field) attribute = Ash.Resource.Info.attribute(resource, field)
cond do cond do
aggregate = Ash.Resource.Info.aggregate(resource, field) ->
aggregate_sort(aggregates, aggregate, order, resource, sorts, errors)
Map.has_key?(aggregates, field) -> Map.has_key?(aggregates, field) ->
aggregate_sort(aggregates, field, order, resource, sorts, errors) aggregate_sort(aggregates, field, order, resource, sorts, errors)
@ -94,7 +97,7 @@ defmodule Ash.Actions.Sort do
end end
!attribute -> !attribute ->
{sorts, [NoSuchAttribute.exception(attribute: field) | errors]} {sorts, [NoSuchAttribute.exception(name: field) | errors]}
Ash.Type.embedded_type?(attribute.type) -> Ash.Type.embedded_type?(attribute.type) ->
{sorts, ["Cannot sort on embedded types" | errors]} {sorts, ["Cannot sort on embedded types" | errors]}
@ -141,16 +144,38 @@ defmodule Ash.Actions.Sort do
end end
defp aggregate_sort(aggregates, field, order, resource, sorts, errors) do defp aggregate_sort(aggregates, field, order, resource, sorts, errors) do
{field, type} =
case field do
field when is_atom(field) ->
aggregate = Map.get(aggregates, field) aggregate = Map.get(aggregates, field)
{field, {:ok, aggregate.type}}
%Ash.Resource.Aggregate{} = agg ->
field_type =
if agg.field do
related = Ash.Resource.Info.related(resource, agg.relationship_path)
Ash.Resource.Info.attribute(related, agg.field).type
end
{agg.name, Ash.Query.Aggregate.kind_to_type(agg.kind, field_type)}
end
case type do
{:ok, type} ->
if Ash.DataLayer.data_layer_can?(resource, :aggregate_sort) && if Ash.DataLayer.data_layer_can?(resource, :aggregate_sort) &&
Ash.DataLayer.data_layer_can?( Ash.DataLayer.data_layer_can?(
resource, resource,
{:sort, Ash.Type.storage_type(aggregate.type)} {:sort, Ash.Type.storage_type(type)}
) do ) do
{sorts ++ [{field, order}], errors} {sorts ++ [{field, order}], errors}
else else
{sorts, [AggregatesNotSupported.exception(resource: resource, feature: "sorting") | errors]} {sorts,
[AggregatesNotSupported.exception(resource: resource, feature: "sorting") | errors]}
end
{:error, error} ->
{sorts, [error | errors]}
end end
end end

View file

@ -1541,6 +1541,7 @@ defmodule Ash.Query do
query = to_query(query) query = to_query(query)
if Ash.DataLayer.data_layer_can?(query.resource, :sort) do if Ash.DataLayer.data_layer_can?(query.resource, :sort) do
query_with_sort =
sorts sorts
|> List.wrap() |> List.wrap()
|> Enum.reduce(query, fn |> Enum.reduce(query, fn
@ -1551,6 +1552,14 @@ defmodule Ash.Query do
%{query | sort: query.sort ++ [{sort, :asc}]} %{query | sort: query.sort ++ [{sort, :asc}]}
end) end)
|> validate_sort() |> validate_sort()
Enum.reduce(query_with_sort.sort || [], query_with_sort, fn {key, _value}, query ->
if Ash.Resource.Info.aggregate(query.resource, key) do
Ash.Query.load(query, key)
else
query
end
end)
else else
add_error(query, :sort, "Data layer does not support sorting") add_error(query, :sort, "Data layer does not support sorting")
end end