okmodel 0.5.1 → 0.7.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 +100 -1116
- package/dist/adapters/capabilities.d.ts +3 -0
- package/dist/adapters/failure.d.ts +13 -2
- package/dist/adapters/lazy-errors.d.ts +22 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +54 -3
- package/dist/adapters/pg/bunsql.d.ts +14 -1
- package/dist/adapters/pg/cursor.d.ts +17 -0
- package/dist/adapters/pg/no-inflight-timeout.d.ts +20 -0
- package/dist/adapters/pg/nodepostgres-extra.d.ts +22 -1
- package/dist/adapters/pg/nodepostgres.d.ts +12 -0
- package/dist/adapters/pg/pglite-wire.d.ts +24 -0
- package/dist/adapters/pg/pglite.d.ts +10 -0
- package/dist/adapters/pg/postgres-extra.d.ts +41 -3
- package/dist/adapters/pg/reserved.d.ts +42 -0
- package/dist/adapters/pg/session.d.ts +0 -18
- 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/connection.d.ts +7 -6
- 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/floor.d.ts +68 -0
- package/dist/dialects/pg/fn/index.js +2 -2
- package/dist/dialects/pg/index.d.ts +8 -2
- package/dist/dialects/pg/index.js +67 -171
- package/dist/dialects/pg/introspect.d.ts +7 -0
- package/dist/dialects/pg/keys.d.ts +11 -8
- package/dist/dialects/pg/model.d.ts +47 -2
- package/dist/dialects/pg/morph.d.ts +43 -0
- package/dist/dialects/pg/operator-fit.d.ts +2 -2
- package/dist/dialects/pg/operators.d.ts +14 -7
- package/dist/dialects/pg/ops/bucket.d.ts +65 -0
- package/dist/dialects/pg/ops/inc.d.ts +2 -2
- package/dist/dialects/pg/ops/matches.d.ts +9 -12
- package/dist/dialects/pg/ops/relevance.d.ts +13 -0
- package/dist/dialects/pg/ops/search-query.d.ts +22 -0
- package/dist/dialects/pg/ops/window.d.ts +103 -0
- package/dist/dialects/pg/owner.d.ts +42 -0
- package/dist/dialects/pg/path-endpoint.d.ts +20 -0
- package/dist/dialects/pg/preset.d.ts +1 -1
- package/dist/dialects/pg/relations.d.ts +100 -3
- 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 +33 -3
- 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/aggregate.d.ts +8 -2
- package/dist/runtime/batch.d.ts +1 -1
- package/dist/runtime/bucket-group.d.ts +70 -0
- package/dist/runtime/conflict.d.ts +24 -6
- package/dist/runtime/drift.d.ts +9 -0
- package/dist/runtime/include.d.ts +0 -8
- package/dist/runtime/inflight.d.ts +14 -0
- package/dist/runtime/page.d.ts +4 -1
- package/dist/runtime/pg/bun.js +12 -5
- package/dist/runtime/pg/pg.js +5 -5
- package/dist/runtime/pg/pglite.d.ts +1 -0
- package/dist/runtime/pg/pglite.js +9 -8
- package/dist/runtime/pg/postgresjs.js +5 -5
- package/dist/runtime/plan.d.ts +113 -15
- package/dist/runtime/predicate.d.ts +19 -0
- package/dist/runtime/read-stream.d.ts +13 -16
- package/dist/runtime/result-name.d.ts +17 -0
- package/dist/runtime/safety/index.js +1 -1
- package/dist/runtime/server-check.d.ts +3 -3
- package/dist/runtime/sort-bind.d.ts +21 -0
- package/dist/runtime/sort.d.ts +56 -0
- package/dist/runtime/sync.d.ts +70 -0
- 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 +1511 -38
- 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/text-search.d.ts +20 -0
- package/dist/runtime/traits/index.d.ts +80 -0
- package/dist/runtime/traits/index.js +187 -17
- package/dist/runtime/tree.d.ts +38 -0
- package/dist/runtime/types.d.ts +231 -23
- package/dist/runtime/validate/index.js +4 -4
- package/dist/runtime/version.d.ts +39 -0
- package/dist/runtime/window.d.ts +21 -0
- package/dist/runtime/write.d.ts +55 -3
- package/dist/shared/{krxx77g0.js → 14vx95q4.js} +12 -18
- package/dist/shared/1est4ezg.js +313 -0
- package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
- package/dist/shared/1w508jbr.js +1611 -0
- package/dist/shared/2c13q96h.js +18 -0
- package/dist/shared/2d3xq4ps.js +9 -0
- package/dist/shared/2shdbn8q.js +23 -0
- package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
- package/dist/shared/3v7t1yrv.js +208 -0
- package/dist/shared/5e3tf63j.js +220 -0
- package/dist/shared/5fe3kbsh.js +10 -0
- package/dist/shared/5v3xf80k.js +37 -0
- package/dist/shared/{51mvgj8w.js → 63qtkrca.js} +130 -3
- package/dist/shared/{gbtcc2d7.js → 67txcrcw.js} +62 -66
- package/dist/shared/79dt02vc.js +12 -0
- package/dist/shared/{v36c5g6p.js → 7k9grvf6.js} +407 -14
- package/dist/shared/7kms6fvj.js +20 -0
- package/dist/shared/7mnme5tn.js +8 -0
- package/dist/shared/7n7ddwt4.js +6 -0
- package/dist/shared/{87jvvhnt.js → 81ebdx9p.js} +48 -68
- package/dist/shared/{szm0cksa.js → 8skf0cam.js} +34 -6
- package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
- package/dist/shared/9a4ae4p8.js +31 -0
- package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
- package/dist/shared/9y3mmmh1.js +436 -0
- package/dist/shared/ab9gmbwy.js +213 -0
- package/dist/shared/{sycnx8gt.js → ax7qv55k.js} +18 -8
- package/dist/shared/{f5cw5q5r.js → aytqh5y2.js} +6 -4
- package/dist/shared/{fancm5pt.js → b5pftnn2.js} +138 -15
- package/dist/shared/{efmy2gcg.js → b76b8d95.js} +2 -2
- package/dist/shared/bdk4sty6.js +58 -0
- package/dist/shared/{32zqc1dw.js → bg3rym3g.js} +63 -32
- package/dist/shared/{0t22wwh1.js → bm22fvzr.js} +16 -14
- package/dist/shared/bz84tkzm.js +342 -0
- package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
- package/dist/shared/cn957f8d.js +179 -0
- package/dist/shared/{pf0d8f77.js → cnkky55j.js} +25 -14
- package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
- package/dist/shared/{nkaxvt9q.js → dkxgzaqd.js} +224 -19
- package/dist/shared/dzj09cye.js +10 -0
- package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
- package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
- package/dist/shared/exn3sd90.js +359 -0
- package/dist/shared/g6evj1j3.js +66 -0
- package/dist/shared/ga9j92qj.js +25 -0
- package/dist/shared/{qv2ydck9.js → gs74dbj5.js} +651 -76
- package/dist/shared/gzaveazc.js +285 -0
- package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
- package/dist/shared/{dyj86cmj.js → hyh73qk6.js} +3 -3
- package/dist/shared/je4axnm8.js +22 -0
- package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
- package/dist/shared/{6qd27mx0.js → jvd0mqag.js} +5 -5
- package/dist/shared/jznfax0y.js +155 -0
- package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
- package/dist/shared/{ps7a6h14.js → kr0jzbw2.js} +12 -8
- package/dist/shared/{janx09m5.js → ktz42yez.js} +20 -8
- package/dist/shared/{gde73es6.js → m6p12kbr.js} +56 -55
- package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
- package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
- package/dist/shared/{nxdp2ze3.js → mtaszv5a.js} +144 -12
- package/dist/shared/n816peh1.js +45 -0
- package/dist/shared/nbw1z4yd.js +18 -0
- package/dist/shared/{cctw17hj.js → p6qc5gcp.js} +38 -34
- package/dist/shared/{6rk2gen5.js → pbp1ss85.js} +20 -17
- package/dist/shared/pt94kz7f.js +6 -0
- package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
- package/dist/shared/q5c6ngn3.js +13 -0
- package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
- 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/{sdc7r2ww.js → rs73fca9.js} +8 -8
- package/dist/shared/{tm5ab8we.js → sfz1ksn6.js} +7 -4
- package/dist/shared/{6mnp99hx.js → svncdeh5.js} +16 -12
- package/dist/shared/{hf22e0wt.js → tbrvgw6z.js} +62 -42
- package/dist/shared/te5as7z7.js +622 -0
- package/dist/shared/{ga3sfy93.js → tsvww22q.js} +535 -200
- package/dist/shared/{47x8x9ze.js → ttsqgp4p.js} +20 -13
- package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
- package/dist/shared/vb6qfyve.js +152 -0
- package/dist/shared/{r2sp8hrc.js → vczs8gd4.js} +22 -13
- package/dist/shared/{1g0drakv.js → vqrjpcqn.js} +145 -3
- package/dist/shared/{2pqx26h8.js → w72kgg4q.js} +31 -22
- package/dist/shared/{96qcj21c.js → w79hsckn.js} +16 -51
- package/dist/shared/wa07eas9.js +730 -0
- package/dist/shared/{k8v5v5wj.js → x933k9a3.js} +75 -34
- package/dist/shared/{cr74e96e.js → xhfsfkgk.js} +62 -28
- package/dist/shared/xjk7hnn5.js +272 -0
- package/dist/shared/{5enne4ma.js → xnxsed62.js} +66 -113
- package/dist/shared/xqve9598.js +53 -0
- package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
- package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
- package/dist/shared/y6njgyda.js +249 -0
- package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
- package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
- package/dist/shared/z7s6fpxv.js +62 -0
- package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
- package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
- package/dist/shared/zm0ptry0.js +40 -0
- package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
- package/dist/shared/zp9fmend.js +145 -0
- 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/engine.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 +8 -3
- package/dist/shared/7m88x3e9.js +0 -45
- package/dist/shared/7zwwyh0v.js +0 -448
- package/dist/shared/aj2qxyhj.js +0 -90
- package/dist/shared/caw8b9d8.js +0 -204
- package/dist/shared/jwtxdj06.js +0 -76
- package/dist/shared/kfjp0gck.js +0 -212
- package/dist/shared/q58y17hy.js +0 -21
- package/dist/shared/qm7cdtvr.js +0 -912
- package/dist/shared/r8x5qhd7.js +0 -86
- package/dist/shared/zqrnhwsq.js +0 -31
|
@@ -4,24 +4,26 @@ import {
|
|
|
4
4
|
viewDependencyEdges,
|
|
5
5
|
PUBLIC,
|
|
6
6
|
introspectSchema
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./b5pftnn2.js";
|
|
8
8
|
import {
|
|
9
9
|
planMigration,
|
|
10
|
+
sessionFailure,
|
|
11
|
+
finishQuiet,
|
|
10
12
|
assertDirectConnection,
|
|
11
13
|
assertStableBackend
|
|
12
|
-
} from "./
|
|
14
|
+
} from "./tsvww22q.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];
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
open3
|
|
3
|
-
|
|
2
|
+
open3,
|
|
3
|
+
seal2
|
|
4
|
+
} from "./81ebdx9p.js";
|
|
4
5
|
import {
|
|
5
6
|
PGLITE_CAPABILITIES,
|
|
6
7
|
readCapability2,
|
|
7
8
|
hasCapability2
|
|
8
|
-
} from "./
|
|
9
|
+
} from "./kb2sdhfb.js";
|
|
9
10
|
export {
|
|
10
11
|
PGLITE_CAPABILITIES as capabilities,
|
|
11
12
|
hasCapability2 as hasCapability,
|
|
12
13
|
open3 as open,
|
|
13
|
-
readCapability2 as readCapability
|
|
14
|
+
readCapability2 as readCapability,
|
|
15
|
+
seal2 as seal
|
|
14
16
|
};
|
|
@@ -2,28 +2,34 @@ import {
|
|
|
2
2
|
roleObject,
|
|
3
3
|
grantObject,
|
|
4
4
|
defaultPrivilegeObject
|
|
5
|
-
} from "./
|
|
5
|
+
} from "./qq3899ht.js";
|
|
6
|
+
import {
|
|
7
|
+
columnPrivilege
|
|
8
|
+
} from "./tsvww22q.js";
|
|
6
9
|
import {
|
|
7
10
|
quoteIdent
|
|
8
|
-
} from "./
|
|
11
|
+
} from "./9s0ypp87.js";
|
|
12
|
+
import {
|
|
13
|
+
policyObject
|
|
14
|
+
} from "./bdk4sty6.js";
|
|
9
15
|
import {
|
|
10
16
|
functionObject,
|
|
11
17
|
triggerObject
|
|
12
|
-
} from "./
|
|
18
|
+
} from "./y34a8714.js";
|
|
13
19
|
import {
|
|
14
20
|
normaliseViewQuery,
|
|
15
21
|
viewObject,
|
|
16
22
|
materializedViewObject,
|
|
17
23
|
materializedViewIndex
|
|
18
|
-
} from "./
|
|
24
|
+
} from "./zy8r7qvz.js";
|
|
19
25
|
import {
|
|
20
26
|
extensionObject
|
|
21
|
-
} from "./
|
|
27
|
+
} from "./r3j8s5y0.js";
|
|
22
28
|
import {
|
|
23
29
|
catalog,
|
|
24
30
|
enumType,
|
|
25
31
|
domainType
|
|
26
|
-
} from "./
|
|
32
|
+
} from "./ywspezzx.js";
|
|
27
33
|
import {
|
|
28
34
|
staticNamespace2,
|
|
29
35
|
identityKey2,
|
|
@@ -32,7 +38,7 @@ import {
|
|
|
32
38
|
index3,
|
|
33
39
|
constraint2,
|
|
34
40
|
sequence2
|
|
35
|
-
} from "./
|
|
41
|
+
} from "./358zsv4r.js";
|
|
36
42
|
import {
|
|
37
43
|
referentialAction
|
|
38
44
|
} from "./4e4c6vq2.js";
|
|
@@ -123,7 +129,8 @@ async function introspectSchema(runner, concrete, logical = "public", options) {
|
|
|
123
129
|
triggers,
|
|
124
130
|
functionDeps,
|
|
125
131
|
views,
|
|
126
|
-
viewDeps
|
|
132
|
+
viewDeps,
|
|
133
|
+
policies
|
|
127
134
|
] = await Promise.all([
|
|
128
135
|
runner.query(TABLES, params),
|
|
129
136
|
runner.query(COLUMNS, params),
|
|
@@ -137,7 +144,8 @@ async function introspectSchema(runner, concrete, logical = "public", options) {
|
|
|
137
144
|
runner.query(TRIGGERS, params),
|
|
138
145
|
runner.query(FUNCTION_DEPS, params),
|
|
139
146
|
runner.query(VIEWS, params),
|
|
140
|
-
runner.query(VIEW_DEPENDENCIES, params)
|
|
147
|
+
runner.query(VIEW_DEPENDENCIES, params),
|
|
148
|
+
runner.query(POLICIES, params)
|
|
141
149
|
]);
|
|
142
150
|
const objects = [];
|
|
143
151
|
const parents = new Map;
|
|
@@ -380,12 +388,38 @@ async function introspectSchema(runner, concrete, logical = "public", options) {
|
|
|
380
388
|
const columns = printedColumns(text(row, "columns"));
|
|
381
389
|
const query = normaliseViewQuery(text(row, "query"));
|
|
382
390
|
const name = text(row, "name");
|
|
391
|
+
const invoker = kind === "view" && securityInvokerOption(text(row, "options"));
|
|
383
392
|
if (kind === "materializedView") {
|
|
384
393
|
objects.push(materializedViewObject({ namespace, name, columns, query, provenance }));
|
|
385
394
|
} else {
|
|
386
|
-
objects.push(viewObject({
|
|
395
|
+
objects.push(viewObject({
|
|
396
|
+
namespace,
|
|
397
|
+
name,
|
|
398
|
+
columns,
|
|
399
|
+
query,
|
|
400
|
+
provenance,
|
|
401
|
+
...invoker ? { securityInvoker: true } : {}
|
|
402
|
+
}));
|
|
387
403
|
}
|
|
388
404
|
}
|
|
405
|
+
for (const row of policies) {
|
|
406
|
+
const parentName = text(row, "table_name");
|
|
407
|
+
const parent = parents.get(parentName);
|
|
408
|
+
if (parent === undefined)
|
|
409
|
+
continue;
|
|
410
|
+
const command = policyCommand(text(row, "command"));
|
|
411
|
+
if (command === undefined || text(row, "enabled") !== "true")
|
|
412
|
+
continue;
|
|
413
|
+
objects.push(policyObject({
|
|
414
|
+
parent,
|
|
415
|
+
name: text(row, "name"),
|
|
416
|
+
command,
|
|
417
|
+
expression: text(row, "using_expr"),
|
|
418
|
+
force: text(row, "force") === "true",
|
|
419
|
+
provenance,
|
|
420
|
+
dependencies: [{ kind: "table", namespace, name: parentName }]
|
|
421
|
+
}));
|
|
422
|
+
}
|
|
389
423
|
const viewEdges = viewDependencyEdges(viewDeps, namespace, objects);
|
|
390
424
|
for (let index = 0;index < objects.length; index += 1) {
|
|
391
425
|
const object = objects[index];
|
|
@@ -402,7 +436,8 @@ async function introspectSchema(runner, concrete, logical = "public", options) {
|
|
|
402
436
|
columns: object.definition.columns,
|
|
403
437
|
query: object.definition.query,
|
|
404
438
|
provenance,
|
|
405
|
-
dependencies
|
|
439
|
+
dependencies,
|
|
440
|
+
...object.definition.securityInvoker === true ? { securityInvoker: true } : {}
|
|
406
441
|
}) : materializedViewObject({
|
|
407
442
|
namespace,
|
|
408
443
|
name: object.identity.name,
|
|
@@ -413,7 +448,7 @@ async function introspectSchema(runner, concrete, logical = "public", options) {
|
|
|
413
448
|
});
|
|
414
449
|
}
|
|
415
450
|
if (options?.managedRoles !== undefined) {
|
|
416
|
-
objects.push(...await readPrivileges(runner, concrete, namespace, provenance, objects, options.managedRoles));
|
|
451
|
+
objects.push(...await readPrivileges(runner, concrete, logical, namespace, provenance, objects, options.managedRoles, options.reportingRole));
|
|
417
452
|
}
|
|
418
453
|
return catalog(objects);
|
|
419
454
|
}
|
|
@@ -452,6 +487,30 @@ var FUNCTION_GRANTS = `select p.proname as name,
|
|
|
452
487
|
select 1 from pg_depend d
|
|
453
488
|
where d.classid = 'pg_proc'::regclass and d.objid = p.oid and d.deptype = 'e'
|
|
454
489
|
)`;
|
|
490
|
+
var COLUMN_GRANTS = `select c.relname as name,
|
|
491
|
+
case c.relkind when 'v' then 'view' when 'm' then 'materializedView' else 'table' end as kind,
|
|
492
|
+
a.attname as column_name,
|
|
493
|
+
r.rolname as role, x.privilege_type as privilege
|
|
494
|
+
from pg_class c
|
|
495
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
496
|
+
join pg_attribute a on a.attrelid = c.oid and a.attnum > 0 and not a.attisdropped
|
|
497
|
+
cross join lateral aclexplode(a.attacl) as x
|
|
498
|
+
join pg_roles r on r.oid = x.grantee
|
|
499
|
+
where n.nspname = $1
|
|
500
|
+
and c.relkind in ('r', 'p', 'v', 'm')
|
|
501
|
+
and a.attacl is not null
|
|
502
|
+
and x.grantee <> 0
|
|
503
|
+
and x.grantee <> c.relowner`;
|
|
504
|
+
var SCHEMA_USAGE = `select 1 as ok
|
|
505
|
+
from pg_namespace n
|
|
506
|
+
cross join lateral aclexplode(n.nspacl) as a
|
|
507
|
+
where n.nspname = $1
|
|
508
|
+
and a.privilege_type = 'USAGE'
|
|
509
|
+
and (
|
|
510
|
+
a.grantee = 0
|
|
511
|
+
or a.grantee = (select oid from pg_roles where rolname = $2)
|
|
512
|
+
)
|
|
513
|
+
limit 1`;
|
|
455
514
|
var DEFAULT_PRIVILEGES = `select owner_role.rolname as for_role, grantee.rolname as grantee,
|
|
456
515
|
case d.defaclobjtype when 'S' then 'sequence' when 'f' then 'function' else 'table' end as object_kind,
|
|
457
516
|
a.privilege_type as privilege
|
|
@@ -463,13 +522,15 @@ var DEFAULT_PRIVILEGES = `select owner_role.rolname as for_role, grantee.rolname
|
|
|
463
522
|
where n.nspname = $1
|
|
464
523
|
and d.defaclobjtype in ('r', 'S', 'f')
|
|
465
524
|
and a.grantee <> 0`;
|
|
466
|
-
async function readPrivileges(runner, concrete, namespace, provenance, built, managedRoles) {
|
|
525
|
+
async function readPrivileges(runner, concrete, logical, namespace, provenance, built, managedRoles, reportingRole) {
|
|
467
526
|
const managed = new Set(managedRoles);
|
|
468
|
-
const [roles, relations, functions, defaults] = await Promise.all([
|
|
527
|
+
const [roles, relations, functions, defaults, columns, usage] = await Promise.all([
|
|
469
528
|
runner.query(ROLES, []),
|
|
470
529
|
runner.query(RELATION_GRANTS, [concrete]),
|
|
471
530
|
runner.query(FUNCTION_GRANTS, [concrete]),
|
|
472
|
-
runner.query(DEFAULT_PRIVILEGES, [concrete])
|
|
531
|
+
runner.query(DEFAULT_PRIVILEGES, [concrete]),
|
|
532
|
+
runner.query(COLUMN_GRANTS, [concrete]),
|
|
533
|
+
reportingRole === undefined ? Promise.resolve([]) : runner.query(SCHEMA_USAGE, [concrete, reportingRole])
|
|
473
534
|
]);
|
|
474
535
|
const objects = [];
|
|
475
536
|
for (const row of roles) {
|
|
@@ -530,6 +591,42 @@ async function readPrivileges(runner, concrete, namespace, provenance, built, ma
|
|
|
530
591
|
]
|
|
531
592
|
}));
|
|
532
593
|
}
|
|
594
|
+
const grouped = new Map;
|
|
595
|
+
for (const row of columns) {
|
|
596
|
+
const privilege = text(row, "privilege").toUpperCase();
|
|
597
|
+
if (privilege !== "SELECT" && privilege !== "UPDATE")
|
|
598
|
+
continue;
|
|
599
|
+
const kind = grantKind(text(row, "kind"));
|
|
600
|
+
if (kind !== "table" && kind !== "view" && kind !== "materializedView")
|
|
601
|
+
continue;
|
|
602
|
+
const name = text(row, "name");
|
|
603
|
+
const role = text(row, "role");
|
|
604
|
+
const key = `${role}\x00${kind}\x00${name}\x00${privilege}`;
|
|
605
|
+
const current = grouped.get(key) ?? { role, kind, name, privilege, columns: [] };
|
|
606
|
+
current.columns.push(text(row, "column_name"));
|
|
607
|
+
grouped.set(key, current);
|
|
608
|
+
}
|
|
609
|
+
for (const group of grouped.values()) {
|
|
610
|
+
const target = built.find((object) => privilegeTarget(object) === `${group.kind}:${group.name}`);
|
|
611
|
+
if (target === undefined)
|
|
612
|
+
continue;
|
|
613
|
+
objects.push(grantObject({
|
|
614
|
+
role: group.role,
|
|
615
|
+
object: { kind: group.kind, namespace, name: group.name },
|
|
616
|
+
privilege: columnPrivilege(group.privilege, group.columns),
|
|
617
|
+
provenance,
|
|
618
|
+
dependencies: [{ kind: "role", name: group.role }, target.identity]
|
|
619
|
+
}));
|
|
620
|
+
}
|
|
621
|
+
if (usage.length > 0 && reportingRole !== undefined) {
|
|
622
|
+
objects.push(grantObject({
|
|
623
|
+
role: reportingRole,
|
|
624
|
+
object: { kind: "namespace", namespace, name: logical },
|
|
625
|
+
privilege: "USAGE",
|
|
626
|
+
provenance,
|
|
627
|
+
dependencies: [{ kind: "role", name: reportingRole }]
|
|
628
|
+
}));
|
|
629
|
+
}
|
|
533
630
|
return objects;
|
|
534
631
|
}
|
|
535
632
|
function privilegeTarget(object) {
|
|
@@ -788,6 +885,7 @@ var TRIGGERS = `
|
|
|
788
885
|
`;
|
|
789
886
|
var VIEWS = `
|
|
790
887
|
select c.relname as name, c.relkind as kind, pg_get_viewdef(c.oid, true) as query,
|
|
888
|
+
coalesce(array_to_string(c.reloptions, ','), '') as options,
|
|
791
889
|
(
|
|
792
890
|
select coalesce(string_agg(
|
|
793
891
|
a.attname || '|' || format_type(a.atttypid, a.atttypmod),
|
|
@@ -821,6 +919,31 @@ var FUNCTION_DEPS = `
|
|
|
821
919
|
and p.prokind = 'f'
|
|
822
920
|
and p.prosrc = ''
|
|
823
921
|
`;
|
|
922
|
+
var POLICIES = `
|
|
923
|
+
select c.relname as table_name,
|
|
924
|
+
p.polname as name,
|
|
925
|
+
p.polcmd as command,
|
|
926
|
+
coalesce(pg_get_expr(p.polqual, p.polrelid), '') as using_expr,
|
|
927
|
+
c.relforcerowsecurity::text as force,
|
|
928
|
+
c.relrowsecurity::text as enabled
|
|
929
|
+
from pg_policy p
|
|
930
|
+
join pg_class c on c.oid = p.polrelid
|
|
931
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
932
|
+
where n.nspname = $1
|
|
933
|
+
and c.relkind = 'r'
|
|
934
|
+
and ${CHILD}
|
|
935
|
+
and ${member("c.oid", "pg_class")}
|
|
936
|
+
`;
|
|
937
|
+
function securityInvokerOption(options) {
|
|
938
|
+
return options.split(",").some((item) => item === "security_invoker=true" || item === "security_invoker=on");
|
|
939
|
+
}
|
|
940
|
+
function policyCommand(command) {
|
|
941
|
+
if (command === "*")
|
|
942
|
+
return "all";
|
|
943
|
+
if (command === "r")
|
|
944
|
+
return "select";
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
824
947
|
function member(oid, classid) {
|
|
825
948
|
return `not exists (
|
|
826
949
|
select 1 from pg_depend member
|
|
@@ -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,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
touchFields,
|
|
3
3
|
fieldSealed
|
|
4
|
-
} from "./
|
|
4
|
+
} from "./1w508jbr.js";
|
|
5
5
|
import {
|
|
6
6
|
projectExpr,
|
|
7
7
|
quote,
|
|
8
8
|
list,
|
|
9
9
|
isRecord,
|
|
10
10
|
registerFailFix,
|
|
11
|
-
|
|
12
|
-
} from "./
|
|
11
|
+
fail2
|
|
12
|
+
} from "./67txcrcw.js";
|
|
13
13
|
import {
|
|
14
14
|
throwNamed2
|
|
15
15
|
} from "./52szzakm.js";
|
|
@@ -24,13 +24,13 @@ function readConflict(table, value, allow = NO_ALLOW, tenantKey) {
|
|
|
24
24
|
if (value === "ignore")
|
|
25
25
|
return { kind: "ignore", columns: [], update: [] };
|
|
26
26
|
if (!isRecord(value)) {
|
|
27
|
-
|
|
27
|
+
fail2("OKM1120", 'onConflict must be "error", "ignore", { on, update }, or { on, return: true }.');
|
|
28
28
|
}
|
|
29
29
|
const keys = Object.keys(value);
|
|
30
30
|
const update = value.update;
|
|
31
31
|
const ret = value.return;
|
|
32
32
|
if (update !== undefined && ret !== undefined) {
|
|
33
|
-
|
|
33
|
+
fail2("OKM1120", "onConflict takes update or return, not both.");
|
|
34
34
|
}
|
|
35
35
|
if (ret === true) {
|
|
36
36
|
rejectConflictKeys(keys, ["on", "return"]);
|
|
@@ -44,9 +44,9 @@ function readConflict(table, value, allow = NO_ALLOW, tenantKey) {
|
|
|
44
44
|
update: updateColumns(table, update, allow)
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
fail2("OKM1120", 'onConflict must be "error", "ignore", { on, update }, or { on, return: true }.');
|
|
48
48
|
}
|
|
49
|
-
function finishInsert(head, returning, params, plan, table
|
|
49
|
+
function finishInsert(head, returning, params, plan, table) {
|
|
50
50
|
if (plan.kind === "ignore") {
|
|
51
51
|
return { text: `${head} on conflict do nothing${returning}`, params: [...params] };
|
|
52
52
|
}
|
|
@@ -66,10 +66,13 @@ function finishInsert(head, returning, params, plan, table, returningColumns, ke
|
|
|
66
66
|
params: [...params]
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
return
|
|
69
|
+
return {
|
|
70
|
+
text: `${head} on conflict (${target})${conflictWhere(table, plan.columns)} do nothing${returning}`,
|
|
71
|
+
params: [...params]
|
|
72
|
+
};
|
|
70
73
|
}
|
|
71
|
-
function
|
|
72
|
-
const
|
|
74
|
+
function lookupExisting(table, keys, returningColumns, keyRows) {
|
|
75
|
+
const params = [];
|
|
73
76
|
const tuples = [];
|
|
74
77
|
for (const row of keyRows) {
|
|
75
78
|
const slots = [];
|
|
@@ -77,18 +80,21 @@ function firstOrCreate(head, returning, params, keys, table, returningColumns, k
|
|
|
77
80
|
const column = keys[index];
|
|
78
81
|
if (column === undefined)
|
|
79
82
|
continue;
|
|
80
|
-
|
|
81
|
-
slots.push(`$${String(
|
|
83
|
+
params.push(row[index] ?? null);
|
|
84
|
+
slots.push(`$${String(params.length)}::${column.dataType}`);
|
|
82
85
|
}
|
|
83
86
|
tuples.push(keys.length === 1 ? slots[0] ?? "null" : `(${slots.join(", ")})`);
|
|
84
87
|
}
|
|
85
|
-
const keyList = keys.map((column) => quote(column.sql)).join(", ");
|
|
86
88
|
const left = keys.length === 1 ? `t.${quote(keys[0]?.sql ?? "")}` : `(${keys.map((column) => `t.${quote(column.sql)}`).join(", ")})`;
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
const projected = returningColumns.map((column) => projectExpr(`t.${quote(column.sql)}`, column.dataType)).join(", ");
|
|
90
|
+
const text = `select ${projected} from ${quote(table.model.sql)} t where ${left} in (${tuples.join(", ")})${activeAnd(table, keys)}`;
|
|
91
|
+
return { text, params };
|
|
92
|
+
}
|
|
93
|
+
function activeAnd(table, columns) {
|
|
94
|
+
const clause = conflictWhere(table, columns);
|
|
95
|
+
if (clause === "")
|
|
96
|
+
return "";
|
|
97
|
+
return ` and t.${clause.replace(/^ where /, "")}`;
|
|
92
98
|
}
|
|
93
99
|
function conflictWhere(table, columns) {
|
|
94
100
|
const archive = table.model.archive;
|
|
@@ -112,27 +118,29 @@ function samePrimary(table, columns) {
|
|
|
112
118
|
}
|
|
113
119
|
function uniqueColumns(table, on, tenantKey) {
|
|
114
120
|
const names = conflictNames(on);
|
|
121
|
+
const keys = keyList(tenantKey);
|
|
115
122
|
for (const unique of table.model.uniques) {
|
|
116
|
-
|
|
123
|
+
const fields = fieldsOf(unique, names, keys);
|
|
124
|
+
if (fields === undefined)
|
|
117
125
|
continue;
|
|
118
126
|
const columns = [];
|
|
119
|
-
for (const name of
|
|
127
|
+
for (const name of fields) {
|
|
120
128
|
const column = table.columns.get(name);
|
|
121
129
|
if (column === undefined) {
|
|
122
|
-
|
|
130
|
+
fail2("OKM1104", `onConflict column ${name} is not on ${table.model.name}.`);
|
|
123
131
|
}
|
|
124
132
|
columns.push(column);
|
|
125
133
|
}
|
|
126
134
|
return columns;
|
|
127
135
|
}
|
|
128
|
-
const accepted = acceptedConstraints(table.model,
|
|
129
|
-
const implicit =
|
|
136
|
+
const accepted = acceptedConstraints(table.model, keys);
|
|
137
|
+
const implicit = keys.length === 0 ? "" : ` The tenant key ${keys.join(", ")} is part of each one and is not named here.`;
|
|
130
138
|
throwNamed2("OKM1104", names.join(", "), accepted, `onConflict on ${table.model.name} names ${names.join(", ")}, which is not a unique constraint. Accepted: ${list(accepted)}.${implicit}`);
|
|
131
139
|
}
|
|
132
|
-
function acceptedConstraints(model,
|
|
140
|
+
function acceptedConstraints(model, keys) {
|
|
133
141
|
const shown = new Set;
|
|
134
142
|
for (const fields of model.uniques) {
|
|
135
|
-
const named =
|
|
143
|
+
const named = keys.length === 0 ? fields : fields.filter((field) => !keys.includes(field));
|
|
136
144
|
if (named.length === 0)
|
|
137
145
|
continue;
|
|
138
146
|
shown.add(named.length > 1 ? `(${named.join(", ")})` : named.join(""));
|
|
@@ -141,12 +149,12 @@ function acceptedConstraints(model, key) {
|
|
|
141
149
|
}
|
|
142
150
|
function updateColumns(table, value, allow) {
|
|
143
151
|
if (!Array.isArray(value) || value.length === 0) {
|
|
144
|
-
|
|
152
|
+
fail2("OKM1120", "onConflict update must name at least one column.");
|
|
145
153
|
}
|
|
146
154
|
const columns = [];
|
|
147
155
|
for (const name of value) {
|
|
148
156
|
if (typeof name !== "string")
|
|
149
|
-
|
|
157
|
+
fail2("OKM1120", "onConflict update must name columns.");
|
|
150
158
|
const column = table.columns.get(name);
|
|
151
159
|
if (column === undefined) {
|
|
152
160
|
throwNamed2("OKM1120", name, table.names, `Field ${name} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
@@ -164,7 +172,29 @@ function conflictNames(on) {
|
|
|
164
172
|
if (Array.isArray(on) && on.length > 0 && on.every((name) => typeof name === "string")) {
|
|
165
173
|
return on;
|
|
166
174
|
}
|
|
167
|
-
|
|
175
|
+
fail2("OKM1104", "onConflict on must name a unique constraint's columns.");
|
|
176
|
+
}
|
|
177
|
+
function fieldsOf(unique, names, tenantKeys) {
|
|
178
|
+
if (tenantKeys.some((key) => unique.includes(key))) {
|
|
179
|
+
const rest = [];
|
|
180
|
+
for (const field of unique) {
|
|
181
|
+
if (!tenantKeys.includes(field))
|
|
182
|
+
rest.push(field);
|
|
183
|
+
}
|
|
184
|
+
if (!same(rest, names))
|
|
185
|
+
return;
|
|
186
|
+
return unique;
|
|
187
|
+
}
|
|
188
|
+
if (!same(unique, names))
|
|
189
|
+
return;
|
|
190
|
+
return names;
|
|
191
|
+
}
|
|
192
|
+
function keyList(tenantKey) {
|
|
193
|
+
if (tenantKey === undefined)
|
|
194
|
+
return [];
|
|
195
|
+
if (typeof tenantKey === "string")
|
|
196
|
+
return [tenantKey];
|
|
197
|
+
return tenantKey;
|
|
168
198
|
}
|
|
169
199
|
function same(unique, names) {
|
|
170
200
|
if (unique.length !== names.length)
|
|
@@ -186,17 +216,18 @@ function rejectConflictKeys(keys, accepted) {
|
|
|
186
216
|
}
|
|
187
217
|
function refuseWrite(table, column) {
|
|
188
218
|
if (fieldSealed(table.model, column.field)) {
|
|
189
|
-
|
|
219
|
+
fail2("OKM1190", `Field ${table.model.name}.${column.field} is set by a trait. Input cannot set it.`);
|
|
190
220
|
}
|
|
191
221
|
if (column.guardUpdate) {
|
|
192
|
-
|
|
222
|
+
fail2("OKM1190", `Field ${table.model.name}.${column.field} is a primary key. Input cannot change it.`);
|
|
193
223
|
}
|
|
194
224
|
if (column.guarded) {
|
|
195
|
-
|
|
225
|
+
fail2("OKM1190", `Field ${table.model.name}.${column.field} is guarded. Input cannot set it.`);
|
|
196
226
|
}
|
|
197
|
-
|
|
227
|
+
fail2("OKM1120", `Field ${table.model.name}.${column.field} cannot be written.`);
|
|
198
228
|
}
|
|
199
229
|
export {
|
|
200
230
|
finishInsert,
|
|
231
|
+
lookupExisting,
|
|
201
232
|
readConflict
|
|
202
233
|
};
|