Skip to content

Commit dd57500

Browse files
committed
test: Add tests for combination queries and loading calculations
These tests show that loading calculations in queries that have combinations works.
1 parent b175eb4 commit dd57500

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
defmodule AshPostgres.CombinationNullableCalcTest do
2+
@moduledoc false
3+
use AshPostgres.RepoCase, async: false
4+
alias AshPostgres.Test.Author
5+
alias AshPostgres.Test.Post
6+
7+
require Ash.Query
8+
import Ash.Expr
9+
10+
describe "combination_of with nullable calculations" do
11+
test "combination query with allow_nil? calculation loses ORDER BY" do
12+
Post
13+
|> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5})
14+
|> Ash.create!()
15+
16+
Post
17+
|> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25})
18+
|> Ash.create!()
19+
20+
Post
21+
|> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10})
22+
|> Ash.create!()
23+
24+
Post
25+
|> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20})
26+
|> Ash.create!()
27+
28+
query =
29+
Post
30+
|> Ash.Query.sort([{:title, :asc}])
31+
|> Ash.Query.load([:latest_comment_title])
32+
|> Ash.Query.combination_of([
33+
Ash.Query.Combination.base(
34+
filter: expr(score < 15),
35+
calculations: %{
36+
sort_order: calc(score * 20, type: :integer)
37+
},
38+
sort: [{calc(score * 20, type: :integer), :desc}]
39+
),
40+
Ash.Query.Combination.union(
41+
filter: expr(score >= 15),
42+
calculations: %{
43+
sort_order: calc(score * 5, type: :integer)
44+
},
45+
sort: [{calc(score * 5, type: :integer), :desc}]
46+
)
47+
])
48+
|> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true)
49+
50+
result = Ash.read!(query)
51+
titles = Enum.map(result, & &1.title)
52+
# Expected order: sort_order DESC, then title ASC
53+
# Dog(200), Apple(125), Cat(100), Zebra(100)
54+
expected_title_order = ["Dog", "Apple", "Cat", "Zebra"]
55+
assert titles == expected_title_order
56+
end
57+
58+
test "combination query without nullable calc works" do
59+
Post
60+
|> Ash.Changeset.for_create(:create, %{title: "Zebra", score: 5})
61+
|> Ash.create!()
62+
63+
Post
64+
|> Ash.Changeset.for_create(:create, %{title: "Apple", score: 25})
65+
|> Ash.create!()
66+
67+
Post
68+
|> Ash.Changeset.for_create(:create, %{title: "Dog", score: 10})
69+
|> Ash.create!()
70+
71+
Post
72+
|> Ash.Changeset.for_create(:create, %{title: "Cat", score: 20})
73+
|> Ash.create!()
74+
75+
query =
76+
Post
77+
|> Ash.Query.sort([{:title, :asc}])
78+
|> Ash.Query.combination_of([
79+
Ash.Query.Combination.base(
80+
filter: expr(score < 15),
81+
calculations: %{
82+
sort_order: calc(score * 20, type: :integer)
83+
},
84+
sort: [{calc(score * 20, type: :integer), :desc}]
85+
),
86+
Ash.Query.Combination.union(
87+
filter: expr(score >= 15),
88+
calculations: %{
89+
sort_order: calc(score * 5, type: :integer)
90+
},
91+
sort: [{calc(score * 5, type: :integer), :desc}]
92+
)
93+
])
94+
|> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true)
95+
96+
result = Ash.read!(query)
97+
titles = Enum.map(result, & &1.title)
98+
# Expected order: sort_order DESC, then title ASC
99+
# Dog(200), Apple(125), Cat(100), Zebra(100)
100+
expected_title_order = ["Dog", "Apple", "Cat", "Zebra"]
101+
assert titles == expected_title_order
102+
end
103+
end
104+
105+
describe "Author combination_of with nullable calculations" do
106+
test "Author combination query with allow_nil? calculation loses ORDER BY" do
107+
Author
108+
|> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"})
109+
|> Ash.create!()
110+
111+
Author
112+
|> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"})
113+
|> Ash.create!()
114+
115+
Author
116+
|> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"})
117+
|> Ash.create!()
118+
119+
Author
120+
|> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"})
121+
|> Ash.create!()
122+
123+
query =
124+
Author
125+
|> Ash.Query.sort([{:first_name, :asc}])
126+
|> Ash.Query.load([:profile_description_calc])
127+
|> Ash.Query.combination_of([
128+
Ash.Query.Combination.base(
129+
filter: expr(first_name in ["Zebra", "Dog"]),
130+
calculations: %{
131+
sort_order: calc(1000, type: :integer)
132+
},
133+
sort: [{calc(1000, type: :integer), :desc}]
134+
),
135+
Ash.Query.Combination.union(
136+
filter: expr(first_name in ["Apple", "Cat"]),
137+
calculations: %{
138+
sort_order: calc(500, type: :integer)
139+
},
140+
sort: [{calc(500, type: :integer), :desc}]
141+
)
142+
])
143+
|> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true)
144+
145+
result = Ash.read!(query)
146+
first_names = Enum.map(result, & &1.first_name)
147+
# Expected order: sort_order DESC, then first_name ASC
148+
# [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat
149+
expected_name_order = ["Dog", "Zebra", "Apple", "Cat"]
150+
assert first_names == expected_name_order
151+
end
152+
153+
test "Author combination query without nullable calc works" do
154+
Author
155+
|> Ash.Changeset.for_create(:create, %{first_name: "Zebra", last_name: "User"})
156+
|> Ash.create!()
157+
158+
Author
159+
|> Ash.Changeset.for_create(:create, %{first_name: "Apple", last_name: "User"})
160+
|> Ash.create!()
161+
162+
Author
163+
|> Ash.Changeset.for_create(:create, %{first_name: "Dog", last_name: "User"})
164+
|> Ash.create!()
165+
166+
Author
167+
|> Ash.Changeset.for_create(:create, %{first_name: "Cat", last_name: "User"})
168+
|> Ash.create!()
169+
170+
query =
171+
Author
172+
|> Ash.Query.sort([{:first_name, :asc}])
173+
|> Ash.Query.combination_of([
174+
Ash.Query.Combination.base(
175+
filter: expr(first_name in ["Zebra", "Dog"]),
176+
calculations: %{
177+
sort_order: calc(1000, type: :integer)
178+
}
179+
),
180+
Ash.Query.Combination.union(
181+
filter: expr(first_name in ["Apple", "Cat"]),
182+
calculations: %{
183+
sort_order: calc(500, type: :integer)
184+
}
185+
)
186+
])
187+
|> Ash.Query.sort([{calc(^combinations(:sort_order)), :desc}], prepend?: true)
188+
189+
result = Ash.read!(query)
190+
first_names = Enum.map(result, & &1.first_name)
191+
# Expected order: sort_order DESC, then first_name ASC
192+
# [Dog, Zebra] (1000), [Apple, Cat] (500) → Dog, Zebra, Apple, Cat
193+
expected_name_order = ["Dog", "Zebra", "Apple", "Cat"]
194+
assert first_names == expected_name_order
195+
end
196+
end
197+
end

test/support/resources/author.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ defmodule AshPostgres.Test.Author do
175175

176176
calculate(:has_posts, :boolean, expr(exists(posts, true == true)))
177177
calculate(:has_no_posts, :boolean, expr(has_posts == false))
178+
179+
calculate(:profile_description_calc, :string, expr(profile.description), allow_nil?: true)
178180
end
179181

180182
aggregates do

test/support/resources/post.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,8 @@ defmodule AshPostgres.Test.Post do
10061006
calculate(:author_first_name_ref_agg_calc, :string, expr(author_first_name))
10071007

10081008
calculate(:author_profile_description_from_agg, :string, expr(author_profile_description))
1009+
1010+
calculate(:latest_comment_title, :string, expr(latest_comment.title), allow_nil?: true)
10091011
end
10101012

10111013
aggregates do

0 commit comments

Comments
 (0)