use stoolap::Database;
fn setup_sales_table(db: &Database) {
db.execute("CREATE TABLE sales_aggr (id INTEGER, product TEXT, category TEXT, amount FLOAT, region TEXT)", ())
.expect("Failed to create table");
let inserts = [
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (1, 'Laptop', 'Electronics', 1200.0, 'North')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (2, 'Smartphone', 'Electronics', 800.0, 'North')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (3, 'TV', 'Electronics', 1500.0, 'South')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (4, 'Chair', 'Furniture', 150.0, 'East')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (5, 'Table', 'Furniture', 450.0, 'East')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (6, 'Sofa', 'Furniture', 950.0, 'West')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (7, 'Shirt', 'Clothing', 35.0, 'North')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (8, 'Jeans', 'Clothing', 60.0, 'South')",
"INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (9, 'Shoes', 'Clothing', 90.0, 'West')",
];
for insert in &inserts {
db.execute(insert, ()).expect("Failed to insert data");
}
}
#[test]
fn test_count_star() {
let db = Database::open("memory://aggregation_count_star").expect("Failed to create database");
setup_sales_table(&db);
let count: i64 = db.query_one("SELECT COUNT(*) FROM sales_aggr", ()).unwrap();
assert_eq!(count, 9, "Expected count of 9");
}
#[test]
fn test_count_with_group_by() {
let db = Database::open("memory://aggregation_group_by").expect("Failed to create database");
setup_sales_table(&db);
let result = db
.query(
"SELECT category, COUNT(*) FROM sales_aggr GROUP BY category",
(),
)
.expect("Failed to query");
let mut row_count = 0;
for row in result {
let row = row.expect("Failed to get row");
row_count += 1;
let _category: String = row.get(0).unwrap();
let count: i64 = row.get(1).unwrap();
assert_eq!(count, 3, "Each category should have 3 items");
}
assert_eq!(row_count, 3, "Expected 3 category groups");
}
#[test]
fn test_count_distinct() {
let db =
Database::open("memory://aggregation_count_distinct").expect("Failed to create database");
setup_sales_table(&db);
db.execute("INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (10, 'Laptop', 'Electronics', 1200.0, 'North')", ())
.expect("Failed to insert duplicate");
let distinct_count: i64 = db
.query_one("SELECT COUNT(DISTINCT product) FROM sales_aggr", ())
.unwrap();
assert_eq!(distinct_count, 9, "Expected 9 distinct products");
}
#[test]
fn test_group_by_with_having() {
let db = Database::open("memory://aggregation_having").expect("Failed to create database");
setup_sales_table(&db);
db.execute("INSERT INTO sales_aggr (id, product, category, amount, region) VALUES (10, 'Laptop', 'Electronics', 1200.0, 'North')", ())
.expect("Failed to insert duplicate");
let result = db
.query(
"SELECT category, COUNT(*) as cnt FROM sales_aggr GROUP BY category HAVING cnt > 2",
(),
)
.expect("Failed to query");
let mut row_count = 0;
let mut categories = std::collections::HashSet::new();
for row in result {
let row = row.expect("Failed to get row");
row_count += 1;
let category: String = row.get(0).unwrap();
let count: i64 = row.get(1).unwrap();
assert!(
count > 2,
"Expected count > 2 for category {}, got {}",
category,
count
);
categories.insert(category);
}
assert_eq!(
row_count, 3,
"Expected 3 rows (Electronics, Furniture, Clothing)"
);
assert!(
categories.contains("Electronics"),
"Expected Electronics in results"
);
assert!(
categories.contains("Furniture"),
"Expected Furniture in results"
);
assert!(
categories.contains("Clothing"),
"Expected Clothing in results"
);
}
#[test]
fn test_sum_function() {
let db = Database::open("memory://aggregation_sum").expect("Failed to create database");
setup_sales_table(&db);
let total: f64 = db
.query_one("SELECT SUM(amount) FROM sales_aggr", ())
.unwrap();
assert!(
(total - 5235.0).abs() < 0.01,
"Expected sum of 5235, got {}",
total
);
}
#[test]
fn test_avg_function() {
let db = Database::open("memory://aggregation_avg").expect("Failed to create database");
setup_sales_table(&db);
let avg: f64 = db
.query_one("SELECT AVG(amount) FROM sales_aggr", ())
.unwrap();
assert!(
(avg - 581.67).abs() < 0.01,
"Expected avg of ~581.67, got {}",
avg
);
}
#[test]
fn test_min_function() {
let db = Database::open("memory://aggregation_min").expect("Failed to create database");
setup_sales_table(&db);
let min: f64 = db
.query_one("SELECT MIN(amount) FROM sales_aggr", ())
.unwrap();
assert!((min - 35.0).abs() < 0.01, "Expected min of 35, got {}", min);
}
#[test]
fn test_max_function() {
let db = Database::open("memory://aggregation_max").expect("Failed to create database");
setup_sales_table(&db);
let max: f64 = db
.query_one("SELECT MAX(amount) FROM sales_aggr", ())
.unwrap();
assert!(
(max - 1500.0).abs() < 0.01,
"Expected max of 1500, got {}",
max
);
}
#[test]
fn test_multiple_aggregations() {
let db = Database::open("memory://aggregation_multiple").expect("Failed to create database");
setup_sales_table(&db);
let result = db
.query(
"SELECT COUNT(*), SUM(amount), AVG(amount), MIN(amount), MAX(amount) FROM sales_aggr",
(),
)
.expect("Failed to query");
for row in result {
let row = row.expect("Failed to get row");
let count: i64 = row.get(0).unwrap();
let sum: f64 = row.get(1).unwrap();
let avg: f64 = row.get(2).unwrap();
let min: f64 = row.get(3).unwrap();
let max: f64 = row.get(4).unwrap();
assert_eq!(count, 9);
assert!((sum - 5235.0).abs() < 0.01);
assert!((avg - 581.67).abs() < 0.01);
assert!((min - 35.0).abs() < 0.01);
assert!((max - 1500.0).abs() < 0.01);
}
}
#[test]
fn test_group_by_with_sum() {
let db = Database::open("memory://aggregation_group_sum").expect("Failed to create database");
setup_sales_table(&db);
let result = db
.query(
"SELECT category, SUM(amount) FROM sales_aggr GROUP BY category ORDER BY category",
(),
)
.expect("Failed to query");
let mut results = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let category: String = row.get(0).unwrap();
let sum: f64 = row.get(1).unwrap();
results.push((category, sum));
}
assert_eq!(results.len(), 3);
for (category, sum) in &results {
match category.as_str() {
"Clothing" => assert!((sum - 185.0).abs() < 0.01, "Clothing sum should be 185"),
"Electronics" => assert!(
(sum - 3500.0).abs() < 0.01,
"Electronics sum should be 3500"
),
"Furniture" => assert!((sum - 1550.0).abs() < 0.01, "Furniture sum should be 1550"),
_ => panic!("Unexpected category: {}", category),
}
}
}
#[test]
fn test_group_by_with_avg() {
let db = Database::open("memory://aggregation_group_avg").expect("Failed to create database");
setup_sales_table(&db);
let result = db
.query(
"SELECT category, AVG(amount) FROM sales_aggr GROUP BY category ORDER BY category",
(),
)
.expect("Failed to query");
let mut results = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let category: String = row.get(0).unwrap();
let avg: f64 = row.get(1).unwrap();
results.push((category, avg));
}
assert_eq!(results.len(), 3);
for (category, avg) in &results {
match category.as_str() {
"Clothing" => assert!((avg - 61.67).abs() < 0.01, "Clothing avg should be ~61.67"),
"Electronics" => assert!(
(avg - 1166.67).abs() < 0.01,
"Electronics avg should be ~1166.67"
),
"Furniture" => assert!(
(avg - 516.67).abs() < 0.01,
"Furniture avg should be ~516.67"
),
_ => panic!("Unexpected category: {}", category),
}
}
}
#[test]
fn test_count_with_where() {
let db = Database::open("memory://aggregation_count_where").expect("Failed to create database");
setup_sales_table(&db);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM sales_aggr WHERE amount > 500", ())
.unwrap();
assert_eq!(count, 4, "Expected 4 items with amount > 500");
}
#[test]
fn test_sum_with_where() {
let db = Database::open("memory://aggregation_sum_where").expect("Failed to create database");
setup_sales_table(&db);
let sum: f64 = db
.query_one(
"SELECT SUM(amount) FROM sales_aggr WHERE category = 'Electronics'",
(),
)
.unwrap();
assert!(
(sum - 3500.0).abs() < 0.01,
"Expected sum of 3500 for Electronics"
);
}