Skip to content

Commit cad434e

Browse files
committed
Feat: ARX004_6A - SELECT SQL Integration Tests
Add comprehensive integration tests for SELECT SQL features: - ORDER BY ASC/DESC with single and multiple fields - GROUP BY with aggregates (count, sum) - SKIP and LIMIT pagination - Aggregate functions (COUNT, SUM, AVG, MIN, MAX) - Subqueries with LET variables - DISTINCT queries with set() function - Combined WHERE, ORDER BY, LIMIT queries 19 test scenarios all passing against real ArcadeDB server.
1 parent fe2bd97 commit cad434e

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
defmodule Arcadex.Integration.SQL.SelectTest do
2+
@moduledoc """
3+
Integration tests for SELECT SQL features against ArcadeDB.
4+
5+
Tests ORDER BY, GROUP BY, SKIP/LIMIT, aggregates, subqueries, and DISTINCT.
6+
"""
7+
use Arcadex.IntegrationCase, async: true
8+
9+
setup_all %{conn: conn} do
10+
# Create Product type with properties
11+
Arcadex.command!(conn, "CREATE DOCUMENT TYPE Product")
12+
Arcadex.command!(conn, "CREATE PROPERTY Product.uid STRING")
13+
Arcadex.command!(conn, "CREATE PROPERTY Product.name STRING")
14+
Arcadex.command!(conn, "CREATE PROPERTY Product.price DECIMAL")
15+
Arcadex.command!(conn, "CREATE PROPERTY Product.category STRING")
16+
Arcadex.command!(conn, "CREATE PROPERTY Product.stock INTEGER")
17+
Arcadex.command!(conn, "CREATE INDEX ON Product (uid) UNIQUE")
18+
19+
# Seed test data with 10 products
20+
for i <- 1..10 do
21+
Arcadex.command!(
22+
conn,
23+
"""
24+
INSERT INTO Product SET
25+
uid = :uid,
26+
name = :name,
27+
price = :price,
28+
category = :category,
29+
stock = :stock
30+
""",
31+
%{
32+
uid: "prod_#{i}",
33+
name: "Product #{i}",
34+
price: i * 10.0,
35+
category: if(rem(i, 2) == 0, do: "even", else: "odd"),
36+
stock: i * 5
37+
}
38+
)
39+
end
40+
41+
:ok
42+
end
43+
44+
describe "ORDER BY" do
45+
test "SELECT with ORDER BY ASC", %{conn: conn} do
46+
products =
47+
Arcadex.query!(
48+
conn,
49+
"SELECT name, price FROM Product ORDER BY price ASC LIMIT 3"
50+
)
51+
52+
prices = Enum.map(products, & &1["price"])
53+
assert prices == [10.0, 20.0, 30.0]
54+
end
55+
56+
test "SELECT with ORDER BY DESC", %{conn: conn} do
57+
products =
58+
Arcadex.query!(
59+
conn,
60+
"SELECT name, price FROM Product ORDER BY price DESC LIMIT 3"
61+
)
62+
63+
prices = Enum.map(products, & &1["price"])
64+
assert prices == [100.0, 90.0, 80.0]
65+
end
66+
67+
test "SELECT with multiple ORDER BY fields", %{conn: conn} do
68+
products =
69+
Arcadex.query!(
70+
conn,
71+
"SELECT name, category, price FROM Product ORDER BY category ASC, price DESC"
72+
)
73+
74+
# First should be 'even' category with highest price
75+
first = hd(products)
76+
assert first["category"] == "even"
77+
assert first["price"] == 100.0
78+
end
79+
end
80+
81+
describe "GROUP BY" do
82+
test "SELECT with GROUP BY", %{conn: conn} do
83+
results =
84+
Arcadex.query!(
85+
conn,
86+
"SELECT category, count(*) as cnt FROM Product GROUP BY category"
87+
)
88+
89+
assert length(results) == 2
90+
91+
by_category = Enum.into(results, %{}, fn r -> {r["category"], r["cnt"]} end)
92+
assert by_category["even"] == 5
93+
assert by_category["odd"] == 5
94+
end
95+
96+
test "SELECT with GROUP BY and aggregate", %{conn: conn} do
97+
results =
98+
Arcadex.query!(
99+
conn,
100+
"SELECT category, sum(price) as total FROM Product GROUP BY category ORDER BY category"
101+
)
102+
103+
# even: 20 + 40 + 60 + 80 + 100 = 300
104+
# odd: 10 + 30 + 50 + 70 + 90 = 250
105+
even_result = Enum.find(results, &(&1["category"] == "even"))
106+
odd_result = Enum.find(results, &(&1["category"] == "odd"))
107+
108+
assert even_result["total"] == 300.0
109+
assert odd_result["total"] == 250.0
110+
end
111+
end
112+
113+
describe "SKIP and LIMIT" do
114+
test "SELECT with SKIP and LIMIT", %{conn: conn} do
115+
products =
116+
Arcadex.query!(
117+
conn,
118+
"SELECT FROM Product ORDER BY price ASC SKIP 2 LIMIT 3"
119+
)
120+
121+
assert length(products) == 3
122+
prices = Enum.map(products, & &1["price"])
123+
# Skipping first 2 (10, 20), getting next 3 (30, 40, 50)
124+
assert prices == [30.0, 40.0, 50.0]
125+
end
126+
127+
test "SELECT with only LIMIT", %{conn: conn} do
128+
products =
129+
Arcadex.query!(
130+
conn,
131+
"SELECT FROM Product ORDER BY price ASC LIMIT 5"
132+
)
133+
134+
assert length(products) == 5
135+
end
136+
137+
test "SELECT with SKIP beyond data", %{conn: conn} do
138+
products =
139+
Arcadex.query!(
140+
conn,
141+
"SELECT FROM Product SKIP 100"
142+
)
143+
144+
assert products == []
145+
end
146+
end
147+
148+
describe "Aggregates" do
149+
test "SELECT with COUNT", %{conn: conn} do
150+
[result] =
151+
Arcadex.query!(
152+
conn,
153+
"SELECT count(*) as total FROM Product"
154+
)
155+
156+
assert result["total"] == 10
157+
end
158+
159+
test "SELECT with SUM", %{conn: conn} do
160+
[result] =
161+
Arcadex.query!(
162+
conn,
163+
"SELECT sum(price) as total FROM Product"
164+
)
165+
166+
# 10 + 20 + 30 + ... + 100 = 550
167+
assert result["total"] == 550.0
168+
end
169+
170+
test "SELECT with AVG", %{conn: conn} do
171+
[result] =
172+
Arcadex.query!(
173+
conn,
174+
"SELECT avg(price) as average FROM Product"
175+
)
176+
177+
# Average of 10, 20, ..., 100 = 55
178+
assert result["average"] == 55.0
179+
end
180+
181+
test "SELECT with MIN and MAX", %{conn: conn} do
182+
[result] =
183+
Arcadex.query!(
184+
conn,
185+
"SELECT min(price) as min_price, max(price) as max_price FROM Product"
186+
)
187+
188+
assert result["min_price"] == 10.0
189+
assert result["max_price"] == 100.0
190+
end
191+
192+
test "SELECT with multiple aggregates", %{conn: conn} do
193+
[result] =
194+
Arcadex.query!(
195+
conn,
196+
"SELECT count(*) as cnt, sum(stock) as total_stock, avg(price) as avg_price FROM Product"
197+
)
198+
199+
assert result["cnt"] == 10
200+
# stock: 5 + 10 + 15 + ... + 50 = 275
201+
assert result["total_stock"] == 275
202+
assert result["avg_price"] == 55.0
203+
end
204+
end
205+
206+
describe "Subqueries" do
207+
test "SELECT with subquery in WHERE", %{conn: conn} do
208+
# First get the average price
209+
[avg_result] =
210+
Arcadex.query!(
211+
conn,
212+
"SELECT avg(price) as avg_price FROM Product"
213+
)
214+
215+
avg_price = avg_result["avg_price"]
216+
217+
# Then use it in a parameterized query
218+
products =
219+
Arcadex.query!(
220+
conn,
221+
"""
222+
SELECT FROM Product
223+
WHERE price > :avg_price
224+
ORDER BY price ASC
225+
""",
226+
%{avg_price: avg_price}
227+
)
228+
229+
# Products with price > 55 (average): 60, 70, 80, 90, 100
230+
assert length(products) == 5
231+
prices = Enum.map(products, & &1["price"])
232+
assert Enum.all?(prices, &(&1 > 55.0))
233+
end
234+
235+
test "SELECT with LET variable for computed value", %{conn: conn} do
236+
# ArcadeDB uses LET for computed subquery values
237+
[result] =
238+
Arcadex.script!(
239+
conn,
240+
"""
241+
LET cnt = SELECT count(*) as cnt FROM Product;
242+
RETURN $cnt[0].cnt
243+
"""
244+
)
245+
246+
assert result["value"] == 10
247+
end
248+
end
249+
250+
describe "DISTINCT" do
251+
test "SELECT DISTINCT on single field", %{conn: conn} do
252+
results =
253+
Arcadex.query!(
254+
conn,
255+
"SELECT DISTINCT category FROM Product ORDER BY category"
256+
)
257+
258+
categories = Enum.map(results, & &1["category"])
259+
assert categories == ["even", "odd"]
260+
end
261+
262+
test "SELECT DISTINCT count", %{conn: conn} do
263+
# ArcadeDB requires set() to count distinct values
264+
[result] =
265+
Arcadex.query!(
266+
conn,
267+
"SELECT set(category).size() as distinct_categories FROM Product"
268+
)
269+
270+
assert result["distinct_categories"] == 2
271+
end
272+
end
273+
274+
describe "Combined features" do
275+
test "SELECT with WHERE, ORDER BY, and LIMIT", %{conn: conn} do
276+
products =
277+
Arcadex.query!(
278+
conn,
279+
"""
280+
SELECT name, price FROM Product
281+
WHERE category = 'odd'
282+
ORDER BY price DESC
283+
LIMIT 2
284+
"""
285+
)
286+
287+
assert length(products) == 2
288+
prices = Enum.map(products, & &1["price"])
289+
# Top 2 odd products by price: 90, 70
290+
assert prices == [90.0, 70.0]
291+
end
292+
293+
test "SELECT with GROUP BY, HAVING would require HAVING", %{conn: conn} do
294+
# ArcadeDB supports GROUP BY with aggregate filtering via WHERE
295+
results =
296+
Arcadex.query!(
297+
conn,
298+
"""
299+
SELECT category, count(*) as cnt, sum(price) as total
300+
FROM Product
301+
GROUP BY category
302+
ORDER BY total DESC
303+
"""
304+
)
305+
306+
# even total = 300, odd total = 250
307+
first = hd(results)
308+
assert first["category"] == "even"
309+
assert first["total"] == 300.0
310+
end
311+
end
312+
end

0 commit comments

Comments
 (0)