okmodel 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -1
- package/dist/adapters/capabilities.d.ts +62 -0
- package/dist/adapters/error.d.ts +91 -0
- package/dist/adapters/failure.d.ts +39 -0
- package/dist/adapters/pg/batch.d.ts +36 -0
- package/dist/adapters/pg/call.d.ts +59 -0
- package/dist/adapters/pg/pglite.d.ts +21 -0
- package/dist/adapters/pg/postgres-extra.d.ts +43 -0
- package/dist/adapters/pg/postgresjs.d.ts +95 -0
- package/dist/adapters/pg/result.d.ts +30 -0
- package/dist/contracts/catalog/build.d.ts +18 -0
- package/dist/contracts/catalog/document.d.ts +79 -0
- package/dist/contracts/catalog/enum.d.ts +35 -0
- package/dist/contracts/catalog/identifier.d.ts +71 -0
- package/dist/contracts/catalog/identity.d.ts +98 -0
- package/dist/contracts/catalog/index.d.ts +11 -0
- package/dist/contracts/catalog/json.d.ts +17 -0
- package/dist/contracts/catalog/object.d.ts +142 -0
- package/dist/contracts/catalog/order.d.ts +43 -0
- package/dist/contracts/catalog/rewrite.d.ts +18 -0
- package/dist/contracts/catalog/types.d.ts +292 -0
- package/dist/contracts/catalog/words.d.ts +13 -0
- package/dist/contracts/connection.d.ts +33 -0
- package/dist/contracts/driver.d.ts +163 -0
- package/dist/contracts/error.d.ts +298 -0
- package/dist/contracts/index.d.ts +11 -0
- package/dist/contracts/index.js +16 -0
- package/dist/contracts/internal.d.ts +15 -0
- package/dist/contracts/internal.js +68 -0
- package/dist/contracts/nearest.d.ts +15 -0
- package/dist/contracts/rows.d.ts +84 -0
- package/dist/contracts/sha256.d.ts +14 -0
- package/dist/contracts/utf8.d.ts +33 -0
- package/dist/dialects/pg/array-literal.d.ts +25 -0
- package/dist/dialects/pg/bool.d.ts +46 -0
- package/dist/dialects/pg/column.d.ts +386 -0
- package/dist/dialects/pg/compile.d.ts +81 -0
- package/dist/dialects/pg/custom.d.ts +21 -0
- package/dist/dialects/pg/ddl.d.ts +70 -0
- package/dist/dialects/pg/decimal.d.ts +62 -0
- package/dist/dialects/pg/declarations.d.ts +34 -0
- package/dist/dialects/pg/emit.d.ts +18 -0
- package/dist/dialects/pg/enum.d.ts +30 -0
- package/dist/dialects/pg/errors.d.ts +30 -0
- package/dist/dialects/pg/finite.d.ts +15 -0
- package/dist/dialects/pg/geometry.d.ts +55 -0
- package/dist/dialects/pg/index.d.ts +45 -0
- package/dist/dialects/pg/index.js +1821 -0
- package/dist/dialects/pg/integer.d.ts +96 -0
- package/dist/dialects/pg/introspect.d.ts +43 -0
- package/dist/dialects/pg/json.d.ts +43 -0
- package/dist/dialects/pg/keys.d.ts +32 -0
- package/dist/dialects/pg/misuse.d.ts +31 -0
- package/dist/dialects/pg/model.d.ts +71 -0
- package/dist/dialects/pg/namespace.d.ts +63 -0
- package/dist/dialects/pg/network.d.ts +28 -0
- package/dist/dialects/pg/operators.d.ts +71 -0
- package/dist/dialects/pg/ops/between.d.ts +10 -0
- package/dist/dialects/pg/ops/contains.d.ts +8 -0
- package/dist/dialects/pg/ops/endsWith.d.ts +8 -0
- package/dist/dialects/pg/ops/eq.d.ts +9 -0
- package/dist/dialects/pg/ops/every.d.ts +9 -0
- package/dist/dialects/pg/ops/gt.d.ts +9 -0
- package/dist/dialects/pg/ops/gte.d.ts +9 -0
- package/dist/dialects/pg/ops/has.d.ts +9 -0
- package/dist/dialects/pg/ops/ilike.d.ts +8 -0
- package/dist/dialects/pg/ops/inList.d.ts +9 -0
- package/dist/dialects/pg/ops/inc.d.ts +13 -0
- package/dist/dialects/pg/ops/like.d.ts +8 -0
- package/dist/dialects/pg/ops/lt.d.ts +9 -0
- package/dist/dialects/pg/ops/lte.d.ts +9 -0
- package/dist/dialects/pg/ops/none.d.ts +9 -0
- package/dist/dialects/pg/ops/not.d.ts +9 -0
- package/dist/dialects/pg/ops/notIn.d.ts +9 -0
- package/dist/dialects/pg/ops/or.d.ts +9 -0
- package/dist/dialects/pg/ops/startsWith.d.ts +8 -0
- package/dist/dialects/pg/quote.d.ts +24 -0
- package/dist/dialects/pg/range.d.ts +50 -0
- package/dist/dialects/pg/relations.d.ts +45 -0
- package/dist/dialects/pg/schema.d.ts +77 -0
- package/dist/dialects/pg/search.d.ts +23 -0
- package/dist/dialects/pg/table.d.ts +201 -0
- package/dist/dialects/pg/temporal.d.ts +211 -0
- package/dist/dialects/pg/text.d.ts +44 -0
- package/dist/dialects/pg/time.d.ts +46 -0
- package/dist/okm.js +2 -0
- package/dist/okmodel.js +2 -0
- package/dist/runtime/client.d.ts +47 -0
- package/dist/runtime/conflict.d.ts +38 -0
- package/dist/runtime/drift-detail.d.ts +32 -0
- package/dist/runtime/drift.d.ts +29 -0
- package/dist/runtime/include.d.ts +15 -0
- package/dist/runtime/pg/pglite.d.ts +25 -0
- package/dist/runtime/pg/pglite.js +48 -0
- package/dist/runtime/pg/postgresjs.d.ts +29 -0
- package/dist/runtime/pg/postgresjs.js +62 -0
- package/dist/runtime/plan.d.ts +167 -0
- package/dist/runtime/tx.d.ts +29 -0
- package/dist/runtime/types.d.ts +369 -0
- package/dist/runtime/write.d.ts +48 -0
- package/dist/shared/4j72449d.js +37 -0
- package/dist/shared/79ggp945.js +148 -0
- package/dist/shared/7ck0dtry.js +259 -0
- package/dist/shared/8b04d28c.js +14 -0
- package/dist/shared/ax16zpvm.js +171 -0
- package/dist/shared/ckb1p0a4.js +566 -0
- package/dist/shared/cn0n68ft.js +16 -0
- package/dist/shared/dynq16vb.js +81 -0
- package/dist/shared/f5thc1s0.js +1050 -0
- package/dist/shared/fgqgsb5z.js +281 -0
- package/dist/shared/g2v6gnc8.js +347 -0
- package/dist/shared/g5fhqmwe.js +188 -0
- package/dist/shared/gk7cs7sp.js +566 -0
- package/dist/shared/hd293j9g.js +98 -0
- package/dist/shared/j5cn2963.js +701 -0
- package/dist/shared/kynx7vbm.js +1490 -0
- package/dist/shared/mkjmqjv4.js +456 -0
- package/dist/shared/mtkwv8wx.js +18 -0
- package/dist/shared/ngk8gj61.js +40 -0
- package/dist/shared/p0cbr3g2.js +79 -0
- package/dist/shared/px90pf9p.js +396 -0
- package/dist/shared/qk3hxfja.js +83 -0
- package/dist/shared/tb4ze1tr.js +119 -0
- package/dist/shared/vkm3q4x1.js +30 -0
- package/dist/shared/w8samvk1.js +18 -0
- package/dist/shared/xy79j5hq.js +177 -0
- package/dist/shared/y9m15dfv.js +888 -0
- package/dist/shared/ycwz42az.js +412 -0
- package/dist/shared/zhc5vmgf.js +257 -0
- package/dist/tooling/cli.d.ts +1 -0
- package/dist/tooling/cli.js +193 -0
- package/dist/tooling/errors/registry.d.ts +33 -0
- package/dist/tooling/migrate/apply.d.ts +86 -0
- package/dist/tooling/migrate/commands.d.ts +21 -0
- package/dist/tooling/migrate/config.d.ts +48 -0
- package/dist/tooling/migrate/dev.d.ts +16 -0
- package/dist/tooling/migrate/equal.d.ts +15 -0
- package/dist/tooling/migrate/files.d.ts +19 -0
- package/dist/tooling/migrate/index.d.ts +7 -0
- package/dist/tooling/migrate/index.js +7 -0
- package/dist/tooling/migrate/plan.d.ts +76 -0
- package/dist/tooling/migrate/policy.d.ts +78 -0
- package/dist/tooling/migrate/project.d.ts +69 -0
- package/dist/tooling/migrate/status.d.ts +74 -0
- package/dist/tooling/migrate/values.d.ts +29 -0
- package/package.json +94 -7
- package/dist/index.js +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import"../shared/y9m15dfv.js";
|
|
2
|
+
import {
|
|
3
|
+
formatPlan,
|
|
4
|
+
buildProject,
|
|
5
|
+
generateProject,
|
|
6
|
+
planProject,
|
|
7
|
+
checkProject
|
|
8
|
+
} from "../shared/kynx7vbm.js";
|
|
9
|
+
import {
|
|
10
|
+
OkmError2
|
|
11
|
+
} from "../shared/ycwz42az.js";
|
|
12
|
+
|
|
13
|
+
// src/tooling/cli.ts
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
// src/tooling/migrate/commands.ts
|
|
19
|
+
async function run(argv, io) {
|
|
20
|
+
const cwd = io?.cwd ?? process.cwd();
|
|
21
|
+
const stdout = io?.stdout ?? ((text) => process.stdout.write(text));
|
|
22
|
+
const [command, ...rest] = argv;
|
|
23
|
+
if (command === "build") {
|
|
24
|
+
const directory = await buildProject(cwd);
|
|
25
|
+
stdout(`${directory}
|
|
26
|
+
`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (command === "check") {
|
|
30
|
+
await checkProject(cwd);
|
|
31
|
+
stdout(`ok
|
|
32
|
+
`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (command === "generate") {
|
|
36
|
+
const parsed = splitFlags(rest);
|
|
37
|
+
const path = await generateProject(cwd, parsed.name ?? "migration", parsed.flags);
|
|
38
|
+
stdout(path === undefined ? `no changes
|
|
39
|
+
` : `${path}
|
|
40
|
+
`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (command === "dev") {
|
|
44
|
+
const { devProject } = await import("../shared/vkm3q4x1.js");
|
|
45
|
+
stdout(await devProject(cwd));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (command === "push") {
|
|
49
|
+
const { pushProject } = await import("../shared/g2v6gnc8.js");
|
|
50
|
+
stdout(await pushProject(cwd, invoke(splitFlags(rest))));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (command === "migrate") {
|
|
54
|
+
const sub = rest[0];
|
|
55
|
+
const parsed = splitFlags(rest.slice(1));
|
|
56
|
+
if (sub === "plan") {
|
|
57
|
+
if (parsed.name === undefined) {
|
|
58
|
+
throw new OkmError2("invalid", "okm migrate plan needs a name.");
|
|
59
|
+
}
|
|
60
|
+
stdout(formatPlan(await planProject(cwd, parsed.name, parsed.flags)));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (sub === "apply") {
|
|
64
|
+
const { applyProject } = await import("../shared/g2v6gnc8.js");
|
|
65
|
+
stdout(await applyProject(cwd, invoke(parsed)));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (sub === "status") {
|
|
69
|
+
const { statusProject } = await import("../shared/ax16zpvm.js");
|
|
70
|
+
stdout(await statusProject(cwd, invoke(parsed)));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new OkmError2("invalid", `Unknown command ${command ?? ""}.`);
|
|
75
|
+
}
|
|
76
|
+
function invoke(parsed) {
|
|
77
|
+
return {
|
|
78
|
+
...parsed.target !== undefined ? { target: parsed.target } : {},
|
|
79
|
+
allowProtected: parsed.allowProtected,
|
|
80
|
+
allowPooler: parsed.allowPooler,
|
|
81
|
+
...parsed.lockTimeoutMs !== undefined ? { lockTimeoutMs: parsed.lockTimeoutMs } : {},
|
|
82
|
+
...parsed.statementTimeoutMs !== undefined ? { statementTimeoutMs: parsed.statementTimeoutMs } : {}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function splitFlags(args) {
|
|
86
|
+
const flags = [];
|
|
87
|
+
const positionals = [];
|
|
88
|
+
let target;
|
|
89
|
+
let allowProtected = false;
|
|
90
|
+
let allowPooler = false;
|
|
91
|
+
let lockTimeoutMs;
|
|
92
|
+
let statementTimeoutMs;
|
|
93
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
94
|
+
const arg = args[index] ?? "";
|
|
95
|
+
if (arg === "--replace") {
|
|
96
|
+
const value = args[index + 1];
|
|
97
|
+
if (value === undefined) {
|
|
98
|
+
throw new OkmError2("OKM1541", "--replace needs table.column.old=new.", {
|
|
99
|
+
fix: { summary: "Pass --replace <table>.<column>.<old>=<new>." }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
flags.push(value);
|
|
103
|
+
index += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (arg.startsWith("--replace=")) {
|
|
107
|
+
flags.push(arg.slice("--replace=".length));
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (arg === "--allow-protected") {
|
|
111
|
+
allowProtected = true;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (arg === "--allow-pooler") {
|
|
115
|
+
allowPooler = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "--target") {
|
|
119
|
+
const value = args[index + 1];
|
|
120
|
+
if (value === undefined || value.startsWith("--")) {
|
|
121
|
+
throw new OkmError2("OKM1853", "--target needs a name.", {
|
|
122
|
+
fix: { summary: "Pass --target <name>." }
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
target = value;
|
|
126
|
+
index += 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (arg.startsWith("--target=")) {
|
|
130
|
+
target = arg.slice("--target=".length);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (arg === "--lock-timeout" || arg === "--statement-timeout") {
|
|
134
|
+
const value = numberFlag(arg, args[index + 1]);
|
|
135
|
+
if (arg === "--lock-timeout")
|
|
136
|
+
lockTimeoutMs = value;
|
|
137
|
+
else
|
|
138
|
+
statementTimeoutMs = value;
|
|
139
|
+
index += 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
positionals.push(arg);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
name: positionals[0],
|
|
146
|
+
flags,
|
|
147
|
+
target,
|
|
148
|
+
allowProtected,
|
|
149
|
+
allowPooler,
|
|
150
|
+
lockTimeoutMs,
|
|
151
|
+
statementTimeoutMs
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function numberFlag(flag, value) {
|
|
155
|
+
const parsed = value === undefined ? Number.NaN : Number(value);
|
|
156
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
157
|
+
throw new OkmError2("invalid", `${flag} needs a number of milliseconds.`, {
|
|
158
|
+
fix: { summary: `Pass ${flag} <milliseconds>.` }
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return parsed;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/tooling/cli.ts
|
|
165
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
166
|
+
var packageJsonPath = join(here, "..", "..", "package.json");
|
|
167
|
+
if (process.argv.includes("--version")) {
|
|
168
|
+
process.stdout.write(`${readPackageVersion(packageJsonPath)}
|
|
169
|
+
`);
|
|
170
|
+
} else if (process.argv.length > 2) {
|
|
171
|
+
try {
|
|
172
|
+
await run(process.argv.slice(2));
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (error instanceof OkmError2) {
|
|
175
|
+
process.stderr.write(`${error.code}: ${error.message}
|
|
176
|
+
${error.fix.summary}
|
|
177
|
+
`);
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
} else {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function readPackageVersion(path) {
|
|
185
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
186
|
+
if (!isRecord(parsed) || typeof parsed.version !== "string") {
|
|
187
|
+
throw new Error(`No string version in ${path}`);
|
|
188
|
+
}
|
|
189
|
+
return parsed.version;
|
|
190
|
+
}
|
|
191
|
+
function isRecord(value) {
|
|
192
|
+
return typeof value === "object" && value !== null;
|
|
193
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor text for every OKM code in spec §21.
|
|
3
|
+
*
|
|
4
|
+
* This module is not on the runtime entry. A process that never explains a
|
|
5
|
+
* code does not load it. Titles stay short. The summary and the fix are the
|
|
6
|
+
* page `okm doctor <code>` will print.
|
|
7
|
+
*/
|
|
8
|
+
/** One code in the error registry. */
|
|
9
|
+
export type ErrorDoc = {
|
|
10
|
+
/** Spec code, for example `OKM1020`. */
|
|
11
|
+
readonly code: string;
|
|
12
|
+
/** Short name. */
|
|
13
|
+
readonly title: string;
|
|
14
|
+
/** What went wrong. */
|
|
15
|
+
readonly summary: string;
|
|
16
|
+
/** What to do. */
|
|
17
|
+
readonly fix: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Every OKM code spec §21 names, in numeric order.
|
|
21
|
+
*
|
|
22
|
+
* OKM1111 is a dynamic call the driver's capabilities do not allow.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ERROR_DOCS: readonly ErrorDoc[];
|
|
25
|
+
/**
|
|
26
|
+
* Looks up one code.
|
|
27
|
+
*
|
|
28
|
+
* The map is built on the first call, not at import.
|
|
29
|
+
*
|
|
30
|
+
* @param code - Spec code, for example `OKM1401`
|
|
31
|
+
* @returns The doctor entry, or `undefined` when the code is not in spec §21
|
|
32
|
+
*/
|
|
33
|
+
export declare function errorDoc(code: string): ErrorDoc | undefined;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applies migrations on one target.
|
|
3
|
+
*
|
|
4
|
+
* A run holds a session advisory lock. Transactional steps of one migration
|
|
5
|
+
* share a transaction. Steps Postgres cannot run there (`CREATE INDEX
|
|
6
|
+
* CONCURRENTLY`, `ADD VALUE`, `VACUUM`) are their own steps. Each finished
|
|
7
|
+
* step is a history row. A later apply skips those rows.
|
|
8
|
+
*/
|
|
9
|
+
import { type PlanStep } from "./plan.js";
|
|
10
|
+
import type { StoredMigration } from "./files.js";
|
|
11
|
+
import { type InvokeFlags } from "./policy.js";
|
|
12
|
+
/** One step with its index in the migration file. */
|
|
13
|
+
export type IndexedStep = {
|
|
14
|
+
readonly index: number;
|
|
15
|
+
readonly step: PlanStep;
|
|
16
|
+
};
|
|
17
|
+
/** Steps that commit together, or one step that cannot. */
|
|
18
|
+
export type ApplyUnit = {
|
|
19
|
+
readonly migrationId: string;
|
|
20
|
+
readonly catalogHash: string;
|
|
21
|
+
/** True when this unit is the last step of its migration. */
|
|
22
|
+
readonly finishes: boolean;
|
|
23
|
+
readonly transactional: boolean;
|
|
24
|
+
readonly steps: readonly IndexedStep[];
|
|
25
|
+
};
|
|
26
|
+
/** What {@link applyTarget} needs. The URL is resolved by the caller. */
|
|
27
|
+
export type ApplyRequest = {
|
|
28
|
+
readonly url: string;
|
|
29
|
+
readonly target: string;
|
|
30
|
+
readonly protected: boolean;
|
|
31
|
+
readonly allowProtected?: boolean;
|
|
32
|
+
readonly allowPooler?: boolean;
|
|
33
|
+
readonly searchPath?: string;
|
|
34
|
+
readonly lockTimeoutMs?: number;
|
|
35
|
+
readonly statementTimeoutMs?: number;
|
|
36
|
+
readonly retries?: number;
|
|
37
|
+
readonly migrations: readonly StoredMigration[];
|
|
38
|
+
/** Runs after the advisory lock is held and before the first step. */
|
|
39
|
+
readonly onLocked?: () => void;
|
|
40
|
+
};
|
|
41
|
+
/** Migrations that ran at least one step in this invocation. */
|
|
42
|
+
export type ApplyReport = {
|
|
43
|
+
readonly target: string;
|
|
44
|
+
readonly applied: readonly string[];
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Groups pending steps into the transactions apply will run.
|
|
48
|
+
*
|
|
49
|
+
* A step Postgres cannot run inside a transaction is its own unit even when
|
|
50
|
+
* the plan marked it transactional.
|
|
51
|
+
*
|
|
52
|
+
* @param migration - One file
|
|
53
|
+
* @param done - Keys `${migrationId}:${stepIndex}` already in history
|
|
54
|
+
* @returns Units in apply order
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyUnits(migration: StoredMigration, done: ReadonlySet<string>): readonly ApplyUnit[];
|
|
57
|
+
/**
|
|
58
|
+
* Applies pending migrations on one target.
|
|
59
|
+
*
|
|
60
|
+
* The connection is reserved for the whole run so the advisory lock stays
|
|
61
|
+
* session-scoped. Lock timeout retries that step. Any other failure stops
|
|
62
|
+
* at that step.
|
|
63
|
+
*
|
|
64
|
+
* @param request - Target, flags, and the migrations to consider
|
|
65
|
+
* @returns The target and the migration ids that ran
|
|
66
|
+
*/
|
|
67
|
+
export declare function applyTarget(request: ApplyRequest): Promise<ApplyReport>;
|
|
68
|
+
/**
|
|
69
|
+
* Applies the migrations in the project to the selected target.
|
|
70
|
+
*
|
|
71
|
+
* @param cwd - Project directory
|
|
72
|
+
* @param flags - `--target`, protection, pooler, and timeouts
|
|
73
|
+
* @returns Text for stdout, including the target name
|
|
74
|
+
*/
|
|
75
|
+
export declare function applyProject(cwd: string, flags: InvokeFlags): Promise<string>;
|
|
76
|
+
/**
|
|
77
|
+
* Prototype sync. Blocked on a protected target.
|
|
78
|
+
*
|
|
79
|
+
* A target named production is not special. Protection is the `protected`
|
|
80
|
+
* flag (spec §19.8). The plan's statements run as one migration.
|
|
81
|
+
*
|
|
82
|
+
* @param cwd - Project directory
|
|
83
|
+
* @param flags - Target and protection flags
|
|
84
|
+
* @returns Text for stdout
|
|
85
|
+
*/
|
|
86
|
+
export declare function pushProject(cwd: string, flags: InvokeFlags): Promise<string>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm` command dispatch.
|
|
3
|
+
*
|
|
4
|
+
* The bin wrapper imports {@link run}. Importing this module does not parse
|
|
5
|
+
* `process.argv`.
|
|
6
|
+
*/
|
|
7
|
+
/** Where a command reads the project and writes its text. */
|
|
8
|
+
export type CommandIo = {
|
|
9
|
+
readonly cwd?: string;
|
|
10
|
+
readonly stdout?: (text: string) => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Runs one `okm` invocation.
|
|
14
|
+
*
|
|
15
|
+
* `--version` stays in the bin. This function handles `build`, `check`,
|
|
16
|
+
* `generate`, `dev`, `push`, and `migrate plan`, `apply`, and `status`.
|
|
17
|
+
*
|
|
18
|
+
* @param argv - Arguments after the program name
|
|
19
|
+
* @param io - Working directory and stdout. Defaults to the process
|
|
20
|
+
*/
|
|
21
|
+
export declare function run(argv: readonly string[], io?: CommandIo): Promise<void>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project configuration for `okm`.
|
|
3
|
+
*
|
|
4
|
+
* Exported from `okmodel/migrate`. The runtime entry stays free of tooling.
|
|
5
|
+
*/
|
|
6
|
+
/** One migration target. A string is the URL. Protection defaults to false. */
|
|
7
|
+
export type TargetInput = string | {
|
|
8
|
+
readonly url?: string;
|
|
9
|
+
/** Refuses contract, push, and other non-expand work unless `--allow-protected`. */
|
|
10
|
+
readonly protected?: boolean;
|
|
11
|
+
};
|
|
12
|
+
/** Paths and targets `okm` reads. */
|
|
13
|
+
export type MigrateConfig = {
|
|
14
|
+
/** Module that exports the built schema. */
|
|
15
|
+
readonly schema: string;
|
|
16
|
+
/** Directory of table files. `okm check` reports one that the schema does not import. */
|
|
17
|
+
readonly tables?: string;
|
|
18
|
+
/** Directory of generated SQL. Defaults to `migrations`. */
|
|
19
|
+
readonly migrations?: string;
|
|
20
|
+
/** Build output. Defaults to `.okm`. */
|
|
21
|
+
readonly out?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The one target named `default`.
|
|
24
|
+
*
|
|
25
|
+
* A direct Postgres URL, not a pooler. Use {@link MigrateConfig.targets} when
|
|
26
|
+
* there is more than one.
|
|
27
|
+
*/
|
|
28
|
+
readonly database?: TargetInput;
|
|
29
|
+
/** Named targets. Replaces `database`. */
|
|
30
|
+
readonly targets?: Readonly<Record<string, TargetInput>>;
|
|
31
|
+
/** Apply against a known pooler URL. The default refuses those hosts. */
|
|
32
|
+
readonly allowPooler?: boolean;
|
|
33
|
+
/** Milliseconds for `lock_timeout` and `statement_timeout` during apply. */
|
|
34
|
+
readonly timeouts?: {
|
|
35
|
+
readonly lock?: number;
|
|
36
|
+
readonly statement?: number;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Returns the config unchanged.
|
|
41
|
+
*
|
|
42
|
+
* `database` is one target named `default`. `targets` is the named map.
|
|
43
|
+
* Commands that touch a database require `--target` when several exist.
|
|
44
|
+
*
|
|
45
|
+
* @param config - Schema module, directories, and targets
|
|
46
|
+
* @returns The same config
|
|
47
|
+
*/
|
|
48
|
+
export declare function defineConfig(config: MigrateConfig): MigrateConfig;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm dev`.
|
|
3
|
+
*
|
|
4
|
+
* When a target named `dev` is configured, the command names it. Otherwise it
|
|
5
|
+
* creates a PGlite database in `.okm/dev-db`.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Starts the dev database.
|
|
9
|
+
*
|
|
10
|
+
* A configured target named `dev` is used as it is. With no such target,
|
|
11
|
+
* PGlite is opened on `.okm/dev-db` so the directory exists for the app.
|
|
12
|
+
*
|
|
13
|
+
* @param cwd - Project directory
|
|
14
|
+
* @returns The target line, or the data directory
|
|
15
|
+
*/
|
|
16
|
+
export declare function devProject(cwd: string): Promise<string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural equality for two catalogs.
|
|
3
|
+
*
|
|
4
|
+
* Introspection stamps the same provenance on every object, so the canonical
|
|
5
|
+
* document is the comparison. Authoring text is not compared to a reprint.
|
|
6
|
+
*/
|
|
7
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Reports whether two catalogs serialise to the same bytes.
|
|
10
|
+
*
|
|
11
|
+
* @param left - First catalog
|
|
12
|
+
* @param right - Second catalog
|
|
13
|
+
* @returns `true` when the canonical documents match
|
|
14
|
+
*/
|
|
15
|
+
export declare function catalogsEqual(left: Catalog, right: Catalog): boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration files on disk: SQL from {@link formatPlan} plus the catalog hash.
|
|
3
|
+
*/
|
|
4
|
+
import { type PlanStep } from "./plan.js";
|
|
5
|
+
/** One migration the applier can run and resume. */
|
|
6
|
+
export type StoredMigration = {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly catalogHash: string;
|
|
9
|
+
readonly steps: readonly PlanStep[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Loads `*.sql` migrations and the sibling catalog snapshot.
|
|
13
|
+
*
|
|
14
|
+
* Files are applied in name order. A SQL file without its catalog is refused.
|
|
15
|
+
*
|
|
16
|
+
* @param directory - Migrations directory. Missing means there are none
|
|
17
|
+
* @returns Migrations in apply order
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadMigrations(directory: string): readonly StoredMigration[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry for `okmodel/migrate`.
|
|
3
|
+
*
|
|
4
|
+
* `defineConfig` and its types. The CLI imports planning and apply helpers
|
|
5
|
+
* from their modules, so those names are not exported.
|
|
6
|
+
*/
|
|
7
|
+
export { defineConfig, type MigrateConfig, type TargetInput } from "./config.js";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diffs two catalogs into an ordered, classified plan.
|
|
3
|
+
*
|
|
4
|
+
* Renames are applied to a copy of the previous catalog before the diff, so
|
|
5
|
+
* a declared rename is not a drop and an add. An unexplained drop-and-add is
|
|
6
|
+
* OKM1530. The planner never prompts.
|
|
7
|
+
*
|
|
8
|
+
* Picklist and enum removals are expand `UPDATE`s plus a contract swap
|
|
9
|
+
* (D131). Those data steps are plain statements here. Batching them is P52.
|
|
10
|
+
*/
|
|
11
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
12
|
+
import type { DeclaredRename } from "../../dialects/pg/declarations.js";
|
|
13
|
+
import { type Replacement } from "./values.js";
|
|
14
|
+
/** Expand, contract, or a step that is neither. */
|
|
15
|
+
export type MigrationClass = "expand" | "contract" | "unclassified";
|
|
16
|
+
/**
|
|
17
|
+
* One statement in a plan.
|
|
18
|
+
*
|
|
19
|
+
* `backfill` is data; P16B runs it as written. `transactional: false` marks a
|
|
20
|
+
* step that cannot share a transaction with a later use (`ALTER TYPE … ADD
|
|
21
|
+
* VALUE`, spec 19.2).
|
|
22
|
+
*/
|
|
23
|
+
export type PlanStep = {
|
|
24
|
+
readonly sql: string;
|
|
25
|
+
readonly class: MigrationClass;
|
|
26
|
+
readonly action: "ddl" | "backfill";
|
|
27
|
+
readonly lock: string;
|
|
28
|
+
readonly transactional: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** A named plan and the class of its strictest step. */
|
|
31
|
+
export type MigrationPlan = {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly class: MigrationClass;
|
|
34
|
+
readonly steps: readonly PlanStep[];
|
|
35
|
+
};
|
|
36
|
+
/** What the planner needs besides the two catalogs. */
|
|
37
|
+
export type PlanRequest = {
|
|
38
|
+
readonly before: Catalog;
|
|
39
|
+
readonly after: Catalog;
|
|
40
|
+
readonly renames?: readonly DeclaredRename[];
|
|
41
|
+
readonly replacements?: readonly Replacement[];
|
|
42
|
+
readonly schema?: string;
|
|
43
|
+
/** Concrete schema written into the SQL. Identities stay logical. */
|
|
44
|
+
readonly name?: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Builds a plan from catalog `before` to catalog `after`.
|
|
48
|
+
*
|
|
49
|
+
* @param request - Catalogs, declared renames, and `--replace` flags
|
|
50
|
+
* @returns Steps in apply order, with one class for the plan
|
|
51
|
+
*/
|
|
52
|
+
export declare function planMigration(request: PlanRequest): MigrationPlan;
|
|
53
|
+
/**
|
|
54
|
+
* Prints a plan. The text is SQL plus class comments, never TypeScript.
|
|
55
|
+
*
|
|
56
|
+
* @param plan - Plan from {@link planMigration}
|
|
57
|
+
* @returns The text `okm generate` writes and `okm migrate plan` prints
|
|
58
|
+
*/
|
|
59
|
+
export declare function formatPlan(plan: MigrationPlan): string;
|
|
60
|
+
/**
|
|
61
|
+
* Reads a plan written by {@link formatPlan}.
|
|
62
|
+
*
|
|
63
|
+
* @param text - SQL file text
|
|
64
|
+
* @returns The plan. The header class is kept when the file has no steps
|
|
65
|
+
*/
|
|
66
|
+
export declare function parsePlan(text: string): MigrationPlan;
|
|
67
|
+
/**
|
|
68
|
+
* Renames whose previous name is absent from the last snapshot.
|
|
69
|
+
*
|
|
70
|
+
* No snapshot means nothing is stale: there is no history to disagree with.
|
|
71
|
+
*
|
|
72
|
+
* @param previous - Last migration catalog, or `undefined` when there is none
|
|
73
|
+
* @param renames - Declarations on the current schema
|
|
74
|
+
* @returns Messages, empty when every rename still matches
|
|
75
|
+
*/
|
|
76
|
+
export declare function staleRenames(previous: Catalog | undefined, renames: readonly DeclaredRename[]): readonly string[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target names, the aliasing guard, pooler refusal, and the protection policy.
|
|
3
|
+
*
|
|
4
|
+
* One function, {@link assertTargetPolicy}, is what every entry point calls.
|
|
5
|
+
* Protection is a property of the target. It is not read from `NODE_ENV`.
|
|
6
|
+
*/
|
|
7
|
+
import type { MigrateConfig } from "./config.js";
|
|
8
|
+
/** An operation the policy table allows or blocks. */
|
|
9
|
+
export type PolicyOperation = "plan" | "status" | "check" | "drift" | "verify" | "pull" | "catalog-export" | "inspect" | "expand" | "reference" | "provision" | "contract" | "unclassified" | "push" | "backfill" | "seed" | "history-repair" | "drop" | "rollback";
|
|
10
|
+
/** Flags shared by commands that touch a target. */
|
|
11
|
+
export type InvokeFlags = {
|
|
12
|
+
readonly target?: string;
|
|
13
|
+
readonly allowProtected: boolean;
|
|
14
|
+
readonly allowPooler: boolean;
|
|
15
|
+
readonly lockTimeoutMs?: number;
|
|
16
|
+
readonly statementTimeoutMs?: number;
|
|
17
|
+
};
|
|
18
|
+
/** A resolved migration target. The plan stores the name, not the URL. */
|
|
19
|
+
export type TargetRecord = {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly url: string;
|
|
22
|
+
readonly protected: boolean;
|
|
23
|
+
readonly host: string;
|
|
24
|
+
readonly port: string;
|
|
25
|
+
readonly database: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Refuses an operation the target's protection does not allow.
|
|
29
|
+
*
|
|
30
|
+
* `--allow-protected` is per invocation. It does not lift `drop` or `rollback`.
|
|
31
|
+
* `provision` is allowed here; the caller still refuses a target that is not empty.
|
|
32
|
+
*
|
|
33
|
+
* @param target - Name and protection flag
|
|
34
|
+
* @param operation - What the entry point is about to do
|
|
35
|
+
* @param allowProtected - The invocation passed `--allow-protected`
|
|
36
|
+
*/
|
|
37
|
+
export declare function assertTargetPolicy(target: {
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly protected: boolean;
|
|
40
|
+
}, operation: PolicyOperation, allowProtected?: boolean): void;
|
|
41
|
+
/**
|
|
42
|
+
* Fails when targets on one host, port, and database disagree about protection.
|
|
43
|
+
*
|
|
44
|
+
* Two unprotected targets may share a database. The comparison ignores schema.
|
|
45
|
+
*
|
|
46
|
+
* @param targets - Resolved targets
|
|
47
|
+
*/
|
|
48
|
+
export declare function assertTargetAlias(targets: readonly TargetRecord[]): void;
|
|
49
|
+
/**
|
|
50
|
+
* Refuses a known pooler URL.
|
|
51
|
+
*
|
|
52
|
+
* Apply needs one session for the advisory lock. A transaction-mode pooler
|
|
53
|
+
* does not keep that session. `--allow-pooler` is the override.
|
|
54
|
+
*
|
|
55
|
+
* @param url - Target URL
|
|
56
|
+
* @param allowPooler - The invocation opted in
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertDirectConnection(url: string, allowPooler: boolean): void;
|
|
59
|
+
/**
|
|
60
|
+
* Lists configured targets.
|
|
61
|
+
*
|
|
62
|
+
* `database` is the target named `default`. `targets` replaces it. Setting
|
|
63
|
+
* both is refused.
|
|
64
|
+
*
|
|
65
|
+
* @param config - Project config
|
|
66
|
+
* @returns Targets in name order
|
|
67
|
+
*/
|
|
68
|
+
export declare function listTargets(config: MigrateConfig): readonly TargetRecord[];
|
|
69
|
+
/**
|
|
70
|
+
* Picks the target a command that must not guess will use.
|
|
71
|
+
*
|
|
72
|
+
* One configured target is that target. Several require `name` (OKM1853).
|
|
73
|
+
*
|
|
74
|
+
* @param config - Project config
|
|
75
|
+
* @param name - `--target`, when the command passed one
|
|
76
|
+
* @returns The target
|
|
77
|
+
*/
|
|
78
|
+
export declare function selectTarget(config: MigrateConfig, name: string | undefined): TargetRecord;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm build`, `okm generate`, `okm check`, and `okm migrate plan`.
|
|
3
|
+
*
|
|
4
|
+
* Build writes the catalog it already validated. Check and dev read
|
|
5
|
+
* `.catalog`, which runs that validation. Generate writes SQL only.
|
|
6
|
+
*/
|
|
7
|
+
import { type DeclaredRename } from "../../dialects/pg/declarations.js";
|
|
8
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
9
|
+
import { type MigrateConfig } from "./config.js";
|
|
10
|
+
import { type MigrationPlan } from "./plan.js";
|
|
11
|
+
/**
|
|
12
|
+
* Validates the schema and writes `.okm/`.
|
|
13
|
+
*
|
|
14
|
+
* @param cwd - Project directory
|
|
15
|
+
* @returns The output directory
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildProject(cwd: string): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Plans the current schema against the latest snapshot and writes SQL.
|
|
20
|
+
*
|
|
21
|
+
* An empty plan writes nothing. The file is SQL, not TypeScript.
|
|
22
|
+
*
|
|
23
|
+
* @param cwd - Project directory
|
|
24
|
+
* @param name - Migration name
|
|
25
|
+
* @param flags - `--replace` values
|
|
26
|
+
* @returns The SQL path, or `undefined` when nothing changed
|
|
27
|
+
*/
|
|
28
|
+
export declare function generateProject(cwd: string, name: string, flags: readonly string[]): Promise<string | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Plans and returns the text. Nothing is written.
|
|
31
|
+
*
|
|
32
|
+
* @param cwd - Project directory
|
|
33
|
+
* @param name - Plan name
|
|
34
|
+
* @param flags - `--replace` values
|
|
35
|
+
* @returns The plan
|
|
36
|
+
*/
|
|
37
|
+
export declare function planProject(cwd: string, name: string, flags: readonly string[]): Promise<MigrationPlan>;
|
|
38
|
+
/**
|
|
39
|
+
* Validates the schema, then reports stale renames and unlisted table files.
|
|
40
|
+
*
|
|
41
|
+
* @param cwd - Project directory
|
|
42
|
+
*/
|
|
43
|
+
export declare function checkProject(cwd: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Table files whose names do not appear in the schema module.
|
|
46
|
+
*
|
|
47
|
+
* @param schemaSource - Source text of the schema module
|
|
48
|
+
* @param fileNames - File names in the tables directory
|
|
49
|
+
* @returns Files `okm check` reports as OKM1024
|
|
50
|
+
*/
|
|
51
|
+
export declare function unlistedTableFiles(schemaSource: string, fileNames: readonly string[]): readonly string[];
|
|
52
|
+
/**
|
|
53
|
+
* The catalogs `okm push` diffs, after stale renames are refused.
|
|
54
|
+
*
|
|
55
|
+
* @param cwd - Project directory
|
|
56
|
+
* @returns The previous snapshot, the current catalog, and declared renames
|
|
57
|
+
*/
|
|
58
|
+
export declare function projectHead(cwd: string): Promise<{
|
|
59
|
+
readonly previous: Catalog;
|
|
60
|
+
readonly catalog: Catalog;
|
|
61
|
+
readonly renames: readonly DeclaredRename[];
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Loads `okmodel.config.ts`.
|
|
65
|
+
*
|
|
66
|
+
* @param cwd - Project directory
|
|
67
|
+
* @returns The config object
|
|
68
|
+
*/
|
|
69
|
+
export declare function loadConfig(cwd: string): Promise<MigrateConfig>;
|