Files
MultiRoombaRover/server/src/configuration/migrations.js
T

70 lines
2.2 KiB
JavaScript

// Configuration Database Migrations
// Purpose: Applies ordered, transactional schema changes to the configuration and administration database.
// Scope: Owns database structure only; configuration-document evolution belongs to the ordered definition and validation.
const migrations = [
{
version: 1,
sql: `
CREATE TABLE configuration_revisions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
config_json TEXT NOT NULL,
created_at INTEGER NOT NULL,
actor TEXT NOT NULL,
source TEXT NOT NULL
);
CREATE TABLE configuration_state (
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
active_revision_id INTEGER NOT NULL REFERENCES configuration_revisions(id)
);
CREATE TABLE administrators (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL COLLATE NOCASE UNIQUE,
password_hash TEXT NOT NULL,
discord_id TEXT,
role TEXT NOT NULL CHECK (role IN ('admin', 'lockdown')),
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE administrative_audit_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at INTEGER NOT NULL,
actor TEXT NOT NULL,
action TEXT NOT NULL,
details_json TEXT NOT NULL
);
`,
},
];
function applySchemaMigrations(db) {
db.exec(`
CREATE TABLE IF NOT EXISTS schema_migrations (
version INTEGER PRIMARY KEY,
applied_at INTEGER NOT NULL
);
`);
const applied = new Set(db.prepare('SELECT version FROM schema_migrations').all().map((row) => Number(row.version)));
const record = db.prepare('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)');
migrations.forEach((migration) => {
if (applied.has(migration.version)) return;
/*
Schema SQL and its version marker are one transaction. A process failure
can therefore retry the migration cleanly instead of finding a partially
changed database whose version incorrectly appears current.
*/
db.transaction(() => {
db.exec(migration.sql);
record.run(migration.version, Date.now());
})();
});
}
module.exports = {
migrations,
applySchemaMigrations,
};