use iridium_core::{parse_sql, types::Value, Engine};
fn exec(engine: &mut Engine, sql: &str) {
let stmt = parse_sql(sql).unwrap_or_else(|_| panic!("parse failed: {}", sql));
engine
.execute(stmt)
.unwrap_or_else(|_| panic!("execute failed: {}", sql));
}
fn query(engine: &mut Engine, sql: &str) -> iridium_core::QueryResult {
let stmt = parse_sql(sql).unwrap_or_else(|_| panic!("parse failed: {}", sql));
engine
.execute(stmt)
.unwrap_or_else(|_| panic!("execute failed: {}", sql))
.expect("expected result")
}
#[test]
fn test_merge_basic_matched() {
let mut e = Engine::new();
exec(
&mut e,
"CREATE TABLE target (id INT PRIMARY KEY, val VARCHAR(10))",
);
exec(&mut e, "CREATE TABLE source (id INT, val VARCHAR(10))");
exec(&mut e, "INSERT INTO target VALUES (1, 'old'), (2, 'old')");
exec(&mut e, "INSERT INTO source VALUES (1, 'new'), (3, 'new')");
exec(
&mut e,
"MERGE target t USING source s ON t.id = s.id \
WHEN MATCHED THEN UPDATE SET val = s.val",
);
let r = query(&mut e, "SELECT * FROM target ORDER BY id");
println!("test_merge_basic_matched: {:?}", r);
assert_eq!(r.rows.len(), 2);
assert_eq!(r.rows[0][1], Value::VarChar("new".to_string())); assert_eq!(r.rows[1][1], Value::VarChar("old".to_string())); }
#[test]
fn test_merge_not_matched_by_source_delete() {
let mut e = Engine::new();
exec(
&mut e,
"CREATE TABLE target (id INT PRIMARY KEY, val VARCHAR(10))",
);
exec(&mut e, "CREATE TABLE source (id INT, val VARCHAR(10))");
exec(
&mut e,
"INSERT INTO target VALUES (1, 'a'), (2, 'b'), (3, 'c')",
);
exec(&mut e, "INSERT INTO source VALUES (1, 'x')");
exec(
&mut e,
"MERGE target t USING source s ON t.id = s.id \
WHEN MATCHED THEN UPDATE SET val = s.val \
WHEN NOT MATCHED BY SOURCE THEN DELETE",
);
let r = query(&mut e, "SELECT * FROM target ORDER BY id");
assert_eq!(r.rows.len(), 1);
assert_eq!(r.rows[0][0], Value::Int(1));
assert_eq!(r.rows[0][1], Value::VarChar("x".to_string()));
}
#[test]
fn test_merge_not_matched_by_source_update() {
let mut e = Engine::new();
exec(
&mut e,
"CREATE TABLE target (id INT PRIMARY KEY, val VARCHAR(10))",
);
exec(&mut e, "CREATE TABLE source (id INT, val VARCHAR(10))");
exec(
&mut e,
"INSERT INTO target VALUES (1, 'a'), (2, 'b'), (3, 'c')",
);
exec(&mut e, "INSERT INTO source VALUES (1, 'x')");
exec(
&mut e,
"MERGE target t USING source s ON t.id = s.id \
WHEN MATCHED THEN UPDATE SET val = s.val \
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET val = 'orphaned'",
);
let r = query(&mut e, "SELECT * FROM target ORDER BY id");
assert_eq!(r.rows.len(), 3);
assert_eq!(r.rows[0][1], Value::VarChar("x".to_string()));
assert_eq!(r.rows[1][1], Value::VarChar("orphaned".to_string()));
assert_eq!(r.rows[2][1], Value::VarChar("orphaned".to_string()));
}
#[test]
fn test_merge_not_matched_by_source_with_condition() {
let mut e = Engine::new();
exec(
&mut e,
"CREATE TABLE target (id INT PRIMARY KEY, val VARCHAR(10))",
);
exec(&mut e, "CREATE TABLE source (id INT, val VARCHAR(10))");
exec(
&mut e,
"INSERT INTO target VALUES (1, 'keep'), (2, 'delete'), (3, 'delete')",
);
exec(&mut e, "INSERT INTO source VALUES (1, 'updated')");
exec(
&mut e,
"MERGE target t USING source s ON t.id = s.id \
WHEN MATCHED THEN UPDATE SET val = s.val \
WHEN NOT MATCHED BY SOURCE AND t.val = 'delete' THEN DELETE",
);
let r = query(&mut e, "SELECT * FROM target ORDER BY id");
assert_eq!(r.rows.len(), 1);
assert_eq!(r.rows[0][0], Value::Int(1));
assert_eq!(r.rows[0][1], Value::VarChar("updated".to_string()));
}
#[test]
fn test_merge_all_three_clauses() {
let mut e = Engine::new();
exec(
&mut e,
"CREATE TABLE target (id INT PRIMARY KEY, val VARCHAR(10))",
);
exec(&mut e, "CREATE TABLE source (id INT, val VARCHAR(10))");
exec(&mut e, "INSERT INTO target VALUES (1, 'old1'), (3, 'old3')");
exec(&mut e, "INSERT INTO source VALUES (1, 'new1'), (2, 'new2')");
exec(
&mut e,
"MERGE target t USING source s ON t.id = s.id \
WHEN MATCHED THEN UPDATE SET val = s.val \
WHEN NOT MATCHED THEN INSERT (id, val) VALUES (s.id, s.val) \
WHEN NOT MATCHED BY SOURCE THEN DELETE",
);
let r = query(&mut e, "SELECT * FROM target ORDER BY id");
assert_eq!(r.rows.len(), 2);
assert_eq!(r.rows[0][0], Value::Int(1));
assert_eq!(r.rows[0][1], Value::VarChar("new1".to_string()));
assert_eq!(r.rows[1][0], Value::Int(2));
assert_eq!(r.rows[1][1], Value::VarChar("new2".to_string()));
}