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
|
@@ -2,29 +2,35 @@ import {
|
|
|
2
2
|
creationOrder2,
|
|
3
3
|
renameColumn2,
|
|
4
4
|
renameTable2
|
|
5
|
-
} from "./
|
|
5
|
+
} from "./qq3899ht.js";
|
|
6
|
+
import {
|
|
7
|
+
isConnectionLost
|
|
8
|
+
} from "./gwn6v667.js";
|
|
6
9
|
import {
|
|
7
10
|
quoteIdent,
|
|
11
|
+
uniqueBeforeForeignKey,
|
|
8
12
|
ownedByView,
|
|
9
13
|
dropObjectSql,
|
|
10
14
|
createObjectSql,
|
|
11
15
|
functionSql,
|
|
12
16
|
viewSql,
|
|
17
|
+
policyCreatePlan,
|
|
18
|
+
policyDropPlan,
|
|
13
19
|
refreshMaterializedViewSql,
|
|
14
20
|
alterColumnSql,
|
|
15
21
|
identitySequence,
|
|
16
22
|
createTableSql,
|
|
17
23
|
qualify
|
|
18
|
-
} from "./
|
|
24
|
+
} from "./9s0ypp87.js";
|
|
19
25
|
import {
|
|
20
26
|
isExactVersion,
|
|
21
27
|
compareExtensionVersions,
|
|
22
28
|
sameExtensionDefinition
|
|
23
|
-
} from "./
|
|
29
|
+
} from "./r3j8s5y0.js";
|
|
24
30
|
import {
|
|
25
31
|
isDomain,
|
|
26
32
|
sameEnumLabels
|
|
27
|
-
} from "./
|
|
33
|
+
} from "./ywspezzx.js";
|
|
28
34
|
import {
|
|
29
35
|
quoteLiteral
|
|
30
36
|
} from "./94ez8kzh.js";
|
|
@@ -33,7 +39,7 @@ import {
|
|
|
33
39
|
identityKey2,
|
|
34
40
|
identityLabel2,
|
|
35
41
|
compareText
|
|
36
|
-
} from "./
|
|
42
|
+
} from "./358zsv4r.js";
|
|
37
43
|
import {
|
|
38
44
|
fitIdentifier2
|
|
39
45
|
} from "./nfzc5z0w.js";
|
|
@@ -41,6 +47,332 @@ import {
|
|
|
41
47
|
OkmError2
|
|
42
48
|
} from "./52szzakm.js";
|
|
43
49
|
|
|
50
|
+
// src/tooling/migrate/sql-lex.ts
|
|
51
|
+
function sqlStatements(sql) {
|
|
52
|
+
return scan(sql).statements;
|
|
53
|
+
}
|
|
54
|
+
function sqlQuoteOpen(sql) {
|
|
55
|
+
return scan(sql).open;
|
|
56
|
+
}
|
|
57
|
+
function scan(sql) {
|
|
58
|
+
const statements = [];
|
|
59
|
+
const parts = [];
|
|
60
|
+
let index = 0;
|
|
61
|
+
let open = false;
|
|
62
|
+
let atomic = 0;
|
|
63
|
+
const flush = () => {
|
|
64
|
+
const text = parts.join("").trim();
|
|
65
|
+
parts.length = 0;
|
|
66
|
+
if (text.length > 0)
|
|
67
|
+
statements.push(text);
|
|
68
|
+
};
|
|
69
|
+
while (index < sql.length) {
|
|
70
|
+
if (sql.startsWith("--", index)) {
|
|
71
|
+
parts.push(" ");
|
|
72
|
+
index = lineCommentEnd(sql, index + 2);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (sql.startsWith("/*", index)) {
|
|
76
|
+
parts.push(" ");
|
|
77
|
+
const block = blockComment(sql, index + 2);
|
|
78
|
+
index = block.index;
|
|
79
|
+
if (block.open) {
|
|
80
|
+
open = true;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const dollar = dollarAt(sql, index);
|
|
86
|
+
if (dollar !== undefined) {
|
|
87
|
+
const closed = takeDollar(sql, dollar);
|
|
88
|
+
parts.push(sql.slice(index, closed.index));
|
|
89
|
+
index = closed.index;
|
|
90
|
+
if (closed.open) {
|
|
91
|
+
open = true;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (isEscapeString(sql, index)) {
|
|
97
|
+
const quote = takeQuoted(sql, index + 2, true);
|
|
98
|
+
parts.push(sql.slice(index, quote.index));
|
|
99
|
+
index = quote.index;
|
|
100
|
+
if (quote.open) {
|
|
101
|
+
open = true;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const char = sql[index];
|
|
107
|
+
if (char === "'") {
|
|
108
|
+
const quote = takeQuoted(sql, index + 1, false);
|
|
109
|
+
parts.push(sql.slice(index, quote.index));
|
|
110
|
+
index = quote.index;
|
|
111
|
+
if (quote.open) {
|
|
112
|
+
open = true;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (char === '"') {
|
|
118
|
+
const quote = takeIdent(sql, index + 1);
|
|
119
|
+
parts.push(sql.slice(index, quote.index));
|
|
120
|
+
index = quote.index;
|
|
121
|
+
if (quote.open) {
|
|
122
|
+
open = true;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (char === ";") {
|
|
128
|
+
if (atomic === 0)
|
|
129
|
+
flush();
|
|
130
|
+
else
|
|
131
|
+
parts.push(";");
|
|
132
|
+
index += 1;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (isIdentStart(sql.charCodeAt(index))) {
|
|
136
|
+
const word = readWord(sql, index);
|
|
137
|
+
const lower = word.toLowerCase();
|
|
138
|
+
if (atomic > 0 && lower === "case")
|
|
139
|
+
atomic += 1;
|
|
140
|
+
else if (atomic > 0 && lower === "end")
|
|
141
|
+
atomic -= 1;
|
|
142
|
+
else if (lower === "begin" && nextWordIs(sql, index + word.length, "atomic")) {
|
|
143
|
+
if (atomic > 0 || isRoutineHead(parts.join("")))
|
|
144
|
+
atomic += 1;
|
|
145
|
+
}
|
|
146
|
+
parts.push(word);
|
|
147
|
+
index += word.length;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
parts.push(char ?? "");
|
|
151
|
+
index += 1;
|
|
152
|
+
}
|
|
153
|
+
flush();
|
|
154
|
+
return { statements, open: open || atomic > 0 };
|
|
155
|
+
}
|
|
156
|
+
function transactionControl(sql) {
|
|
157
|
+
for (const statement of sqlStatements(sql)) {
|
|
158
|
+
const top = controlWord(statement, false);
|
|
159
|
+
if (top !== undefined)
|
|
160
|
+
return top;
|
|
161
|
+
if (!isDo(statement))
|
|
162
|
+
continue;
|
|
163
|
+
for (const body of dollarBodies(statement)) {
|
|
164
|
+
for (const inner of sqlStatements(body)) {
|
|
165
|
+
const hit = controlWord(inner, true);
|
|
166
|
+
if (hit !== undefined)
|
|
167
|
+
return hit;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
function isDo(statement) {
|
|
174
|
+
return /^do(?:\s|$)/i.test(statement.trim());
|
|
175
|
+
}
|
|
176
|
+
function controlWord(statement, insideBody) {
|
|
177
|
+
let text = statement.trim().replace(/\s+/g, " ").toLowerCase();
|
|
178
|
+
if (insideBody && /^begin(?:\s|$)/.test(text) && !/^begin\s+(?:work|transaction)\b/.test(text)) {
|
|
179
|
+
text = text.replace(/^begin\s+/, "").trim();
|
|
180
|
+
if (text.length === 0)
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (/^commit(?:\s+(?:work|transaction|prepared\b.*))?$/.test(text))
|
|
184
|
+
return "commit";
|
|
185
|
+
if (text === "abort")
|
|
186
|
+
return "abort";
|
|
187
|
+
if (/^rollback(?:\s+(?:work|transaction|prepared\b.*))?$/.test(text))
|
|
188
|
+
return "rollback";
|
|
189
|
+
if (/^prepare\s+transaction\b/.test(text))
|
|
190
|
+
return "prepare transaction";
|
|
191
|
+
if (/^start\s+transaction\b/.test(text))
|
|
192
|
+
return "start transaction";
|
|
193
|
+
if (/^begin(?:\s+(?:work|transaction)\b.*)?$/.test(text) || /^begin\s+\S/.test(text)) {
|
|
194
|
+
if (insideBody && !/^begin\s+(?:work|transaction)\b/.test(text))
|
|
195
|
+
return;
|
|
196
|
+
return "begin";
|
|
197
|
+
}
|
|
198
|
+
if (/^end(?:\s+(?:work|transaction))?$/.test(text)) {
|
|
199
|
+
if (insideBody && text === "end")
|
|
200
|
+
return;
|
|
201
|
+
return "end";
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
function dollarBodies(sql) {
|
|
206
|
+
const bodies = [];
|
|
207
|
+
let index = 0;
|
|
208
|
+
while (index < sql.length) {
|
|
209
|
+
if (sql.startsWith("--", index)) {
|
|
210
|
+
index = lineCommentEnd(sql, index + 2);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (sql.startsWith("/*", index)) {
|
|
214
|
+
index = blockComment(sql, index + 2).index;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (isEscapeString(sql, index)) {
|
|
218
|
+
index = takeQuoted(sql, index + 2, true).index;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (sql[index] === "'") {
|
|
222
|
+
index = takeQuoted(sql, index + 1, false).index;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (sql[index] === '"') {
|
|
226
|
+
index = takeIdent(sql, index + 1).index;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const dollar = dollarAt(sql, index);
|
|
230
|
+
if (dollar !== undefined) {
|
|
231
|
+
const closed = takeDollar(sql, dollar);
|
|
232
|
+
if (!closed.open) {
|
|
233
|
+
const closer = `$${dollar.tag}$`.length;
|
|
234
|
+
bodies.push(sql.slice(dollar.end, closed.index - closer));
|
|
235
|
+
}
|
|
236
|
+
index = closed.index;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
index += 1;
|
|
240
|
+
}
|
|
241
|
+
return bodies;
|
|
242
|
+
}
|
|
243
|
+
function readWord(sql, index) {
|
|
244
|
+
let cursor = index + 1;
|
|
245
|
+
while (isIdentCont(sql.charCodeAt(cursor)))
|
|
246
|
+
cursor += 1;
|
|
247
|
+
return sql.slice(index, cursor);
|
|
248
|
+
}
|
|
249
|
+
function nextWordIs(sql, index, expected) {
|
|
250
|
+
const at = skipTrivia(sql, index);
|
|
251
|
+
if (!isIdentStart(sql.charCodeAt(at)))
|
|
252
|
+
return false;
|
|
253
|
+
return readWord(sql, at).toLowerCase() === expected;
|
|
254
|
+
}
|
|
255
|
+
function skipTrivia(sql, index) {
|
|
256
|
+
while (index < sql.length) {
|
|
257
|
+
const code = sql.charCodeAt(index);
|
|
258
|
+
if (code === 32 || code === 9 || code === 10 || code === 13) {
|
|
259
|
+
index += 1;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (sql.startsWith("--", index)) {
|
|
263
|
+
index = lineCommentEnd(sql, index + 2);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (sql.startsWith("/*", index)) {
|
|
267
|
+
const block = blockComment(sql, index + 2);
|
|
268
|
+
if (block.open)
|
|
269
|
+
return sql.length;
|
|
270
|
+
index = block.index;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
return index;
|
|
274
|
+
}
|
|
275
|
+
return index;
|
|
276
|
+
}
|
|
277
|
+
function isRoutineHead(text) {
|
|
278
|
+
return /^create(?:\s+or\s+replace)?\s+(?:function|procedure)\b/i.test(text.replace(/\s+/g, " ").trim());
|
|
279
|
+
}
|
|
280
|
+
function lineCommentEnd(sql, index) {
|
|
281
|
+
while (index < sql.length && sql.charCodeAt(index) !== 10)
|
|
282
|
+
index += 1;
|
|
283
|
+
return index;
|
|
284
|
+
}
|
|
285
|
+
function blockComment(sql, index) {
|
|
286
|
+
let depth = 1;
|
|
287
|
+
while (index < sql.length) {
|
|
288
|
+
if (sql.startsWith("/*", index)) {
|
|
289
|
+
depth += 1;
|
|
290
|
+
index += 2;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (sql.startsWith("*/", index)) {
|
|
294
|
+
depth -= 1;
|
|
295
|
+
index += 2;
|
|
296
|
+
if (depth === 0)
|
|
297
|
+
return { index, open: false };
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
index += 1;
|
|
301
|
+
}
|
|
302
|
+
return { index, open: true };
|
|
303
|
+
}
|
|
304
|
+
function dollarAt(sql, index) {
|
|
305
|
+
if (sql.charCodeAt(index) !== 36)
|
|
306
|
+
return;
|
|
307
|
+
const next = index + 1;
|
|
308
|
+
if (sql.charCodeAt(next) === 36)
|
|
309
|
+
return { tag: "", end: next + 1 };
|
|
310
|
+
if (!isIdentStart(sql.charCodeAt(next)))
|
|
311
|
+
return;
|
|
312
|
+
let cursor = next + 1;
|
|
313
|
+
while (isIdentCont(sql.charCodeAt(cursor)))
|
|
314
|
+
cursor += 1;
|
|
315
|
+
if (sql.charCodeAt(cursor) !== 36)
|
|
316
|
+
return;
|
|
317
|
+
return { tag: sql.slice(next, cursor), end: cursor + 1 };
|
|
318
|
+
}
|
|
319
|
+
function takeDollar(sql, dollar) {
|
|
320
|
+
const closer = `$${dollar.tag}$`;
|
|
321
|
+
const found = sql.indexOf(closer, dollar.end);
|
|
322
|
+
if (found === -1)
|
|
323
|
+
return { index: sql.length, open: true };
|
|
324
|
+
return { index: found + closer.length, open: false };
|
|
325
|
+
}
|
|
326
|
+
function takeQuoted(sql, index, escape) {
|
|
327
|
+
while (index < sql.length) {
|
|
328
|
+
const char = sql[index];
|
|
329
|
+
if (escape && char === "\\") {
|
|
330
|
+
if (index + 1 >= sql.length)
|
|
331
|
+
return { index: sql.length, open: true };
|
|
332
|
+
index += 2;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (char === "'") {
|
|
336
|
+
if (sql[index + 1] === "'") {
|
|
337
|
+
index += 2;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
return { index: index + 1, open: false };
|
|
341
|
+
}
|
|
342
|
+
index += 1;
|
|
343
|
+
}
|
|
344
|
+
return { index, open: true };
|
|
345
|
+
}
|
|
346
|
+
function takeIdent(sql, index) {
|
|
347
|
+
while (index < sql.length) {
|
|
348
|
+
if (sql[index] === '"') {
|
|
349
|
+
if (sql[index + 1] === '"') {
|
|
350
|
+
index += 2;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
return { index: index + 1, open: false };
|
|
354
|
+
}
|
|
355
|
+
index += 1;
|
|
356
|
+
}
|
|
357
|
+
return { index, open: true };
|
|
358
|
+
}
|
|
359
|
+
function isEscapeString(sql, index) {
|
|
360
|
+
const code = sql.charCodeAt(index);
|
|
361
|
+
if (code !== 69 && code !== 101)
|
|
362
|
+
return false;
|
|
363
|
+
if (sql.charCodeAt(index + 1) !== 39)
|
|
364
|
+
return false;
|
|
365
|
+
if (index > 0 && isIdentCont(sql.charCodeAt(index - 1)))
|
|
366
|
+
return false;
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
function isIdentStart(code) {
|
|
370
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95;
|
|
371
|
+
}
|
|
372
|
+
function isIdentCont(code) {
|
|
373
|
+
return isIdentStart(code) || code >= 48 && code <= 57;
|
|
374
|
+
}
|
|
375
|
+
|
|
44
376
|
// src/tooling/migrate/type-name.ts
|
|
45
377
|
function canonicalTypeName(typeName) {
|
|
46
378
|
const suffix = arraySuffix(typeName);
|
|
@@ -108,6 +440,10 @@ function canonicalTime(name, precision) {
|
|
|
108
440
|
|
|
109
441
|
// src/dialects/pg/role/sql.ts
|
|
110
442
|
var PRIVILEGE = /^(select|insert|update|delete|execute|usage)$/;
|
|
443
|
+
var COLUMN_PRIVILEGE = /^(select|update)\(([^)]*)\)$/i;
|
|
444
|
+
function columnPrivilege(name, columns) {
|
|
445
|
+
return `${name.toUpperCase()}(${[...columns].sort().join(",")})`;
|
|
446
|
+
}
|
|
111
447
|
function privilegeSql(before, after, schema, recreated = new Set) {
|
|
112
448
|
const beforeBy = index(before);
|
|
113
449
|
const afterBy = index(after);
|
|
@@ -145,7 +481,13 @@ function privilegeSql(before, after, schema, recreated = new Set) {
|
|
|
145
481
|
const target = grantTargetKey(object.identity.object);
|
|
146
482
|
if (previous !== undefined && (target === undefined || !recreated.has(target)))
|
|
147
483
|
continue;
|
|
484
|
+
const tighten = tightenColumnSelect(object, after, schema);
|
|
485
|
+
if (tighten !== undefined)
|
|
486
|
+
grant.push(tighten);
|
|
148
487
|
grant.push({ sql: grantStatement(object, schema, false), kind: "grant" });
|
|
488
|
+
const writes = revokeMatviewWrites(object, after, schema);
|
|
489
|
+
if (writes !== undefined)
|
|
490
|
+
grant.push(writes);
|
|
149
491
|
continue;
|
|
150
492
|
}
|
|
151
493
|
if (previous !== undefined)
|
|
@@ -191,12 +533,48 @@ function login(object) {
|
|
|
191
533
|
function inherit(object) {
|
|
192
534
|
return object.definition.inherit ? "inherit" : "noinherit";
|
|
193
535
|
}
|
|
536
|
+
function tightenColumnSelect(object, after, schema) {
|
|
537
|
+
if (!/^select\([^)]*\)$/.test(object.identity.privilege.toLowerCase()))
|
|
538
|
+
return;
|
|
539
|
+
const target = object.identity.object;
|
|
540
|
+
const covered = after.some((item) => item.kind === "grant" && item.identity.role === object.identity.role && item.identity.privilege.toUpperCase() === "SELECT" && item.identity.object.kind === target.kind && item.identity.object.name === target.name);
|
|
541
|
+
if (covered)
|
|
542
|
+
return;
|
|
543
|
+
return {
|
|
544
|
+
sql: `revoke select on ${grantTarget(target, schema)} from ${quoteIdent(object.identity.role)}`,
|
|
545
|
+
kind: "revoke"
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function revokeMatviewWrites(object, after, schema) {
|
|
549
|
+
if (object.identity.privilege.toUpperCase() !== "SELECT")
|
|
550
|
+
return;
|
|
551
|
+
const target = object.identity.object;
|
|
552
|
+
if (target.kind !== "materializedView")
|
|
553
|
+
return;
|
|
554
|
+
const inheritsWrites = after.some((item) => item.kind === "defaultPrivilege" && item.identity.grantee === object.identity.role && item.identity.objectKind === "table" && (item.identity.privilege === "INSERT" || item.identity.privilege === "UPDATE" || item.identity.privilege === "DELETE"));
|
|
555
|
+
if (!inheritsWrites)
|
|
556
|
+
return;
|
|
557
|
+
return {
|
|
558
|
+
sql: `revoke insert, update, delete on ${grantTarget(target, schema)} from ${quoteIdent(object.identity.role)}`,
|
|
559
|
+
kind: "revoke"
|
|
560
|
+
};
|
|
561
|
+
}
|
|
194
562
|
function grantStatement(object, schema, revoke) {
|
|
195
|
-
const privilege = object.identity.privilege
|
|
196
|
-
|
|
563
|
+
const privilege = object.identity.privilege;
|
|
564
|
+
const column = COLUMN_PRIVILEGE.exec(privilege);
|
|
197
565
|
const verb = revoke ? "revoke" : "grant";
|
|
198
566
|
const direction = revoke ? "from" : "to";
|
|
199
|
-
|
|
567
|
+
const target = grantTarget(object.identity.object, schema);
|
|
568
|
+
const role = quoteIdent(object.identity.role);
|
|
569
|
+
const listed = column?.[2];
|
|
570
|
+
const base = column?.[1];
|
|
571
|
+
if (listed !== undefined && base !== undefined) {
|
|
572
|
+
const names = listed.split(",").filter((name) => name.length > 0).map((name) => quoteIdent(name)).join(", ");
|
|
573
|
+
return `${verb} ${base.toLowerCase()} (${names}) on ${target} ${direction} ${role}`;
|
|
574
|
+
}
|
|
575
|
+
const keyword = privilege.toLowerCase();
|
|
576
|
+
assertPrivilege(keyword);
|
|
577
|
+
return `${verb} ${keyword} on ${target} ${direction} ${role}`;
|
|
200
578
|
}
|
|
201
579
|
function defaultStatement(object, schema, revoke) {
|
|
202
580
|
const privilege = object.identity.privilege.toLowerCase();
|
|
@@ -229,7 +607,7 @@ function grantTarget(object, schema) {
|
|
|
229
607
|
if (object.kind === "function")
|
|
230
608
|
return functionTarget(object.name, schema);
|
|
231
609
|
if (object.kind === "namespace")
|
|
232
|
-
return `schema ${quoteIdent(
|
|
610
|
+
return `schema ${quoteIdent(schema)}`;
|
|
233
611
|
return `table ${qualify(schema, object.name)}`;
|
|
234
612
|
}
|
|
235
613
|
function functionTarget(name, schema) {
|
|
@@ -481,6 +859,10 @@ var STEP_CLASS = {
|
|
|
481
859
|
"rename-sequence": "contract",
|
|
482
860
|
"backfill-expand": "expand",
|
|
483
861
|
"backfill-contract": "contract",
|
|
862
|
+
"enable-rls": "expand",
|
|
863
|
+
"create-policy": "expand",
|
|
864
|
+
"drop-policy": "contract",
|
|
865
|
+
"disable-rls": "contract",
|
|
484
866
|
"raw-sql": "unclassified"
|
|
485
867
|
};
|
|
486
868
|
var STEP_KINDS = Object.keys(STEP_CLASS);
|
|
@@ -690,6 +1072,43 @@ function managedSequence(name) {
|
|
|
690
1072
|
return name === "okm_meta" || name === "okm_history" || name === "okm_backfill" || name.startsWith("okm_meta_") || name.startsWith("okm_history_") || name.startsWith("okm_backfill_");
|
|
691
1073
|
}
|
|
692
1074
|
|
|
1075
|
+
// src/tooling/migrate/text.ts
|
|
1076
|
+
var FIX = {
|
|
1077
|
+
"no-steps": "Add -- no steps when the migration is intentionally empty. Otherwise the file needs a statement okm can read.",
|
|
1078
|
+
utf16: "Save the file as UTF-8. okm does not read UTF-16."
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
class MigrationTextError extends OkmError2 {
|
|
1082
|
+
reason;
|
|
1083
|
+
constructor(reason, message) {
|
|
1084
|
+
super("invalid", message, {
|
|
1085
|
+
kind: "invalid",
|
|
1086
|
+
fieldReason: reason,
|
|
1087
|
+
fix: { summary: FIX[reason] }
|
|
1088
|
+
});
|
|
1089
|
+
this.name = "OkmError";
|
|
1090
|
+
this.reason = reason;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
function prepareMigrationText(text, label = "Migration SQL") {
|
|
1094
|
+
if (text.includes("\x00")) {
|
|
1095
|
+
throw new MigrationTextError("utf16", `${label} is UTF-16. Save the file as UTF-8.`);
|
|
1096
|
+
}
|
|
1097
|
+
const withoutBom = text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
1098
|
+
return withoutBom.replaceAll(`\r
|
|
1099
|
+
`, `
|
|
1100
|
+
`).replaceAll("\r", `
|
|
1101
|
+
`);
|
|
1102
|
+
}
|
|
1103
|
+
function assertMigrationSteps(text, stepCount, label) {
|
|
1104
|
+
if (stepCount > 0 || text.trim().length === 0)
|
|
1105
|
+
return;
|
|
1106
|
+
if (text.split(`
|
|
1107
|
+
`).includes("-- no steps"))
|
|
1108
|
+
return;
|
|
1109
|
+
throw new MigrationTextError("no-steps", `${label} has text but no steps. okm did not apply it.`);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
693
1112
|
// src/tooling/migrate/safe.ts
|
|
694
1113
|
var ACCESS = "ACCESS EXCLUSIVE";
|
|
695
1114
|
var SHARE_UPDATE = "SHARE UPDATE EXCLUSIVE";
|
|
@@ -976,189 +1395,6 @@ function functionCalls(expression) {
|
|
|
976
1395
|
return names;
|
|
977
1396
|
}
|
|
978
1397
|
|
|
979
|
-
// src/tooling/migrate/sql-lex.ts
|
|
980
|
-
function sqlStatements(sql) {
|
|
981
|
-
return scan(sql).statements;
|
|
982
|
-
}
|
|
983
|
-
function sqlQuoteOpen(sql) {
|
|
984
|
-
return scan(sql).open;
|
|
985
|
-
}
|
|
986
|
-
function scan(sql) {
|
|
987
|
-
const statements = [];
|
|
988
|
-
const parts = [];
|
|
989
|
-
let index = 0;
|
|
990
|
-
let open = false;
|
|
991
|
-
const flush = () => {
|
|
992
|
-
const text = parts.join("").trim();
|
|
993
|
-
parts.length = 0;
|
|
994
|
-
if (text.length > 0)
|
|
995
|
-
statements.push(text);
|
|
996
|
-
};
|
|
997
|
-
while (index < sql.length) {
|
|
998
|
-
if (sql.startsWith("--", index)) {
|
|
999
|
-
parts.push(" ");
|
|
1000
|
-
index = lineCommentEnd(sql, index + 2);
|
|
1001
|
-
continue;
|
|
1002
|
-
}
|
|
1003
|
-
if (sql.startsWith("/*", index)) {
|
|
1004
|
-
parts.push(" ");
|
|
1005
|
-
const block = blockComment(sql, index + 2);
|
|
1006
|
-
index = block.index;
|
|
1007
|
-
if (block.open) {
|
|
1008
|
-
open = true;
|
|
1009
|
-
break;
|
|
1010
|
-
}
|
|
1011
|
-
continue;
|
|
1012
|
-
}
|
|
1013
|
-
const dollar = dollarAt(sql, index);
|
|
1014
|
-
if (dollar !== undefined) {
|
|
1015
|
-
const closed = takeDollar(sql, dollar);
|
|
1016
|
-
parts.push(sql.slice(index, closed.index));
|
|
1017
|
-
index = closed.index;
|
|
1018
|
-
if (closed.open) {
|
|
1019
|
-
open = true;
|
|
1020
|
-
break;
|
|
1021
|
-
}
|
|
1022
|
-
continue;
|
|
1023
|
-
}
|
|
1024
|
-
if (isEscapeString(sql, index)) {
|
|
1025
|
-
const quote = takeQuoted(sql, index + 2, true);
|
|
1026
|
-
parts.push(sql.slice(index, quote.index));
|
|
1027
|
-
index = quote.index;
|
|
1028
|
-
if (quote.open) {
|
|
1029
|
-
open = true;
|
|
1030
|
-
break;
|
|
1031
|
-
}
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
const char = sql[index];
|
|
1035
|
-
if (char === "'") {
|
|
1036
|
-
const quote = takeQuoted(sql, index + 1, false);
|
|
1037
|
-
parts.push(sql.slice(index, quote.index));
|
|
1038
|
-
index = quote.index;
|
|
1039
|
-
if (quote.open) {
|
|
1040
|
-
open = true;
|
|
1041
|
-
break;
|
|
1042
|
-
}
|
|
1043
|
-
continue;
|
|
1044
|
-
}
|
|
1045
|
-
if (char === '"') {
|
|
1046
|
-
const quote = takeIdent(sql, index + 1);
|
|
1047
|
-
parts.push(sql.slice(index, quote.index));
|
|
1048
|
-
index = quote.index;
|
|
1049
|
-
if (quote.open) {
|
|
1050
|
-
open = true;
|
|
1051
|
-
break;
|
|
1052
|
-
}
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (char === ";") {
|
|
1056
|
-
flush();
|
|
1057
|
-
index += 1;
|
|
1058
|
-
continue;
|
|
1059
|
-
}
|
|
1060
|
-
parts.push(char ?? "");
|
|
1061
|
-
index += 1;
|
|
1062
|
-
}
|
|
1063
|
-
flush();
|
|
1064
|
-
return { statements, open };
|
|
1065
|
-
}
|
|
1066
|
-
function lineCommentEnd(sql, index) {
|
|
1067
|
-
while (index < sql.length && sql.charCodeAt(index) !== 10)
|
|
1068
|
-
index += 1;
|
|
1069
|
-
return index;
|
|
1070
|
-
}
|
|
1071
|
-
function blockComment(sql, index) {
|
|
1072
|
-
let depth = 1;
|
|
1073
|
-
while (index < sql.length) {
|
|
1074
|
-
if (sql.startsWith("/*", index)) {
|
|
1075
|
-
depth += 1;
|
|
1076
|
-
index += 2;
|
|
1077
|
-
continue;
|
|
1078
|
-
}
|
|
1079
|
-
if (sql.startsWith("*/", index)) {
|
|
1080
|
-
depth -= 1;
|
|
1081
|
-
index += 2;
|
|
1082
|
-
if (depth === 0)
|
|
1083
|
-
return { index, open: false };
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
|
-
index += 1;
|
|
1087
|
-
}
|
|
1088
|
-
return { index, open: true };
|
|
1089
|
-
}
|
|
1090
|
-
function dollarAt(sql, index) {
|
|
1091
|
-
if (sql.charCodeAt(index) !== 36)
|
|
1092
|
-
return;
|
|
1093
|
-
const next = index + 1;
|
|
1094
|
-
if (sql.charCodeAt(next) === 36)
|
|
1095
|
-
return { tag: "", end: next + 1 };
|
|
1096
|
-
if (!isIdentStart(sql.charCodeAt(next)))
|
|
1097
|
-
return;
|
|
1098
|
-
let cursor = next + 1;
|
|
1099
|
-
while (isIdentCont(sql.charCodeAt(cursor)))
|
|
1100
|
-
cursor += 1;
|
|
1101
|
-
if (sql.charCodeAt(cursor) !== 36)
|
|
1102
|
-
return;
|
|
1103
|
-
return { tag: sql.slice(next, cursor), end: cursor + 1 };
|
|
1104
|
-
}
|
|
1105
|
-
function takeDollar(sql, dollar) {
|
|
1106
|
-
const closer = `$${dollar.tag}$`;
|
|
1107
|
-
const found = sql.indexOf(closer, dollar.end);
|
|
1108
|
-
if (found === -1)
|
|
1109
|
-
return { index: sql.length, open: true };
|
|
1110
|
-
return { index: found + closer.length, open: false };
|
|
1111
|
-
}
|
|
1112
|
-
function takeQuoted(sql, index, escape) {
|
|
1113
|
-
while (index < sql.length) {
|
|
1114
|
-
const char = sql[index];
|
|
1115
|
-
if (escape && char === "\\") {
|
|
1116
|
-
if (index + 1 >= sql.length)
|
|
1117
|
-
return { index: sql.length, open: true };
|
|
1118
|
-
index += 2;
|
|
1119
|
-
continue;
|
|
1120
|
-
}
|
|
1121
|
-
if (char === "'") {
|
|
1122
|
-
if (sql[index + 1] === "'") {
|
|
1123
|
-
index += 2;
|
|
1124
|
-
continue;
|
|
1125
|
-
}
|
|
1126
|
-
return { index: index + 1, open: false };
|
|
1127
|
-
}
|
|
1128
|
-
index += 1;
|
|
1129
|
-
}
|
|
1130
|
-
return { index, open: true };
|
|
1131
|
-
}
|
|
1132
|
-
function takeIdent(sql, index) {
|
|
1133
|
-
while (index < sql.length) {
|
|
1134
|
-
if (sql[index] === '"') {
|
|
1135
|
-
if (sql[index + 1] === '"') {
|
|
1136
|
-
index += 2;
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
return { index: index + 1, open: false };
|
|
1140
|
-
}
|
|
1141
|
-
index += 1;
|
|
1142
|
-
}
|
|
1143
|
-
return { index, open: true };
|
|
1144
|
-
}
|
|
1145
|
-
function isEscapeString(sql, index) {
|
|
1146
|
-
const code = sql.charCodeAt(index);
|
|
1147
|
-
if (code !== 69 && code !== 101)
|
|
1148
|
-
return false;
|
|
1149
|
-
if (sql.charCodeAt(index + 1) !== 39)
|
|
1150
|
-
return false;
|
|
1151
|
-
if (index > 0 && isIdentCont(sql.charCodeAt(index - 1)))
|
|
1152
|
-
return false;
|
|
1153
|
-
return true;
|
|
1154
|
-
}
|
|
1155
|
-
function isIdentStart(code) {
|
|
1156
|
-
return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95;
|
|
1157
|
-
}
|
|
1158
|
-
function isIdentCont(code) {
|
|
1159
|
-
return isIdentStart(code) || code >= 48 && code <= 57;
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
1398
|
// src/tooling/migrate/values.ts
|
|
1163
1399
|
function parseReplace(flag) {
|
|
1164
1400
|
const eq = flag.indexOf("=");
|
|
@@ -1230,17 +1466,24 @@ function planMigration(input) {
|
|
|
1230
1466
|
if (!afterBy.has(item.key)) {
|
|
1231
1467
|
if (item.object.kind === "role")
|
|
1232
1468
|
continue;
|
|
1469
|
+
if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
|
|
1470
|
+
continue;
|
|
1233
1471
|
dropKeys.add(item.key);
|
|
1234
1472
|
}
|
|
1235
1473
|
}
|
|
1236
1474
|
for (const item of afterList) {
|
|
1237
|
-
if (!beforeBy.has(item.key))
|
|
1475
|
+
if (!beforeBy.has(item.key)) {
|
|
1476
|
+
if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
|
|
1477
|
+
continue;
|
|
1238
1478
|
createKeys.add(item.key);
|
|
1479
|
+
}
|
|
1239
1480
|
}
|
|
1240
1481
|
for (const item of afterList) {
|
|
1241
1482
|
const previous = beforeBy.get(item.key);
|
|
1242
1483
|
if (previous === undefined || sameDefinition(previous, item.object))
|
|
1243
1484
|
continue;
|
|
1485
|
+
if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
|
|
1486
|
+
continue;
|
|
1244
1487
|
if (previous.kind === "extension" && item.object.kind === "extension")
|
|
1245
1488
|
continue;
|
|
1246
1489
|
if (previous.kind === "role" && item.object.kind === "role")
|
|
@@ -1276,6 +1519,8 @@ function planMigration(input) {
|
|
|
1276
1519
|
refuseRoutineDrops(beforeBy, afterBy, dropKeys);
|
|
1277
1520
|
omitOwnedSequences(createKeys, afterBy, request.after);
|
|
1278
1521
|
omitOwnedSequences(dropKeys, beforeBy, renamed);
|
|
1522
|
+
releaseHandsOff(dropKeys, beforeBy, afterBy);
|
|
1523
|
+
releaseHandsOff(createKeys, afterBy, afterBy);
|
|
1279
1524
|
const recreated = new Set;
|
|
1280
1525
|
for (const key of createKeys) {
|
|
1281
1526
|
if (dropKeys.has(key))
|
|
@@ -1294,7 +1539,7 @@ function planMigration(input) {
|
|
|
1294
1539
|
const deferred = new Set(picklists.map((change) => identityKey2(change.before.identity)));
|
|
1295
1540
|
const typeDrops = [];
|
|
1296
1541
|
const extensionDrops = [];
|
|
1297
|
-
const reverse = [...creationOrder2(renamed)].reverse();
|
|
1542
|
+
const reverse = [...uniqueBeforeForeignKey(creationOrder2(renamed))].reverse();
|
|
1298
1543
|
const emitDrop = (object) => {
|
|
1299
1544
|
const key = identityKey2(object.identity);
|
|
1300
1545
|
if (!dropKeys.has(key) || deferred.has(key) || covered(object, droppedTables))
|
|
@@ -1328,7 +1573,17 @@ function planMigration(input) {
|
|
|
1328
1573
|
emitDrop(object);
|
|
1329
1574
|
}
|
|
1330
1575
|
for (const object of reverse) {
|
|
1331
|
-
if (object.kind
|
|
1576
|
+
if (object.kind !== "policy")
|
|
1577
|
+
continue;
|
|
1578
|
+
const key = identityKey2(object.identity);
|
|
1579
|
+
if (!dropKeys.has(key) || deferred.has(key))
|
|
1580
|
+
continue;
|
|
1581
|
+
for (const item of policyDropPlan(object, schema)) {
|
|
1582
|
+
steps.push(step(item.sql, item.kind, "ddl", ACCESS2, true, [object.identity.parent.name]));
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
for (const object of reverse) {
|
|
1586
|
+
if (object.kind === "trigger" || object.kind === "function" || object.kind === "view" || object.kind === "materializedView" || object.kind === "policy" || ownedByView(object)) {
|
|
1332
1587
|
continue;
|
|
1333
1588
|
}
|
|
1334
1589
|
const key = identityKey2(object.identity);
|
|
@@ -1400,8 +1655,8 @@ function planMigration(input) {
|
|
|
1400
1655
|
continue;
|
|
1401
1656
|
steps.push(step(sql, kind, "ddl", ACCESS2));
|
|
1402
1657
|
}
|
|
1403
|
-
for (const object of creationOrder2(request.after)) {
|
|
1404
|
-
if (object.kind === "type" || object.kind === "extension" || object.kind === "function" || object.kind === "trigger" || object.kind === "view" || object.kind === "materializedView" || ownedByView(object)) {
|
|
1658
|
+
for (const object of uniqueBeforeForeignKey(creationOrder2(request.after))) {
|
|
1659
|
+
if (object.kind === "type" || object.kind === "extension" || object.kind === "function" || object.kind === "trigger" || object.kind === "view" || object.kind === "materializedView" || object.kind === "policy" || ownedByView(object)) {
|
|
1405
1660
|
continue;
|
|
1406
1661
|
}
|
|
1407
1662
|
const key = identityKey2(object.identity);
|
|
@@ -1432,6 +1687,17 @@ function planMigration(input) {
|
|
|
1432
1687
|
}
|
|
1433
1688
|
steps.push(step(sql, kind, "ddl", object.kind === "index" ? SHARE : ACCESS2));
|
|
1434
1689
|
}
|
|
1690
|
+
for (const object of creationOrder2(request.after)) {
|
|
1691
|
+
if (object.kind !== "policy")
|
|
1692
|
+
continue;
|
|
1693
|
+
const key = identityKey2(object.identity);
|
|
1694
|
+
if (!createKeys.has(key) || emitted.has(key))
|
|
1695
|
+
continue;
|
|
1696
|
+
emitted.add(key);
|
|
1697
|
+
for (const item of policyCreatePlan(object, schema)) {
|
|
1698
|
+
steps.push(step(item.sql, item.kind, "ddl", ACCESS2, true, [object.identity.parent.name]));
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1435
1701
|
for (const change of replaces) {
|
|
1436
1702
|
if (sameDefinition(change.before, change.after))
|
|
1437
1703
|
continue;
|
|
@@ -1528,7 +1794,7 @@ function formatPlan(plan, lockText) {
|
|
|
1528
1794
|
`);
|
|
1529
1795
|
}
|
|
1530
1796
|
function parsePlan(text) {
|
|
1531
|
-
const lines = text.split(`
|
|
1797
|
+
const lines = prepareMigrationText(text).split(`
|
|
1532
1798
|
`);
|
|
1533
1799
|
let name = "migration";
|
|
1534
1800
|
let planClass = "expand";
|
|
@@ -1752,7 +2018,7 @@ function withoutNameKey(value) {
|
|
|
1752
2018
|
}
|
|
1753
2019
|
function renameShapeStep(pair, schema) {
|
|
1754
2020
|
if (pair.from.kind === "index" && pair.to.kind === "index") {
|
|
1755
|
-
return step(`alter index ${qualify(schema, pair.from.identity.name)} rename to ${quoteIdent(pair.to.identity.name)}`, "rename-index", "ddl",
|
|
2021
|
+
return step(`alter index ${qualify(schema, pair.from.identity.name)} rename to ${quoteIdent(pair.to.identity.name)}`, "rename-index", "ddl", SHARE_UPDATE2);
|
|
1756
2022
|
}
|
|
1757
2023
|
if (pair.from.kind !== "constraint" || pair.to.kind !== "constraint") {
|
|
1758
2024
|
throw new OkmError2("invalid", "A same-shape rename is an index or a constraint.", {
|
|
@@ -2325,6 +2591,25 @@ function reprintedDefaultBase(typeName) {
|
|
|
2325
2591
|
return `${time[1] ?? ""} ${time[2] ?? ""}`;
|
|
2326
2592
|
return;
|
|
2327
2593
|
}
|
|
2594
|
+
function handsOff(object) {
|
|
2595
|
+
return object.owner === "external" || object.owner === "ignored";
|
|
2596
|
+
}
|
|
2597
|
+
function childOfHandsOff(object, catalog) {
|
|
2598
|
+
if (object.kind !== "column" && object.kind !== "index" && object.kind !== "constraint" && object.kind !== "trigger" && object.kind !== "policy") {
|
|
2599
|
+
return false;
|
|
2600
|
+
}
|
|
2601
|
+
const parent = object.identity.parent;
|
|
2602
|
+
const table = catalog.get(identityKey2({ kind: "table", namespace: parent.namespace, name: parent.name }));
|
|
2603
|
+
return table !== undefined && handsOff(table);
|
|
2604
|
+
}
|
|
2605
|
+
function releaseHandsOff(keys, objects, parents) {
|
|
2606
|
+
for (const key of keys) {
|
|
2607
|
+
const object = objects.get(key);
|
|
2608
|
+
if (object !== undefined && (handsOff(object) || childOfHandsOff(object, parents))) {
|
|
2609
|
+
keys.delete(key);
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2328
2613
|
function sameDefinition(left, right) {
|
|
2329
2614
|
if (left.kind === "materializedView" && right.kind === "materializedView") {
|
|
2330
2615
|
return stable(canonicalColumns(left.definition.columns)) === stable(canonicalColumns(right.definition.columns)) && left.definition.query === right.definition.query;
|
|
@@ -2364,6 +2649,9 @@ function forComparison(object) {
|
|
|
2364
2649
|
if (!isDomain(object.definition))
|
|
2365
2650
|
return object.definition;
|
|
2366
2651
|
return { ...object.definition, base: canonicalTypeName(object.definition.base) };
|
|
2652
|
+
case "constraint":
|
|
2653
|
+
case "index":
|
|
2654
|
+
return withoutNameKey(object.definition);
|
|
2367
2655
|
default:
|
|
2368
2656
|
return object.definition;
|
|
2369
2657
|
}
|
|
@@ -2622,6 +2910,53 @@ function order(value) {
|
|
|
2622
2910
|
return value;
|
|
2623
2911
|
}
|
|
2624
2912
|
|
|
2913
|
+
// src/tooling/migrate/lost.ts
|
|
2914
|
+
var UNAVAILABLE_FIX = {
|
|
2915
|
+
summary: "The connection to Postgres closed. Run the command again when the database is reachable."
|
|
2916
|
+
};
|
|
2917
|
+
function sessionFailure(error) {
|
|
2918
|
+
if (error instanceof OkmError2) {
|
|
2919
|
+
if (error.kind === "outcome_unknown" || error.kind === "unavailable")
|
|
2920
|
+
return error;
|
|
2921
|
+
const cause = error.cause;
|
|
2922
|
+
if (cause === undefined || cause === error || error.kind !== "invalid")
|
|
2923
|
+
return;
|
|
2924
|
+
const inner = sessionFailure(cause);
|
|
2925
|
+
if (inner === undefined)
|
|
2926
|
+
return;
|
|
2927
|
+
return new OkmError2(inner.code, error.message, {
|
|
2928
|
+
kind: inner.kind,
|
|
2929
|
+
cause: error,
|
|
2930
|
+
fix: inner.fix
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
if (isOutcomeUnknown(error)) {
|
|
2934
|
+
return new OkmError2("OKM1401", "The commit outcome is unknown. The result never arrived.", {
|
|
2935
|
+
kind: "outcome_unknown",
|
|
2936
|
+
cause: error,
|
|
2937
|
+
fix: {
|
|
2938
|
+
summary: "Check whether the write landed before retrying. This error is never retried automatically."
|
|
2939
|
+
}
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
if (!isConnectionLost(error))
|
|
2943
|
+
return;
|
|
2944
|
+
const message = error instanceof Error && error.message.length > 0 ? error.message : "The database is unavailable.";
|
|
2945
|
+
return new OkmError2("unavailable", message, {
|
|
2946
|
+
kind: "unavailable",
|
|
2947
|
+
cause: error,
|
|
2948
|
+
fix: UNAVAILABLE_FIX
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
async function finishQuiet(run) {
|
|
2952
|
+
await run().catch(() => {
|
|
2953
|
+
return;
|
|
2954
|
+
});
|
|
2955
|
+
}
|
|
2956
|
+
function isOutcomeUnknown(error) {
|
|
2957
|
+
return typeof error === "object" && error !== null && Reflect.get(error, "kind") === "outcome_unknown";
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2625
2960
|
// src/tooling/migrate/policy.ts
|
|
2626
2961
|
var READ = new Set([
|
|
2627
2962
|
"plan",
|
|
@@ -2783,4 +3118,4 @@ function endpointOf(url) {
|
|
|
2783
3118
|
};
|
|
2784
3119
|
}
|
|
2785
3120
|
|
|
2786
|
-
export { canonicalTypeName, createdRoleName, createRoleOnce, changesRole, DEFAULT_BACKFILL_PAUSE_MS, DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS, batchSizeField, aboutBatchCount, boundaryQuery, checkedCast, classOf, strictestClass, assertExtensionsAvailable, omitManagedObjects,
|
|
3121
|
+
export { sqlStatements, transactionControl, canonicalTypeName, prepareMigrationText, assertMigrationSteps, columnPrivilege, createdRoleName, createRoleOnce, changesRole, DEFAULT_BACKFILL_PAUSE_MS, DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS, batchSizeField, aboutBatchCount, boundaryQuery, checkedCast, classOf, strictestClass, assertExtensionsAvailable, omitManagedObjects, parseReplace, planMigration, formatPlan, parsePlan, staleRenames, sessionFailure, finishQuiet, assertTargetPolicy, assertTargetAlias, assertDirectConnection, assertStableBackend, listTargets, selectTarget };
|