use stoolap::parser::{parse_sql, Statement};
fn parse_ok(sql: &str) -> Statement {
match parse_sql(sql) {
Ok(stmts) => {
assert!(!stmts.is_empty(), "No statements parsed from: {}", sql);
stmts.into_iter().next().unwrap()
}
Err(e) => panic!("Failed to parse '{}': {:?}", sql, e),
}
}
fn parse_succeeds(sql: &str) -> bool {
match parse_sql(sql) {
Ok(stmts) => !stmts.is_empty(),
Err(_) => false,
}
}
#[test]
fn test_create_table_with_all_types() {
let sql = r#"
CREATE TABLE employees (
id INTEGER,
name TEXT,
salary FLOAT,
is_active BOOLEAN,
hire_date DATE,
start_time TIME,
created_at TIMESTAMP,
metadata JSON
)
"#;
let stmt = parse_ok(sql);
match stmt {
Statement::CreateTable(create) => {
assert_eq!(create.table_name.value, "employees");
assert_eq!(create.columns.len(), 8);
let expected = [
("id", "INTEGER"),
("name", "TEXT"),
("salary", "FLOAT"),
("is_active", "BOOLEAN"),
("hire_date", "DATE"),
("start_time", "TIME"),
("created_at", "TIMESTAMP"),
("metadata", "JSON"),
];
for (i, (name, typ)) in expected.iter().enumerate() {
assert_eq!(
create.columns[i].name.value, *name,
"Column {} name mismatch",
i
);
assert_eq!(
create.columns[i].data_type, *typ,
"Column {} type mismatch",
i
);
}
}
_ => panic!("Expected CreateTableStatement"),
}
}
#[test]
fn test_insert_with_integer_value() {
let stmt = parse_ok("INSERT INTO employees (id) VALUES (42)");
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_float_value() {
let stmt = parse_ok("INSERT INTO employees (salary) VALUES (55.5)");
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_text_value() {
let stmt = parse_ok("INSERT INTO employees (name) VALUES ('John Doe')");
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_boolean_true() {
let stmt = parse_ok("INSERT INTO employees (is_active) VALUES (TRUE)");
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_boolean_false() {
let stmt = parse_ok("INSERT INTO employees (is_active) VALUES (FALSE)");
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_json_value() {
let stmt = parse_ok(
r#"INSERT INTO employees (metadata) VALUES ('{"department":"Engineering","skills":["Go","SQL"]}')"#,
);
match stmt {
Statement::Insert(_) => {}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_insert_with_multiple_types() {
let stmt = parse_ok(
"INSERT INTO employees (id, name, salary, is_active, hire_date, start_time, metadata) VALUES (1, 'John Smith', 75000.50, TRUE, '2022-01-15', '09:00:00', '{\"role\":\"developer\"}')",
);
match stmt {
Statement::Insert(insert) => {
assert_eq!(insert.values.len(), 1);
assert_eq!(insert.values[0].len(), 7);
}
_ => panic!("Expected InsertStatement"),
}
}
#[test]
fn test_select_all_columns() {
let stmt = parse_ok("SELECT * FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_column_list() {
let stmt = parse_ok("SELECT id, name, salary FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_integer_condition() {
let stmt = parse_ok("SELECT * FROM employees WHERE id = 42");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_text_condition() {
let stmt = parse_ok("SELECT * FROM employees WHERE name = 'John Doe'");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_boolean_condition() {
let stmt = parse_ok("SELECT * FROM employees WHERE is_active = TRUE");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_date_condition() {
let stmt = parse_ok("SELECT * FROM employees WHERE hire_date = '2023-05-15'");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_complex_date_condition() {
let stmt = parse_ok(
"SELECT * FROM employees WHERE hire_date >= '2022-01-01' AND hire_date <= '2022-12-31'",
);
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_time_condition() {
let stmt = parse_ok("SELECT * FROM employees WHERE start_time = '09:00:00'");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_multiple_conditions() {
let stmt = parse_ok("SELECT * FROM employees WHERE is_active = TRUE AND salary > 50000.0");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_order_by() {
let stmt = parse_ok("SELECT * FROM employees ORDER BY hire_date DESC, salary ASC");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_limit_offset() {
let stmt = parse_ok("SELECT * FROM employees ORDER BY id LIMIT 10 OFFSET 20");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_join() {
let stmt = parse_ok(
"SELECT e.name, d.name FROM employees e JOIN departments d ON e.department_id = d.id",
);
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_left_join() {
let stmt = parse_ok(
"SELECT e.name, d.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id",
);
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_select_with_complex_time_date() {
let stmt = parse_ok("SELECT * FROM employees WHERE start_time >= '09:00:00' AND start_time <= '17:00:00' AND hire_date >= '2022-01-01'");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_count_star() {
let stmt = parse_ok("SELECT COUNT(*) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_count_column() {
let stmt = parse_ok("SELECT COUNT(id) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_sum_function() {
let stmt = parse_ok("SELECT SUM(salary) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_avg_function() {
let stmt = parse_ok("SELECT AVG(salary) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_min_function() {
let stmt = parse_ok("SELECT MIN(salary) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_max_function() {
let stmt = parse_ok("SELECT MAX(salary) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_multiple_aggregations() {
let stmt = parse_ok("SELECT COUNT(*), AVG(salary), MIN(salary), MAX(salary) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_group_by() {
let stmt = parse_ok("SELECT department_id, COUNT(*) FROM employees GROUP BY department_id");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_having_clause() {
let stmt = parse_ok(
"SELECT department_id, COUNT(*) FROM employees GROUP BY department_id HAVING COUNT(*) > 5",
);
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_complex_aggregation() {
let stmt = parse_ok("SELECT department_id, AVG(salary) FROM employees WHERE is_active = TRUE GROUP BY department_id HAVING COUNT(*) > 3 ORDER BY AVG(salary) DESC");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_upper_function() {
let stmt = parse_ok("SELECT UPPER(name) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_lower_function() {
let stmt = parse_ok("SELECT LOWER(name) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_abs_function() {
let stmt = parse_ok("SELECT ABS(salary - 50000) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_round_function() {
let stmt = parse_ok("SELECT ROUND(salary, 2) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_length_function() {
let stmt = parse_ok("SELECT LENGTH(name) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_substring_function() {
let stmt = parse_ok("SELECT SUBSTRING(name, 1, 3) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_concat_function() {
let stmt = parse_ok("SELECT CONCAT(name, ' - ', department) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_scalar_in_where() {
let stmt = parse_ok("SELECT * FROM employees WHERE UPPER(name) = 'JOHN DOE'");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_cast_int_to_float() {
let stmt = parse_ok("SELECT CAST(id AS FLOAT) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_cast_string_to_int() {
let stmt = parse_ok("SELECT CAST('42' AS INTEGER) FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_cast_in_where() {
let stmt = parse_ok("SELECT * FROM employees WHERE CAST(salary AS INTEGER) > 50000");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_cast_with_arithmetic() {
let stmt = parse_ok("SELECT CAST(id AS FLOAT) + 0.5 FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_simple_case() {
let stmt =
parse_ok("SELECT CASE WHEN salary > 50000 THEN 'High' ELSE 'Low' END FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_multiple_when_clauses() {
let stmt = parse_ok("SELECT CASE WHEN salary > 100000 THEN 'Very High' WHEN salary > 50000 THEN 'High' ELSE 'Low' END FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_case_with_complex_conditions() {
let stmt = parse_ok("SELECT CASE WHEN salary > 50000 AND is_active = TRUE THEN 'Active High' WHEN salary <= 50000 AND is_active = TRUE THEN 'Active Low' ELSE 'Inactive' END FROM employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_subquery_in_where() {
let result = parse_succeeds(
"SELECT * FROM employees WHERE salary > (SELECT AVG(salary) FROM employees)",
);
println!(
"Subquery in WHERE: {}",
if result { "PASS" } else { "NOT IMPLEMENTED" }
);
}
#[test]
fn test_subquery_with_in() {
let result = parse_succeeds("SELECT * FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = 'New York')");
println!(
"Subquery with IN: {}",
if result { "PASS" } else { "NOT IMPLEMENTED" }
);
}
#[test]
fn test_simple_cte() {
let stmt = parse_ok("WITH high_salary AS (SELECT * FROM employees WHERE salary > 50000) SELECT * FROM high_salary");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_cte_with_join() {
let stmt = parse_ok("WITH dept_employees AS (SELECT d.name AS dept_name, e.name AS emp_name FROM departments d JOIN employees e ON d.id = e.department_id) SELECT * FROM dept_employees");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_simple_parameter() {
let stmt = parse_ok("SELECT * FROM employees WHERE id = ?");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_multiple_parameters() {
let stmt = parse_ok("SELECT * FROM employees WHERE salary > ? AND hire_date < ?");
assert!(matches!(stmt, Statement::Select(_)));
}
#[test]
fn test_parameters_in_insert() {
let stmt = parse_ok("INSERT INTO employees (name, salary) VALUES (?, ?)");
assert!(matches!(stmt, Statement::Insert(_)));
}
#[test]
fn test_parameters_in_update() {
let stmt = parse_ok("UPDATE employees SET name = ?, salary = ? WHERE id = ?");
assert!(matches!(stmt, Statement::Update(_)));
}
#[test]
fn test_alter_add_column() {
let stmt = parse_ok("ALTER TABLE employees ADD COLUMN department_id INTEGER");
assert!(matches!(stmt, Statement::AlterTable(_)));
}
#[test]
fn test_alter_drop_column() {
let stmt = parse_ok("ALTER TABLE employees DROP COLUMN metadata");
assert!(matches!(stmt, Statement::AlterTable(_)));
}
#[test]
fn test_alter_rename_column() {
let stmt = parse_ok("ALTER TABLE employees RENAME COLUMN name TO full_name");
assert!(matches!(stmt, Statement::AlterTable(_)));
}
#[test]
fn test_alter_rename_table() {
let stmt = parse_ok("ALTER TABLE employees RENAME TO staff");
assert!(matches!(stmt, Statement::AlterTable(_)));
}
#[test]
fn test_create_index() {
let stmt = parse_ok("CREATE INDEX idx_salary ON employees(salary)");
assert!(matches!(stmt, Statement::CreateIndex(_)));
}
#[test]
fn test_create_unique_index() {
let stmt = parse_ok("CREATE UNIQUE INDEX idx_email ON employees(email)");
assert!(matches!(stmt, Statement::CreateIndex(_)));
}
#[test]
fn test_create_multi_column_index() {
let stmt = parse_ok("CREATE INDEX idx_dept_hire ON employees(department_id, hire_date)");
assert!(matches!(stmt, Statement::CreateIndex(_)));
}
#[test]
fn test_drop_index() {
let stmt = parse_ok("DROP INDEX idx_salary ON employees");
assert!(matches!(stmt, Statement::DropIndex(_)));
}
#[test]
fn test_drop_index_if_exists() {
let stmt = parse_ok("DROP INDEX IF EXISTS idx_nonexistent ON employees");
assert!(matches!(stmt, Statement::DropIndex(_)));
}