Files
crowd-funder-from-jason/src/services/migrationService.ts

74 lines
2.5 KiB
TypeScript

interface Migration {
name: string;
sql: string;
}
export class MigrationService {
private static instance: MigrationService;
private migrations: Migration[] = [];
private constructor() {}
static getInstance(): MigrationService {
if (!MigrationService.instance) {
MigrationService.instance = new MigrationService();
}
return MigrationService.instance;
}
registerMigration(migration: Migration) {
this.migrations.push(migration);
}
/**
* @param sqlExec - A function that executes a SQL statement and returns some update result
* @param sqlQuery - A function that executes a SQL query and returns the result in some format
* @param extractMigrationNames - A function that extracts the names (string array) from a "select name from migrations" query
*/
async runMigrations<T>(
// note that this does not take parameters because the Capacitor SQLite 'execute' is different
sqlExec: (sql: string) => Promise<unknown>,
sqlQuery: (sql: string) => Promise<T>,
extractMigrationNames: (result: T) => Set<string>,
): Promise<void> {
// eslint-disable-next-line no-console
console.log("Will run migrations");
// Create migrations table if it doesn't exist
const result0 = await sqlExec(`
CREATE TABLE IF NOT EXISTS migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`);
// eslint-disable-next-line no-console
console.log("Created migrations table", JSON.stringify(result0));
// Get list of executed migrations
const result1: T = await sqlQuery("SELECT name FROM migrations;");
const executedMigrations = extractMigrationNames(result1);
// eslint-disable-next-line no-console
console.log(
"Executed migration select",
JSON.stringify(executedMigrations),
);
// Run pending migrations in order
for (const migration of this.migrations) {
if (!executedMigrations.has(migration.name)) {
const result2 = await sqlExec(migration.sql);
// eslint-disable-next-line no-console
console.log("Executed migration", JSON.stringify(result2));
const result3 = await sqlExec(
`INSERT INTO migrations (name) VALUES ('${migration.name}')`,
);
// eslint-disable-next-line no-console
console.log("Updated migrations table", JSON.stringify(result3));
}
}
}
}
export default MigrationService.getInstance();