mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 02:11:56 +00:00
104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import { types as T } from "./mod.ts";
|
|
import { EmVer } from "./emver-lite/mod.ts";
|
|
import { matches } from "./dependencies.ts";
|
|
import { LegacyExpectedExports as ExpectedExports } from "./types.ts";
|
|
|
|
export class Migration2<Version extends string> {
|
|
version: Version;
|
|
up: (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes>;
|
|
down: (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes>;
|
|
constructor(options: {
|
|
version: Version;
|
|
up: (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes>;
|
|
down: (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes>;
|
|
}) {
|
|
this.version = options.version;
|
|
this.up = options.up;
|
|
this.down = options.down;
|
|
}
|
|
}
|
|
export class MigrationMapping2<Migrations extends Migration2<string>[]> {
|
|
constructor(
|
|
readonly migrations: Migrations,
|
|
) {
|
|
}
|
|
}
|
|
|
|
export type MigrationFn<version extends string, type extends "up" | "down"> = (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes> & { _type: type; _version: version };
|
|
|
|
export function migrationFn<version extends string, type extends "up" | "down">(
|
|
fn: (
|
|
effects: T.Effects,
|
|
) => Promise<T.MigrationRes>,
|
|
): MigrationFn<version, type> {
|
|
return fn as MigrationFn<version, type>;
|
|
}
|
|
|
|
export interface Migration<version extends string> {
|
|
up: MigrationFn<version, "up">;
|
|
down: MigrationFn<version, "down">;
|
|
}
|
|
|
|
export type MigrationMapping<versions extends string> = {
|
|
[version in versions]: Migration<version>;
|
|
};
|
|
|
|
export function fromMapping<versions extends string>(
|
|
migrations: MigrationMapping<versions>,
|
|
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<string>,
|
|
Migration<string>,
|
|
][])
|
|
.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 } };
|
|
};
|
|
}
|