#![allow(dead_code, unused_variables)]
use manifoldb::{Database, Value};
fn get_by_name<'a>(
result: &'a manifoldb::QueryResult,
row_idx: usize,
col_name: &str,
) -> Option<&'a Value> {
result
.column_index(col_name)
.and_then(|_col_idx| result.rows().get(row_idx))
.and_then(|row| result.column_index(col_name).and_then(|idx| row.get(idx)))
}
#[test]
fn test_select_all_from_empty_table() {
let db = Database::in_memory().expect("failed to create db");
let result = db.query("SELECT * FROM users").expect("query failed");
assert!(result.is_empty());
}
#[test]
fn test_insert_and_select() {
let db = Database::in_memory().expect("failed to create db");
let affected =
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let name_idx = result.column_index("name").expect("name column not found");
let age_idx = result.column_index("age").expect("age column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Alice".to_string())));
assert_eq!(result.rows()[0].get(age_idx), Some(&Value::Int(30)));
}
#[test]
fn test_insert_multiple_rows() {
let db = Database::in_memory().expect("failed to create db");
let affected = db.execute(
"INSERT INTO products (name, price) VALUES ('Widget', 10), ('Gadget', 25), ('Gizmo', 15)"
).expect("insert failed");
assert_eq!(affected, 3);
let result = db.query("SELECT * FROM products").expect("query failed");
assert_eq!(result.len(), 3);
}
#[test]
fn test_select_with_where_clause() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT * FROM users WHERE age > 28").expect("query failed");
assert_eq!(result.len(), 2);
}
#[test]
fn test_select_with_projection() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age, email) VALUES ('Alice', 30, 'alice@example.com')")
.expect("insert failed");
let result = db.query("SELECT name, age FROM users").expect("query failed");
assert_eq!(result.len(), 1);
assert_eq!(result.columns().len(), 2);
assert!(result.columns().contains(&"name".to_string()));
assert!(result.columns().contains(&"age".to_string()));
}
#[test]
fn test_update_single_row() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
let affected =
db.execute("UPDATE users SET age = 31 WHERE name = 'Alice'").expect("update failed");
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users WHERE name = 'Alice'").expect("query failed");
assert_eq!(result.len(), 1);
let age_idx = result.column_index("age").expect("age column not found");
assert_eq!(result.rows()[0].get(age_idx), Some(&Value::Int(31)));
}
#[test]
fn test_update_multiple_rows() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age, active) VALUES ('Alice', 30, false)")
.expect("insert failed");
db.execute("INSERT INTO users (name, age, active) VALUES ('Bob', 25, false)")
.expect("insert failed");
db.execute("INSERT INTO users (name, age, active) VALUES ('Charlie', 35, false)")
.expect("insert failed");
let affected =
db.execute("UPDATE users SET active = true WHERE age >= 30").expect("update failed");
assert_eq!(affected, 2);
let result = db.query("SELECT * FROM users WHERE active = true").expect("query failed");
assert_eq!(result.len(), 2);
}
#[test]
fn test_update_no_matching_rows() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
let affected =
db.execute("UPDATE users SET age = 100 WHERE name = 'Nobody'").expect("update failed");
assert_eq!(affected, 0);
}
#[test]
fn test_delete_single_row() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
let affected = db.execute("DELETE FROM users WHERE name = 'Alice'").expect("delete failed");
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let name_idx = result.column_index("name").expect("name column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Bob".to_string())));
}
#[test]
fn test_delete_all_rows() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
let affected = db.execute("DELETE FROM users").expect("delete failed");
assert_eq!(affected, 2);
let result = db.query("SELECT * FROM users").expect("query failed");
assert!(result.is_empty());
}
#[test]
fn test_parameterized_insert() {
let db = Database::in_memory().expect("failed to create db");
let affected = db
.execute_with_params(
"INSERT INTO users (name, age) VALUES ($1, $2)",
&[Value::String("Alice".to_string()), Value::Int(30)],
)
.expect("insert failed");
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let name_idx = result.column_index("name").expect("name column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Alice".to_string())));
}
#[test]
fn test_parameterized_select() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
let result = db
.query_with_params("SELECT * FROM users WHERE age > $1", &[Value::Int(28)])
.expect("query failed");
assert_eq!(result.len(), 1);
let name_idx = result.column_index("name").expect("name column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Alice".to_string())));
}
#[test]
fn test_parameterized_update() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
let affected = db
.execute_with_params(
"UPDATE users SET age = $1 WHERE name = $2",
&[Value::Int(31), Value::String("Alice".to_string())],
)
.expect("update failed");
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users WHERE name = 'Alice'").expect("query failed");
let age_idx = result.column_index("age").expect("age column not found");
assert_eq!(result.rows()[0].get(age_idx), Some(&Value::Int(31)));
}
#[test]
fn test_select_with_order_by() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT * FROM users ORDER BY age").expect("query failed");
assert_eq!(result.len(), 3);
let name_idx = result.column_index("name").expect("name column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Bob".to_string())));
assert_eq!(result.rows()[1].get(name_idx), Some(&Value::String("Alice".to_string())));
assert_eq!(result.rows()[2].get(name_idx), Some(&Value::String("Charlie".to_string())));
}
#[test]
fn test_select_with_order_by_multiple_columns() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (id, age, name) VALUES (1, 25, 'Bob')").expect("insert failed");
db.execute("INSERT INTO users (id, age, name) VALUES (2, 25, 'Alice')").expect("insert failed");
db.execute("INSERT INTO users (id, age, name) VALUES (3, 30, 'Carol')").expect("insert failed");
let result = db.query("SELECT * FROM users ORDER BY age, name").expect("query failed");
assert_eq!(result.len(), 3);
let name_idx = result.column_index("name").expect("name column not found");
let age_idx = result.column_index("age").expect("age column not found");
assert_eq!(result.rows()[0].get(age_idx), Some(&Value::Int(25)));
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Alice".to_string())));
assert_eq!(result.rows()[1].get(age_idx), Some(&Value::Int(25)));
assert_eq!(result.rows()[1].get(name_idx), Some(&Value::String("Bob".to_string())));
assert_eq!(result.rows()[2].get(age_idx), Some(&Value::Int(30)));
assert_eq!(result.rows()[2].get(name_idx), Some(&Value::String("Carol".to_string())));
}
#[test]
fn test_select_with_limit() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT * FROM users LIMIT 2").expect("query failed");
assert_eq!(result.len(), 2);
}
#[test]
fn test_select_with_limit_and_offset() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT * FROM users LIMIT 1 OFFSET 1").expect("query failed");
assert_eq!(result.len(), 1);
}
#[test]
fn test_transaction_api_and_sql() {
let db = Database::in_memory().expect("failed to create db");
{
let mut tx = db.begin().expect("failed to begin");
let entity = tx
.create_entity()
.expect("failed to create entity")
.with_label("users")
.with_property("name", "Alice")
.with_property("age", 30i64);
tx.put_entity(&entity).expect("failed to put entity");
tx.commit().expect("failed to commit");
}
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let name_idx = result.column_index("name").expect("name column not found");
assert_eq!(result.rows()[0].get(name_idx), Some(&Value::String("Alice".to_string())));
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 2);
{
let tx = db.begin_read().expect("failed to begin read");
let entities = tx.iter_entities(Some("users")).expect("failed to iterate");
assert_eq!(entities.len(), 2);
}
}
#[test]
fn test_null_values() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', NULL)").expect("insert failed");
let result = db.query("SELECT * FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let age_idx = result.column_index("age").expect("age column not found");
assert_eq!(result.rows()[0].get(age_idx), Some(&Value::Null));
}
#[test]
fn test_string_values_with_special_chars() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO notes (content) VALUES ('Hello, World!')").expect("insert failed");
let result = db.query("SELECT * FROM notes").expect("query failed");
assert_eq!(result.len(), 1);
let content_idx = result.column_index("content").expect("content column not found");
assert_eq!(
result.rows()[0].get(content_idx),
Some(&Value::String("Hello, World!".to_string()))
);
}
#[test]
fn test_numeric_types() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO data (int_val, float_val) VALUES (42, 3.14)").expect("insert failed");
let result = db.query("SELECT * FROM data").expect("query failed");
assert_eq!(result.len(), 1);
let int_idx = result.column_index("int_val").expect("int_val column not found");
assert_eq!(result.rows()[0].get(int_idx), Some(&Value::Int(42)));
let float_idx = result.column_index("float_val").expect("float_val column not found");
if let Some(Value::Float(f)) = result.rows()[0].get(float_idx) {
let expected = 3.14;
assert!((f - expected).abs() < 0.001);
} else {
panic!("Expected float value");
}
}
#[test]
fn test_boolean_values() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO flags (active) VALUES (true)").expect("insert failed");
db.execute("INSERT INTO flags (active) VALUES (false)").expect("insert failed");
let result = db.query("SELECT * FROM flags WHERE active = true").expect("query failed");
assert_eq!(result.len(), 1);
}
#[test]
fn test_inner_join() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')").expect("insert failed");
db.execute("INSERT INTO users (id, name) VALUES (2, 'Bob')").expect("insert failed");
db.execute("INSERT INTO users (id, name) VALUES (3, 'Carol')").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (1, 100)").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (1, 150)").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (2, 200)").expect("insert failed");
let result = db
.query("SELECT * FROM users u INNER JOIN orders o ON u.id = o.user_id")
.expect("join query failed");
assert_eq!(result.len(), 3, "Expected 3 rows from inner join, got {}", result.len());
}
#[test]
fn test_left_join() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')").expect("insert failed");
db.execute("INSERT INTO users (id, name) VALUES (2, 'Bob')").expect("insert failed");
db.execute("INSERT INTO users (id, name) VALUES (3, 'Carol')").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (1, 100)").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (2, 200)").expect("insert failed");
let result = db
.query("SELECT * FROM users u LEFT JOIN orders o ON u.id = o.user_id")
.expect("join query failed");
assert_eq!(result.len(), 3, "Expected 3 rows from left join, got {}", result.len());
}
#[test]
fn test_cross_join() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO colors (name) VALUES ('red')").expect("insert failed");
db.execute("INSERT INTO colors (name) VALUES ('blue')").expect("insert failed");
db.execute("INSERT INTO sizes (name) VALUES ('small')").expect("insert failed");
db.execute("INSERT INTO sizes (name) VALUES ('large')").expect("insert failed");
let result =
db.query("SELECT * FROM colors CROSS JOIN sizes").expect("cross join query failed");
assert_eq!(result.len(), 4, "Expected 4 rows from cross join, got {}", result.len());
}
#[test]
fn test_join_with_filter() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')").expect("insert failed");
db.execute("INSERT INTO users (id, name) VALUES (2, 'Bob')").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (1, 100)").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (1, 150)").expect("insert failed");
db.execute("INSERT INTO orders (user_id, amount) VALUES (2, 200)").expect("insert failed");
let result = db
.query("SELECT * FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE o.amount > 120")
.expect("join query failed");
assert_eq!(result.len(), 2, "Expected 2 rows from filtered join, got {}", result.len());
}
#[test]
fn test_invalid_sql_syntax() {
let db = Database::in_memory().expect("failed to create db");
let result = db.query("SELEKT * FORM users");
assert!(result.is_err());
}
#[test]
fn test_count_aggregate() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT COUNT(*) FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let count_val = result.rows()[0].get(0);
assert_eq!(count_val, Some(&Value::Int(3)));
}
#[test]
fn test_sum_aggregate() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO products (name, price) VALUES ('Widget', 10)").expect("insert failed");
db.execute("INSERT INTO products (name, price) VALUES ('Gadget', 25)").expect("insert failed");
db.execute("INSERT INTO products (name, price) VALUES ('Gizmo', 15)").expect("insert failed");
let result = db.query("SELECT SUM(price) FROM products").expect("query failed");
assert_eq!(result.len(), 1);
if let Some(Value::Float(sum)) = result.rows()[0].get(0) {
assert!((sum - 50.0).abs() < 0.001);
} else {
panic!("Expected float sum value, got {:?}", result.rows()[0].get(0));
}
}
#[test]
fn test_group_by_count() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO employees (name, dept) VALUES ('Alice', 'Engineering')")
.expect("insert failed");
db.execute("INSERT INTO employees (name, dept) VALUES ('Bob', 'Engineering')")
.expect("insert failed");
db.execute("INSERT INTO employees (name, dept) VALUES ('Charlie', 'Engineering')")
.expect("insert failed");
db.execute("INSERT INTO employees (name, dept) VALUES ('Diana', 'Sales')")
.expect("insert failed");
db.execute("INSERT INTO employees (name, dept) VALUES ('Eve', 'Sales')")
.expect("insert failed");
let result =
db.query("SELECT dept, COUNT(*) FROM employees GROUP BY dept").expect("query failed");
assert_eq!(result.len(), 2);
let mut eng_count = 0;
let mut sales_count = 0;
for row in result.rows() {
if let Some(Value::String(dept)) = row.get(0) {
if let Some(Value::Int(count)) = row.get(1) {
if dept == "Engineering" {
eng_count = *count;
} else if dept == "Sales" {
sales_count = *count;
}
}
}
}
assert_eq!(eng_count, 3, "Engineering should have 3 employees");
assert_eq!(sales_count, 2, "Sales should have 2 employees");
}
#[test]
fn test_group_by_sum() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO products (category, price) VALUES ('Electronics', 100)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Electronics', 150)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Clothing', 50)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Clothing', 75)")
.expect("insert failed");
let result = db
.query("SELECT category, SUM(price) FROM products GROUP BY category")
.expect("query failed");
assert_eq!(result.len(), 2);
let mut electronics_sum = 0.0;
let mut clothing_sum = 0.0;
for row in result.rows() {
if let Some(Value::String(category)) = row.get(0) {
if let Some(Value::Float(sum)) = row.get(1) {
if category == "Electronics" {
electronics_sum = *sum;
} else if category == "Clothing" {
clothing_sum = *sum;
}
}
}
}
assert!((electronics_sum - 250.0).abs() < 0.001, "Electronics sum should be 250");
assert!((clothing_sum - 125.0).abs() < 0.001, "Clothing sum should be 125");
}
#[test]
fn test_min_max_aggregate() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, age) VALUES ('Alice', 30)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Bob', 25)").expect("insert failed");
db.execute("INSERT INTO users (name, age) VALUES ('Charlie', 35)").expect("insert failed");
let result = db.query("SELECT MIN(age), MAX(age) FROM users").expect("query failed");
assert_eq!(result.len(), 1);
let min_val = result.rows()[0].get(0);
let max_val = result.rows()[0].get(1);
assert_eq!(min_val, Some(&Value::Int(25)), "Min age should be 25");
assert_eq!(max_val, Some(&Value::Int(35)), "Max age should be 35");
}
#[test]
fn test_aggregate_empty_table() {
let db = Database::in_memory().expect("failed to create db");
let result = db.query("SELECT COUNT(*) FROM empty_table").expect("query failed");
assert_eq!(result.len(), 1);
let count_val = result.rows()[0].get(0);
assert_eq!(count_val, Some(&Value::Int(0)));
}
#[test]
fn test_multiple_aggregates() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO products (name, price) VALUES ('Widget', 10)").expect("insert failed");
db.execute("INSERT INTO products (name, price) VALUES ('Gadget', 25)").expect("insert failed");
db.execute("INSERT INTO products (name, price) VALUES ('Gizmo', 15)").expect("insert failed");
let result = db
.query("SELECT COUNT(*), SUM(price), MIN(price), MAX(price) FROM products")
.expect("query failed");
assert_eq!(result.len(), 1);
let row = &result.rows()[0];
assert_eq!(row.get(0), Some(&Value::Int(3)));
if let Some(Value::Float(sum)) = row.get(1) {
assert!((sum - 50.0).abs() < 0.001);
} else {
panic!("Expected float sum value");
}
assert_eq!(row.get(2), Some(&Value::Int(10)));
assert_eq!(row.get(3), Some(&Value::Int(25)));
}
#[test]
fn test_select_distinct_single_column() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO products (name, category) VALUES ('Widget', 'Electronics')")
.expect("insert failed");
db.execute("INSERT INTO products (name, category) VALUES ('Gadget', 'Electronics')")
.expect("insert failed");
db.execute("INSERT INTO products (name, category) VALUES ('Shirt', 'Clothing')")
.expect("insert failed");
db.execute("INSERT INTO products (name, category) VALUES ('Pants', 'Clothing')")
.expect("insert failed");
db.execute("INSERT INTO products (name, category) VALUES ('Hat', 'Clothing')")
.expect("insert failed");
let result = db.query("SELECT DISTINCT category FROM products").expect("query failed");
assert_eq!(result.len(), 2, "Expected 2 distinct categories, got {}", result.len());
let mut categories: Vec<String> =
result
.rows()
.iter()
.filter_map(|row| {
if let Some(Value::String(s)) = row.get(0) {
Some(s.clone())
} else {
None
}
})
.collect();
categories.sort();
assert_eq!(categories, vec!["Clothing", "Electronics"]);
}
#[test]
fn test_select_distinct_multiple_columns() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name, city) VALUES ('Alice', 'NYC')").expect("insert failed");
db.execute("INSERT INTO users (name, city) VALUES ('Alice', 'NYC')").expect("insert failed");
db.execute("INSERT INTO users (name, city) VALUES ('Alice', 'LA')").expect("insert failed");
db.execute("INSERT INTO users (name, city) VALUES ('Bob', 'NYC')").expect("insert failed");
db.execute("INSERT INTO users (name, city) VALUES ('Bob', 'NYC')").expect("insert failed");
let result = db.query("SELECT DISTINCT name, city FROM users").expect("query failed");
assert_eq!(result.len(), 3, "Expected 3 distinct name/city combinations, got {}", result.len());
}
#[test]
fn test_select_distinct_all_unique() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO users (name) VALUES ('Alice')").expect("insert failed");
db.execute("INSERT INTO users (name) VALUES ('Bob')").expect("insert failed");
db.execute("INSERT INTO users (name) VALUES ('Charlie')").expect("insert failed");
let result = db.query("SELECT DISTINCT name FROM users").expect("query failed");
assert_eq!(result.len(), 3, "Expected 3 distinct names, got {}", result.len());
}
#[test]
fn test_select_distinct_empty_table() {
let db = Database::in_memory().expect("failed to create db");
let result = db.query("SELECT DISTINCT category FROM products").expect("query failed");
assert!(result.is_empty());
}
#[test]
fn test_select_distinct_with_where() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO products (category, price) VALUES ('Electronics', 100)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Electronics', 200)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Clothing', 50)")
.expect("insert failed");
db.execute("INSERT INTO products (category, price) VALUES ('Clothing', 75)")
.expect("insert failed");
let result =
db.query("SELECT DISTINCT category FROM products WHERE price > 60").expect("query failed");
assert_eq!(result.len(), 2, "Expected 2 distinct categories, got {}", result.len());
}
#[test]
fn test_select_distinct_star() {
let db = Database::in_memory().expect("failed to create db");
db.execute("INSERT INTO simple (val) VALUES (1)").expect("insert failed");
db.execute("INSERT INTO simple (val) VALUES (1)").expect("insert failed");
db.execute("INSERT INTO simple (val) VALUES (2)").expect("insert failed");
let result = db.query("SELECT DISTINCT * FROM simple").expect("query failed");
assert_eq!(result.len(), 3);
}
#[test]
fn test_vector_distance_euclidean() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc1', $1)",
&[Value::Vector(vec![1.0, 0.0, 0.0, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc2', $1)",
&[Value::Vector(vec![0.0, 1.0, 0.0, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc3', $1)",
&[Value::Vector(vec![0.0, 0.0, 1.0, 0.0])],
)
.expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <-> $1 as distance FROM documents",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 3);
let dist_idx = result.column_index("distance").expect("distance column not found");
let mut has_zero_distance = false;
for row in result.rows() {
if let Some(Value::Float(dist)) = row.get(dist_idx) {
if *dist < 0.001 {
has_zero_distance = true;
}
}
}
assert!(has_zero_distance, "Should have one document with zero distance");
}
#[test]
fn test_vector_distance_order_by() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc1', $1)",
&[Value::Vector(vec![1.0, 0.0, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc2', $1)",
&[Value::Vector(vec![0.8, 0.2, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc3', $1)",
&[Value::Vector(vec![0.5, 0.5, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('doc4', $1)",
&[Value::Vector(vec![0.0, 1.0, 0.0])],
)
.expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <-> $1 as distance FROM documents ORDER BY embedding <-> $1",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 4);
let title_idx = result.column_index("title").expect("title column not found");
assert_eq!(
result.rows()[0].get(title_idx),
Some(&Value::String("doc1".to_string())),
"First result should be doc1 (closest)"
);
assert_eq!(
result.rows()[3].get(title_idx),
Some(&Value::String("doc4".to_string())),
"Last result should be doc4 (farthest)"
);
}
#[test]
fn test_vector_distance_with_limit() {
let db = Database::in_memory().expect("failed to create db");
for i in 1..=5 {
let v = i as f32 / 5.0;
db.execute_with_params(
&format!("INSERT INTO documents (title, embedding) VALUES ('doc{}', $1)", i),
&[Value::Vector(vec![v, 1.0 - v, 0.0])],
)
.expect("insert failed");
}
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <-> $1 as distance FROM documents ORDER BY embedding <-> $1 LIMIT 3",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 3, "Expected 3 results with LIMIT 3");
}
#[test]
fn test_vector_distance_cosine() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('same_dir', $1)",
&[Value::Vector(vec![2.0, 0.0, 0.0])], )
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('opposite', $1)",
&[Value::Vector(vec![-1.0, 0.0, 0.0])], )
.expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <=> $1 as distance FROM documents",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 2);
let title_idx = result.column_index("title").expect("title column not found");
let dist_idx = result.column_index("distance").expect("distance column not found");
for row in result.rows() {
if let Some(Value::String(title)) = row.get(title_idx) {
if let Some(Value::Float(dist)) = row.get(dist_idx) {
if title == "same_dir" {
assert!(
*dist < 0.001,
"Same direction should have cosine distance ~0, got {}",
dist
);
} else if title == "opposite" {
assert!(
(*dist - 2.0).abs() < 0.001,
"Opposite direction should have cosine distance ~2, got {}",
dist
);
}
}
}
}
}
#[test]
fn test_vector_distance_inner_product() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('high_dot', $1)",
&[Value::Vector(vec![2.0, 2.0])], )
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('low_dot', $1)",
&[Value::Vector(vec![0.5, 0.5])], )
.expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 1.0]);
let result = db
.query_with_params(
"SELECT title, embedding <#> $1 as distance FROM documents ORDER BY embedding <#> $1",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 2);
let title_idx = result.column_index("title").expect("title column not found");
assert_eq!(
result.rows()[0].get(title_idx),
Some(&Value::String("high_dot".to_string())),
"Higher inner product should come first"
);
}
#[test]
fn test_vector_distance_with_filter() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, category, embedding) VALUES ('tech1', 'Technology', $1)",
&[Value::Vector(vec![1.0, 0.0, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, category, embedding) VALUES ('tech2', 'Technology', $1)",
&[Value::Vector(vec![0.8, 0.2, 0.0])],
)
.expect("insert failed");
db.execute_with_params(
"INSERT INTO documents (title, category, embedding) VALUES ('sports1', 'Sports', $1)",
&[Value::Vector(vec![0.5, 0.5, 0.0])],
)
.expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <-> $1 as distance FROM documents WHERE category = 'Technology' ORDER BY embedding <-> $1",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 2);
let title_idx = result.column_index("title").expect("title column not found");
assert_eq!(result.rows()[0].get(title_idx), Some(&Value::String("tech1".to_string())));
}
#[test]
fn test_vector_distance_null_handling() {
let db = Database::in_memory().expect("failed to create db");
db.execute_with_params(
"INSERT INTO documents (title, embedding) VALUES ('with_embedding', $1)",
&[Value::Vector(vec![1.0, 0.0, 0.0])],
)
.expect("insert failed");
db.execute("INSERT INTO documents (title) VALUES ('no_embedding')").expect("insert failed");
let query_vector = Value::Vector(vec![1.0, 0.0, 0.0]);
let result = db
.query_with_params(
"SELECT title, embedding <-> $1 as distance FROM documents",
&[query_vector],
)
.expect("query failed");
assert_eq!(result.len(), 2);
let title_idx = result.column_index("title").expect("title column not found");
let dist_idx = result.column_index("distance").expect("distance column not found");
for row in result.rows() {
if let Some(Value::String(title)) = row.get(title_idx) {
if title == "no_embedding" {
assert_eq!(
row.get(dist_idx),
Some(&Value::Null),
"Document without embedding should have NULL distance"
);
}
}
}
}
#[test]
fn test_explain_basic() {
let db = Database::in_memory().expect("failed to create db");
let result = db.query("EXPLAIN SELECT * FROM users WHERE age > 21").expect("explain failed");
assert!(!result.is_empty(), "EXPLAIN should return plan output");
let plan_idx = result.column_index("plan").expect("plan column not found");
let first_row = result.rows().first().expect("no rows");
if let Some(Value::String(line)) = first_row.get(plan_idx) {
assert!(line.contains("Logical Plan"), "Expected Logical Plan header, got: {}", line);
}
let has_physical = result.rows().iter().any(|row| {
if let Some(Value::String(line)) = row.get(plan_idx) {
line.contains("Physical Plan")
} else {
false
}
});
assert!(has_physical, "EXPLAIN should include Physical Plan");
}
#[test]
fn test_explain_with_join() {
let db = Database::in_memory().expect("failed to create db");
let result = db
.query("EXPLAIN SELECT * FROM users u JOIN orders o ON u.id = o.user_id")
.expect("explain failed");
assert!(!result.is_empty(), "EXPLAIN should return plan output");
let plan_idx = result.column_index("plan").expect("plan column not found");
let has_join = result.rows().iter().any(|row| {
if let Some(Value::String(line)) = row.get(plan_idx) {
line.contains("Join")
} else {
false
}
});
assert!(has_join, "EXPLAIN of JOIN query should mention Join in plan");
}