Skip to content

Commit d3c8ca2

Browse files
authored
test: aggregate with parent ref in relationship filter and sorting on relationship field (#658)
1 parent 5a417a4 commit d3c8ca2

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

test/aggregate_test.exs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule AshSql.AggregateTest do
88
alias AshPostgres.Test.{Author, Chat, Comment, Organization, Post, Rating, User}
99

1010
require Ash.Query
11+
require Ash.Sort
1112
import Ash.Expr
1213

1314
test "nested sum aggregates" do
@@ -1975,6 +1976,81 @@ defmodule AshSql.AggregateTest do
19751976
end
19761977
end
19771978

1979+
test "aggregate with parent() ref in relationship filter and sorting on relationship field" do
1980+
chat_1 =
1981+
Chat
1982+
|> Ash.Changeset.for_create(:create, %{name: "Test Chat"})
1983+
|> Ash.create!()
1984+
1985+
chat_1_message_1 =
1986+
AshPostgres.Test.Message
1987+
|> Ash.Changeset.for_create(:create, %{
1988+
chat_id: chat_1.id,
1989+
content: "First message",
1990+
sent_at: DateTime.add(DateTime.utc_now(), -3600, :second)
1991+
})
1992+
|> Ash.create!()
1993+
1994+
_chat_1_message_2 =
1995+
AshPostgres.Test.Message
1996+
|> Ash.Changeset.for_create(:create, %{
1997+
chat_id: chat_1.id,
1998+
content: "Second message",
1999+
sent_at: DateTime.add(DateTime.utc_now(), -1800, :second)
2000+
})
2001+
|> Ash.create!()
2002+
2003+
# Update chat to set last_read_message to the first message
2004+
# This means message_2 should be "unread"
2005+
_chat =
2006+
chat_1
2007+
|> Ash.Changeset.for_update(:update, %{last_read_message_id: chat_1_message_1.id})
2008+
|> Ash.update!()
2009+
2010+
# Create a second chat to force multiple records and trigger DISTINCT ON
2011+
chat_2 =
2012+
Chat
2013+
|> Ash.Changeset.for_create(:create, %{name: "Test Chat 2"})
2014+
|> Ash.create!()
2015+
2016+
chat_2_message_1 =
2017+
AshPostgres.Test.Message
2018+
|> Ash.Changeset.for_create(:create, %{
2019+
chat_id: chat_2.id,
2020+
content: "Chat 2 - Message 1",
2021+
sent_at: DateTime.add(DateTime.utc_now(), -100, :second)
2022+
})
2023+
|> Ash.create!()
2024+
2025+
AshPostgres.Test.Message
2026+
|> Ash.Changeset.for_create(:create, %{
2027+
chat_id: chat_2.id,
2028+
content: "Chat 2 - Message 2",
2029+
sent_at: DateTime.utc_now()
2030+
})
2031+
|> Ash.create!()
2032+
2033+
chat_2
2034+
|> Ash.Changeset.for_update(:update, %{last_read_message_id: chat_2_message_1.id})
2035+
|> Ash.update!()
2036+
2037+
# This query exercises the following conditions:
2038+
# - select() excludes last_read_message_id from the query
2039+
# - Sorting by last_message.sent_at (has_one from_many?) causes DISTINCT ON + subquery wrapping
2040+
# - Loading unread_messages_count_alt (aggregate on relationship with parent() in filter)
2041+
# uses a lateral join that references parent(last_read_message_id)
2042+
# - The wrapped subquery must include last_read_message_id for the lateral join to work
2043+
result =
2044+
Chat
2045+
|> Ash.Query.filter(id in [^chat_1.id, ^chat_2.id])
2046+
|> Ash.Query.select([:id, :name])
2047+
|> Ash.Query.load(:unread_messages_count_alt)
2048+
|> Ash.Query.sort([{Ash.Sort.expr_sort(expr(last_message.sent_at)), :asc}])
2049+
|> Ash.read!()
2050+
2051+
assert length(result) == 2
2052+
end
2053+
19782054
test "multiple aggregates filtering on nested first aggregate" do
19792055
post =
19802056
Post

test/support/resources/chat.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,22 @@ defmodule AshPostgres.Test.Chat do
4646
filter(expr(is_nil(read_at)))
4747
sort(sent_at: :desc)
4848
end
49+
50+
has_many :unread_messages, AshPostgres.Test.Message do
51+
public?(true)
52+
no_attributes?(true)
53+
filter(expr(is_nil(parent(last_read_message_id)) or id > parent(last_read_message_id)))
54+
end
4955
end
5056

5157
aggregates do
5258
count :unread_message_count, :messages do
5359
public?(true)
5460
filter(expr(is_nil(parent(last_read_message_id)) or id > parent(last_read_message_id)))
5561
end
62+
63+
count :unread_messages_count_alt, :unread_messages do
64+
public?(true)
65+
end
5666
end
5767
end

0 commit comments

Comments
 (0)