mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-20 13:33:50 +12:00
fix: sorting on optimized first aggregates
This commit is contained in:
parent
0650a76105
commit
bbb45f3622
5 changed files with 49 additions and 7 deletions
|
@ -657,7 +657,7 @@ defmodule AshPostgres.Aggregate do
|
||||||
ref = %Ash.Query.Ref{
|
ref = %Ash.Query.Ref{
|
||||||
attribute: Ash.Resource.Info.field(resource, aggregate.field),
|
attribute: Ash.Resource.Info.field(resource, aggregate.field),
|
||||||
relationship_path: relationship_path,
|
relationship_path: relationship_path,
|
||||||
resource: resource
|
resource: query.__ash_bindings__.resource
|
||||||
}
|
}
|
||||||
|
|
||||||
type = AshPostgres.Types.parameterized_type(aggregate.type, aggregate.constraints)
|
type = AshPostgres.Types.parameterized_type(aggregate.type, aggregate.constraints)
|
||||||
|
@ -678,7 +678,10 @@ defmodule AshPostgres.Aggregate do
|
||||||
AshPostgres.Sort.sort(
|
AshPostgres.Sort.sort(
|
||||||
query,
|
query,
|
||||||
aggregate.query.sort,
|
aggregate.query.sort,
|
||||||
Ash.Resource.Info.related(resource, relationship_path),
|
Ash.Resource.Info.related(
|
||||||
|
query.__ash_bindings__.resource,
|
||||||
|
relationship_path
|
||||||
|
),
|
||||||
relationship_path,
|
relationship_path,
|
||||||
binding,
|
binding,
|
||||||
true
|
true
|
||||||
|
@ -745,7 +748,7 @@ defmodule AshPostgres.Aggregate do
|
||||||
ref = %Ash.Query.Ref{
|
ref = %Ash.Query.Ref{
|
||||||
attribute: Ash.Resource.Info.field(resource, aggregate.field),
|
attribute: Ash.Resource.Info.field(resource, aggregate.field),
|
||||||
relationship_path: relationship_path,
|
relationship_path: relationship_path,
|
||||||
resource: resource
|
resource: query.__ash_bindings__.resource
|
||||||
}
|
}
|
||||||
|
|
||||||
field = AshPostgres.Expr.dynamic_expr(query, ref, query.__ash_bindings__, false)
|
field = AshPostgres.Expr.dynamic_expr(query, ref, query.__ash_bindings__, false)
|
||||||
|
@ -756,7 +759,10 @@ defmodule AshPostgres.Aggregate do
|
||||||
AshPostgres.Sort.sort(
|
AshPostgres.Sort.sort(
|
||||||
query,
|
query,
|
||||||
aggregate.query.sort,
|
aggregate.query.sort,
|
||||||
Ash.Resource.Info.related(resource, relationship_path),
|
Ash.Resource.Info.related(
|
||||||
|
query.__ash_bindings__.resource,
|
||||||
|
relationship_path
|
||||||
|
),
|
||||||
relationship_path,
|
relationship_path,
|
||||||
binding,
|
binding,
|
||||||
true
|
true
|
||||||
|
|
|
@ -346,7 +346,8 @@ defmodule AshPostgres.Join do
|
||||||
|
|
||||||
defp can_inner_join?(_, _, _), do: false
|
defp can_inner_join?(_, _, _), do: false
|
||||||
|
|
||||||
defp get_binding(resource, candidate_path, %{__ash_bindings__: _} = query, types) do
|
@doc false
|
||||||
|
def get_binding(resource, candidate_path, %{__ash_bindings__: _} = query, types) do
|
||||||
types = List.wrap(types)
|
types = List.wrap(types)
|
||||||
|
|
||||||
Enum.find_value(query.__ash_bindings__.bindings, fn
|
Enum.find_value(query.__ash_bindings__.bindings, fn
|
||||||
|
@ -361,7 +362,7 @@ defmodule AshPostgres.Join do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_binding(_, _, _, _), do: nil
|
def get_binding(_, _, _, _), do: nil
|
||||||
|
|
||||||
defp add_distinct(relationship, _join_type, joined_query) do
|
defp add_distinct(relationship, _join_type, joined_query) do
|
||||||
if !joined_query.__ash_bindings__.in_group? && relationship.cardinality == :many &&
|
if !joined_query.__ash_bindings__.in_group? && relationship.cardinality == :many &&
|
||||||
|
|
13
lib/sort.ex
13
lib/sort.ex
|
@ -84,6 +84,19 @@ defmodule AshPostgres.Sort do
|
||||||
end
|
end
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
|
aggregate = Ash.Resource.Info.aggregate(resource, sort)
|
||||||
|
|
||||||
|
{binding, sort} =
|
||||||
|
if aggregate && aggregate.kind == :first &&
|
||||||
|
AshPostgres.Aggregate.single_path?(resource, aggregate.relationship_path) do
|
||||||
|
{AshPostgres.Join.get_binding(resource, aggregate.relationship_path, query, [
|
||||||
|
:left,
|
||||||
|
:inner
|
||||||
|
]), aggregate.field}
|
||||||
|
else
|
||||||
|
{binding, sort}
|
||||||
|
end
|
||||||
|
|
||||||
Ecto.Query.dynamic(field(as(^binding), ^sort))
|
Ecto.Query.dynamic(field(as(^binding), ^sort))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule AshPostgres.AggregateTest do
|
defmodule AshPostgres.AggregateTest do
|
||||||
use AshPostgres.RepoCase, async: false
|
use AshPostgres.RepoCase, async: false
|
||||||
alias AshPostgres.Test.{Api, Comment, Organization, Post, Rating, User}
|
alias AshPostgres.Test.{Api, Author, Comment, Organization, Post, Rating, User}
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
@ -316,6 +316,26 @@ defmodule AshPostgres.AggregateTest do
|
||||||
|> Api.read_one!()
|
|> Api.read_one!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "first aggregates can be sorted on" do
|
||||||
|
author =
|
||||||
|
Author
|
||||||
|
|> Ash.Changeset.new(%{first_name: "first name"})
|
||||||
|
|> Api.create!()
|
||||||
|
|
||||||
|
post =
|
||||||
|
Post
|
||||||
|
|> Ash.Changeset.new(%{title: "title"})
|
||||||
|
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|
||||||
|
|> Api.create!()
|
||||||
|
|
||||||
|
assert %{author_first_name: "first name"} =
|
||||||
|
Post
|
||||||
|
|> Ash.Query.filter(id == ^post.id)
|
||||||
|
|> Ash.Query.load(:author_first_name)
|
||||||
|
|> Ash.Query.sort(author_first_name: :asc)
|
||||||
|
|> Api.read_one!()
|
||||||
|
end
|
||||||
|
|
||||||
test "it can be sorted on and produces the appropriate order" do
|
test "it can be sorted on and produces the appropriate order" do
|
||||||
post1 =
|
post1 =
|
||||||
Post
|
Post
|
||||||
|
|
|
@ -184,6 +184,8 @@ defmodule AshPostgres.Test.Post do
|
||||||
sort(title: :desc)
|
sort(title: :desc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
first(:author_first_name, :author, :first_name)
|
||||||
|
|
||||||
max(:highest_comment_rating, [:comments, :ratings], :score)
|
max(:highest_comment_rating, [:comments, :ratings], :score)
|
||||||
min(:lowest_comment_rating, [:comments, :ratings], :score)
|
min(:lowest_comment_rating, [:comments, :ratings], :score)
|
||||||
avg(:avg_comment_rating, [:comments, :ratings], :score)
|
avg(:avg_comment_rating, [:comments, :ratings], :score)
|
||||||
|
|
Loading…
Reference in a new issue