okmodel 0.5.0 → 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.
Files changed (169) hide show
  1. package/README.md +36 -18
  2. package/dist/adapters/pg/no-inflight-timeout.d.ts +17 -0
  3. package/dist/adapters/pg/postgres-extra.d.ts +22 -0
  4. package/dist/contracts/catalog/document.d.ts +19 -5
  5. package/dist/contracts/catalog/object.d.ts +2 -1
  6. package/dist/contracts/catalog/policy.d.ts +48 -0
  7. package/dist/contracts/catalog/types.d.ts +25 -1
  8. package/dist/contracts/catalog/view.d.ts +2 -0
  9. package/dist/contracts/internal.js +1 -1
  10. package/dist/contracts/location.d.ts +10 -0
  11. package/dist/dialects/pg/column.d.ts +13 -2
  12. package/dist/dialects/pg/ddl.d.ts +37 -1
  13. package/dist/dialects/pg/emit.d.ts +19 -1
  14. package/dist/dialects/pg/errors.d.ts +32 -1
  15. package/dist/dialects/pg/ext/citext.js +1 -1
  16. package/dist/dialects/pg/ext/index.js +1 -1
  17. package/dist/dialects/pg/ext/pg-trgm.js +1 -1
  18. package/dist/dialects/pg/filter-parse.d.ts +10 -3
  19. package/dist/dialects/pg/fn/index.js +10 -2
  20. package/dist/dialects/pg/index.d.ts +2 -1
  21. package/dist/dialects/pg/index.js +29 -17
  22. package/dist/dialects/pg/introspect.d.ts +7 -0
  23. package/dist/dialects/pg/model.d.ts +7 -2
  24. package/dist/dialects/pg/ops/or.d.ts +1 -1
  25. package/dist/dialects/pg/owner.d.ts +42 -0
  26. package/dist/dialects/pg/path-endpoint.d.ts +20 -0
  27. package/dist/dialects/pg/role/check.d.ts +3 -0
  28. package/dist/dialects/pg/role/index.d.ts +71 -6
  29. package/dist/dialects/pg/role/sql.d.ts +11 -0
  30. package/dist/dialects/pg/schema.d.ts +2 -0
  31. package/dist/dialects/pg/table.d.ts +25 -3
  32. package/dist/dialects/pg/temporal.d.ts +5 -76
  33. package/dist/dialects/pg/tenancy.d.ts +45 -3
  34. package/dist/dialects/pg/view/client.d.ts +19 -1
  35. package/dist/dialects/pg/view/index.d.ts +4 -0
  36. package/dist/dialects/pg/view/index.js +21 -178
  37. package/dist/dialects/pg/view/refresh.d.ts +24 -0
  38. package/dist/runtime/batch.d.ts +1 -1
  39. package/dist/runtime/client.d.ts +6 -1
  40. package/dist/runtime/conflict.d.ts +2 -1
  41. package/dist/runtime/drift.d.ts +9 -0
  42. package/dist/runtime/inflight.d.ts +14 -0
  43. package/dist/runtime/pg/bun.js +6 -5
  44. package/dist/runtime/pg/pg.js +5 -5
  45. package/dist/runtime/pg/pglite.js +6 -5
  46. package/dist/runtime/pg/postgresjs.js +5 -5
  47. package/dist/runtime/plan.d.ts +22 -1
  48. package/dist/runtime/predicate.d.ts +19 -0
  49. package/dist/runtime/safety/index.js +1 -1
  50. package/dist/runtime/tenancy/composite.d.ts +26 -0
  51. package/dist/runtime/tenancy/context.d.ts +16 -0
  52. package/dist/runtime/tenancy/index.d.ts +9 -5
  53. package/dist/runtime/tenancy/index.js +1508 -37
  54. package/dist/runtime/tenancy/path.d.ts +87 -0
  55. package/dist/runtime/tenancy/rls.d.ts +67 -0
  56. package/dist/runtime/tenancy/via.d.ts +22 -0
  57. package/dist/runtime/traits/index.js +17 -11
  58. package/dist/runtime/types.d.ts +13 -1
  59. package/dist/runtime/validate/index.js +4 -4
  60. package/dist/runtime/write.d.ts +1 -1
  61. package/dist/shared/09p049xa.js +702 -0
  62. package/dist/shared/{ykv7wh5b.js → 1f0xa3cb.js} +5 -5
  63. package/dist/shared/1nw1f3vs.js +23 -0
  64. package/dist/shared/{6p5k20sm.js → 1z04fa85.js} +21 -11
  65. package/dist/shared/{p7pfx624.js → 2cg3wnxc.js} +314 -65
  66. package/dist/shared/{dyj86cmj.js → 2jd1sn0e.js} +2 -2
  67. package/dist/shared/{qgvt8nx1.js → 2z7wv5tj.js} +21 -5
  68. package/dist/shared/{kyxb62mc.js → 31vm914h.js} +9 -1
  69. package/dist/shared/{sf8m6tfy.js → 32cnm7kn.js} +8 -3
  70. package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
  71. package/dist/shared/{jdgqqx31.js → 3fqwmr09.js} +38 -14
  72. package/dist/shared/{922qbgnw.js → 3qnhc7w5.js} +16 -9
  73. package/dist/shared/{zvbjc949.js → 4az561fn.js} +1 -1
  74. package/dist/shared/{k3ted12y.js → 54tqkxja.js} +20 -2
  75. package/dist/shared/{k7cc9nzk.js → 5d8t84hg.js} +15 -3
  76. package/dist/shared/{fa9vt245.js → 5j36z8dn.js} +17 -6
  77. package/dist/shared/{1g0drakv.js → 5yv4k6a6.js} +1 -1
  78. package/dist/shared/8dqhth8c.js +12 -0
  79. package/dist/shared/8etn7d8w.js +62 -0
  80. package/dist/shared/{g516zdsb.js → 8x72s86k.js} +476 -30
  81. package/dist/shared/{nkc9sfqb.js → 929h19xp.js} +145 -7
  82. package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
  83. package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
  84. package/dist/shared/{b066g80h.js → ag4c7516.js} +2 -2
  85. package/dist/shared/b3awxn7h.js +45 -0
  86. package/dist/shared/b4v57v3x.js +9 -0
  87. package/dist/shared/bdk4sty6.js +58 -0
  88. package/dist/shared/{s6gqfn5j.js → c58secgj.js} +125 -8
  89. package/dist/shared/{rrstp3kb.js → cgbamx3e.js} +2 -2
  90. package/dist/shared/d5azex6s.js +6 -0
  91. package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
  92. package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
  93. package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
  94. package/dist/shared/{wxn4b7pp.js → f0f1n281.js} +59 -12
  95. package/dist/shared/{gdh9mrtp.js → g90m9b0g.js} +3 -2
  96. package/dist/shared/{tbszx8mz.js → gwn6v667.js} +2 -2
  97. package/dist/shared/{c8aghh05.js → h15jx9bc.js} +8 -2
  98. package/dist/shared/{3p4b1fg0.js → hazqqecq.js} +17 -93
  99. package/dist/shared/{4ef7mmqf.js → j3rkk835.js} +34 -11
  100. package/dist/shared/{bt9sfq0z.js → j60w0dvr.js} +56 -21
  101. package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
  102. package/dist/shared/k68eedmy.js +85 -0
  103. package/dist/shared/{szm0cksa.js → knmes2kh.js} +34 -6
  104. package/dist/shared/{ckjbyrt9.js → mb2ycs1p.js} +7 -9
  105. package/dist/shared/{tq9afp8d.js → n076ydsc.js} +1 -1
  106. package/dist/shared/{xhh1srw3.js → nx9hh281.js} +50 -32
  107. package/dist/shared/{kdkxh3kb.js → p248q79y.js} +58 -59
  108. package/dist/shared/{990a291j.js → p6bjzq9q.js} +14 -9
  109. package/dist/shared/{h4nqvjkp.js → pjr6xrm5.js} +2 -2
  110. package/dist/shared/pz6rj8ay.js +212 -0
  111. package/dist/shared/{5vdm4sgp.js → q3j1tq7a.js} +36 -23
  112. package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
  113. package/dist/shared/{dxjp14rk.js → r11n8grd.js} +2 -2
  114. package/dist/shared/r1fdd0f6.js +19 -0
  115. package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
  116. package/dist/shared/rhs3xe4k.js +7 -0
  117. package/dist/shared/{jsd07prz.js → rpycarcr.js} +6 -6
  118. package/dist/shared/{xsq7v6wp.js → sbdme3vy.js} +14 -2
  119. package/dist/shared/{xdpj5kkm.js → t3g0k88x.js} +775 -264
  120. package/dist/shared/{ayz64vzj.js → ttmg09vd.js} +708 -19
  121. package/dist/shared/{r6pj4fq2.js → venqrjna.js} +8 -4
  122. package/dist/shared/{fancm5pt.js → vjpnzwjz.js} +138 -15
  123. package/dist/shared/{9tgmr1gh.js → vmfkhszw.js} +44 -9
  124. package/dist/shared/{wqem4jed.js → wkme6tep.js} +11 -9
  125. package/dist/shared/{qy9rdq0g.js → wt5rzv1h.js} +15 -11
  126. package/dist/shared/wxr8cwns.js +6 -0
  127. package/dist/shared/{bzsjtd7c.js → wynzeggs.js} +19 -14
  128. package/dist/shared/x3jc53kg.js +220 -0
  129. package/dist/shared/{7p2wbz7f.js → x72jb7ad.js} +1 -1
  130. package/dist/shared/{fyqkk1m0.js → xq0mvhts.js} +10 -9
  131. package/dist/shared/xqve9598.js +53 -0
  132. package/dist/shared/{47xzb9fc.js → y2t3jktd.js} +2 -2
  133. package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
  134. package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
  135. package/dist/shared/{h8ne16fq.js → ys0xzyaj.js} +1 -1
  136. package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
  137. package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
  138. package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
  139. package/dist/shared/{fb00y8fp.js → zm0mafk4.js} +12 -6
  140. package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
  141. package/dist/tooling/cli.js +97 -24
  142. package/dist/tooling/migrate/apply.d.ts +14 -0
  143. package/dist/tooling/migrate/check.d.ts +3 -4
  144. package/dist/tooling/migrate/classify.d.ts +4 -0
  145. package/dist/tooling/migrate/commands.d.ts +1 -2
  146. package/dist/tooling/migrate/config.d.ts +3 -2
  147. package/dist/tooling/migrate/drift.d.ts +1 -1
  148. package/dist/tooling/migrate/estimate.d.ts +14 -1
  149. package/dist/tooling/migrate/files.d.ts +11 -1
  150. package/dist/tooling/migrate/index.js +17 -16
  151. package/dist/tooling/migrate/lint.d.ts +4 -4
  152. package/dist/tooling/migrate/lost.d.ts +28 -0
  153. package/dist/tooling/migrate/paths.d.ts +14 -0
  154. package/dist/tooling/migrate/plan.d.ts +10 -3
  155. package/dist/tooling/migrate/policy.d.ts +11 -0
  156. package/dist/tooling/migrate/runner.d.ts +25 -0
  157. package/dist/tooling/migrate/sandbox.d.ts +57 -0
  158. package/dist/tooling/migrate/sql-lex.d.ts +39 -0
  159. package/dist/tooling/migrate/text.d.ts +42 -0
  160. package/dist/tooling/node-version.d.ts +21 -0
  161. package/dist/tooling/testing/factories.d.ts +10 -0
  162. package/dist/tooling/testing/facts.d.ts +33 -5
  163. package/dist/tooling/testing/index.d.ts +1 -1
  164. package/dist/tooling/testing/index.js +3 -3
  165. package/dist/tooling/testing/isolation.d.ts +15 -8
  166. package/package.json +10 -6
  167. package/dist/shared/0v1g424p.js +0 -26
  168. package/dist/shared/r73pt594.js +0 -426
  169. package/dist/shared/rasvvzgz.js +0 -21
@@ -2,29 +2,35 @@ import {
2
2
  creationOrder2,
3
3
  renameColumn2,
4
4
  renameTable2
5
- } from "./8bwbwy8h.js";
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 "./8xsbagad.js";
24
+ } from "./9s0ypp87.js";
19
25
  import {
20
26
  isExactVersion,
21
27
  compareExtensionVersions,
22
28
  sameExtensionDefinition
23
- } from "./8ktwd3rh.js";
29
+ } from "./r3j8s5y0.js";
24
30
  import {
25
31
  isDomain,
26
32
  sameEnumLabels
27
- } from "./g7ez901n.js";
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 "./t4tbsy9h.js";
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.toLowerCase();
196
- assertPrivilege(privilege);
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
- return `${verb} ${privilege} on ${grantTarget(object.identity.object, schema)} ${direction} ${quoteIdent(object.identity.role)}`;
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(object.name)}`;
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";
@@ -1047,17 +1466,24 @@ function planMigration(input) {
1047
1466
  if (!afterBy.has(item.key)) {
1048
1467
  if (item.object.kind === "role")
1049
1468
  continue;
1469
+ if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
1470
+ continue;
1050
1471
  dropKeys.add(item.key);
1051
1472
  }
1052
1473
  }
1053
1474
  for (const item of afterList) {
1054
- if (!beforeBy.has(item.key))
1475
+ if (!beforeBy.has(item.key)) {
1476
+ if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
1477
+ continue;
1055
1478
  createKeys.add(item.key);
1479
+ }
1056
1480
  }
1057
1481
  for (const item of afterList) {
1058
1482
  const previous = beforeBy.get(item.key);
1059
1483
  if (previous === undefined || sameDefinition(previous, item.object))
1060
1484
  continue;
1485
+ if (handsOff(item.object) || childOfHandsOff(item.object, afterBy))
1486
+ continue;
1061
1487
  if (previous.kind === "extension" && item.object.kind === "extension")
1062
1488
  continue;
1063
1489
  if (previous.kind === "role" && item.object.kind === "role")
@@ -1093,6 +1519,8 @@ function planMigration(input) {
1093
1519
  refuseRoutineDrops(beforeBy, afterBy, dropKeys);
1094
1520
  omitOwnedSequences(createKeys, afterBy, request.after);
1095
1521
  omitOwnedSequences(dropKeys, beforeBy, renamed);
1522
+ releaseHandsOff(dropKeys, beforeBy, afterBy);
1523
+ releaseHandsOff(createKeys, afterBy, afterBy);
1096
1524
  const recreated = new Set;
1097
1525
  for (const key of createKeys) {
1098
1526
  if (dropKeys.has(key))
@@ -1111,7 +1539,7 @@ function planMigration(input) {
1111
1539
  const deferred = new Set(picklists.map((change) => identityKey2(change.before.identity)));
1112
1540
  const typeDrops = [];
1113
1541
  const extensionDrops = [];
1114
- const reverse = [...creationOrder2(renamed)].reverse();
1542
+ const reverse = [...uniqueBeforeForeignKey(creationOrder2(renamed))].reverse();
1115
1543
  const emitDrop = (object) => {
1116
1544
  const key = identityKey2(object.identity);
1117
1545
  if (!dropKeys.has(key) || deferred.has(key) || covered(object, droppedTables))
@@ -1145,7 +1573,17 @@ function planMigration(input) {
1145
1573
  emitDrop(object);
1146
1574
  }
1147
1575
  for (const object of reverse) {
1148
- if (object.kind === "trigger" || object.kind === "function" || object.kind === "view" || object.kind === "materializedView" || ownedByView(object)) {
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)) {
1149
1587
  continue;
1150
1588
  }
1151
1589
  const key = identityKey2(object.identity);
@@ -1217,8 +1655,8 @@ function planMigration(input) {
1217
1655
  continue;
1218
1656
  steps.push(step(sql, kind, "ddl", ACCESS2));
1219
1657
  }
1220
- for (const object of creationOrder2(request.after)) {
1221
- 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)) {
1222
1660
  continue;
1223
1661
  }
1224
1662
  const key = identityKey2(object.identity);
@@ -1249,6 +1687,17 @@ function planMigration(input) {
1249
1687
  }
1250
1688
  steps.push(step(sql, kind, "ddl", object.kind === "index" ? SHARE : ACCESS2));
1251
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
+ }
1252
1701
  for (const change of replaces) {
1253
1702
  if (sameDefinition(change.before, change.after))
1254
1703
  continue;
@@ -1345,7 +1794,7 @@ function formatPlan(plan, lockText) {
1345
1794
  `);
1346
1795
  }
1347
1796
  function parsePlan(text) {
1348
- const lines = text.split(`
1797
+ const lines = prepareMigrationText(text).split(`
1349
1798
  `);
1350
1799
  let name = "migration";
1351
1800
  let planClass = "expand";
@@ -1377,9 +1826,16 @@ function parsePlan(text) {
1377
1826
  let behavior;
1378
1827
  const allows = [];
1379
1828
  const sql = [];
1380
- while (index < lines.length && (lines[index] ?? "") !== "") {
1829
+ let quoteOpen = false;
1830
+ while (index < lines.length && (quoteOpen || (lines[index] ?? "") !== "")) {
1381
1831
  const line = lines[index] ?? "";
1382
1832
  index += 1;
1833
+ if (quoteOpen) {
1834
+ sql.push(line);
1835
+ quoteOpen = sqlQuoteOpen(sql.join(`
1836
+ `));
1837
+ continue;
1838
+ }
1383
1839
  if (line.startsWith("-- class: ")) {
1384
1840
  stepClass = readClass(line.slice("-- class: ".length));
1385
1841
  sawClass = true;
@@ -1401,8 +1857,11 @@ function parsePlan(text) {
1401
1857
  behavior = "change";
1402
1858
  else if (line.startsWith("-- okm-allow"))
1403
1859
  allows.push(readAllow(line));
1404
- else if (!line.startsWith("--"))
1860
+ else if (!line.startsWith("--")) {
1405
1861
  sql.push(line);
1862
+ quoteOpen = sqlQuoteOpen(sql.join(`
1863
+ `));
1864
+ }
1406
1865
  }
1407
1866
  const statement = sql.join(`
1408
1867
  `).replace(/;\s*$/, "");
@@ -1559,7 +2018,7 @@ function withoutNameKey(value) {
1559
2018
  }
1560
2019
  function renameShapeStep(pair, schema) {
1561
2020
  if (pair.from.kind === "index" && pair.to.kind === "index") {
1562
- return step(`alter index ${qualify(schema, pair.from.identity.name)} rename to ${quoteIdent(pair.to.identity.name)}`, "rename-index", "ddl", ACCESS2);
2021
+ return step(`alter index ${qualify(schema, pair.from.identity.name)} rename to ${quoteIdent(pair.to.identity.name)}`, "rename-index", "ddl", SHARE_UPDATE2);
1563
2022
  }
1564
2023
  if (pair.from.kind !== "constraint" || pair.to.kind !== "constraint") {
1565
2024
  throw new OkmError2("invalid", "A same-shape rename is an index or a constraint.", {
@@ -2132,6 +2591,25 @@ function reprintedDefaultBase(typeName) {
2132
2591
  return `${time[1] ?? ""} ${time[2] ?? ""}`;
2133
2592
  return;
2134
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
+ }
2135
2613
  function sameDefinition(left, right) {
2136
2614
  if (left.kind === "materializedView" && right.kind === "materializedView") {
2137
2615
  return stable(canonicalColumns(left.definition.columns)) === stable(canonicalColumns(right.definition.columns)) && left.definition.query === right.definition.query;
@@ -2171,6 +2649,9 @@ function forComparison(object) {
2171
2649
  if (!isDomain(object.definition))
2172
2650
  return object.definition;
2173
2651
  return { ...object.definition, base: canonicalTypeName(object.definition.base) };
2652
+ case "constraint":
2653
+ case "index":
2654
+ return withoutNameKey(object.definition);
2174
2655
  default:
2175
2656
  return object.definition;
2176
2657
  }
@@ -2429,4 +2910,212 @@ function order(value) {
2429
2910
  return value;
2430
2911
  }
2431
2912
 
2432
- export { canonicalTypeName, 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 };
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
+
2960
+ // src/tooling/migrate/policy.ts
2961
+ var READ = new Set([
2962
+ "plan",
2963
+ "status",
2964
+ "check",
2965
+ "drift",
2966
+ "verify",
2967
+ "pull",
2968
+ "catalog-export",
2969
+ "inspect"
2970
+ ]);
2971
+ var ALLOWED = new Set(["expand", "reference", "provision"]);
2972
+ var FORWARD_ONLY = new Set(["drop", "rollback"]);
2973
+ function assertTargetPolicy(target, operation, allowProtected = false) {
2974
+ if (FORWARD_ONLY.has(operation)) {
2975
+ throw new OkmError2("invalid", "There is no down migration.", {
2976
+ fix: { summary: "Recovery is a new forward migration." }
2977
+ });
2978
+ }
2979
+ if (!target.protected || allowProtected)
2980
+ return;
2981
+ if (READ.has(operation) || ALLOWED.has(operation))
2982
+ return;
2983
+ throw new OkmError2("OKM1850", `${operation} is blocked on protected target ${target.name}.`, {
2984
+ kind: "forbidden",
2985
+ fix: {
2986
+ summary: "Run a read-only command or an expand migration, or pass --allow-protected for this invocation."
2987
+ }
2988
+ });
2989
+ }
2990
+ function assertTargetAlias(targets) {
2991
+ const groups = new Map;
2992
+ for (const target of targets) {
2993
+ const key = `${target.host}
2994
+ ${target.port}
2995
+ ${target.database}`;
2996
+ const group = groups.get(key);
2997
+ if (group === undefined)
2998
+ groups.set(key, [target]);
2999
+ else
3000
+ group.push(target);
3001
+ }
3002
+ for (const group of groups.values()) {
3003
+ const protectedTarget = group.find((target) => target.protected);
3004
+ const open = group.find((target) => !target.protected);
3005
+ if (protectedTarget !== undefined && open !== undefined) {
3006
+ throw new OkmError2("OKM1852", `${open.name} and ${protectedTarget.name} resolve to the same database and disagree about protection.`, {
3007
+ fix: {
3008
+ summary: "Give those targets the same protection flag. okm check and okm doctor both report this."
3009
+ }
3010
+ });
3011
+ }
3012
+ }
3013
+ }
3014
+ function assertDirectConnection(url, allowPooler) {
3015
+ if (allowPooler)
3016
+ return;
3017
+ const endpoint = endpointOf(url);
3018
+ const parsed = new URL(url);
3019
+ const host = endpoint.host;
3020
+ if (host.includes("pooler") || host.includes("pgbouncer") || host.includes("-pooler") || endpoint.port === "6543" || endpoint.port === "6432" || parsed.searchParams.get("pgbouncer") === "true") {
3021
+ throw new OkmError2("invalid", `Refusing pooler host ${host}. Apply needs a direct connection.`, { fix: { summary: "Use a direct connection, or pass --allow-pooler." } });
3022
+ }
3023
+ }
3024
+ async function assertStableBackend(readPid, allowPooler) {
3025
+ if (allowPooler)
3026
+ return;
3027
+ const first = await readPid();
3028
+ const second = await readPid();
3029
+ if (first === second)
3030
+ return;
3031
+ throw new OkmError2("OKM1854", `The backend pid changed from ${first} to ${second}. A pooler is handing out a new session between statements.`, { fix: { summary: "Use a direct connection, or pass --allow-pooler." } });
3032
+ }
3033
+ function listTargets(config) {
3034
+ if (config.database !== undefined && config.targets !== undefined) {
3035
+ throw new OkmError2("invalid", "Set database or targets, not both.", {
3036
+ fix: { summary: "database is the one target named default. Use targets for more than one." }
3037
+ });
3038
+ }
3039
+ const entries = [];
3040
+ if (config.database !== undefined)
3041
+ entries.push(["default", config.database]);
3042
+ if (config.targets !== undefined) {
3043
+ for (const name of Object.keys(config.targets).sort()) {
3044
+ const input = config.targets[name];
3045
+ if (input !== undefined)
3046
+ entries.push([name, input]);
3047
+ }
3048
+ }
3049
+ return entries.map(([name, input]) => resolveTarget(name, input));
3050
+ }
3051
+ function selectTarget(config, name) {
3052
+ const targets = listTargets(config);
3053
+ if (targets.length === 0) {
3054
+ throw new OkmError2("OKM1845", "No target is configured.", {
3055
+ fix: { summary: "Set database or targets in okmodel.config.ts." }
3056
+ });
3057
+ }
3058
+ if (name === undefined) {
3059
+ if (targets.length === 1) {
3060
+ const only = targets[0];
3061
+ if (only !== undefined)
3062
+ return only;
3063
+ }
3064
+ throw new OkmError2("OKM1853", "Several targets are configured and --target was not passed.", {
3065
+ fix: { summary: "Pass --target <name>. The command does not guess." }
3066
+ });
3067
+ }
3068
+ const found = targets.find((target) => target.name === name);
3069
+ if (found === undefined) {
3070
+ throw new OkmError2("OKM1845", `Target ${name} is not configured.`, {
3071
+ fix: { summary: "Pass a name from targets, or database for the target named default." }
3072
+ });
3073
+ }
3074
+ return found;
3075
+ }
3076
+ function resolveTarget(name, input) {
3077
+ if (typeof input !== "string" && isReplicaTarget(input)) {
3078
+ throw new OkmError2("OKM1845", `Target ${name} is a replica. Migrations run on the primary only.`, {
3079
+ fix: {
3080
+ summary: "Set database or targets to the primary URL. A replica is not a migration target."
3081
+ }
3082
+ });
3083
+ }
3084
+ const url = typeof input === "string" ? input : input.url;
3085
+ const protectedTarget = typeof input === "string" ? false : input.protected === true;
3086
+ if (url === undefined || url.length === 0) {
3087
+ throw new OkmError2("OKM1845", `Target ${name} has no url.`, {
3088
+ fix: { summary: "Set the target url. A target is not inferred from the environment." }
3089
+ });
3090
+ }
3091
+ const endpoint = endpointOf(url);
3092
+ return {
3093
+ name,
3094
+ url,
3095
+ protected: protectedTarget,
3096
+ host: endpoint.host,
3097
+ port: endpoint.port,
3098
+ database: endpoint.database
3099
+ };
3100
+ }
3101
+ function isReplicaTarget(input) {
3102
+ return "primary" in input || "replicas" in input || "weight" in input || "pool" in input;
3103
+ }
3104
+ function endpointOf(url) {
3105
+ let parsed;
3106
+ try {
3107
+ parsed = new URL(url);
3108
+ } catch {
3109
+ throw new OkmError2("OKM1845", "The target URL is not a Postgres URL.", {
3110
+ fix: { summary: "Pass a postgres:// URL for the target." }
3111
+ });
3112
+ }
3113
+ const database = decodeURIComponent(parsed.pathname.replace(/^\//, ""));
3114
+ return {
3115
+ host: parsed.hostname.toLowerCase(),
3116
+ port: parsed.port.length > 0 ? parsed.port : "5432",
3117
+ database
3118
+ };
3119
+ }
3120
+
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 };