Skip to content

Commit

Permalink
improvement: support parent in sort expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Oct 26, 2023
1 parent 75208a7 commit 342920a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 5 deletions.
12 changes: 11 additions & 1 deletion lib/data_layer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
8 changes: 5 additions & 3 deletions lib/expr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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
Expand Down
19 changes: 18 additions & 1 deletion lib/sort.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule AshPostgres.Sort do
%{
resource: resource,
aggregates: %{},
parent_stack: query.__ash_bindings__[:parent_resources] || [],
calculations: %{},
public?: false
}
Expand Down Expand Up @@ -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}]}}

Expand Down
44 changes: 44 additions & 0 deletions test/sort_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit 342920a

Please sign in to comment.