use std::sync::atomic::{AtomicUsize, Ordering};
use stoolap::Database;
static TEST_ID: AtomicUsize = AtomicUsize::new(0);
fn setup_db() -> Database {
let id = TEST_ID.fetch_add(1, Ordering::Relaxed);
let db = Database::open(&format!("memory://agg_subquery_{}", id))
.expect("Failed to create database");
db.execute("CREATE TABLE p (id INTEGER PRIMARY KEY, r TEXT)", ())
.expect("Failed to create table p");
db.execute(
"CREATE TABLE plain5 (account_id INTEGER PRIMARY KEY, v INTEGER)",
(),
)
.expect("Failed to create table plain5");
db.execute("INSERT INTO p VALUES (1, 'x'), (2, 'y'), (3, 'x')", ())
.expect("Failed to insert into p");
db.execute(
"INSERT INTO plain5 VALUES (1, 10), (2, 20), (3, 30), (4, 40)",
(),
)
.expect("Failed to insert into plain5");
db
}
#[test]
fn test_count_with_in_subquery_on_pk() {
let db = setup_db();
let count: i64 = db
.query_one(
"SELECT COUNT(*) FROM plain5 WHERE account_id IN (SELECT id FROM p WHERE r = 'x')",
(),
)
.expect("COUNT with IN subquery on PK should work");
assert_eq!(count, 2);
}
#[test]
fn test_sum_with_in_subquery_on_pk() {
let db = setup_db();
let sum: i64 = db
.query_one(
"SELECT SUM(v) FROM plain5 WHERE account_id IN (SELECT id FROM p WHERE r = 'x')",
(),
)
.expect("SUM with IN subquery on PK should work");
assert_eq!(sum, 40);
}
#[test]
fn test_avg_with_in_subquery_on_pk() {
let db = setup_db();
let avg: f64 = db
.query_one(
"SELECT AVG(v) FROM plain5 WHERE account_id IN (SELECT id FROM p WHERE r = 'x')",
(),
)
.expect("AVG with IN subquery on PK should work");
assert!((avg - 20.0).abs() < 0.001);
}
#[test]
fn test_min_max_with_in_subquery_on_pk() {
let db = setup_db();
let min: i64 = db
.query_one(
"SELECT MIN(v) FROM plain5 WHERE account_id IN (SELECT id FROM p WHERE r = 'x')",
(),
)
.expect("MIN with IN subquery on PK should work");
assert_eq!(min, 10);
let max: i64 = db
.query_one(
"SELECT MAX(v) FROM plain5 WHERE account_id IN (SELECT id FROM p WHERE r = 'x')",
(),
)
.expect("MAX with IN subquery on PK should work");
assert_eq!(max, 30);
}
#[test]
fn test_count_with_in_subquery_on_indexed_column() {
let db = Database::open("memory://agg_in_idx").expect("Failed to create database");
db.execute(
"CREATE TABLE lookup (id INTEGER PRIMARY KEY, category TEXT)",
(),
)
.expect("create");
db.execute(
"CREATE TABLE data (id INTEGER PRIMARY KEY, lookup_id INTEGER, amount FLOAT)",
(),
)
.expect("create");
db.execute("CREATE INDEX idx_lookup ON data(lookup_id)", ())
.expect("create index");
db.execute("INSERT INTO lookup VALUES (1, 'A'), (2, 'B'), (3, 'A')", ())
.expect("insert");
db.execute(
"INSERT INTO data VALUES (1, 1, 100.0), (2, 2, 200.0), (3, 3, 300.0), (4, 1, 150.0)",
(),
)
.expect("insert");
let count: i64 = db
.query_one(
"SELECT COUNT(*) FROM data WHERE lookup_id IN (SELECT id FROM lookup WHERE category = 'A')",
(),
)
.expect("COUNT with IN subquery on indexed column should work");
assert_eq!(count, 3);
}
#[test]
fn test_aggregate_with_in_literal_list_on_pk() {
let db = setup_db();
let count: i64 = db
.query_one("SELECT COUNT(*) FROM plain5 WHERE account_id IN (1, 3)", ())
.expect("COUNT with IN literal list on PK should work");
assert_eq!(count, 2);
let sum: i64 = db
.query_one("SELECT SUM(v) FROM plain5 WHERE account_id IN (1, 3)", ())
.expect("SUM with IN literal list on PK should work");
assert_eq!(sum, 40);
}
#[test]
fn test_group_by_with_in_subquery_on_pk() {
let db = Database::open("memory://grp_in_pk").expect("Failed to create database");
db.execute(
"CREATE TABLE categories (id INTEGER PRIMARY KEY, active BOOLEAN)",
(),
)
.expect("create");
db.execute(
"CREATE TABLE items (id INTEGER PRIMARY KEY, cat_id INTEGER, price INTEGER)",
(),
)
.expect("create");
db.execute("CREATE INDEX idx_cat ON items(cat_id)", ())
.expect("create index");
db.execute(
"INSERT INTO categories VALUES (1, true), (2, false), (3, true)",
(),
)
.expect("insert");
db.execute(
"INSERT INTO items VALUES (1, 1, 10), (2, 1, 20), (3, 2, 30), (4, 3, 40), (5, 3, 50)",
(),
)
.expect("insert");
let result = db
.query(
"SELECT cat_id, SUM(price) FROM items WHERE cat_id IN (SELECT id FROM categories WHERE active = true) GROUP BY cat_id ORDER BY cat_id",
(),
)
.expect("GROUP BY with IN subquery on indexed column should work");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let cat_id: i64 = row.get(0).unwrap();
let sum: i64 = row.get(1).unwrap();
rows.push((cat_id, sum));
}
assert_eq!(rows, vec![(1, 30), (3, 90)]);
}