use stoolap::Database;
#[test]
fn test_conflict_target_rejects_wrong_column() {
let db = Database::open("memory://conflict_target_wrong").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
let result = db.execute(
"INSERT INTO t VALUES (2, 10, 'y') ON CONFLICT (a) DO UPDATE SET v = 'updated'",
(),
);
assert!(
result.is_err(),
"Should error when conflict is on b but target is (a)"
);
let rows: Vec<_> = db
.query("SELECT a, b, v FROM t ORDER BY a", ())
.unwrap()
.map(|r| {
let r = r.unwrap();
(
r.get::<i64>(0).unwrap(),
r.get::<i64>(1).unwrap(),
r.get::<String>(2).unwrap(),
)
})
.collect();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0], (1, 10, "x".to_string()));
}
#[test]
fn test_conflict_target_matches_correct_column() {
let db = Database::open("memory://conflict_target_match").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
db.execute(
"INSERT INTO t VALUES (1, 20, 'y') ON CONFLICT (a) DO UPDATE SET v = 'updated'",
(),
)
.unwrap();
let v: String = db
.query("SELECT v FROM t", ())
.unwrap()
.next()
.unwrap()
.unwrap()
.get(0)
.unwrap();
assert_eq!(v, "updated");
}
#[test]
fn test_do_nothing_target_rejects_wrong_column() {
let db = Database::open("memory://do_nothing_target_wrong").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
let result = db.execute(
"INSERT INTO t VALUES (2, 10, 'y') ON CONFLICT (a) DO NOTHING",
(),
);
assert!(
result.is_err(),
"Should error when conflict is on b but target is (a)"
);
}
#[test]
fn test_do_nothing_target_skips_matching_conflict() {
let db = Database::open("memory://do_nothing_target_match").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
db.execute(
"INSERT INTO t VALUES (1, 99, 'y') ON CONFLICT (a) DO NOTHING",
(),
)
.unwrap();
let count: i64 = db
.query("SELECT COUNT(*) FROM t", ())
.unwrap()
.next()
.unwrap()
.unwrap()
.get(0)
.unwrap();
assert_eq!(count, 1);
}
#[test]
fn test_empty_conflict_target_matches_all() {
let db = Database::open("memory://empty_conflict_target").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
db.execute(
"INSERT INTO t VALUES (1, 20, 'y') ON DUPLICATE KEY UPDATE v = 'updated'",
(),
)
.unwrap();
let v: String = db
.query("SELECT v FROM t", ())
.unwrap()
.next()
.unwrap()
.unwrap()
.get(0)
.unwrap();
assert_eq!(v, "updated");
}
#[test]
fn test_conflict_target_pk() {
let db = Database::open("memory://conflict_target_pk").unwrap();
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
db.execute(
"INSERT INTO t VALUES (1, 20, 'y') ON CONFLICT (id) DO UPDATE SET v = 'updated'",
(),
)
.unwrap();
let v: String = db
.query("SELECT v FROM t WHERE id = 1", ())
.unwrap()
.next()
.unwrap()
.unwrap()
.get(0)
.unwrap();
assert_eq!(v, "updated");
}
#[test]
fn test_conflict_target_pk_wrong_target() {
let db = Database::open("memory://conflict_target_pk_wrong").unwrap();
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
let result = db.execute(
"INSERT INTO t VALUES (1, 20, 'y') ON CONFLICT (a) DO UPDATE SET v = 'updated'",
(),
);
assert!(
result.is_err(),
"Should error when PK conflict but target is (a)"
);
}
#[test]
fn test_conflict_target_insert_select() {
let db = Database::open("memory://conflict_target_insert_select").unwrap();
db.execute(
"CREATE TABLE t (a INTEGER UNIQUE, b INTEGER UNIQUE, v TEXT)",
(),
)
.unwrap();
db.execute("CREATE TABLE src (a INTEGER, b INTEGER, v TEXT)", ())
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10, 'x')", ()).unwrap();
db.execute("INSERT INTO src VALUES (2, 10, 'y')", ())
.unwrap();
let result = db.execute(
"INSERT INTO t SELECT * FROM src ON CONFLICT (a) DO UPDATE SET v = 'updated'",
(),
);
assert!(
result.is_err(),
"INSERT...SELECT should error when conflict is on b but target is (a)"
);
}