large refactor

This commit is contained in:
hzrd149
2025-03-08 15:52:12 +00:00
parent 5ccfdee953
commit 6a07ce7888
45 changed files with 3085 additions and 770 deletions

94
src/sqlite/migrations.ts Normal file
View File

@@ -0,0 +1,94 @@
import { unixNow } from "applesauce-core/helpers";
import { Database } from "better-sqlite3";
type ScriptFunction = (database: Database, log: (message: string) => void) => Promise<void>;
type MigrationScript = { version: number; migrate: ScriptFunction };
export class MigrationSet {
scripts: MigrationScript[] = [];
name: string;
database?: Database;
setupMigrationTables = true;
constructor(name: string, database?: Database) {
this.database = database;
this.name = name;
}
private ensureMigrations(database: Database | undefined = this.database) {
if (!database) throw new Error("database required");
database
.prepare(
`
CREATE TABLE IF NOT EXISTS "migrations" (
"id" INTEGER NOT NULL,
"name" TEXT NOT NULL,
"version" INTEGER NOT NULL,
"date" INTEGER NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT)
);
`,
)
.run();
database
.prepare(
`
CREATE TABLE IF NOT EXISTS "migration_logs" (
"id" INTEGER NOT NULL,
"migration" INTEGER NOT NULL,
"message" TEXT NOT NULL,
FOREIGN KEY("migration") REFERENCES "migrations",
PRIMARY KEY("id" AUTOINCREMENT)
);
`,
)
.run();
}
addScript(version: number, migrate: ScriptFunction) {
this.scripts.push({ version, migrate });
}
async run(database: Database | undefined = this.database) {
if (!database) throw new Error("database required");
// ensure migration tables are setup
await this.ensureMigrations(database);
const prev = database
.prepare<[string], { name: string; version: number }>(`SELECT * FROM migrations WHERE name=?`)
.all(this.name);
const lastVersion = prev.reduce((v, m) => Math.max(m.version, v), 0);
const sorted = Array.from(this.scripts).sort((a, b) => a.version - b.version);
let version = lastVersion;
for (const script of sorted) {
if (version < script.version) {
let logs: string[] = [];
await database.transaction(() => {
return script.migrate(database, (message) => logs.push(message));
})();
version = script.version;
// save the migration
database.transaction(() => {
const result = database
.prepare<[string, number, number]>(`INSERT INTO migrations (name, version, date) VALUES (?1, ?2, ?3)`)
.run(this.name, script.version, unixNow());
const insertLog = database.prepare<[number | bigint, string]>(
`INSERT INTO migration_logs (migration, message) VALUES (?, ?)`,
);
for (const message of logs) {
insertLog.run(result.lastInsertRowid, message);
}
})();
}
}
}
}