okmodel 0.5.1 → 0.6.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 +29 -14
- package/dist/adapters/pg/no-inflight-timeout.d.ts +17 -0
- package/dist/adapters/pg/postgres-extra.d.ts +22 -0
- package/dist/contracts/catalog/document.d.ts +19 -5
- package/dist/contracts/catalog/object.d.ts +2 -1
- package/dist/contracts/catalog/policy.d.ts +48 -0
- package/dist/contracts/catalog/types.d.ts +25 -1
- package/dist/contracts/catalog/view.d.ts +2 -0
- package/dist/contracts/internal.js +1 -1
- package/dist/contracts/location.d.ts +10 -0
- package/dist/dialects/pg/column.d.ts +13 -2
- package/dist/dialects/pg/ddl.d.ts +37 -1
- package/dist/dialects/pg/emit.d.ts +19 -1
- package/dist/dialects/pg/errors.d.ts +32 -1
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/pg-trgm.js +1 -1
- package/dist/dialects/pg/filter-parse.d.ts +5 -4
- package/dist/dialects/pg/fn/index.js +2 -2
- package/dist/dialects/pg/index.d.ts +2 -1
- package/dist/dialects/pg/index.js +23 -17
- package/dist/dialects/pg/introspect.d.ts +7 -0
- package/dist/dialects/pg/model.d.ts +7 -2
- package/dist/dialects/pg/owner.d.ts +42 -0
- package/dist/dialects/pg/path-endpoint.d.ts +20 -0
- package/dist/dialects/pg/role/check.d.ts +3 -0
- package/dist/dialects/pg/role/index.d.ts +71 -6
- package/dist/dialects/pg/role/sql.d.ts +11 -0
- package/dist/dialects/pg/schema.d.ts +2 -0
- package/dist/dialects/pg/table.d.ts +25 -3
- package/dist/dialects/pg/tenancy.d.ts +45 -3
- package/dist/dialects/pg/view/client.d.ts +19 -1
- package/dist/dialects/pg/view/index.d.ts +4 -0
- package/dist/dialects/pg/view/index.js +21 -178
- package/dist/dialects/pg/view/refresh.d.ts +24 -0
- package/dist/runtime/batch.d.ts +1 -1
- package/dist/runtime/conflict.d.ts +2 -2
- package/dist/runtime/drift.d.ts +9 -0
- package/dist/runtime/inflight.d.ts +14 -0
- package/dist/runtime/pg/bun.js +4 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +4 -3
- package/dist/runtime/pg/postgresjs.js +3 -3
- package/dist/runtime/plan.d.ts +18 -10
- package/dist/runtime/predicate.d.ts +19 -0
- package/dist/runtime/safety/index.js +1 -1
- package/dist/runtime/tenancy/composite.d.ts +26 -0
- package/dist/runtime/tenancy/context.d.ts +16 -0
- package/dist/runtime/tenancy/index.d.ts +9 -5
- package/dist/runtime/tenancy/index.js +1508 -37
- package/dist/runtime/tenancy/path.d.ts +87 -0
- package/dist/runtime/tenancy/rls.d.ts +67 -0
- package/dist/runtime/tenancy/via.d.ts +22 -0
- package/dist/runtime/traits/index.js +17 -11
- package/dist/runtime/types.d.ts +13 -1
- package/dist/runtime/validate/index.js +4 -4
- package/dist/runtime/write.d.ts +1 -1
- package/dist/shared/09p049xa.js +702 -0
- package/dist/shared/{6qd27mx0.js → 1f0xa3cb.js} +5 -5
- package/dist/shared/1nw1f3vs.js +23 -0
- package/dist/shared/{96qcj21c.js → 1z04fa85.js} +19 -9
- package/dist/shared/{qm7cdtvr.js → 2cg3wnxc.js} +296 -60
- package/dist/shared/{dyj86cmj.js → 2jd1sn0e.js} +2 -2
- package/dist/shared/{gbtcc2d7.js → 2z7wv5tj.js} +10 -35
- package/dist/shared/{k8v5v5wj.js → 32cnm7kn.js} +6 -1
- package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
- package/dist/shared/{2pqx26h8.js → 3fqwmr09.js} +31 -22
- package/dist/shared/{zqrnhwsq.js → 3qnhc7w5.js} +16 -9
- package/dist/shared/{r2sp8hrc.js → 5d8t84hg.js} +12 -3
- package/dist/shared/{87jvvhnt.js → 5j36z8dn.js} +16 -5
- package/dist/shared/{1g0drakv.js → 5yv4k6a6.js} +1 -1
- package/dist/shared/8dqhth8c.js +12 -0
- package/dist/shared/8etn7d8w.js +62 -0
- package/dist/shared/{v36c5g6p.js → 8x72s86k.js} +400 -13
- package/dist/shared/{nxdp2ze3.js → 929h19xp.js} +107 -5
- package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
- package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
- package/dist/shared/{efmy2gcg.js → ag4c7516.js} +1 -1
- package/dist/shared/b3awxn7h.js +45 -0
- package/dist/shared/b4v57v3x.js +9 -0
- package/dist/shared/bdk4sty6.js +58 -0
- package/dist/shared/{51mvgj8w.js → c58secgj.js} +100 -7
- package/dist/shared/d5azex6s.js +6 -0
- package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
- package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
- package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
- package/dist/shared/{sycnx8gt.js → f0f1n281.js} +18 -8
- package/dist/shared/{f5cw5q5r.js → g90m9b0g.js} +2 -1
- package/dist/shared/{pf0d8f77.js → gwn6v667.js} +1 -1
- package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
- package/dist/shared/{5enne4ma.js → hazqqecq.js} +17 -93
- package/dist/shared/{jwtxdj06.js → j3rkk835.js} +32 -9
- package/dist/shared/{hf22e0wt.js → j60w0dvr.js} +19 -18
- package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
- package/dist/shared/k68eedmy.js +85 -0
- package/dist/shared/{szm0cksa.js → knmes2kh.js} +34 -6
- package/dist/shared/{0t22wwh1.js → mb2ycs1p.js} +4 -2
- package/dist/shared/{cr74e96e.js → n076ydsc.js} +1 -1
- package/dist/shared/{cctw17hj.js → nx9hh281.js} +31 -28
- package/dist/shared/{gde73es6.js → p248q79y.js} +56 -55
- package/dist/shared/{janx09m5.js → p6bjzq9q.js} +11 -7
- package/dist/shared/{6rk2gen5.js → pjr6xrm5.js} +2 -2
- package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
- package/dist/shared/{caw8b9d8.js → q3j1tq7a.js} +35 -22
- package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
- package/dist/shared/{tm5ab8we.js → r11n8grd.js} +2 -2
- package/dist/shared/r1fdd0f6.js +19 -0
- package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
- package/dist/shared/rhs3xe4k.js +7 -0
- package/dist/shared/{ntneex2a.js → rpycarcr.js} +6 -6
- package/dist/shared/{aj2qxyhj.js → sbdme3vy.js} +14 -2
- package/dist/shared/{qv2ydck9.js → t3g0k88x.js} +638 -67
- package/dist/shared/{ga3sfy93.js → ttmg09vd.js} +535 -200
- package/dist/shared/{kfjp0gck.js → venqrjna.js} +8 -4
- package/dist/shared/{fancm5pt.js → vjpnzwjz.js} +138 -15
- package/dist/shared/{32zqc1dw.js → vmfkhszw.js} +31 -7
- package/dist/shared/{krxx77g0.js → wkme6tep.js} +10 -8
- package/dist/shared/{ps7a6h14.js → wt5rzv1h.js} +12 -8
- package/dist/shared/wxr8cwns.js +6 -0
- package/dist/shared/{6mnp99hx.js → wynzeggs.js} +16 -12
- package/dist/shared/x3jc53kg.js +220 -0
- package/dist/shared/{sdc7r2ww.js → xq0mvhts.js} +8 -8
- package/dist/shared/xqve9598.js +53 -0
- package/dist/shared/{47x8x9ze.js → y2t3jktd.js} +2 -2
- package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
- package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
- package/dist/shared/{nkaxvt9q.js → ys0xzyaj.js} +1 -1
- package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
- package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
- package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
- package/dist/shared/{r8x5qhd7.js → zm0mafk4.js} +10 -4
- package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
- package/dist/tooling/cli.js +41 -15
- package/dist/tooling/migrate/apply.d.ts +14 -0
- package/dist/tooling/migrate/check.d.ts +3 -4
- package/dist/tooling/migrate/classify.d.ts +4 -0
- package/dist/tooling/migrate/config.d.ts +3 -2
- package/dist/tooling/migrate/files.d.ts +11 -1
- package/dist/tooling/migrate/index.js +14 -14
- package/dist/tooling/migrate/lint.d.ts +1 -1
- package/dist/tooling/migrate/lost.d.ts +28 -0
- package/dist/tooling/migrate/paths.d.ts +14 -0
- package/dist/tooling/migrate/plan.d.ts +6 -3
- package/dist/tooling/migrate/runner.d.ts +25 -0
- package/dist/tooling/migrate/sandbox.d.ts +57 -0
- package/dist/tooling/migrate/sql-lex.d.ts +20 -3
- package/dist/tooling/migrate/text.d.ts +42 -0
- package/dist/tooling/node-version.d.ts +21 -0
- package/dist/tooling/testing/facts.d.ts +33 -5
- package/dist/tooling/testing/index.d.ts +1 -1
- package/dist/tooling/testing/index.js +3 -3
- package/dist/tooling/testing/isolation.d.ts +11 -5
- package/package.json +5 -2
- package/dist/shared/7zwwyh0v.js +0 -448
- package/dist/shared/q58y17hy.js +0 -21
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
creationOrder2
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./qq3899ht.js";
|
|
4
4
|
import {
|
|
5
5
|
isDomain
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./ywspezzx.js";
|
|
7
7
|
import {
|
|
8
8
|
quoteLiteral
|
|
9
9
|
} from "./94ez8kzh.js";
|
|
10
10
|
import {
|
|
11
11
|
identityKey2
|
|
12
|
-
} from "./
|
|
12
|
+
} from "./358zsv4r.js";
|
|
13
13
|
import {
|
|
14
14
|
fitIdentifier2
|
|
15
15
|
} from "./nfzc5z0w.js";
|
|
@@ -22,6 +22,7 @@ function renderCatalog(source, schema) {
|
|
|
22
22
|
const folded = foldedKeys(source);
|
|
23
23
|
const statements = [];
|
|
24
24
|
const ordered = creationOrder2(source);
|
|
25
|
+
const created = uniqueBeforeForeignKey(ordered);
|
|
25
26
|
for (const object of ordered) {
|
|
26
27
|
if (object.kind !== "type" || object.owner === "ignored")
|
|
27
28
|
continue;
|
|
@@ -29,8 +30,8 @@ function renderCatalog(source, schema) {
|
|
|
29
30
|
if (sql !== undefined)
|
|
30
31
|
statements.push(sql);
|
|
31
32
|
}
|
|
32
|
-
for (const object of
|
|
33
|
-
if (object.kind === "type" || object.kind === "function" || object.kind === "trigger" || object.kind === "view" || object.kind === "materializedView" || ownedByView(object)) {
|
|
33
|
+
for (const object of created) {
|
|
34
|
+
if (object.kind === "type" || object.kind === "function" || object.kind === "trigger" || object.kind === "view" || object.kind === "materializedView" || object.kind === "policy" || ownedByView(object)) {
|
|
34
35
|
continue;
|
|
35
36
|
}
|
|
36
37
|
if (object.owner === "ignored")
|
|
@@ -46,6 +47,12 @@ function renderCatalog(source, schema) {
|
|
|
46
47
|
if (sql !== undefined)
|
|
47
48
|
statements.push(sql);
|
|
48
49
|
}
|
|
50
|
+
for (const object of created) {
|
|
51
|
+
if (object.kind !== "policy" || object.owner === "ignored")
|
|
52
|
+
continue;
|
|
53
|
+
for (const step of policyCreatePlan(object, schema))
|
|
54
|
+
statements.push(step.sql);
|
|
55
|
+
}
|
|
49
56
|
for (const kind of ["function", "trigger"]) {
|
|
50
57
|
for (const object of ordered) {
|
|
51
58
|
if (object.kind !== kind || object.owner === "ignored")
|
|
@@ -73,6 +80,48 @@ function renderCatalog(source, schema) {
|
|
|
73
80
|
}
|
|
74
81
|
return statements;
|
|
75
82
|
}
|
|
83
|
+
function uniqueBeforeForeignKey(objects) {
|
|
84
|
+
const uniques = objects.filter((object) => object.kind === "constraint" && object.definition.constraintKind === "unique");
|
|
85
|
+
if (uniques.length === 0)
|
|
86
|
+
return objects;
|
|
87
|
+
const emitted = new Set;
|
|
88
|
+
const result = [];
|
|
89
|
+
for (const object of objects) {
|
|
90
|
+
if (emitted.has(object))
|
|
91
|
+
continue;
|
|
92
|
+
if (object.kind === "constraint" && object.definition.constraintKind === "foreignKey") {
|
|
93
|
+
const target = object.definition.references;
|
|
94
|
+
if (target !== undefined && !coveredByPrimary(objects, target.parent, target.columns)) {
|
|
95
|
+
const columns = target.columns.join("\x00");
|
|
96
|
+
for (const unique of uniques) {
|
|
97
|
+
if (emitted.has(unique))
|
|
98
|
+
continue;
|
|
99
|
+
if (!sameRef(unique.identity.parent, target.parent))
|
|
100
|
+
continue;
|
|
101
|
+
if (unique.definition.columns.join("\x00") !== columns)
|
|
102
|
+
continue;
|
|
103
|
+
result.push(unique);
|
|
104
|
+
emitted.add(unique);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
result.push(object);
|
|
109
|
+
emitted.add(object);
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
function coveredByPrimary(objects, parent, columns) {
|
|
114
|
+
const key = columns.join("\x00");
|
|
115
|
+
return objects.some((object) => object.kind === "constraint" && object.definition.constraintKind === "primaryKey" && sameRef(object.identity.parent, parent) && object.definition.columns.join("\x00") === key);
|
|
116
|
+
}
|
|
117
|
+
function sameRef(left, right) {
|
|
118
|
+
if (left.name !== right.name || left.namespace.form !== right.namespace.form)
|
|
119
|
+
return false;
|
|
120
|
+
if (left.namespace.form === "static" && right.namespace.form === "static") {
|
|
121
|
+
return left.namespace.name === right.namespace.name;
|
|
122
|
+
}
|
|
123
|
+
return left.namespace.form === "template" && right.namespace.form === "template" ? left.namespace.pattern === right.namespace.pattern : false;
|
|
124
|
+
}
|
|
76
125
|
function ownedByView(object) {
|
|
77
126
|
if (object.kind !== "index")
|
|
78
127
|
return false;
|
|
@@ -149,7 +198,39 @@ function functionSql(object, schema, replace) {
|
|
|
149
198
|
}
|
|
150
199
|
function viewSql(object, schema, replace) {
|
|
151
200
|
const verb = replace ? "create or replace view" : "create view";
|
|
152
|
-
|
|
201
|
+
const invoker = object.definition.securityInvoker === true ? " with (security_invoker = true)" : "";
|
|
202
|
+
return `${verb} ${qualify(schema, object.identity.name)}${invoker} as ${object.definition.query}`;
|
|
203
|
+
}
|
|
204
|
+
function policyCreatePlan(object, schema) {
|
|
205
|
+
const table = qualify(schema, object.identity.parent.name);
|
|
206
|
+
const name = quoteIdent(object.identity.name);
|
|
207
|
+
const command = object.definition.command === "all" ? "all" : "select";
|
|
208
|
+
const check = object.definition.command === "all" ? ` with check ${object.definition.expression}` : "";
|
|
209
|
+
const create = {
|
|
210
|
+
sql: `create policy ${name} on ${table} as permissive for ${command} using ${object.definition.expression}${check}`,
|
|
211
|
+
kind: "create-policy"
|
|
212
|
+
};
|
|
213
|
+
if (object.definition.command !== "all")
|
|
214
|
+
return [create];
|
|
215
|
+
return [
|
|
216
|
+
{ sql: `alter table ${table} enable row level security`, kind: "enable-rls" },
|
|
217
|
+
{ sql: `alter table ${table} force row level security`, kind: "enable-rls" },
|
|
218
|
+
create
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
function policyDropPlan(object, schema) {
|
|
222
|
+
const table = qualify(schema, object.identity.parent.name);
|
|
223
|
+
const drop = {
|
|
224
|
+
sql: `drop policy ${quoteIdent(object.identity.name)} on ${table}`,
|
|
225
|
+
kind: "drop-policy"
|
|
226
|
+
};
|
|
227
|
+
if (object.definition.command !== "all")
|
|
228
|
+
return [drop];
|
|
229
|
+
return [
|
|
230
|
+
drop,
|
|
231
|
+
{ sql: `alter table ${table} no force row level security`, kind: "disable-rls" },
|
|
232
|
+
{ sql: `alter table ${table} disable row level security`, kind: "disable-rls" }
|
|
233
|
+
];
|
|
153
234
|
}
|
|
154
235
|
function materializedViewSql(object, schema) {
|
|
155
236
|
return `create materialized view ${qualify(schema, object.identity.name)} as ${object.definition.query} with no data`;
|
|
@@ -315,4 +396,4 @@ function qualify(schema, name) {
|
|
|
315
396
|
return `${quoteIdent(schema)}.${quoteIdent(name)}`;
|
|
316
397
|
}
|
|
317
398
|
|
|
318
|
-
export { quoteIdent, renderCatalog, ownedByView, dropObjectSql, createObjectSql, functionSql, viewSql, refreshMaterializedViewSql, alterColumnSql, identitySequence, createTableSql, qualify };
|
|
399
|
+
export { quoteIdent, renderCatalog, uniqueBeforeForeignKey, ownedByView, dropObjectSql, createObjectSql, functionSql, viewSql, policyCreatePlan, policyDropPlan, refreshMaterializedViewSql, alterColumnSql, identitySequence, createTableSql, qualify };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord,
|
|
3
|
+
orFail
|
|
4
|
+
} from "./2z7wv5tj.js";
|
|
5
|
+
import {
|
|
6
|
+
isOperator,
|
|
7
|
+
operatorName,
|
|
8
|
+
operatorValue
|
|
9
|
+
} from "./cn0n68ft.js";
|
|
10
|
+
|
|
11
|
+
// src/runtime/predicate.ts
|
|
12
|
+
function effectivePredicate(where) {
|
|
13
|
+
if (where === undefined)
|
|
14
|
+
return false;
|
|
15
|
+
if (isOperator(where)) {
|
|
16
|
+
const name = operatorName(where);
|
|
17
|
+
const value = operatorValue(where);
|
|
18
|
+
if (name === "or") {
|
|
19
|
+
if (!Array.isArray(value))
|
|
20
|
+
orFail(false);
|
|
21
|
+
if (value.length === 0)
|
|
22
|
+
return true;
|
|
23
|
+
for (const branch of value) {
|
|
24
|
+
if (!effectivePredicate(branch))
|
|
25
|
+
orFail(true);
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (name === "and") {
|
|
30
|
+
return Array.isArray(value) && value.some((part) => effectivePredicate(part));
|
|
31
|
+
}
|
|
32
|
+
if (name === "not")
|
|
33
|
+
return effectivePredicate(value);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
if (!isRecord(where))
|
|
37
|
+
return true;
|
|
38
|
+
for (const key of Object.keys(where)) {
|
|
39
|
+
if (where[key] !== undefined)
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { effectivePredicate };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/runtime/inflight.ts
|
|
2
|
+
async function refuseUncancellableTimeout(pool, timeout) {
|
|
3
|
+
if (pool.capabilities.cancel === true || timeout === undefined || !(timeout > 0))
|
|
4
|
+
return;
|
|
5
|
+
const { noTimeout } = await import("./wxr8cwns.js");
|
|
6
|
+
noTimeout({ timeout });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { refuseUncancellableTimeout };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertNamespace2,
|
|
3
|
+
normaliseEdges,
|
|
4
|
+
assertProvenance
|
|
5
|
+
} from "./358zsv4r.js";
|
|
6
|
+
import {
|
|
7
|
+
isReservedIdentifier2,
|
|
8
|
+
assertIdentifier2,
|
|
9
|
+
fitIdentifier2,
|
|
10
|
+
assertStoredText
|
|
11
|
+
} from "./nfzc5z0w.js";
|
|
12
|
+
import {
|
|
13
|
+
catalogError2
|
|
14
|
+
} from "./52szzakm.js";
|
|
15
|
+
|
|
16
|
+
// src/contracts/catalog/policy.ts
|
|
17
|
+
var BARE_IDENT = /^[a-z_][a-z0-9_$]*$/;
|
|
18
|
+
function policyIdent(name) {
|
|
19
|
+
if (BARE_IDENT.test(name) && !isReservedIdentifier2(name))
|
|
20
|
+
return name;
|
|
21
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
22
|
+
}
|
|
23
|
+
function tenantPolicyExpression(column, dataType) {
|
|
24
|
+
return `(${policyIdent(column)} = (NULLIF(current_setting('app.tenant'::text, true), ''::text))::${dataType})`;
|
|
25
|
+
}
|
|
26
|
+
function unscopedPolicyExpression() {
|
|
27
|
+
return `(current_setting('app.unscoped'::text, true) = 'on'::text)`;
|
|
28
|
+
}
|
|
29
|
+
function policyObject(input) {
|
|
30
|
+
assertNamespace2(input.parent.namespace);
|
|
31
|
+
assertIdentifier2(input.parent.name, "policy parent");
|
|
32
|
+
assertIdentifier2(input.name, "policy");
|
|
33
|
+
assertStoredText(input.expression, "policy expression");
|
|
34
|
+
if (input.command !== "all" && input.command !== "select") {
|
|
35
|
+
catalogError2("OKM1020", `Policy ${input.name} command is not supported.`);
|
|
36
|
+
}
|
|
37
|
+
assertProvenance(input.provenance);
|
|
38
|
+
const parent = {
|
|
39
|
+
kind: "table",
|
|
40
|
+
namespace: input.parent.namespace,
|
|
41
|
+
name: input.parent.name
|
|
42
|
+
};
|
|
43
|
+
const definition = {
|
|
44
|
+
command: input.command,
|
|
45
|
+
expression: input.expression,
|
|
46
|
+
force: input.force
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
kind: "policy",
|
|
50
|
+
identity: { kind: "policy", parent: input.parent, name: fitIdentifier2(input.name) },
|
|
51
|
+
owner: input.owner ?? "managed",
|
|
52
|
+
definition,
|
|
53
|
+
dependencies: normaliseEdges([parent, ...input.dependencies ?? []]),
|
|
54
|
+
provenance: input.provenance
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { tenantPolicyExpression, unscopedPolicyExpression, policyObject };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isConnectionSqlstate,
|
|
3
3
|
isConnectionFailure
|
|
4
|
-
} from "./
|
|
4
|
+
} from "./gwn6v667.js";
|
|
5
5
|
import {
|
|
6
6
|
OkmError2,
|
|
7
7
|
stripRowValues,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./52szzakm.js";
|
|
10
10
|
|
|
11
11
|
// src/dialects/pg/errors.ts
|
|
12
|
-
function
|
|
12
|
+
function mapPostgresError2(error, options) {
|
|
13
13
|
if (error instanceof OkmError2)
|
|
14
14
|
return error;
|
|
15
15
|
if (!isDriverError(error))
|
|
@@ -17,7 +17,7 @@ function mapPostgresError(error, options) {
|
|
|
17
17
|
const kind = kindOf(error);
|
|
18
18
|
const columns = columnsOf(error);
|
|
19
19
|
const hint = hintOf(error, kind);
|
|
20
|
-
const fieldReason = hint?.reason ?? (kind === "not_null" ? "not_null" : reasonOf(kind, error.table, error.constraint));
|
|
20
|
+
const fieldReason = hint?.reason ?? (kind === "not_null" ? "not_null" : reasonOf(kind, error.table, error.constraint, columns, options?.schema));
|
|
21
21
|
const values = options?.includeValues === true ? valuesOf(error.detail, columns) : undefined;
|
|
22
22
|
const code = kind === "outcome_unknown" ? "OKM1401" : kind;
|
|
23
23
|
return new OkmError2(code, summaryOf(kind, error, columns, fieldReason), {
|
|
@@ -70,11 +70,39 @@ function hintOf(error, kind) {
|
|
|
70
70
|
return { reason: "undefined_table", fix: MIGRATE_FIX };
|
|
71
71
|
if (error.sqlstate === "42703")
|
|
72
72
|
return { reason: "undefined_column", fix: MIGRATE_FIX };
|
|
73
|
+
const refresh = refreshHint(error);
|
|
74
|
+
if (refresh !== undefined)
|
|
75
|
+
return refresh;
|
|
73
76
|
if (kind === "unavailable" && error.sqlstate === undefined && isTlsFailure(error)) {
|
|
74
77
|
return { reason: "tls", fix: TLS_FIX };
|
|
75
78
|
}
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
81
|
+
function refreshHint(error) {
|
|
82
|
+
if (error.sqlstate === "0A000" && error.message.includes("materialized view is not populated")) {
|
|
83
|
+
return {
|
|
84
|
+
reason: "not_populated",
|
|
85
|
+
fix: { summary: "Refresh once without CONCURRENTLY so the view is populated." }
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (error.sqlstate === "55000" && error.message.includes("cannot refresh materialized view") && error.message.includes("concurrently")) {
|
|
89
|
+
return {
|
|
90
|
+
reason: "no_unique_index",
|
|
91
|
+
fix: {
|
|
92
|
+
summary: "Add a unique index with no WHERE clause, or refresh without CONCURRENTLY."
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (error.sqlstate === "42501" && error.message.includes("materialized view")) {
|
|
97
|
+
return {
|
|
98
|
+
reason: "not_owner",
|
|
99
|
+
fix: {
|
|
100
|
+
summary: "Refresh runs as the owner, the migration role. Connect as that role and call refresh(), or run REFRESH MATERIALIZED VIEW as that role. The application role is not the owner."
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
78
106
|
function kindFromSqlstate(sqlstate) {
|
|
79
107
|
switch (sqlstate) {
|
|
80
108
|
case "23505":
|
|
@@ -112,7 +140,15 @@ function kindFromSqlstate(sqlstate) {
|
|
|
112
140
|
return;
|
|
113
141
|
}
|
|
114
142
|
}
|
|
115
|
-
function reasonOf(kind, table, constraint) {
|
|
143
|
+
function reasonOf(kind, table, constraint, columns, schema) {
|
|
144
|
+
if (schema !== undefined && schema.catalog !== undefined && table !== undefined) {
|
|
145
|
+
const matched = matchObject(schema.catalog, table, constraint, columns);
|
|
146
|
+
if (matched !== undefined)
|
|
147
|
+
return reasonFromObject(schema, table, matched, columns);
|
|
148
|
+
}
|
|
149
|
+
return reasonFromName(kind, table, constraint);
|
|
150
|
+
}
|
|
151
|
+
function reasonFromName(kind, table, constraint) {
|
|
116
152
|
if (constraint === undefined || constraint.length === 0)
|
|
117
153
|
return kind;
|
|
118
154
|
if (table !== undefined) {
|
|
@@ -128,6 +164,61 @@ function reasonOf(kind, table, constraint) {
|
|
|
128
164
|
}
|
|
129
165
|
return constraint;
|
|
130
166
|
}
|
|
167
|
+
function matchObject(catalog, table, constraint, columns) {
|
|
168
|
+
const rows = [];
|
|
169
|
+
for (const object of catalog.objects) {
|
|
170
|
+
if (object.kind !== "constraint" && object.kind !== "index")
|
|
171
|
+
continue;
|
|
172
|
+
if (object.identity.parent.name !== table)
|
|
173
|
+
continue;
|
|
174
|
+
rows.push(object);
|
|
175
|
+
}
|
|
176
|
+
if (columns.length > 0) {
|
|
177
|
+
const key = columns.join(",");
|
|
178
|
+
const hits = rows.filter((object) => object.definition.columns.join(",") === key);
|
|
179
|
+
if (constraint !== undefined) {
|
|
180
|
+
const named = hits.find((object) => object.identity.name === constraint);
|
|
181
|
+
if (named !== undefined)
|
|
182
|
+
return named;
|
|
183
|
+
}
|
|
184
|
+
const only = hits.length === 1 ? hits[0] : undefined;
|
|
185
|
+
if (only !== undefined)
|
|
186
|
+
return only;
|
|
187
|
+
}
|
|
188
|
+
if (constraint === undefined)
|
|
189
|
+
return;
|
|
190
|
+
return rows.find((object) => object.identity.name === constraint);
|
|
191
|
+
}
|
|
192
|
+
function reasonFromObject(schema, table, object, columns) {
|
|
193
|
+
if (object.kind === "index")
|
|
194
|
+
return object.identity.name;
|
|
195
|
+
const nameKey = object.definition.nameKey;
|
|
196
|
+
if (columns.length === 0)
|
|
197
|
+
return nameKey;
|
|
198
|
+
const sqlKey = object.definition.columns.join("_");
|
|
199
|
+
if (nameKey !== sqlKey || object.definition.columns.length < 2)
|
|
200
|
+
return nameKey;
|
|
201
|
+
return fieldKey(schema, table, object.definition.columns) ?? nameKey;
|
|
202
|
+
}
|
|
203
|
+
function fieldKey(schema, table, columns) {
|
|
204
|
+
let model;
|
|
205
|
+
for (const item of Object.values(schema.model)) {
|
|
206
|
+
if (item.sql === table) {
|
|
207
|
+
model = item;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (model === undefined)
|
|
212
|
+
return;
|
|
213
|
+
const fields = [];
|
|
214
|
+
for (const column of columns) {
|
|
215
|
+
const found = model.columns.find((item) => item.sql === column);
|
|
216
|
+
if (found === undefined)
|
|
217
|
+
return;
|
|
218
|
+
fields.push(found.field);
|
|
219
|
+
}
|
|
220
|
+
return fields.join("_");
|
|
221
|
+
}
|
|
131
222
|
function nameKeyOf(rest) {
|
|
132
223
|
const tags = ["_fkey", "_check", "_key"];
|
|
133
224
|
for (const tag of tags) {
|
|
@@ -212,6 +303,9 @@ function unquote(name) {
|
|
|
212
303
|
}
|
|
213
304
|
function summaryOf(kind, error, columns, fieldReason) {
|
|
214
305
|
const label = labelOf(kind);
|
|
306
|
+
if (kind === "driver" && fieldReason === "not_owner") {
|
|
307
|
+
return "The application role cannot refresh a materialized view. Refresh runs as the owner, the migration role.";
|
|
308
|
+
}
|
|
215
309
|
if (kind === "driver")
|
|
216
310
|
return stripRowValues(error.message);
|
|
217
311
|
const where = place(error.table, columns);
|
|
@@ -276,6 +370,5 @@ function labelOf(kind) {
|
|
|
276
370
|
return "Driver error";
|
|
277
371
|
}
|
|
278
372
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
};
|
|
373
|
+
|
|
374
|
+
export { mapPostgresError2 };
|
|
@@ -7,9 +7,11 @@ import {
|
|
|
7
7
|
startupCatalog2,
|
|
8
8
|
startupHash2,
|
|
9
9
|
loadTrustedCatalog2,
|
|
10
|
+
catalogFileText2,
|
|
10
11
|
parseCatalog2
|
|
11
|
-
} from "./
|
|
12
|
+
} from "./qq3899ht.js";
|
|
12
13
|
export {
|
|
14
|
+
catalogFileText2 as catalogFileText,
|
|
13
15
|
catalogHash2 as catalogHash,
|
|
14
16
|
creationOrder2 as creationOrder,
|
|
15
17
|
loadTrustedCatalog2 as loadTrustedCatalog,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
catalogFileText2
|
|
3
|
+
} from "./qq3899ht.js";
|
|
1
4
|
import {
|
|
2
5
|
OkmError2
|
|
3
6
|
} from "./52szzakm.js";
|
|
@@ -11,7 +14,7 @@ async function assertCompatible(pool, schema, recordedHash, source, options) {
|
|
|
11
14
|
if (code.artifact !== undefined) {
|
|
12
15
|
const artifact = code.artifact;
|
|
13
16
|
await loadOnce(`text\x00${artifact.hash}`, async () => {
|
|
14
|
-
const { loadTrustedCatalog } = await import("./
|
|
17
|
+
const { loadTrustedCatalog } = await import("./dk8v79p3.js");
|
|
15
18
|
loadTrustedCatalog(artifact.text, artifact.hash);
|
|
16
19
|
});
|
|
17
20
|
} else if (code.fromFile) {
|
|
@@ -25,7 +28,7 @@ async function assertCompatible(pool, schema, recordedHash, source, options) {
|
|
|
25
28
|
}
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
|
-
const { loadTrustedCatalog } = await import("./
|
|
31
|
+
const { loadTrustedCatalog } = await import("./dk8v79p3.js");
|
|
29
32
|
loadTrustedCatalog(text, code.hash);
|
|
30
33
|
});
|
|
31
34
|
}
|
|
@@ -39,7 +42,7 @@ async function codeHash(schema, source) {
|
|
|
39
42
|
const listed = await readHashFile(source.catalogDir);
|
|
40
43
|
if (listed !== undefined)
|
|
41
44
|
return { hash: listed, fromFile: true };
|
|
42
|
-
const { catalogHash } = await import("./
|
|
45
|
+
const { catalogHash } = await import("./dk8v79p3.js");
|
|
43
46
|
return { hash: catalogHash(schemaCatalog(schema)), fromFile: false };
|
|
44
47
|
}
|
|
45
48
|
function schemaCatalog(schema) {
|
|
@@ -57,12 +60,12 @@ async function readHashFile(catalogDir) {
|
|
|
57
60
|
const text = await readText(`${artifactDir(catalogDir)}/catalog.hash`);
|
|
58
61
|
if (text === undefined)
|
|
59
62
|
return;
|
|
60
|
-
const hash = text.trim();
|
|
63
|
+
const hash = catalogFileText2(text, "catalog.hash").trim();
|
|
61
64
|
return hash.length === 0 ? undefined : hash;
|
|
62
65
|
}
|
|
63
66
|
function artifactDir(catalogDir) {
|
|
64
67
|
if (catalogDir !== undefined)
|
|
65
|
-
return catalogDir.replace(
|
|
68
|
+
return catalogDir.replace(/[/\\]+$/, "");
|
|
66
69
|
const cwd = globalThis.process?.cwd?.() ?? ".";
|
|
67
70
|
return `${cwd}/.okm`;
|
|
68
71
|
}
|
|
@@ -4,24 +4,26 @@ import {
|
|
|
4
4
|
viewDependencyEdges,
|
|
5
5
|
PUBLIC,
|
|
6
6
|
introspectSchema
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./vjpnzwjz.js";
|
|
8
8
|
import {
|
|
9
9
|
planMigration,
|
|
10
|
+
sessionFailure,
|
|
11
|
+
finishQuiet,
|
|
10
12
|
assertDirectConnection,
|
|
11
13
|
assertStableBackend
|
|
12
|
-
} from "./
|
|
14
|
+
} from "./ttmg09vd.js";
|
|
13
15
|
import {
|
|
14
16
|
quoteIdent,
|
|
15
17
|
createObjectSql
|
|
16
|
-
} from "./
|
|
18
|
+
} from "./9s0ypp87.js";
|
|
17
19
|
import {
|
|
18
20
|
normaliseViewQuery,
|
|
19
21
|
viewObject,
|
|
20
22
|
materializedViewObject
|
|
21
|
-
} from "./
|
|
23
|
+
} from "./zy8r7qvz.js";
|
|
22
24
|
import {
|
|
23
25
|
catalog
|
|
24
|
-
} from "./
|
|
26
|
+
} from "./ywspezzx.js";
|
|
25
27
|
import {
|
|
26
28
|
OkmError2
|
|
27
29
|
} from "./52szzakm.js";
|
|
@@ -88,7 +90,8 @@ async function sealViews(runner, source) {
|
|
|
88
90
|
query,
|
|
89
91
|
owner: object.owner,
|
|
90
92
|
provenance: object.provenance,
|
|
91
|
-
dependencies
|
|
93
|
+
dependencies,
|
|
94
|
+
...object.definition.securityInvoker === true ? { securityInvoker: true } : {}
|
|
92
95
|
});
|
|
93
96
|
}
|
|
94
97
|
return materializedViewObject({
|
|
@@ -256,8 +259,10 @@ ${plan.steps.map((step) => step.sql).join(`
|
|
|
256
259
|
summary: "Change the schema or the database so okm check reports no difference."
|
|
257
260
|
}
|
|
258
261
|
});
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw sessionFailure(error) ?? error;
|
|
259
264
|
} finally {
|
|
260
|
-
await sql.end({ timeout: 5 });
|
|
265
|
+
await finishQuiet(() => sql.end({ timeout: 5 }));
|
|
261
266
|
}
|
|
262
267
|
}
|
|
263
268
|
function catalogQuery2(sql) {
|
|
@@ -275,12 +280,17 @@ function catalogQuery2(sql) {
|
|
|
275
280
|
}
|
|
276
281
|
function managedRoleOptions2(roles) {
|
|
277
282
|
const names = managedRoleNames(roles);
|
|
278
|
-
return names === undefined ? undefined : {
|
|
283
|
+
return names === undefined ? undefined : {
|
|
284
|
+
managedRoles: names,
|
|
285
|
+
...roles?.reporting !== undefined ? { reportingRole: roles.reporting } : {}
|
|
286
|
+
};
|
|
279
287
|
}
|
|
280
288
|
function managedRoleNames(roles) {
|
|
281
289
|
if (roles === undefined)
|
|
282
290
|
return;
|
|
283
291
|
const names = new Set([roles.migration, roles.app]);
|
|
292
|
+
if (roles.reporting !== undefined)
|
|
293
|
+
names.add(roles.reporting);
|
|
284
294
|
for (const role of roles.managed ?? [])
|
|
285
295
|
names.add(role.name);
|
|
286
296
|
return [...names];
|
|
@@ -28,7 +28,7 @@ function isConnectionFailure(error) {
|
|
|
28
28
|
if (!(error instanceof Error))
|
|
29
29
|
return false;
|
|
30
30
|
const message = error.message;
|
|
31
|
-
return message.includes("ECONNREFUSED") || message.includes("ECONNRESET") || message.includes("
|
|
31
|
+
return message.includes("ECONNREFUSED") || message.includes("ECONNRESET") || message.includes("CONNECT") || message.includes("terminating connection") || message.includes("The pool is closed");
|
|
32
32
|
}
|
|
33
33
|
function isConnectionLost(error) {
|
|
34
34
|
if (isConnectionFailure(error))
|