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,51 +1,51 @@
|
|
|
1
1
|
import {
|
|
2
2
|
open2
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./wkme6tep.js";
|
|
4
4
|
import {
|
|
5
5
|
startupHash2
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./qq3899ht.js";
|
|
7
7
|
import {
|
|
8
8
|
runTarget,
|
|
9
9
|
assumeRole,
|
|
10
|
+
grantAppMeta,
|
|
10
11
|
statementOutsideTransaction,
|
|
11
|
-
loadMigrations,
|
|
12
|
-
loadHeadSnapshot,
|
|
13
12
|
readReference,
|
|
14
13
|
referenceInserts,
|
|
15
14
|
provisionMark,
|
|
16
15
|
expandProvisioned,
|
|
17
16
|
installSnapshot
|
|
18
|
-
} from "./
|
|
17
|
+
} from "./p248q79y.js";
|
|
19
18
|
import {
|
|
20
19
|
assertCreateRole,
|
|
21
20
|
currentUser,
|
|
22
21
|
roleExists
|
|
23
|
-
} from "./
|
|
22
|
+
} from "./knmes2kh.js";
|
|
24
23
|
import {
|
|
24
|
+
projectPath,
|
|
25
|
+
loadMigrations,
|
|
26
|
+
loadHeadSnapshot,
|
|
25
27
|
lintMigrationDirectory,
|
|
26
28
|
hasError,
|
|
27
29
|
lintRefusal,
|
|
28
30
|
projectHead,
|
|
29
31
|
loadBuiltSchema,
|
|
30
32
|
loadConfig
|
|
31
|
-
} from "./
|
|
33
|
+
} from "./t3g0k88x.js";
|
|
32
34
|
import {
|
|
33
35
|
changesRole,
|
|
34
36
|
batchSizeField,
|
|
35
37
|
assertExtensionsAvailable,
|
|
36
38
|
planMigration,
|
|
39
|
+
finishQuiet,
|
|
37
40
|
assertTargetPolicy,
|
|
38
41
|
assertDirectConnection,
|
|
39
42
|
assertStableBackend,
|
|
40
43
|
selectTarget
|
|
41
|
-
} from "./
|
|
44
|
+
} from "./ttmg09vd.js";
|
|
42
45
|
import {
|
|
43
46
|
OkmError2
|
|
44
47
|
} from "./52szzakm.js";
|
|
45
48
|
|
|
46
|
-
// src/tooling/migrate/apply.ts
|
|
47
|
-
import { join } from "node:path";
|
|
48
|
-
|
|
49
49
|
// src/tooling/migrate/engine.ts
|
|
50
50
|
var IDENT = String.raw`"(?:[^"]|"")+"|[A-Za-z_][\w$]*`;
|
|
51
51
|
var DEFAULT_UUIDV7 = /\bdefault\s+uuidv7\s*\(\s*\)/i;
|
|
@@ -121,6 +121,11 @@ var BACKFILL = `create table if not exists okm_backfill (
|
|
|
121
121
|
updated_at timestamptz not null default now(),
|
|
122
122
|
primary key (migration_id, step_index)
|
|
123
123
|
)`;
|
|
124
|
+
async function ensureMigrationTables2(execute) {
|
|
125
|
+
await execute(META);
|
|
126
|
+
await execute(HISTORY);
|
|
127
|
+
await execute(BACKFILL);
|
|
128
|
+
}
|
|
124
129
|
function applyUnits(migration, done) {
|
|
125
130
|
const pending = [];
|
|
126
131
|
for (let index = 0;index < migration.steps.length; index += 1) {
|
|
@@ -175,7 +180,8 @@ async function applyTarget2(request) {
|
|
|
175
180
|
fix: { summary: "Apply needs a driver with interactive transactions." }
|
|
176
181
|
});
|
|
177
182
|
}
|
|
178
|
-
const
|
|
183
|
+
const reserved = await pool.reserve();
|
|
184
|
+
const connection = reserved;
|
|
179
185
|
let locked = false;
|
|
180
186
|
try {
|
|
181
187
|
await assertStableBackend(() => backendPid(connection), request.allowPooler === true);
|
|
@@ -202,9 +208,7 @@ async function applyTarget2(request) {
|
|
|
202
208
|
throw notEmpty(request.target, state.kind === "occupied" ? state.object : "okm_meta");
|
|
203
209
|
}
|
|
204
210
|
}
|
|
205
|
-
await connection.execute(
|
|
206
|
-
await connection.execute(HISTORY);
|
|
207
|
-
await connection.execute(BACKFILL);
|
|
211
|
+
await ensureMigrationTables2((sql) => connection.execute(sql));
|
|
208
212
|
const restamped = await restampLegacy(connection, request);
|
|
209
213
|
const history = await readHistory(connection);
|
|
210
214
|
const done = expandProvisioned(request.migrations, history.done, history.ids);
|
|
@@ -225,14 +229,14 @@ async function applyTarget2(request) {
|
|
|
225
229
|
if (request.snapshot !== undefined) {
|
|
226
230
|
await insertReference(connection, request);
|
|
227
231
|
}
|
|
232
|
+
await grantAppMeta(connection, request.appRole, session);
|
|
228
233
|
return restamped.length === 0 ? report : { ...report, restamped };
|
|
229
234
|
} finally {
|
|
230
|
-
if (locked)
|
|
231
|
-
await connection.execute("select pg_advisory_unlock(hashtext($1))", [
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
await
|
|
235
|
-
await pool.close();
|
|
235
|
+
if (locked) {
|
|
236
|
+
await finishQuiet(() => connection.execute("select pg_advisory_unlock(hashtext($1))", [lockKey(request.target)]));
|
|
237
|
+
}
|
|
238
|
+
await finishQuiet(() => connection.release());
|
|
239
|
+
await finishQuiet(() => pool.close());
|
|
236
240
|
}
|
|
237
241
|
}
|
|
238
242
|
async function applyProject2(cwd, flags, write) {
|
|
@@ -267,7 +271,7 @@ nothing to apply
|
|
|
267
271
|
catalogHash: head.catalogHash,
|
|
268
272
|
reference: built === undefined ? [] : readReference(built.tables, built.casing, head.catalog)
|
|
269
273
|
},
|
|
270
|
-
...config.roles !== undefined ? { migrationRole: config.roles.migration } : {},
|
|
274
|
+
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {},
|
|
271
275
|
lintDirectory: directory,
|
|
272
276
|
onProgress: (line) => {
|
|
273
277
|
if (write !== undefined)
|
|
@@ -314,7 +318,7 @@ no changes
|
|
|
314
318
|
steps: plan.steps
|
|
315
319
|
}
|
|
316
320
|
],
|
|
317
|
-
...config.roles !== undefined ? { migrationRole: config.roles.migration } : {}
|
|
321
|
+
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {}
|
|
318
322
|
});
|
|
319
323
|
return formatReport(report);
|
|
320
324
|
}
|
|
@@ -380,7 +384,7 @@ var RESTAMP = `with pairs as (
|
|
|
380
384
|
)
|
|
381
385
|
select distinct id from history order by id`;
|
|
382
386
|
function joinMigrations(cwd, migrations) {
|
|
383
|
-
return
|
|
387
|
+
return projectPath(cwd, migrations ?? "migrations");
|
|
384
388
|
}
|
|
385
389
|
async function backendPid(connection) {
|
|
386
390
|
const result = await connection.execute("select pg_backend_pid()::text");
|
|
@@ -464,10 +468,9 @@ async function provisionEmpty(connection, request, session) {
|
|
|
464
468
|
assertTargetPolicy({ name: request.target, protected: request.protected }, "reference", request.allowProtected === true);
|
|
465
469
|
}
|
|
466
470
|
const schema = concreteSchema(request);
|
|
467
|
-
await connection.execute(
|
|
468
|
-
await connection.execute(HISTORY);
|
|
469
|
-
await connection.execute(BACKFILL);
|
|
471
|
+
await ensureMigrationTables2((sql) => connection.execute(sql));
|
|
470
472
|
await installSnapshot(connection, snapshot.catalog, schema, snapshot.reference, session, request.migrationRole);
|
|
473
|
+
await grantAppMeta(connection, request.appRole, session);
|
|
471
474
|
const mark = provisionMark(snapshot.migrationId);
|
|
472
475
|
await connection.execute("begin");
|
|
473
476
|
try {
|
|
@@ -601,4 +604,4 @@ function wireTrue(value) {
|
|
|
601
604
|
return value === "t" || value === "true";
|
|
602
605
|
}
|
|
603
606
|
|
|
604
|
-
export { applyTarget2, applyProject2, pushProject2, backfillTiming2 };
|
|
607
|
+
export { ensureMigrationTables2, applyTarget2, applyProject2, pushProject2, backfillTiming2 };
|
|
@@ -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 "./knmes2kh.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 "./ttmg09vd.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,20 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
open2
|
|
3
|
-
} from "./
|
|
4
|
-
import"./
|
|
3
|
+
} from "./wkme6tep.js";
|
|
4
|
+
import"./qq3899ht.js";
|
|
5
5
|
import"./n442h54c.js";
|
|
6
6
|
import {
|
|
7
7
|
openProject
|
|
8
|
-
} from "./
|
|
8
|
+
} from "./t3g0k88x.js";
|
|
9
9
|
import {
|
|
10
|
+
sessionFailure,
|
|
11
|
+
finishQuiet,
|
|
10
12
|
assertTargetPolicy,
|
|
11
13
|
selectTarget
|
|
12
|
-
} from "./
|
|
13
|
-
import"./
|
|
14
|
+
} from "./ttmg09vd.js";
|
|
15
|
+
import"./9s0ypp87.js";
|
|
14
16
|
import {
|
|
15
17
|
isExactVersion,
|
|
16
18
|
compareExtensionVersions
|
|
17
|
-
} from "./
|
|
19
|
+
} from "./r3j8s5y0.js";
|
|
18
20
|
import {
|
|
19
21
|
OkmError2
|
|
20
22
|
} from "./52szzakm.js";
|
|
@@ -29,8 +31,10 @@ async function extProject(cwd, command, flags) {
|
|
|
29
31
|
if (command === "list")
|
|
30
32
|
return formatList(await readExtensions(pool));
|
|
31
33
|
return formatCheck(opened.built.catalog.objects, await readExtensions(pool));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw sessionFailure(error) ?? error;
|
|
32
36
|
} finally {
|
|
33
|
-
await pool.close();
|
|
37
|
+
await finishQuiet(() => pool.close());
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
var LIST_SQL = `
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
readHandle,
|
|
4
4
|
readCall,
|
|
5
5
|
attachHttp
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./j60w0dvr.js";
|
|
7
7
|
import {
|
|
8
8
|
selectedColumns,
|
|
9
9
|
parseOrder,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isRecord,
|
|
16
16
|
registerFailFix,
|
|
17
17
|
fail
|
|
18
|
-
} from "./
|
|
18
|
+
} from "./2z7wv5tj.js";
|
|
19
19
|
import {
|
|
20
20
|
OkmError2,
|
|
21
21
|
throwNamed2
|
|
@@ -6,9 +6,30 @@ import {
|
|
|
6
6
|
} from "./52szzakm.js";
|
|
7
7
|
|
|
8
8
|
// src/dialects/pg/filter-parse.ts
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
var PARSED = [
|
|
10
|
+
"eq",
|
|
11
|
+
"in",
|
|
12
|
+
"inList",
|
|
13
|
+
"notIn",
|
|
14
|
+
"lt",
|
|
15
|
+
"lte",
|
|
16
|
+
"gt",
|
|
17
|
+
"gte",
|
|
18
|
+
"between",
|
|
19
|
+
"startsWith",
|
|
20
|
+
"endsWith",
|
|
21
|
+
"contains",
|
|
22
|
+
"like",
|
|
23
|
+
"ilike",
|
|
24
|
+
"not",
|
|
25
|
+
"containedBy",
|
|
26
|
+
"overlaps",
|
|
27
|
+
"hasKey",
|
|
28
|
+
"hasAnyKey"
|
|
29
|
+
];
|
|
30
|
+
var PARSED_OPS = `,${PARSED.join(",")},`;
|
|
31
|
+
var PARSED_FIX = "Use eq, in, notIn, lt, lte, gt, gte, between, startsWith, endsWith, contains, like, ilike, not, containedBy, overlaps, hasKey, or hasAnyKey.";
|
|
32
|
+
function parseQuery(allow, sort, query, relations) {
|
|
12
33
|
if (typeof query !== "object" || query === null || Array.isArray(query)) {
|
|
13
34
|
throw new OkmError2("OKM1121", "filters parse expects an object of fields.");
|
|
14
35
|
}
|
|
@@ -21,6 +42,7 @@ function parseQuery(allow, sort, query) {
|
|
|
21
42
|
});
|
|
22
43
|
}
|
|
23
44
|
}
|
|
45
|
+
const nested = relations ?? {};
|
|
24
46
|
const whereParts = [];
|
|
25
47
|
let orderBy;
|
|
26
48
|
for (const key of Object.keys(query)) {
|
|
@@ -29,13 +51,17 @@ function parseQuery(allow, sort, query) {
|
|
|
29
51
|
orderBy = { [value]: "asc" };
|
|
30
52
|
continue;
|
|
31
53
|
}
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
54
|
+
if (Object.hasOwn(allow, key)) {
|
|
55
|
+
whereParts.push(...clauses(key, allow[key] ?? [], value));
|
|
56
|
+
continue;
|
|
36
57
|
}
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
if (Object.hasOwn(nested, key)) {
|
|
59
|
+
whereParts.push(relationClause(key, nested[key] ?? [], value));
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw new OkmError2("OKM1123", `Field ${key} is not in the allow list.`, {
|
|
63
|
+
fix: { summary: "Remove the field, or add it to filters({ allow }) or relations." }
|
|
64
|
+
});
|
|
39
65
|
}
|
|
40
66
|
const where = combine(whereParts);
|
|
41
67
|
return orderBy === undefined ? { where } : { where, orderBy };
|
|
@@ -100,6 +126,21 @@ function one(field, op, value) {
|
|
|
100
126
|
return { [field]: tag("endsWith", text(value, op)) };
|
|
101
127
|
case "contains":
|
|
102
128
|
return { [field]: tag("contains", value) };
|
|
129
|
+
case "not":
|
|
130
|
+
if (value !== null && typeof value === "object") {
|
|
131
|
+
throw new OkmError2("OKM1120", `not on ${field} takes a scalar.`, {
|
|
132
|
+
fix: { summary: "Send not a scalar or null. Nested operators are not accepted." }
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return { [field]: tag("not", value) };
|
|
136
|
+
case "containedBy":
|
|
137
|
+
return { [field]: tag("containedBy", value) };
|
|
138
|
+
case "overlaps":
|
|
139
|
+
return { [field]: tag("overlaps", value) };
|
|
140
|
+
case "hasKey":
|
|
141
|
+
return { [field]: tag("hasKey", text(value, "hasKey")) };
|
|
142
|
+
case "hasAnyKey":
|
|
143
|
+
return { [field]: tag("hasAnyKey", strings(value, field)) };
|
|
103
144
|
case "like":
|
|
104
145
|
return { [field]: tag("like", text(value, op)) };
|
|
105
146
|
case "ilike":
|
|
@@ -110,6 +151,30 @@ function one(field, op, value) {
|
|
|
110
151
|
});
|
|
111
152
|
}
|
|
112
153
|
}
|
|
154
|
+
function relationClause(name, fields, value) {
|
|
155
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
156
|
+
throw new OkmError2("OKM1120", `filters() cannot apply a value on ${name}.`, {
|
|
157
|
+
fix: { summary: "Send the relation an object of allowlisted fields." }
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const parts = [];
|
|
161
|
+
for (const field of Object.keys(value)) {
|
|
162
|
+
if (!Object.hasOwn(value, field))
|
|
163
|
+
continue;
|
|
164
|
+
if (!fields.includes(field)) {
|
|
165
|
+
throw new OkmError2("OKM1123", `Field ${field} is not in the allow list.`, {
|
|
166
|
+
fix: { summary: "Remove the field, or add it to filters({ relations })." }
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
parts.push(...clauses(field, PARSED, value[field]));
|
|
170
|
+
}
|
|
171
|
+
if (parts.length === 0) {
|
|
172
|
+
throw new OkmError2("OKM1120", `filters() cannot apply a value on ${name}.`, {
|
|
173
|
+
fix: { summary: "Send the relation an object of allowlisted fields." }
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return { [name]: tag("has", combine(parts)) };
|
|
177
|
+
}
|
|
113
178
|
function combine(parts) {
|
|
114
179
|
const first = parts[0];
|
|
115
180
|
if (first === undefined)
|
|
@@ -126,6 +191,14 @@ function list(value, op) {
|
|
|
126
191
|
}
|
|
127
192
|
return value;
|
|
128
193
|
}
|
|
194
|
+
function strings(value, field) {
|
|
195
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
196
|
+
throw new OkmError2("OKM1120", `hasAnyKey on ${field} needs an array of strings.`, {
|
|
197
|
+
fix: { summary: "Send hasAnyKey an array of strings." }
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
129
202
|
function text(value, op) {
|
|
130
203
|
if (typeof value !== "string") {
|
|
131
204
|
throw new OkmError2("OKM1120", `${op} needs a string.`, {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PgSession
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./wkme6tep.js";
|
|
4
4
|
import {
|
|
5
5
|
isConnectionLost
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./gwn6v667.js";
|
|
7
7
|
import {
|
|
8
8
|
driverErrors,
|
|
9
9
|
rejectClosed,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
// src/adapters/pg/postgres-extra.ts
|
|
17
17
|
var RESET_ALL = "RESET ALL";
|
|
18
18
|
var UNLOCK = "SELECT pg_advisory_unlock_all()";
|
|
19
|
-
async function
|
|
19
|
+
async function checkout2(pool) {
|
|
20
20
|
if (pool.isClosed())
|
|
21
21
|
return rejectClosed();
|
|
22
22
|
const reserved = await reserveConnection(pool.sql, pool.acquireMs, pool.counters);
|
|
@@ -24,16 +24,17 @@ async function checkout(pool) {
|
|
|
24
24
|
const local = new Set;
|
|
25
25
|
const session = new PgSession(reserved, pool.counters, "reserved", local, pool.isClosed, pool.poolInflight, pool.notices, pool.named);
|
|
26
26
|
let released = false;
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const lost = { on: false };
|
|
28
|
+
arm(reserved, lost);
|
|
29
|
+
const guard = (run) => lost.on ? rejectClosed("CONNECTION_CLOSED") : run().catch((error) => {
|
|
29
30
|
if (isConnectionLost(error))
|
|
30
|
-
lost = true;
|
|
31
|
+
lost.on = true;
|
|
31
32
|
throw error;
|
|
32
33
|
});
|
|
33
34
|
return {
|
|
34
35
|
execute: (text, params, options) => guard(() => runCall(pool.isClosed(), options, (watch) => session.query(text, params, watch))),
|
|
35
36
|
batch: (statements, options) => guard(() => runCall(pool.isClosed(), options, async (watch) => {
|
|
36
|
-
const { runAtomicBatch } = await import("./
|
|
37
|
+
const { runAtomicBatch } = await import("./ag4c7516.js");
|
|
37
38
|
return runAtomicBatch(session, statements, watch);
|
|
38
39
|
})),
|
|
39
40
|
cancel() {
|
|
@@ -44,17 +45,21 @@ async function checkout(pool) {
|
|
|
44
45
|
return;
|
|
45
46
|
released = true;
|
|
46
47
|
try {
|
|
47
|
-
if (!lost)
|
|
48
|
+
if (!lost.on)
|
|
48
49
|
await resetConnection(reserved, session.depth());
|
|
49
50
|
} finally {
|
|
50
51
|
pool.counters.reserved = Math.max(0, pool.counters.reserved - 1);
|
|
51
|
-
if (
|
|
52
|
+
if (lost.on)
|
|
53
|
+
await pool.sql.unsafe("select 1").catch(() => {
|
|
54
|
+
return;
|
|
55
|
+
});
|
|
56
|
+
else
|
|
52
57
|
reserved.release();
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
|
-
async function
|
|
62
|
+
async function describe2(sql, text, params) {
|
|
58
63
|
const pending = sql.unsafe(text, asParams(params), { prepare: true });
|
|
59
64
|
const described = await pending.describe();
|
|
60
65
|
return {
|
|
@@ -62,7 +67,7 @@ async function describe(sql, text, params) {
|
|
|
62
67
|
parameterCount: described.types.length
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
|
-
async function*
|
|
70
|
+
async function* stream2(sql, text, params) {
|
|
66
71
|
const pending = sql.unsafe(text, asParams(params));
|
|
67
72
|
for await (const chunk of pending.cursor(64)) {
|
|
68
73
|
yield rowsFrom(chunk);
|
|
@@ -124,7 +129,21 @@ function asParams(params) {
|
|
|
124
129
|
return [];
|
|
125
130
|
return params;
|
|
126
131
|
}
|
|
127
|
-
|
|
132
|
+
function watchReserved2(sql, lost) {
|
|
133
|
+
arm(sql, lost);
|
|
134
|
+
}
|
|
135
|
+
function arm(sql, lost) {
|
|
136
|
+
const unsafe = sql.unsafe.bind(sql);
|
|
137
|
+
sql.unsafe = (text, params, options) => unsafe(text, params, {
|
|
138
|
+
...options,
|
|
139
|
+
onexecute(connection) {
|
|
140
|
+
connection.onclose = () => {
|
|
141
|
+
lost.on = true;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async function holdCheckout2(gate, checkout) {
|
|
128
147
|
try {
|
|
129
148
|
const connection = await checkout();
|
|
130
149
|
let released = false;
|
|
@@ -143,7 +162,7 @@ async function holdCheckout(gate, checkout) {
|
|
|
143
162
|
throw error;
|
|
144
163
|
}
|
|
145
164
|
}
|
|
146
|
-
async function
|
|
165
|
+
async function holdListener2(gate, start) {
|
|
147
166
|
try {
|
|
148
167
|
const stop = await start();
|
|
149
168
|
let stopped = false;
|
|
@@ -162,7 +181,7 @@ async function holdListener(gate, start) {
|
|
|
162
181
|
throw error;
|
|
163
182
|
}
|
|
164
183
|
}
|
|
165
|
-
function
|
|
184
|
+
function watchQuery2(pending, watch, onAbort, ctx) {
|
|
166
185
|
return pending.then((result) => {
|
|
167
186
|
finishWatch(pending, watch, onAbort, ctx);
|
|
168
187
|
const why = watch.reason();
|
|
@@ -194,11 +213,5 @@ async function classify(error, watch) {
|
|
|
194
213
|
}
|
|
195
214
|
return Promise.reject(errors.mapDriverError(error));
|
|
196
215
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
describe,
|
|
200
|
-
holdCheckout,
|
|
201
|
-
holdListener,
|
|
202
|
-
stream,
|
|
203
|
-
watchQuery
|
|
204
|
-
};
|
|
216
|
+
|
|
217
|
+
export { checkout2, describe2, stream2, watchReserved2, holdCheckout2, holdListener2, watchQuery2 };
|