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
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
serializeCatalog2
|
|
3
|
-
|
|
4
|
-
startupCatalog2,
|
|
5
|
-
parseCatalog2
|
|
6
|
-
} from "./8bwbwy8h.js";
|
|
2
|
+
serializeCatalog2
|
|
3
|
+
} from "./qq3899ht.js";
|
|
7
4
|
import {
|
|
8
5
|
roleExists
|
|
9
|
-
} from "./
|
|
6
|
+
} from "./8skf0cam.js";
|
|
10
7
|
import {
|
|
11
8
|
canonicalTypeName,
|
|
12
9
|
createdRoleName,
|
|
@@ -17,30 +14,30 @@ import {
|
|
|
17
14
|
checkedCast,
|
|
18
15
|
omitManagedObjects,
|
|
19
16
|
planMigration,
|
|
20
|
-
|
|
17
|
+
sessionFailure,
|
|
21
18
|
assertTargetPolicy
|
|
22
|
-
} from "./
|
|
19
|
+
} from "./tsvww22q.js";
|
|
23
20
|
import {
|
|
24
21
|
quoteIdent,
|
|
25
22
|
qualify
|
|
26
|
-
} from "./
|
|
23
|
+
} from "./9s0ypp87.js";
|
|
27
24
|
import {
|
|
28
25
|
alignExtensionVersions
|
|
29
|
-
} from "./
|
|
26
|
+
} from "./r3j8s5y0.js";
|
|
30
27
|
import {
|
|
31
28
|
catalog,
|
|
32
29
|
isDomain
|
|
33
|
-
} from "./
|
|
30
|
+
} from "./ywspezzx.js";
|
|
34
31
|
import {
|
|
35
32
|
snakeCase
|
|
36
|
-
} from "./
|
|
33
|
+
} from "./rpycarcr.js";
|
|
37
34
|
import {
|
|
38
35
|
quoteLiteral
|
|
39
36
|
} from "./94ez8kzh.js";
|
|
40
37
|
import {
|
|
41
38
|
identityKey2,
|
|
42
39
|
identityLabel2
|
|
43
|
-
} from "./
|
|
40
|
+
} from "./358zsv4r.js";
|
|
44
41
|
import {
|
|
45
42
|
OkmError2
|
|
46
43
|
} from "./52szzakm.js";
|
|
@@ -76,6 +73,16 @@ async function assumeRole(connection, role, session) {
|
|
|
76
73
|
await connection.execute(`set role ${quoteIdent(role)}`);
|
|
77
74
|
session.setRole = role;
|
|
78
75
|
}
|
|
76
|
+
async function grantAppMeta(connection, role, session) {
|
|
77
|
+
if (role === undefined)
|
|
78
|
+
return;
|
|
79
|
+
const previous = session.setRole;
|
|
80
|
+
if (previous !== undefined)
|
|
81
|
+
await connection.execute("reset role");
|
|
82
|
+
await connection.execute(`grant select on okm_meta to ${quoteIdent(role)}`);
|
|
83
|
+
if (previous !== undefined)
|
|
84
|
+
await connection.execute(`set role ${quoteIdent(previous)}`);
|
|
85
|
+
}
|
|
79
86
|
async function grantSchema(connection, schema, role) {
|
|
80
87
|
await connection.execute(`grant usage, create on schema ${quoteIdent(schema)} to ${quoteIdent(role)}`);
|
|
81
88
|
}
|
|
@@ -98,9 +105,10 @@ async function runUnit(connection, unit, run, session) {
|
|
|
98
105
|
await rebuildInvalidIndex(connection, item.step.sql);
|
|
99
106
|
const created = createdRoleName(item.step.sql);
|
|
100
107
|
const existed = created !== undefined && await roleExists(connection, created);
|
|
101
|
-
if (created === undefined)
|
|
108
|
+
if (created === undefined) {
|
|
102
109
|
await connection.execute(item.step.sql);
|
|
103
|
-
|
|
110
|
+
await assertSchemaUsageLanded(connection, item.step.sql);
|
|
111
|
+
} else if (!existed)
|
|
104
112
|
await connection.execute(createRoleOnce(item.step.sql));
|
|
105
113
|
if (created !== undefined && created === run.migrationRole) {
|
|
106
114
|
if (!existed) {
|
|
@@ -303,7 +311,35 @@ function concurrentIndexName(sql) {
|
|
|
303
311
|
const match = /^create\s+(?:unique\s+)?index\s+concurrently\s+(?:if\s+not\s+exists\s+)?(?:"([^"]+)"|([A-Za-z_][\w$]*))/i.exec(sql.trim());
|
|
304
312
|
return match?.[1] ?? match?.[2];
|
|
305
313
|
}
|
|
314
|
+
var SCHEMA_USAGE = /^\s*grant\s+usage\s+on\s+schema\s+(?:"((?:[^"]|"")*)"|([A-Za-z_][\w$]*))\s+to\s+(?:"((?:[^"]|"")*)"|([A-Za-z_][\w$]*))\s*;?\s*$/i;
|
|
315
|
+
async function assertSchemaUsageLanded(connection, sql) {
|
|
316
|
+
const match = SCHEMA_USAGE.exec(sql.trim());
|
|
317
|
+
if (match === null)
|
|
318
|
+
return;
|
|
319
|
+
const schema = (match[1] ?? match[2] ?? "").replaceAll('""', '"');
|
|
320
|
+
const role = (match[3] ?? match[4] ?? "").replaceAll('""', '"');
|
|
321
|
+
const found = await connection.execute(`select exists (
|
|
322
|
+
select 1
|
|
323
|
+
from pg_namespace n
|
|
324
|
+
cross join lateral aclexplode(n.nspacl) a
|
|
325
|
+
join pg_roles r on r.oid = a.grantee
|
|
326
|
+
where n.nspname = $1 and r.rolname = $2 and a.privilege_type = 'USAGE'
|
|
327
|
+
)`, [schema, role]);
|
|
328
|
+
const landed = found.rows[0]?.[0];
|
|
329
|
+
if (landed === "t" || landed === "true")
|
|
330
|
+
return;
|
|
331
|
+
throw new OkmError2("OKM1825", `Grant usage on schema ${schema} to ${role} did not take effect.`, {
|
|
332
|
+
kind: "forbidden",
|
|
333
|
+
fix: {
|
|
334
|
+
summary: `Make the migration role the owner of schema ${schema}. ALTER SCHEMA ${quoteIdent(schema)} OWNER TO <migration role>.`
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
306
338
|
function failStep(unit, index, error) {
|
|
339
|
+
const lost = sessionFailure(error);
|
|
340
|
+
if (lost !== undefined) {
|
|
341
|
+
return new OkmError2(lost.code, `Migration ${unit.migrationId} failed at step ${String(index + 1)}: ${lost.message}`, { kind: lost.kind, cause: error, fix: lost.fix });
|
|
342
|
+
}
|
|
307
343
|
if (error instanceof OkmError2)
|
|
308
344
|
return error;
|
|
309
345
|
const message = error instanceof Error ? error.message : "The step failed.";
|
|
@@ -360,44 +396,6 @@ function delay(ms) {
|
|
|
360
396
|
});
|
|
361
397
|
}
|
|
362
398
|
|
|
363
|
-
// src/tooling/migrate/files.ts
|
|
364
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
365
|
-
import { join } from "node:path";
|
|
366
|
-
function loadMigrations(directory) {
|
|
367
|
-
if (!existsSync(directory))
|
|
368
|
-
return [];
|
|
369
|
-
const names = readdirSync(directory).filter((file) => file.endsWith(".sql")).sort();
|
|
370
|
-
const migrations = [];
|
|
371
|
-
for (const file of names) {
|
|
372
|
-
const id = file.slice(0, -".sql".length);
|
|
373
|
-
const catalogPath = join(directory, `${id}.catalog.json`);
|
|
374
|
-
if (!existsSync(catalogPath)) {
|
|
375
|
-
throw new OkmError2("invalid", `Migration ${id} is missing its catalog snapshot.`, {
|
|
376
|
-
fix: {
|
|
377
|
-
summary: "Generate the migration again so the SQL and the catalog are written together."
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
const plan = parsePlan(readFileSync(join(directory, file), "utf8"));
|
|
382
|
-
const stored = parseCatalog2(readFileSync(catalogPath, "utf8"));
|
|
383
|
-
const startup = startupCatalog2(stored);
|
|
384
|
-
const hash = catalogHash2(startup);
|
|
385
|
-
migrations.push(startup === stored ? { id, catalogHash: hash, steps: plan.steps } : { id, catalogHash: hash, legacyHash: catalogHash2(stored), steps: plan.steps });
|
|
386
|
-
}
|
|
387
|
-
return migrations;
|
|
388
|
-
}
|
|
389
|
-
function loadHeadSnapshot(directory) {
|
|
390
|
-
const migrations = loadMigrations(directory);
|
|
391
|
-
const last = migrations.at(-1);
|
|
392
|
-
if (last === undefined)
|
|
393
|
-
return;
|
|
394
|
-
return {
|
|
395
|
-
id: last.id,
|
|
396
|
-
catalogHash: last.catalogHash,
|
|
397
|
-
catalog: parseCatalog2(readFileSync(join(directory, `${last.id}.catalog.json`), "utf8"))
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
399
|
// src/tooling/migrate/reference.ts
|
|
402
400
|
function readReference(tables, casing, head) {
|
|
403
401
|
const declared = [];
|
|
@@ -588,8 +586,10 @@ async function installSnapshot(connection, head, schema, reference, session, mig
|
|
|
588
586
|
return;
|
|
589
587
|
await connection.execute("begin");
|
|
590
588
|
began = true;
|
|
591
|
-
for (const sql of batch)
|
|
589
|
+
for (const sql of batch) {
|
|
592
590
|
await connection.execute(sql);
|
|
591
|
+
await assertSchemaUsageLanded(connection, sql);
|
|
592
|
+
}
|
|
593
593
|
await connection.execute("commit");
|
|
594
594
|
began = false;
|
|
595
595
|
batch.length = 0;
|
|
@@ -611,6 +611,7 @@ async function installSnapshot(connection, head, schema, reference, session, mig
|
|
|
611
611
|
} else {
|
|
612
612
|
await flush();
|
|
613
613
|
await connection.execute(sql);
|
|
614
|
+
await assertSchemaUsageLanded(connection, sql);
|
|
614
615
|
}
|
|
615
616
|
if (created !== undefined && created === migrationRole) {
|
|
616
617
|
await flush();
|
|
@@ -753,4 +754,4 @@ function normaliseFunction(object) {
|
|
|
753
754
|
};
|
|
754
755
|
}
|
|
755
756
|
|
|
756
|
-
export { runTarget, assumeRole,
|
|
757
|
+
export { runTarget, assumeRole, grantAppMeta, grantSchema, assertSchemaUsageLanded, statementOutsideTransaction, readReference, referenceInserts, catalogsEqual, provisionMark, expandProvisioned, provisionHistoryIsKnown, installSnapshot, snapshotDifference };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./
|
|
2
|
+
stack2
|
|
3
|
+
} from "./mss6ctgv.js";
|
|
4
4
|
import {
|
|
5
5
|
checkPresetNames
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./znm0bpp5.js";
|
|
7
7
|
import {
|
|
8
8
|
isOperator,
|
|
9
9
|
operatorValue
|
|
@@ -60,7 +60,7 @@ function refine(schema, call, uses) {
|
|
|
60
60
|
const { wheres, rules } = resolve(schema, call.table, uses);
|
|
61
61
|
return {
|
|
62
62
|
...call,
|
|
63
|
-
where:
|
|
63
|
+
where: stack2(call.where, wheres),
|
|
64
64
|
ruleLines: [...call.ruleLines ?? [], ...rules]
|
|
65
65
|
};
|
|
66
66
|
}
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "./cn0n68ft.js";
|
|
4
4
|
|
|
5
5
|
// src/runtime/preset-stack.ts
|
|
6
|
-
function
|
|
6
|
+
function stack2(where, presets) {
|
|
7
7
|
if (presets === undefined || presets.length === 0)
|
|
8
8
|
return where;
|
|
9
9
|
return tag("and", where === undefined ? presets : [where, ...presets]);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export {
|
|
12
|
+
export { stack2 };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isConnectionSqlstate,
|
|
3
3
|
isConnectionErrno
|
|
4
|
-
} from "./
|
|
4
|
+
} from "./cnkky55j.js";
|
|
5
5
|
import {
|
|
6
6
|
createClient
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./tbrvgw6z.js";
|
|
8
8
|
import {
|
|
9
9
|
OkmError2
|
|
10
10
|
} from "./52szzakm.js";
|
|
@@ -331,7 +331,8 @@ async function openEndpoint(open, url, max, defaults, name, role, weight, probeM
|
|
|
331
331
|
timer: undefined,
|
|
332
332
|
current: 0,
|
|
333
333
|
inflight: 0,
|
|
334
|
-
latencyMs: null
|
|
334
|
+
latencyMs: null,
|
|
335
|
+
generation: 0
|
|
335
336
|
};
|
|
336
337
|
}
|
|
337
338
|
async function detectPosition(endpoint) {
|
|
@@ -345,8 +346,11 @@ async function detectPosition(endpoint) {
|
|
|
345
346
|
async function sample(handle, endpoint) {
|
|
346
347
|
try {
|
|
347
348
|
const sampled = await readPosition(handle, endpoint);
|
|
349
|
+
const reopened = endpoint.circuit === "open";
|
|
348
350
|
endpoint.failures = 0;
|
|
349
351
|
endpoint.circuit = "closed";
|
|
352
|
+
if (reopened)
|
|
353
|
+
endpoint.generation += 1;
|
|
350
354
|
applySample(endpoint, sampled);
|
|
351
355
|
} catch {
|
|
352
356
|
endpoint.failures += 1;
|
|
@@ -502,7 +506,7 @@ function routePool(handle) {
|
|
|
502
506
|
execute: async (text, params, options) => {
|
|
503
507
|
if (handle.closed)
|
|
504
508
|
closed();
|
|
505
|
-
const choice = await
|
|
509
|
+
const choice = await resolve(handle, text, options);
|
|
506
510
|
const result = await attempt(handle, choice, (endpoint) => endpoint.pool.execute(text, params, strip(options)));
|
|
507
511
|
if (choice.op === "write")
|
|
508
512
|
await noteWrite(handle, primary.pool);
|
|
@@ -515,6 +519,7 @@ function routePool(handle) {
|
|
|
515
519
|
replicaRefused();
|
|
516
520
|
const reason = options?.route === "primary" ? "constraint:primary" : "primary-required";
|
|
517
521
|
tell(handle, { op: "write", endpoint: primary.name, reason });
|
|
522
|
+
await callGuard(primary);
|
|
518
523
|
const result = await primary.pool.batch(statements, strip(options));
|
|
519
524
|
await noteWrite(handle, primary.pool);
|
|
520
525
|
return result;
|
|
@@ -555,6 +560,14 @@ function routePool(handle) {
|
|
|
555
560
|
endpoint.pool.cancel?.();
|
|
556
561
|
};
|
|
557
562
|
}
|
|
563
|
+
const routed = pool;
|
|
564
|
+
routed.okmReadOnlyUnit = (text, params, prelude, options) => readOnlyUnit(handle, text, params, prelude, options);
|
|
565
|
+
routed.okmReadOnlyStream = (text, params, prelude, options) => readOnlyStream(handle, text, params, prelude, options);
|
|
566
|
+
routed.okmEndpoints = () => handle.endpoints.map((endpoint) => ({
|
|
567
|
+
name: endpoint.name,
|
|
568
|
+
generation: endpoint.generation,
|
|
569
|
+
pool: endpoint.pool
|
|
570
|
+
}));
|
|
558
571
|
return pool;
|
|
559
572
|
}
|
|
560
573
|
function derive(schema, handle, router, shared, route) {
|
|
@@ -601,8 +614,82 @@ function force(handle, router, route) {
|
|
|
601
614
|
}
|
|
602
615
|
if (router.cancel !== undefined)
|
|
603
616
|
pool.cancel = () => router.cancel();
|
|
617
|
+
const unit = router.okmReadOnlyUnit;
|
|
618
|
+
const stream = router.okmReadOnlyStream;
|
|
619
|
+
const forced = pool;
|
|
620
|
+
if (unit !== undefined) {
|
|
621
|
+
forced.okmReadOnlyUnit = (text, params, prelude, options) => unit(text, params, prelude, { ...options, route });
|
|
622
|
+
}
|
|
623
|
+
if (stream !== undefined) {
|
|
624
|
+
forced.okmReadOnlyStream = (text, params, prelude, options) => stream(text, params, prelude, { ...options, route });
|
|
625
|
+
}
|
|
604
626
|
return pool;
|
|
605
627
|
}
|
|
628
|
+
async function readOnlyUnit(handle, text, params, prelude, options) {
|
|
629
|
+
if (handle.closed)
|
|
630
|
+
closed();
|
|
631
|
+
const choice = await resolve(handle, text, options);
|
|
632
|
+
return attempt(handle, choice, async (endpoint) => {
|
|
633
|
+
if (endpoint.pool.reserve === undefined)
|
|
634
|
+
replicaReserve();
|
|
635
|
+
const conn = await endpoint.pool.reserve();
|
|
636
|
+
try {
|
|
637
|
+
await conn.execute("begin read only");
|
|
638
|
+
try {
|
|
639
|
+
await conn.execute(prelude.text, prelude.params);
|
|
640
|
+
const result = await conn.execute(text, params, strip(options));
|
|
641
|
+
await conn.execute("commit");
|
|
642
|
+
return result;
|
|
643
|
+
} catch (error) {
|
|
644
|
+
await conn.execute("rollback").catch(() => {
|
|
645
|
+
return;
|
|
646
|
+
});
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
} finally {
|
|
650
|
+
await conn.release();
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
function readOnlyStream(handle, text, params, prelude, options) {
|
|
655
|
+
return async function* () {
|
|
656
|
+
if (handle.closed)
|
|
657
|
+
closed();
|
|
658
|
+
const choice = await choose(handle, text, options?.route);
|
|
659
|
+
tell(handle, { op: choice.op, endpoint: choice.endpoint.name, reason: choice.reason });
|
|
660
|
+
await callGuard(choice.endpoint);
|
|
661
|
+
if (choice.endpoint.pool.reserve === undefined)
|
|
662
|
+
replicaReserve();
|
|
663
|
+
const conn = await choice.endpoint.pool.reserve();
|
|
664
|
+
try {
|
|
665
|
+
await conn.execute("begin read only");
|
|
666
|
+
try {
|
|
667
|
+
await conn.execute(prelude.text, prelude.params);
|
|
668
|
+
await conn.execute(`declare okm_rls no scroll cursor for ${text}`, params);
|
|
669
|
+
for (;; ) {
|
|
670
|
+
const chunk = await conn.execute("fetch 64 from okm_rls");
|
|
671
|
+
if (chunk.rows.length === 0)
|
|
672
|
+
break;
|
|
673
|
+
yield chunk.rows;
|
|
674
|
+
}
|
|
675
|
+
await conn.execute("close okm_rls");
|
|
676
|
+
await conn.execute("commit");
|
|
677
|
+
} catch (error) {
|
|
678
|
+
await conn.execute("rollback").catch(() => {
|
|
679
|
+
return;
|
|
680
|
+
});
|
|
681
|
+
throw error;
|
|
682
|
+
}
|
|
683
|
+
} finally {
|
|
684
|
+
await conn.release();
|
|
685
|
+
}
|
|
686
|
+
}();
|
|
687
|
+
}
|
|
688
|
+
function replicaReserve() {
|
|
689
|
+
throw new OkmError2("OKM1111", "Row-level security needs a driver that can reserve a connection.", {
|
|
690
|
+
fix: { summary: "Use a Postgres driver that supports interactive transactions." }
|
|
691
|
+
});
|
|
692
|
+
}
|
|
606
693
|
function classOf(text) {
|
|
607
694
|
const head = text.trimStart().toLowerCase().replace(/\s+/g, " ");
|
|
608
695
|
if (/^(begin|start transaction|commit|rollback|savepoint|release|set|reset)\b/.test(head)) {
|
|
@@ -612,7 +699,7 @@ function classOf(text) {
|
|
|
612
699
|
return "lock";
|
|
613
700
|
if (/\sfor (no key update|key share|update|share)\b/.test(head))
|
|
614
701
|
return "lock";
|
|
615
|
-
if (/^(insert|update|delete|with|create|alter|drop|truncate|grant|revoke|comment|vacuum|analyze|reindex|copy)\b/.test(head)) {
|
|
702
|
+
if (/^(insert|update|delete|refresh|with|create|alter|drop|truncate|grant|revoke|comment|vacuum|analyze|reindex|copy)\b/.test(head)) {
|
|
616
703
|
return "write";
|
|
617
704
|
}
|
|
618
705
|
return "read";
|
|
@@ -626,7 +713,7 @@ async function choose(handle, text, route) {
|
|
|
626
713
|
if (primary === undefined)
|
|
627
714
|
throw new OkmError2("OKM1120", "A topology needs one primary URL.");
|
|
628
715
|
if (text.trimStart().toLowerCase().startsWith("select current_setting")) {
|
|
629
|
-
return { endpoint: primary, op: "read", reason: "primary-required" };
|
|
716
|
+
return { endpoint: primary, op: "read", reason: "primary-required", skipGuard: true };
|
|
630
717
|
}
|
|
631
718
|
if (route === "replica" && op !== "read")
|
|
632
719
|
replicaRefused();
|
|
@@ -673,17 +760,32 @@ async function* readStream(handle, text, route, params, fallback) {
|
|
|
673
760
|
async function attempt(handle, choice, run) {
|
|
674
761
|
tell(handle, { op: choice.op, endpoint: choice.endpoint.name, reason: choice.reason });
|
|
675
762
|
try {
|
|
763
|
+
if (choice.skipGuard !== true)
|
|
764
|
+
await callGuard(choice.endpoint);
|
|
676
765
|
return await tracked(choice.endpoint, choice.op === "read", () => run(choice.endpoint));
|
|
677
766
|
} catch (error) {
|
|
678
|
-
if (choice.op !== "read" || !isUnreachable(error))
|
|
767
|
+
if (choice.pinned === true || choice.op !== "read" || !isUnreachable(error))
|
|
679
768
|
throw error;
|
|
769
|
+
choice.endpoint.generation += 1;
|
|
680
770
|
const next = await retryOf(handle, choice);
|
|
681
771
|
if (next === undefined)
|
|
682
772
|
throw error;
|
|
683
773
|
tell(handle, { op: "read", endpoint: next.endpoint.name, reason: next.reason });
|
|
774
|
+
if (choice.skipGuard !== true)
|
|
775
|
+
await callGuard(next.endpoint);
|
|
684
776
|
return tracked(next.endpoint, true, () => run(next.endpoint));
|
|
685
777
|
}
|
|
686
778
|
}
|
|
779
|
+
function callGuard(endpoint) {
|
|
780
|
+
const guard = endpoint.pool.okmGuard;
|
|
781
|
+
if (guard === undefined)
|
|
782
|
+
return Promise.resolve();
|
|
783
|
+
return guard({
|
|
784
|
+
name: endpoint.name,
|
|
785
|
+
generation: endpoint.generation,
|
|
786
|
+
pool: endpoint.pool
|
|
787
|
+
});
|
|
788
|
+
}
|
|
687
789
|
var CHAIN_DEPTH = 8;
|
|
688
790
|
function isUnreachable(error) {
|
|
689
791
|
const seen = new Set;
|
|
@@ -715,9 +817,7 @@ function unreachableNode(node) {
|
|
|
715
817
|
return true;
|
|
716
818
|
}
|
|
717
819
|
}
|
|
718
|
-
|
|
719
|
-
return false;
|
|
720
|
-
return node.message.includes("ECONNREFUSED") || node.message.includes("ECONNRESET") || node.message.includes("CONNECTION_CLOSED") || node.message.includes("terminating connection") || node.message.includes("The pool is closed");
|
|
820
|
+
return false;
|
|
721
821
|
}
|
|
722
822
|
async function tracked(endpoint, time, run) {
|
|
723
823
|
const replica = endpoint.role === "replica";
|
|
@@ -1007,13 +1107,45 @@ function noteFailure(endpoint) {
|
|
|
1007
1107
|
endpoint.circuit = "open";
|
|
1008
1108
|
}
|
|
1009
1109
|
function strip(options) {
|
|
1010
|
-
if (options === undefined
|
|
1110
|
+
if (options === undefined)
|
|
1111
|
+
return;
|
|
1112
|
+
if (!("route" in options) && !("pin" in options))
|
|
1011
1113
|
return options;
|
|
1012
|
-
const
|
|
1114
|
+
const bag = options;
|
|
1115
|
+
const { route: _route, pin: _pin, ...rest } = bag;
|
|
1013
1116
|
if (rest.signal === undefined && rest.timeout === undefined)
|
|
1014
1117
|
return;
|
|
1015
1118
|
return rest;
|
|
1016
1119
|
}
|
|
1120
|
+
async function resolve(handle, text, options) {
|
|
1121
|
+
const pin = taken(options);
|
|
1122
|
+
if (pin?.name !== undefined)
|
|
1123
|
+
return held(handle, pin.name);
|
|
1124
|
+
const choice = await choose(handle, text, options?.route);
|
|
1125
|
+
if (pin !== undefined && choice.op === "read") {
|
|
1126
|
+
pin.name = choice.endpoint.name;
|
|
1127
|
+
return { ...choice, pinned: true };
|
|
1128
|
+
}
|
|
1129
|
+
return choice;
|
|
1130
|
+
}
|
|
1131
|
+
function taken(options) {
|
|
1132
|
+
if (options === undefined || !("pin" in options))
|
|
1133
|
+
return;
|
|
1134
|
+
const pin = options.pin;
|
|
1135
|
+
if (typeof pin !== "object" || pin === null)
|
|
1136
|
+
return;
|
|
1137
|
+
return pin;
|
|
1138
|
+
}
|
|
1139
|
+
function held(handle, name) {
|
|
1140
|
+
for (const endpoint of handle.endpoints) {
|
|
1141
|
+
if (endpoint.name !== name)
|
|
1142
|
+
continue;
|
|
1143
|
+
return { endpoint, op: "read", reason: `stream:${name}`, pinned: true };
|
|
1144
|
+
}
|
|
1145
|
+
throw new OkmError2("OKM1120", `stream() stays on ${name}. That target is not in this topology.`, {
|
|
1146
|
+
fix: { summary: "The first batch chose this target. Later batches do not move." }
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1017
1149
|
async function noteWrite(handle, runner) {
|
|
1018
1150
|
if (!tracks(handle))
|
|
1019
1151
|
return;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord,
|
|
3
|
+
orFail
|
|
4
|
+
} from "./67txcrcw.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,18 @@
|
|
|
1
|
+
// src/dialects/pg/ops/bucket.ts
|
|
2
|
+
var RUNTIME = Symbol.for("okmodel.bucket");
|
|
3
|
+
function bucket2(column, unit, options) {
|
|
4
|
+
const spec = options ?? { as: undefined, tz: undefined, weekStart: undefined };
|
|
5
|
+
return {
|
|
6
|
+
[RUNTIME]: true,
|
|
7
|
+
column,
|
|
8
|
+
unit,
|
|
9
|
+
as: spec.as,
|
|
10
|
+
tz: spec.tz,
|
|
11
|
+
weekStart: spec.weekStart
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function isBucket(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && RUNTIME in value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { bucket2, isBucket };
|