okmodel 0.9.0 → 0.9.1
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 +9 -1
- package/dist/adapters/pg/bunsql-extra.d.ts +5 -5
- package/dist/adapters/pg/bunsql.d.ts +6 -2
- package/dist/adapters/pg/nodepostgres.d.ts +16 -1
- package/dist/adapters/pg/postgres-extra.d.ts +3 -17
- package/dist/adapters/pg/postgresjs.d.ts +2 -1
- package/dist/contracts/driver.d.ts +3 -2
- package/dist/contracts/error.d.ts +1 -1
- package/dist/dialects/pg/errors.d.ts +2 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.js +1 -1
- package/dist/dialects/pg/ext/hstore.js +1 -1
- package/dist/dialects/pg/ext/ltree.js +1 -1
- package/dist/dialects/pg/ext/pgcrypto.js +1 -1
- package/dist/dialects/pg/ext/unaccent.js +1 -1
- package/dist/dialects/pg/filters.d.ts +2 -2
- package/dist/dialects/pg/fn/index.js +1 -1
- package/dist/dialects/pg/index.js +3 -3
- package/dist/dialects/pg/introspect.d.ts +12 -0
- package/dist/dialects/pg/view/index.js +2 -2
- package/dist/runtime/param-limit.d.ts +20 -0
- package/dist/runtime/pg/bun.js +3 -3
- package/dist/runtime/pg/neon.js +3 -3
- package/dist/runtime/pg/pg.js +3 -3
- package/dist/runtime/pg/pglite.js +2 -2
- package/dist/runtime/pg/postgresjs.js +10 -10
- package/dist/runtime/tenancy/index.js +1 -1
- package/dist/runtime/traits/index.js +2 -2
- package/dist/runtime/validate/index.js +2 -2
- package/dist/runtime/write.d.ts +1 -1
- package/dist/shared/{5kyb3tqx.js → 1h5h1rf5.js} +1 -1
- package/dist/shared/{4vbf83xx.js → 2vcnpf0n.js} +1 -1
- package/dist/shared/{8n688yjg.js → 3ap5hxvj.js} +2 -1
- package/dist/shared/{wvtjg5m3.js → 3d7a80fq.js} +1 -1
- package/dist/shared/{bphrgwz9.js → 3dr444ny.js} +57 -78
- package/dist/shared/{yvabyg9k.js → 3vvpcphd.js} +7 -6
- package/dist/shared/{760ppr76.js → 4a3mmhhe.js} +2 -2
- package/dist/shared/{90sg0w5a.js → 4pkz5nvw.js} +65 -10
- package/dist/shared/{mazpbcdj.js → 4te76xc5.js} +1 -1
- package/dist/shared/{xwhdcrm4.js → 60y4ahmw.js} +1 -1
- package/dist/shared/{9dtgn1z2.js → 63qjmhnp.js} +100 -17
- package/dist/shared/{s7he5e5d.js → 67w3kn71.js} +1 -1
- package/dist/shared/{n306gqkd.js → 6vfvsdkt.js} +9 -7
- package/dist/shared/{jpybhf98.js → 6xqvesa5.js} +1 -1
- package/dist/shared/{n5whk3mt.js → 8gdbty5v.js} +8 -8
- package/dist/shared/{ccsmhv9r.js → 8ma6drzr.js} +194 -31
- package/dist/shared/{3456242y.js → 8p2bgye0.js} +110 -18
- package/dist/shared/{ebhz8vh6.js → 8qwqrxed.js} +11 -3
- package/dist/shared/{ss2kv2rs.js → 8v7vzpgt.js} +10 -7
- package/dist/shared/{8qzkd9f3.js → ak61ye1f.js} +3 -3
- package/dist/shared/{6nae0spm.js → bdekbvmt.js} +69 -7
- package/dist/shared/{tw1nvvfj.js → bxjq6xqv.js} +2 -2
- package/dist/shared/{rbxt795q.js → c7dqd3gk.js} +81 -41
- package/dist/shared/ddh72ym5.js +20 -0
- package/dist/shared/e1c55v04.js +10 -0
- package/dist/shared/{8jesqsrk.js → ekhq3ytz.js} +1 -1
- package/dist/shared/{7ba5h6pb.js → esy4dyxe.js} +5 -5
- package/dist/shared/{gcefca6p.js → f9t9g54z.js} +22 -9
- package/dist/shared/fkjne6gx.js +8 -0
- package/dist/shared/{ds229x4r.js → fne90dvz.js} +4 -1
- package/dist/shared/{cexb7z6b.js → gr9sn4za.js} +1 -1
- package/dist/shared/{mvmm3xpb.js → gzgfsspx.js} +1 -1
- package/dist/shared/{fdsz3w80.js → hgt69zjf.js} +2 -2
- package/dist/shared/{dd5pmnky.js → jvxcp1qk.js} +70 -86
- package/dist/shared/{yybhre6n.js → k73e8n9d.js} +3 -3
- package/dist/shared/{mgaq2sd3.js → kzgrcy8s.js} +8 -7
- package/dist/shared/{myk8fswx.js → mz48rs74.js} +14 -3
- package/dist/shared/{62b603gr.js → n6je5b28.js} +10 -23
- package/dist/shared/{2szgv6yj.js → ns35jqz0.js} +71 -45
- package/dist/shared/{xtsydxjg.js → nstwgzn8.js} +1 -1
- package/dist/shared/{stfa9xcw.js → py2zrrm6.js} +7 -6
- package/dist/shared/{9dr2qnx7.js → qqm3ze6q.js} +1 -1
- package/dist/shared/{cf8zdz5p.js → rcjm0yn7.js} +27 -34
- package/dist/shared/{ckz05z15.js → rged92v6.js} +7 -4
- package/dist/shared/{qvwwp1mp.js → rw4tpcd0.js} +30 -21
- package/dist/shared/{bsek72fg.js → s5qe47a6.js} +3 -0
- package/dist/shared/{1d9q9cv2.js → smxzjz60.js} +2 -2
- package/dist/shared/{c3mvnq7a.js → th5rnaxw.js} +1 -1
- package/dist/shared/{1mxm04fy.js → tyqapcgk.js} +71 -8
- package/dist/shared/{zdqf8k5d.js → vsna85qf.js} +1 -1
- package/dist/shared/{63qtkrca.js → vy47ryqa.js} +55 -5
- package/dist/shared/{xv8qj97g.js → wbdh9qbg.js} +3 -1
- package/dist/shared/{2zdxkt7b.js → wp7y8q3y.js} +41 -9
- package/dist/shared/{pg4ezgyf.js → xbd9xs6p.js} +2 -2
- package/dist/shared/{npdftanb.js → xbvz446k.js} +16 -13
- package/dist/shared/{aksb89mn.js → y6tfjk9q.js} +2 -2
- package/dist/shared/{3bb7wsqt.js → ycnft340.js} +1 -1
- package/dist/shared/{z7s6fpxv.js → ymenf259.js} +1 -1
- package/dist/shared/{71n0jmhc.js → ysdw2fg3.js} +10 -2
- package/dist/shared/{xqacq37x.js → zecrwdk9.js} +1 -1
- package/dist/shared/{3t6kw83m.js → zm2rzqba.js} +2 -1
- package/dist/tooling/cli.js +122 -44
- package/dist/tooling/driver-run.js +107 -24
- package/dist/tooling/github/comment.d.ts +8 -2
- package/dist/tooling/migrate/apply.d.ts +17 -2
- package/dist/tooling/migrate/drift.d.ts +12 -0
- package/dist/tooling/migrate/driver-url.d.ts +17 -0
- package/dist/tooling/migrate/index.js +9 -7
- package/dist/tooling/migrate/policy.d.ts +17 -5
- package/dist/tooling/migrate/pooler-probe.d.ts +23 -0
- package/dist/tooling/migrate/pull.d.ts +3 -0
- package/dist/tooling/migrate/runner.d.ts +24 -1
- package/dist/tooling/shared/{0j0jtse1.js → 09a6vsys.js} +1 -1
- package/dist/tooling/shared/{68tf18v4.js → 0v9ptnxp.js} +8 -8
- package/dist/tooling/shared/{qartgazh.js → 0wtzps9p.js} +6 -6
- package/dist/tooling/shared/{1800eymw.js → 0yhf1db4.js} +6 -6
- package/dist/tooling/shared/{s6qha57m.js → 19msgrsc.js} +2 -2
- package/dist/tooling/shared/{3yn79q5m.js → 1fwfm5m3.js} +1 -1
- package/dist/tooling/shared/{hfq3n3bd.js → 2jdn09e2.js} +55 -5
- package/dist/tooling/shared/{v6j1ep6w.js → 2qrte2ct.js} +5 -5
- package/dist/tooling/shared/{yb4kd19s.js → 2v4nwnkb.js} +1 -1
- package/dist/tooling/shared/{ezqn88nj.js → 33z39trp.js} +106 -23
- package/dist/tooling/shared/{0r05zhyq.js → 353vnw9z.js} +5 -5
- package/dist/tooling/shared/{m4hhb8aa.js → 390kry9g.js} +2 -2
- package/dist/tooling/shared/{rcywj2w8.js → 3f6etb9z.js} +18 -31
- package/dist/tooling/shared/{9wsnsvbf.js → 3t2cqmsx.js} +1 -1
- package/dist/tooling/shared/{5zrzffnk.js → 4dzvjtpy.js} +1 -1
- package/dist/tooling/shared/{am04v8na.js → 4ec0nxvw.js} +10 -10
- package/dist/tooling/shared/{04svnxxj.js → 4tg2bn41.js} +59 -78
- package/dist/tooling/shared/{829fjxyw.js → 5rah55z0.js} +2 -2
- package/dist/tooling/shared/{c0xevn1h.js → 804w1t69.js} +4 -4
- package/dist/tooling/shared/{dhatassp.js → 8g0m0rvd.js} +6 -6
- package/dist/tooling/shared/{zx3v9phv.js → 8msbtw5s.js} +1 -1
- package/dist/tooling/shared/{7pxncnzs.js → 8t22h3h7.js} +2 -2
- package/dist/tooling/shared/{wbwq1jsa.js → 91c59b7b.js} +2 -2
- package/dist/tooling/shared/{a2xe04bm.js → adk9k6va.js} +1 -1
- package/dist/tooling/shared/{w17sj05d.js → ajjd5cwz.js} +2 -2
- package/dist/tooling/shared/{35zemrmf.js → angjck01.js} +1 -1
- package/dist/tooling/shared/{jsjjz875.js → asnnc3v5.js} +1 -1
- package/dist/tooling/shared/{5bmksndh.js → bj1kyqc8.js} +2 -2
- package/dist/tooling/shared/{kbqnrs1x.js → bt3tjemb.js} +11 -3
- package/dist/tooling/shared/{vwr2y833.js → chk2bh4f.js} +2 -2
- package/dist/tooling/shared/{ybdew6j7.js → ckq4z5ax.js} +5 -2
- package/dist/tooling/shared/{3rmaz3pq.js → d3rhb24q.js} +1 -1
- package/dist/tooling/shared/{mw5npye0.js → d8q00vxg.js} +4 -4
- package/dist/tooling/shared/{j664qjrt.js → dx188rxs.js} +2 -2
- package/dist/tooling/shared/{8yr7ges1.js → efq6p9df.js} +35 -42
- package/dist/tooling/shared/{yhp829bx.js → en6rwzq0.js} +3 -3
- package/dist/tooling/shared/{f77nnfqy.js → f2r5g0fs.js} +2 -2
- package/dist/tooling/shared/{zs9aymcp.js → f4gep0nk.js} +1 -1
- package/dist/tooling/shared/{kz715295.js → f8a010fm.js} +13 -11
- package/dist/tooling/shared/{w5d89rb4.js → fdsek6pa.js} +1 -1
- package/dist/tooling/shared/fvmrxsd1.js +8 -0
- package/dist/tooling/shared/{jpgmjsx3.js → g3xybeqf.js} +4 -3
- package/dist/tooling/shared/{wezxf3h8.js → gefmpwsa.js} +1 -1
- package/dist/tooling/shared/{jr2nmr81.js → gjj71hfh.js} +23 -20
- package/dist/tooling/shared/{9sfbtwsk.js → jgzt69pa.js} +5 -5
- package/dist/tooling/shared/{a4pzghha.js → jm30k2ca.js} +10 -8
- package/dist/tooling/shared/{shjs0379.js → kayqzpbk.js} +6 -3
- package/dist/tooling/shared/{tcwpjvxe.js → kvw1672d.js} +1 -1
- package/dist/tooling/shared/{stebqyyd.js → mr1kcgpw.js} +3 -3
- package/dist/tooling/shared/{tpssp7ac.js → mwbdf409.js} +1 -1
- package/dist/tooling/shared/{fh07z1dt.js → ns9207v3.js} +1 -1
- package/dist/tooling/shared/{5p8km5jb.js → p6tjv97k.js} +3 -3
- package/dist/tooling/shared/{ytk1tjs0.js → p73evwf0.js} +1 -1
- package/dist/tooling/shared/{8m5znpdt.js → phc1nc4g.js} +1 -1
- package/dist/tooling/shared/{asgr07mp.js → ppybjw50.js} +79 -16
- package/dist/tooling/shared/{t4xveemq.js → qdrn8ghn.js} +5 -4
- package/dist/tooling/shared/rd8h01ta.js +20 -0
- package/dist/tooling/shared/{7aews1zg.js → rwg8y90m.js} +3 -3
- package/dist/tooling/shared/{5x3pf400.js → ry2f3w8p.js} +3 -3
- package/dist/tooling/shared/{m3xt8b1h.js → ryc5sa58.js} +8 -8
- package/dist/tooling/shared/{57btdkgm.js → ss87qxwv.js} +2 -2
- package/dist/tooling/shared/{6vk28rjp.js → vg68k11z.js} +3 -3
- package/dist/tooling/shared/{62fxpc1p.js → vms9dta5.js} +73 -89
- package/dist/tooling/shared/{gqwevek4.js → xchpnbdv.js} +1 -1
- package/dist/tooling/shared/{t6zjeake.js → xn6p01fh.js} +5 -5
- package/dist/tooling/shared/{7b3xp9gc.js → xwr6q618.js} +3 -3
- package/dist/tooling/shared/{yfedr1zb.js → xx3gmq94.js} +1 -1
- package/dist/tooling/shared/{9qr9rkbh.js → y2bd7yfx.js} +21 -13
- package/dist/tooling/shared/{nxq95eb6.js → y4gq9rbe.js} +11 -11
- package/dist/tooling/shared/{76pv6qff.js → y4vwft92.js} +2 -2
- package/dist/tooling/shared/{sjwkt1pg.js → yz68xcmc.js} +1 -1
- package/dist/tooling/testing/factories.d.ts +1 -3
- package/dist/tooling/testing/index.js +1 -1
- package/package.json +2 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertParamCount2
|
|
3
|
+
} from "./ddh72ym5.js";
|
|
1
4
|
import {
|
|
2
5
|
stack2
|
|
3
6
|
} from "./mss6ctgv.js";
|
|
@@ -29,6 +32,7 @@ import {
|
|
|
29
32
|
decodeRow,
|
|
30
33
|
indexes,
|
|
31
34
|
quote,
|
|
35
|
+
list,
|
|
32
36
|
isRecord,
|
|
33
37
|
registerFailFix,
|
|
34
38
|
fail2
|
|
@@ -163,7 +167,7 @@ async function prepareWrite(host, op, table, input, options, mods, scope) {
|
|
|
163
167
|
return {
|
|
164
168
|
statements: planned.statements,
|
|
165
169
|
options: callOptions(options),
|
|
166
|
-
...planned.parentGuard === true ? { checked: "parent" } : planned.expect !== undefined ? { checked: "expect" } : {},
|
|
170
|
+
...planned.parentGuard === true ? { checked: "parent" } : planned.treeGuard === true ? { checked: "tree" } : planned.expect !== undefined ? { checked: "expect" } : {},
|
|
167
171
|
...planned.recover === undefined ? {} : {
|
|
168
172
|
follow: (results) => planned.recover?.(decodePlanned(withoutQuiet(results, planned.quiet), planned.outputs)) ?? []
|
|
169
173
|
},
|
|
@@ -198,7 +202,7 @@ async function planWrite(schema, generators, op, tableName, input, options, mods
|
|
|
198
202
|
}
|
|
199
203
|
if (op === "update") {
|
|
200
204
|
if (traitNamed(table, "versioned")) {
|
|
201
|
-
const { planVersioned } = await import("./
|
|
205
|
+
const { planVersioned } = await import("./zm2rzqba.js");
|
|
202
206
|
return withRowFilters(scope, mods.archive, () => {
|
|
203
207
|
noteArchive(table, mods.archive);
|
|
204
208
|
const planned = planVersioned(schema, table, input, record, mods);
|
|
@@ -244,7 +248,7 @@ async function planInsert(table, input, options, mods, generators, scope, tenanc
|
|
|
244
248
|
keyColumns: undefined
|
|
245
249
|
};
|
|
246
250
|
}
|
|
247
|
-
const conflictMod = options.onConflict === undefined || options.onConflict === "error" ? undefined : await import("./
|
|
251
|
+
const conflictMod = options.onConflict === undefined || options.onConflict === "error" ? undefined : await import("./60y4ahmw.js");
|
|
248
252
|
const conflict = conflictMod?.readConflict(table, options.onConflict, allow, tenantKeyList(tenancy));
|
|
249
253
|
if (conflict?.kind === "update" && traitNamed(table, "versioned")) {
|
|
250
254
|
fail2("OKM1120", `onConflict update on ${table.model.name} does not check the version you read.`, "Read the row and update. ignore and return do not change the existing row.");
|
|
@@ -308,7 +312,7 @@ function planUpdate(schema, table, input, options, mods, scope) {
|
|
|
308
312
|
rejectDuplicateTargets2(table, rows);
|
|
309
313
|
rejectMixedSets2(rows);
|
|
310
314
|
for (const row of rows)
|
|
311
|
-
refuseTreeCycle(table, row.where, row.set, schema.tenancy
|
|
315
|
+
refuseTreeCycle(table, row.where, row.set, tenantKeys(schema.tenancy));
|
|
312
316
|
const moves = rows.some((row) => pathField(schema.tenancy, table.model.name, row.set) !== undefined);
|
|
313
317
|
if (moves) {
|
|
314
318
|
return {
|
|
@@ -338,7 +342,8 @@ function planUpdate(schema, table, input, options, mods, scope) {
|
|
|
338
342
|
requireFilter2(table, input.where, mods, "update");
|
|
339
343
|
if (Object.keys(set).length === 0)
|
|
340
344
|
fail2("OKM1120", "update set is empty.");
|
|
341
|
-
|
|
345
|
+
const keys = tenantKeys(schema.tenancy);
|
|
346
|
+
const cycle = refuseTreeCycle(table, input.where, set, keys);
|
|
342
347
|
const where = stack2(input.where, mods.presets);
|
|
343
348
|
const moved = pathAssignment(schema.tenancy, table.model.name, set, scope);
|
|
344
349
|
if (moved !== undefined && claim !== undefined) {
|
|
@@ -365,6 +370,17 @@ function planUpdate(schema, table, input, options, mods, scope) {
|
|
|
365
370
|
keyColumns: undefined
|
|
366
371
|
};
|
|
367
372
|
}
|
|
373
|
+
if (cycle !== undefined) {
|
|
374
|
+
return {
|
|
375
|
+
statements: [treeSetUpdate(schema, table, where, set, cycle, returning)],
|
|
376
|
+
outputs: parentOutputs(returning),
|
|
377
|
+
shape: returning === undefined ? "count" : "rows",
|
|
378
|
+
expect,
|
|
379
|
+
keys: undefined,
|
|
380
|
+
keyColumns: undefined,
|
|
381
|
+
treeGuard: true
|
|
382
|
+
};
|
|
383
|
+
}
|
|
368
384
|
const sql = new Sql2;
|
|
369
385
|
sql.text("update ");
|
|
370
386
|
sql.text(quote(table.model.sql));
|
|
@@ -411,6 +427,8 @@ function finish(results, planned, table) {
|
|
|
411
427
|
return finishVersioned(results, planned, table);
|
|
412
428
|
if (planned.parentGuard === true)
|
|
413
429
|
return finishParent(results, planned, table);
|
|
430
|
+
if (planned.treeGuard === true)
|
|
431
|
+
return finishTree(results, planned, table);
|
|
414
432
|
if (planned.shape === "count") {
|
|
415
433
|
let count = 0;
|
|
416
434
|
for (const result of results)
|
|
@@ -439,6 +457,18 @@ function finishParent(results, planned, table) {
|
|
|
439
457
|
fix: { summary: "Point the foreign key at a parent in this tenant." }
|
|
440
458
|
});
|
|
441
459
|
}
|
|
460
|
+
return finishGuarded(results, planned, table, updated);
|
|
461
|
+
}
|
|
462
|
+
function finishTree(results, planned, table) {
|
|
463
|
+
const row = results[0]?.rows[0];
|
|
464
|
+
const matched = countCell(row?.[0]);
|
|
465
|
+
const updated = countCell(row?.[1]);
|
|
466
|
+
if (updated < matched) {
|
|
467
|
+
fail2("OKM1120", `update on ${table} cannot point a tree row at itself or its descendant.`, "Set the parent to another row that is not under this one. A filter that is not the primary key is not checked.");
|
|
468
|
+
}
|
|
469
|
+
return finishGuarded(results, planned, table, updated);
|
|
470
|
+
}
|
|
471
|
+
function finishGuarded(results, planned, table, updated) {
|
|
442
472
|
if (planned.shape === "count") {
|
|
443
473
|
checkExpect(updated, planned.expect, table, "write");
|
|
444
474
|
return { count: updated };
|
|
@@ -1074,6 +1104,7 @@ class Sql2 {
|
|
|
1074
1104
|
};
|
|
1075
1105
|
}
|
|
1076
1106
|
statement() {
|
|
1107
|
+
assertParamCount2(this.params.length);
|
|
1077
1108
|
return this.params.length === 0 ? { text: this.parts.join("") } : { text: this.parts.join(""), params: this.params };
|
|
1078
1109
|
}
|
|
1079
1110
|
}
|
|
@@ -1084,7 +1115,7 @@ function insertRow(table, value, allow, tenancy) {
|
|
|
1084
1115
|
for (const key of Object.keys(value)) {
|
|
1085
1116
|
const column = table.columns.get(key);
|
|
1086
1117
|
if (column === undefined)
|
|
1087
|
-
|
|
1118
|
+
refuseUnknownField(table, key);
|
|
1088
1119
|
tenancy?.guard(table.model.name, key, "insert");
|
|
1089
1120
|
if (!writable(table, column, allow, "insert"))
|
|
1090
1121
|
refuse(table, column);
|
|
@@ -1094,6 +1125,9 @@ function insertRow(table, value, allow, tenancy) {
|
|
|
1094
1125
|
refuseHalfMorph(table, row);
|
|
1095
1126
|
return row;
|
|
1096
1127
|
}
|
|
1128
|
+
function refuseUnknownField(table, key) {
|
|
1129
|
+
throwNamed2("OKM1120", key, table.names, `Field ${key} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
|
|
1130
|
+
}
|
|
1097
1131
|
function cellsFor(columns, row) {
|
|
1098
1132
|
return columns.map((column) => {
|
|
1099
1133
|
if (!Object.hasOwn(row, column.field))
|
|
@@ -1200,10 +1234,10 @@ function writeSet2(table, value, allow, tenancy) {
|
|
|
1200
1234
|
}
|
|
1201
1235
|
const set = {};
|
|
1202
1236
|
for (const key of Object.keys(value)) {
|
|
1203
|
-
if (value[key] === undefined)
|
|
1204
|
-
continue;
|
|
1205
1237
|
const column = table.columns.get(key);
|
|
1206
1238
|
if (column === undefined)
|
|
1239
|
+
refuseUnknownField(table, key);
|
|
1240
|
+
if (value[key] === undefined)
|
|
1207
1241
|
continue;
|
|
1208
1242
|
tenancy?.guard(table.model.name, key, "update");
|
|
1209
1243
|
if (column.guardUpdate || !writable(table, column, allow, "update"))
|
|
@@ -1213,10 +1247,11 @@ function writeSet2(table, value, allow, tenancy) {
|
|
|
1213
1247
|
refuseHalfMorph(table, set);
|
|
1214
1248
|
return set;
|
|
1215
1249
|
}
|
|
1216
|
-
function refuseTreeCycle(table, where, set,
|
|
1217
|
-
const
|
|
1218
|
-
if (
|
|
1250
|
+
function refuseTreeCycle(table, where, set, scopeKeys) {
|
|
1251
|
+
const keyed = keyedId(table, where, scopeKeys);
|
|
1252
|
+
if (keyed === undefined)
|
|
1219
1253
|
return;
|
|
1254
|
+
let found;
|
|
1220
1255
|
for (const relation of table.model.relations) {
|
|
1221
1256
|
if (relation.kind !== "many" || relation.through !== undefined || relation.morph !== undefined) {
|
|
1222
1257
|
continue;
|
|
@@ -1231,17 +1266,20 @@ function refuseTreeCycle(table, where, set, scopeKey) {
|
|
|
1231
1266
|
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "bigint") {
|
|
1232
1267
|
continue;
|
|
1233
1268
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1269
|
+
const parent = typeof value === "string" ? value : value.toString();
|
|
1270
|
+
if (parent === keyed.own) {
|
|
1271
|
+
fail2("OKM1120", `update on ${table.model.name}.${column.field} cannot point a tree row at itself.`, "Set the parent to another row. A filter that is not the primary key is not checked.");
|
|
1272
|
+
}
|
|
1273
|
+
found = { own: keyed.own, parent, column, identity: keyed.identity };
|
|
1237
1274
|
}
|
|
1238
1275
|
}
|
|
1276
|
+
return found;
|
|
1239
1277
|
}
|
|
1240
|
-
function keyedId(table, where,
|
|
1278
|
+
function keyedId(table, where, scopeKeys) {
|
|
1241
1279
|
if (!isRecord(where))
|
|
1242
1280
|
return;
|
|
1243
1281
|
const primary = table.model.primary;
|
|
1244
|
-
const required = primary.filter((field) => field
|
|
1282
|
+
const required = primary.filter((field) => !scopeKeys.includes(field));
|
|
1245
1283
|
const field = required.length === 1 ? required[0] : undefined;
|
|
1246
1284
|
if (field === undefined || !Object.hasOwn(where, field))
|
|
1247
1285
|
return;
|
|
@@ -1253,7 +1291,51 @@ function keyedId(table, where, scopeKey) {
|
|
|
1253
1291
|
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "bigint") {
|
|
1254
1292
|
return;
|
|
1255
1293
|
}
|
|
1256
|
-
|
|
1294
|
+
const identity = table.columns.get(field);
|
|
1295
|
+
if (identity === undefined)
|
|
1296
|
+
return;
|
|
1297
|
+
return { own: String(value), identity };
|
|
1298
|
+
}
|
|
1299
|
+
function tenantKeys(tenancy) {
|
|
1300
|
+
if (tenancy === undefined)
|
|
1301
|
+
return [];
|
|
1302
|
+
if (tenancy.keys !== undefined && tenancy.keys.length > 0)
|
|
1303
|
+
return tenancy.keys;
|
|
1304
|
+
return [tenancy.key];
|
|
1305
|
+
}
|
|
1306
|
+
function treeSetUpdate(schema, table, where, set, cycle, returning) {
|
|
1307
|
+
const sql = new Sql2;
|
|
1308
|
+
sql.text("with matched as (select ");
|
|
1309
|
+
sql.text(rowId("t"));
|
|
1310
|
+
sql.text(" from ");
|
|
1311
|
+
sql.text(quote(table.model.sql));
|
|
1312
|
+
sql.text(" as t");
|
|
1313
|
+
emitFilter(schema, table, where, sql, "t");
|
|
1314
|
+
sql.text("), updated as (update ");
|
|
1315
|
+
sql.text(quote(table.model.sql));
|
|
1316
|
+
sql.text(" as t set ");
|
|
1317
|
+
emitSet2(sql, table, set, "t");
|
|
1318
|
+
sql.text(" where (");
|
|
1319
|
+
sql.text(rowId("t"));
|
|
1320
|
+
sql.text(") in (select tableoid, ctid from matched) and not exists (with recursive d as (select ");
|
|
1321
|
+
sql.text(quote(cycle.identity.sql));
|
|
1322
|
+
sql.text(" as k from ");
|
|
1323
|
+
sql.text(quote(table.model.sql));
|
|
1324
|
+
sql.text(" where ");
|
|
1325
|
+
sql.text(quote(cycle.column.sql));
|
|
1326
|
+
sql.text(" = ");
|
|
1327
|
+
sql.param(cycle.own, cycle.identity.dataType);
|
|
1328
|
+
sql.text(" union all select c.");
|
|
1329
|
+
sql.text(quote(cycle.identity.sql));
|
|
1330
|
+
sql.text(" from ");
|
|
1331
|
+
sql.text(quote(table.model.sql));
|
|
1332
|
+
sql.text(" c join d on c.");
|
|
1333
|
+
sql.text(quote(cycle.column.sql));
|
|
1334
|
+
sql.text(" = d.k) select 1 from d where d.k = ");
|
|
1335
|
+
sql.param(cycle.parent, cycle.identity.dataType);
|
|
1336
|
+
sql.text(")");
|
|
1337
|
+
endParent(sql, returning);
|
|
1338
|
+
return sql.statement();
|
|
1257
1339
|
}
|
|
1258
1340
|
function columnBySql(table, sql) {
|
|
1259
1341
|
for (const column of table.model.columns) {
|
|
@@ -1362,6 +1444,7 @@ function chunkRows(rows) {
|
|
|
1362
1444
|
function withParams(text, params) {
|
|
1363
1445
|
if (params === undefined || params.length === 0)
|
|
1364
1446
|
return { text };
|
|
1447
|
+
assertParamCount2(params.length);
|
|
1365
1448
|
return { text, params };
|
|
1366
1449
|
}
|
|
1367
1450
|
function keyWire(columns, row) {
|
|
@@ -4,16 +4,18 @@ import {
|
|
|
4
4
|
applyProject2,
|
|
5
5
|
pushProject2,
|
|
6
6
|
backfillTiming2
|
|
7
|
-
} from "./
|
|
8
|
-
import"./
|
|
9
|
-
import"./
|
|
10
|
-
import"./
|
|
11
|
-
import"./
|
|
12
|
-
import"./
|
|
7
|
+
} from "./8ma6drzr.js";
|
|
8
|
+
import"./8p2bgye0.js";
|
|
9
|
+
import"./6xqvesa5.js";
|
|
10
|
+
import"./4pkz5nvw.js";
|
|
11
|
+
import"./e1c55v04.js";
|
|
12
|
+
import"./mz48rs74.js";
|
|
13
|
+
import"./wp7y8q3y.js";
|
|
14
|
+
import"./bdekbvmt.js";
|
|
13
15
|
import"./n442h54c.js";
|
|
14
16
|
import"./fk9vef30.js";
|
|
15
17
|
import"./12z7aznj.js";
|
|
16
|
-
import"./
|
|
18
|
+
import"./jvxcp1qk.js";
|
|
17
19
|
export {
|
|
18
20
|
applyProject2 as applyProject,
|
|
19
21
|
applyTarget2 as applyTarget,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import"./12z7aznj.js";
|
|
2
2
|
import"./fk9vef30.js";
|
|
3
3
|
import"./n442h54c.js";
|
|
4
|
-
import"./
|
|
4
|
+
import"./jvxcp1qk.js";
|
|
5
5
|
import {
|
|
6
6
|
emitPull,
|
|
7
7
|
formatPullReport,
|
|
8
8
|
pullLayout2,
|
|
9
9
|
commitPullFiles2
|
|
10
|
-
} from "./
|
|
11
|
-
import"./
|
|
10
|
+
} from "./c7dqd3gk.js";
|
|
11
|
+
import"./mz48rs74.js";
|
|
12
12
|
import {
|
|
13
13
|
loadConfig
|
|
14
|
-
} from "./
|
|
15
|
-
import"./
|
|
14
|
+
} from "./wp7y8q3y.js";
|
|
15
|
+
import"./bdekbvmt.js";
|
|
16
16
|
import {
|
|
17
17
|
catalog,
|
|
18
18
|
enumType
|
|
@@ -452,14 +452,14 @@ function columnOf(parent, property, value, primaryColumns, enums, objects, names
|
|
|
452
452
|
}));
|
|
453
453
|
}
|
|
454
454
|
const defaultExpression = serial || identity !== undefined || generated !== undefined ? undefined : readDefault(value, extras, `${tableName}.${sqlName}`);
|
|
455
|
-
const nullable = flag(value, "notNull") ? false : true;
|
|
456
455
|
const dataType = note !== undefined ? note.name : mapped.dataType;
|
|
457
|
-
const
|
|
456
|
+
const inPrimary = primaryColumns.includes(sqlName);
|
|
457
|
+
const nullable = inPrimary || flag(value, "notNull") ? false : true;
|
|
458
458
|
return column2({
|
|
459
459
|
parent,
|
|
460
460
|
name: sqlName,
|
|
461
461
|
dataType,
|
|
462
|
-
nullable
|
|
462
|
+
nullable,
|
|
463
463
|
provenance: provenanceOf(`field:${property}`),
|
|
464
464
|
...defaultExpression !== undefined ? { defaultExpression } : {},
|
|
465
465
|
...identity !== undefined ? { identity } : {},
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
open2
|
|
3
|
-
} from "./
|
|
3
|
+
} from "./jvxcp1qk.js";
|
|
4
4
|
import {
|
|
5
5
|
startupHash2
|
|
6
6
|
} from "./12z7aznj.js";
|
|
7
7
|
import {
|
|
8
8
|
quoteIdent2
|
|
9
9
|
} from "./fk9vef30.js";
|
|
10
|
+
import {
|
|
11
|
+
sealViews,
|
|
12
|
+
sealDomainChecks2,
|
|
13
|
+
catalogQuery2,
|
|
14
|
+
managedRoleOptions2
|
|
15
|
+
} from "./4pkz5nvw.js";
|
|
10
16
|
import {
|
|
11
17
|
runTarget,
|
|
12
18
|
assumeRole,
|
|
@@ -17,14 +23,21 @@ import {
|
|
|
17
23
|
provisionMark,
|
|
18
24
|
expandProvisioned,
|
|
19
25
|
installSnapshot
|
|
20
|
-
} from "./
|
|
26
|
+
} from "./8p2bgye0.js";
|
|
21
27
|
import {
|
|
22
28
|
assertCreateRole,
|
|
23
29
|
currentUser,
|
|
24
30
|
roleExists
|
|
25
|
-
} from "./
|
|
31
|
+
} from "./6xqvesa5.js";
|
|
32
|
+
import {
|
|
33
|
+
probeStableBackend
|
|
34
|
+
} from "./e1c55v04.js";
|
|
35
|
+
import {
|
|
36
|
+
introspectSchema
|
|
37
|
+
} from "./mz48rs74.js";
|
|
26
38
|
import {
|
|
27
39
|
projectPath,
|
|
40
|
+
assertSnapshots,
|
|
28
41
|
loadMigrations,
|
|
29
42
|
loadHeadSnapshot,
|
|
30
43
|
lintMigrationDirectory,
|
|
@@ -33,8 +46,9 @@ import {
|
|
|
33
46
|
projectHead,
|
|
34
47
|
loadBuiltSchema,
|
|
35
48
|
loadConfig
|
|
36
|
-
} from "./
|
|
49
|
+
} from "./wp7y8q3y.js";
|
|
37
50
|
import {
|
|
51
|
+
driverUrl,
|
|
38
52
|
changesRole,
|
|
39
53
|
batchSizeField,
|
|
40
54
|
assertExtensionsAvailable,
|
|
@@ -42,9 +56,8 @@ import {
|
|
|
42
56
|
finishQuiet,
|
|
43
57
|
assertTargetPolicy,
|
|
44
58
|
assertDirectConnection,
|
|
45
|
-
assertStableBackend,
|
|
46
59
|
selectTarget
|
|
47
|
-
} from "./
|
|
60
|
+
} from "./bdekbvmt.js";
|
|
48
61
|
import {
|
|
49
62
|
UUIDV7_POSTGRES,
|
|
50
63
|
uuidv7NeedsPostgres
|
|
@@ -99,6 +112,7 @@ function unquote(name) {
|
|
|
99
112
|
}
|
|
100
113
|
|
|
101
114
|
// src/tooling/migrate/apply.ts
|
|
115
|
+
import postgres from "postgres";
|
|
102
116
|
var DEFAULT_LOCK_MS = 5000;
|
|
103
117
|
var DEFAULT_STATEMENT_MS = 30000;
|
|
104
118
|
var DEFAULT_RETRIES = 3;
|
|
@@ -173,8 +187,9 @@ function applyUnits(migration, done) {
|
|
|
173
187
|
}
|
|
174
188
|
async function applyTarget2(request) {
|
|
175
189
|
assertDirectConnection(request.url, request.allowPooler === true);
|
|
190
|
+
const url = driverUrl(request.url);
|
|
176
191
|
const pool = open2({
|
|
177
|
-
url
|
|
192
|
+
url,
|
|
178
193
|
max: 1,
|
|
179
194
|
...request.searchPath !== undefined ? { searchPath: request.searchPath } : {}
|
|
180
195
|
});
|
|
@@ -188,7 +203,7 @@ async function applyTarget2(request) {
|
|
|
188
203
|
const connection = reserved;
|
|
189
204
|
let locked = false;
|
|
190
205
|
try {
|
|
191
|
-
await
|
|
206
|
+
await probeStableBackend(request.url, () => backendPid(connection), request.allowPooler === true);
|
|
192
207
|
await assertStandardStrings(connection);
|
|
193
208
|
await setTimeouts(connection, request);
|
|
194
209
|
await lockTarget(connection, request.target);
|
|
@@ -234,8 +249,11 @@ async function applyTarget2(request) {
|
|
|
234
249
|
if (request.snapshot !== undefined) {
|
|
235
250
|
await insertReference(connection, request);
|
|
236
251
|
}
|
|
252
|
+
const desiredHash = request.headHash;
|
|
253
|
+
const headStamp = desiredHash === undefined || request.restampHead !== true ? [] : await restampHeadHash(connection, request, nextSequenceId("restamp", history.ids), desiredHash);
|
|
237
254
|
await grantAppMeta(connection, request.appRole, session);
|
|
238
|
-
|
|
255
|
+
const stamped = [...restamped, ...headStamp];
|
|
256
|
+
return stamped.length === 0 ? report : { ...report, restamped: stamped };
|
|
239
257
|
} finally {
|
|
240
258
|
if (locked) {
|
|
241
259
|
await finishQuiet(() => connection.execute("select pg_advisory_unlock(hashtext($1))", [lockKey(request.target)]));
|
|
@@ -259,7 +277,10 @@ nothing to apply
|
|
|
259
277
|
return;
|
|
260
278
|
throw error;
|
|
261
279
|
});
|
|
280
|
+
if (built !== undefined)
|
|
281
|
+
assertSnapshots(cwd, config, built.catalog);
|
|
262
282
|
const progress = [];
|
|
283
|
+
const externalConfigured = (config.external ?? []).length > 0;
|
|
263
284
|
const report = await applyTarget2({
|
|
264
285
|
url: target.url,
|
|
265
286
|
target: target.name,
|
|
@@ -276,6 +297,8 @@ nothing to apply
|
|
|
276
297
|
catalogHash: head.catalogHash,
|
|
277
298
|
reference: built === undefined ? [] : readReference(built.tables, built.casing, head.catalog)
|
|
278
299
|
},
|
|
300
|
+
...built !== undefined ? { headHash: startupHash2(built.catalog) } : {},
|
|
301
|
+
...externalConfigured ? { restampHead: true } : {},
|
|
279
302
|
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {},
|
|
280
303
|
...catalogSchema(config.namespace),
|
|
281
304
|
lintDirectory: directory,
|
|
@@ -299,37 +322,176 @@ async function pushProject2(cwd, flags) {
|
|
|
299
322
|
const target = selectTarget(config, flags.target);
|
|
300
323
|
assertTargetPolicy(target, "push", flags.allowProtected);
|
|
301
324
|
const head = await projectHead(cwd);
|
|
302
|
-
|
|
303
|
-
|
|
325
|
+
assertSnapshots(cwd, config, head.catalog);
|
|
326
|
+
const catalogHash = startupHash2(head.catalog);
|
|
327
|
+
const report = await pushTarget({
|
|
328
|
+
url: target.url,
|
|
329
|
+
target: target.name,
|
|
330
|
+
protected: target.protected,
|
|
331
|
+
allowProtected: flags.allowProtected,
|
|
332
|
+
allowPooler: flags.allowPooler || config.allowPooler === true,
|
|
333
|
+
...backfillTiming2(config.backfill),
|
|
304
334
|
after: head.catalog,
|
|
305
335
|
renames: head.renames,
|
|
306
|
-
|
|
336
|
+
catalogHash,
|
|
337
|
+
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app, roles: config.roles } : {},
|
|
307
338
|
...catalogSchema(config.namespace),
|
|
308
339
|
...batchSizeField(config.backfill?.batchSize)
|
|
309
340
|
});
|
|
310
|
-
if (
|
|
341
|
+
if (report.applied.length === 0 && (report.restamped ?? []).length === 0) {
|
|
311
342
|
return `target ${target.name}
|
|
312
343
|
no changes
|
|
313
344
|
`;
|
|
314
|
-
|
|
315
|
-
url: target.url,
|
|
316
|
-
target: target.name,
|
|
317
|
-
protected: target.protected,
|
|
318
|
-
allowProtected: flags.allowProtected,
|
|
319
|
-
allowPooler: flags.allowPooler || config.allowPooler === true,
|
|
320
|
-
...backfillTiming2(config.backfill),
|
|
321
|
-
migrations: [
|
|
322
|
-
{
|
|
323
|
-
id: "push",
|
|
324
|
-
catalogHash: startupHash2(head.catalog),
|
|
325
|
-
steps: plan.steps
|
|
326
|
-
}
|
|
327
|
-
],
|
|
328
|
-
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {},
|
|
329
|
-
...catalogSchema(config.namespace)
|
|
330
|
-
});
|
|
345
|
+
}
|
|
331
346
|
return formatReport(report);
|
|
332
347
|
}
|
|
348
|
+
async function pushTarget(request) {
|
|
349
|
+
assertDirectConnection(request.url, request.allowPooler === true);
|
|
350
|
+
const url = driverUrl(request.url);
|
|
351
|
+
const pool = open2({
|
|
352
|
+
url,
|
|
353
|
+
max: 1,
|
|
354
|
+
...request.searchPath !== undefined ? { searchPath: request.searchPath } : {}
|
|
355
|
+
});
|
|
356
|
+
if (pool.reserve === undefined) {
|
|
357
|
+
await pool.close();
|
|
358
|
+
throw new OkmError2("invalid", "The driver cannot reserve a connection.", {
|
|
359
|
+
fix: { summary: "Push needs a driver with interactive transactions." }
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
const connection = await pool.reserve();
|
|
363
|
+
let locked = false;
|
|
364
|
+
try {
|
|
365
|
+
await probeStableBackend(request.url, () => backendPid(connection), request.allowPooler === true);
|
|
366
|
+
await assertStandardStrings(connection);
|
|
367
|
+
await setTimeouts(connection, {
|
|
368
|
+
url: request.url,
|
|
369
|
+
target: request.target,
|
|
370
|
+
protected: request.protected,
|
|
371
|
+
migrations: []
|
|
372
|
+
});
|
|
373
|
+
await lockTarget(connection, request.target);
|
|
374
|
+
locked = true;
|
|
375
|
+
const session = {};
|
|
376
|
+
const schema = request.schema ?? "public";
|
|
377
|
+
await enterCatalogSchema(connection, schema);
|
|
378
|
+
await ensureMigrationTables2((sql) => connection.execute(sql));
|
|
379
|
+
const history = await readHistory(connection);
|
|
380
|
+
const pushId = nextSequenceId("push", history.ids);
|
|
381
|
+
const sql = postgres(url, {
|
|
382
|
+
max: 1,
|
|
383
|
+
connect_timeout: 5,
|
|
384
|
+
idle_timeout: 1,
|
|
385
|
+
onnotice: () => {},
|
|
386
|
+
...schema !== "public" ? { connection: { search_path: schema } } : {}
|
|
387
|
+
});
|
|
388
|
+
let planSteps = [];
|
|
389
|
+
try {
|
|
390
|
+
const runner = catalogQuery2(sql);
|
|
391
|
+
if (schema !== "public") {
|
|
392
|
+
await sql.unsafe(`create schema if not exists ${quoteIdent2(schema)}`);
|
|
393
|
+
await sql.unsafe(`set search_path to ${quoteIdent2(schema)}`);
|
|
394
|
+
}
|
|
395
|
+
const authorViews = await sealViews(runner, request.after);
|
|
396
|
+
const author = await sealDomainChecks2(runner, authorViews);
|
|
397
|
+
const live = await introspectSchema(runner, schema, schema, managedRoleOptions2(request.roles));
|
|
398
|
+
const plan = planMigration({
|
|
399
|
+
before: live,
|
|
400
|
+
after: author,
|
|
401
|
+
renames: request.renames,
|
|
402
|
+
name: pushId,
|
|
403
|
+
...request.schema !== undefined ? { schema: request.schema } : {},
|
|
404
|
+
...request.batchSize !== undefined ? { batchSize: request.batchSize } : {}
|
|
405
|
+
});
|
|
406
|
+
planSteps = plan.steps;
|
|
407
|
+
} finally {
|
|
408
|
+
await finishQuiet(() => sql.end({ timeout: 5 }));
|
|
409
|
+
}
|
|
410
|
+
if (planSteps.length === 0) {
|
|
411
|
+
const stamped = await restampHeadHash(connection, request, pushId, request.catalogHash);
|
|
412
|
+
await grantAppMeta(connection, request.appRole, session);
|
|
413
|
+
if (stamped.length === 0) {
|
|
414
|
+
return { target: request.target, applied: [] };
|
|
415
|
+
}
|
|
416
|
+
return { target: request.target, applied: [], restamped: stamped };
|
|
417
|
+
}
|
|
418
|
+
const migration = {
|
|
419
|
+
id: pushId,
|
|
420
|
+
catalogHash: request.catalogHash,
|
|
421
|
+
steps: planSteps
|
|
422
|
+
};
|
|
423
|
+
await prepareMigrationRole(connection, {
|
|
424
|
+
url: request.url,
|
|
425
|
+
target: request.target,
|
|
426
|
+
protected: request.protected,
|
|
427
|
+
migrations: [migration],
|
|
428
|
+
...request.migrationRole !== undefined ? { migrationRole: request.migrationRole } : {},
|
|
429
|
+
...request.schema !== undefined ? { schema: request.schema } : {}
|
|
430
|
+
}, session);
|
|
431
|
+
await assertExtensionsAvailable(connection, [migration]);
|
|
432
|
+
await assertUuidV7Available(connection, [migration]);
|
|
433
|
+
const units = applyUnits(migration, new Set);
|
|
434
|
+
const report = await runTarget(connection, {
|
|
435
|
+
policy: {
|
|
436
|
+
target: request.target,
|
|
437
|
+
protected: request.protected,
|
|
438
|
+
allowProtected: request.allowProtected === true
|
|
439
|
+
},
|
|
440
|
+
units,
|
|
441
|
+
retries: DEFAULT_RETRIES,
|
|
442
|
+
lockTimeoutMs: DEFAULT_LOCK_MS,
|
|
443
|
+
statementTimeoutMs: DEFAULT_STATEMENT_MS,
|
|
444
|
+
backfillStatementTimeoutMs: request.backfillStatementTimeoutMs ?? DEFAULT_STATEMENT_MS,
|
|
445
|
+
...request.backfillPauseMs !== undefined ? { backfillPauseMs: request.backfillPauseMs } : {},
|
|
446
|
+
...request.migrationRole !== undefined ? { migrationRole: request.migrationRole } : {},
|
|
447
|
+
...request.schema !== undefined ? { schema: request.schema } : {}
|
|
448
|
+
}, session);
|
|
449
|
+
await grantAppMeta(connection, request.appRole, session);
|
|
450
|
+
return report;
|
|
451
|
+
} finally {
|
|
452
|
+
if (locked) {
|
|
453
|
+
await finishQuiet(() => connection.execute("select pg_advisory_unlock(hashtext($1))", [lockKey(request.target)]));
|
|
454
|
+
}
|
|
455
|
+
await finishQuiet(() => connection.release());
|
|
456
|
+
await finishQuiet(() => pool.close());
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async function restampHeadHash(connection, request, migrationId, catalogHash) {
|
|
460
|
+
const present = await connection.execute("select to_regclass('okm_meta') is not null");
|
|
461
|
+
if (!wireTrue(present.rows[0]?.[0]))
|
|
462
|
+
return [];
|
|
463
|
+
const current = await connection.execute("select catalog_hash from okm_meta where id = 'head'");
|
|
464
|
+
const stored = current.rows[0]?.[0];
|
|
465
|
+
if (typeof stored === "string" && stored === catalogHash)
|
|
466
|
+
return [];
|
|
467
|
+
assertTargetPolicy({ name: request.target, protected: request.protected }, "history-repair", request.allowProtected === true);
|
|
468
|
+
await connection.execute("begin");
|
|
469
|
+
try {
|
|
470
|
+
await connection.execute("insert into okm_history (migration_id, step_index, class, catalog_hash) values ($1, 0, 'expand', $2)", [migrationId, catalogHash]);
|
|
471
|
+
await connection.execute(`insert into okm_meta (id, catalog_hash, migration_id) values ('head', $1, $2)
|
|
472
|
+
on conflict (id) do update set catalog_hash = excluded.catalog_hash, migration_id = excluded.migration_id`, [catalogHash, migrationId]);
|
|
473
|
+
await connection.execute("commit");
|
|
474
|
+
} catch (error) {
|
|
475
|
+
await connection.execute("rollback").catch(() => {
|
|
476
|
+
return;
|
|
477
|
+
});
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
return [migrationId];
|
|
481
|
+
}
|
|
482
|
+
function nextSequenceId(prefix, ids) {
|
|
483
|
+
const pattern = new RegExp(`^${prefix}-(\\d+)$`);
|
|
484
|
+
let max = 0;
|
|
485
|
+
for (const id of ids) {
|
|
486
|
+
const match = pattern.exec(id);
|
|
487
|
+
if (match === null)
|
|
488
|
+
continue;
|
|
489
|
+
const value = Number(match[1]);
|
|
490
|
+
if (Number.isFinite(value) && value > max)
|
|
491
|
+
max = value;
|
|
492
|
+
}
|
|
493
|
+
return `${prefix}-${String(max + 1)}`;
|
|
494
|
+
}
|
|
333
495
|
function backfillTiming2(backfill) {
|
|
334
496
|
return {
|
|
335
497
|
...backfill?.pauseMs !== undefined ? { backfillPauseMs: backfill.pauseMs } : {},
|
|
@@ -341,10 +503,11 @@ function formatReport(report) {
|
|
|
341
503
|
` : "";
|
|
342
504
|
const restamped = (report.restamped ?? []).map((id) => `restamped ${id}
|
|
343
505
|
`).join("");
|
|
344
|
-
if (report.applied.length === 0)
|
|
506
|
+
if (report.applied.length === 0) {
|
|
345
507
|
return `target ${report.target}
|
|
346
508
|
${role}${restamped}nothing to apply
|
|
347
509
|
`;
|
|
510
|
+
}
|
|
348
511
|
return `target ${report.target}
|
|
349
512
|
${role}${restamped}${report.applied.map((id) => `applied ${id}`).join(`
|
|
350
513
|
`)}
|