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,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OkmError2
|
|
3
|
+
} from "./52szzakm.js";
|
|
4
|
+
|
|
5
|
+
// src/dialects/pg/role/check.ts
|
|
6
|
+
async function assertRoleHealth(runner, roles, objects) {
|
|
7
|
+
const managed = new Set((roles.managed ?? []).map((role) => role.name));
|
|
8
|
+
const named = [roles.migration, roles.app];
|
|
9
|
+
for (const name of named) {
|
|
10
|
+
if (managed.has(name))
|
|
11
|
+
continue;
|
|
12
|
+
if (!await roleExists(runner, name)) {
|
|
13
|
+
throw new OkmError2("not_found", `Role ${name} is named in roles and does not exist.`, {
|
|
14
|
+
kind: "not_found",
|
|
15
|
+
fix: { summary: "Create the role, or list it in roles.managed so the plan creates it." }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (managed.size > 0)
|
|
20
|
+
await assertCreateRole(runner, await currentUser(runner));
|
|
21
|
+
for (const object of objects) {
|
|
22
|
+
if (object.kind !== "grant" || object.identity.role !== roles.app)
|
|
23
|
+
continue;
|
|
24
|
+
await assertGrant(runner, object);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function assertCreateRole(runner, role) {
|
|
28
|
+
const result = await runner.execute("select rolcreaterole from pg_roles where rolname = $1", [
|
|
29
|
+
role
|
|
30
|
+
]);
|
|
31
|
+
if (!truthy(result.rows[0]?.[0])) {
|
|
32
|
+
throw new OkmError2("forbidden", `Role ${role} lacks CREATEROLE. Nothing was changed.`, {
|
|
33
|
+
kind: "forbidden",
|
|
34
|
+
fix: { summary: "Grant CREATEROLE to the role that applies migrations." }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function currentUser(runner) {
|
|
39
|
+
const result = await runner.execute("select current_user");
|
|
40
|
+
const name = result.rows[0]?.[0];
|
|
41
|
+
return typeof name === "string" ? name : "";
|
|
42
|
+
}
|
|
43
|
+
async function roleExists(runner, name) {
|
|
44
|
+
const result = await runner.execute("select 1 from pg_roles where rolname = $1", [name]);
|
|
45
|
+
return result.rows.length > 0;
|
|
46
|
+
}
|
|
47
|
+
async function assertGrant(runner, object) {
|
|
48
|
+
const target = object.identity.object;
|
|
49
|
+
const schema = target.namespace.form === "static" ? target.namespace.name : "public";
|
|
50
|
+
const privilege = object.identity.privilege;
|
|
51
|
+
if (target.kind === "function") {
|
|
52
|
+
const open = target.name.lastIndexOf("(");
|
|
53
|
+
const fn = open < 0 ? target.name : target.name.slice(0, open);
|
|
54
|
+
const args = open < 0 ? "" : target.name.slice(open + 1, -1);
|
|
55
|
+
if (!await functionExists(runner, schema, fn, args))
|
|
56
|
+
return;
|
|
57
|
+
const allowed = await runner.execute("select has_function_privilege($1, format('%I.%I(%s)', $2::text, $3::text, $4::text), $5)", [object.identity.role, schema, fn, args, privilege]);
|
|
58
|
+
if (!truthy(allowed.rows[0]?.[0]))
|
|
59
|
+
missing(object, `${schema}.${fn}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (target.kind === "namespace")
|
|
63
|
+
return;
|
|
64
|
+
const relkinds = target.kind === "sequence" ? "'S'" : target.kind === "view" ? "'v'" : target.kind === "materializedView" ? "'m'" : "'r', 'p'";
|
|
65
|
+
if (!await relationExists(runner, schema, target.name, relkinds))
|
|
66
|
+
return;
|
|
67
|
+
const probe = target.kind === "sequence" ? "select has_sequence_privilege($1, format('%I.%I', $2::text, $3::text), $4)" : "select has_table_privilege($1, format('%I.%I', $2::text, $3::text), $4)";
|
|
68
|
+
const allowed = await runner.execute(probe, [
|
|
69
|
+
object.identity.role,
|
|
70
|
+
schema,
|
|
71
|
+
target.name,
|
|
72
|
+
privilege
|
|
73
|
+
]);
|
|
74
|
+
if (!truthy(allowed.rows[0]?.[0]))
|
|
75
|
+
missing(object, `${schema}.${target.name}`);
|
|
76
|
+
}
|
|
77
|
+
function missing(object, name) {
|
|
78
|
+
throw new OkmError2("OKM1825", `Role ${object.identity.role} lacks ${object.identity.privilege} on ${name}.`, {
|
|
79
|
+
kind: "forbidden",
|
|
80
|
+
fix: {
|
|
81
|
+
summary: "Grant the privilege, or change the role. okm doctor reports the object and the privilege."
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function relationExists(runner, schema, name, relkinds) {
|
|
86
|
+
const result = await runner.execute(`select 1 from pg_class c
|
|
87
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
88
|
+
where n.nspname = $1 and c.relname = $2 and c.relkind in (${relkinds})`, [schema, name]);
|
|
89
|
+
return result.rows.length > 0;
|
|
90
|
+
}
|
|
91
|
+
async function functionExists(runner, schema, name, args) {
|
|
92
|
+
const result = await runner.execute(`select 1 from pg_proc p
|
|
93
|
+
join pg_namespace n on n.oid = p.pronamespace
|
|
94
|
+
where n.nspname = $1 and p.proname = $2
|
|
95
|
+
and replace(pg_get_function_identity_arguments(p.oid), ' ', '') = $3`, [schema, name, args]);
|
|
96
|
+
return result.rows.length > 0;
|
|
97
|
+
}
|
|
98
|
+
function truthy(value) {
|
|
99
|
+
return value === true || value === "t" || value === "true";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { assertRoleHealth, assertCreateRole, currentUser, roleExists };
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
assertNamespace2,
|
|
3
2
|
identityKey2,
|
|
4
3
|
identityLabel2,
|
|
5
|
-
|
|
6
|
-
compareText,
|
|
7
|
-
assertProvenance
|
|
4
|
+
compareText
|
|
8
5
|
} from "./t4tbsy9h.js";
|
|
9
6
|
import {
|
|
10
7
|
CATALOG_VERSION2
|
|
11
8
|
} from "./4e4c6vq2.js";
|
|
12
|
-
import {
|
|
13
|
-
assertIdentifier2,
|
|
14
|
-
assertStoredText
|
|
15
|
-
} from "./nfzc5z0w.js";
|
|
16
9
|
import {
|
|
17
10
|
catalogError2
|
|
18
11
|
} from "./52szzakm.js";
|
|
@@ -142,49 +135,4 @@ function assertForeignKeys(objects, keys) {
|
|
|
142
135
|
}
|
|
143
136
|
}
|
|
144
137
|
|
|
145
|
-
|
|
146
|
-
function enumType(input) {
|
|
147
|
-
assertNamespace2(input.namespace);
|
|
148
|
-
assertIdentifier2(input.name, "type");
|
|
149
|
-
assertProvenance(input.provenance);
|
|
150
|
-
if (input.labels.length === 0) {
|
|
151
|
-
catalogError2("OKM1020", `Enum ${input.name} must list at least one label.`);
|
|
152
|
-
}
|
|
153
|
-
const labels = [];
|
|
154
|
-
const seen = new Set;
|
|
155
|
-
for (const label of input.labels) {
|
|
156
|
-
assertStoredText(label, "enum label");
|
|
157
|
-
if (label.length === 0) {
|
|
158
|
-
catalogError2("OKM1020", `Enum ${input.name} has an empty label.`);
|
|
159
|
-
}
|
|
160
|
-
if (seen.has(label)) {
|
|
161
|
-
catalogError2("OKM1020", `Enum ${input.name} repeats label ${label}.`);
|
|
162
|
-
}
|
|
163
|
-
seen.add(label);
|
|
164
|
-
labels.push(label);
|
|
165
|
-
}
|
|
166
|
-
const identity = {
|
|
167
|
-
kind: "type",
|
|
168
|
-
namespace: input.namespace,
|
|
169
|
-
name: input.name
|
|
170
|
-
};
|
|
171
|
-
return {
|
|
172
|
-
kind: "type",
|
|
173
|
-
identity,
|
|
174
|
-
owner: input.owner ?? "managed",
|
|
175
|
-
definition: { labels },
|
|
176
|
-
dependencies: normaliseEdges(input.dependencies ?? []),
|
|
177
|
-
provenance: input.provenance
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
function sameEnumLabels(left, right) {
|
|
181
|
-
if (left.length !== right.length)
|
|
182
|
-
return false;
|
|
183
|
-
for (let index = 0;index < left.length; index += 1) {
|
|
184
|
-
if (left[index] !== right[index])
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export { dependencyOrder, catalog, enumType, sameEnumLabels };
|
|
138
|
+
export { dependencyOrder, catalog };
|
|
@@ -72,7 +72,7 @@ function openClient(session) {
|
|
|
72
72
|
},
|
|
73
73
|
close,
|
|
74
74
|
connected: session.connected,
|
|
75
|
-
tx: (...args) => import("./
|
|
75
|
+
tx: (...args) => import("./m78s7898.js").then((mod) => mod.tx(session, args)),
|
|
76
76
|
batch: (ops, options) => batchHandle(session, ops, options),
|
|
77
77
|
...session.tx?.extras
|
|
78
78
|
};
|
|
@@ -107,7 +107,7 @@ function tableApi(session, table, view, uses) {
|
|
|
107
107
|
const api = {
|
|
108
108
|
find(options = {}) {
|
|
109
109
|
if ("lock" in options) {
|
|
110
|
-
return lazyRead(session, () => import("./
|
|
110
|
+
return lazyRead(session, () => import("./ydaz1sv3.js"), table, options, base, view);
|
|
111
111
|
}
|
|
112
112
|
return start(session, "find", table, options, base, view);
|
|
113
113
|
},
|
|
@@ -121,10 +121,10 @@ function tableApi(session, table, view, uses) {
|
|
|
121
121
|
return start(session, "exists", table, options, base, view);
|
|
122
122
|
},
|
|
123
123
|
page(options) {
|
|
124
|
-
return lazyRead(session, () => import("./
|
|
124
|
+
return lazyRead(session, () => import("./p24x2334.js"), table, options, base, view);
|
|
125
125
|
},
|
|
126
126
|
aggregate(options = {}) {
|
|
127
|
-
return lazyRead(session, () => import("./
|
|
127
|
+
return lazyRead(session, () => import("./3ekj9x92.js"), table, options, base, view);
|
|
128
128
|
},
|
|
129
129
|
insert(data, options = {}) {
|
|
130
130
|
return writeHandle(session, "insert", table, data, options, mods);
|
|
@@ -154,13 +154,13 @@ function tableApi(session, table, view, uses) {
|
|
|
154
154
|
return api;
|
|
155
155
|
}
|
|
156
156
|
function batchHandle(session, ops, options, replica) {
|
|
157
|
-
return queryHandle(() => import("./
|
|
157
|
+
return queryHandle(() => import("./mt5wswjz.js").then((mod) => mod.batch(session, ops, options, replica)), {
|
|
158
158
|
replica: () => batchHandle(session, ops, options, true)
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
var writers;
|
|
162
162
|
function loadWrite() {
|
|
163
|
-
writers ??= import("./
|
|
163
|
+
writers ??= import("./xva8v7qk.js");
|
|
164
164
|
return writers;
|
|
165
165
|
}
|
|
166
166
|
function queryHandle(run, extra) {
|
|
@@ -320,7 +320,7 @@ function readHandle(session, table, call, mods, decode, extra) {
|
|
|
320
320
|
}
|
|
321
321
|
function streamLazy(session, call, prepare) {
|
|
322
322
|
return async function* () {
|
|
323
|
-
const { streamRows } = await import("./
|
|
323
|
+
const { streamRows } = await import("./bryqk9k9.js");
|
|
324
324
|
yield* streamRows(session, call, prepare, (error) => logged(session, error));
|
|
325
325
|
}();
|
|
326
326
|
}
|
|
@@ -357,7 +357,7 @@ function readCall(op, table, options, all, scope, model, schema, view) {
|
|
|
357
357
|
};
|
|
358
358
|
}
|
|
359
359
|
async function checkServer(pool, schema, http, requireMeta, options, source) {
|
|
360
|
-
const server = await import("./
|
|
360
|
+
const server = await import("./ty3v3hfk.js");
|
|
361
361
|
let rows;
|
|
362
362
|
try {
|
|
363
363
|
const result = await pool.execute(server.versionQuery, undefined, options);
|
|
@@ -386,7 +386,7 @@ function errorFields(error) {
|
|
|
386
386
|
var includeHooks;
|
|
387
387
|
var operatorSql;
|
|
388
388
|
function loadOperatorSql() {
|
|
389
|
-
operatorSql ??= import("./
|
|
389
|
+
operatorSql ??= import("./axhk06q1.js").then(() => {
|
|
390
390
|
return;
|
|
391
391
|
});
|
|
392
392
|
return operatorSql;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
open3
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./75xkjv0t.js";
|
|
4
4
|
import {
|
|
5
5
|
PGLITE_CAPABILITIES,
|
|
6
6
|
readCapability2,
|
|
7
7
|
hasCapability2
|
|
8
|
-
} from "./
|
|
8
|
+
} from "./rrstp3kb.js";
|
|
9
9
|
export {
|
|
10
10
|
PGLITE_CAPABILITIES as capabilities,
|
|
11
11
|
hasCapability2 as hasCapability,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
open2
|
|
3
|
+
} from "./xw1d69vd.js";
|
|
4
|
+
import"./t616ynfn.js";
|
|
5
|
+
import"./n442h54c.js";
|
|
6
|
+
import {
|
|
7
|
+
assertTargetPolicy,
|
|
8
|
+
selectTarget,
|
|
9
|
+
openProject
|
|
10
|
+
} from "./5nmdenb6.js";
|
|
11
|
+
import"./2ssqrv66.js";
|
|
12
|
+
import {
|
|
13
|
+
isExactVersion,
|
|
14
|
+
compareExtensionVersions
|
|
15
|
+
} from "./th14ygv2.js";
|
|
16
|
+
import {
|
|
17
|
+
OkmError2
|
|
18
|
+
} from "./52szzakm.js";
|
|
19
|
+
|
|
20
|
+
// src/tooling/migrate/ext.ts
|
|
21
|
+
async function extProject(cwd, command, flags) {
|
|
22
|
+
const opened = await openProject(cwd);
|
|
23
|
+
const target = selectTarget(opened.config, flags.target);
|
|
24
|
+
assertTargetPolicy(target, "check", flags.allowProtected);
|
|
25
|
+
const pool = open2({ url: target.url, max: 1 });
|
|
26
|
+
try {
|
|
27
|
+
if (command === "list")
|
|
28
|
+
return formatList(await readExtensions(pool));
|
|
29
|
+
return formatCheck(opened.built.catalog.objects, await readExtensions(pool));
|
|
30
|
+
} finally {
|
|
31
|
+
await pool.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var LIST_SQL = `
|
|
35
|
+
select a.name, a.default_version, e.extversion, n.nspname
|
|
36
|
+
from pg_available_extensions a
|
|
37
|
+
left join pg_extension e on e.extname = a.name
|
|
38
|
+
left join pg_namespace n on n.oid = e.extnamespace
|
|
39
|
+
order by a.name
|
|
40
|
+
`;
|
|
41
|
+
async function readExtensions(pool) {
|
|
42
|
+
const result = await pool.execute(LIST_SQL);
|
|
43
|
+
return result.rows.map((row) => ({
|
|
44
|
+
name: cell(row[0]),
|
|
45
|
+
defaultVersion: cell(row[1]),
|
|
46
|
+
installedVersion: cell(row[2]),
|
|
47
|
+
schema: cell(row[3])
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
function cell(value) {
|
|
51
|
+
return typeof value === "string" ? value : "";
|
|
52
|
+
}
|
|
53
|
+
function formatList(rows) {
|
|
54
|
+
const lines = ["name\tdefault\tinstalled\tschema"];
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
lines.push([row.name, row.defaultVersion, row.installedVersion, row.schema].join("\t"));
|
|
57
|
+
}
|
|
58
|
+
return `${lines.join(`
|
|
59
|
+
`)}
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
function formatCheck(objects, server) {
|
|
63
|
+
const declared = objects.filter((object) => object.kind === "extension");
|
|
64
|
+
if (declared.length === 0)
|
|
65
|
+
return `no extensions
|
|
66
|
+
`;
|
|
67
|
+
const installed = new Map(server.map((row) => [row.name, row.installedVersion]));
|
|
68
|
+
const lines = ["name\tdeclared\tinstalled"];
|
|
69
|
+
for (const object of [...declared].sort((left, right) => left.identity.name < right.identity.name ? -1 : 1)) {
|
|
70
|
+
const name = object.identity.name;
|
|
71
|
+
const have = installed.get(name) ?? "";
|
|
72
|
+
if (have.length === 0) {
|
|
73
|
+
throw new OkmError2("OKM1811", `Extension ${name} is not installed on the server.`, {
|
|
74
|
+
fix: { summary: "Install the extension, or remove the declaration." }
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const want = object.definition.version;
|
|
78
|
+
if (!versionAccepted(want, have)) {
|
|
79
|
+
throw new OkmError2("OKM1812", `Extension ${name} is ${have} on the server. The schema requires ${want ?? ""}.`, { fix: { summary: "Install a version the declaration accepts, or change the pin." } });
|
|
80
|
+
}
|
|
81
|
+
lines.push([name, want ?? "-", have].join("\t"));
|
|
82
|
+
}
|
|
83
|
+
return `${lines.join(`
|
|
84
|
+
`)}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
function versionAccepted(declared, installed) {
|
|
88
|
+
if (declared === undefined)
|
|
89
|
+
return true;
|
|
90
|
+
const floor = /^>=(\d+(?:\.\d+)*)$/.exec(declared);
|
|
91
|
+
const minimum = floor?.[1];
|
|
92
|
+
if (minimum !== undefined) {
|
|
93
|
+
return isExactVersion(installed) && compareExtensionVersions(installed, minimum) >= 0;
|
|
94
|
+
}
|
|
95
|
+
return declared === installed;
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
extProject
|
|
99
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
open2
|
|
3
|
+
} from "./xw1d69vd.js";
|
|
4
|
+
import"./n442h54c.js";
|
|
5
|
+
import"./t616ynfn.js";
|
|
6
|
+
import {
|
|
7
|
+
assertRoleHealth
|
|
8
|
+
} from "./hcmdtwgh.js";
|
|
9
|
+
import {
|
|
10
|
+
errorDoc,
|
|
11
|
+
selectTarget,
|
|
12
|
+
openProject
|
|
13
|
+
} from "./5nmdenb6.js";
|
|
14
|
+
import {
|
|
15
|
+
omitManagedObjects
|
|
16
|
+
} from "./2ssqrv66.js";
|
|
17
|
+
import {
|
|
18
|
+
OkmError2
|
|
19
|
+
} from "./52szzakm.js";
|
|
20
|
+
|
|
21
|
+
// src/tooling/migrate/doctor.ts
|
|
22
|
+
async function doctorProject(cwd, code, flags) {
|
|
23
|
+
if (code !== undefined) {
|
|
24
|
+
const doc = errorDoc(code);
|
|
25
|
+
if (doc === undefined) {
|
|
26
|
+
throw new OkmError2("invalid", `Unknown code ${code}.`, {
|
|
27
|
+
fix: { summary: "Pass a code from the registry, or run okm doctor with no argument." }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return `${doc.code}: ${doc.title}
|
|
31
|
+
${doc.summary}
|
|
32
|
+
${doc.fix}
|
|
33
|
+
`;
|
|
34
|
+
}
|
|
35
|
+
const opened = await openProject(cwd);
|
|
36
|
+
const objects = omitManagedObjects(opened.built.catalog).objects;
|
|
37
|
+
if (opened.config.roles !== undefined) {
|
|
38
|
+
const target = selectTarget(opened.config, flags?.target);
|
|
39
|
+
const pool = open2({ url: target.url, max: 1 });
|
|
40
|
+
try {
|
|
41
|
+
await assertRoleHealth(pool, opened.config.roles, objects);
|
|
42
|
+
} finally {
|
|
43
|
+
await pool.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return formatTriggers(objects);
|
|
47
|
+
}
|
|
48
|
+
function formatTriggers(objects) {
|
|
49
|
+
const tables = new Map;
|
|
50
|
+
for (const object of objects) {
|
|
51
|
+
if (object.kind !== "trigger")
|
|
52
|
+
continue;
|
|
53
|
+
const table = object.identity.parent.name;
|
|
54
|
+
const names = tables.get(table) ?? [];
|
|
55
|
+
names.push(object.identity.name);
|
|
56
|
+
tables.set(table, names);
|
|
57
|
+
}
|
|
58
|
+
if (tables.size === 0)
|
|
59
|
+
return `no triggers
|
|
60
|
+
`;
|
|
61
|
+
const lines = [...tables.entries()].sort((left, right) => left[0] < right[0] ? -1 : left[0] > right[0] ? 1 : 0).map(([table, names]) => `${table}: ${[...names].sort().join(", ")}`);
|
|
62
|
+
return `${lines.join(`
|
|
63
|
+
`)}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
doctorProject
|
|
68
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertNamespace2,
|
|
3
|
+
normaliseEdges,
|
|
4
|
+
assertProvenance
|
|
5
|
+
} from "./t4tbsy9h.js";
|
|
6
|
+
import {
|
|
7
|
+
assertIdentifier2,
|
|
8
|
+
assertStoredText
|
|
9
|
+
} from "./nfzc5z0w.js";
|
|
10
|
+
import {
|
|
11
|
+
catalogError2
|
|
12
|
+
} from "./52szzakm.js";
|
|
13
|
+
|
|
14
|
+
// src/contracts/catalog/enum.ts
|
|
15
|
+
function enumType(input) {
|
|
16
|
+
assertNamespace2(input.namespace);
|
|
17
|
+
assertIdentifier2(input.name, "type");
|
|
18
|
+
assertProvenance(input.provenance);
|
|
19
|
+
if (input.labels.length === 0) {
|
|
20
|
+
catalogError2("OKM1020", `Enum ${input.name} must list at least one label.`);
|
|
21
|
+
}
|
|
22
|
+
const labels = [];
|
|
23
|
+
const seen = new Set;
|
|
24
|
+
for (const label of input.labels) {
|
|
25
|
+
assertStoredText(label, "enum label");
|
|
26
|
+
if (label.length === 0) {
|
|
27
|
+
catalogError2("OKM1020", `Enum ${input.name} has an empty label.`);
|
|
28
|
+
}
|
|
29
|
+
if (seen.has(label)) {
|
|
30
|
+
catalogError2("OKM1020", `Enum ${input.name} repeats label ${label}.`);
|
|
31
|
+
}
|
|
32
|
+
seen.add(label);
|
|
33
|
+
labels.push(label);
|
|
34
|
+
}
|
|
35
|
+
const identity = {
|
|
36
|
+
kind: "type",
|
|
37
|
+
namespace: input.namespace,
|
|
38
|
+
name: input.name
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
kind: "type",
|
|
42
|
+
identity,
|
|
43
|
+
owner: input.owner ?? "managed",
|
|
44
|
+
definition: { labels },
|
|
45
|
+
dependencies: normaliseEdges(input.dependencies ?? []),
|
|
46
|
+
provenance: input.provenance
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function domainType(input) {
|
|
50
|
+
assertNamespace2(input.namespace);
|
|
51
|
+
assertIdentifier2(input.name, "type");
|
|
52
|
+
assertProvenance(input.provenance);
|
|
53
|
+
if (input.base.length === 0) {
|
|
54
|
+
catalogError2("OKM1020", `Domain ${input.name} needs a base type.`);
|
|
55
|
+
}
|
|
56
|
+
assertStoredText(input.check, "domain check");
|
|
57
|
+
if (input.check.length === 0) {
|
|
58
|
+
catalogError2("OKM1020", `Domain ${input.name} needs a check.`);
|
|
59
|
+
}
|
|
60
|
+
const identity = {
|
|
61
|
+
kind: "type",
|
|
62
|
+
namespace: input.namespace,
|
|
63
|
+
name: input.name
|
|
64
|
+
};
|
|
65
|
+
const definition = { base: input.base, check: input.check };
|
|
66
|
+
return {
|
|
67
|
+
kind: "type",
|
|
68
|
+
identity,
|
|
69
|
+
owner: input.owner ?? "managed",
|
|
70
|
+
definition,
|
|
71
|
+
dependencies: normaliseEdges(input.dependencies ?? []),
|
|
72
|
+
provenance: input.provenance
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function isDomain(definition) {
|
|
76
|
+
return "base" in definition;
|
|
77
|
+
}
|
|
78
|
+
function sameEnumLabels(left, right) {
|
|
79
|
+
if (left.length !== right.length)
|
|
80
|
+
return false;
|
|
81
|
+
for (let index = 0;index < left.length; index += 1) {
|
|
82
|
+
if (left[index] !== right[index])
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { enumType, domainType, isDomain, sameEnumLabels };
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
open2
|
|
3
|
-
} from "./
|
|
4
|
-
import"./
|
|
3
|
+
} from "./xw1d69vd.js";
|
|
4
|
+
import"./t616ynfn.js";
|
|
5
5
|
import"./n442h54c.js";
|
|
6
6
|
import {
|
|
7
7
|
loadMigrations
|
|
8
|
-
} from "./
|
|
8
|
+
} from "./g4f5kcx9.js";
|
|
9
9
|
import {
|
|
10
10
|
assertTargetPolicy,
|
|
11
11
|
listTargets,
|
|
12
12
|
loadConfig
|
|
13
|
-
} from "./
|
|
13
|
+
} from "./5nmdenb6.js";
|
|
14
|
+
import"./2ssqrv66.js";
|
|
14
15
|
import {
|
|
15
16
|
OkmError2
|
|
16
17
|
} from "./52szzakm.js";
|