import { types as T } from "./index"; import { EmVer } from "./emver-lite/mod"; import * as matches from "ts-matches"; import { LegacyExpectedExports as ExpectedExports } from "./types"; export class Migration2 { version: Version; up: (effects: T.Effects) => Promise; down: (effects: T.Effects) => Promise; constructor(options: { version: Version; up: (effects: T.Effects) => Promise; down: (effects: T.Effects) => Promise; }) { this.version = options.version; this.up = options.up; this.down = options.down; } } export class MigrationMapping2[]> { constructor(readonly migrations: Migrations) {} } export type MigrationFn = ( effects: T.Effects ) => Promise & { _type: type; _version: version }; export function migrationFn( fn: (effects: T.Effects) => Promise ): MigrationFn { return fn as MigrationFn; } export interface Migration { up: MigrationFn; down: MigrationFn; } export type MigrationMapping = { [version in versions]: Migration; }; export function fromMapping( migrations: MigrationMapping, currentVersion: string ): ExpectedExports.migration { const directionShape = matches.literals("from", "to"); return async (effects: T.Effects, version: string, direction?: unknown) => { if (!directionShape.test(direction)) { return { error: 'Must specify arg "from" or "to".' }; } let configured = true; const current = EmVer.parse(currentVersion); const other = EmVer.parse(version); const filteredMigrations = ( Object.entries(migrations) as [ keyof MigrationMapping, Migration ][] ) .map(([version, migration]) => ({ version: EmVer.parse(version), migration, })) .filter( ({ version }) => version.greaterThan(other) && version.lessThanOrEqual(current) ); const migrationsToRun = matches .matches(direction) .when("from", () => filteredMigrations .sort((a, b) => a.version.compareForSort(b.version)) // low to high .map(({ migration }) => migration.up) ) .when("to", () => filteredMigrations .sort((a, b) => b.version.compareForSort(a.version)) // high to low .map(({ migration }) => migration.down) ) .unwrap(); for (const migration of migrationsToRun) { configured = (await migration(effects)).configured && configured; } return { result: { configured } }; }; }