use stoolap::Database;
#[test]
fn test_unique_index_constraint() {
let db = Database::open("memory://unique_index").expect("Failed to create database");
db.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)",
(),
)
.expect("Failed to create table");
db.execute("CREATE UNIQUE INDEX idx_users_email ON users (email)", ())
.expect("Failed to create unique index");
db.execute(
"INSERT INTO users (id, name, email) VALUES (1, 'User1', 'user1@example.com')",
(),
)
.expect("Failed to insert first row");
let result = db.execute(
"INSERT INTO users (id, name, email) VALUES (2, 'User2', 'user1@example.com')",
(),
);
assert!(
result.is_err(),
"Inserting duplicate email should have failed"
);
}
#[test]
fn test_unique_index_with_null() {
let db = Database::open("memory://unique_null").expect("Failed to create database");
db.execute(
"CREATE TABLE products (id INTEGER PRIMARY KEY, sku TEXT, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute("CREATE UNIQUE INDEX idx_sku ON products (sku)", ())
.expect("Failed to create unique index");
db.execute("INSERT INTO products VALUES (1, NULL, 'Product 1')", ())
.expect("Failed to insert first NULL sku");
db.execute("INSERT INTO products VALUES (2, NULL, 'Product 2')", ())
.expect("Failed to insert second NULL sku");
db.execute(
"INSERT INTO products VALUES (3, 'SKU-001', 'Product 3')",
(),
)
.expect("Failed to insert SKU-001");
let result = db.execute(
"INSERT INTO products VALUES (4, 'SKU-001', 'Product 4')",
(),
);
assert!(result.is_err(), "Duplicate SKU should have failed");
let count: i64 = db
.query_one("SELECT COUNT(*) FROM products", ())
.expect("Failed to count");
assert_eq!(count, 3, "Expected 3 rows");
}
#[test]
fn test_drop_unique_index() {
let db = Database::open("memory://drop_unique").expect("Failed to create database");
db.execute("CREATE TABLE items (id INTEGER PRIMARY KEY, code TEXT)", ())
.expect("Failed to create table");
db.execute("CREATE UNIQUE INDEX idx_code ON items (code)", ())
.expect("Failed to create unique index");
db.execute("INSERT INTO items VALUES (1, 'CODE-001')", ())
.expect("Failed to insert first row");
let result = db.execute("INSERT INTO items VALUES (2, 'CODE-001')", ());
assert!(
result.is_err(),
"Duplicate code should have failed before drop"
);
db.execute("DROP INDEX idx_code ON items", ())
.expect("Failed to drop index");
db.execute("INSERT INTO items VALUES (2, 'CODE-001')", ())
.expect("Failed to insert after drop");
let count: i64 = db
.query_one("SELECT COUNT(*) FROM items WHERE code = 'CODE-001'", ())
.expect("Failed to count");
assert_eq!(count, 2, "Expected 2 rows with same code after drop");
}
#[test]
fn test_multi_column_unique_index() {
let db = Database::open("memory://multi_unique").expect("Failed to create database");
db.execute(
"CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER,
order_date TEXT,
amount FLOAT
)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE UNIQUE INDEX idx_customer_date ON orders (customer_id, order_date)",
(),
)
.expect("Failed to create multi-column unique index");
db.execute(
"INSERT INTO orders VALUES (1, 100, '2025-01-01', 99.99)",
(),
)
.expect("Failed to insert first order");
db.execute(
"INSERT INTO orders VALUES (2, 100, '2025-01-02', 149.99)",
(),
)
.expect("Failed to insert second order (same customer, different date)");
db.execute(
"INSERT INTO orders VALUES (3, 200, '2025-01-01', 199.99)",
(),
)
.expect("Failed to insert third order (different customer, same date)");
let result = db.execute(
"INSERT INTO orders VALUES (4, 100, '2025-01-01', 299.99)",
(),
);
assert!(
result.is_err(),
"Duplicate customer_id + order_date should have failed"
);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM orders", ())
.expect("Failed to count");
assert_eq!(count, 3, "Expected 3 rows");
}
#[test]
fn test_show_unique_index() {
let db = Database::open("memory://show_unique").expect("Failed to create database");
db.execute(
"CREATE TABLE accounts (id INTEGER PRIMARY KEY, account_no TEXT, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE UNIQUE INDEX idx_account_no ON accounts (account_no)",
(),
)
.expect("Failed to create unique index");
let result = db
.query("SHOW INDEXES FROM accounts", ())
.expect("Failed to show indexes");
let mut found_unique = false;
for row in result {
let row = row.expect("Failed to get row");
let index_name: String = row.get(1).unwrap();
let is_unique: bool = row.get(4).unwrap();
if index_name == "idx_account_no" {
found_unique = true;
assert!(is_unique, "Index should be marked as unique");
}
}
assert!(found_unique, "Unique index should be found in SHOW INDEXES");
}
#[test]
fn test_unique_index_update() {
let db = Database::open("memory://unique_update").expect("Failed to create database");
db.execute(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, employee_id TEXT, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE UNIQUE INDEX idx_emp_id ON employees (employee_id)",
(),
)
.expect("Failed to create unique index");
db.execute("INSERT INTO employees VALUES (1, 'EMP-001', 'Alice')", ())
.expect("Failed to insert Alice");
db.execute("INSERT INTO employees VALUES (2, 'EMP-002', 'Bob')", ())
.expect("Failed to insert Bob");
let result = db.execute(
"UPDATE employees SET employee_id = 'EMP-001' WHERE id = 2",
(),
);
assert!(
result.is_err(),
"Update to duplicate employee_id should have failed"
);
let result = db
.query("SELECT employee_id FROM employees WHERE id = 2", ())
.expect("Failed to query");
for row in result {
let row = row.expect("Failed to get row");
let emp_id: String = row.get(0).unwrap();
assert_eq!(emp_id, "EMP-002", "Bob's employee_id should be unchanged");
}
}
#[test]
fn test_unique_index_if_not_exists() {
let db = Database::open("memory://unique_if_not_exists").expect("Failed to create database");
db.execute("CREATE TABLE tags (id INTEGER PRIMARY KEY, tag TEXT)", ())
.expect("Failed to create table");
db.execute("CREATE UNIQUE INDEX idx_tag ON tags (tag)", ())
.expect("Failed to create unique index first time");
let result = db.execute("CREATE UNIQUE INDEX idx_tag ON tags (tag)", ());
assert!(
result.is_err(),
"Creating duplicate index without IF NOT EXISTS should fail"
);
db.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS idx_tag ON tags (tag)",
(),
)
.expect("Failed with IF NOT EXISTS");
}