use stoolap::Database;
fn create_test_db(name: &str) -> Database {
Database::open(&format!("memory://{}", name)).expect("Failed to create in-memory database")
}
#[test]
fn test_insert_select_from_same_table() {
let db = create_test_db("insert_select_same");
db.execute(
"CREATE TABLE numbers (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO numbers VALUES (1, 100), (2, 200), (3, 300)",
(),
)
.unwrap();
db.execute(
"INSERT INTO numbers (id, value) SELECT id + 10, value * 2 FROM numbers",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM numbers", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(6));
let result = db
.query(
"SELECT id, value FROM numbers WHERE id > 10 ORDER BY id",
(),
)
.unwrap();
let mut rows: Vec<(i64, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], (11, 200));
assert_eq!(rows[1], (12, 400));
assert_eq!(rows[2], (13, 600));
}
#[test]
fn test_insert_select_from_another_table() {
let db = create_test_db("insert_select_other");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute(
"INSERT INTO source VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')",
(),
)
.unwrap();
db.execute(
"INSERT INTO target (id, name) SELECT id, name FROM source",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM target", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(3));
let result = db.query("SELECT name FROM target ORDER BY id", ()).unwrap();
let mut names: Vec<String> = Vec::new();
for row in result {
let row = row.unwrap();
names.push(row.get(0).unwrap());
}
assert_eq!(names, vec!["Alice", "Bob", "Charlie"]);
}
#[test]
fn test_insert_select_with_where_clause() {
let db = create_test_db("insert_select_where");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO source VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50)",
(),
)
.unwrap();
db.execute(
"INSERT INTO target (id, value) SELECT id, value FROM source WHERE value > 25",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM target", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(3));
let result = db.query("SELECT id FROM target ORDER BY id", ()).unwrap();
let mut ids: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
ids.push(row.get(0).unwrap());
}
assert_eq!(ids, vec![3, 4, 5]);
}
#[test]
fn test_insert_select_from_values() {
let db = create_test_db("insert_select_values");
db.execute(
"CREATE TABLE numbers (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO numbers (id, name) SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS t(id, name)", ())
.unwrap();
let result = db.query("SELECT COUNT(*) FROM numbers", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(3));
let result = db
.query("SELECT id, name FROM numbers ORDER BY id", ())
.unwrap();
let mut rows: Vec<(i64, String)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows[0], (1, "one".to_string()));
assert_eq!(rows[1], (2, "two".to_string()));
assert_eq!(rows[2], (3, "three".to_string()));
}
#[test]
fn test_insert_select_from_values_with_expressions() {
let db = create_test_db("insert_select_values_expr");
db.execute(
"CREATE TABLE data (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute("INSERT INTO data (id, value) SELECT x, x * x FROM (VALUES (1), (2), (3), (4), (5)) AS t(x)", ())
.unwrap();
let result = db
.query("SELECT id, value FROM data ORDER BY id", ())
.unwrap();
let mut rows: Vec<(i64, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 5);
assert_eq!(rows[0], (1, 1)); assert_eq!(rows[1], (2, 4)); assert_eq!(rows[2], (3, 9)); assert_eq!(rows[3], (4, 16)); assert_eq!(rows[4], (5, 25)); }
#[test]
fn test_insert_select_from_values_filtered() {
let db = create_test_db("insert_select_values_filter");
db.execute(
"CREATE TABLE positive (id INTEGER PRIMARY KEY, num INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO positive (id, num)
SELECT ROW_NUMBER() OVER (), x
FROM (VALUES (-2), (-1), (0), (1), (2), (3)) AS t(x)
WHERE x > 0",
(),
)
.unwrap();
let result = db
.query("SELECT num FROM positive ORDER BY num", ())
.unwrap();
let mut nums: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
nums.push(row.get(0).unwrap());
}
assert_eq!(nums, vec![1, 2, 3]);
}
#[test]
fn test_insert_select_with_aggregation() {
let db = create_test_db("insert_select_agg");
db.execute(
"CREATE TABLE sales (id INTEGER PRIMARY KEY, category TEXT, amount INTEGER)",
(),
)
.unwrap();
db.execute("CREATE TABLE summary (category TEXT, total INTEGER)", ())
.unwrap();
db.execute(
"INSERT INTO sales VALUES
(1, 'Electronics', 100),
(2, 'Electronics', 200),
(3, 'Books', 50),
(4, 'Books', 75),
(5, 'Clothing', 150)",
(),
)
.unwrap();
db.execute(
"INSERT INTO summary (category, total)
SELECT category, SUM(amount) FROM sales GROUP BY category",
(),
)
.unwrap();
let result = db
.query("SELECT category, total FROM summary ORDER BY category", ())
.unwrap();
let mut rows: Vec<(String, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], ("Books".to_string(), 125));
assert_eq!(rows[1], ("Clothing".to_string(), 150));
assert_eq!(rows[2], ("Electronics".to_string(), 300));
}
#[test]
fn test_insert_select_with_count() {
let db = create_test_db("insert_select_count");
db.execute(
"CREATE TABLE items (id INTEGER PRIMARY KEY, category TEXT)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE category_counts (category TEXT, item_count INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO items VALUES (1, 'A'), (2, 'A'), (3, 'B'), (4, 'A'), (5, 'C')",
(),
)
.unwrap();
db.execute(
"INSERT INTO category_counts (category, item_count)
SELECT category, COUNT(*) FROM items GROUP BY category",
(),
)
.unwrap();
let result = db
.query(
"SELECT category, item_count FROM category_counts ORDER BY category",
(),
)
.unwrap();
let mut rows: Vec<(String, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], ("A".to_string(), 3));
assert_eq!(rows[1], ("B".to_string(), 1));
assert_eq!(rows[2], ("C".to_string(), 1));
}
#[test]
fn test_insert_select_with_join() {
let db = create_test_db("insert_select_join");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", ())
.unwrap();
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER, amount INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE user_totals (user_name TEXT, total_amount INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')",
(),
)
.unwrap();
db.execute(
"INSERT INTO orders VALUES (1, 1, 100), (2, 1, 50), (3, 2, 200), (4, 3, 75)",
(),
)
.unwrap();
db.execute(
"INSERT INTO user_totals (user_name, total_amount)
SELECT u.name, SUM(o.amount)
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.name",
(),
)
.unwrap();
let result = db
.query(
"SELECT user_name, total_amount FROM user_totals ORDER BY user_name",
(),
)
.unwrap();
let mut rows: Vec<(String, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], ("Alice".to_string(), 150));
assert_eq!(rows[1], ("Bob".to_string(), 200));
assert_eq!(rows[2], ("Charlie".to_string(), 75));
}
#[test]
fn test_insert_select_with_union() {
let db = create_test_db("insert_select_union");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("CREATE TABLE combined (val INTEGER)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 10), (2, 20)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (1, 20), (2, 30)", ())
.unwrap();
db.execute(
"INSERT INTO combined (val) SELECT val FROM t1 UNION SELECT val FROM t2",
(),
)
.unwrap();
let result = db
.query("SELECT val FROM combined ORDER BY val", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
assert_eq!(values, vec![10, 20, 30]);
}
#[test]
fn test_insert_select_with_union_all() {
let db = create_test_db("insert_select_union_all");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.unwrap();
db.execute("CREATE TABLE combined (val INTEGER)", ())
.unwrap();
db.execute("INSERT INTO t1 VALUES (1, 10), (2, 20)", ())
.unwrap();
db.execute("INSERT INTO t2 VALUES (1, 20), (2, 30)", ())
.unwrap();
db.execute(
"INSERT INTO combined (val) SELECT val FROM t1 UNION ALL SELECT val FROM t2",
(),
)
.unwrap();
let result = db
.query("SELECT val FROM combined ORDER BY val", ())
.unwrap();
let mut values: Vec<i64> = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get(0).unwrap());
}
assert_eq!(values, vec![10, 20, 20, 30]);
}
#[test]
fn test_insert_select_with_cte() {
let db = create_test_db("insert_select_cte");
db.execute(
"CREATE TABLE results (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"INSERT INTO results (id, value)
WITH doubled AS (
SELECT * FROM (VALUES (1, 10), (2, 20), (3, 30)) AS t(id, val)
)
SELECT id, val * 2 FROM doubled",
(),
)
.unwrap();
let result = db
.query("SELECT id, value FROM results ORDER BY id", ())
.unwrap();
let mut rows: Vec<(i64, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get(0).unwrap(), row.get(1).unwrap()));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], (1, 20));
assert_eq!(rows[1], (2, 40));
assert_eq!(rows[2], (3, 60));
}
#[test]
fn test_insert_select_column_reorder() {
let db = create_test_db("insert_select_reorder");
db.execute(
"CREATE TABLE source (a INTEGER PRIMARY KEY, b TEXT, c INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (x INTEGER, y INTEGER PRIMARY KEY, z TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, 'hello', 100)", ())
.unwrap();
db.execute(
"INSERT INTO target (z, y, x) SELECT b, a, c FROM source",
(),
)
.unwrap();
let result = db.query("SELECT x, y, z FROM target", ()).unwrap();
for row in result {
let row = row.unwrap();
let x: i64 = row.get(0).unwrap();
let y: i64 = row.get(1).unwrap();
let z: String = row.get(2).unwrap();
assert_eq!(x, 100);
assert_eq!(y, 1);
assert_eq!(z, "hello");
}
}
#[test]
fn test_insert_select_partial_columns() {
let db = create_test_db("insert_select_partial");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, name TEXT, value INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute(
"INSERT INTO source VALUES (1, 'Alice', 100), (2, 'Bob', 200)",
(),
)
.unwrap();
db.execute(
"INSERT INTO target (id, name) SELECT id, name FROM source",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM target", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(2));
}
#[test]
fn test_insert_select_with_limit_only() {
let db = create_test_db("insert_select_limit_only");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute("CREATE TABLE limited (value INTEGER)", ())
.unwrap();
db.execute(
"INSERT INTO source VALUES (1, 50), (2, 30), (3, 80), (4, 10), (5, 90)",
(),
)
.unwrap();
db.execute(
"INSERT INTO limited (value) SELECT value FROM source LIMIT 3",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM limited", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(3));
}
#[test]
fn test_insert_select_large_dataset() {
let db = create_test_db("insert_select_large");
db.execute("CREATE TABLE source (id INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute("CREATE TABLE target (id INTEGER PRIMARY KEY)", ())
.unwrap();
db.execute(
"INSERT INTO source
WITH RECURSIVE cnt(x) AS (
SELECT 1
UNION ALL
SELECT x + 1 FROM cnt WHERE x < 1000
)
SELECT x FROM cnt",
(),
)
.unwrap();
db.execute("INSERT INTO target (id) SELECT id FROM source", ())
.unwrap();
let result = db.query("SELECT COUNT(*) FROM target", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(1000));
let result = db.query("SELECT MIN(id), MAX(id) FROM target", ()).unwrap();
for row in result {
let row = row.unwrap();
let min: i64 = row.get(0).unwrap();
let max: i64 = row.get(1).unwrap();
assert_eq!(min, 1);
assert_eq!(max, 1000);
}
}
#[test]
fn test_insert_select_empty_result() {
let db = create_test_db("insert_select_empty");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, 100)", ())
.unwrap();
db.execute(
"INSERT INTO target (id, value) SELECT id, value FROM source WHERE value > 1000",
(),
)
.unwrap();
let result = db.query("SELECT COUNT(*) FROM target", ()).unwrap();
let mut count: Option<i64> = None;
for row in result {
let row = row.unwrap();
count = Some(row.get(0).unwrap());
}
assert_eq!(count, Some(0));
}
#[test]
fn test_insert_select_single_row() {
let db = create_test_db("insert_select_single");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, 'only')", ())
.unwrap();
db.execute(
"INSERT INTO target (id, name) SELECT id, name FROM source",
(),
)
.unwrap();
let result = db.query("SELECT name FROM target", ()).unwrap();
let mut names: Vec<String> = Vec::new();
for row in result {
let row = row.unwrap();
names.push(row.get(0).unwrap());
}
assert_eq!(names, vec!["only"]);
}
#[test]
fn test_insert_select_with_default_values() {
let db = create_test_db("insert_select_default");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (
id INTEGER PRIMARY KEY,
value INTEGER,
status TEXT DEFAULT 'active',
priority INTEGER DEFAULT 5,
category TEXT DEFAULT 'general'
)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, 100), (2, 200), (3, 300)", ())
.unwrap();
db.execute(
"INSERT INTO target (id, value) SELECT id, value FROM source",
(),
)
.unwrap();
let result = db
.query(
"SELECT id, value, status, priority, category FROM target ORDER BY id",
(),
)
.unwrap();
let mut rows: Vec<(i64, i64, String, i64, String)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((
row.get(0).unwrap(),
row.get(1).unwrap(),
row.get(2).unwrap(),
row.get(3).unwrap(),
row.get(4).unwrap(),
));
}
assert_eq!(rows.len(), 3);
assert_eq!(
rows[0],
(1, 100, "active".to_string(), 5, "general".to_string())
);
assert_eq!(
rows[1],
(2, 200, "active".to_string(), 5, "general".to_string())
);
assert_eq!(
rows[2],
(3, 300, "active".to_string(), 5, "general".to_string())
);
}
#[test]
fn test_insert_select_default_with_expressions() {
let db = create_test_db("insert_select_default_expr");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (
id INTEGER PRIMARY KEY,
name TEXT,
created_at TEXT DEFAULT 'now',
is_active INTEGER DEFAULT 1
)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, 'Alice'), (2, 'Bob')", ())
.unwrap();
db.execute(
"INSERT INTO target (id, name) SELECT id * 10, UPPER(name) FROM source",
(),
)
.unwrap();
let result = db
.query(
"SELECT id, name, created_at, is_active FROM target ORDER BY id",
(),
)
.unwrap();
let mut rows: Vec<(i64, String, String, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((
row.get(0).unwrap(),
row.get(1).unwrap(),
row.get(2).unwrap(),
row.get(3).unwrap(),
));
}
assert_eq!(rows.len(), 2);
assert_eq!(rows[0], (10, "ALICE".to_string(), "now".to_string(), 1));
assert_eq!(rows[1], (20, "BOB".to_string(), "now".to_string(), 1));
}
#[test]
fn test_insert_select_default_vs_explicit_null() {
let db = create_test_db("insert_select_default_null");
db.execute(
"CREATE TABLE source (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.unwrap();
db.execute(
"CREATE TABLE target (
id INTEGER PRIMARY KEY,
val INTEGER,
status TEXT DEFAULT 'pending'
)",
(),
)
.unwrap();
db.execute("INSERT INTO source VALUES (1, NULL), (2, 100)", ())
.unwrap();
db.execute(
"INSERT INTO target (id, val) SELECT id, val FROM source",
(),
)
.unwrap();
let result = db
.query("SELECT id, val, status FROM target ORDER BY id", ())
.unwrap();
let mut row1_status: Option<String> = None;
let mut row2_val: Option<i64> = None;
let mut row2_status: Option<String> = None;
let mut count = 0;
for row in result {
let row = row.unwrap();
let id: i64 = row.get(0).unwrap();
if id == 1 {
row1_status = Some(row.get::<String>(2).unwrap());
} else if id == 2 {
row2_val = Some(row.get(1).unwrap());
row2_status = Some(row.get(2).unwrap());
}
count += 1;
}
assert_eq!(count, 2);
assert_eq!(row1_status, Some("pending".to_string()));
assert_eq!(row2_val, Some(100));
assert_eq!(row2_status, Some("pending".to_string()));
}
#[test]
fn test_insert_select_default_consistency() {
let db = create_test_db("insert_select_default_consistent");
db.execute(
"CREATE TABLE mixed (
id INTEGER PRIMARY KEY,
value INTEGER,
tag TEXT DEFAULT 'default_tag'
)",
(),
)
.unwrap();
db.execute("INSERT INTO mixed (id, value) VALUES (1, 100)", ())
.unwrap();
db.execute("INSERT INTO mixed (id, value) SELECT 2, 200", ())
.unwrap();
let result = db
.query("SELECT id, value, tag FROM mixed ORDER BY id", ())
.unwrap();
let mut rows: Vec<(i64, i64, String)> = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((
row.get(0).unwrap(),
row.get(1).unwrap(),
row.get(2).unwrap(),
));
}
assert_eq!(rows.len(), 2);
assert_eq!(rows[0], (1, 100, "default_tag".to_string()));
assert_eq!(rows[1], (2, 200, "default_tag".to_string()));
}