Files
sync-server-v2/source/services/storage/migrate.ts
T
2026-07-27 10:19:13 +00:00

57 lines
1.9 KiB
TypeScript

import { promises as fs } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { FileMigrationProvider, Migrator } from 'kysely/migration';
import type { Database } from './database.ts';
import type { Logger } from '../../utils/logger.ts';
/**
* Applies versioned schema migrations from the on-disk migrations folder.
*/
export class MigrationService {
private readonly debug: Logger;
private readonly migrator: Migrator;
/**
* @param database - Open database whose schema will be migrated.
* @param debug - Root logger extended with a migrations namespace.
*/
constructor(database: Database, debug: Logger) {
// Extend the debug logger to include the migrations namespace.
this.debug = debug.extend('migrations');
// Resolve the migrations directory relative to this module file.
const currentFilePath = fileURLToPath(import.meta.url);
const currentDirectory = path.dirname(currentFilePath);
const migrationsPath = path.join(currentDirectory, 'migrations');
// Create the migrator backed by filesystem migration files.
this.migrator = new Migrator({
db: database.db,
provider: new FileMigrationProvider({
fs,
path,
migrationFolder: migrationsPath,
}),
});
}
/**
* Migrates the database to the latest version.
*
* Throws when any pending migration fails so startup can abort cleanly.
*/
async migrateToLatest(): Promise<void> {
this.debug('migrating database to latest');
const { error } = await this.migrator.migrateToLatest();
if (error) {
const errorInstance = error instanceof Error ? error : new Error(String(error));
this.debug('migration failed: %O', errorInstance);
throw errorInstance;
}
this.debug('database migrations complete');
}
}