okmodel 0.2.1 → 0.3.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 +710 -36
- package/dist/contracts/catalog/enum.d.ts +31 -4
- package/dist/contracts/catalog/extension.d.ts +61 -0
- package/dist/contracts/catalog/privilege.d.ts +64 -0
- package/dist/contracts/catalog/routine.d.ts +56 -0
- package/dist/contracts/catalog/types.d.ts +164 -10
- package/dist/contracts/catalog/view.d.ts +73 -0
- package/dist/dialects/pg/column.d.ts +3 -1
- package/dist/dialects/pg/ddl.d.ts +65 -1
- package/dist/dialects/pg/enum.d.ts +10 -8
- package/dist/dialects/pg/ext/citext.d.ts +14 -0
- package/dist/dialects/pg/ext/citext.js +11 -0
- package/dist/dialects/pg/ext/index.d.ts +52 -0
- package/dist/dialects/pg/ext/index.js +6 -0
- package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
- package/dist/dialects/pg/ext/pg-trgm.js +42 -0
- package/dist/dialects/pg/fn/index.d.ts +107 -0
- package/dist/dialects/pg/fn/index.js +175 -0
- package/dist/dialects/pg/fn/touch.d.ts +14 -0
- package/dist/dialects/pg/index.js +104 -19
- package/dist/dialects/pg/introspect.d.ts +10 -1
- package/dist/dialects/pg/operators.d.ts +8 -1
- package/dist/dialects/pg/role/check.d.ts +45 -0
- package/dist/dialects/pg/role/index.d.ts +50 -0
- package/dist/dialects/pg/role/sql.d.ts +44 -0
- package/dist/dialects/pg/table.d.ts +7 -0
- package/dist/dialects/pg/tenancy.d.ts +9 -0
- package/dist/dialects/pg/view/client.d.ts +30 -0
- package/dist/dialects/pg/view/depend.d.ts +35 -0
- package/dist/dialects/pg/view/index.d.ts +114 -0
- package/dist/dialects/pg/view/index.js +289 -0
- package/dist/dialects/pg/view/scratch.d.ts +21 -0
- package/dist/dialects/pg/where.d.ts +2 -2
- package/dist/runtime/pg/bun.js +3 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +3 -3
- package/dist/runtime/pg/postgresjs.js +3 -3
- package/dist/runtime/tenancy/index.js +6 -3
- package/dist/runtime/traits/index.d.ts +7 -2
- package/dist/runtime/traits/index.js +149 -12
- package/dist/runtime/validate/index.js +4 -4
- package/dist/shared/{ytg3xf9p.js → 01yr20s5.js} +3 -3
- package/dist/shared/{cstgkzdx.js → 0jc3ffzf.js} +1 -1
- package/dist/shared/{xkz8g6by.js → 1g0drakv.js} +2 -2
- package/dist/shared/{eaxwrgby.js → 1tfdfvhh.js} +4 -3
- package/dist/shared/2ssqrv66.js +1576 -0
- package/dist/shared/{10tjenmd.js → 3ekj9x92.js} +1 -1
- package/dist/shared/49ypnfwt.js +1122 -0
- package/dist/shared/{sacqha1y.js → 4m9fn52z.js} +2 -2
- package/dist/shared/5nmdenb6.js +1229 -0
- package/dist/shared/{qa5dsc7z.js → 6bazvqwm.js} +3 -3
- package/dist/shared/{x9v1qgeb.js → 6w5j844a.js} +1 -1
- package/dist/shared/{0qkxbm1f.js → 75xkjv0t.js} +1 -1
- package/dist/shared/7fvtrkwr.js +84 -0
- package/dist/shared/94ez8kzh.js +19 -0
- package/dist/shared/{1dp5knt7.js → 999ade2q.js} +2 -2
- package/dist/shared/{3a5ne750.js → 9m80mkac.js} +2 -2
- package/dist/shared/9x25fxhc.js +150 -0
- package/dist/shared/{4b9da9d7.js → axhk06q1.js} +19 -1
- package/dist/shared/{38crxbgn.js → bqha5cg6.js} +3 -3
- package/dist/shared/{zd93g3rq.js → bryqk9k9.js} +1 -1
- package/dist/shared/{n47rd821.js → c8aghh05.js} +1 -1
- package/dist/shared/{dd4f8mnx.js → c9z5g0fm.js} +4 -2
- package/dist/shared/{eqmtn1bj.js → dbjej1tw.js} +71 -14
- package/dist/shared/{ps43134h.js → dyj86cmj.js} +4 -4
- package/dist/shared/{sfh4pk75.js → fptpmvxp.js} +3 -3
- package/dist/shared/{97g2jnrw.js → fs0ex00p.js} +3 -3
- package/dist/shared/{rtnaqre0.js → g4f5kcx9.js} +2 -2
- package/dist/shared/{yw5c610b.js → gjthds9j.js} +2 -2
- package/dist/shared/hcmdtwgh.js +102 -0
- package/dist/shared/{qxa0yb9j.js → jkc6ws1p.js} +2 -54
- package/dist/shared/{mxmcdsh5.js → k34e0xf2.js} +9 -9
- package/dist/shared/{py3nh7jy.js → kgnc8grt.js} +2 -2
- package/dist/shared/{g9f0zqce.js → m78s7898.js} +1 -1
- package/dist/shared/meck53jv.js +99 -0
- package/dist/shared/{v18jva5b.js → mt5wswjz.js} +1 -1
- package/dist/shared/{g1b5zzj9.js → n0dgs0pb.js} +1 -1
- package/dist/shared/{zt8y0wzb.js → n7mcc1gk.js} +1 -1
- package/dist/shared/ne02ng5c.js +68 -0
- package/dist/shared/{e7a268fy.js → p24x2334.js} +1 -1
- package/dist/shared/qbxzvwwc.js +88 -0
- package/dist/shared/{a1gdp7j9.js → qybh48nd.js} +1 -1
- package/dist/shared/{d04j53v8.js → scwxrpx2.js} +5 -4
- package/dist/shared/{d2whjz4k.js → t616ynfn.js} +530 -24
- package/dist/shared/th14ygv2.js +69 -0
- package/dist/shared/{xatfg0gn.js → tmbdywx0.js} +4 -19
- package/dist/shared/{ge03bfca.js → ty3v3hfk.js} +2 -2
- package/dist/shared/wekze34d.js +246 -0
- package/dist/shared/{7mht49yd.js → x6wysh83.js} +59 -18
- package/dist/shared/{4jzzghr6.js → xva8v7qk.js} +8 -8
- package/dist/shared/{ecdzej21.js → xw1d69vd.js} +7 -7
- package/dist/shared/y005b761.js +112 -0
- package/dist/shared/{mrq77sgw.js → ydaz1sv3.js} +1 -1
- package/dist/tooling/cli.js +32 -8
- package/dist/tooling/migrate/apply.d.ts +16 -0
- package/dist/tooling/migrate/commands.d.ts +2 -1
- package/dist/tooling/migrate/config.d.ts +8 -0
- package/dist/tooling/migrate/doctor.d.ts +25 -0
- package/dist/tooling/migrate/drift.d.ts +19 -0
- package/dist/tooling/migrate/ext.d.ts +17 -0
- package/dist/tooling/migrate/extensions.d.ts +51 -0
- package/dist/tooling/migrate/managed.d.ts +17 -0
- package/dist/tooling/migrate/plan.d.ts +14 -1
- package/dist/tooling/migrate/project.d.ts +25 -1
- package/dist/tooling/migrate/type-name.d.ts +19 -0
- package/package.json +22 -2
- package/dist/shared/5z4q2zda.js +0 -2073
- /package/dist/shared/{9k6vetvf.js → rrstp3kb.js} +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
staticNamespace2,
|
|
3
|
+
assertNamespace2,
|
|
4
|
+
normaliseEdges,
|
|
5
|
+
assertProvenance
|
|
6
|
+
} from "./t4tbsy9h.js";
|
|
7
|
+
import {
|
|
8
|
+
assertIdentifier2,
|
|
9
|
+
fitIdentifier2,
|
|
10
|
+
deterministicName2
|
|
11
|
+
} from "./nfzc5z0w.js";
|
|
12
|
+
import {
|
|
13
|
+
catalogError2
|
|
14
|
+
} from "./52szzakm.js";
|
|
15
|
+
|
|
16
|
+
// src/contracts/catalog/view.ts
|
|
17
|
+
function normaliseViewQuery(query) {
|
|
18
|
+
return query.trim().replace(/;\s*$/, "");
|
|
19
|
+
}
|
|
20
|
+
function viewObject(input) {
|
|
21
|
+
const namespace = input.namespace ?? staticNamespace2("public");
|
|
22
|
+
const columns = readColumns(input.name, input.columns);
|
|
23
|
+
const query = readQuery(input.name, input.query);
|
|
24
|
+
assertNamespace2(namespace);
|
|
25
|
+
assertProvenance(input.provenance);
|
|
26
|
+
const definition = { columns, query };
|
|
27
|
+
return {
|
|
28
|
+
kind: "view",
|
|
29
|
+
identity: { kind: "view", namespace, name: input.name },
|
|
30
|
+
owner: input.owner ?? "managed",
|
|
31
|
+
definition,
|
|
32
|
+
dependencies: normaliseEdges(input.dependencies ?? []),
|
|
33
|
+
provenance: input.provenance
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function materializedViewObject(input) {
|
|
37
|
+
const namespace = input.namespace ?? staticNamespace2("public");
|
|
38
|
+
const columns = readColumns(input.name, input.columns);
|
|
39
|
+
const query = readQuery(input.name, input.query);
|
|
40
|
+
assertNamespace2(namespace);
|
|
41
|
+
assertProvenance(input.provenance);
|
|
42
|
+
const definition = {
|
|
43
|
+
columns,
|
|
44
|
+
query,
|
|
45
|
+
...input.refresh === "concurrently" ? { refresh: "concurrently" } : {}
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
kind: "materializedView",
|
|
49
|
+
identity: { kind: "materializedView", namespace, name: input.name },
|
|
50
|
+
owner: input.owner ?? "managed",
|
|
51
|
+
definition,
|
|
52
|
+
dependencies: normaliseEdges(input.dependencies ?? []),
|
|
53
|
+
provenance: input.provenance
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function materializedViewIndex(input) {
|
|
57
|
+
assertNamespace2(input.parent.namespace);
|
|
58
|
+
assertIdentifier2(input.parent.name, "index parent");
|
|
59
|
+
assertProvenance(input.provenance);
|
|
60
|
+
const columns = [...input.columns];
|
|
61
|
+
for (const name of columns)
|
|
62
|
+
assertIdentifier2(name, "index column");
|
|
63
|
+
if (columns.length === 0 && input.expression === undefined) {
|
|
64
|
+
catalogError2("OKM1020", `Index on ${input.parent.name} needs a column or an expression.`);
|
|
65
|
+
}
|
|
66
|
+
const nameKey = input.nameKey ?? (columns.length > 0 ? columns.join("_") : "expr");
|
|
67
|
+
const name = input.name === undefined ? deterministicName2({ parent: input.parent.name, purpose: "index", nameKey }) : fitIdentifier2(input.name);
|
|
68
|
+
const parentView = {
|
|
69
|
+
kind: "materializedView",
|
|
70
|
+
namespace: input.parent.namespace,
|
|
71
|
+
name: input.parent.name
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
kind: "index",
|
|
75
|
+
identity: { kind: "index", parent: input.parent, name },
|
|
76
|
+
owner: input.owner ?? "managed",
|
|
77
|
+
definition: {
|
|
78
|
+
columns,
|
|
79
|
+
unique: input.unique === true,
|
|
80
|
+
nameKey,
|
|
81
|
+
...input.expression !== undefined ? { expression: input.expression } : {},
|
|
82
|
+
...input.predicate !== undefined ? { predicate: input.predicate } : {}
|
|
83
|
+
},
|
|
84
|
+
dependencies: normaliseEdges(input.dependencies ?? [parentView]),
|
|
85
|
+
provenance: input.provenance
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function readColumns(view, columns) {
|
|
89
|
+
assertIdentifier2(view, "view");
|
|
90
|
+
if (columns.length === 0)
|
|
91
|
+
catalogError2("OKM1020", `View ${view} needs a column.`);
|
|
92
|
+
const seen = new Set;
|
|
93
|
+
return columns.map((column) => {
|
|
94
|
+
assertIdentifier2(column.name, `view ${view} column`);
|
|
95
|
+
if (seen.has(column.name)) {
|
|
96
|
+
catalogError2("OKM1020", `View ${view} lists column ${column.name} twice.`);
|
|
97
|
+
}
|
|
98
|
+
seen.add(column.name);
|
|
99
|
+
if (column.dataType.length === 0 || /[;'"\\]/.test(column.dataType)) {
|
|
100
|
+
catalogError2("OKM1020", `View ${view} column ${column.name} type is not a type name.`);
|
|
101
|
+
}
|
|
102
|
+
return { name: column.name, dataType: column.dataType };
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function readQuery(view, query) {
|
|
106
|
+
const text = normaliseViewQuery(query);
|
|
107
|
+
if (text.length === 0)
|
|
108
|
+
catalogError2("OKM1020", `View ${view} needs a query.`);
|
|
109
|
+
return text;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { normaliseViewQuery, viewObject, materializedViewObject, materializedViewIndex };
|
package/dist/tooling/cli.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import"../shared/
|
|
1
|
+
import"../shared/t616ynfn.js";
|
|
2
2
|
import"../shared/n442h54c.js";
|
|
3
3
|
import {
|
|
4
|
-
formatPlan,
|
|
5
4
|
buildProject,
|
|
6
5
|
generateProject,
|
|
7
6
|
planProject,
|
|
8
7
|
checkProject
|
|
9
|
-
} from "../shared/
|
|
8
|
+
} from "../shared/5nmdenb6.js";
|
|
9
|
+
import {
|
|
10
|
+
formatPlan
|
|
11
|
+
} from "../shared/2ssqrv66.js";
|
|
10
12
|
import {
|
|
11
13
|
OkmError2
|
|
12
14
|
} from "../shared/52szzakm.js";
|
|
@@ -33,7 +35,7 @@ async function run(argv, io) {
|
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
if (command === "check") {
|
|
36
|
-
await checkProject(cwd);
|
|
38
|
+
await checkProject(cwd, invoke(splitFlags(rest)));
|
|
37
39
|
stdout(`ok
|
|
38
40
|
`);
|
|
39
41
|
return;
|
|
@@ -47,12 +49,12 @@ async function run(argv, io) {
|
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
51
|
if (command === "dev") {
|
|
50
|
-
const { devProject } = await import("../shared/
|
|
52
|
+
const { devProject } = await import("../shared/1tfdfvhh.js");
|
|
51
53
|
stdout(await devProject(cwd));
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
56
|
if (command === "push") {
|
|
55
|
-
const { pushProject } = await import("../shared/
|
|
57
|
+
const { pushProject } = await import("../shared/dbjej1tw.js");
|
|
56
58
|
stdout(await pushProject(cwd, invoke(splitFlags(rest))));
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
@@ -67,16 +69,38 @@ async function run(argv, io) {
|
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
69
71
|
if (sub === "apply") {
|
|
70
|
-
const { applyProject } = await import("../shared/
|
|
72
|
+
const { applyProject } = await import("../shared/dbjej1tw.js");
|
|
71
73
|
stdout(await applyProject(cwd, invoke(parsed)));
|
|
72
74
|
return;
|
|
73
75
|
}
|
|
74
76
|
if (sub === "status") {
|
|
75
|
-
const { statusProject } = await import("../shared/
|
|
77
|
+
const { statusProject } = await import("../shared/scwxrpx2.js");
|
|
76
78
|
stdout(await statusProject(cwd, invoke(parsed)));
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
81
|
}
|
|
82
|
+
if (command === "doctor") {
|
|
83
|
+
const parsed = splitFlags(rest);
|
|
84
|
+
const { doctorProject } = await import("../shared/ne02ng5c.js");
|
|
85
|
+
stdout(await doctorProject(cwd, parsed.name, invoke(parsed)));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (command === "ext") {
|
|
89
|
+
const sub = rest[0];
|
|
90
|
+
if (sub === "test" || sub === "scaffold") {
|
|
91
|
+
throw new OkmError2("invalid", `okm ext ${sub} is not available yet.`, {
|
|
92
|
+
fix: { summary: "okm ext list and okm ext check are the commands in this version." }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (sub === "list" || sub === "check") {
|
|
96
|
+
const { extProject } = await import("../shared/meck53jv.js");
|
|
97
|
+
stdout(await extProject(cwd, sub, invoke(splitFlags(rest.slice(1)))));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
throw new OkmError2("invalid", `Unknown command ext ${sub ?? ""}.`, {
|
|
101
|
+
fix: { summary: "Use okm ext list or okm ext check." }
|
|
102
|
+
});
|
|
103
|
+
}
|
|
80
104
|
throw new OkmError2("invalid", `Unknown command ${command ?? ""}.`);
|
|
81
105
|
}
|
|
82
106
|
function invoke(parsed) {
|
|
@@ -37,11 +37,27 @@ export type ApplyRequest = {
|
|
|
37
37
|
readonly migrations: readonly StoredMigration[];
|
|
38
38
|
/** Runs after the advisory lock is held and before the first step. */
|
|
39
39
|
readonly onLocked?: () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Role that runs the migration.
|
|
42
|
+
*
|
|
43
|
+
* When it already exists and is not `current_user`, the runner issues one
|
|
44
|
+
* `SET ROLE` before any statement. That statement is not a plan step.
|
|
45
|
+
*/
|
|
46
|
+
readonly migrationRole?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Schema the migration role may create in.
|
|
49
|
+
*
|
|
50
|
+
* When this run creates that role, the runner grants `USAGE` and `CREATE`
|
|
51
|
+
* on this schema before `SET ROLE`. The default is `public`.
|
|
52
|
+
*/
|
|
53
|
+
readonly schema?: string;
|
|
40
54
|
};
|
|
41
55
|
/** Migrations that ran at least one step in this invocation. */
|
|
42
56
|
export type ApplyReport = {
|
|
43
57
|
readonly target: string;
|
|
44
58
|
readonly applied: readonly string[];
|
|
59
|
+
/** Set when the runner issued `SET ROLE` at session start. */
|
|
60
|
+
readonly setRole?: string;
|
|
45
61
|
};
|
|
46
62
|
/**
|
|
47
63
|
* Groups pending steps into the transactions apply will run.
|
|
@@ -23,7 +23,8 @@ export declare function formatFailure(error: OkmError): string;
|
|
|
23
23
|
* Runs one `okm` invocation.
|
|
24
24
|
*
|
|
25
25
|
* `--version` stays in the bin. This function handles `build`, `check`,
|
|
26
|
-
* `generate`, `dev`, `push`,
|
|
26
|
+
* `generate`, `dev`, `push`, `ext list`, `ext check`, `doctor`, and `migrate plan`,
|
|
27
|
+
* `apply`, and `status`.
|
|
27
28
|
*
|
|
28
29
|
* @param argv - Arguments after the program name
|
|
29
30
|
* @param io - Working directory and stdout. Defaults to the process
|
|
@@ -9,6 +9,7 @@ export type TargetInput = string | {
|
|
|
9
9
|
/** Refuses contract, push, and other non-expand work unless `--allow-protected`. */
|
|
10
10
|
readonly protected?: boolean;
|
|
11
11
|
};
|
|
12
|
+
import type { RolesInput } from "../../dialects/pg/role/index.js";
|
|
12
13
|
/** Paths and targets `okm` reads. */
|
|
13
14
|
export type MigrateConfig = {
|
|
14
15
|
/** Module that exports the built schema. */
|
|
@@ -35,6 +36,13 @@ export type MigrateConfig = {
|
|
|
35
36
|
readonly lock?: number;
|
|
36
37
|
readonly statement?: number;
|
|
37
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Migration role and application role.
|
|
41
|
+
*
|
|
42
|
+
* A name is external unless it is also listed in `managed`. The plan creates
|
|
43
|
+
* a managed role and never drops one.
|
|
44
|
+
*/
|
|
45
|
+
readonly roles?: RolesInput;
|
|
38
46
|
};
|
|
39
47
|
/**
|
|
40
48
|
* Returns the config unchanged.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm doctor`.
|
|
3
|
+
*
|
|
4
|
+
* A code prints the registry entry. With no code, the project is loaded and
|
|
5
|
+
* each table's triggers are listed. When `roles` is set, the command also
|
|
6
|
+
* connects and checks that those roles exist, that a managed role can be
|
|
7
|
+
* created, and that the application role can reach each managed object.
|
|
8
|
+
*/
|
|
9
|
+
import type { CatalogObject } from "../../contracts/catalog/types.js";
|
|
10
|
+
import { type InvokeFlags } from "./policy.js";
|
|
11
|
+
/**
|
|
12
|
+
* Explains one code, or lists the triggers on each table.
|
|
13
|
+
*
|
|
14
|
+
* @param cwd - Project directory
|
|
15
|
+
* @param code - Spec code, when the caller passed one
|
|
16
|
+
* @returns Text for stdout, including the trailing newline
|
|
17
|
+
*/
|
|
18
|
+
export declare function doctorProject(cwd: string, code: string | undefined, flags?: InvokeFlags): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* One line per table that has a trigger.
|
|
21
|
+
*
|
|
22
|
+
* @param objects - Catalog objects
|
|
23
|
+
* @returns The listing, or `no triggers` when none are present
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatTriggers(objects: readonly CatalogObject[]): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live drift for `okm check`.
|
|
3
|
+
*
|
|
4
|
+
* A database that has never been pushed has no `okm_meta` and is left alone.
|
|
5
|
+
* After push, the introspected catalog is planned back to the schema. Each
|
|
6
|
+
* view is reprinted on this server first, so a `pg_get_viewdef` spelling is
|
|
7
|
+
* not drift. Any remaining statement is OKM1520. `okm_meta` and `okm_history`
|
|
8
|
+
* are omitted by the planner.
|
|
9
|
+
*/
|
|
10
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
11
|
+
import type { RolesInput } from "../../dialects/pg/role/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Refuses when the connected database differs from the schema.
|
|
14
|
+
*
|
|
15
|
+
* @param url - Target URL
|
|
16
|
+
* @param author - Schema catalog, including roles when the config names them
|
|
17
|
+
* @param roles - `defineConfig({ roles })`, when set
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertAuthorDrift(url: string, author: Catalog, roles?: RolesInput): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `okm ext list` and `okm ext check`.
|
|
3
|
+
*
|
|
4
|
+
* Both talk to the selected target. List prints every extension the server
|
|
5
|
+
* can install, and the installed version when one is present. Check compares
|
|
6
|
+
* the schema's declarations with what is installed.
|
|
7
|
+
*/
|
|
8
|
+
import { type InvokeFlags } from "./policy.js";
|
|
9
|
+
/**
|
|
10
|
+
* Runs `list` or `check` against the selected target.
|
|
11
|
+
*
|
|
12
|
+
* @param cwd - Project directory
|
|
13
|
+
* @param command - `list` or `check`
|
|
14
|
+
* @param flags - Target and protection flags
|
|
15
|
+
* @returns Text for stdout, including the trailing newline
|
|
16
|
+
*/
|
|
17
|
+
export declare function extProject(cwd: string, command: "list" | "check", flags: InvokeFlags): Promise<string>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension alters and the apply preflight.
|
|
3
|
+
*
|
|
4
|
+
* Create and drop SQL come from the dialect. An upgrade is `ALTER EXTENSION
|
|
5
|
+
* … UPDATE`, marked `path-unverified` until apply checks
|
|
6
|
+
* `pg_extension_update_paths`. A move is `SET SCHEMA` and only when the
|
|
7
|
+
* declaration is relocatable.
|
|
8
|
+
*/
|
|
9
|
+
import type { CatalogObject } from "../../contracts/catalog/types.js";
|
|
10
|
+
import type { DriverConnection } from "../../contracts/driver.js";
|
|
11
|
+
/** One extension alter. The planner stores it as a plan step. */
|
|
12
|
+
export type ExtensionStep = {
|
|
13
|
+
readonly sql: string;
|
|
14
|
+
readonly class: "expand" | "contract";
|
|
15
|
+
readonly action: "ddl";
|
|
16
|
+
readonly lock: string;
|
|
17
|
+
readonly transactional: boolean;
|
|
18
|
+
readonly path?: "unverified";
|
|
19
|
+
};
|
|
20
|
+
/** Migrations the preflight reads. Only the statement text is used. */
|
|
21
|
+
type MigrationSql = {
|
|
22
|
+
readonly steps: readonly {
|
|
23
|
+
readonly sql: string;
|
|
24
|
+
}[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Upgrade and move steps for extensions whose definition changed.
|
|
28
|
+
*
|
|
29
|
+
* Exact downgrades and moves of a non-relocatable extension are OKM1814.
|
|
30
|
+
* Dropping an extension that an object in the next catalog still uses is
|
|
31
|
+
* OKM1814. `DROP` is never `CASCADE`.
|
|
32
|
+
*
|
|
33
|
+
* @param beforeBy - Previous objects, keyed by identity
|
|
34
|
+
* @param afterBy - Next objects, keyed by identity
|
|
35
|
+
* @param dropKeys - Identities the plan drops
|
|
36
|
+
* @returns Alter steps. Creates and drops stay in the main planner
|
|
37
|
+
*/
|
|
38
|
+
export declare function extensionAlterSteps(beforeBy: ReadonlyMap<string, CatalogObject>, afterBy: ReadonlyMap<string, CatalogObject>, dropKeys: ReadonlySet<string>): ExtensionStep[];
|
|
39
|
+
/**
|
|
40
|
+
* Refuses a migration that names an extension the server cannot install,
|
|
41
|
+
* or an upgrade with no path.
|
|
42
|
+
*
|
|
43
|
+
* The server is asked only when a step creates or upgrades an extension.
|
|
44
|
+
* The check runs before any statement.
|
|
45
|
+
*
|
|
46
|
+
* @param connection - The reserved apply connection
|
|
47
|
+
* @param migrations - Migrations in apply order
|
|
48
|
+
* @throws OkmError OKM1811 when the extension is not available, OKM1814 when the update path is missing
|
|
49
|
+
*/
|
|
50
|
+
export declare function assertExtensionsAvailable(connection: DriverConnection, migrations: readonly MigrationSql[]): Promise<void>;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tables OKModel owns: `okm_meta` and `okm_history`.
|
|
3
|
+
*
|
|
4
|
+
* Apply creates them. They are not part of the author schema. Plan, push,
|
|
5
|
+
* check, and doctor omit them on both sides, so a diff neither drops them
|
|
6
|
+
* nor creates them.
|
|
7
|
+
*/
|
|
8
|
+
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Removes the migration history tables and the objects that belong to them.
|
|
11
|
+
*
|
|
12
|
+
* A catalog that has neither is returned as itself.
|
|
13
|
+
*
|
|
14
|
+
* @param source - Catalog about to be diffed or diagnosed
|
|
15
|
+
* @returns The catalog without OKModel's own tables
|
|
16
|
+
*/
|
|
17
|
+
export declare function omitManagedObjects(source: Catalog): Catalog;
|
|
@@ -26,6 +26,19 @@ export type PlanStep = {
|
|
|
26
26
|
readonly action: "ddl" | "backfill";
|
|
27
27
|
readonly lock: string;
|
|
28
28
|
readonly transactional: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Set on an extension upgrade the planner could not check.
|
|
31
|
+
*
|
|
32
|
+
* Apply reads `pg_extension_update_paths` before any statement and refuses
|
|
33
|
+
* a missing path. Offline `okm migrate plan` leaves this unverified.
|
|
34
|
+
*/
|
|
35
|
+
readonly path?: "unverified";
|
|
36
|
+
/**
|
|
37
|
+
* Set on `CREATE OR REPLACE` of a function whose signature did not change.
|
|
38
|
+
*
|
|
39
|
+
* The statement is expand. The flag says the body or the settings changed.
|
|
40
|
+
*/
|
|
41
|
+
readonly behavior?: "change";
|
|
29
42
|
};
|
|
30
43
|
/** A named plan and the class of its strictest step. */
|
|
31
44
|
export type MigrationPlan = {
|
|
@@ -49,7 +62,7 @@ export type PlanRequest = {
|
|
|
49
62
|
* @param request - Catalogs, declared renames, and `--replace` flags
|
|
50
63
|
* @returns Steps in apply order, with one class for the plan
|
|
51
64
|
*/
|
|
52
|
-
export declare function planMigration(
|
|
65
|
+
export declare function planMigration(input: PlanRequest): MigrationPlan;
|
|
53
66
|
/**
|
|
54
67
|
* Prints a plan. The text is SQL plus class comments, never TypeScript.
|
|
55
68
|
*
|
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
* `.catalog`, which runs that validation. Generate writes SQL only.
|
|
6
6
|
*/
|
|
7
7
|
import { type DeclaredRename } from "../../dialects/pg/declarations.js";
|
|
8
|
+
import type { BuiltSchema } from "../../dialects/pg/schema.js";
|
|
9
|
+
import type { AnyTable } from "../../dialects/pg/table.js";
|
|
8
10
|
import type { Catalog } from "../../contracts/catalog/types.js";
|
|
9
11
|
import { type MigrateConfig } from "./config.js";
|
|
12
|
+
import { type InvokeFlags } from "./policy.js";
|
|
10
13
|
import { type MigrationPlan } from "./plan.js";
|
|
14
|
+
type Built = BuiltSchema<readonly AnyTable[]>;
|
|
11
15
|
/**
|
|
12
16
|
* Validates the schema and writes `.okm/`.
|
|
13
17
|
*
|
|
@@ -38,9 +42,14 @@ export declare function planProject(cwd: string, name: string, flags: readonly s
|
|
|
38
42
|
/**
|
|
39
43
|
* Validates the schema, then reports stale renames and unlisted table files.
|
|
40
44
|
*
|
|
45
|
+
* When exactly one target is configured, or `--target` names one, a database
|
|
46
|
+
* that already has `okm_meta` is compared with the schema. A difference is
|
|
47
|
+
* OKM1520. Several targets and no `--target` skip that comparison.
|
|
48
|
+
*
|
|
41
49
|
* @param cwd - Project directory
|
|
50
|
+
* @param flags - `--target`, when the caller passed one
|
|
42
51
|
*/
|
|
43
|
-
export declare function checkProject(cwd: string): Promise<void>;
|
|
52
|
+
export declare function checkProject(cwd: string, flags?: InvokeFlags): Promise<void>;
|
|
44
53
|
/**
|
|
45
54
|
* Table files whose names do not appear in the schema module.
|
|
46
55
|
*
|
|
@@ -60,6 +69,20 @@ export declare function projectHead(cwd: string): Promise<{
|
|
|
60
69
|
readonly catalog: Catalog;
|
|
61
70
|
readonly renames: readonly DeclaredRename[];
|
|
62
71
|
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Loads the config, the schema, and the previous catalog snapshot.
|
|
74
|
+
*
|
|
75
|
+
* A `renamedFrom` that the previous catalog does not contain is OKM1020.
|
|
76
|
+
*
|
|
77
|
+
* @param cwd - Project directory
|
|
78
|
+
* @returns The loaded project
|
|
79
|
+
*/
|
|
80
|
+
export declare function openProject(cwd: string): Promise<{
|
|
81
|
+
readonly config: MigrateConfig;
|
|
82
|
+
readonly built: Built;
|
|
83
|
+
readonly previous: Catalog;
|
|
84
|
+
readonly renames: readonly DeclaredRename[];
|
|
85
|
+
}>;
|
|
63
86
|
/**
|
|
64
87
|
* Loads `okmodel.config.ts`.
|
|
65
88
|
*
|
|
@@ -67,3 +90,4 @@ export declare function projectHead(cwd: string): Promise<{
|
|
|
67
90
|
* @returns The config object
|
|
68
91
|
*/
|
|
69
92
|
export declare function loadConfig(cwd: string): Promise<MigrateConfig>;
|
|
93
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One spelling for a SQL type name in a diff (D191).
|
|
3
|
+
*
|
|
4
|
+
* The catalog keeps the spelling the schema wrote. Introspection keeps
|
|
5
|
+
* `format_type`. Both sides of a comparison pass through here, so
|
|
6
|
+
* `timestamptz` and `timestamp with time zone` are one type. A different
|
|
7
|
+
* length, precision, or type stays different. An unknown name is returned
|
|
8
|
+
* as written.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Maps a schema spelling or a `format_type` spelling to the long form.
|
|
12
|
+
*
|
|
13
|
+
* Modifiers and array ranks stay. `varchar(20)[]` becomes
|
|
14
|
+
* `character varying(20)[]`.
|
|
15
|
+
*
|
|
16
|
+
* @param typeName - Type name from a catalog definition
|
|
17
|
+
* @returns The Postgres long spelling
|
|
18
|
+
*/
|
|
19
|
+
export declare function canonicalTypeName(typeName: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "okmodel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "okmodel is a catalog-first TypeScript ORM, PostgreSQL first.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"migrations",
|
|
@@ -85,10 +85,30 @@
|
|
|
85
85
|
"./validate": {
|
|
86
86
|
"types": "./dist/runtime/validate/index.d.ts",
|
|
87
87
|
"import": "./dist/runtime/validate/index.js"
|
|
88
|
+
},
|
|
89
|
+
"./ext": {
|
|
90
|
+
"types": "./dist/dialects/pg/ext/index.d.ts",
|
|
91
|
+
"import": "./dist/dialects/pg/ext/index.js"
|
|
92
|
+
},
|
|
93
|
+
"./fn": {
|
|
94
|
+
"types": "./dist/dialects/pg/fn/index.d.ts",
|
|
95
|
+
"import": "./dist/dialects/pg/fn/index.js"
|
|
96
|
+
},
|
|
97
|
+
"./view": {
|
|
98
|
+
"types": "./dist/dialects/pg/view/index.d.ts",
|
|
99
|
+
"import": "./dist/dialects/pg/view/index.js"
|
|
100
|
+
},
|
|
101
|
+
"./pg/citext": {
|
|
102
|
+
"types": "./dist/dialects/pg/ext/citext.d.ts",
|
|
103
|
+
"import": "./dist/dialects/pg/ext/citext.js"
|
|
104
|
+
},
|
|
105
|
+
"./pg/pg_trgm": {
|
|
106
|
+
"types": "./dist/dialects/pg/ext/pg-trgm.d.ts",
|
|
107
|
+
"import": "./dist/dialects/pg/ext/pg-trgm.js"
|
|
88
108
|
}
|
|
89
109
|
},
|
|
90
110
|
"scripts": {
|
|
91
|
-
"build": "rm -rf dist && bun build ./src/contracts/index.ts ./src/contracts/internal.ts ./src/dialects/pg/index.ts ./src/runtime/pg/postgresjs.ts ./src/runtime/pg/pglite.ts ./src/runtime/pg/pg.ts ./src/runtime/pg/bun.ts ./src/runtime/ids/index.ts ./src/runtime/safety/index.ts ./src/runtime/traits/index.ts ./src/runtime/tenancy/index.ts ./src/runtime/validate/index.ts ./src/tooling/migrate/index.ts ./src/tooling/cli.ts --outdir ./dist --root ./src --format esm --target node --splitting --chunk-naming=shared/[hash].js --external postgres --external @electric-sql/pglite --external pg --external bun && bunx tsc -p tsconfig.build.json && bun ./scripts/write-bin-wrappers.ts",
|
|
111
|
+
"build": "rm -rf dist && bun build ./src/contracts/index.ts ./src/contracts/internal.ts ./src/dialects/pg/index.ts ./src/runtime/pg/postgresjs.ts ./src/runtime/pg/pglite.ts ./src/runtime/pg/pg.ts ./src/runtime/pg/bun.ts ./src/runtime/ids/index.ts ./src/runtime/safety/index.ts ./src/runtime/traits/index.ts ./src/runtime/tenancy/index.ts ./src/runtime/validate/index.ts ./src/dialects/pg/ext/index.ts ./src/dialects/pg/fn/index.ts ./src/dialects/pg/view/index.ts ./src/dialects/pg/ext/citext.ts ./src/dialects/pg/ext/pg-trgm.ts ./src/tooling/migrate/index.ts ./src/tooling/cli.ts --outdir ./dist --root ./src --format esm --target node --splitting --chunk-naming=shared/[hash].js --external postgres --external @electric-sql/pglite --external pg --external bun && bunx tsc -p tsconfig.build.json && bun ./scripts/write-bin-wrappers.ts",
|
|
92
112
|
"driver-bench": "bun ./scripts/driver-bench.ts",
|
|
93
113
|
"typecheck": "bunx tsc --noEmit -p tsconfig.json",
|
|
94
114
|
"editor-check": "bun ./scripts/editor-check.ts",
|