fix(#2279): idempotent column-guard migrations, drop invalid ADD COLUMN IF NOT EXISTS
This commit is contained in:
parent
c47faf0af9
commit
dfbf198ef3
5 changed files with 188 additions and 121 deletions
|
|
@ -10,6 +10,8 @@ use hive_sh4re::wire_time::now_unix;
|
|||
use hive_sh4re::{Approval, ApprovalKind, ApprovalStatus};
|
||||
use rusqlite::{Connection, OptionalExtension, params};
|
||||
|
||||
use crate::db::Migration;
|
||||
|
||||
const SCHEMA: &str = r"
|
||||
CREATE TABLE IF NOT EXISTS approvals (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
@ -25,20 +27,32 @@ CREATE INDEX IF NOT EXISTS idx_approvals_pending
|
|||
";
|
||||
|
||||
/// Ordered schema migrations tracked in `schema_versions` (key `"approvals"`).
|
||||
/// Legacy databases are detected via the `submitter` column — the last
|
||||
/// column added before versioning was introduced — and fast-forwarded past
|
||||
/// all known migrations. New columns go here as v5, v6, …
|
||||
const MIGRATIONS: &[&str] = &[
|
||||
/// Each migration declares the column it adds, so a legacy DB (fully or
|
||||
/// partially migrated before versioning) converges by skipping the migrations
|
||||
/// whose column already exists. New columns go here as v5, v6, …
|
||||
const MIGRATIONS: &[Migration] = &[
|
||||
// v1: `kind` (pre-Phase-8 dbs): legacy rows default to `apply_commit`.
|
||||
"ALTER TABLE approvals ADD COLUMN IF NOT EXISTS \
|
||||
Migration {
|
||||
sql: "ALTER TABLE approvals ADD COLUMN \
|
||||
kind TEXT NOT NULL DEFAULT 'apply_commit'",
|
||||
adds_column: Some(("approvals", "kind")),
|
||||
},
|
||||
// v2: `description`: manager-supplied note on the dashboard card.
|
||||
"ALTER TABLE approvals ADD COLUMN IF NOT EXISTS description TEXT",
|
||||
Migration {
|
||||
sql: "ALTER TABLE approvals ADD COLUMN description TEXT",
|
||||
adds_column: Some(("approvals", "description")),
|
||||
},
|
||||
// v3: `fetched_sha`: canonical sha hive-c0re resolved at submit time.
|
||||
"ALTER TABLE approvals ADD COLUMN IF NOT EXISTS fetched_sha TEXT",
|
||||
Migration {
|
||||
sql: "ALTER TABLE approvals ADD COLUMN fetched_sha TEXT",
|
||||
adds_column: Some(("approvals", "fetched_sha")),
|
||||
},
|
||||
// v4: `submitter`: authenticated agent that submitted the approval.
|
||||
// Legacy rows are NULL → callers fall back to the root agent.
|
||||
"ALTER TABLE approvals ADD COLUMN IF NOT EXISTS submitter TEXT",
|
||||
Migration {
|
||||
sql: "ALTER TABLE approvals ADD COLUMN submitter TEXT",
|
||||
adds_column: Some(("approvals", "submitter")),
|
||||
},
|
||||
];
|
||||
|
||||
pub struct Approvals {
|
||||
|
|
@ -50,12 +64,7 @@ impl Approvals {
|
|||
let conn = crate::db::open(path, "approvals")?;
|
||||
conn.execute_batch(SCHEMA)
|
||||
.context("apply approvals schema")?;
|
||||
crate::db::apply_versioned_migrations(
|
||||
&conn,
|
||||
"approvals",
|
||||
("approvals", "submitter"),
|
||||
MIGRATIONS,
|
||||
)?;
|
||||
crate::db::apply_versioned_migrations(&conn, "approvals", MIGRATIONS)?;
|
||||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue