okmodel 0.8.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 +23 -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/btree-gin.d.ts +26 -0
- package/dist/dialects/pg/ext/btree-gin.js +20 -0
- package/dist/dialects/pg/ext/btree-gist.d.ts +26 -0
- package/dist/dialects/pg/ext/btree-gist.js +20 -0
- package/dist/dialects/pg/ext/call.d.ts +53 -0
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/feature.d.ts +26 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.d.ts +34 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.js +33 -0
- package/dist/dialects/pg/ext/hstore.d.ts +41 -0
- package/dist/dialects/pg/ext/hstore.js +29 -0
- package/dist/dialects/pg/ext/index.d.ts +56 -0
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/ltree.d.ts +41 -0
- package/dist/dialects/pg/ext/ltree.js +29 -0
- package/dist/dialects/pg/ext/pg-trgm.js +4 -13
- package/dist/dialects/pg/ext/pgcrypto.d.ts +33 -0
- package/dist/dialects/pg/ext/pgcrypto.js +33 -0
- package/dist/dialects/pg/ext/unaccent.d.ts +26 -0
- package/dist/dialects/pg/ext/unaccent.js +21 -0
- package/dist/dialects/pg/ext/using.d.ts +23 -0
- package/dist/dialects/pg/ext/versions.d.ts +36 -0
- package/dist/dialects/pg/external.d.ts +19 -0
- package/dist/dialects/pg/filters.d.ts +2 -2
- package/dist/dialects/pg/fn/index.js +5 -5
- package/dist/dialects/pg/index.d.ts +1 -0
- package/dist/dialects/pg/index.js +19 -14
- package/dist/dialects/pg/introspect.d.ts +12 -0
- package/dist/dialects/pg/view/index.js +7 -7
- package/dist/dialects/pg/view/scratch.d.ts +4 -1
- package/dist/runtime/artifact-file.d.ts +22 -0
- package/dist/runtime/client.d.ts +10 -0
- package/dist/runtime/drift-detail.d.ts +2 -1
- package/dist/runtime/drift.d.ts +3 -10
- package/dist/runtime/param-limit.d.ts +20 -0
- package/dist/runtime/pg/bun.js +4 -4
- package/dist/runtime/pg/neon.js +4 -4
- package/dist/runtime/pg/pg.js +4 -4
- package/dist/runtime/pg/pglite.js +4 -4
- package/dist/runtime/pg/postgresjs.js +11 -11
- package/dist/runtime/server-check.d.ts +36 -6
- package/dist/runtime/tenancy/index.js +1 -1
- package/dist/runtime/traits/index.js +6 -6
- package/dist/runtime/validate/index.js +2 -2
- package/dist/runtime/write.d.ts +1 -1
- package/dist/shared/{4m6hskg8.js → 0j6qe91y.js} +4 -4
- package/dist/shared/{6m78c8ss.js → 1h5h1rf5.js} +1 -1
- package/dist/shared/{4vbf83xx.js → 2vcnpf0n.js} +1 -1
- package/dist/shared/{qd9hhd8f.js → 3ap5hxvj.js} +2 -1
- package/dist/shared/{v1wad97q.js → 3d7a80fq.js} +1 -1
- package/dist/shared/{wcrheftc.js → 3dr444ny.js} +58 -79
- package/dist/shared/{hm5f8jby.js → 3vvpcphd.js} +8 -7
- package/dist/shared/{760ppr76.js → 4a3mmhhe.js} +2 -2
- package/dist/shared/{mkrn359n.js → 4pkz5nvw.js} +222 -39
- package/dist/shared/{agsfb86s.js → 4te76xc5.js} +4 -4
- package/dist/shared/{63f4ksbz.js → 60y4ahmw.js} +1 -1
- package/dist/shared/61bmrmhr.js +35 -0
- package/dist/shared/{bxas03mq.js → 63qjmhnp.js} +100 -17
- package/dist/shared/{g5yc06ka.js → 67w3kn71.js} +1 -1
- package/dist/shared/{jgqj11w4.js → 6f0z3hzh.js} +4 -0
- package/dist/shared/{njga14v4.js → 6vfvsdkt.js} +10 -8
- package/dist/shared/{kj9d8maq.js → 6xqvesa5.js} +1 -1
- package/dist/shared/8gdbty5v.js +665 -0
- package/dist/shared/{pan0370z.js → 8ma6drzr.js} +211 -30
- package/dist/shared/{mnvjvqyp.js → 8p2bgye0.js} +124 -32
- package/dist/shared/{mfedzr74.js → 8qwqrxed.js} +14 -6
- package/dist/shared/{hfqmpasr.js → 8v7vzpgt.js} +11 -8
- package/dist/shared/{7ghwamrf.js → 99qp9vtg.js} +1 -1
- package/dist/shared/{zgex00fd.js → ak61ye1f.js} +5 -5
- package/dist/shared/{dpc2r7rb.js → bdekbvmt.js} +218 -95
- package/dist/shared/{jebgrkeq.js → bxjq6xqv.js} +2 -2
- package/dist/shared/c7dqd3gk.js +1806 -0
- package/dist/shared/ddh72ym5.js +20 -0
- package/dist/shared/e1c55v04.js +10 -0
- package/dist/shared/{mtw6jz76.js → e275q7sd.js} +1 -1
- package/dist/shared/{k86n8vq3.js → ekhq3ytz.js} +1 -1
- package/dist/shared/esy4dyxe.js +17 -0
- package/dist/shared/{gcefca6p.js → f9t9g54z.js} +22 -9
- package/dist/shared/{sjk86yrx.js → fk9vef30.js} +84 -73
- package/dist/shared/fkjne6gx.js +8 -0
- package/dist/shared/{e8zyaqvj.js → fne90dvz.js} +4 -1
- package/dist/shared/{needfe47.js → g89fmz5s.js} +1 -1
- package/dist/shared/{m4xff2a6.js → ghqzdp94.js} +2 -2
- package/dist/shared/{n0jmpgj1.js → gr9sn4za.js} +1 -1
- package/dist/shared/{5mtf6cj3.js → gzgfsspx.js} +5 -2
- package/dist/shared/h9811jjm.js +17 -0
- package/dist/shared/{z581d7ny.js → hgt69zjf.js} +2 -2
- package/dist/shared/{35q0n9tz.js → jvxcp1qk.js} +71 -87
- package/dist/shared/k73e8n9d.js +136 -0
- package/dist/shared/{195pzzzz.js → kzgrcy8s.js} +12 -8
- package/dist/shared/kzgrnckd.js +29 -0
- package/dist/shared/{p3xbdcvt.js → mz48rs74.js} +68 -8
- package/dist/shared/{zbqbmmrp.js → n6je5b28.js} +13 -26
- package/dist/shared/{b6d6p0zc.js → ns35jqz0.js} +75 -49
- package/dist/shared/{n05z9nwz.js → nstwgzn8.js} +1 -1
- package/dist/{tooling/shared/08kemxjd.js → shared/pgsak1yw.js} +1 -1
- package/dist/shared/py2zrrm6.js +451 -0
- package/dist/shared/{9dr2qnx7.js → qqm3ze6q.js} +1 -1
- package/dist/shared/{wvdjznah.js → rcjm0yn7.js} +31 -38
- package/dist/shared/rged92v6.js +17 -0
- package/dist/shared/{jp36k7dp.js → rw4tpcd0.js} +81 -51
- package/dist/shared/{bsek72fg.js → s5qe47a6.js} +3 -0
- package/dist/shared/{1d9q9cv2.js → smxzjz60.js} +2 -2
- package/dist/shared/{wz2a78mp.js → th5rnaxw.js} +1 -1
- package/dist/{tooling/shared/rs1jb051.js → shared/tr64w5p0.js} +1 -1
- package/dist/shared/{14x60fbf.js → tyqapcgk.js} +73 -10
- package/dist/shared/vsna85qf.js +8 -0
- package/dist/shared/{63qtkrca.js → vy47ryqa.js} +55 -5
- package/dist/shared/{jx2m62cs.js → wbdh9qbg.js} +7 -5
- package/dist/shared/{f4jy1j7x.js → wp7y8q3y.js} +946 -105
- package/dist/shared/{16kvjebh.js → xbd9xs6p.js} +7 -26
- package/dist/shared/{bah9nbg3.js → xbvz446k.js} +18 -23
- package/dist/shared/{p5nh3r8q.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/{0wrea3jq.js → ysdw2fg3.js} +10 -2
- package/dist/shared/zecrwdk9.js +61 -0
- package/dist/shared/{3t6kw83m.js → zm2rzqba.js} +2 -1
- package/dist/tooling/cli.js +200 -50
- package/dist/tooling/driver-run.js +109 -343
- package/dist/tooling/github/comment.d.ts +56 -0
- package/dist/tooling/github/post-comment.d.ts +17 -0
- package/dist/tooling/migrate/apply.d.ts +17 -2
- package/dist/tooling/migrate/commands.d.ts +2 -1
- package/dist/tooling/migrate/config.d.ts +13 -0
- package/dist/tooling/migrate/drift.d.ts +12 -0
- package/dist/tooling/migrate/driver-url.d.ts +17 -0
- package/dist/tooling/migrate/export.d.ts +165 -0
- package/dist/tooling/migrate/ext-surface.d.ts +80 -0
- package/dist/tooling/migrate/ext.d.ts +31 -4
- package/dist/tooling/migrate/import-drizzle.d.ts +40 -0
- package/dist/tooling/migrate/index.d.ts +3 -0
- package/dist/tooling/migrate/index.js +57 -10
- package/dist/tooling/migrate/lint-rules.d.ts +18 -1
- package/dist/tooling/migrate/lint.d.ts +14 -1
- package/dist/tooling/migrate/place.d.ts +18 -0
- package/dist/tooling/migrate/plan-json.d.ts +65 -0
- package/dist/tooling/migrate/policy.d.ts +17 -5
- package/dist/tooling/migrate/pooler-probe.d.ts +23 -0
- package/dist/tooling/migrate/project.d.ts +10 -1
- package/dist/tooling/migrate/pull-emit.d.ts +98 -0
- package/dist/tooling/migrate/pull-routines.d.ts +126 -0
- package/dist/tooling/migrate/pull-verify.d.ts +26 -0
- package/dist/tooling/migrate/pull.d.ts +65 -0
- package/dist/tooling/migrate/reprint.d.ts +32 -0
- package/dist/tooling/migrate/runner.d.ts +24 -1
- package/dist/tooling/migrate/sandbox.d.ts +8 -2
- package/dist/tooling/migrate/schema-api.d.ts +43 -0
- package/dist/tooling/migrate/sql-lex.d.ts +18 -0
- package/dist/tooling/shared/{ppnnnvj8.js → 09a6vsys.js} +1 -1
- package/dist/tooling/shared/{7ae7rjmn.js → 0v9ptnxp.js} +8 -8
- package/dist/tooling/shared/{fb9k2qwd.js → 0wtzps9p.js} +11 -30
- package/dist/tooling/shared/{a6pp9d12.js → 0yhf1db4.js} +6 -6
- package/dist/tooling/shared/{dy672fz6.js → 19msgrsc.js} +2 -2
- package/dist/{shared/q0cqt2sp.js → tooling/shared/1fwfm5m3.js} +1 -1
- package/dist/tooling/shared/{f9mphxej.js → 2jdn09e2.js} +401 -24
- package/dist/tooling/shared/{jne7b93p.js → 2qrte2ct.js} +5 -5
- package/dist/tooling/shared/{5bvw2nev.js → 2v4nwnkb.js} +1 -1
- package/dist/tooling/shared/{spk1jg3r.js → 33z39trp.js} +106 -23
- package/dist/tooling/shared/{z8d7ptht.js → 353vnw9z.js} +5 -5
- package/dist/tooling/shared/{dw08f3m8.js → 390kry9g.js} +2 -2
- package/dist/tooling/shared/{xjs6zqtc.js → 3f6etb9z.js} +18 -31
- package/dist/{shared/bnby0esn.js → tooling/shared/3t2cqmsx.js} +1 -1
- package/dist/tooling/shared/{wwnekq5n.js → 4dzvjtpy.js} +1 -1
- package/dist/tooling/shared/{y5656f0e.js → 4ec0nxvw.js} +10 -10
- package/dist/tooling/shared/{3m1hkg7z.js → 4tg2bn41.js} +59 -78
- package/dist/tooling/shared/{zvnhh1n0.js → 5rah55z0.js} +2 -2
- package/dist/tooling/shared/{pqy21k24.js → 804w1t69.js} +4 -4
- package/dist/tooling/shared/8g0m0rvd.js +134 -0
- package/dist/tooling/shared/8msbtw5s.js +8 -0
- package/dist/tooling/shared/{4d2w25vw.js → 8t22h3h7.js} +2 -2
- package/dist/tooling/shared/{smn6kz1p.js → 91c59b7b.js} +2 -2
- package/dist/tooling/shared/{aftb2mwr.js → adk9k6va.js} +1 -1
- package/dist/tooling/shared/{j9t5s12a.js → ajjd5cwz.js} +2 -2
- package/dist/tooling/shared/{cmptmb4f.js → angjck01.js} +1 -1
- package/dist/tooling/shared/{yw30vnq2.js → asnnc3v5.js} +1 -1
- package/dist/tooling/shared/{ma2340rx.js → bj1kyqc8.js} +2 -2
- package/dist/tooling/shared/{2wtvc7rw.js → bt3tjemb.js} +11 -3
- package/dist/tooling/shared/{ec71zqgt.js → chk2bh4f.js} +2 -2
- package/dist/tooling/shared/{gmcf9cxf.js → ckq4z5ax.js} +5 -2
- package/dist/tooling/shared/{w7qe8sj1.js → d3rhb24q.js} +1 -1
- package/dist/tooling/shared/{y031jct9.js → d8q00vxg.js} +4 -4
- package/dist/tooling/shared/{vs0t6qt8.js → dx188rxs.js} +2 -2
- package/dist/tooling/shared/{g9ad4n80.js → efq6p9df.js} +35 -42
- package/dist/tooling/shared/{ddjtfgnx.js → en6rwzq0.js} +3 -3
- package/dist/tooling/shared/{6nyfyw70.js → f2r5g0fs.js} +2 -2
- package/dist/tooling/shared/{03k6res6.js → f4gep0nk.js} +1 -1
- package/dist/tooling/shared/{gfvtj6d0.js → f8a010fm.js} +13 -11
- package/dist/tooling/shared/{3tq8pnb8.js → fdsek6pa.js} +1 -1
- package/dist/tooling/shared/fvmrxsd1.js +8 -0
- package/dist/tooling/shared/{733a1tq3.js → g3xybeqf.js} +4 -3
- package/dist/tooling/shared/{pwsytxm5.js → gefmpwsa.js} +1 -1
- package/dist/tooling/shared/{mtrqn2hn.js → gjj71hfh.js} +25 -30
- package/dist/tooling/shared/{8sqrsw3s.js → jgzt69pa.js} +5 -5
- package/dist/tooling/shared/{nf7jmhfa.js → jm30k2ca.js} +10 -8
- package/dist/tooling/shared/{vx86qjv8.js → kayqzpbk.js} +6 -3
- package/dist/tooling/shared/{zhwnfyb2.js → kvw1672d.js} +1 -1
- package/dist/tooling/shared/{rq5kk8j6.js → mr1kcgpw.js} +3 -3
- package/dist/tooling/shared/{72fyg4zv.js → mwbdf409.js} +1 -1
- package/dist/tooling/shared/{wt7j7nf6.js → ns9207v3.js} +1 -1
- package/dist/tooling/shared/{9xzm7hjg.js → p6tjv97k.js} +3 -3
- package/dist/tooling/shared/{yfr8hzhm.js → p73evwf0.js} +1 -1
- package/dist/tooling/shared/{dzx85q70.js → phc1nc4g.js} +1 -1
- package/dist/tooling/shared/{417zdsk7.js → ppybjw50.js} +79 -16
- package/dist/tooling/shared/{yk9mp7vb.js → qdrn8ghn.js} +5 -4
- package/dist/tooling/shared/rd8h01ta.js +20 -0
- package/dist/tooling/shared/{bz2dqhab.js → rwg8y90m.js} +3 -3
- package/dist/tooling/shared/{xhrnjch9.js → ry2f3w8p.js} +3 -3
- package/dist/tooling/shared/{a7q7t4n3.js → ryc5sa58.js} +8 -8
- package/dist/tooling/shared/{2revefqt.js → ss87qxwv.js} +2 -2
- package/dist/tooling/shared/{rf83gr2d.js → vg68k11z.js} +7 -3
- package/dist/tooling/shared/{p7f08ktn.js → vms9dta5.js} +73 -89
- package/dist/tooling/shared/{3rrw5w8f.js → xchpnbdv.js} +1 -1
- package/dist/tooling/shared/{djydjpqt.js → xn6p01fh.js} +5 -5
- package/dist/tooling/shared/{9kazs5p6.js → xwr6q618.js} +3 -3
- package/dist/tooling/shared/{ep8zh3bk.js → xx3gmq94.js} +1 -1
- package/dist/tooling/shared/{tn8gay14.js → y2bd7yfx.js} +21 -13
- package/dist/tooling/shared/{vraj6d74.js → y4gq9rbe.js} +11 -11
- package/dist/tooling/shared/y4vwft92.js +9 -0
- package/dist/tooling/shared/{345tbc2k.js → yz68xcmc.js} +1 -1
- package/dist/tooling/testing/factories.d.ts +1 -3
- package/dist/tooling/testing/index.js +2 -2
- package/package.json +39 -9
- package/dist/shared/3449rcae.js +0 -14
- package/dist/shared/fjpnhqan.js +0 -71
- package/dist/shared/n41w4fbz.js +0 -113
- package/dist/tooling/shared/pw8fgahx.js +0 -69
- /package/dist/shared/{ae4j5f42.js → mfvx6kjx.js} +0 -0
|
@@ -1,9 +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
|
+
import {
|
|
8
|
+
quoteIdent2
|
|
9
|
+
} from "./fk9vef30.js";
|
|
10
|
+
import {
|
|
11
|
+
sealViews,
|
|
12
|
+
sealDomainChecks2,
|
|
13
|
+
catalogQuery2,
|
|
14
|
+
managedRoleOptions2
|
|
15
|
+
} from "./4pkz5nvw.js";
|
|
7
16
|
import {
|
|
8
17
|
runTarget,
|
|
9
18
|
assumeRole,
|
|
@@ -14,14 +23,21 @@ import {
|
|
|
14
23
|
provisionMark,
|
|
15
24
|
expandProvisioned,
|
|
16
25
|
installSnapshot
|
|
17
|
-
} from "./
|
|
26
|
+
} from "./8p2bgye0.js";
|
|
18
27
|
import {
|
|
19
28
|
assertCreateRole,
|
|
20
29
|
currentUser,
|
|
21
30
|
roleExists
|
|
22
|
-
} from "./
|
|
31
|
+
} from "./6xqvesa5.js";
|
|
32
|
+
import {
|
|
33
|
+
probeStableBackend
|
|
34
|
+
} from "./e1c55v04.js";
|
|
35
|
+
import {
|
|
36
|
+
introspectSchema
|
|
37
|
+
} from "./mz48rs74.js";
|
|
23
38
|
import {
|
|
24
39
|
projectPath,
|
|
40
|
+
assertSnapshots,
|
|
25
41
|
loadMigrations,
|
|
26
42
|
loadHeadSnapshot,
|
|
27
43
|
lintMigrationDirectory,
|
|
@@ -30,8 +46,9 @@ import {
|
|
|
30
46
|
projectHead,
|
|
31
47
|
loadBuiltSchema,
|
|
32
48
|
loadConfig
|
|
33
|
-
} from "./
|
|
49
|
+
} from "./wp7y8q3y.js";
|
|
34
50
|
import {
|
|
51
|
+
driverUrl,
|
|
35
52
|
changesRole,
|
|
36
53
|
batchSizeField,
|
|
37
54
|
assertExtensionsAvailable,
|
|
@@ -39,9 +56,8 @@ import {
|
|
|
39
56
|
finishQuiet,
|
|
40
57
|
assertTargetPolicy,
|
|
41
58
|
assertDirectConnection,
|
|
42
|
-
assertStableBackend,
|
|
43
59
|
selectTarget
|
|
44
|
-
} from "./
|
|
60
|
+
} from "./bdekbvmt.js";
|
|
45
61
|
import {
|
|
46
62
|
UUIDV7_POSTGRES,
|
|
47
63
|
uuidv7NeedsPostgres
|
|
@@ -96,6 +112,7 @@ function unquote(name) {
|
|
|
96
112
|
}
|
|
97
113
|
|
|
98
114
|
// src/tooling/migrate/apply.ts
|
|
115
|
+
import postgres from "postgres";
|
|
99
116
|
var DEFAULT_LOCK_MS = 5000;
|
|
100
117
|
var DEFAULT_STATEMENT_MS = 30000;
|
|
101
118
|
var DEFAULT_RETRIES = 3;
|
|
@@ -170,8 +187,9 @@ function applyUnits(migration, done) {
|
|
|
170
187
|
}
|
|
171
188
|
async function applyTarget2(request) {
|
|
172
189
|
assertDirectConnection(request.url, request.allowPooler === true);
|
|
190
|
+
const url = driverUrl(request.url);
|
|
173
191
|
const pool = open2({
|
|
174
|
-
url
|
|
192
|
+
url,
|
|
175
193
|
max: 1,
|
|
176
194
|
...request.searchPath !== undefined ? { searchPath: request.searchPath } : {}
|
|
177
195
|
});
|
|
@@ -185,7 +203,7 @@ async function applyTarget2(request) {
|
|
|
185
203
|
const connection = reserved;
|
|
186
204
|
let locked = false;
|
|
187
205
|
try {
|
|
188
|
-
await
|
|
206
|
+
await probeStableBackend(request.url, () => backendPid(connection), request.allowPooler === true);
|
|
189
207
|
await assertStandardStrings(connection);
|
|
190
208
|
await setTimeouts(connection, request);
|
|
191
209
|
await lockTarget(connection, request.target);
|
|
@@ -198,6 +216,7 @@ async function applyTarget2(request) {
|
|
|
198
216
|
await prepareMigrationRole(connection, request, session);
|
|
199
217
|
await assertExtensionsAvailable(connection, request.migrations);
|
|
200
218
|
await assertUuidV7Available(connection, request.migrations);
|
|
219
|
+
await enterCatalogSchema(connection, request.schema ?? "public");
|
|
201
220
|
const state = request.snapshot === undefined ? undefined : await targetState(connection);
|
|
202
221
|
if (request.snapshot !== undefined && state !== undefined) {
|
|
203
222
|
if (state.kind === "empty") {
|
|
@@ -230,8 +249,11 @@ async function applyTarget2(request) {
|
|
|
230
249
|
if (request.snapshot !== undefined) {
|
|
231
250
|
await insertReference(connection, request);
|
|
232
251
|
}
|
|
252
|
+
const desiredHash = request.headHash;
|
|
253
|
+
const headStamp = desiredHash === undefined || request.restampHead !== true ? [] : await restampHeadHash(connection, request, nextSequenceId("restamp", history.ids), desiredHash);
|
|
233
254
|
await grantAppMeta(connection, request.appRole, session);
|
|
234
|
-
|
|
255
|
+
const stamped = [...restamped, ...headStamp];
|
|
256
|
+
return stamped.length === 0 ? report : { ...report, restamped: stamped };
|
|
235
257
|
} finally {
|
|
236
258
|
if (locked) {
|
|
237
259
|
await finishQuiet(() => connection.execute("select pg_advisory_unlock(hashtext($1))", [lockKey(request.target)]));
|
|
@@ -255,7 +277,10 @@ nothing to apply
|
|
|
255
277
|
return;
|
|
256
278
|
throw error;
|
|
257
279
|
});
|
|
280
|
+
if (built !== undefined)
|
|
281
|
+
assertSnapshots(cwd, config, built.catalog);
|
|
258
282
|
const progress = [];
|
|
283
|
+
const externalConfigured = (config.external ?? []).length > 0;
|
|
259
284
|
const report = await applyTarget2({
|
|
260
285
|
url: target.url,
|
|
261
286
|
target: target.name,
|
|
@@ -272,7 +297,10 @@ nothing to apply
|
|
|
272
297
|
catalogHash: head.catalogHash,
|
|
273
298
|
reference: built === undefined ? [] : readReference(built.tables, built.casing, head.catalog)
|
|
274
299
|
},
|
|
300
|
+
...built !== undefined ? { headHash: startupHash2(built.catalog) } : {},
|
|
301
|
+
...externalConfigured ? { restampHead: true } : {},
|
|
275
302
|
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {},
|
|
303
|
+
...catalogSchema(config.namespace),
|
|
276
304
|
lintDirectory: directory,
|
|
277
305
|
onProgress: (line) => {
|
|
278
306
|
if (write !== undefined)
|
|
@@ -294,35 +322,176 @@ async function pushProject2(cwd, flags) {
|
|
|
294
322
|
const target = selectTarget(config, flags.target);
|
|
295
323
|
assertTargetPolicy(target, "push", flags.allowProtected);
|
|
296
324
|
const head = await projectHead(cwd);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
renames: head.renames,
|
|
301
|
-
name: "push",
|
|
302
|
-
...batchSizeField(config.backfill?.batchSize)
|
|
303
|
-
});
|
|
304
|
-
if (plan.steps.length === 0)
|
|
305
|
-
return `target ${target.name}
|
|
306
|
-
no changes
|
|
307
|
-
`;
|
|
308
|
-
const report = await applyTarget2({
|
|
325
|
+
assertSnapshots(cwd, config, head.catalog);
|
|
326
|
+
const catalogHash = startupHash2(head.catalog);
|
|
327
|
+
const report = await pushTarget({
|
|
309
328
|
url: target.url,
|
|
310
329
|
target: target.name,
|
|
311
330
|
protected: target.protected,
|
|
312
331
|
allowProtected: flags.allowProtected,
|
|
313
332
|
allowPooler: flags.allowPooler || config.allowPooler === true,
|
|
314
333
|
...backfillTiming2(config.backfill),
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
],
|
|
322
|
-
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app } : {}
|
|
334
|
+
after: head.catalog,
|
|
335
|
+
renames: head.renames,
|
|
336
|
+
catalogHash,
|
|
337
|
+
...config.roles !== undefined ? { migrationRole: config.roles.migration, appRole: config.roles.app, roles: config.roles } : {},
|
|
338
|
+
...catalogSchema(config.namespace),
|
|
339
|
+
...batchSizeField(config.backfill?.batchSize)
|
|
323
340
|
});
|
|
341
|
+
if (report.applied.length === 0 && (report.restamped ?? []).length === 0) {
|
|
342
|
+
return `target ${target.name}
|
|
343
|
+
no changes
|
|
344
|
+
`;
|
|
345
|
+
}
|
|
324
346
|
return formatReport(report);
|
|
325
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
|
+
}
|
|
326
495
|
function backfillTiming2(backfill) {
|
|
327
496
|
return {
|
|
328
497
|
...backfill?.pauseMs !== undefined ? { backfillPauseMs: backfill.pauseMs } : {},
|
|
@@ -334,10 +503,11 @@ function formatReport(report) {
|
|
|
334
503
|
` : "";
|
|
335
504
|
const restamped = (report.restamped ?? []).map((id) => `restamped ${id}
|
|
336
505
|
`).join("");
|
|
337
|
-
if (report.applied.length === 0)
|
|
506
|
+
if (report.applied.length === 0) {
|
|
338
507
|
return `target ${report.target}
|
|
339
508
|
${role}${restamped}nothing to apply
|
|
340
509
|
`;
|
|
510
|
+
}
|
|
341
511
|
return `target ${report.target}
|
|
342
512
|
${role}${restamped}${report.applied.map((id) => `applied ${id}`).join(`
|
|
343
513
|
`)}
|
|
@@ -514,6 +684,17 @@ async function insertReference(connection, request) {
|
|
|
514
684
|
function concreteSchema(request) {
|
|
515
685
|
return request.searchPath ?? request.schema ?? "public";
|
|
516
686
|
}
|
|
687
|
+
function catalogSchema(namespace) {
|
|
688
|
+
if (namespace === undefined || namespace === "public")
|
|
689
|
+
return;
|
|
690
|
+
return { schema: namespace };
|
|
691
|
+
}
|
|
692
|
+
async function enterCatalogSchema(connection, schema) {
|
|
693
|
+
if (schema === "public")
|
|
694
|
+
return;
|
|
695
|
+
await connection.execute(`create schema if not exists ${quoteIdent2(schema)}`);
|
|
696
|
+
await connection.execute(`set search_path to ${quoteIdent2(schema)}`);
|
|
697
|
+
}
|
|
517
698
|
async function targetState(connection) {
|
|
518
699
|
const meta = await connection.execute(`select to_regclass('okm_meta') is not null
|
|
519
700
|
or to_regclass('okm_history') is not null
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
serializeCatalog2
|
|
3
3
|
} from "./12z7aznj.js";
|
|
4
|
+
import {
|
|
5
|
+
quoteIdent2,
|
|
6
|
+
qualify2
|
|
7
|
+
} from "./fk9vef30.js";
|
|
4
8
|
import {
|
|
5
9
|
roleExists
|
|
6
|
-
} from "./
|
|
10
|
+
} from "./6xqvesa5.js";
|
|
7
11
|
import {
|
|
8
12
|
canonicalTypeName,
|
|
9
13
|
createdRoleName,
|
|
10
14
|
createRoleOnce,
|
|
15
|
+
changesRole,
|
|
11
16
|
DEFAULT_BACKFILL_PAUSE_MS,
|
|
12
17
|
DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS,
|
|
13
18
|
boundaryQuery,
|
|
@@ -16,14 +21,10 @@ import {
|
|
|
16
21
|
planMigration,
|
|
17
22
|
sessionFailure,
|
|
18
23
|
assertTargetPolicy
|
|
19
|
-
} from "./
|
|
24
|
+
} from "./bdekbvmt.js";
|
|
20
25
|
import {
|
|
21
26
|
snakeCase
|
|
22
|
-
} from "./
|
|
23
|
-
import {
|
|
24
|
-
quoteIdent,
|
|
25
|
-
qualify
|
|
26
|
-
} from "./sjk86yrx.js";
|
|
27
|
+
} from "./f9t9g54z.js";
|
|
27
28
|
import {
|
|
28
29
|
catalog,
|
|
29
30
|
isDomain
|
|
@@ -70,21 +71,97 @@ async function runTarget(connection, run, session) {
|
|
|
70
71
|
async function assumeRole(connection, role, session) {
|
|
71
72
|
if (session.setRole === role)
|
|
72
73
|
return;
|
|
73
|
-
await connection
|
|
74
|
+
await ensureSetOption(connection, role);
|
|
75
|
+
await connection.execute(`set role ${quoteIdent2(role)}`);
|
|
74
76
|
session.setRole = role;
|
|
75
77
|
}
|
|
78
|
+
async function ensureSetOption(connection, role) {
|
|
79
|
+
const who = await connection.execute("select current_user, rolsuper from pg_roles where rolname = current_user");
|
|
80
|
+
const current = who.rows[0]?.[0];
|
|
81
|
+
if (typeof current !== "string" || current === role)
|
|
82
|
+
return;
|
|
83
|
+
if (roleFlag(who.rows[0]?.[1]))
|
|
84
|
+
return;
|
|
85
|
+
const version = await connection.execute("show server_version_num");
|
|
86
|
+
const versionNum = Number(version.rows[0]?.[0] ?? 0);
|
|
87
|
+
if (Number.isFinite(versionNum) && versionNum >= 160000) {
|
|
88
|
+
const option = await connection.execute(`select am.set_option
|
|
89
|
+
from pg_auth_members am
|
|
90
|
+
join pg_roles r on r.oid = am.roleid
|
|
91
|
+
join pg_roles m on m.oid = am.member
|
|
92
|
+
where r.rolname = $1 and m.rolname = $2`, [role, current]);
|
|
93
|
+
if (roleFlag(option.rows[0]?.[0]))
|
|
94
|
+
return;
|
|
95
|
+
await connection.execute(`grant ${quoteIdent2(role)} to ${quoteIdent2(current)} with set true`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const member = await connection.execute("select pg_has_role($1, $2, 'MEMBER')", [current, role]);
|
|
99
|
+
if (roleFlag(member.rows[0]?.[0]))
|
|
100
|
+
return;
|
|
101
|
+
await connection.execute(`grant ${quoteIdent2(role)} to ${quoteIdent2(current)}`);
|
|
102
|
+
}
|
|
103
|
+
function rolePrivilegeError(error, role) {
|
|
104
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
105
|
+
if (/permission denied to create role/i.test(message)) {
|
|
106
|
+
return new OkmError2("forbidden", "CREATEROLE is required to create roles. Nothing was changed.", {
|
|
107
|
+
kind: "forbidden",
|
|
108
|
+
cause: error,
|
|
109
|
+
fix: {
|
|
110
|
+
summary: "Grant CREATEROLE to the connecting role, or connect as a superuser."
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (/permission denied to set role/i.test(message)) {
|
|
115
|
+
const name = role ?? "the migration role";
|
|
116
|
+
return new OkmError2("forbidden", `Cannot SET ROLE ${name}: the connecting role lacks the SET option on that membership.`, {
|
|
117
|
+
kind: "forbidden",
|
|
118
|
+
cause: error,
|
|
119
|
+
fix: {
|
|
120
|
+
summary: `Grant ${name} to the connecting role (WITH SET TRUE on Postgres 16+), or connect as a superuser.`
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (/must be able to SET ROLE|not a member/i.test(message)) {
|
|
125
|
+
const name = role ?? "the migration role";
|
|
126
|
+
return new OkmError2("forbidden", `Cannot SET ROLE ${name}: the connecting role is not a member with the SET option.`, {
|
|
127
|
+
kind: "forbidden",
|
|
128
|
+
cause: error,
|
|
129
|
+
fix: {
|
|
130
|
+
summary: `Grant ${name} to the connecting role (WITH SET TRUE on Postgres 16+), or connect as a superuser.`
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
76
136
|
async function grantAppMeta(connection, role, session) {
|
|
77
137
|
if (role === undefined)
|
|
78
138
|
return;
|
|
79
139
|
const previous = session.setRole;
|
|
80
140
|
if (previous !== undefined)
|
|
81
141
|
await connection.execute("reset role");
|
|
82
|
-
await connection.execute(`grant select on okm_meta to ${
|
|
142
|
+
await connection.execute(`grant select on okm_meta to ${quoteIdent2(role)}`);
|
|
83
143
|
if (previous !== undefined)
|
|
84
|
-
await connection.execute(`set role ${
|
|
144
|
+
await connection.execute(`set role ${quoteIdent2(previous)}`);
|
|
85
145
|
}
|
|
86
146
|
async function grantSchema(connection, schema, role) {
|
|
87
|
-
await connection.execute(`grant usage, create on schema ${
|
|
147
|
+
await connection.execute(`grant usage, create on schema ${quoteIdent2(schema)} to ${quoteIdent2(role)}`);
|
|
148
|
+
}
|
|
149
|
+
async function ownSchema(connection, schema, role) {
|
|
150
|
+
await ensureSetOption(connection, role);
|
|
151
|
+
await connection.execute("savepoint okm_own_schema");
|
|
152
|
+
try {
|
|
153
|
+
const database = await databaseName(connection);
|
|
154
|
+
await connection.execute(`grant create on database ${quoteIdent2(database)} to ${quoteIdent2(role)}`);
|
|
155
|
+
await connection.execute(`alter schema ${quoteIdent2(schema)} owner to ${quoteIdent2(role)}`);
|
|
156
|
+
await connection.execute("release savepoint okm_own_schema");
|
|
157
|
+
} catch {
|
|
158
|
+
await connection.execute("rollback to savepoint okm_own_schema");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function databaseName(connection) {
|
|
162
|
+
const result = await connection.execute("select current_database()");
|
|
163
|
+
const name = result.rows[0]?.[0];
|
|
164
|
+
return typeof name === "string" ? name : "postgres";
|
|
88
165
|
}
|
|
89
166
|
async function runUnit(connection, unit, run, session) {
|
|
90
167
|
const only = unit.steps.length === 1 ? unit.steps[0] : undefined;
|
|
@@ -102,6 +179,9 @@ async function runUnit(connection, unit, run, session) {
|
|
|
102
179
|
}
|
|
103
180
|
for (const item of unit.steps) {
|
|
104
181
|
current = item.index;
|
|
182
|
+
if (run.migrationRole !== undefined && !changesRole(item.step.sql) && session.setRole !== run.migrationRole && await roleExists(connection, run.migrationRole)) {
|
|
183
|
+
await assumeRole(connection, run.migrationRole, session);
|
|
184
|
+
}
|
|
105
185
|
await rebuildInvalidIndex(connection, item.step.sql);
|
|
106
186
|
const created = createdRoleName(item.step.sql);
|
|
107
187
|
const existed = created !== undefined && await roleExists(connection, created);
|
|
@@ -110,12 +190,10 @@ async function runUnit(connection, unit, run, session) {
|
|
|
110
190
|
await assertSchemaUsageLanded(connection, item.step.sql);
|
|
111
191
|
} else if (!existed)
|
|
112
192
|
await connection.execute(createRoleOnce(item.step.sql));
|
|
113
|
-
if (created !== undefined && created === run.migrationRole) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
await assumeRole(connection, created, session);
|
|
193
|
+
if (created !== undefined && created === run.migrationRole && !existed) {
|
|
194
|
+
await grantSchema(connection, run.schema ?? "public", created);
|
|
195
|
+
await ownSchema(connection, run.schema ?? "public", created);
|
|
196
|
+
await connection.execute(`grant select, insert, update on okm_meta, okm_history, okm_backfill to ${quoteIdent2(created)}`);
|
|
119
197
|
}
|
|
120
198
|
if (!unit.transactional) {
|
|
121
199
|
await connection.execute("begin");
|
|
@@ -127,6 +205,9 @@ async function runUnit(connection, unit, run, session) {
|
|
|
127
205
|
began = false;
|
|
128
206
|
}
|
|
129
207
|
}
|
|
208
|
+
if (run.migrationRole !== undefined && session.setRole !== run.migrationRole && await roleExists(connection, run.migrationRole)) {
|
|
209
|
+
await assumeRole(connection, run.migrationRole, session);
|
|
210
|
+
}
|
|
130
211
|
if (unit.transactional) {
|
|
131
212
|
for (const item of unit.steps)
|
|
132
213
|
await writeStep(connection, unit, item);
|
|
@@ -182,7 +263,7 @@ async function runBackfill(connection, unit, item, spec, run) {
|
|
|
182
263
|
rows,
|
|
183
264
|
lastKey: committed.lastKey
|
|
184
265
|
};
|
|
185
|
-
run.onProgress?.(`backfill ${unit.migrationId} step ${String(item.index)} batch ${String(batches)} rows ${String(rows)} key ${committed.lastKey ?? "-"}`);
|
|
266
|
+
run.onProgress?.(`backfill ${unit.migrationId} step ${String(item.index + 1)} batch ${String(batches)} rows ${String(rows)} key ${committed.lastKey ?? "-"}`);
|
|
186
267
|
await run.afterBatch?.(note);
|
|
187
268
|
if (committed.final)
|
|
188
269
|
return;
|
|
@@ -305,7 +386,7 @@ async function rebuildInvalidIndex(connection, sql) {
|
|
|
305
386
|
const valid = found.rows[0]?.[0];
|
|
306
387
|
if (valid === undefined || wireTrue(valid))
|
|
307
388
|
return;
|
|
308
|
-
await connection.execute(`drop index concurrently if exists ${
|
|
389
|
+
await connection.execute(`drop index concurrently if exists ${quoteIdent2(name)}`);
|
|
309
390
|
}
|
|
310
391
|
function concurrentIndexName(sql) {
|
|
311
392
|
const match = /^create\s+(?:unique\s+)?index\s+concurrently\s+(?:if\s+not\s+exists\s+)?(?:"([^"]+)"|([A-Za-z_][\w$]*))/i.exec(sql.trim());
|
|
@@ -325,13 +406,12 @@ async function assertSchemaUsageLanded(connection, sql) {
|
|
|
325
406
|
join pg_roles r on r.oid = a.grantee
|
|
326
407
|
where n.nspname = $1 and r.rolname = $2 and a.privilege_type = 'USAGE'
|
|
327
408
|
)`, [schema, role]);
|
|
328
|
-
|
|
329
|
-
if (landed === "t" || landed === "true")
|
|
409
|
+
if (roleFlag(found.rows[0]?.[0]))
|
|
330
410
|
return;
|
|
331
411
|
throw new OkmError2("OKM1825", `Grant usage on schema ${schema} to ${role} did not take effect.`, {
|
|
332
412
|
kind: "forbidden",
|
|
333
413
|
fix: {
|
|
334
|
-
summary: `Make the migration role the owner of schema ${schema}. ALTER SCHEMA ${
|
|
414
|
+
summary: `Make the migration role the owner of schema ${schema}. ALTER SCHEMA ${quoteIdent2(schema)} OWNER TO <migration role>.`
|
|
335
415
|
}
|
|
336
416
|
});
|
|
337
417
|
}
|
|
@@ -340,6 +420,10 @@ function failStep(unit, index, error) {
|
|
|
340
420
|
if (lost !== undefined) {
|
|
341
421
|
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
422
|
}
|
|
423
|
+
const privilege = rolePrivilegeError(error, undefined);
|
|
424
|
+
if (privilege !== undefined) {
|
|
425
|
+
return new OkmError2(privilege.code, `Migration ${unit.migrationId} failed at step ${String(index + 1)}: ${privilege.message}`, { kind: privilege.kind, cause: error, fix: privilege.fix });
|
|
426
|
+
}
|
|
343
427
|
if (error instanceof OkmError2)
|
|
344
428
|
return error;
|
|
345
429
|
const message = error instanceof Error ? error.message : "The step failed.";
|
|
@@ -359,6 +443,9 @@ function isLockTimeout(error) {
|
|
|
359
443
|
function wireTrue(value) {
|
|
360
444
|
return value === "t" || value === "true";
|
|
361
445
|
}
|
|
446
|
+
function roleFlag(value) {
|
|
447
|
+
return value === true || value === "t" || value === "true";
|
|
448
|
+
}
|
|
362
449
|
function unquote(token) {
|
|
363
450
|
if (token.startsWith('"') && token.endsWith('"')) {
|
|
364
451
|
return token.slice(1, -1).replaceAll('""', '"');
|
|
@@ -423,11 +510,11 @@ function readReference(tables, casing, head) {
|
|
|
423
510
|
function referenceInserts(tables, schema) {
|
|
424
511
|
const statements = [];
|
|
425
512
|
for (const item of tables) {
|
|
426
|
-
const conflict = item.key.map((name) =>
|
|
513
|
+
const conflict = item.key.map((name) => quoteIdent2(name)).join(", ");
|
|
427
514
|
for (const row of item.rows) {
|
|
428
|
-
const columns = row.map(([name]) =>
|
|
515
|
+
const columns = row.map(([name]) => quoteIdent2(name)).join(", ");
|
|
429
516
|
const values = row.map(([, value]) => literal(value)).join(", ");
|
|
430
|
-
statements.push(`insert into ${
|
|
517
|
+
statements.push(`insert into ${qualify2(schema, item.table)} (${columns}) values (${values}) on conflict (${conflict}) do nothing`);
|
|
431
518
|
}
|
|
432
519
|
}
|
|
433
520
|
return statements;
|
|
@@ -598,13 +685,14 @@ async function installSnapshot(connection, head, schema, reference, session, mig
|
|
|
598
685
|
for (const step of plan.steps) {
|
|
599
686
|
if (step.backfill !== undefined)
|
|
600
687
|
continue;
|
|
688
|
+
if (migrationRole !== undefined && !changesRole(step.sql) && session.setRole !== migrationRole && await roleExists(connection, migrationRole)) {
|
|
689
|
+
await flush();
|
|
690
|
+
await assumeRole(connection, migrationRole, session);
|
|
691
|
+
}
|
|
601
692
|
const created = createdRoleName(step.sql);
|
|
602
693
|
const existed = created !== undefined && await roleExists(connection, created);
|
|
603
|
-
if (created !== undefined && existed)
|
|
604
|
-
if (created === migrationRole)
|
|
605
|
-
await assumeRole(connection, created, session);
|
|
694
|
+
if (created !== undefined && existed)
|
|
606
695
|
continue;
|
|
607
|
-
}
|
|
608
696
|
const sql = created === undefined ? step.sql : createRoleOnce(step.sql);
|
|
609
697
|
if (step.transactional && !statementOutsideTransaction(step.sql)) {
|
|
610
698
|
batch.push(sql);
|
|
@@ -616,10 +704,14 @@ async function installSnapshot(connection, head, schema, reference, session, mig
|
|
|
616
704
|
if (created !== undefined && created === migrationRole) {
|
|
617
705
|
await flush();
|
|
618
706
|
await grantSchema(connection, schema, created);
|
|
619
|
-
await connection
|
|
620
|
-
await
|
|
707
|
+
await ownSchema(connection, schema, created);
|
|
708
|
+
await connection.execute(`grant select, insert, update on okm_meta, okm_history, okm_backfill to ${quoteIdent2(created)}`);
|
|
621
709
|
}
|
|
622
710
|
}
|
|
711
|
+
if (migrationRole !== undefined && session.setRole !== migrationRole && await roleExists(connection, migrationRole)) {
|
|
712
|
+
await flush();
|
|
713
|
+
await assumeRole(connection, migrationRole, session);
|
|
714
|
+
}
|
|
623
715
|
await flush();
|
|
624
716
|
for (const sql of referenceInserts(reference, schema)) {
|
|
625
717
|
if (!began) {
|
|
@@ -754,4 +846,4 @@ function normaliseFunction(object) {
|
|
|
754
846
|
};
|
|
755
847
|
}
|
|
756
848
|
|
|
757
|
-
export { runTarget, assumeRole, grantAppMeta, grantSchema, assertSchemaUsageLanded, statementOutsideTransaction, readReference, referenceInserts, catalogsEqual, provisionMark, expandProvisioned, provisionHistoryIsKnown, installSnapshot, snapshotDifference };
|
|
849
|
+
export { runTarget, assumeRole, grantAppMeta, grantSchema, ownSchema, assertSchemaUsageLanded, statementOutsideTransaction, readReference, referenceInserts, catalogsEqual, provisionMark, expandProvisioned, provisionHistoryIsKnown, installSnapshot, snapshotDifference };
|