improvement: support parent in sort expressions

This commit is contained in:
Zach Daniel 2023-10-26 09:47:56 -04:00
parent 75208a70f8
commit 342920a3c4
4 changed files with 78 additions and 5 deletions

View file

@ -552,12 +552,22 @@ defmodule AshPostgres.DataLayer do
|> default_bindings(resource, context)
case context[:data_layer][:lateral_join_source] do
{_, [{%{resource: resource}, _, _, _} | _]} ->
{_, [{%{resource: resource}, _, _, _} | rest]} ->
parent =
resource
|> resource_to_query(nil)
|> default_bindings(resource, context)
parent =
case rest do
[{resource, _, _, %{name: join_relationship_name}} | _] ->
binding_data = %{type: :inner, path: [join_relationship_name], source: resource}
add_binding(parent, binding_data)
_ ->
parent
end
ash_bindings =
data_layer_query.__ash_bindings__
|> Map.put(:parent_bindings, Map.put(parent.__ash_bindings__, :parent?, true))

View file

@ -1055,14 +1055,15 @@ defmodule AshPostgres.Expr do
type
) do
parent? = Map.get(bindings.parent_bindings, :parent_is_parent_as?, true)
new_bindings = Map.put(bindings.parent_bindings, :parent?, parent?)
do_dynamic_expr(
%{
query
| __ash_bindings__: Map.put(bindings.parent_bindings, :parent?, parent?)
| __ash_bindings__: new_bindings
},
expr,
bindings,
new_bindings,
embedded?,
type
)
@ -1607,7 +1608,8 @@ defmodule AshPostgres.Expr do
end
end
defp set_parent_path(query, parent) do
@doc false
def set_parent_path(query, parent) do
# This is a stupid name. Its actually the path we *remove* when stepping up a level. I.e the child's path
Map.update!(query, :__ash_bindings__, fn ash_bindings ->
ash_bindings

View file

@ -20,6 +20,7 @@ defmodule AshPostgres.Sort do
%{
resource: resource,
aggregates: %{},
parent_stack: query.__ash_bindings__[:parent_resources] || [],
calculations: %{},
public?: false
}
@ -84,14 +85,30 @@ defmodule AshPostgres.Sort do
|> Ash.Filter.hydrate_refs(%{
resource: resource,
aggregates: query.__ash_bindings__.aggregate_defs,
parent_stack: query.__ash_bindings__[:parent_resources] || [],
calculations: %{},
public?: false
})
|> Ash.Filter.move_to_relationship_path(relationship_path)
|> case do
{:ok, expr} ->
bindings =
if query.__ash_bindings__[:parent_bindings] do
Map.update!(query.__ash_bindings__, :parent_bindings, fn parent ->
Map.put(parent, :parent_is_parent_as?, false)
end)
else
query.__ash_bindings__
end
expr =
AshPostgres.Expr.dynamic_expr(query, expr, query.__ash_bindings__, false, type)
AshPostgres.Expr.dynamic_expr(
query,
expr,
bindings,
false,
type
)
{:cont, {:ok, query_expr ++ [{order, expr}]}}

View file

@ -4,6 +4,8 @@ defmodule AshPostgres.SortTest do
alias AshPostgres.Test.{Api, Comment, Post, PostLink}
require Ash.Query
require Ash.Sort
import Ash.Expr
test "multi-column sorts work" do
Post
@ -181,4 +183,46 @@ defmodule AshPostgres.SortTest do
|> Ash.Query.sort(:c_times_p)
|> Api.read!()
end
test "calculations can sort on expressions" do
post1 =
Post
|> Ash.Changeset.new(%{title: "aaa", score: 0})
|> Api.create!()
post2 =
Post
|> Ash.Changeset.new(%{title: "bbb", score: 1})
|> Api.create!()
post3 =
Post
|> Ash.Changeset.new(%{title: "ccc", score: 0})
|> Api.create!()
PostLink
|> Ash.Changeset.new()
|> Ash.Changeset.manage_relationship(:source_post, post1, type: :append)
|> Ash.Changeset.manage_relationship(:destination_post, post3, type: :append)
|> Api.create!()
PostLink
|> Ash.Changeset.new()
|> Ash.Changeset.manage_relationship(:source_post, post2, type: :append)
|> Ash.Changeset.manage_relationship(:destination_post, post2, type: :append)
|> Api.create!()
PostLink
|> Ash.Changeset.new()
|> Ash.Changeset.manage_relationship(:source_post, post3, type: :append)
|> Ash.Changeset.manage_relationship(:destination_post, post1, type: :append)
|> Api.create!()
posts_query =
Ash.Query.sort(Post, Ash.Sort.expr_sort(source(post_links.state)))
Post
|> Ash.Query.load(linked_posts: posts_query)
|> Api.read!()
end
end