okmodel 0.6.0 → 0.7.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 (157) hide show
  1. package/README.md +100 -1131
  2. package/dist/adapters/capabilities.d.ts +3 -0
  3. package/dist/adapters/failure.d.ts +13 -2
  4. package/dist/adapters/lazy-errors.d.ts +22 -0
  5. package/dist/adapters/pg/bunsql-extra.d.ts +54 -3
  6. package/dist/adapters/pg/bunsql.d.ts +14 -1
  7. package/dist/adapters/pg/cursor.d.ts +17 -0
  8. package/dist/adapters/pg/no-inflight-timeout.d.ts +11 -8
  9. package/dist/adapters/pg/nodepostgres-extra.d.ts +22 -1
  10. package/dist/adapters/pg/nodepostgres.d.ts +12 -0
  11. package/dist/adapters/pg/pglite-wire.d.ts +24 -0
  12. package/dist/adapters/pg/pglite.d.ts +10 -0
  13. package/dist/adapters/pg/postgres-extra.d.ts +27 -11
  14. package/dist/adapters/pg/reserved.d.ts +42 -0
  15. package/dist/adapters/pg/session.d.ts +0 -18
  16. package/dist/contracts/connection.d.ts +7 -6
  17. package/dist/dialects/pg/floor.d.ts +68 -0
  18. package/dist/dialects/pg/index.d.ts +6 -1
  19. package/dist/dialects/pg/index.js +49 -159
  20. package/dist/dialects/pg/keys.d.ts +11 -8
  21. package/dist/dialects/pg/model.d.ts +40 -0
  22. package/dist/dialects/pg/morph.d.ts +43 -0
  23. package/dist/dialects/pg/operator-fit.d.ts +2 -2
  24. package/dist/dialects/pg/operators.d.ts +14 -7
  25. package/dist/dialects/pg/ops/bucket.d.ts +65 -0
  26. package/dist/dialects/pg/ops/inc.d.ts +2 -2
  27. package/dist/dialects/pg/ops/matches.d.ts +9 -12
  28. package/dist/dialects/pg/ops/relevance.d.ts +13 -0
  29. package/dist/dialects/pg/ops/search-query.d.ts +22 -0
  30. package/dist/dialects/pg/ops/window.d.ts +103 -0
  31. package/dist/dialects/pg/preset.d.ts +1 -1
  32. package/dist/dialects/pg/relations.d.ts +100 -3
  33. package/dist/dialects/pg/schema.d.ts +31 -3
  34. package/dist/dialects/pg/view/index.js +1 -1
  35. package/dist/runtime/aggregate.d.ts +8 -2
  36. package/dist/runtime/bucket-group.d.ts +70 -0
  37. package/dist/runtime/conflict.d.ts +22 -4
  38. package/dist/runtime/include.d.ts +0 -8
  39. package/dist/runtime/inflight.d.ts +1 -1
  40. package/dist/runtime/page.d.ts +4 -1
  41. package/dist/runtime/pg/bun.js +12 -6
  42. package/dist/runtime/pg/pg.js +5 -5
  43. package/dist/runtime/pg/pglite.d.ts +1 -0
  44. package/dist/runtime/pg/pglite.js +9 -9
  45. package/dist/runtime/pg/postgresjs.js +5 -5
  46. package/dist/runtime/plan.d.ts +95 -5
  47. package/dist/runtime/read-stream.d.ts +13 -16
  48. package/dist/runtime/result-name.d.ts +17 -0
  49. package/dist/runtime/server-check.d.ts +3 -3
  50. package/dist/runtime/sort-bind.d.ts +21 -0
  51. package/dist/runtime/sort.d.ts +56 -0
  52. package/dist/runtime/sync.d.ts +70 -0
  53. package/dist/runtime/tenancy/index.js +7 -5
  54. package/dist/runtime/text-search.d.ts +20 -0
  55. package/dist/runtime/traits/index.d.ts +80 -0
  56. package/dist/runtime/traits/index.js +175 -11
  57. package/dist/runtime/tree.d.ts +38 -0
  58. package/dist/runtime/types.d.ts +218 -22
  59. package/dist/runtime/validate/index.js +2 -2
  60. package/dist/runtime/version.d.ts +39 -0
  61. package/dist/runtime/window.d.ts +21 -0
  62. package/dist/runtime/write.d.ts +54 -2
  63. package/dist/shared/{wkme6tep.js → 14vx95q4.js} +8 -16
  64. package/dist/shared/1est4ezg.js +313 -0
  65. package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
  66. package/dist/shared/{2cg3wnxc.js → 1w508jbr.js} +593 -130
  67. package/dist/shared/2c13q96h.js +18 -0
  68. package/dist/shared/{b4v57v3x.js → 2d3xq4ps.js} +2 -2
  69. package/dist/shared/{1nw1f3vs.js → 2shdbn8q.js} +7 -7
  70. package/dist/shared/3v7t1yrv.js +208 -0
  71. package/dist/shared/{x3jc53kg.js → 5e3tf63j.js} +2 -2
  72. package/dist/shared/5fe3kbsh.js +10 -0
  73. package/dist/shared/5v3xf80k.js +37 -0
  74. package/dist/shared/{c58secgj.js → 63qtkrca.js} +38 -4
  75. package/dist/shared/{2z7wv5tj.js → 67txcrcw.js} +55 -34
  76. package/dist/shared/79dt02vc.js +12 -0
  77. package/dist/shared/{8x72s86k.js → 7k9grvf6.js} +10 -4
  78. package/dist/shared/7kms6fvj.js +20 -0
  79. package/dist/shared/7mnme5tn.js +8 -0
  80. package/dist/shared/7n7ddwt4.js +6 -0
  81. package/dist/shared/{5j36z8dn.js → 81ebdx9p.js} +39 -70
  82. package/dist/shared/{knmes2kh.js → 8skf0cam.js} +1 -1
  83. package/dist/shared/9a4ae4p8.js +31 -0
  84. package/dist/shared/9y3mmmh1.js +436 -0
  85. package/dist/shared/ab9gmbwy.js +213 -0
  86. package/dist/shared/{f0f1n281.js → ax7qv55k.js} +2 -2
  87. package/dist/shared/{g90m9b0g.js → aytqh5y2.js} +6 -5
  88. package/dist/shared/{vjpnzwjz.js → b5pftnn2.js} +1 -1
  89. package/dist/shared/{ag4c7516.js → b76b8d95.js} +2 -2
  90. package/dist/shared/{vmfkhszw.js → bg3rym3g.js} +33 -26
  91. package/dist/shared/{mb2ycs1p.js → bm22fvzr.js} +15 -15
  92. package/dist/shared/{q3j1tq7a.js → bz84tkzm.js} +148 -23
  93. package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
  94. package/dist/shared/cn957f8d.js +179 -0
  95. package/dist/shared/{gwn6v667.js → cnkky55j.js} +25 -14
  96. package/dist/shared/{ys0xzyaj.js → dkxgzaqd.js} +224 -19
  97. package/dist/shared/dzj09cye.js +10 -0
  98. package/dist/shared/exn3sd90.js +359 -0
  99. package/dist/shared/g6evj1j3.js +66 -0
  100. package/dist/shared/ga9j92qj.js +25 -0
  101. package/dist/shared/{t3g0k88x.js → gs74dbj5.js} +16 -12
  102. package/dist/shared/gzaveazc.js +285 -0
  103. package/dist/shared/{2jd1sn0e.js → hyh73qk6.js} +1 -1
  104. package/dist/shared/{r1fdd0f6.js → je4axnm8.js} +5 -2
  105. package/dist/shared/{1f0xa3cb.js → jvd0mqag.js} +3 -3
  106. package/dist/shared/jznfax0y.js +155 -0
  107. package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
  108. package/dist/shared/{wt5rzv1h.js → kr0jzbw2.js} +5 -5
  109. package/dist/shared/{p6bjzq9q.js → ktz42yez.js} +12 -4
  110. package/dist/shared/{p248q79y.js → m6p12kbr.js} +2 -2
  111. package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
  112. package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
  113. package/dist/shared/{929h19xp.js → mtaszv5a.js} +40 -10
  114. package/dist/shared/{b3awxn7h.js → n816peh1.js} +1 -1
  115. package/dist/shared/nbw1z4yd.js +18 -0
  116. package/dist/shared/{nx9hh281.js → p6qc5gcp.js} +12 -11
  117. package/dist/shared/{pjr6xrm5.js → pbp1ss85.js} +20 -17
  118. package/dist/shared/pt94kz7f.js +6 -0
  119. package/dist/shared/q5c6ngn3.js +13 -0
  120. package/dist/shared/{xq0mvhts.js → rs73fca9.js} +4 -4
  121. package/dist/shared/{r11n8grd.js → sfz1ksn6.js} +7 -4
  122. package/dist/shared/{wynzeggs.js → svncdeh5.js} +6 -6
  123. package/dist/shared/{j60w0dvr.js → tbrvgw6z.js} +57 -38
  124. package/dist/shared/te5as7z7.js +622 -0
  125. package/dist/shared/{ttmg09vd.js → tsvww22q.js} +1 -1
  126. package/dist/shared/{y2t3jktd.js → ttsqgp4p.js} +19 -12
  127. package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
  128. package/dist/shared/{sbdme3vy.js → vb6qfyve.js} +60 -10
  129. package/dist/shared/{5d8t84hg.js → vczs8gd4.js} +14 -14
  130. package/dist/shared/{5yv4k6a6.js → vqrjpcqn.js} +144 -2
  131. package/dist/shared/{3fqwmr09.js → w72kgg4q.js} +4 -4
  132. package/dist/shared/{1z04fa85.js → w79hsckn.js} +12 -57
  133. package/dist/shared/{09p049xa.js → wa07eas9.js} +42 -14
  134. package/dist/shared/{32cnm7kn.js → x933k9a3.js} +74 -38
  135. package/dist/shared/{n076ydsc.js → xhfsfkgk.js} +62 -28
  136. package/dist/shared/xjk7hnn5.js +272 -0
  137. package/dist/shared/{hazqqecq.js → xnxsed62.js} +50 -21
  138. package/dist/shared/y6njgyda.js +249 -0
  139. package/dist/shared/{8etn7d8w.js → z7s6fpxv.js} +1 -1
  140. package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
  141. package/dist/shared/zm0ptry0.js +40 -0
  142. package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
  143. package/dist/shared/zp9fmend.js +145 -0
  144. package/dist/tooling/cli.js +11 -11
  145. package/dist/tooling/migrate/engine.d.ts +3 -2
  146. package/dist/tooling/migrate/index.js +7 -7
  147. package/dist/tooling/testing/index.js +1 -1
  148. package/package.json +4 -2
  149. package/dist/shared/3qnhc7w5.js +0 -38
  150. package/dist/shared/7m88x3e9.js +0 -45
  151. package/dist/shared/8dqhth8c.js +0 -12
  152. package/dist/shared/d5azex6s.js +0 -6
  153. package/dist/shared/j3rkk835.js +0 -99
  154. package/dist/shared/k68eedmy.js +0 -85
  155. package/dist/shared/venqrjna.js +0 -216
  156. package/dist/shared/wxr8cwns.js +0 -6
  157. package/dist/shared/zm0mafk4.js +0 -92
@@ -1,3 +1,11 @@
1
+ import {
2
+ UUIDV7_POSTGRES,
3
+ isPostgresMajor,
4
+ parsePostgresFloor,
5
+ formatPostgresFloor,
6
+ minPostgresDefinition,
7
+ uuidv7NeedsPostgres
8
+ } from "./ga9j92qj.js";
1
9
  import {
2
10
  catalog,
3
11
  enumType,
@@ -5,7 +13,7 @@ import {
5
13
  } from "./ywspezzx.js";
6
14
  import {
7
15
  isRelationCall
8
- } from "./k68eedmy.js";
16
+ } from "./exn3sd90.js";
9
17
  import {
10
18
  encodeText,
11
19
  decodeText
@@ -149,6 +157,7 @@ var SCHEMA_KNOWN = new Set([
149
157
  "defaults",
150
158
  "extensions",
151
159
  "functions",
160
+ "minPostgres",
152
161
  "requires",
153
162
  "tables",
154
163
  "tenancy",
@@ -178,7 +187,7 @@ function schema2(config) {
178
187
  const hooks = collectHooks(tenancy, schemaTraits, config.tables, config.views);
179
188
  const types = readTypes(config.types);
180
189
  const codecs = readCodecs(config.codecs);
181
- const requires = readRequires(config.requires);
190
+ const requires = readFloor(config.minPostgres, config.requires);
182
191
  const idDefault = readIdDefault(config.defaults);
183
192
  const namespace = staticNamespace2("public");
184
193
  const accepted = acceptTables(config.tables);
@@ -203,8 +212,9 @@ function schema2(config) {
203
212
  compileForeignKeys(item, byName, accepted, jobs, edges);
204
213
  }
205
214
  const model = {};
215
+ const scopeFields = tenancy === undefined ? undefined : tenancy.keys !== undefined ? tenancy.keys : [tenancy.key];
206
216
  for (const item of prepared) {
207
- model[item.tsName] = tableModel(item, edges, byName, accepted);
217
+ model[item.tsName] = tableModel(item, edges, byName, accepted, scopeFields);
208
218
  }
209
219
  bindViews(config.views, model, tenancy, tables, casing);
210
220
  let document;
@@ -502,7 +512,7 @@ function compileTable(item, namespace, casing, codecs, requires, idDefault, jobs
502
512
  columnPrimary.push(prepared.sqlName);
503
513
  }
504
514
  if (column.state.defaultSql === "uuidv7()") {
505
- refuseUuidV7(item.name, field, requires);
515
+ refuseUuidV7(requires);
506
516
  }
507
517
  const labels = column.state.enumLabels;
508
518
  if (labels !== undefined) {
@@ -858,7 +868,7 @@ function readCodecs(codecs) {
858
868
  }
859
869
  return { bigint, numeric, timestamps };
860
870
  }
861
- function tableModel(item, edges, byName, accepted) {
871
+ function tableModel(item, edges, byName, accepted, scopeFields) {
862
872
  const primary = [];
863
873
  for (const sqlName of item.primary) {
864
874
  const column = item.bySql.get(sqlName);
@@ -891,7 +901,7 @@ function tableModel(item, edges, byName, accepted) {
891
901
  primary,
892
902
  uniques: item.uniques,
893
903
  columns,
894
- relations: resolveRelations(item, edges, byName, accepted),
904
+ relations: resolveRelations(item, edges, byName, accepted, scopeFields),
895
905
  ...conceal ? { conceal: true } : {},
896
906
  ...item.traits !== undefined ? { traits: item.traits } : {},
897
907
  ...item.provenance.source !== undefined ? { source: item.provenance.source } : {},
@@ -899,10 +909,11 @@ function tableModel(item, edges, byName, accepted) {
899
909
  ...item.presets !== undefined ? { presets: item.presets } : {}
900
910
  };
901
911
  }
902
- function resolveRelations(item, edges, byName, accepted) {
912
+ function resolveRelations(item, edges, byName, accepted, scopeFields) {
903
913
  const raw = item.relationOptions;
904
914
  if (raw === undefined)
905
915
  return [];
916
+ const describe = (table) => byName.get(table);
906
917
  const record = raw;
907
918
  const names = Object.keys(record);
908
919
  const resolved = [];
@@ -913,11 +924,18 @@ function resolveRelations(item, edges, byName, accepted) {
913
924
  seen.add(name);
914
925
  const call = record[name];
915
926
  if (!isRelationCall(call)) {
916
- unavailable(`Table ${item.tsName} relation ${name} is not available yet. one(), many(), and manyThrough() are accepted. morph arrives later.`);
927
+ unavailable(`Table ${item.tsName} relation ${name} is not a relation. one(), many(), manyThrough(), morph(), and morphMany() are accepted.`);
917
928
  }
918
929
  const own = call.resolve;
919
930
  if (own !== undefined) {
920
- resolved.push(own({ owner: item.tsName, name, edges, tables: accepted }));
931
+ resolved.push(own({
932
+ owner: item.tsName,
933
+ name,
934
+ edges,
935
+ tables: accepted,
936
+ describe,
937
+ ...scopeFields === undefined ? {} : { scopeFields }
938
+ }));
921
939
  continue;
922
940
  }
923
941
  if (!byName.has(call.table)) {
@@ -1002,21 +1020,32 @@ function readIdDefault(defaults) {
1002
1020
  return { kind: "client", fill };
1003
1021
  definition('schema() defaults.id must be "uuidv7", "uuidv4", or a client generator.');
1004
1022
  }
1005
- function refuseUuidV7(tableName, field, requires) {
1006
- const declared = Number(/^>=(\d+)$/.exec(requires?.postgres ?? "")?.[1]);
1007
- if (!(declared > 0) || declared >= 18)
1023
+ function refuseUuidV7(requires) {
1024
+ const declared = parsePostgresFloor(requires?.postgres);
1025
+ if (!(declared > 0) || declared >= UUIDV7_POSTGRES)
1008
1026
  return;
1009
- throw new OkmError2("OKM1812", `Column ${tableName}.${field} uses uuidv7(). Set defaults.id to "uuidv4" or a client generator.`, { fix: { summary: "Set defaults.id." } });
1027
+ const sentence = uuidv7NeedsPostgres();
1028
+ throw new OkmError2("OKM1812", sentence, { fix: { summary: sentence } });
1010
1029
  }
1011
- function readRequires(requires) {
1012
- if (requires === undefined) {
1013
- return;
1014
- }
1015
- const postgres = requires.postgres;
1016
- if (postgres !== undefined && postgres.length === 0) {
1017
- definition("schema() requires.postgres must be a version range such as >=17.");
1030
+ function readFloor(minPostgres, requires) {
1031
+ if (minPostgres !== undefined && requires !== undefined) {
1032
+ definition("minPostgres or requires.postgres, not both.");
1018
1033
  }
1019
- return postgres === undefined ? {} : { postgres };
1034
+ if (minPostgres === undefined && requires === undefined)
1035
+ return;
1036
+ let major = minPostgres;
1037
+ if (minPostgres === undefined) {
1038
+ if (typeof requires !== "object" || requires === null || Array.isArray(requires)) {
1039
+ definition(minPostgresDefinition());
1040
+ }
1041
+ const postgres = requires.postgres;
1042
+ if (postgres === undefined)
1043
+ return {};
1044
+ major = typeof postgres === "string" ? parsePostgresFloor(postgres) : NaN;
1045
+ }
1046
+ if (!isPostgresMajor(major))
1047
+ definition(minPostgresDefinition());
1048
+ return { postgres: formatPostgresFloor(major) };
1020
1049
  }
1021
1050
  function readIndex(tableName, call) {
1022
1051
  if (call.columns.length === 0) {
@@ -0,0 +1,249 @@
1
+ import {
2
+ stack2
3
+ } from "./mss6ctgv.js";
4
+ import {
5
+ updateSliceBody2,
6
+ rejectDuplicateTargets2,
7
+ emitSet2,
8
+ Sql2,
9
+ writeSet2,
10
+ rejectMixedSets2,
11
+ readClaim2,
12
+ rejectUpdateKeys2,
13
+ requireFilter2,
14
+ returningOption2,
15
+ expectOf2,
16
+ allowSet2,
17
+ noteGuarded2
18
+ } from "./1w508jbr.js";
19
+ import {
20
+ emitWhere,
21
+ projectExpr,
22
+ quote,
23
+ isRecord,
24
+ fail2
25
+ } from "./67txcrcw.js";
26
+
27
+ // src/runtime/version.ts
28
+ function planVersioned(schema, table, input, options, mods) {
29
+ if (mods.all !== undefined) {
30
+ fail2("OKM1120", `update on ${table.model.name} cannot use .all() with versioned().`, "Pass a per-row list with the version you read for each row.");
31
+ }
32
+ const allow = allowSet2(table, options.allow);
33
+ noteGuarded2(table, allow, "update");
34
+ const column = versionColumn(table);
35
+ const returning = returningOption2(table, options.returning);
36
+ const expect = expectOf2(options, mods);
37
+ if (Array.isArray(input) && input.length === 0) {
38
+ return {
39
+ statements: [],
40
+ outputs: outputsOf(undefined),
41
+ shape: "count",
42
+ expect,
43
+ versioned: { fields: [], sent: [] }
44
+ };
45
+ }
46
+ const rows = readRows(schema, table, input, allow, mods, column);
47
+ const fields = writtenFields(rows);
48
+ const sent = rows.map((row) => row.version);
49
+ const claim = Array.isArray(input) ? undefined : isRecord(input) ? readClaim2(input) : undefined;
50
+ const statement = claim !== undefined ? claimStatement(schema, table, rows[0], claim, column, returning) : targetStatement(schema, table, rows, column, returning);
51
+ const width = statement.params?.length ?? 0;
52
+ if (width > 30000) {
53
+ fail2("OKM1120", `update on ${table.model.name} is too large to check version in one statement.`, "Split the list.");
54
+ }
55
+ return {
56
+ statements: [statement],
57
+ outputs: outputsOf(returning),
58
+ shape: returning === undefined ? "count" : "rows",
59
+ expect,
60
+ versioned: { fields, sent }
61
+ };
62
+ }
63
+ function versionColumn(table) {
64
+ const column = table.columns.get("version");
65
+ if (column === undefined) {
66
+ fail2("OKM1120", `Table ${table.model.name} is versioned and has no version column.`);
67
+ }
68
+ return column;
69
+ }
70
+ function readRows(schema, table, input, allow, mods, column) {
71
+ if (Array.isArray(input)) {
72
+ if (input.length === 0)
73
+ fail2("OKM1120", "update set is empty.");
74
+ const rows = input.map((item) => readRow(schema, table, item, allow, mods, column, true));
75
+ rejectDuplicateTargets2(table, rows);
76
+ rejectMixedSets2(rows);
77
+ return rows;
78
+ }
79
+ return [readRow(schema, table, input, allow, mods, column, false)];
80
+ }
81
+ function readRow(schema, table, input, allow, mods, column, row) {
82
+ if (!isRecord(input))
83
+ fail2("OKM1121", "update expects { where, set, version } or a list of rows.");
84
+ rejectUpdateKeys2(input, row);
85
+ if (!Object.hasOwn(input, "version")) {
86
+ fail2("OKM1120", `update on ${table.model.name} needs the version you read.`, "Pass version from the row you read. If this write conflicts, reread and retry.");
87
+ }
88
+ const version = readVersion(input.version, table.model.name, column);
89
+ const set = writeSet2(table, input.set, allow, schema.tenancy);
90
+ if (Object.keys(set).length === 0)
91
+ fail2("OKM1120", "update set is empty.");
92
+ refusePath(schema, table, set);
93
+ const where = input.where !== undefined ? input.where : input.id !== undefined ? { id: input.id } : undefined;
94
+ requireFilter2(table, where, mods, "update");
95
+ return { where: stack2(where, mods.presets), set, version };
96
+ }
97
+ function readVersion(value, table, column) {
98
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
99
+ fail2("OKM1121", `version on ${table} must be an integer.`, "Pass the version you read.");
100
+ }
101
+ column.encode(value);
102
+ return value;
103
+ }
104
+ function refusePath(schema, table, set) {
105
+ if (schema.tenancy?.isPath?.(table.model.name) !== true)
106
+ return;
107
+ const field = schema.tenancy.pathOf?.(table.model.name)?.[0]?.localField;
108
+ if (field === undefined || !Object.hasOwn(set, field))
109
+ return;
110
+ fail2("OKM1120", `update on ${table.model.name} cannot change ${field} and check version in one write.`, "Point it at a parent in a later update.");
111
+ }
112
+ function writtenFields(rows) {
113
+ const names = [];
114
+ for (const row of rows) {
115
+ for (const key of Object.keys(row.set))
116
+ if (!names.includes(key))
117
+ names.push(key);
118
+ }
119
+ return names;
120
+ }
121
+ function targetStatement(schema, table, rows, column, returning) {
122
+ const sql = new Sql2;
123
+ sql.text("with ");
124
+ for (let index = 0;index < rows.length; index += 1) {
125
+ const row = rows[index];
126
+ if (row === undefined)
127
+ continue;
128
+ if (index > 0)
129
+ sql.text(", ");
130
+ sql.text("m");
131
+ sql.text(String(index));
132
+ sql.text(" as (select s.ctid as tid, s.tableoid as toid, s.");
133
+ sql.text(quote(column.sql));
134
+ sql.text(" as okm_version from ");
135
+ sql.text(quote(table.model.sql));
136
+ sql.text(" as s");
137
+ emitWhere(schema, table, row.where, sql.sink(), "s", 0);
138
+ sql.text(" for update of s)");
139
+ }
140
+ sql.text(", gate as (select count(*)::int as n from (");
141
+ for (let index = 0;index < rows.length; index += 1) {
142
+ const row = rows[index];
143
+ if (row === undefined)
144
+ continue;
145
+ if (index > 0)
146
+ sql.text(" union all ");
147
+ sql.text("select 1 from m");
148
+ sql.text(String(index));
149
+ sql.text(" where okm_version is distinct from ");
150
+ sql.param(column.encode(row.version), column.dataType);
151
+ }
152
+ sql.text(") as okm_diff), updated as (");
153
+ updateSliceBody2(schema, table, rows, sql, true, {
154
+ afterWhere(body, index) {
155
+ const row = rows[index];
156
+ if (row === undefined)
157
+ return;
158
+ body.text(" and t.");
159
+ body.text(quote(column.sql));
160
+ body.text(" = ");
161
+ body.param(column.encode(row.version), column.dataType);
162
+ },
163
+ afterSet(body) {
164
+ bump(body, column);
165
+ }
166
+ });
167
+ sql.text(" and (select n from gate) = 0");
168
+ closeUpdated(sql, returning, "gate");
169
+ return sql.statement();
170
+ }
171
+ function claimStatement(schema, table, row, limit, column, returning) {
172
+ if (row === undefined)
173
+ fail2("OKM1120", "update set is empty.");
174
+ const sql = new Sql2;
175
+ sql.text("with claimed as (select s.tableoid as toid, s.ctid as tid from ");
176
+ sql.text(quote(table.model.sql));
177
+ sql.text(" as s");
178
+ emitWhere(schema, table, row.where, sql.sink(), "s", 0);
179
+ sql.text(" and s.");
180
+ sql.text(quote(column.sql));
181
+ sql.text(" = ");
182
+ sql.param(column.encode(row.version), column.dataType);
183
+ sql.text(" for update of s skip locked limit ");
184
+ sql.param(String(limit), "integer");
185
+ sql.text("), stale_free as (select 1 as hit from ");
186
+ sql.text(quote(table.model.sql));
187
+ sql.text(" as s");
188
+ emitWhere(schema, table, row.where, sql.sink(), "s", 0);
189
+ sql.text(" and s.");
190
+ sql.text(quote(column.sql));
191
+ sql.text(" is distinct from ");
192
+ sql.param(column.encode(row.version), column.dataType);
193
+ sql.text(" for update of s skip locked limit 1), updated as (update ");
194
+ sql.text(quote(table.model.sql));
195
+ sql.text(" as t set ");
196
+ emitSet2(sql, table, row.set, "t");
197
+ bump(sql, column);
198
+ sql.text(" where (t.tableoid, t.ctid) in (select toid, tid from claimed)");
199
+ closeUpdated(sql, returning, "claim");
200
+ return sql.statement();
201
+ }
202
+ function bump(sql, column) {
203
+ sql.text(", ");
204
+ sql.text(quote(column.sql));
205
+ sql.text(" = t.");
206
+ sql.text(quote(column.sql));
207
+ sql.text(" + 1");
208
+ }
209
+ function closeUpdated(sql, returning, source) {
210
+ const stale = source === "gate" ? "(select n from gate)" : "(case when (select count(*) from updated) > 0 then 0 else (select count(*)::int from stale_free) end)";
211
+ if (returning === undefined || returning.length === 0) {
212
+ sql.text(" returning 1) select ");
213
+ sql.text(stale);
214
+ sql.text(", (select count(*)::int from updated)");
215
+ return;
216
+ }
217
+ sql.text(" returning t.ctid as okm_tid");
218
+ for (let index = 0;index < returning.length; index += 1) {
219
+ const column = returning[index];
220
+ if (column === undefined)
221
+ continue;
222
+ sql.text(", ");
223
+ sql.text(projectExpr(`t.${quote(column.sql)}`, column.dataType));
224
+ sql.text(" as okm_");
225
+ sql.text(String(index));
226
+ }
227
+ sql.text(") select ");
228
+ sql.text(stale);
229
+ sql.text(", case when u.okm_tid is null then 0 else 1 end");
230
+ for (let index = 0;index < returning.length; index += 1) {
231
+ sql.text(", u.okm_");
232
+ sql.text(String(index));
233
+ }
234
+ sql.text(" from (select 1) as okm_one left join updated u on true");
235
+ }
236
+ function outputsOf(columns) {
237
+ const list = columns ?? [];
238
+ return {
239
+ fields: list.map((column, index) => ({
240
+ key: column.field,
241
+ at: index + 2,
242
+ decode: column.decode
243
+ })),
244
+ includes: []
245
+ };
246
+ }
247
+ export {
248
+ planVersioned
249
+ };
@@ -39,7 +39,7 @@ async function refreshView(session, name, concurrently) {
39
39
  throw error;
40
40
  }
41
41
  } catch (error) {
42
- const { mapPostgresError } = await import("./d5azex6s.js");
42
+ const { mapPostgresError } = await import("./63qtkrca.js");
43
43
  const mapped = mapPostgresError(error, {
44
44
  ...host.http !== undefined ? { http: host.http } : {},
45
45
  ...host.includeValues === true ? { includeValues: true } : {},
@@ -18,6 +18,7 @@ var FAMILIES = {
18
18
  hasAnyKey: ["jsonb"],
19
19
  path: ["json", "jsonb"],
20
20
  matches: ["tsvector"],
21
+ relevance: ["tsvector"],
21
22
  "json.set": ["json", "jsonb"],
22
23
  "arr.append": ["array"],
23
24
  "arr.remove": ["array"]
@@ -53,7 +54,7 @@ var ACCEPTED = {
53
54
  jsonb: ["eq", "not", "contains", "containedBy", "hasKey", "hasAnyKey", "path", "json.set"],
54
55
  json: ["eq", "not", "path", "json.set"],
55
56
  range: ["eq", "not", "lt", "lte", "gt", "gte", "contains", "containedBy", "overlaps"],
56
- tsvector: ["eq", "not", "matches"],
57
+ tsvector: ["eq", "not", "matches", "relevance"],
57
58
  scalar: ["eq", "not", "lt", "lte", "gt", "gte", "between", "inList", "notIn", "inc"]
58
59
  };
59
60
  var SAFE_TYPE = /^[A-Za-z_][A-Za-z0-9_]*(\(\d+\))?(\[\])*$/;
@@ -81,7 +82,7 @@ function assertOperatorFits(column, name) {
81
82
  if (families.includes(columnFamily(column.dataType)))
82
83
  return;
83
84
  const accepted = ACCEPTED[columnFamily(column.dataType)];
84
- const search = name === "matches" && columnFamily(column.dataType) === "text" ? " Text search needs a tsvector column." : "";
85
+ const search = (name === "matches" || name === "relevance") && columnFamily(column.dataType) === "text" ? " Search needs a column built for search, not a plain text column." : "";
85
86
  throw new OkmError2("OKM1124", `Operator ${name} does not apply to ${column.dataType} column ${column.field}. Accepted operators: ${accepted.join(", ")}.${search}`, { fix: { summary: `Use one of: ${accepted.join(", ")}.` } });
86
87
  }
87
88
  function sqlType(dataType, column) {
@@ -110,7 +111,7 @@ function assertBoundText(value, role) {
110
111
  }
111
112
  function assertRegconfig(config) {
112
113
  if (!REGCONFIG.test(config)) {
113
- throw new OkmError2("OKM1122", `Text search config ${config} must be a regconfig name such as english or pg_catalog.simple.`, { fix: { summary: "Pass a regconfig name. Quotes and extra clauses are not accepted." } });
114
+ throw new OkmError2("OKM1122", `Language ${config} is not a text search language. Pass a name such as english.`, { fix: { summary: "Pass a language name such as english." } });
114
115
  }
115
116
  }
116
117
  function textArray(values, role) {
@@ -0,0 +1,40 @@
1
+ import {
2
+ isConnectionLost
3
+ } from "./cnkky55j.js";
4
+ import {
5
+ rejectClosed
6
+ } from "./kb2sdhfb.js";
7
+
8
+ // src/adapters/pg/reserved.ts
9
+ var RESET_ALL = "RESET ALL";
10
+ var UNLOCK = "SELECT pg_advisory_unlock_all()";
11
+ async function resetSession2(depth, run) {
12
+ if (depth > 0)
13
+ await run("ROLLBACK").catch(() => {
14
+ return;
15
+ });
16
+ try {
17
+ await run(RESET_ALL);
18
+ await run(UNLOCK);
19
+ } catch {
20
+ await run("ROLLBACK").catch(() => {
21
+ return;
22
+ });
23
+ await run(RESET_ALL);
24
+ await run(UNLOCK);
25
+ }
26
+ }
27
+ async function resetQueried2(session) {
28
+ await resetSession2(session.inTransaction() ? 1 : 0, (text) => text === "ROLLBACK" ? session.rollback() : session.query(text, undefined, undefined));
29
+ }
30
+ function refuseWhenLost2(lost, run) {
31
+ if (lost.on)
32
+ return rejectClosed();
33
+ return run().catch((error) => {
34
+ if (isConnectionLost(error))
35
+ lost.on = true;
36
+ throw error;
37
+ });
38
+ }
39
+
40
+ export { resetSession2, resetQueried2, refuseWhenLost2 };
@@ -13,6 +13,9 @@ var RESERVED_PRESETS = new Set([
13
13
  "insert",
14
14
  "update",
15
15
  "delete",
16
+ "descendants",
17
+ "ancestors",
18
+ "sync",
16
19
  "archive",
17
20
  "restore",
18
21
  "withArchived",
@@ -0,0 +1,145 @@
1
+ import {
2
+ DriverError2
3
+ } from "./cm3w0ywp.js";
4
+ import {
5
+ armDriverError,
6
+ send,
7
+ connectClient
8
+ } from "./w79hsckn.js";
9
+ import {
10
+ resetSession2
11
+ } from "./zm0ptry0.js";
12
+ import {
13
+ cursorStream
14
+ } from "./7kms6fvj.js";
15
+ import {
16
+ isConnectionLost
17
+ } from "./cnkky55j.js";
18
+ import {
19
+ WireSession
20
+ } from "./1qa0qajz.js";
21
+ import {
22
+ rejectClosed,
23
+ runCall
24
+ } from "./kb2sdhfb.js";
25
+
26
+ // src/adapters/pg/nodepostgres-extra.ts
27
+ async function checkout(held) {
28
+ const { pool, counters, named, isClosed } = held;
29
+ if (isClosed())
30
+ return rejectClosed();
31
+ const client = await connectClient(pool, held.acquireMs, counters);
32
+ counters.reserved += 1;
33
+ let lost = false;
34
+ const onError = () => {
35
+ lost = true;
36
+ };
37
+ const events = client;
38
+ events.on("error", onError);
39
+ const local = new Set;
40
+ const session = new WireSession((text, params) => {
41
+ const pending = send(client, text, params, named, client);
42
+ const guarded = pending.catch((error) => {
43
+ if (isConnectionLost(error) || lost) {
44
+ lost = true;
45
+ if (isConnectionLost(error))
46
+ throw error;
47
+ throw Object.assign(new DriverError2("CONNECTION_CLOSED", { cause: error }), {
48
+ code: "CONNECTION_CLOSED"
49
+ });
50
+ }
51
+ throw error;
52
+ });
53
+ guarded.cancel = () => {
54
+ pending.cancel?.();
55
+ };
56
+ return guarded;
57
+ }, held.notices, isClosed, true, () => {
58
+ counters.reservedBusy += 1;
59
+ }, () => {
60
+ counters.reservedBusy = Math.max(0, counters.reservedBusy - 1);
61
+ }, local);
62
+ const guard = (run) => lost ? rejectClosed() : run();
63
+ let released = false;
64
+ return {
65
+ execute: (text, params, options) => guard(() => runCall(isClosed(), options, (watch) => session.query(text, params, watch))),
66
+ batch: (statements, options) => guard(() => runCall(isClosed(), options, async (watch) => {
67
+ const { runAtomicBatch } = await import("./b76b8d95.js");
68
+ return runAtomicBatch(session, statements, watch);
69
+ })),
70
+ cancel() {
71
+ session.cancel();
72
+ },
73
+ async release() {
74
+ if (released)
75
+ return;
76
+ released = true;
77
+ try {
78
+ if (!lost)
79
+ await reset(session, client);
80
+ } finally {
81
+ counters.reserved = Math.max(0, counters.reserved - 1);
82
+ events.removeListener("error", onError);
83
+ client.release(lost);
84
+ }
85
+ }
86
+ };
87
+ }
88
+ async function reset(session, client) {
89
+ await resetSession2(session.depth(), (text) => client.query(text));
90
+ }
91
+ async function listen(held, channel, onNotify) {
92
+ const { pool, counters } = held;
93
+ const client = await connectClient(pool, held.acquireMs, counters);
94
+ counters.reserved += 1;
95
+ const quoted = quoteIdent(channel);
96
+ const onNotification = (message) => {
97
+ if (message.channel === channel)
98
+ onNotify(message.payload ?? "");
99
+ };
100
+ client.on("notification", onNotification);
101
+ let released = false;
102
+ const release = (dead) => {
103
+ if (released)
104
+ return;
105
+ released = true;
106
+ client.removeListener("notification", onNotification);
107
+ client.removeListener("error", release);
108
+ counters.reserved = Math.max(0, counters.reserved - 1);
109
+ client.release(Boolean(dead));
110
+ };
111
+ armDriverError(client, release);
112
+ try {
113
+ await client.query(`LISTEN ${quoted}`);
114
+ } catch (error) {
115
+ release(false);
116
+ throw error;
117
+ }
118
+ return async () => {
119
+ if (released)
120
+ return;
121
+ try {
122
+ await client.query(`UNLISTEN ${quoted}`);
123
+ } finally {
124
+ release(false);
125
+ }
126
+ };
127
+ }
128
+ function streamRows(checkout, text, params) {
129
+ return async function* () {
130
+ const connection = await checkout();
131
+ try {
132
+ yield* cursorStream((statement, values) => connection.execute(statement, values), text, params);
133
+ } finally {
134
+ await connection.release();
135
+ }
136
+ }();
137
+ }
138
+ function quoteIdent(name) {
139
+ return `"${name.replaceAll('"', '""')}"`;
140
+ }
141
+ export {
142
+ checkout,
143
+ listen,
144
+ streamRows
145
+ };