mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 21:26:33 +00:00
fix: proper migration version tracking via user_version PRAGMA
- Migrations now run exactly once per DB lifetime, tracked via SQLite's user_version PRAGMA - Re-runs become no-ops after schema reaches target version - v0.2 also made defensive — skips if template_id already dropped Fixes "no such column: layouts.template_id" on second startup after v0.5 rebuild dropped the legacy columns.
This commit is contained in:
parent
16ab165b06
commit
374a2e091b
2 changed files with 30 additions and 6 deletions
|
|
@ -120,14 +120,29 @@ export class Plugin extends BSBService<InstanceType<typeof Config>, typeof Event
|
||||||
this.db.exec("PRAGMA foreign_keys = ON");
|
this.db.exec("PRAGMA foreign_keys = ON");
|
||||||
this.db.exec("PRAGMA busy_timeout = 10000");
|
this.db.exec("PRAGMA busy_timeout = 10000");
|
||||||
|
|
||||||
obs.log.info("running {n} migrations", { n: MIGRATIONS.length });
|
// Track schema version via SQLite's built-in user_version PRAGMA.
|
||||||
for (const entry of MIGRATIONS) {
|
// Each migration entry runs exactly once across all server boots.
|
||||||
|
const row = this.db.prepare("PRAGMA user_version").get() as { user_version: number };
|
||||||
|
const currentVersion = row.user_version;
|
||||||
|
const targetVersion = MIGRATIONS.length;
|
||||||
|
|
||||||
|
if (currentVersion < targetVersion) {
|
||||||
|
obs.log.info("running migrations from {from} to {to}", {
|
||||||
|
from: currentVersion,
|
||||||
|
to: targetVersion,
|
||||||
|
});
|
||||||
|
for (let i = currentVersion; i < targetVersion; i++) {
|
||||||
|
const entry = MIGRATIONS[i];
|
||||||
if (typeof entry === "string") {
|
if (typeof entry === "string") {
|
||||||
this.db.exec(entry);
|
this.db.exec(entry);
|
||||||
} else {
|
} else if (typeof entry === "function") {
|
||||||
entry(this.db);
|
entry(this.db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.db.exec(`PRAGMA user_version = ${targetVersion}`);
|
||||||
|
} else {
|
||||||
|
obs.log.info("schema up to date (version {v})", { v: currentVersion });
|
||||||
|
}
|
||||||
|
|
||||||
this._repo = new Repository(this.db, async (table, op, id) => {
|
this._repo = new Repository(this.db, async (table, op, id) => {
|
||||||
// Best-effort broadcast — never let a failed event-bus call fail a write.
|
// Best-effort broadcast — never let a failed event-bus call fail a write.
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,15 @@ export const MIGRATIONS: readonly MigrationEntry[] = [
|
||||||
|
|
||||||
// ---- v0.2: flatten layout_templates into layouts, display→kiosk inversion ---
|
// ---- v0.2: flatten layout_templates into layouts, display→kiosk inversion ---
|
||||||
(db: DatabaseSync) => {
|
(db: DatabaseSync) => {
|
||||||
|
// Skip entirely if v0.5 rebuild already dropped template_id (idempotent re-run)
|
||||||
|
const cols = db.prepare(`PRAGMA table_info("layouts")`).all() as Array<{ name: string }>;
|
||||||
|
const hasTemplateId = cols.some((c) => c.name === "template_id");
|
||||||
|
if (!hasTemplateId) {
|
||||||
|
// Just ensure displays.kiosk_id exists for fresh-but-post-v0.5 DBs
|
||||||
|
addColumnIfNotExists(db, "displays", "kiosk_id", "INTEGER REFERENCES kiosks(id) ON DELETE SET NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
addColumnIfNotExists(db, "layouts", "regions", "TEXT NOT NULL DEFAULT '[]'");
|
addColumnIfNotExists(db, "layouts", "regions", "TEXT NOT NULL DEFAULT '[]'");
|
||||||
addColumnIfNotExists(db, "layouts", "grid_cols", "INTEGER NOT NULL DEFAULT 1");
|
addColumnIfNotExists(db, "layouts", "grid_cols", "INTEGER NOT NULL DEFAULT 1");
|
||||||
addColumnIfNotExists(db, "layouts", "grid_rows", "INTEGER NOT NULL DEFAULT 1");
|
addColumnIfNotExists(db, "layouts", "grid_rows", "INTEGER NOT NULL DEFAULT 1");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue