Current section
Files
Jump to
Current section
Files
test/integration/sql/select_test.exs
defmodule Arcadex.Integration.SQL.SelectTest do
@moduledoc """
Integration tests for SELECT SQL features against ArcadeDB.
Tests ORDER BY, GROUP BY, SKIP/LIMIT, aggregates, subqueries, and DISTINCT.
"""
use Arcadex.IntegrationCase, async: true
setup_all %{conn: conn} do
# Create Product type with properties
Arcadex.command!(conn, "CREATE DOCUMENT TYPE Product")
Arcadex.command!(conn, "CREATE PROPERTY Product.uid STRING")
Arcadex.command!(conn, "CREATE PROPERTY Product.name STRING")
Arcadex.command!(conn, "CREATE PROPERTY Product.price DECIMAL")
Arcadex.command!(conn, "CREATE PROPERTY Product.category STRING")
Arcadex.command!(conn, "CREATE PROPERTY Product.stock INTEGER")
Arcadex.command!(conn, "CREATE INDEX ON Product (uid) UNIQUE")
# Seed test data with 10 products
for i <- 1..10 do
Arcadex.command!(
conn,
"""
INSERT INTO Product SET
uid = :uid,
name = :name,
price = :price,
category = :category,
stock = :stock
""",
%{
uid: "prod_#{i}",
name: "Product #{i}",
price: i * 10.0,
category: if(rem(i, 2) == 0, do: "even", else: "odd"),
stock: i * 5
}
)
end
:ok
end
describe "ORDER BY" do
test "SELECT with ORDER BY ASC", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT name, price FROM Product ORDER BY price ASC LIMIT 3"
)
prices = Enum.map(products, & &1["price"])
assert prices == [10.0, 20.0, 30.0]
end
test "SELECT with ORDER BY DESC", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT name, price FROM Product ORDER BY price DESC LIMIT 3"
)
prices = Enum.map(products, & &1["price"])
assert prices == [100.0, 90.0, 80.0]
end
test "SELECT with multiple ORDER BY fields", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT name, category, price FROM Product ORDER BY category ASC, price DESC"
)
# First should be 'even' category with highest price
first = hd(products)
assert first["category"] == "even"
assert first["price"] == 100.0
end
end
describe "GROUP BY" do
test "SELECT with GROUP BY", %{conn: conn} do
results =
Arcadex.query!(
conn,
"SELECT category, count(*) as cnt FROM Product GROUP BY category"
)
assert length(results) == 2
by_category = Enum.into(results, %{}, fn r -> {r["category"], r["cnt"]} end)
assert by_category["even"] == 5
assert by_category["odd"] == 5
end
test "SELECT with GROUP BY and aggregate", %{conn: conn} do
results =
Arcadex.query!(
conn,
"SELECT category, sum(price) as total FROM Product GROUP BY category ORDER BY category"
)
# even: 20 + 40 + 60 + 80 + 100 = 300
# odd: 10 + 30 + 50 + 70 + 90 = 250
even_result = Enum.find(results, &(&1["category"] == "even"))
odd_result = Enum.find(results, &(&1["category"] == "odd"))
assert even_result["total"] == 300.0
assert odd_result["total"] == 250.0
end
end
describe "SKIP and LIMIT" do
test "SELECT with SKIP and LIMIT", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT FROM Product ORDER BY price ASC SKIP 2 LIMIT 3"
)
assert length(products) == 3
prices = Enum.map(products, & &1["price"])
# Skipping first 2 (10, 20), getting next 3 (30, 40, 50)
assert prices == [30.0, 40.0, 50.0]
end
test "SELECT with only LIMIT", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT FROM Product ORDER BY price ASC LIMIT 5"
)
assert length(products) == 5
end
test "SELECT with SKIP beyond data", %{conn: conn} do
products =
Arcadex.query!(
conn,
"SELECT FROM Product SKIP 100"
)
assert products == []
end
end
describe "Aggregates" do
test "SELECT with COUNT", %{conn: conn} do
[result] =
Arcadex.query!(
conn,
"SELECT count(*) as total FROM Product"
)
assert result["total"] == 10
end
test "SELECT with SUM", %{conn: conn} do
[result] =
Arcadex.query!(
conn,
"SELECT sum(price) as total FROM Product"
)
# 10 + 20 + 30 + ... + 100 = 550
assert result["total"] == 550.0
end
test "SELECT with AVG", %{conn: conn} do
[result] =
Arcadex.query!(
conn,
"SELECT avg(price) as average FROM Product"
)
# Average of 10, 20, ..., 100 = 55
assert result["average"] == 55.0
end
test "SELECT with MIN and MAX", %{conn: conn} do
[result] =
Arcadex.query!(
conn,
"SELECT min(price) as min_price, max(price) as max_price FROM Product"
)
assert result["min_price"] == 10.0
assert result["max_price"] == 100.0
end
test "SELECT with multiple aggregates", %{conn: conn} do
[result] =
Arcadex.query!(
conn,
"SELECT count(*) as cnt, sum(stock) as total_stock, avg(price) as avg_price FROM Product"
)
assert result["cnt"] == 10
# stock: 5 + 10 + 15 + ... + 50 = 275
assert result["total_stock"] == 275
assert result["avg_price"] == 55.0
end
end
describe "Subqueries" do
test "SELECT with subquery in WHERE", %{conn: conn} do
# First get the average price
[avg_result] =
Arcadex.query!(
conn,
"SELECT avg(price) as avg_price FROM Product"
)
avg_price = avg_result["avg_price"]
# Then use it in a parameterized query
products =
Arcadex.query!(
conn,
"""
SELECT FROM Product
WHERE price > :avg_price
ORDER BY price ASC
""",
%{avg_price: avg_price}
)
# Products with price > 55 (average): 60, 70, 80, 90, 100
assert length(products) == 5
prices = Enum.map(products, & &1["price"])
assert Enum.all?(prices, &(&1 > 55.0))
end
test "SELECT with LET variable for computed value", %{conn: conn} do
# ArcadeDB uses LET for computed subquery values
[result] =
Arcadex.script!(
conn,
"""
LET cnt = SELECT count(*) as cnt FROM Product;
RETURN $cnt[0].cnt
"""
)
assert result["value"] == 10
end
end
describe "DISTINCT" do
test "SELECT DISTINCT on single field", %{conn: conn} do
results =
Arcadex.query!(
conn,
"SELECT DISTINCT category FROM Product ORDER BY category"
)
categories = Enum.map(results, & &1["category"])
assert categories == ["even", "odd"]
end
test "SELECT DISTINCT count", %{conn: conn} do
# ArcadeDB requires set() to count distinct values
[result] =
Arcadex.query!(
conn,
"SELECT set(category).size() as distinct_categories FROM Product"
)
assert result["distinct_categories"] == 2
end
end
describe "Combined features" do
test "SELECT with WHERE, ORDER BY, and LIMIT", %{conn: conn} do
products =
Arcadex.query!(
conn,
"""
SELECT name, price FROM Product
WHERE category = 'odd'
ORDER BY price DESC
LIMIT 2
"""
)
assert length(products) == 2
prices = Enum.map(products, & &1["price"])
# Top 2 odd products by price: 90, 70
assert prices == [90.0, 70.0]
end
test "SELECT with GROUP BY, HAVING would require HAVING", %{conn: conn} do
# ArcadeDB supports GROUP BY with aggregate filtering via WHERE
results =
Arcadex.query!(
conn,
"""
SELECT category, count(*) as cnt, sum(price) as total
FROM Product
GROUP BY category
ORDER BY total DESC
"""
)
# even total = 300, odd total = 250
first = hd(results)
assert first["category"] == "even"
assert first["total"] == 300.0
end
end
end