Auto-migrate any missing servers column, not just recent additions
Legacy cherry.db files created before commit 854f553 lack the game_port
column (it was added via CREATE TABLE which is a no-op on existing
tables). Users upgrading through several versions were left with a
partial schema, and setServerField('game_port', ...) crashed with
"no such column: game_port" — which the worker's generic catch mislabeled
as an RCON send-error in the UI.
Replaces the hardcoded post-v0.1 migration list with an introspection-
based one: PRAGMA table_info(servers), diff against the desired column
set, ADD COLUMN for anything missing. Covers base columns too (komodo_
server, game_port, rcon_host, last_players, last_checked_at) so legacy
DBs from any past version heal themselves on boot.
Verified manually: created a 3-column legacy servers table, booted the
app, all 13 desired columns present after PRAGMA re-check.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+24
-15
@@ -6,24 +6,33 @@ import schemaSql from './schema.sql?raw';
|
|||||||
|
|
||||||
let _db: Database.Database | null = null;
|
let _db: Database.Database | null = null;
|
||||||
|
|
||||||
// Columns that were added to `servers` after v0.1 shipped. Applied on every
|
// Desired shape of the `servers` table. Every column here is added to the
|
||||||
// boot; better-sqlite3 has no `ADD COLUMN IF NOT EXISTS`, so we run each and
|
// table on boot if missing — introspection via PRAGMA table_info handles
|
||||||
// swallow the "duplicate column" error.
|
// both fresh DBs and legacy DBs that predate any given column. CREATE TABLE
|
||||||
const SERVERS_MIGRATIONS: Array<{ column: string; ddl: string }> = [
|
// IF NOT EXISTS in schema.sql is a no-op on existing tables, so it can't
|
||||||
{ column: 'last_map', ddl: 'ALTER TABLE servers ADD COLUMN last_map TEXT' },
|
// backfill columns; this can.
|
||||||
{ column: 'last_gametype', ddl: 'ALTER TABLE servers ADD COLUMN last_gametype TEXT' },
|
const SERVERS_COLUMNS: Array<{ name: string; ddl: string }> = [
|
||||||
{ column: 'last_roster', ddl: 'ALTER TABLE servers ADD COLUMN last_roster TEXT' },
|
// Base columns that shipped in the very first schema stay here for parity
|
||||||
{ column: 'last_seen_at', ddl: 'ALTER TABLE servers ADD COLUMN last_seen_at TEXT' },
|
// with fresh installs — no ALTER is issued if they're already present.
|
||||||
{ column: 'last_error', ddl: 'ALTER TABLE servers ADD COLUMN last_error TEXT' }
|
{ name: 'komodo_server', ddl: 'ALTER TABLE servers ADD COLUMN komodo_server TEXT' },
|
||||||
|
{ name: 'game_port', ddl: 'ALTER TABLE servers ADD COLUMN game_port INTEGER' },
|
||||||
|
{ name: 'rcon_host', ddl: 'ALTER TABLE servers ADD COLUMN rcon_host TEXT' },
|
||||||
|
{ name: 'last_players', ddl: 'ALTER TABLE servers ADD COLUMN last_players INTEGER' },
|
||||||
|
{ name: 'last_checked_at', ddl: 'ALTER TABLE servers ADD COLUMN last_checked_at TEXT' },
|
||||||
|
// Post-v0.1 additions from the perk-a-cola/diagnostics work
|
||||||
|
{ name: 'last_map', ddl: 'ALTER TABLE servers ADD COLUMN last_map TEXT' },
|
||||||
|
{ name: 'last_gametype', ddl: 'ALTER TABLE servers ADD COLUMN last_gametype TEXT' },
|
||||||
|
{ name: 'last_roster', ddl: 'ALTER TABLE servers ADD COLUMN last_roster TEXT' },
|
||||||
|
{ name: 'last_seen_at', ddl: 'ALTER TABLE servers ADD COLUMN last_seen_at TEXT' },
|
||||||
|
{ name: 'last_error', ddl: 'ALTER TABLE servers ADD COLUMN last_error TEXT' }
|
||||||
];
|
];
|
||||||
|
|
||||||
function migrateServers(handle: Database.Database): void {
|
function migrateServers(handle: Database.Database): void {
|
||||||
for (const m of SERVERS_MIGRATIONS) {
|
const rows = handle.prepare('PRAGMA table_info(servers)').all() as Array<{ name: string }>;
|
||||||
try {
|
const existing = new Set(rows.map((r) => r.name));
|
||||||
handle.exec(m.ddl);
|
for (const col of SERVERS_COLUMNS) {
|
||||||
} catch (err) {
|
if (!existing.has(col.name)) {
|
||||||
const msg = (err as Error).message ?? '';
|
handle.exec(col.ddl);
|
||||||
if (!/duplicate column name/i.test(msg)) throw err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user