use stoolap::Database;
fn setup_simple_tables(db: &Database) {
db.execute(
"CREATE TABLE departments_simple (id INTEGER, name TEXT)",
(),
)
.expect("Failed to create departments_simple table");
db.execute(
"CREATE TABLE employees_simple (id INTEGER, name TEXT, dept_id INTEGER)",
(),
)
.expect("Failed to create employees_simple table");
db.execute(
"INSERT INTO departments_simple (id, name) VALUES (1, 'Engineering')",
(),
)
.expect("Failed to insert department 1");
db.execute(
"INSERT INTO departments_simple (id, name) VALUES (2, 'Sales')",
(),
)
.expect("Failed to insert department 2");
db.execute(
"INSERT INTO departments_simple (id, name) VALUES (3, 'Marketing')",
(),
)
.expect("Failed to insert department 3");
db.execute(
"INSERT INTO employees_simple (id, name, dept_id) VALUES (101, 'John', 1)",
(),
)
.expect("Failed to insert employee 1");
db.execute(
"INSERT INTO employees_simple (id, name, dept_id) VALUES (102, 'Jane', 1)",
(),
)
.expect("Failed to insert employee 2");
db.execute(
"INSERT INTO employees_simple (id, name, dept_id) VALUES (103, 'Bob', 2)",
(),
)
.expect("Failed to insert employee 3");
db.execute(
"INSERT INTO employees_simple (id, name, dept_id) VALUES (104, 'Alice', NULL)",
(),
)
.expect("Failed to insert employee 4");
}
#[test]
fn test_inner_join_basic() {
let db = Database::open("memory://join_inner_basic").expect("Failed to create database");
setup_simple_tables(&db);
let result = db.query(
"SELECT e.id, e.name, d.name FROM employees_simple e INNER JOIN departments_simple d ON e.dept_id = d.id", ()).expect("Failed to execute INNER JOIN");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let emp_id: i64 = row.get(0).unwrap();
let emp_name: String = row.get(1).unwrap();
let dept_name: String = row.get(2).unwrap();
rows.push((emp_id, emp_name, dept_name));
}
assert_eq!(rows.len(), 3, "Expected 3 rows from INNER JOIN");
let expected = vec![
(101, "John".to_string(), "Engineering".to_string()),
(102, "Jane".to_string(), "Engineering".to_string()),
(103, "Bob".to_string(), "Sales".to_string()),
];
for exp in &expected {
assert!(
rows.contains(exp),
"Expected row {:?} not found in results: {:?}",
exp,
rows
);
}
}
#[test]
fn test_left_join_basic() {
let db = Database::open("memory://join_left_basic").expect("Failed to create database");
setup_simple_tables(&db);
let result = db.query(
"SELECT e.id, e.name, d.name FROM employees_simple e LEFT JOIN departments_simple d ON e.dept_id = d.id", ()).expect("Failed to execute LEFT JOIN");
let mut row_count = 0;
for row in result {
let _row = row.expect("Failed to get row");
row_count += 1;
}
assert_eq!(row_count, 4, "Expected 4 rows from LEFT JOIN");
}
#[test]
fn test_join_with_where_clause() {
let db = Database::open("memory://join_with_where").expect("Failed to create database");
setup_simple_tables(&db);
let result = db.query(
"SELECT e.id, e.name, d.name FROM employees_simple e INNER JOIN departments_simple d ON e.dept_id = d.id WHERE d.name = 'Engineering'", ()).expect("Failed to execute INNER JOIN with WHERE");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let emp_id: i64 = row.get(0).unwrap();
let emp_name: String = row.get(1).unwrap();
let dept_name: String = row.get(2).unwrap();
rows.push((emp_id, emp_name, dept_name));
}
assert_eq!(rows.len(), 2, "Expected 2 Engineering employees");
for (_, _, dept) in &rows {
assert_eq!(
dept, "Engineering",
"All results should be from Engineering"
);
}
}
#[test]
fn test_join_with_multiple_conditions() {
let db = Database::open("memory://join_multi_cond").expect("Failed to create database");
setup_simple_tables(&db);
let result = db.query(
"SELECT e.id, e.name, d.name FROM employees_simple e INNER JOIN departments_simple d ON e.dept_id = d.id WHERE e.id > 101", ()).expect("Failed to execute join with condition");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let emp_id: i64 = row.get(0).unwrap();
let emp_name: String = row.get(1).unwrap();
let dept_name: String = row.get(2).unwrap();
rows.push((emp_id, emp_name, dept_name));
}
assert_eq!(rows.len(), 2, "Expected 2 rows with id > 101");
for (id, _, _) in &rows {
assert!(*id > 101, "All employee IDs should be > 101");
}
}
#[test]
fn test_join_self() {
let db = Database::open("memory://join_self").expect("Failed to create database");
db.execute(
"CREATE TABLE org (id INTEGER, name TEXT, manager_id INTEGER)",
(),
)
.expect("Failed to create org table");
db.execute(
"INSERT INTO org (id, name, manager_id) VALUES (1, 'CEO', NULL)",
(),
)
.expect("Failed to insert CEO");
db.execute(
"INSERT INTO org (id, name, manager_id) VALUES (2, 'VP1', 1)",
(),
)
.expect("Failed to insert VP1");
db.execute(
"INSERT INTO org (id, name, manager_id) VALUES (3, 'VP2', 1)",
(),
)
.expect("Failed to insert VP2");
db.execute(
"INSERT INTO org (id, name, manager_id) VALUES (4, 'Manager1', 2)",
(),
)
.expect("Failed to insert Manager1");
let result = db
.query(
"SELECT e.name, m.name FROM org e INNER JOIN org m ON e.manager_id = m.id",
(),
)
.expect("Failed to execute self join");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let emp_name: String = row.get(0).unwrap();
let mgr_name: String = row.get(1).unwrap();
rows.push((emp_name, mgr_name));
}
assert_eq!(rows.len(), 3, "Expected 3 employee-manager relationships");
let expected = vec![
("VP1".to_string(), "CEO".to_string()),
("VP2".to_string(), "CEO".to_string()),
("Manager1".to_string(), "VP1".to_string()),
];
for exp in &expected {
assert!(
rows.contains(exp),
"Expected relationship {:?} not found",
exp
);
}
}
#[test]
fn test_right_join() {
let db = Database::open("memory://join_right").expect("Failed to create database");
setup_simple_tables(&db);
let result = db.query(
"SELECT e.id, e.name, d.name FROM employees_simple e RIGHT JOIN departments_simple d ON e.dept_id = d.id", ()).expect("Failed to execute RIGHT JOIN");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let emp_id: Option<i64> = row.get(0).ok();
let emp_name: Option<String> = row.get(1).ok();
let dept_name: String = row.get(2).unwrap();
rows.push((emp_id, emp_name, dept_name));
}
assert!(
rows.len() >= 4,
"Expected at least 4 rows from RIGHT JOIN, got {}",
rows.len()
);
let marketing_row = rows.iter().find(|(_, _, dept)| dept == "Marketing");
assert!(
marketing_row.is_some(),
"Marketing department should appear in RIGHT JOIN results"
);
}
#[test]
fn test_cross_join() {
let db = Database::open("memory://join_cross").expect("Failed to create database");
db.execute("CREATE TABLE colors (name TEXT)", ())
.expect("Failed to create colors table");
db.execute("CREATE TABLE sizes (name TEXT)", ())
.expect("Failed to create sizes table");
db.execute("INSERT INTO colors (name) VALUES ('Red')", ())
.unwrap();
db.execute("INSERT INTO colors (name) VALUES ('Blue')", ())
.unwrap();
db.execute("INSERT INTO sizes (name) VALUES ('S')", ())
.unwrap();
db.execute("INSERT INTO sizes (name) VALUES ('M')", ())
.unwrap();
db.execute("INSERT INTO sizes (name) VALUES ('L')", ())
.unwrap();
let result = db
.query("SELECT c.name, s.name FROM colors c CROSS JOIN sizes s", ())
.expect("Failed to execute CROSS JOIN");
let mut rows = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let color: String = row.get(0).unwrap();
let size: String = row.get(1).unwrap();
rows.push((color, size));
}
assert_eq!(rows.len(), 6, "Expected 6 rows from CROSS JOIN (2 x 3)");
let expected_combinations = vec![
("Red", "S"),
("Red", "M"),
("Red", "L"),
("Blue", "S"),
("Blue", "M"),
("Blue", "L"),
];
for (color, size) in expected_combinations {
assert!(
rows.iter().any(|(c, s)| c == color && s == size),
"Expected combination ({}, {}) not found",
color,
size
);
}
}