okmodel 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/dist/dialects/pg/filter-parse.d.ts +8 -2
- package/dist/dialects/pg/fn/index.js +8 -0
- package/dist/dialects/pg/index.js +8 -2
- package/dist/dialects/pg/ops/or.d.ts +1 -1
- package/dist/dialects/pg/temporal.d.ts +5 -76
- package/dist/dialects/pg/view/index.js +1 -1
- package/dist/runtime/client.d.ts +6 -1
- package/dist/runtime/conflict.d.ts +2 -1
- package/dist/runtime/pg/bun.js +5 -5
- package/dist/runtime/pg/pg.js +5 -5
- package/dist/runtime/pg/pglite.js +5 -5
- package/dist/runtime/pg/postgresjs.js +5 -5
- package/dist/runtime/plan.d.ts +13 -0
- package/dist/runtime/tenancy/index.js +1 -1
- package/dist/runtime/traits/index.js +4 -4
- package/dist/runtime/validate/index.js +3 -3
- package/dist/shared/{ckjbyrt9.js → 0t22wwh1.js} +5 -9
- package/dist/shared/{jdgqqx31.js → 2pqx26h8.js} +23 -8
- package/dist/shared/{kyxb62mc.js → 31vm914h.js} +9 -1
- package/dist/shared/{9tgmr1gh.js → 32zqc1dw.js} +18 -7
- package/dist/shared/{47xzb9fc.js → 47x8x9ze.js} +1 -1
- package/dist/shared/{zvbjc949.js → 4az561fn.js} +1 -1
- package/dist/shared/{s6gqfn5j.js → 51mvgj8w.js} +27 -3
- package/dist/shared/{k3ted12y.js → 54tqkxja.js} +20 -2
- package/dist/shared/{3p4b1fg0.js → 5enne4ma.js} +1 -1
- package/dist/shared/{bzsjtd7c.js → 6mnp99hx.js} +7 -6
- package/dist/shared/{ykv7wh5b.js → 6qd27mx0.js} +2 -2
- package/dist/shared/{h4nqvjkp.js → 6rk2gen5.js} +2 -2
- package/dist/shared/{r73pt594.js → 7zwwyh0v.js} +32 -10
- package/dist/shared/{fa9vt245.js → 87jvvhnt.js} +2 -2
- package/dist/shared/{c8aghh05.js → 8rsy3hxz.js} +7 -1
- package/dist/shared/{6p5k20sm.js → 96qcj21c.js} +3 -3
- package/dist/shared/{xsq7v6wp.js → aj2qxyhj.js} +2 -2
- package/dist/shared/{5vdm4sgp.js → caw8b9d8.js} +4 -4
- package/dist/shared/{xhh1srw3.js → cctw17hj.js} +23 -8
- package/dist/shared/{rrstp3kb.js → cgbamx3e.js} +2 -2
- package/dist/shared/{tq9afp8d.js → cr74e96e.js} +1 -1
- package/dist/shared/{b066g80h.js → efmy2gcg.js} +2 -2
- package/dist/shared/{gdh9mrtp.js → f5cw5q5r.js} +2 -2
- package/dist/shared/{ayz64vzj.js → ga3sfy93.js} +357 -3
- package/dist/shared/{qgvt8nx1.js → gbtcc2d7.js} +44 -3
- package/dist/shared/{kdkxh3kb.js → gde73es6.js} +5 -7
- package/dist/shared/{bt9sfq0z.js → hf22e0wt.js} +51 -17
- package/dist/shared/{990a291j.js → janx09m5.js} +6 -5
- package/dist/shared/{4ef7mmqf.js → jwtxdj06.js} +5 -5
- package/dist/shared/{sf8m6tfy.js → k8v5v5wj.js} +3 -3
- package/dist/shared/{r6pj4fq2.js → kfjp0gck.js} +2 -2
- package/dist/shared/{wqem4jed.js → krxx77g0.js} +7 -7
- package/dist/shared/{h8ne16fq.js → nkaxvt9q.js} +1 -1
- package/dist/shared/{jsd07prz.js → ntneex2a.js} +1 -1
- package/dist/shared/{nkc9sfqb.js → nxdp2ze3.js} +40 -4
- package/dist/shared/{tbszx8mz.js → pf0d8f77.js} +1 -1
- package/dist/shared/{qy9rdq0g.js → ps7a6h14.js} +6 -6
- package/dist/shared/{rasvvzgz.js → q58y17hy.js} +5 -5
- package/dist/shared/{p7pfx624.js → qm7cdtvr.js} +22 -9
- package/dist/shared/{xdpj5kkm.js → qv2ydck9.js} +149 -209
- package/dist/shared/{k7cc9nzk.js → r2sp8hrc.js} +6 -3
- package/dist/shared/{fb00y8fp.js → r8x5qhd7.js} +5 -5
- package/dist/shared/{fyqkk1m0.js → sdc7r2ww.js} +6 -5
- package/dist/shared/{wxn4b7pp.js → sycnx8gt.js} +42 -5
- package/dist/shared/{dxjp14rk.js → tm5ab8we.js} +2 -2
- package/dist/shared/{g516zdsb.js → v36c5g6p.js} +78 -19
- package/dist/shared/wq9n6pwr.js +139 -0
- package/dist/shared/{7p2wbz7f.js → x72jb7ad.js} +1 -1
- package/dist/shared/{922qbgnw.js → zqrnhwsq.js} +3 -3
- package/dist/tooling/cli.js +68 -21
- package/dist/tooling/migrate/commands.d.ts +1 -2
- package/dist/tooling/migrate/drift.d.ts +1 -1
- package/dist/tooling/migrate/estimate.d.ts +14 -1
- package/dist/tooling/migrate/index.js +8 -7
- package/dist/tooling/migrate/lint.d.ts +3 -3
- package/dist/tooling/migrate/plan.d.ts +7 -3
- package/dist/tooling/migrate/policy.d.ts +11 -0
- package/dist/tooling/migrate/sql-lex.d.ts +22 -0
- package/dist/tooling/testing/factories.d.ts +10 -0
- package/dist/tooling/testing/index.js +1 -1
- package/dist/tooling/testing/isolation.d.ts +4 -3
- package/package.json +6 -5
- package/dist/shared/0v1g424p.js +0 -26
|
@@ -976,6 +976,189 @@ function functionCalls(expression) {
|
|
|
976
976
|
return names;
|
|
977
977
|
}
|
|
978
978
|
|
|
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
|
+
|
|
979
1162
|
// src/tooling/migrate/values.ts
|
|
980
1163
|
function parseReplace(flag) {
|
|
981
1164
|
const eq = flag.indexOf("=");
|
|
@@ -1377,9 +1560,16 @@ function parsePlan(text) {
|
|
|
1377
1560
|
let behavior;
|
|
1378
1561
|
const allows = [];
|
|
1379
1562
|
const sql = [];
|
|
1380
|
-
|
|
1563
|
+
let quoteOpen = false;
|
|
1564
|
+
while (index < lines.length && (quoteOpen || (lines[index] ?? "") !== "")) {
|
|
1381
1565
|
const line = lines[index] ?? "";
|
|
1382
1566
|
index += 1;
|
|
1567
|
+
if (quoteOpen) {
|
|
1568
|
+
sql.push(line);
|
|
1569
|
+
quoteOpen = sqlQuoteOpen(sql.join(`
|
|
1570
|
+
`));
|
|
1571
|
+
continue;
|
|
1572
|
+
}
|
|
1383
1573
|
if (line.startsWith("-- class: ")) {
|
|
1384
1574
|
stepClass = readClass(line.slice("-- class: ".length));
|
|
1385
1575
|
sawClass = true;
|
|
@@ -1401,8 +1591,11 @@ function parsePlan(text) {
|
|
|
1401
1591
|
behavior = "change";
|
|
1402
1592
|
else if (line.startsWith("-- okm-allow"))
|
|
1403
1593
|
allows.push(readAllow(line));
|
|
1404
|
-
else if (!line.startsWith("--"))
|
|
1594
|
+
else if (!line.startsWith("--")) {
|
|
1405
1595
|
sql.push(line);
|
|
1596
|
+
quoteOpen = sqlQuoteOpen(sql.join(`
|
|
1597
|
+
`));
|
|
1598
|
+
}
|
|
1406
1599
|
}
|
|
1407
1600
|
const statement = sql.join(`
|
|
1408
1601
|
`).replace(/;\s*$/, "");
|
|
@@ -2429,4 +2622,165 @@ function order(value) {
|
|
|
2429
2622
|
return value;
|
|
2430
2623
|
}
|
|
2431
2624
|
|
|
2432
|
-
|
|
2625
|
+
// src/tooling/migrate/policy.ts
|
|
2626
|
+
var READ = new Set([
|
|
2627
|
+
"plan",
|
|
2628
|
+
"status",
|
|
2629
|
+
"check",
|
|
2630
|
+
"drift",
|
|
2631
|
+
"verify",
|
|
2632
|
+
"pull",
|
|
2633
|
+
"catalog-export",
|
|
2634
|
+
"inspect"
|
|
2635
|
+
]);
|
|
2636
|
+
var ALLOWED = new Set(["expand", "reference", "provision"]);
|
|
2637
|
+
var FORWARD_ONLY = new Set(["drop", "rollback"]);
|
|
2638
|
+
function assertTargetPolicy(target, operation, allowProtected = false) {
|
|
2639
|
+
if (FORWARD_ONLY.has(operation)) {
|
|
2640
|
+
throw new OkmError2("invalid", "There is no down migration.", {
|
|
2641
|
+
fix: { summary: "Recovery is a new forward migration." }
|
|
2642
|
+
});
|
|
2643
|
+
}
|
|
2644
|
+
if (!target.protected || allowProtected)
|
|
2645
|
+
return;
|
|
2646
|
+
if (READ.has(operation) || ALLOWED.has(operation))
|
|
2647
|
+
return;
|
|
2648
|
+
throw new OkmError2("OKM1850", `${operation} is blocked on protected target ${target.name}.`, {
|
|
2649
|
+
kind: "forbidden",
|
|
2650
|
+
fix: {
|
|
2651
|
+
summary: "Run a read-only command or an expand migration, or pass --allow-protected for this invocation."
|
|
2652
|
+
}
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
function assertTargetAlias(targets) {
|
|
2656
|
+
const groups = new Map;
|
|
2657
|
+
for (const target of targets) {
|
|
2658
|
+
const key = `${target.host}
|
|
2659
|
+
${target.port}
|
|
2660
|
+
${target.database}`;
|
|
2661
|
+
const group = groups.get(key);
|
|
2662
|
+
if (group === undefined)
|
|
2663
|
+
groups.set(key, [target]);
|
|
2664
|
+
else
|
|
2665
|
+
group.push(target);
|
|
2666
|
+
}
|
|
2667
|
+
for (const group of groups.values()) {
|
|
2668
|
+
const protectedTarget = group.find((target) => target.protected);
|
|
2669
|
+
const open = group.find((target) => !target.protected);
|
|
2670
|
+
if (protectedTarget !== undefined && open !== undefined) {
|
|
2671
|
+
throw new OkmError2("OKM1852", `${open.name} and ${protectedTarget.name} resolve to the same database and disagree about protection.`, {
|
|
2672
|
+
fix: {
|
|
2673
|
+
summary: "Give those targets the same protection flag. okm check and okm doctor both report this."
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
function assertDirectConnection(url, allowPooler) {
|
|
2680
|
+
if (allowPooler)
|
|
2681
|
+
return;
|
|
2682
|
+
const endpoint = endpointOf(url);
|
|
2683
|
+
const parsed = new URL(url);
|
|
2684
|
+
const host = endpoint.host;
|
|
2685
|
+
if (host.includes("pooler") || host.includes("pgbouncer") || host.includes("-pooler") || endpoint.port === "6543" || endpoint.port === "6432" || parsed.searchParams.get("pgbouncer") === "true") {
|
|
2686
|
+
throw new OkmError2("invalid", `Refusing pooler host ${host}. Apply needs a direct connection.`, { fix: { summary: "Use a direct connection, or pass --allow-pooler." } });
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
async function assertStableBackend(readPid, allowPooler) {
|
|
2690
|
+
if (allowPooler)
|
|
2691
|
+
return;
|
|
2692
|
+
const first = await readPid();
|
|
2693
|
+
const second = await readPid();
|
|
2694
|
+
if (first === second)
|
|
2695
|
+
return;
|
|
2696
|
+
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." } });
|
|
2697
|
+
}
|
|
2698
|
+
function listTargets(config) {
|
|
2699
|
+
if (config.database !== undefined && config.targets !== undefined) {
|
|
2700
|
+
throw new OkmError2("invalid", "Set database or targets, not both.", {
|
|
2701
|
+
fix: { summary: "database is the one target named default. Use targets for more than one." }
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
const entries = [];
|
|
2705
|
+
if (config.database !== undefined)
|
|
2706
|
+
entries.push(["default", config.database]);
|
|
2707
|
+
if (config.targets !== undefined) {
|
|
2708
|
+
for (const name of Object.keys(config.targets).sort()) {
|
|
2709
|
+
const input = config.targets[name];
|
|
2710
|
+
if (input !== undefined)
|
|
2711
|
+
entries.push([name, input]);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
return entries.map(([name, input]) => resolveTarget(name, input));
|
|
2715
|
+
}
|
|
2716
|
+
function selectTarget(config, name) {
|
|
2717
|
+
const targets = listTargets(config);
|
|
2718
|
+
if (targets.length === 0) {
|
|
2719
|
+
throw new OkmError2("OKM1845", "No target is configured.", {
|
|
2720
|
+
fix: { summary: "Set database or targets in okmodel.config.ts." }
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
if (name === undefined) {
|
|
2724
|
+
if (targets.length === 1) {
|
|
2725
|
+
const only = targets[0];
|
|
2726
|
+
if (only !== undefined)
|
|
2727
|
+
return only;
|
|
2728
|
+
}
|
|
2729
|
+
throw new OkmError2("OKM1853", "Several targets are configured and --target was not passed.", {
|
|
2730
|
+
fix: { summary: "Pass --target <name>. The command does not guess." }
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
const found = targets.find((target) => target.name === name);
|
|
2734
|
+
if (found === undefined) {
|
|
2735
|
+
throw new OkmError2("OKM1845", `Target ${name} is not configured.`, {
|
|
2736
|
+
fix: { summary: "Pass a name from targets, or database for the target named default." }
|
|
2737
|
+
});
|
|
2738
|
+
}
|
|
2739
|
+
return found;
|
|
2740
|
+
}
|
|
2741
|
+
function resolveTarget(name, input) {
|
|
2742
|
+
if (typeof input !== "string" && isReplicaTarget(input)) {
|
|
2743
|
+
throw new OkmError2("OKM1845", `Target ${name} is a replica. Migrations run on the primary only.`, {
|
|
2744
|
+
fix: {
|
|
2745
|
+
summary: "Set database or targets to the primary URL. A replica is not a migration target."
|
|
2746
|
+
}
|
|
2747
|
+
});
|
|
2748
|
+
}
|
|
2749
|
+
const url = typeof input === "string" ? input : input.url;
|
|
2750
|
+
const protectedTarget = typeof input === "string" ? false : input.protected === true;
|
|
2751
|
+
if (url === undefined || url.length === 0) {
|
|
2752
|
+
throw new OkmError2("OKM1845", `Target ${name} has no url.`, {
|
|
2753
|
+
fix: { summary: "Set the target url. A target is not inferred from the environment." }
|
|
2754
|
+
});
|
|
2755
|
+
}
|
|
2756
|
+
const endpoint = endpointOf(url);
|
|
2757
|
+
return {
|
|
2758
|
+
name,
|
|
2759
|
+
url,
|
|
2760
|
+
protected: protectedTarget,
|
|
2761
|
+
host: endpoint.host,
|
|
2762
|
+
port: endpoint.port,
|
|
2763
|
+
database: endpoint.database
|
|
2764
|
+
};
|
|
2765
|
+
}
|
|
2766
|
+
function isReplicaTarget(input) {
|
|
2767
|
+
return "primary" in input || "replicas" in input || "weight" in input || "pool" in input;
|
|
2768
|
+
}
|
|
2769
|
+
function endpointOf(url) {
|
|
2770
|
+
let parsed;
|
|
2771
|
+
try {
|
|
2772
|
+
parsed = new URL(url);
|
|
2773
|
+
} catch {
|
|
2774
|
+
throw new OkmError2("OKM1845", "The target URL is not a Postgres URL.", {
|
|
2775
|
+
fix: { summary: "Pass a postgres:// URL for the target." }
|
|
2776
|
+
});
|
|
2777
|
+
}
|
|
2778
|
+
const database = decodeURIComponent(parsed.pathname.replace(/^\//, ""));
|
|
2779
|
+
return {
|
|
2780
|
+
host: parsed.hostname.toLowerCase(),
|
|
2781
|
+
port: parsed.port.length > 0 ? parsed.port : "5432",
|
|
2782
|
+
database
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
export { canonicalTypeName, createdRoleName, createRoleOnce, changesRole, DEFAULT_BACKFILL_PAUSE_MS, DEFAULT_BACKFILL_STATEMENT_TIMEOUT_MS, batchSizeField, aboutBatchCount, boundaryQuery, checkedCast, classOf, strictestClass, assertExtensionsAvailable, omitManagedObjects, sqlStatements, parseReplace, planMigration, formatPlan, parsePlan, staleRenames, assertTargetPolicy, assertTargetAlias, assertDirectConnection, assertStableBackend, listTargets, selectTarget };
|
|
@@ -533,7 +533,9 @@ function emitIn(column, ref, name, value, sink) {
|
|
|
533
533
|
sink.text(")");
|
|
534
534
|
}
|
|
535
535
|
function emitOr(schema, table, value, sink, alias, depth) {
|
|
536
|
-
if (!Array.isArray(value)
|
|
536
|
+
if (!Array.isArray(value))
|
|
537
|
+
orFail(false);
|
|
538
|
+
if (value.length === 0) {
|
|
537
539
|
sink.text("false");
|
|
538
540
|
sink.mark(":0");
|
|
539
541
|
return;
|
|
@@ -559,7 +561,7 @@ function emitOr(schema, table, value, sink, alias, depth) {
|
|
|
559
561
|
emitPredicate(schema, table, key, item, sink, alias, depth);
|
|
560
562
|
}
|
|
561
563
|
if (!wrote)
|
|
562
|
-
|
|
564
|
+
orFail(true);
|
|
563
565
|
sink.text(")");
|
|
564
566
|
}
|
|
565
567
|
sink.text(")");
|
|
@@ -844,6 +846,45 @@ function list(names) {
|
|
|
844
846
|
function isRecord(value) {
|
|
845
847
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !isOperator(value);
|
|
846
848
|
}
|
|
849
|
+
function effectivePredicate(where) {
|
|
850
|
+
if (where === undefined)
|
|
851
|
+
return false;
|
|
852
|
+
if (isOperator(where)) {
|
|
853
|
+
const name = operatorName(where);
|
|
854
|
+
const value = operatorValue(where);
|
|
855
|
+
if (name === "or") {
|
|
856
|
+
if (!Array.isArray(value))
|
|
857
|
+
orFail(false);
|
|
858
|
+
if (value.length === 0)
|
|
859
|
+
return true;
|
|
860
|
+
for (const branch of value) {
|
|
861
|
+
if (!effectivePredicate(branch))
|
|
862
|
+
orFail(true);
|
|
863
|
+
}
|
|
864
|
+
return true;
|
|
865
|
+
}
|
|
866
|
+
if (name === "and") {
|
|
867
|
+
return Array.isArray(value) && value.some((part) => effectivePredicate(part));
|
|
868
|
+
}
|
|
869
|
+
if (name === "not")
|
|
870
|
+
return effectivePredicate(value);
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
if (!isRecord(where))
|
|
874
|
+
return true;
|
|
875
|
+
for (const key of Object.keys(where)) {
|
|
876
|
+
if (where[key] !== undefined)
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
function orFail(empty) {
|
|
882
|
+
throw new OkmError2("OKM1121", empty ? "or() branch is empty." : "Pass an array: or([a, b]).", {
|
|
883
|
+
fix: {
|
|
884
|
+
summary: empty ? "Give every or() branch a predicate. An empty branch matches every row." : "Pass an array: or([a, b])."
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
}
|
|
847
888
|
var FAIL_FIX = {
|
|
848
889
|
OKM1121: "Use eq for an object value, or has, none, or every for a relation.",
|
|
849
890
|
OKM1101: "Pass limit, or call .all(reason)."
|
|
@@ -875,4 +916,4 @@ function hasMany(include) {
|
|
|
875
916
|
return Object.keys(include).length > 0;
|
|
876
917
|
}
|
|
877
918
|
|
|
878
|
-
export { withRowFilters, installArchiveInspect, archiveRules, readOptionNames, installOperatorSql, readNeedsOperatorSql, emitRelationFrom, bindCall, compileCall, decodeResult, logicalIntent, appliedRules, emitJoin, emitWhere, emitOrder, emitPrimaryOrder, selectedColumns, parseOrder, rejectKeys, readLimit, takeObject, projectExpr, jsonExpr, decodeRow, cell, indexes, quote, list, isRecord, registerFailFix, fail };
|
|
919
|
+
export { withRowFilters, installArchiveInspect, archiveRules, readOptionNames, installOperatorSql, readNeedsOperatorSql, emitRelationFrom, bindCall, compileCall, decodeResult, logicalIntent, appliedRules, emitJoin, emitWhere, emitOrder, emitPrimaryOrder, selectedColumns, parseOrder, rejectKeys, readLimit, takeObject, projectExpr, jsonExpr, decodeRow, cell, indexes, quote, list, isRecord, effectivePredicate, registerFailFix, fail };
|
|
@@ -7,9 +7,6 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
roleExists
|
|
9
9
|
} from "./szm0cksa.js";
|
|
10
|
-
import {
|
|
11
|
-
assertTargetPolicy
|
|
12
|
-
} from "./xdpj5kkm.js";
|
|
13
10
|
import {
|
|
14
11
|
canonicalTypeName,
|
|
15
12
|
createdRoleName,
|
|
@@ -20,8 +17,9 @@ import {
|
|
|
20
17
|
checkedCast,
|
|
21
18
|
omitManagedObjects,
|
|
22
19
|
planMigration,
|
|
23
|
-
parsePlan
|
|
24
|
-
|
|
20
|
+
parsePlan,
|
|
21
|
+
assertTargetPolicy
|
|
22
|
+
} from "./ga3sfy93.js";
|
|
25
23
|
import {
|
|
26
24
|
quoteIdent,
|
|
27
25
|
qualify
|
|
@@ -35,7 +33,7 @@ import {
|
|
|
35
33
|
} from "./g7ez901n.js";
|
|
36
34
|
import {
|
|
37
35
|
snakeCase
|
|
38
|
-
} from "./
|
|
36
|
+
} from "./ntneex2a.js";
|
|
39
37
|
import {
|
|
40
38
|
quoteLiteral
|
|
41
39
|
} from "./94ez8kzh.js";
|
|
@@ -309,7 +307,7 @@ function failStep(unit, index, error) {
|
|
|
309
307
|
if (error instanceof OkmError2)
|
|
310
308
|
return error;
|
|
311
309
|
const message = error instanceof Error ? error.message : "The step failed.";
|
|
312
|
-
return new OkmError2("invalid", `Migration ${unit.migrationId} failed at step ${String(index)}: ${message}`, {
|
|
310
|
+
return new OkmError2("invalid", `Migration ${unit.migrationId} failed at step ${String(index + 1)}: ${message}`, {
|
|
313
311
|
cause: error,
|
|
314
312
|
fix: { summary: "Fix the step and run apply again. Finished steps are not repeated." }
|
|
315
313
|
});
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
decodeResult,
|
|
8
8
|
logicalIntent,
|
|
9
9
|
appliedRules
|
|
10
|
-
} from "./
|
|
10
|
+
} from "./gbtcc2d7.js";
|
|
11
11
|
import {
|
|
12
12
|
OkmError2,
|
|
13
13
|
safe2,
|
|
@@ -22,10 +22,22 @@ var SINGLE_ENDPOINT = {
|
|
|
22
22
|
reason: "single-endpoint"
|
|
23
23
|
};
|
|
24
24
|
function createClient(schema, pool, options) {
|
|
25
|
-
const
|
|
25
|
+
const closing = {
|
|
26
|
+
current: undefined,
|
|
27
|
+
early: false
|
|
28
|
+
};
|
|
29
|
+
const checked = checkServer(pool, schema, options.http, options.requireMeta === true, callOptions(options), {
|
|
26
30
|
...options.catalog !== undefined ? { catalog: options.catalog } : {},
|
|
27
31
|
...options.catalogDir !== undefined ? { catalogDir: options.catalogDir } : {}
|
|
28
32
|
});
|
|
33
|
+
const connected = checked.catch((error) => {
|
|
34
|
+
if (!closing.early)
|
|
35
|
+
throw error;
|
|
36
|
+
throw new OkmError2("unavailable", "The client was closed before it connected. Await connected before close(), or do not close it before use.", { kind: "unavailable", fix: { summary: "Await client.connected before calling close()." } });
|
|
37
|
+
});
|
|
38
|
+
connected.catch(() => {
|
|
39
|
+
return;
|
|
40
|
+
});
|
|
29
41
|
const session = {
|
|
30
42
|
schema,
|
|
31
43
|
pool,
|
|
@@ -38,7 +50,7 @@ function createClient(schema, pool, options) {
|
|
|
38
50
|
generators: options.generators,
|
|
39
51
|
timeouts: options.timeouts,
|
|
40
52
|
hookm: options.hookm,
|
|
41
|
-
closing
|
|
53
|
+
closing
|
|
42
54
|
};
|
|
43
55
|
return openClient(session);
|
|
44
56
|
}
|
|
@@ -50,6 +62,7 @@ function openClient(session) {
|
|
|
50
62
|
const close = () => {
|
|
51
63
|
if (!session.ownsPool)
|
|
52
64
|
return Promise.resolve();
|
|
65
|
+
session.closing.early = true;
|
|
53
66
|
session.closing.current ??= session.pool.close();
|
|
54
67
|
return session.closing.current;
|
|
55
68
|
};
|
|
@@ -72,7 +85,7 @@ function openClient(session) {
|
|
|
72
85
|
},
|
|
73
86
|
close,
|
|
74
87
|
connected: session.connected,
|
|
75
|
-
tx: (...args) => import("./
|
|
88
|
+
tx: (...args) => import("./r2sp8hrc.js").then((mod) => mod.tx(session, args)),
|
|
76
89
|
batch: (ops, options) => batchHandle(session, ops, options),
|
|
77
90
|
...session.tx?.extras
|
|
78
91
|
};
|
|
@@ -107,7 +120,7 @@ function tableApi(session, table, view, uses) {
|
|
|
107
120
|
const api = {
|
|
108
121
|
find(options = {}) {
|
|
109
122
|
if ("lock" in options) {
|
|
110
|
-
return lazyRead(session, () => import("./
|
|
123
|
+
return lazyRead(session, () => import("./tm5ab8we.js"), table, options, base, view);
|
|
111
124
|
}
|
|
112
125
|
return start(session, "find", table, options, base, view);
|
|
113
126
|
},
|
|
@@ -121,10 +134,10 @@ function tableApi(session, table, view, uses) {
|
|
|
121
134
|
return start(session, "exists", table, options, base, view);
|
|
122
135
|
},
|
|
123
136
|
page(options) {
|
|
124
|
-
return lazyRead(session, () => import("./
|
|
137
|
+
return lazyRead(session, () => import("./6rk2gen5.js"), table, options, base, view);
|
|
125
138
|
},
|
|
126
139
|
aggregate(options = {}) {
|
|
127
|
-
return lazyRead(session, () => import("./
|
|
140
|
+
return lazyRead(session, () => import("./kfjp0gck.js"), table, options, base, view);
|
|
128
141
|
},
|
|
129
142
|
insert(data, options = {}) {
|
|
130
143
|
return writeHandle(session, "insert", table, data, options, mods);
|
|
@@ -154,13 +167,13 @@ function tableApi(session, table, view, uses) {
|
|
|
154
167
|
return api;
|
|
155
168
|
}
|
|
156
169
|
function batchHandle(session, ops, options, replica) {
|
|
157
|
-
return queryHandle(() => import("./
|
|
170
|
+
return queryHandle(() => import("./aj2qxyhj.js").then((mod) => mod.batch(session, ops, options, replica)), {
|
|
158
171
|
replica: () => batchHandle(session, ops, options, true)
|
|
159
172
|
});
|
|
160
173
|
}
|
|
161
174
|
var writers;
|
|
162
175
|
function loadWrite() {
|
|
163
|
-
writers ??= import("./
|
|
176
|
+
writers ??= import("./qm7cdtvr.js");
|
|
164
177
|
return writers;
|
|
165
178
|
}
|
|
166
179
|
function queryHandle(run, extra) {
|
|
@@ -215,9 +228,30 @@ async function runWrite(session, op, table, input, options, mods, plan) {
|
|
|
215
228
|
throw logged(session, await mapError(session, error));
|
|
216
229
|
}
|
|
217
230
|
}
|
|
231
|
+
function rejectedRead(error) {
|
|
232
|
+
const fail = () => Promise.reject(error);
|
|
233
|
+
return queryHandle(fail, {
|
|
234
|
+
all: () => rejectedRead(error),
|
|
235
|
+
required: () => rejectedRead(error),
|
|
236
|
+
inspect: fail,
|
|
237
|
+
sql: fail,
|
|
238
|
+
stream() {
|
|
239
|
+
return {
|
|
240
|
+
[Symbol.asyncIterator]() {
|
|
241
|
+
return { next: fail };
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
218
247
|
function start(session, op, table, options, mods, view) {
|
|
219
248
|
const model = session.schema.model[table];
|
|
220
|
-
|
|
249
|
+
let call;
|
|
250
|
+
try {
|
|
251
|
+
call = readCall(op, table, options, mods.all, session.scope, model, session.schema, view);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
return rejectedRead(error instanceof OkmError2 ? attachHttp(session.http, error) : error);
|
|
254
|
+
}
|
|
221
255
|
return readHandle(session, table, call, mods, async (plan, rows) => {
|
|
222
256
|
const value = await decodeRows(plan, rows, table);
|
|
223
257
|
if (mods.required === true && value === null) {
|
|
@@ -245,7 +279,7 @@ function lazyRead(session, load, table, options, mods, view) {
|
|
|
245
279
|
});
|
|
246
280
|
}
|
|
247
281
|
async function decodeRows(plan, rows, table) {
|
|
248
|
-
return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./
|
|
282
|
+
return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./nkaxvt9q.js")).decodeIncluded(plan, rows, table);
|
|
249
283
|
}
|
|
250
284
|
function readHandle(session, table, call, mods, decode, extra) {
|
|
251
285
|
let prepared;
|
|
@@ -320,7 +354,7 @@ function readHandle(session, table, call, mods, decode, extra) {
|
|
|
320
354
|
}
|
|
321
355
|
function streamLazy(session, call, prepare) {
|
|
322
356
|
return async function* () {
|
|
323
|
-
const { streamRows } = await import("./
|
|
357
|
+
const { streamRows } = await import("./zqrnhwsq.js");
|
|
324
358
|
yield* streamRows(session, call, prepare, (error) => logged(session, error));
|
|
325
359
|
}();
|
|
326
360
|
}
|
|
@@ -357,13 +391,13 @@ function readCall(op, table, options, all, scope, model, schema, view) {
|
|
|
357
391
|
};
|
|
358
392
|
}
|
|
359
393
|
async function checkServer(pool, schema, http, requireMeta, options, source) {
|
|
360
|
-
const server = await import("./
|
|
394
|
+
const server = await import("./47x8x9ze.js");
|
|
361
395
|
let rows;
|
|
362
396
|
try {
|
|
363
397
|
const result = await pool.execute(server.versionQuery, undefined, options);
|
|
364
398
|
rows = result.rows;
|
|
365
399
|
} catch (error) {
|
|
366
|
-
const { mapPostgresError } = await import("./
|
|
400
|
+
const { mapPostgresError } = await import("./51mvgj8w.js");
|
|
367
401
|
throw mapPostgresError(error, mapOptions(http, false));
|
|
368
402
|
}
|
|
369
403
|
await server.acceptServer(pool, schema, rows, http, requireMeta, options, source);
|
|
@@ -372,7 +406,7 @@ async function mapError(session, error) {
|
|
|
372
406
|
if (error instanceof OkmError2) {
|
|
373
407
|
return session.http === undefined ? error : new OkmError2(error.code, error.message, { ...errorFields(error), http: session.http });
|
|
374
408
|
}
|
|
375
|
-
const { mapPostgresError } = await import("./
|
|
409
|
+
const { mapPostgresError } = await import("./51mvgj8w.js");
|
|
376
410
|
return mapPostgresError(error, mapOptions(session.http, session.includeValues));
|
|
377
411
|
}
|
|
378
412
|
function errorFields(error) {
|
|
@@ -386,7 +420,7 @@ function errorFields(error) {
|
|
|
386
420
|
var includeHooks;
|
|
387
421
|
var operatorSql;
|
|
388
422
|
function loadOperatorSql() {
|
|
389
|
-
operatorSql ??= import("./
|
|
423
|
+
operatorSql ??= import("./cr74e96e.js").then(() => {
|
|
390
424
|
return;
|
|
391
425
|
});
|
|
392
426
|
return operatorSql;
|
|
@@ -394,7 +428,7 @@ function loadOperatorSql() {
|
|
|
394
428
|
function hooksFor(call) {
|
|
395
429
|
if (call.include === undefined)
|
|
396
430
|
return Promise.resolve(undefined);
|
|
397
|
-
includeHooks ??= import("./
|
|
431
|
+
includeHooks ??= import("./nkaxvt9q.js").then((mod) => mod.includeHooks);
|
|
398
432
|
return includeHooks;
|
|
399
433
|
}
|
|
400
434
|
function bindNow(schema, call) {
|