import type Database from 'better-sqlite3'; /** Provisioning outcomes remain report inputs even after the policy is removed. */ export function installMetricsProvisioningRevisions(handle: Database.Database) { for (const table of ['server_deployments', 'provisioning_sources']) for (const action of ['INSERT', 'UPDATE', 'DELETE']) { const versions = action === 'INSERT' ? ['NEW'] : action === 'DELETE' ? ['OLD'] : ['OLD', 'NEW']; const fields = ['server', 'action', 'state', 'started_at', 'finished_at']; const condition = table === 'provisioning_sources' ? versions.map((row) => `${row}.kind='autoscaling'`).join(' OR ') : `EXISTS (SELECT 1 FROM provisioning_sources WHERE operation_id=${action === 'DELETE' ? 'OLD' : 'NEW'}.id AND kind='autoscaling')${ action === 'UPDATE' ? ` AND (${fields.map((field) => `OLD.${field} IS NOT NEW.${field}`).join(' OR ')})` : '' }`; handle.exec(`CREATE TRIGGER IF NOT EXISTS report_metrics_${table}_${action} AFTER ${action} ON ${table} WHEN ${condition} BEGIN UPDATE report_revisions SET revision=revision+1 WHERE topic='metrics'; END;`); } } /** Match demand includes active and interrupted matches, independent of leaderboard eligibility. */ export function installMetricsMatchRevisions(handle: Database.Database) { for (const table of ['leaderboard_matches', 'leaderboard_match_players']) for (const action of ['INSERT', 'UPDATE', 'DELETE']) { const fields = table === 'leaderboard_matches' ? ['game', 'map_name', 'started_at'] : ['match_id']; // Score/presence heartbeats do not change distinct participant counts. const condition = action === 'UPDATE' ? `WHEN ${fields.map((field) => `OLD.${field} IS NOT NEW.${field}`).join(' OR ')}` : ''; handle.exec(`CREATE TRIGGER IF NOT EXISTS report_metrics_${table}_${action} AFTER ${action} ON ${table} ${condition} BEGIN UPDATE report_revisions SET revision=revision+1 WHERE topic='metrics'; END;`); } } /** Current policy settings are inputs to historical metrics advice. */ export function installMetricsPolicyRevisions(handle: Database.Database) { for (const table of ['autoscaling_policies', 'settings']) for (const action of ['INSERT', 'UPDATE', 'DELETE']) { const versions = action === 'INSERT' ? ['NEW'] : action === 'DELETE' ? ['OLD'] : ['OLD', 'NEW']; const condition = table === 'settings' ? `WHEN ${versions.map((row) => `${row}.key='autoscaling_paused'`).join(' OR ')}` : ''; handle.exec(`CREATE TRIGGER IF NOT EXISTS report_metrics_${table}_${action} AFTER ${action} ON ${table} ${condition} BEGIN UPDATE report_revisions SET revision=revision+1 WHERE topic='metrics'; END;`); } } export function installReportRevisions(handle: Database.Database) { handle.exec(`CREATE TABLE IF NOT EXISTS report_revisions (topic TEXT PRIMARY KEY, revision INTEGER NOT NULL DEFAULT 0); INSERT OR IGNORE INTO report_revisions(topic) VALUES ('metrics'), ('leaderboard');`); for (const table of ['metric_samples', 'servers']) for (const action of ['INSERT', 'UPDATE', 'DELETE']) { const condition = table === 'servers' && action === 'UPDATE' ? 'WHEN OLD.destroyed_at IS NOT NEW.destroyed_at OR OLD.name IS NOT NEW.name' : ''; handle.exec(`CREATE TRIGGER IF NOT EXISTS report_${table}_${action} AFTER ${action} ON ${table} ${condition} BEGIN UPDATE report_revisions SET revision=revision+1 WHERE topic='metrics'; END;`); } if (handle.prepare("SELECT 1 FROM settings WHERE key='completed_report_revisions_v1'").get()) return; handle.transaction(() => { for (const table of [ 'leaderboard_matches', 'leaderboard_match_players', 'leaderboard_players' ]) { for (const action of ['INSERT', 'UPDATE', 'DELETE']) { const name = `report_${table}_${action}`; const versions = action === 'INSERT' ? ['NEW'] : action === 'DELETE' ? ['OLD'] : ['OLD', 'NEW']; const condition = table === 'leaderboard_matches' ? `WHEN ${versions.map((row) => `${row}.status='completed'`).join(' OR ')}` : table === 'leaderboard_match_players' ? `WHEN ${versions.map((row) => `(SELECT status FROM leaderboard_matches WHERE id=${row}.match_id)='completed'`).join(' OR ')}` : action === 'UPDATE' ? 'WHEN OLD.name IS NOT NEW.name' : ''; const event = table === 'leaderboard_players' && action === 'UPDATE' ? 'UPDATE OF name' : action; handle.exec(`DROP TRIGGER IF EXISTS ${name}; CREATE TRIGGER ${name} AFTER ${event} ON ${table} ${condition} BEGIN UPDATE report_revisions SET revision=revision+1 WHERE topic='leaderboard'; END;`); } } handle.exec("INSERT INTO settings(key,value) VALUES('completed_report_revisions_v1','1')"); })(); }