import { NonNegativeInteger } from "type-fest"; import { MigrationHelper } from "./migration-helper"; export const IRREVERSIBLE = new Error("Irreversible migration"); export type VersionFrom = T extends Migrator ? TFrom extends NonNegativeInteger ? TFrom : never : never; export type VersionTo = T extends Migrator ? TTo extends NonNegativeInteger ? TTo : never : never; export type Direction = "up" | "down"; export abstract class Migrator { constructor( public fromVersion: TFrom, public toVersion: TTo, ) { if (fromVersion == null || toVersion == null) { throw new Error("Invalid migration"); } if (fromVersion > toVersion) { throw new Error("Invalid migration"); } } shouldMigrate(helper: MigrationHelper, direction: Direction): Promise { const startVersion = direction === "up" ? this.fromVersion : this.toVersion; return Promise.resolve(helper.currentVersion === startVersion); } abstract migrate(helper: MigrationHelper): Promise; abstract rollback(helper: MigrationHelper): Promise; async updateVersion(helper: MigrationHelper, direction: Direction): Promise { const endVersion = direction === "up" ? this.toVersion : this.fromVersion; helper.currentVersion = endVersion; await helper.set("stateVersion", endVersion); } }