#![cfg(feature = "std")]
use graphitesql::{Connection, Value};
use std::process::Command;
fn temp_path(name: &str) -> String {
let mut p = std::env::temp_dir();
p.push(format!("graphitesql-alter-{}-{name}", std::process::id()));
p.to_string_lossy().into_owned()
}
#[test]
fn add_column_applies_default_to_existing_rows() {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE t(id INTEGER PRIMARY KEY, a TEXT)")
.unwrap();
c.execute("INSERT INTO t(a) VALUES ('x'),('y')").unwrap();
c.execute("ALTER TABLE t ADD COLUMN n INT DEFAULT 42")
.unwrap();
c.execute("ALTER TABLE t ADD COLUMN note TEXT").unwrap();
let r = c.query("SELECT id, a, n, note FROM t ORDER BY id").unwrap();
assert_eq!(r.columns, vec!["id", "a", "n", "note"]);
assert_eq!(r.rows[0][2], Value::Integer(42)); assert_eq!(r.rows[0][3], Value::Null);
c.execute("INSERT INTO t(a, n, note) VALUES ('z', 7, 'hi')")
.unwrap();
let r = c.query("SELECT n, note FROM t WHERE a = 'z'").unwrap();
assert_eq!(r.rows[0][0], Value::Integer(7));
assert_eq!(r.rows[0][1], Value::Text("hi".into()));
}
#[test]
fn rename_column_updates_table_and_index() {
let sqlite = Command::new("sqlite3").arg("--version").output().is_ok();
let path = temp_path("renamecol.db");
let _ = std::fs::remove_file(&path);
let _ = std::fs::remove_file(format!("{path}-journal"));
{
let mut c = Connection::create(&path).unwrap();
c.execute("CREATE TABLE t(id INTEGER PRIMARY KEY, old_name TEXT)")
.unwrap();
c.execute("CREATE INDEX i ON t(old_name)").unwrap();
c.execute("INSERT INTO t(old_name) VALUES ('x'),('y')")
.unwrap();
c.execute("ALTER TABLE t RENAME COLUMN old_name TO new_name")
.unwrap();
assert!(c.query("SELECT old_name FROM t").is_err());
let r = c.query("SELECT new_name FROM t ORDER BY new_name").unwrap();
assert_eq!(r.rows[0][0], Value::Text("x".into()));
assert_eq!(r.rows[1][0], Value::Text("y".into()));
}
if sqlite {
let out = Command::new("sqlite3")
.arg(&path)
.arg("PRAGMA integrity_check; SELECT new_name FROM t ORDER BY new_name;")
.output()
.unwrap();
let s = String::from_utf8_lossy(&out.stdout);
assert!(s.contains("ok"), "integrity: {s}");
assert!(s.contains('x') && s.contains('y'));
}
let _ = std::fs::remove_file(&path);
let _ = std::fs::remove_file(format!("{path}-journal"));
}
#[test]
fn rename_table_updates_catalog_and_indexes() {
let sqlite = Command::new("sqlite3").arg("--version").output().is_ok();
let path = temp_path("rename.db");
let _ = std::fs::remove_file(&path);
let _ = std::fs::remove_file(format!("{path}-journal"));
{
let mut c = Connection::create(&path).unwrap();
c.execute("CREATE TABLE old(id INTEGER PRIMARY KEY, v TEXT)")
.unwrap();
c.execute("CREATE INDEX idx_v ON old(v)").unwrap();
c.execute("INSERT INTO old(v) VALUES ('a'),('b'),('c')")
.unwrap();
c.execute("ALTER TABLE old RENAME TO renamed").unwrap();
assert!(c.schema().table("old").is_none());
assert!(c.schema().table("renamed").is_some());
let r = c.query("SELECT count(*) FROM renamed").unwrap();
assert_eq!(r.rows[0][0], Value::Integer(3));
assert_eq!(c.schema().index("idx_v").unwrap().tbl_name, "renamed");
}
if sqlite {
let out = Command::new("sqlite3")
.arg(&path)
.arg("PRAGMA integrity_check; SELECT count(*) FROM renamed;")
.output()
.unwrap();
let s = String::from_utf8_lossy(&out.stdout);
assert!(s.contains("ok"), "integrity: {s}");
assert!(s.contains('3'));
}
let _ = std::fs::remove_file(&path);
let _ = std::fs::remove_file(format!("{path}-journal"));
}