Skip to content

Commit 29db3e6

Browse files
committed
test: add a test that shows problems with two multiple relationships
1 parent ee7da5b commit 29db3e6

File tree

11 files changed

+506
-1
lines changed

11 files changed

+506
-1
lines changed

lib/verifiers/validate_check_constraints.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,3 @@ defmodule AshPostgres.Verifiers.ValidateCheckConstraints do
3333
:ok
3434
end
3535
end
36-
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"attributes": [
3+
{
4+
"allow_nil?": false,
5+
"default": "fragment(\"uuid_generate_v7()\")",
6+
"generated?": false,
7+
"precision": null,
8+
"primary_key?": true,
9+
"references": null,
10+
"scale": null,
11+
"size": null,
12+
"source": "id",
13+
"type": "uuid"
14+
}
15+
],
16+
"base_filter": null,
17+
"check_constraints": [],
18+
"custom_indexes": [],
19+
"custom_statements": [],
20+
"has_create_action": true,
21+
"hash": "85454A705DFC565FD634E25E9CE8FB510367A800470B9B85E0FA65494AC296D8",
22+
"identities": [],
23+
"multitenancy": {
24+
"attribute": null,
25+
"global": null,
26+
"strategy": null
27+
},
28+
"repo": "Elixir.AshPostgres.TestRepo",
29+
"schema": null,
30+
"table": "containers"
31+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2019 ash_postgres contributors <https://github.com/ash-project/ash_postgres/graphs.contributors>
2+
3+
SPDX-License-Identifier: MIT
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
{
2+
"attributes": [
3+
{
4+
"allow_nil?": false,
5+
"default": "fragment(\"uuid_generate_v7()\")",
6+
"generated?": false,
7+
"precision": null,
8+
"primary_key?": true,
9+
"references": null,
10+
"scale": null,
11+
"size": null,
12+
"source": "id",
13+
"type": "uuid"
14+
},
15+
{
16+
"allow_nil?": true,
17+
"default": "nil",
18+
"generated?": false,
19+
"precision": null,
20+
"primary_key?": false,
21+
"references": null,
22+
"scale": null,
23+
"size": null,
24+
"source": "name",
25+
"type": "text"
26+
},
27+
{
28+
"allow_nil?": true,
29+
"default": "false",
30+
"generated?": false,
31+
"precision": null,
32+
"primary_key?": false,
33+
"references": null,
34+
"scale": null,
35+
"size": null,
36+
"source": "active",
37+
"type": "boolean"
38+
},
39+
{
40+
"allow_nil?": true,
41+
"default": "nil",
42+
"generated?": false,
43+
"precision": null,
44+
"primary_key?": false,
45+
"references": {
46+
"deferrable": false,
47+
"destination_attribute": "id",
48+
"destination_attribute_default": null,
49+
"destination_attribute_generated": null,
50+
"index?": false,
51+
"match_type": null,
52+
"match_with": null,
53+
"multitenancy": {
54+
"attribute": null,
55+
"global": null,
56+
"strategy": null
57+
},
58+
"name": "items_container_id_fkey",
59+
"on_delete": null,
60+
"on_update": null,
61+
"primary_key?": true,
62+
"schema": "public",
63+
"table": "containers"
64+
},
65+
"scale": null,
66+
"size": null,
67+
"source": "container_id",
68+
"type": "uuid"
69+
},
70+
{
71+
"allow_nil?": true,
72+
"default": "nil",
73+
"generated?": false,
74+
"precision": null,
75+
"primary_key?": false,
76+
"references": null,
77+
"scale": null,
78+
"size": null,
79+
"source": "key",
80+
"type": "text"
81+
},
82+
{
83+
"allow_nil?": true,
84+
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
85+
"generated?": false,
86+
"precision": null,
87+
"primary_key?": false,
88+
"references": null,
89+
"scale": null,
90+
"size": null,
91+
"source": "inserted_at",
92+
"type": "utc_datetime_usec"
93+
},
94+
{
95+
"allow_nil?": true,
96+
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
97+
"generated?": false,
98+
"precision": null,
99+
"primary_key?": false,
100+
"references": null,
101+
"scale": null,
102+
"size": null,
103+
"source": "updated_at",
104+
"type": "utc_datetime_usec"
105+
}
106+
],
107+
"base_filter": null,
108+
"check_constraints": [],
109+
"custom_indexes": [],
110+
"custom_statements": [],
111+
"has_create_action": true,
112+
"hash": "8BF7AAEFEDD546F7EF1E399B6267932F80A964026BD5299E54C56AC52346833C",
113+
"identities": [],
114+
"multitenancy": {
115+
"attribute": null,
116+
"global": null,
117+
"strategy": null
118+
},
119+
"repo": "Elixir.AshPostgres.TestRepo",
120+
"schema": null,
121+
"table": "items"
122+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2019 ash_postgres contributors <https://github.com/ash-project/ash_postgres/graphs.contributors>
2+
3+
SPDX-License-Identifier: MIT
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# SPDX-FileCopyrightText: 2019 ash_postgres contributors <https://github.com/ash-project/ash_postgres/graphs.contributors>
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
defmodule AshPostgres.TestRepo.Migrations.MigrateResources67 do
6+
@moduledoc """
7+
Updates resources based on their most recent snapshots.
8+
9+
This file was autogenerated with `mix ash_postgres.generate_migrations`
10+
"""
11+
12+
use Ecto.Migration
13+
14+
def up do
15+
alter table(:items) do
16+
modify(:updated_at, :utc_datetime_usec, null: true)
17+
modify(:inserted_at, :utc_datetime_usec, null: true)
18+
add(:name, :text)
19+
add(:active, :boolean, default: false)
20+
add(:container_id, :uuid)
21+
end
22+
23+
create table(:containers, primary_key: false) do
24+
add(:id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true)
25+
end
26+
27+
alter table(:items) do
28+
modify(
29+
:container_id,
30+
references(:containers,
31+
column: :id,
32+
name: "items_container_id_fkey",
33+
type: :uuid,
34+
prefix: "public"
35+
)
36+
)
37+
end
38+
end
39+
40+
def down do
41+
drop(constraint(:items, "items_container_id_fkey"))
42+
43+
alter table(:items) do
44+
modify(:container_id, :uuid)
45+
end
46+
47+
drop(table(:containers))
48+
49+
alter table(:items) do
50+
remove(:container_id)
51+
remove(:active)
52+
remove(:name)
53+
modify(:inserted_at, :utc_datetime_usec, null: false)
54+
modify(:updated_at, :utc_datetime_usec, null: false)
55+
end
56+
end
57+
end

test/aggregate_test.exs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,4 +1919,69 @@ defmodule AshSql.AggregateTest do
19191919
|> Ash.read!()
19201920
end
19211921
end
1922+
1923+
describe "page with count and aggregates with relationship-based calculations" do
1924+
test "loads relationship-based calculations correctly when using page(count: true) with aggregates" do
1925+
# This test reproduces the bug from https://github.com/ash-project/ash_sql/issues/191
1926+
# When using page(count: true) with both an aggregate and a calculation that depends on
1927+
# a relationship, the calculation fails to load (remains #Ash.NotLoaded)
1928+
1929+
# Create test data
1930+
author =
1931+
Author
1932+
|> Ash.Changeset.for_create(:create, %{
1933+
first_name: "John",
1934+
last_name: "Doe"
1935+
})
1936+
|> Ash.create!()
1937+
1938+
post =
1939+
Post
1940+
|> Ash.Changeset.for_create(:create, %{
1941+
title: "Test Post"
1942+
})
1943+
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
1944+
|> Ash.create!()
1945+
1946+
Comment
1947+
|> Ash.Changeset.for_create(:create, %{title: "Test Comment"})
1948+
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
1949+
|> Ash.create!()
1950+
1951+
# Test without page(count: true) - should work
1952+
result_without_page_count =
1953+
Post
1954+
|> Ash.Query.filter(id == ^post.id)
1955+
|> Ash.Query.load([
1956+
# aggregate
1957+
:count_of_comments,
1958+
# calculation that depends on author relationship
1959+
:author_first_name_calc
1960+
])
1961+
|> Ash.read_one!()
1962+
1963+
assert result_without_page_count.count_of_comments == 1
1964+
assert result_without_page_count.author_first_name_calc == "John"
1965+
1966+
Logger.configure(level: :debug)
1967+
# Test with page(count: true) - this triggers the bug
1968+
%{results: [result_with_page_count | _]} =
1969+
Post
1970+
|> Ash.Query.filter(id == ^post.id)
1971+
|> Ash.Query.load([
1972+
# aggregate
1973+
:count_of_comments,
1974+
# calculation that depends on author relationship
1975+
:author_first_name_calc
1976+
])
1977+
|> Ash.Query.page(limit: 50, offset: 0, count: true)
1978+
|> Ash.read!()
1979+
1980+
# Both should be loaded correctly
1981+
assert result_with_page_count.count_of_comments == 1
1982+
# This assertion should fail if the bug is present
1983+
assert result_with_page_count.author_first_name_calc == "John",
1984+
"Calculation was not loaded when using page(count: true) with aggregates"
1985+
end
1986+
end
19221987
end

0 commit comments

Comments
 (0)