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,10 +1,10 @@
1
1
  import {
2
2
  isConnectionSqlstate,
3
3
  isConnectionErrno
4
- } from "./gwn6v667.js";
4
+ } from "./cnkky55j.js";
5
5
  import {
6
6
  createClient
7
- } from "./j60w0dvr.js";
7
+ } from "./tbrvgw6z.js";
8
8
  import {
9
9
  OkmError2
10
10
  } from "./52szzakm.js";
@@ -506,7 +506,7 @@ function routePool(handle) {
506
506
  execute: async (text, params, options) => {
507
507
  if (handle.closed)
508
508
  closed();
509
- const choice = await choose(handle, text, options?.route);
509
+ const choice = await resolve(handle, text, options);
510
510
  const result = await attempt(handle, choice, (endpoint) => endpoint.pool.execute(text, params, strip(options)));
511
511
  if (choice.op === "write")
512
512
  await noteWrite(handle, primary.pool);
@@ -628,7 +628,7 @@ function force(handle, router, route) {
628
628
  async function readOnlyUnit(handle, text, params, prelude, options) {
629
629
  if (handle.closed)
630
630
  closed();
631
- const choice = await choose(handle, text, options?.route);
631
+ const choice = await resolve(handle, text, options);
632
632
  return attempt(handle, choice, async (endpoint) => {
633
633
  if (endpoint.pool.reserve === undefined)
634
634
  replicaReserve();
@@ -764,7 +764,7 @@ async function attempt(handle, choice, run) {
764
764
  await callGuard(choice.endpoint);
765
765
  return await tracked(choice.endpoint, choice.op === "read", () => run(choice.endpoint));
766
766
  } catch (error) {
767
- if (choice.op !== "read" || !isUnreachable(error))
767
+ if (choice.pinned === true || choice.op !== "read" || !isUnreachable(error))
768
768
  throw error;
769
769
  choice.endpoint.generation += 1;
770
770
  const next = await retryOf(handle, choice);
@@ -817,9 +817,7 @@ function unreachableNode(node) {
817
817
  return true;
818
818
  }
819
819
  }
820
- if (!(node instanceof Error))
821
- return false;
822
- return node.message.includes("ECONNREFUSED") || node.message.includes("ECONNRESET") || node.message.includes("CONNECTION_CLOSED") || node.message.includes("terminating connection") || node.message.includes("The pool is closed");
820
+ return false;
823
821
  }
824
822
  async function tracked(endpoint, time, run) {
825
823
  const replica = endpoint.role === "replica";
@@ -1109,13 +1107,45 @@ function noteFailure(endpoint) {
1109
1107
  endpoint.circuit = "open";
1110
1108
  }
1111
1109
  function strip(options) {
1112
- if (options === undefined || options.route === undefined)
1110
+ if (options === undefined)
1111
+ return;
1112
+ if (!("route" in options) && !("pin" in options))
1113
1113
  return options;
1114
- const { route: _route, ...rest } = options;
1114
+ const bag = options;
1115
+ const { route: _route, pin: _pin, ...rest } = bag;
1115
1116
  if (rest.signal === undefined && rest.timeout === undefined)
1116
1117
  return;
1117
1118
  return rest;
1118
1119
  }
1120
+ async function resolve(handle, text, options) {
1121
+ const pin = taken(options);
1122
+ if (pin?.name !== undefined)
1123
+ return held(handle, pin.name);
1124
+ const choice = await choose(handle, text, options?.route);
1125
+ if (pin !== undefined && choice.op === "read") {
1126
+ pin.name = choice.endpoint.name;
1127
+ return { ...choice, pinned: true };
1128
+ }
1129
+ return choice;
1130
+ }
1131
+ function taken(options) {
1132
+ if (options === undefined || !("pin" in options))
1133
+ return;
1134
+ const pin = options.pin;
1135
+ if (typeof pin !== "object" || pin === null)
1136
+ return;
1137
+ return pin;
1138
+ }
1139
+ function held(handle, name) {
1140
+ for (const endpoint of handle.endpoints) {
1141
+ if (endpoint.name !== name)
1142
+ continue;
1143
+ return { endpoint, op: "read", reason: `stream:${name}`, pinned: true };
1144
+ }
1145
+ throw new OkmError2("OKM1120", `stream() stays on ${name}. That target is not in this topology.`, {
1146
+ fix: { summary: "The first batch chose this target. Later batches do not move." }
1147
+ });
1148
+ }
1119
1149
  async function noteWrite(handle, runner) {
1120
1150
  if (!tracks(handle))
1121
1151
  return;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isRecord,
3
3
  orFail
4
- } from "./2z7wv5tj.js";
4
+ } from "./67txcrcw.js";
5
5
  import {
6
6
  isOperator,
7
7
  operatorName,
@@ -0,0 +1,18 @@
1
+ // src/dialects/pg/ops/bucket.ts
2
+ var RUNTIME = Symbol.for("okmodel.bucket");
3
+ function bucket2(column, unit, options) {
4
+ const spec = options ?? { as: undefined, tz: undefined, weekStart: undefined };
5
+ return {
6
+ [RUNTIME]: true,
7
+ column,
8
+ unit,
9
+ as: spec.as,
10
+ tz: spec.tz,
11
+ weekStart: spec.weekStart
12
+ };
13
+ }
14
+ function isBucket(value) {
15
+ return typeof value === "object" && value !== null && RUNTIME in value;
16
+ }
17
+
18
+ export { bucket2, isBucket };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  open2
3
- } from "./wkme6tep.js";
3
+ } from "./14vx95q4.js";
4
4
  import {
5
5
  startupHash2
6
6
  } from "./qq3899ht.js";
@@ -14,12 +14,12 @@ import {
14
14
  provisionMark,
15
15
  expandProvisioned,
16
16
  installSnapshot
17
- } from "./p248q79y.js";
17
+ } from "./m6p12kbr.js";
18
18
  import {
19
19
  assertCreateRole,
20
20
  currentUser,
21
21
  roleExists
22
- } from "./knmes2kh.js";
22
+ } from "./8skf0cam.js";
23
23
  import {
24
24
  projectPath,
25
25
  loadMigrations,
@@ -30,7 +30,7 @@ import {
30
30
  projectHead,
31
31
  loadBuiltSchema,
32
32
  loadConfig
33
- } from "./t3g0k88x.js";
33
+ } from "./gs74dbj5.js";
34
34
  import {
35
35
  changesRole,
36
36
  batchSizeField,
@@ -41,7 +41,11 @@ import {
41
41
  assertDirectConnection,
42
42
  assertStableBackend,
43
43
  selectTarget
44
- } from "./ttmg09vd.js";
44
+ } from "./tsvww22q.js";
45
+ import {
46
+ UUIDV7_POSTGRES,
47
+ uuidv7NeedsPostgres
48
+ } from "./ga9j92qj.js";
45
49
  import {
46
50
  OkmError2
47
51
  } from "./52szzakm.js";
@@ -70,14 +74,11 @@ async function assertUuidV7Available(connection, migrations) {
70
74
  const row = result.rows[0];
71
75
  const major = Math.floor(Number(row?.[0] ?? "0") / 1e4);
72
76
  const defined = row?.[1] !== null && row?.[1] !== undefined;
73
- if (major >= 18 || defined)
77
+ if (major >= UUIDV7_POSTGRES || defined)
74
78
  return;
75
79
  const where = found.column === undefined ? "A column" : `Column ${found.column}`;
76
- throw new OkmError2("OKM1812", `${where} has a uuidv7() default (migration ${found.migrationId}, step ${String(found.stepIndex)}), and the server is PostgreSQL ${String(major)}. uuidv7() arrives in PostgreSQL 18. Nothing was changed.`, {
77
- fix: {
78
- summary: 'Either run PostgreSQL 18 and declare schema({ requires: { postgres: ">=18" } }), or use t.id({ default: "uuidv4" }) (or schema({ defaults: { id: "uuidv4" } })), which uses gen_random_uuid() and works on PostgreSQL 13 and newer. Then delete the migration that was not applied and generate it again.'
79
- }
80
- });
80
+ const message = `${where} has a uuidv7() default (migration ${found.migrationId}, step ${String(found.stepIndex)}), and the server is PostgreSQL ${String(major)}. ${uuidv7NeedsPostgres()} Nothing was changed.`;
81
+ throw new OkmError2("OKM1812", message, { fix: { summary: uuidv7NeedsPostgres() } });
81
82
  }
82
83
  function columnOf(sql) {
83
84
  const table = TABLE.exec(sql)?.[1];
@@ -3,7 +3,7 @@ import {
3
3
  readHandle,
4
4
  readCall,
5
5
  attachHttp
6
- } from "./j60w0dvr.js";
6
+ } from "./tbrvgw6z.js";
7
7
  import {
8
8
  selectedColumns,
9
9
  parseOrder,
@@ -14,8 +14,8 @@ import {
14
14
  list,
15
15
  isRecord,
16
16
  registerFailFix,
17
- fail
18
- } from "./2z7wv5tj.js";
17
+ fail2
18
+ } from "./67txcrcw.js";
19
19
  import {
20
20
  OkmError2,
21
21
  throwNamed2
@@ -34,21 +34,24 @@ var OPTIONS = [
34
34
  "signal",
35
35
  "timeout"
36
36
  ];
37
- function build(session, table, options, mods, view) {
37
+ function build3(session, table, options, mods, view, pin) {
38
38
  try {
39
- return plan(session, table, options, mods, view);
39
+ return plan(session, table, options, mods, view, pin);
40
40
  } catch (error) {
41
41
  throw error instanceof OkmError2 ? attachHttp(session.http, error) : error;
42
42
  }
43
43
  }
44
- function plan(session, table, options, mods, view) {
44
+ function plan(session, table, options, mods, view, pin) {
45
45
  const record = isRecord(options) ? options : {};
46
+ if (Object.hasOwn(record, "search")) {
47
+ fail2("OKM1120", "page() does not take search in this version. Use find({ search, limit }) for a ranked list.", "Ranked pages are later. find({ search, limit }) returns one ranked list.");
48
+ }
46
49
  rejectKeys(record, OPTIONS, "page");
47
50
  const indexed = indexes(session.schema).get(table);
48
51
  if (indexed === undefined)
49
- fail("OKM1120", `Table ${table} is not in the schema.`);
52
+ fail2("OKM1120", `Table ${table} is not in the schema.`);
50
53
  if (record.limit === undefined)
51
- fail("OKM1101", "page() needs a limit.");
54
+ fail2("OKM1101", "page() needs a limit.");
52
55
  const size = readLimit(record.limit);
53
56
  if (size < 1) {
54
57
  throw new OkmError2("invalid", "page() limit must be at least 1.", { kind: "invalid" });
@@ -73,7 +76,8 @@ function plan(session, table, options, mods, view) {
73
76
  timeout: record.timeout,
74
77
  route: record.route
75
78
  }, undefined, session.scope, session.schema.model[table], session.schema, view),
76
- ...after !== undefined ? { after } : {}
79
+ ...after !== undefined ? { after } : {},
80
+ ...pin !== undefined ? { pin } : {}
77
81
  };
78
82
  return readHandle(session, table, call, mods, async (compiled, rows) => {
79
83
  const items = await decodeRows(compiled, rows, table);
@@ -92,7 +96,7 @@ function plan(session, table, options, mods, view) {
92
96
  }
93
97
  function orderKeys(table, orderBy) {
94
98
  if (orderBy !== undefined && !isRecord(orderBy)) {
95
- fail("OKM1120", "orderBy must be an object of fields.");
99
+ fail2("OKM1120", "orderBy must be an object of fields.");
96
100
  }
97
101
  const keys = [];
98
102
  for (const field of Object.keys(orderBy ?? {})) {
@@ -103,7 +107,7 @@ function orderKeys(table, orderBy) {
103
107
  keys.push({ column, ...parseOrder(field, orderBy?.[field]) });
104
108
  }
105
109
  if (table.model.primary.length === 0) {
106
- fail("OKM1120", `page() needs a primary key on ${table.model.name} to break ties.`);
110
+ fail2("OKM1120", `page() needs a primary key on ${table.model.name} to break ties.`);
107
111
  }
108
112
  for (const field of table.model.primary) {
109
113
  const column = table.columns.get(field);
@@ -181,17 +185,16 @@ function readCursor(token, signature, count) {
181
185
  }
182
186
  }
183
187
  if (!Array.isArray(parsed) || typeof parsed[0] !== "string") {
184
- fail("OKM1130", "after is not a cursor that page() returned.");
188
+ fail2("OKM1130", "after is not a cursor that page() returned.");
185
189
  }
186
190
  if (parsed[0] !== signature) {
187
- fail("OKM1130", `The cursor was made for another order: ${parsed[0]}. This page orders by ${signature}.`);
191
+ fail2("OKM1130", `The cursor was made for another order: ${parsed[0]}. This page orders by ${signature}.`);
188
192
  }
189
193
  const values = parsed.slice(1);
190
194
  if (values.length !== count || !values.every((value) => value === null || typeof value === "string")) {
191
- fail("OKM1130", "after is not a cursor that page() returned.");
195
+ fail2("OKM1130", "after is not a cursor that page() returned.");
192
196
  }
193
197
  return values;
194
198
  }
195
- export {
196
- build
197
- };
199
+
200
+ export { build3 };
@@ -0,0 +1,6 @@
1
+ import {
2
+ build3
3
+ } from "./pbp1ss85.js";
4
+ export {
5
+ build3 as build
6
+ };
@@ -0,0 +1,13 @@
1
+ import {
2
+ fail2
3
+ } from "./67txcrcw.js";
4
+
5
+ // src/runtime/result-name.ts
6
+ var PROTOTYPE_KEYS = ",__proto__,constructor,toString,hasOwnProperty,valueOf,isPrototypeOf,propertyIsEnumerable,toLocaleString,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,then,";
7
+ function refusePrototypeKey(name, where) {
8
+ if (!PROTOTYPE_KEYS.includes(`,${name},`))
9
+ return;
10
+ fail2("OKM1120", `${where} ${name} is a prototype key. Use another name for the result.`);
11
+ }
12
+
13
+ export { refusePrototypeKey };
@@ -1,13 +1,13 @@
1
1
  import"./qq3899ht.js";
2
2
  import"./n442h54c.js";
3
- import"./wkme6tep.js";
3
+ import"./14vx95q4.js";
4
4
  import {
5
5
  projectPath,
6
6
  loadConfig
7
- } from "./t3g0k88x.js";
7
+ } from "./gs74dbj5.js";
8
8
  import {
9
9
  listTargets
10
- } from "./ttmg09vd.js";
10
+ } from "./tsvww22q.js";
11
11
  import"./9s0ypp87.js";
12
12
 
13
13
  // src/tooling/migrate/dev.ts
@@ -20,7 +20,7 @@ async function devProject(cwd) {
20
20
  `;
21
21
  const directory = projectPath(cwd, config.out ?? ".okm", "dev-db");
22
22
  mkdirSync(directory, { recursive: true });
23
- const { open } = await import("./g90m9b0g.js");
23
+ const { open } = await import("./aytqh5y2.js");
24
24
  const pool = await open({ dataDir: directory });
25
25
  try {
26
26
  await pool.execute("select 1");
@@ -3,10 +3,10 @@ import {
3
3
  readHandle,
4
4
  readCall,
5
5
  attachHttp
6
- } from "./j60w0dvr.js";
6
+ } from "./tbrvgw6z.js";
7
7
  import {
8
- fail
9
- } from "./2z7wv5tj.js";
8
+ fail2
9
+ } from "./67txcrcw.js";
10
10
  import {
11
11
  OkmError2,
12
12
  throwNamed2
@@ -35,13 +35,16 @@ function plan(session, table, options, mods, view) {
35
35
  }
36
36
  });
37
37
  }
38
+ if (lock === "skip") {
39
+ fail2("OKM1120", 'lock: "skip" claims rows on update. A read uses lock: "update" and wait: "skip".', 'Pass lock: "update" and wait: "skip" inside tx(). An update can claim rows on its own.');
40
+ }
38
41
  if (session.tx === undefined) {
39
42
  throw new OkmError2("OKM1830", "A row lock needs a transaction. find was called outside tx().", {
40
43
  fix: { summary: "Move the find into tx(): the lock lasts until the transaction ends." }
41
44
  });
42
45
  }
43
46
  if (lock === undefined)
44
- fail("OKM1121", "wait needs lock: pass lock: update or lock: share.");
47
+ fail2("OKM1121", "wait needs lock: pass lock: update or lock: share.");
45
48
  if (typeof lock !== "string" || !LOCKS.includes(lock)) {
46
49
  throwNamed2("OKM1120", shown(lock), LOCKS, `lock must be one of: ${LOCKS.join(", ")}.`);
47
50
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  open2
3
- } from "./wkme6tep.js";
3
+ } from "./14vx95q4.js";
4
4
  import"./qq3899ht.js";
5
5
  import"./n442h54c.js";
6
6
  import {
@@ -14,20 +14,20 @@ import {
14
14
  import {
15
15
  expandProvisioned,
16
16
  provisionHistoryIsKnown
17
- } from "./p248q79y.js";
18
- import"./knmes2kh.js";
19
- import"./vjpnzwjz.js";
17
+ } from "./m6p12kbr.js";
18
+ import"./8skf0cam.js";
19
+ import"./b5pftnn2.js";
20
20
  import {
21
21
  projectPath,
22
22
  loadMigrations,
23
23
  loadConfig
24
- } from "./t3g0k88x.js";
24
+ } from "./gs74dbj5.js";
25
25
  import {
26
26
  sessionFailure,
27
27
  finishQuiet,
28
28
  assertTargetPolicy,
29
29
  listTargets
30
- } from "./ttmg09vd.js";
30
+ } from "./tsvww22q.js";
31
31
  import"./9s0ypp87.js";
32
32
  import {
33
33
  OkmError2
@@ -6,8 +6,9 @@ import {
6
6
  compileCall,
7
7
  decodeResult,
8
8
  logicalIntent,
9
- appliedRules
10
- } from "./2z7wv5tj.js";
9
+ appliedRules,
10
+ rejectKeys
11
+ } from "./67txcrcw.js";
11
12
  import {
12
13
  OkmError2,
13
14
  safe2,
@@ -85,7 +86,7 @@ function openClient(session) {
85
86
  },
86
87
  close,
87
88
  connected: session.connected,
88
- tx: (...args) => import("./5d8t84hg.js").then((mod) => mod.tx(session, args)),
89
+ tx: (...args) => import("./vczs8gd4.js").then((mod) => mod.tx(session, args)),
89
90
  batch: (ops, options) => batchHandle(session, ops, options),
90
91
  ...session.tx?.extras
91
92
  };
@@ -120,7 +121,7 @@ function tableApi(session, table, view, uses) {
120
121
  const api = {
121
122
  find(options = {}) {
122
123
  if ("lock" in options) {
123
- return lazyRead(session, () => import("./r11n8grd.js"), table, options, base, view);
124
+ return lazyRead(session, () => import("./sfz1ksn6.js"), table, options, base, view);
124
125
  }
125
126
  return start(session, "find", table, options, base, view);
126
127
  },
@@ -134,10 +135,10 @@ function tableApi(session, table, view, uses) {
134
135
  return start(session, "exists", table, options, base, view);
135
136
  },
136
137
  page(options) {
137
- return lazyRead(session, () => import("./pjr6xrm5.js"), table, options, base, view);
138
+ return lazyRead(session, () => import("./pt94kz7f.js"), table, options, base, view);
138
139
  },
139
140
  aggregate(options = {}) {
140
- return lazyRead(session, () => import("./venqrjna.js"), table, options, base, view);
141
+ return lazyRead(session, () => import("./1est4ezg.js"), table, options, base, view);
141
142
  },
142
143
  insert(data, options = {}) {
143
144
  return writeHandle(session, "insert", table, data, options, mods);
@@ -149,6 +150,10 @@ function tableApi(session, table, view, uses) {
149
150
  return writeHandle(session, "delete", table, target, options, mods);
150
151
  }
151
152
  };
153
+ for (const walk of ["descendants", "ancestors"]) {
154
+ api[walk] = (id, options) => lazyRead(session, () => import("./7mnme5tn.js"), table, { id, walk, options }, base, view);
155
+ }
156
+ api.sync = (id, relation, ids, options) => lazyRead(session, () => import("./te5as7z7.js"), table, { id, relation, ids, options }, base, view, true);
152
157
  const hooks = session.schema.hooks;
153
158
  if (hooks !== undefined) {
154
159
  for (const hook of hooks) {
@@ -167,13 +172,13 @@ function tableApi(session, table, view, uses) {
167
172
  return api;
168
173
  }
169
174
  function batchHandle(session, ops, options, replica) {
170
- return queryHandle(() => import("./sbdme3vy.js").then((mod) => mod.batch(session, ops, options, replica)), {
175
+ return queryHandle(() => import("./vb6qfyve.js").then((mod) => mod.batch(session, ops, options, replica)), {
171
176
  replica: () => batchHandle(session, ops, options, true)
172
177
  });
173
178
  }
174
179
  var writers;
175
180
  function loadWrite() {
176
- writers ??= import("./2cg3wnxc.js");
181
+ writers ??= import("./5v3xf80k.js");
177
182
  return writers;
178
183
  }
179
184
  function queryHandle(run, extra) {
@@ -258,41 +263,53 @@ function start(session, op, table, options, mods, view) {
258
263
  throw new OkmError2("not_found", `one() on ${table} matched no row.`, withHttp(session.http, { kind: "not_found", table }));
259
264
  }
260
265
  return value;
261
- }, (prepare) => ({
266
+ }, () => ({
262
267
  all(reason) {
263
268
  return start(session, op, table, options, { ...mods, all: reason }, view);
264
269
  },
265
270
  required() {
266
271
  return start(session, op, table, options, { ...mods, required: true }, view);
267
272
  },
268
- stream() {
269
- return streamLazy(session, call, prepare);
273
+ stream(batch) {
274
+ return streamLazy(session, call, mods, view, batch);
270
275
  }
271
276
  }));
272
277
  }
273
- function lazyRead(session, load, table, options, mods, view) {
278
+ function lazyRead(session, load, table, options, mods, view, sync) {
274
279
  const read = () => load().then((mod) => ({ it: mod.build(session, table, options, mods, view) }));
275
- return queryHandle(() => read().then((box) => box.it), {
276
- inspect: () => read().then((box) => box.it.inspect()),
277
- sql: () => read().then((box) => box.it.sql()),
278
- all: (reason) => lazyRead(session, load, table, options, { ...mods, all: reason }, view)
279
- });
280
+ const sql = () => read().then((box) => box.it.sql());
281
+ const extra = { sql };
282
+ if (sync) {
283
+ extra.expect = (count) => lazyRead(session, load, table, options, { ...mods, expect: count }, view, true);
284
+ } else {
285
+ extra.inspect = () => read().then((box) => box.it.inspect());
286
+ extra.all = (reason) => lazyRead(session, load, table, options, { ...mods, all: reason }, view);
287
+ }
288
+ return queryHandle(() => read().then((box) => box.it), extra);
280
289
  }
281
290
  async function decodeRows(plan, rows, table) {
282
- return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./ys0xzyaj.js")).decodeIncluded(plan, rows, table);
291
+ return plan.outputs.includes.length === 0 ? decodeResult(plan, rows, table) : (await import("./dkxgzaqd.js")).decodeIncluded(plan, rows, table);
283
292
  }
284
293
  function readHandle(session, table, call, mods, decode, extra) {
285
294
  let prepared;
286
295
  const origin = call;
296
+ const searched = "search" in call;
287
297
  const prepare = async () => {
288
298
  if (prepared !== undefined)
289
299
  return prepared;
290
300
  if (mods.uses !== undefined) {
291
- call = (await import("./r6nwkxnt.js")).refine(session.schema, origin, mods.uses);
301
+ call = (await import("./m7n9h2a5.js")).refine(session.schema, origin, mods.uses);
302
+ }
303
+ if (searched) {
304
+ call = (await import("./jznfax0y.js")).applyTextSearch(session.schema, call);
292
305
  }
293
- if (readNeedsOperatorSql(session.schema, call))
294
- await loadOperatorSql();
295
306
  const hooks = await hooksFor(call);
307
+ if (readNeedsOperatorSql(session.schema, call) || hooks?.needsOperator(session.schema, call)) {
308
+ await loadOperatorSql();
309
+ }
310
+ if (call.build === undefined && selectHasWindow(call.select)) {
311
+ call = (await import("./gzaveazc.js")).attach(session.schema, call);
312
+ }
296
313
  const bound = bindCall(session.schema, call, hooks);
297
314
  let plan = session.cache.get(bound.key);
298
315
  if (plan === undefined) {
@@ -307,7 +324,7 @@ function readHandle(session, table, call, mods, decode, extra) {
307
324
  prepared = { plan, params: bound.params };
308
325
  return prepared;
309
326
  };
310
- const sync = () => call.include === undefined && mods.uses === undefined && !readNeedsOperatorSql(session.schema, call);
327
+ const sync = () => !searched && call.include === undefined && mods.uses === undefined && !selectHasWindow(call.select) && !readNeedsOperatorSql(session.schema, call);
311
328
  const run = async () => {
312
329
  await session.connected;
313
330
  const { plan, params } = await prepare();
@@ -352,10 +369,10 @@ function readHandle(session, table, call, mods, decode, extra) {
352
369
  ...extra?.(prepare)
353
370
  });
354
371
  }
355
- function streamLazy(session, call, prepare) {
372
+ function streamLazy(session, call, mods, view, batch) {
356
373
  return async function* () {
357
- const { streamRows } = await import("./3qnhc7w5.js");
358
- yield* streamRows(session, call, prepare, (error) => logged(session, error));
374
+ const { streamRows } = await import("./cn957f8d.js");
375
+ yield* streamRows(session, call, mods, view, batch, (error) => logged(session, error));
359
376
  }();
360
377
  }
361
378
  function archiveRecord(model, view) {
@@ -368,12 +385,7 @@ function archiveRecord(model, view) {
368
385
  }
369
386
  function readCall(op, table, options, all, scope, model, schema, view) {
370
387
  const record = options;
371
- const accepted = readOptionNames(op);
372
- for (const key of Object.keys(record)) {
373
- if (!accepted.includes(key)) {
374
- throwNamed2("OKM1120", key, accepted, `Option ${key} is not accepted by ${op}. Accepted options: ${accepted.join(", ")}.`);
375
- }
376
- }
388
+ rejectKeys(record, readOptionNames(op), op, true);
377
389
  return {
378
390
  op,
379
391
  table,
@@ -382,6 +394,7 @@ function readCall(op, table, options, all, scope, model, schema, view) {
382
394
  ...record.orderBy !== undefined ? { orderBy: record.orderBy } : {},
383
395
  ...record.limit !== undefined ? { limit: record.limit } : {},
384
396
  ...record.include !== undefined ? { include: record.include } : {},
397
+ ..."search" in record ? { search: record.search } : {},
385
398
  ...callOptions(record),
386
399
  ...all !== undefined ? { all } : {},
387
400
  ...scope !== undefined ? { scope } : {},
@@ -391,13 +404,13 @@ function readCall(op, table, options, all, scope, model, schema, view) {
391
404
  };
392
405
  }
393
406
  async function checkServer(pool, schema, http, requireMeta, options, source) {
394
- const server = await import("./y2t3jktd.js");
407
+ const server = await import("./ttsqgp4p.js");
395
408
  let rows;
396
409
  try {
397
410
  const result = await pool.execute(server.versionQuery, undefined, options);
398
411
  rows = result.rows;
399
412
  } catch (error) {
400
- const { mapPostgresError } = await import("./d5azex6s.js");
413
+ const { mapPostgresError } = await import("./63qtkrca.js");
401
414
  throw mapPostgresError(error, mapOptions(http, false, schema));
402
415
  }
403
416
  await server.acceptServer(pool, schema, rows, http, requireMeta, options, source);
@@ -406,7 +419,7 @@ async function mapError(session, error) {
406
419
  if (error instanceof OkmError2) {
407
420
  return session.http === undefined ? error : new OkmError2(error.code, error.message, { ...errorFields(error), http: session.http });
408
421
  }
409
- const { mapPostgresError } = await import("./d5azex6s.js");
422
+ const { mapPostgresError } = await import("./63qtkrca.js");
410
423
  return mapPostgresError(error, mapOptions(session.http, session.includeValues, session.schema));
411
424
  }
412
425
  function errorFields(error) {
@@ -420,15 +433,18 @@ function errorFields(error) {
420
433
  var includeHooks;
421
434
  var operatorSql;
422
435
  function loadOperatorSql() {
423
- operatorSql ??= import("./n076ydsc.js").then(() => {
436
+ operatorSql ??= import("./xhfsfkgk.js").then(() => {
424
437
  return;
425
438
  });
426
439
  return operatorSql;
427
440
  }
441
+ function selectHasWindow(select) {
442
+ return Array.isArray(select) && select.some((item) => typeof item !== "string");
443
+ }
428
444
  function hooksFor(call) {
429
445
  if (call.include === undefined)
430
446
  return Promise.resolve(undefined);
431
- includeHooks ??= import("./ys0xzyaj.js").then((mod) => mod.includeHooks);
447
+ includeHooks ??= import("./dkxgzaqd.js").then((mod) => mod.includeHooks);
432
448
  return includeHooks;
433
449
  }
434
450
  function bindNow(schema, call) {
@@ -461,12 +477,15 @@ function attachHttp(http, error) {
461
477
  function callOptions(input, statement) {
462
478
  const timeout = input.timeout ?? statement;
463
479
  const route = input.route;
464
- if (input.signal === undefined && timeout === undefined && route === undefined)
480
+ const pin = input.pin;
481
+ if (input.signal === undefined && timeout === undefined && route === undefined && pin === undefined) {
465
482
  return;
483
+ }
466
484
  return {
467
485
  ...input.signal !== undefined ? { signal: input.signal } : {},
468
486
  ...timeout !== undefined ? { timeout } : {},
469
- ...route !== undefined ? { route } : {}
487
+ ...route !== undefined ? { route } : {},
488
+ ...pin !== undefined ? { pin } : {}
470
489
  };
471
490
  }
472
491
  function mapOptions(http, includeValues, schema) {