#[cfg(test)]
mod tests {
use vibesql_parser::Parser;
use vibesql_storage::Database;
use crate::SelectExecutor;
#[test]
fn test_except_left_to_right_evaluation() {
let mut db = Database::new();
let create_t1 = "CREATE TABLE t1 (a INT)";
let create_t2 = "CREATE TABLE t2 (a INT)";
let create_t3 = "CREATE TABLE t3 (a INT)";
for sql in &[create_t1, create_t2, create_t3] {
let stmt = Parser::parse_sql(sql).unwrap();
if let vibesql_ast::Statement::CreateTable(create_stmt) = stmt {
crate::CreateTableExecutor::execute(&create_stmt, &mut db).unwrap();
}
}
let insert_t1 = "INSERT INTO t1 VALUES (1), (2), (3)";
let insert_t2 = "INSERT INTO t2 VALUES (2), (3), (4)";
let insert_t3 = "INSERT INTO t3 VALUES (3), (4), (5)";
for sql in &[insert_t1, insert_t2, insert_t3] {
let stmt = Parser::parse_sql(sql).unwrap();
if let vibesql_ast::Statement::Insert(insert_stmt) = stmt {
crate::InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
}
}
let query = "SELECT a FROM t1 EXCEPT SELECT a FROM t2 EXCEPT SELECT a FROM t3";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let executor = SelectExecutor::new(&db);
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 1, "Should have exactly 1 row");
assert_eq!(rows[0].values.len(), 1, "Should have exactly 1 column");
if let vibesql_types::SqlValue::Integer(val) = rows[0].values[0] {
assert_eq!(val, 1, "Result should be 1");
} else {
panic!("Expected Integer value");
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_union_except_left_to_right() {
let mut db = Database::new();
let create_t1 = "CREATE TABLE t1 (a INT)";
let create_t2 = "CREATE TABLE t2 (a INT)";
let create_t3 = "CREATE TABLE t3 (a INT)";
for sql in &[create_t1, create_t2, create_t3] {
let stmt = Parser::parse_sql(sql).unwrap();
if let vibesql_ast::Statement::CreateTable(create_stmt) = stmt {
crate::CreateTableExecutor::execute(&create_stmt, &mut db).unwrap();
}
}
let insert_t1 = "INSERT INTO t1 VALUES (1), (2), (3)";
let insert_t2 = "INSERT INTO t2 VALUES (2), (3), (4)";
let insert_t3 = "INSERT INTO t3 VALUES (3), (4), (5)";
for sql in &[insert_t1, insert_t2, insert_t3] {
let stmt = Parser::parse_sql(sql).unwrap();
if let vibesql_ast::Statement::Insert(insert_stmt) = stmt {
crate::InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
}
}
let query = "SELECT a FROM t1 UNION SELECT a FROM t2 EXCEPT SELECT a FROM t3";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let executor = SelectExecutor::new(&db);
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 2, "Should have exactly 2 rows");
let mut values: Vec<i64> = rows
.iter()
.map(|row| {
if let vibesql_types::SqlValue::Integer(val) = row.values[0] {
val
} else {
panic!("Expected Integer value");
}
})
.collect();
values.sort();
assert_eq!(values, vec![1, 2], "Result should be [1, 2]");
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_multiple_except_operations() {
let mut db = Database::new();
let sqls = vec![
"CREATE TABLE t1 (a INT)",
"CREATE TABLE t2 (a INT)",
"CREATE TABLE t3 (a INT)",
"CREATE TABLE t4 (a INT)",
"INSERT INTO t1 VALUES (1), (2), (3)",
"INSERT INTO t2 VALUES (2), (3), (4)",
"INSERT INTO t3 VALUES (3), (4), (5)",
"INSERT INTO t4 VALUES (1), (5)",
];
for sql in sqls {
let stmt = Parser::parse_sql(sql).unwrap();
match stmt {
vibesql_ast::Statement::CreateTable(create_stmt) => {
crate::CreateTableExecutor::execute(&create_stmt, &mut db).unwrap();
}
vibesql_ast::Statement::Insert(insert_stmt) => {
crate::InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
}
_ => {}
}
}
let query = "SELECT a FROM t1 UNION SELECT a FROM t2 EXCEPT SELECT a FROM t3 EXCEPT SELECT a FROM t4";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let executor = SelectExecutor::new(&db);
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 1, "Should have exactly 1 row");
if let vibesql_types::SqlValue::Integer(val) = rows[0].values[0] {
assert_eq!(val, 2, "Result should be 2");
} else {
panic!("Expected Integer value");
}
} else {
panic!("Expected SELECT statement");
}
}
}