-
Notifications
You must be signed in to change notification settings - Fork 0
/
migrations.ts
73 lines (62 loc) · 2.2 KB
/
migrations.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { types as T } from "./mod.ts";
import { EmVer } from "./emver-lite/mod.ts";
import { matches } from "./dependencies.ts";
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,
): T.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 } };
};
}