@@ -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
@@ -1920,6 +1921,81 @@ defmodule AshSql.AggregateTest do
19201921 end
19211922 end
19221923
1924+ test "aggregate with parent() ref in relationship filter and sorting on relationship field" do
1925+ chat_1 =
1926+ Chat
1927+ |> Ash.Changeset . for_create ( :create , % { name: "Test Chat" } )
1928+ |> Ash . create! ( )
1929+
1930+ chat_1_message_1 =
1931+ AshPostgres.Test.Message
1932+ |> Ash.Changeset . for_create ( :create , % {
1933+ chat_id: chat_1 . id ,
1934+ content: "First message" ,
1935+ sent_at: DateTime . add ( DateTime . utc_now ( ) , - 3600 , :second )
1936+ } )
1937+ |> Ash . create! ( )
1938+
1939+ _chat_1_message_2 =
1940+ AshPostgres.Test.Message
1941+ |> Ash.Changeset . for_create ( :create , % {
1942+ chat_id: chat_1 . id ,
1943+ content: "Second message" ,
1944+ sent_at: DateTime . add ( DateTime . utc_now ( ) , - 1800 , :second )
1945+ } )
1946+ |> Ash . create! ( )
1947+
1948+ # Update chat to set last_read_message to the first message
1949+ # This means message_2 should be "unread"
1950+ _chat =
1951+ chat_1
1952+ |> Ash.Changeset . for_update ( :update , % { last_read_message_id: chat_1_message_1 . id } )
1953+ |> Ash . update! ( )
1954+
1955+ # Create a second chat to force multiple records and trigger DISTINCT ON
1956+ chat_2 =
1957+ Chat
1958+ |> Ash.Changeset . for_create ( :create , % { name: "Test Chat 2" } )
1959+ |> Ash . create! ( )
1960+
1961+ chat_2_message_1 =
1962+ AshPostgres.Test.Message
1963+ |> Ash.Changeset . for_create ( :create , % {
1964+ chat_id: chat_2 . id ,
1965+ content: "Chat 2 - Message 1" ,
1966+ sent_at: DateTime . add ( DateTime . utc_now ( ) , - 100 , :second )
1967+ } )
1968+ |> Ash . create! ( )
1969+
1970+ AshPostgres.Test.Message
1971+ |> Ash.Changeset . for_create ( :create , % {
1972+ chat_id: chat_2 . id ,
1973+ content: "Chat 2 - Message 2" ,
1974+ sent_at: DateTime . utc_now ( )
1975+ } )
1976+ |> Ash . create! ( )
1977+
1978+ chat_2
1979+ |> Ash.Changeset . for_update ( :update , % { last_read_message_id: chat_2_message_1 . id } )
1980+ |> Ash . update! ( )
1981+
1982+ # This query should work but fails without the fix:
1983+ # - select() excludes last_read_message_id from the query
1984+ # - Sorting by last_message.sent_at (has_one from_many?) causes DISTINCT ON + subquery wrapping
1985+ # - Loading unread_messages_count_alt (aggregate on relationship with parent() in filter)
1986+ # uses a lateral join that references parent(last_read_message_id)
1987+ # - The wrapped subquery doesn't include last_read_message_id, so the lateral join fails
1988+ result =
1989+ Chat
1990+ |> Ash.Query . filter ( id in [ ^ chat_1 . id , ^ chat_2 . id ] )
1991+ |> Ash.Query . select ( [ :id , :name ] )
1992+ |> Ash.Query . load ( :unread_messages_count_alt )
1993+ |> Ash.Query . sort ( [ { Ash.Sort . expr_sort ( expr ( last_message . sent_at ) ) , :asc } ] )
1994+ |> Ash . read! ( )
1995+
1996+ assert length ( result ) == 2
1997+ end
1998+
19231999 test "multiple aggregates filtering on nested first aggregate" do
19242000 post =
19252001 Post
0 commit comments