use stoolap::Database;
fn create_test_db(name: &str) -> Database {
Database::open(&format!("memory://{}", name)).expect("Failed to create in-memory database")
}
#[test]
fn test_union_basic() {
let db = create_test_db("union_basic");
let result = db
.query("SELECT 1 AS x UNION SELECT 2 UNION SELECT 3", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_union_removes_duplicates() {
let db = create_test_db("union_dedup");
let result = db
.query(
"SELECT 1 AS x UNION SELECT 1 UNION SELECT 2 UNION SELECT 2 UNION SELECT 3",
(),
)
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_union_all_keeps_duplicates() {
let db = create_test_db("union_all");
let result = db
.query("SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 2", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![1, 1, 2]);
}
#[test]
fn test_union_with_tables() {
let db = create_test_db("union_tables");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 'Alice'), (2, 'Bob')", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (2, 'Bob'), (3, 'Charlie')", ())
.unwrap();
let result = db
.query("SELECT name FROM t1 UNION SELECT name FROM t2", ())
.unwrap();
let mut names: Vec<String> = Vec::new();
for row in result {
let row = row.unwrap();
names.push(row.get(0).unwrap());
}
names.sort();
assert_eq!(names, vec!["Alice", "Bob", "Charlie"]);
}
#[test]
fn test_union_all_with_tables() {
let db = create_test_db("union_all_tables");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 'Alice'), (2, 'Bob')", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (2, 'Bob'), (3, 'Charlie')", ())
.unwrap();
let result = db
.query("SELECT name FROM t1 UNION ALL SELECT name FROM t2", ())
.unwrap();
let mut names: Vec<String> = Vec::new();
for row in result {
let row = row.unwrap();
names.push(row.get(0).unwrap());
}
names.sort();
assert_eq!(names, vec!["Alice", "Bob", "Bob", "Charlie"]);
}
#[test]
fn test_union_with_order_by() {
let db = create_test_db("union_order");
let result = db
.query("SELECT 3 AS x UNION SELECT 1 UNION SELECT 2 ORDER BY x", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_union_with_limit() {
let db = create_test_db("union_limit");
let result = db
.query(
"SELECT 1 AS x UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 LIMIT 2",
(),
)
.unwrap();
let mut count = 0;
for _ in result {
count += 1;
}
assert_eq!(count, 2);
}
#[test]
fn test_intersect_basic() {
let db = create_test_db("intersect_basic");
db.execute("CREATE TABLE t1 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE t2 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1), (2), (3)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (2), (3), (4)", ())
.unwrap();
let result = db
.query("SELECT x FROM t1 INTERSECT SELECT x FROM t2", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![2, 3]);
}
#[test]
fn test_intersect_no_common_elements() {
let db = create_test_db("intersect_none");
db.execute("CREATE TABLE t1 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE t2 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1), (2)", ()).unwrap();
db.execute("INSERT INTO t2 VALUES (3), (4)", ()).unwrap();
let result = db
.query("SELECT x FROM t1 INTERSECT SELECT x FROM t2", ())
.unwrap();
let mut count = 0;
for _ in result {
count += 1;
}
assert_eq!(count, 0);
}
#[test]
fn test_except_basic() {
let db = create_test_db("except_basic");
db.execute("CREATE TABLE t1 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE t2 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1), (2), (3)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (2), (3), (4)", ())
.unwrap();
let result = db
.query("SELECT x FROM t1 EXCEPT SELECT x FROM t2", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
assert_eq!(values, vec![1]);
}
#[test]
fn test_except_removes_all_matching() {
let db = create_test_db("except_all_match");
db.execute("CREATE TABLE t1 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE t2 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1), (2), (3)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (1), (2), (3)", ())
.unwrap();
let result = db
.query("SELECT x FROM t1 EXCEPT SELECT x FROM t2", ())
.unwrap();
let mut count = 0;
for _ in result {
count += 1;
}
assert_eq!(count, 0);
}
#[test]
fn test_except_order_matters() {
let db = create_test_db("except_order");
db.execute("CREATE TABLE t1 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE t2 (x INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1), (2)", ()).unwrap();
db.execute("INSERT INTO t2 VALUES (2), (3)", ()).unwrap();
let result1 = db
.query("SELECT x FROM t1 EXCEPT SELECT x FROM t2", ())
.unwrap();
let mut values1: Vec<i64> = Vec::new();
for row in result1 {
let row = row.unwrap();
values1.push(row.get(0).unwrap());
}
assert_eq!(values1, vec![1]);
let result2 = db
.query("SELECT x FROM t2 EXCEPT SELECT x FROM t1", ())
.unwrap();
let mut values2: Vec<i64> = Vec::new();
for row in result2 {
let row = row.unwrap();
values2.push(row.get(0).unwrap());
}
assert_eq!(values2, vec![3]);
}
#[test]
fn test_multiple_unions() {
let db = create_test_db("multi_union");
let result = db
.query(
"SELECT 1 AS x UNION SELECT 2 UNION SELECT 3 UNION SELECT 4",
(),
)
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![1, 2, 3, 4]);
}
#[test]
fn test_union_with_where_clause() {
let db = create_test_db("union_where");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 10), (2, 20), (3, 30)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (4, 40), (5, 50), (6, 60)", ())
.unwrap();
let result = db
.query(
"SELECT val FROM t1 WHERE val > 15 UNION SELECT val FROM t2 WHERE val < 55",
(),
)
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
values.sort();
assert_eq!(values, vec![20, 30, 40, 50]);
}
#[test]
fn test_union_multiple_columns() {
let db = create_test_db("union_multi_col");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 'Alice')", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (2, 'Bob')", ()).unwrap();
let result = db
.query("SELECT id, name FROM t1 UNION SELECT id, name FROM t2", ())
.unwrap();
let mut rows: Vec<(i64, String)> = Vec::new();
for row in result {
let row = row.unwrap();
let id: i64 = row.get(0).unwrap();
let name: String = row.get(1).unwrap();
rows.push((id, name));
}
rows.sort_by_key(|(id, _)| *id);
assert_eq!(rows.len(), 2);
assert_eq!(rows[0], (1, "Alice".to_string()));
assert_eq!(rows[1], (2, "Bob".to_string()));
}