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.
Files changed (80) hide show
  1. package/README.md +9 -6
  2. package/dist/dialects/pg/filter-parse.d.ts +8 -2
  3. package/dist/dialects/pg/fn/index.js +8 -0
  4. package/dist/dialects/pg/index.js +8 -2
  5. package/dist/dialects/pg/ops/or.d.ts +1 -1
  6. package/dist/dialects/pg/temporal.d.ts +5 -76
  7. package/dist/dialects/pg/view/index.js +1 -1
  8. package/dist/runtime/client.d.ts +6 -1
  9. package/dist/runtime/conflict.d.ts +2 -1
  10. package/dist/runtime/pg/bun.js +5 -5
  11. package/dist/runtime/pg/pg.js +5 -5
  12. package/dist/runtime/pg/pglite.js +5 -5
  13. package/dist/runtime/pg/postgresjs.js +5 -5
  14. package/dist/runtime/plan.d.ts +13 -0
  15. package/dist/runtime/tenancy/index.js +1 -1
  16. package/dist/runtime/traits/index.js +4 -4
  17. package/dist/runtime/validate/index.js +3 -3
  18. package/dist/shared/{ckjbyrt9.js → 0t22wwh1.js} +5 -9
  19. package/dist/shared/{jdgqqx31.js → 2pqx26h8.js} +23 -8
  20. package/dist/shared/{kyxb62mc.js → 31vm914h.js} +9 -1
  21. package/dist/shared/{9tgmr1gh.js → 32zqc1dw.js} +18 -7
  22. package/dist/shared/{47xzb9fc.js → 47x8x9ze.js} +1 -1
  23. package/dist/shared/{zvbjc949.js → 4az561fn.js} +1 -1
  24. package/dist/shared/{s6gqfn5j.js → 51mvgj8w.js} +27 -3
  25. package/dist/shared/{k3ted12y.js → 54tqkxja.js} +20 -2
  26. package/dist/shared/{3p4b1fg0.js → 5enne4ma.js} +1 -1
  27. package/dist/shared/{bzsjtd7c.js → 6mnp99hx.js} +7 -6
  28. package/dist/shared/{ykv7wh5b.js → 6qd27mx0.js} +2 -2
  29. package/dist/shared/{h4nqvjkp.js → 6rk2gen5.js} +2 -2
  30. package/dist/shared/{r73pt594.js → 7zwwyh0v.js} +32 -10
  31. package/dist/shared/{fa9vt245.js → 87jvvhnt.js} +2 -2
  32. package/dist/shared/{c8aghh05.js → 8rsy3hxz.js} +7 -1
  33. package/dist/shared/{6p5k20sm.js → 96qcj21c.js} +3 -3
  34. package/dist/shared/{xsq7v6wp.js → aj2qxyhj.js} +2 -2
  35. package/dist/shared/{5vdm4sgp.js → caw8b9d8.js} +4 -4
  36. package/dist/shared/{xhh1srw3.js → cctw17hj.js} +23 -8
  37. package/dist/shared/{rrstp3kb.js → cgbamx3e.js} +2 -2
  38. package/dist/shared/{tq9afp8d.js → cr74e96e.js} +1 -1
  39. package/dist/shared/{b066g80h.js → efmy2gcg.js} +2 -2
  40. package/dist/shared/{gdh9mrtp.js → f5cw5q5r.js} +2 -2
  41. package/dist/shared/{ayz64vzj.js → ga3sfy93.js} +357 -3
  42. package/dist/shared/{qgvt8nx1.js → gbtcc2d7.js} +44 -3
  43. package/dist/shared/{kdkxh3kb.js → gde73es6.js} +5 -7
  44. package/dist/shared/{bt9sfq0z.js → hf22e0wt.js} +51 -17
  45. package/dist/shared/{990a291j.js → janx09m5.js} +6 -5
  46. package/dist/shared/{4ef7mmqf.js → jwtxdj06.js} +5 -5
  47. package/dist/shared/{sf8m6tfy.js → k8v5v5wj.js} +3 -3
  48. package/dist/shared/{r6pj4fq2.js → kfjp0gck.js} +2 -2
  49. package/dist/shared/{wqem4jed.js → krxx77g0.js} +7 -7
  50. package/dist/shared/{h8ne16fq.js → nkaxvt9q.js} +1 -1
  51. package/dist/shared/{jsd07prz.js → ntneex2a.js} +1 -1
  52. package/dist/shared/{nkc9sfqb.js → nxdp2ze3.js} +40 -4
  53. package/dist/shared/{tbszx8mz.js → pf0d8f77.js} +1 -1
  54. package/dist/shared/{qy9rdq0g.js → ps7a6h14.js} +6 -6
  55. package/dist/shared/{rasvvzgz.js → q58y17hy.js} +5 -5
  56. package/dist/shared/{p7pfx624.js → qm7cdtvr.js} +22 -9
  57. package/dist/shared/{xdpj5kkm.js → qv2ydck9.js} +149 -209
  58. package/dist/shared/{k7cc9nzk.js → r2sp8hrc.js} +6 -3
  59. package/dist/shared/{fb00y8fp.js → r8x5qhd7.js} +5 -5
  60. package/dist/shared/{fyqkk1m0.js → sdc7r2ww.js} +6 -5
  61. package/dist/shared/{wxn4b7pp.js → sycnx8gt.js} +42 -5
  62. package/dist/shared/{dxjp14rk.js → tm5ab8we.js} +2 -2
  63. package/dist/shared/{g516zdsb.js → v36c5g6p.js} +78 -19
  64. package/dist/shared/wq9n6pwr.js +139 -0
  65. package/dist/shared/{7p2wbz7f.js → x72jb7ad.js} +1 -1
  66. package/dist/shared/{922qbgnw.js → zqrnhwsq.js} +3 -3
  67. package/dist/tooling/cli.js +68 -21
  68. package/dist/tooling/migrate/commands.d.ts +1 -2
  69. package/dist/tooling/migrate/drift.d.ts +1 -1
  70. package/dist/tooling/migrate/estimate.d.ts +14 -1
  71. package/dist/tooling/migrate/index.js +8 -7
  72. package/dist/tooling/migrate/lint.d.ts +3 -3
  73. package/dist/tooling/migrate/plan.d.ts +7 -3
  74. package/dist/tooling/migrate/policy.d.ts +11 -0
  75. package/dist/tooling/migrate/sql-lex.d.ts +22 -0
  76. package/dist/tooling/testing/factories.d.ts +10 -0
  77. package/dist/tooling/testing/index.js +1 -1
  78. package/dist/tooling/testing/isolation.d.ts +4 -3
  79. package/package.json +6 -5
  80. 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
- while (index < lines.length && (lines[index] ?? "") !== "") {
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
- 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 };
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) || value.length === 0) {
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
- sink.text("true");
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
- } from "./ayz64vzj.js";
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 "./jsd07prz.js";
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 "./qgvt8nx1.js";
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 connected = checkServer(pool, schema, options.http, options.requireMeta === true, callOptions(options), {
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: { current: undefined }
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("./k7cc9nzk.js").then((mod) => mod.tx(session, args)),
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("./dxjp14rk.js"), table, options, base, view);
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("./h4nqvjkp.js"), table, options, base, view);
137
+ return lazyRead(session, () => import("./6rk2gen5.js"), table, options, base, view);
125
138
  },
126
139
  aggregate(options = {}) {
127
- return lazyRead(session, () => import("./r6pj4fq2.js"), table, options, base, view);
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("./xsq7v6wp.js").then((mod) => mod.batch(session, ops, options, replica)), {
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("./p7pfx624.js");
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
- const call = readCall(op, table, options, mods.all, session.scope, model, session.schema, view);
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("./h8ne16fq.js")).decodeIncluded(plan, rows, table);
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("./922qbgnw.js");
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("./47xzb9fc.js");
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("./s6gqfn5j.js");
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("./s6gqfn5j.js");
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("./tq9afp8d.js").then(() => {
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("./h8ne16fq.js").then((mod) => mod.includeHooks);
431
+ includeHooks ??= import("./nkaxvt9q.js").then((mod) => mod.includeHooks);
398
432
  return includeHooks;
399
433
  }
400
434
  function bindNow(schema, call) {