use stoolap::Database;
fn setup_update_tables(db: &Database) {
db.execute(
"CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
category TEXT,
price FLOAT,
discount FLOAT
)",
(),
)
.expect("Failed to create products table");
db.execute(
"CREATE TABLE categories (
id INTEGER PRIMARY KEY,
name TEXT,
is_premium BOOLEAN
)",
(),
)
.expect("Failed to create categories table");
db.execute(
"INSERT INTO categories (id, name, is_premium) VALUES (1, 'Electronics', true)",
(),
)
.unwrap();
db.execute(
"INSERT INTO categories (id, name, is_premium) VALUES (2, 'Books', false)",
(),
)
.unwrap();
db.execute(
"INSERT INTO categories (id, name, is_premium) VALUES (3, 'Clothing', true)",
(),
)
.unwrap();
db.execute(
"INSERT INTO categories (id, name, is_premium) VALUES (4, 'Food', false)",
(),
)
.unwrap();
db.execute("INSERT INTO products (id, name, category, price, discount) VALUES (1, 'Laptop', 'Electronics', 1000.0, 0.0)", ()).unwrap();
db.execute("INSERT INTO products (id, name, category, price, discount) VALUES (2, 'Novel', 'Books', 20.0, 0.0)", ()).unwrap();
db.execute("INSERT INTO products (id, name, category, price, discount) VALUES (3, 'Shirt', 'Clothing', 50.0, 0.0)", ()).unwrap();
db.execute("INSERT INTO products (id, name, category, price, discount) VALUES (4, 'Phone', 'Electronics', 800.0, 0.0)", ()).unwrap();
db.execute("INSERT INTO products (id, name, category, price, discount) VALUES (5, 'Bread', 'Food', 5.0, 0.0)", ()).unwrap();
}
#[test]
fn test_update_with_in_subquery() {
let db = Database::open("memory://update_in").expect("Failed to create database");
setup_update_tables(&db);
db.execute(
"UPDATE products SET discount = 0.15 WHERE category IN (
SELECT name FROM categories WHERE is_premium = true
)",
(),
)
.expect("Failed to update with IN subquery");
let result = db
.query("SELECT id, name, discount FROM products ORDER BY id", ())
.expect("Failed to query");
let expected = [
(1, "Laptop", 0.15), (2, "Novel", 0.0), (3, "Shirt", 0.15), (4, "Phone", 0.15), (5, "Bread", 0.0), ];
for (idx, row) in result.enumerate() {
let row = row.expect("Failed to get row");
let id: i64 = row.get(0).unwrap();
let name: String = row.get(1).unwrap();
let discount: f64 = row.get(2).unwrap();
assert_eq!(id, expected[idx].0, "ID mismatch at index {}", idx);
assert_eq!(name, expected[idx].1, "Name mismatch at index {}", idx);
assert!(
(discount - expected[idx].2).abs() < 0.001,
"Discount mismatch at index {}",
idx
);
}
}
#[test]
fn test_update_with_not_in_subquery() {
let db = Database::open("memory://update_not_in").expect("Failed to create database");
setup_update_tables(&db);
db.execute(
"UPDATE products SET price = price * 0.9 WHERE category NOT IN (
SELECT name FROM categories WHERE is_premium = true
)",
(),
)
.expect("Failed to update with NOT IN subquery");
let result = db
.query("SELECT id, name, price FROM products ORDER BY id", ())
.expect("Failed to query");
let expected = [
(1, "Laptop", 1000.0), (2, "Novel", 18.0), (3, "Shirt", 50.0), (4, "Phone", 800.0), (5, "Bread", 4.5), ];
for (idx, row) in result.enumerate() {
let row = row.expect("Failed to get row");
let id: i64 = row.get(0).unwrap();
let name: String = row.get(1).unwrap();
let price: f64 = row.get(2).unwrap();
assert_eq!(id, expected[idx].0, "ID mismatch at index {}", idx);
assert_eq!(name, expected[idx].1, "Name mismatch at index {}", idx);
assert!(
(price - expected[idx].2).abs() < 0.001,
"Price mismatch at index {}: expected {}, got {}",
idx,
expected[idx].2,
price
);
}
}
#[test]
fn test_update_with_empty_subquery() {
let db = Database::open("memory://update_empty").expect("Failed to create database");
setup_update_tables(&db);
db.execute(
"UPDATE products SET discount = 0.5 WHERE category IN (
SELECT name FROM categories WHERE id > 100
)",
(),
)
.expect("Failed to update");
let result = db
.query("SELECT discount FROM products", ())
.expect("Failed to query");
for row in result {
let row = row.expect("Failed to get row");
let discount: f64 = row.get(0).unwrap();
assert!(
(discount - 0.0).abs() < 0.001,
"Discount should be unchanged"
);
}
}
#[test]
fn test_update_with_complex_condition() {
let db = Database::open("memory://update_complex").expect("Failed to create database");
setup_update_tables(&db);
db.execute(
"UPDATE products SET discount = 0.20 WHERE price > 100 AND category IN (
SELECT name FROM categories WHERE is_premium = true
)",
(),
)
.expect("Failed to update");
let result = db
.query("SELECT id, discount FROM products ORDER BY id", ())
.expect("Failed to query");
let expected_discounts = [
(1, 0.20), (2, 0.0), (3, 0.0), (4, 0.20), (5, 0.0), ];
for (idx, row) in result.enumerate() {
let row = row.expect("Failed to get row");
let id: i64 = row.get(0).unwrap();
let discount: f64 = row.get(1).unwrap();
assert_eq!(id, expected_discounts[idx].0);
assert!(
(discount - expected_discounts[idx].1).abs() < 0.001,
"Discount mismatch for id {}: expected {}, got {}",
id,
expected_discounts[idx].1,
discount
);
}
}
#[test]
fn test_update_multiple_columns() {
let db = Database::open("memory://update_multi").expect("Failed to create database");
setup_update_tables(&db);
db.execute(
"UPDATE products SET price = price * 0.95, discount = 0.05 WHERE category NOT IN (
SELECT name FROM categories WHERE is_premium = true
)",
(),
)
.expect("Failed to update");
let result = db
.query(
"SELECT id, price, discount FROM products WHERE id IN (2, 5) ORDER BY id",
(),
)
.expect("Failed to query");
let mut rows: Vec<(i64, f64, f64)> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let id: i64 = row.get(0).unwrap();
let price: f64 = row.get(1).unwrap();
let discount: f64 = row.get(2).unwrap();
rows.push((id, price, discount));
}
assert_eq!(rows.len(), 2);
assert_eq!(rows[0].0, 2);
assert!((rows[0].1 - 19.0).abs() < 0.001);
assert!((rows[0].2 - 0.05).abs() < 0.001);
assert_eq!(rows[1].0, 5);
assert!((rows[1].1 - 4.75).abs() < 0.001);
assert!((rows[1].2 - 0.05).abs() < 0.001);
}