okmodel 0.5.1 → 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 (233) hide show
  1. package/README.md +100 -1116
  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 +20 -0
  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 +41 -3
  14. package/dist/adapters/pg/reserved.d.ts +42 -0
  15. package/dist/adapters/pg/session.d.ts +0 -18
  16. package/dist/contracts/catalog/document.d.ts +19 -5
  17. package/dist/contracts/catalog/object.d.ts +2 -1
  18. package/dist/contracts/catalog/policy.d.ts +48 -0
  19. package/dist/contracts/catalog/types.d.ts +25 -1
  20. package/dist/contracts/catalog/view.d.ts +2 -0
  21. package/dist/contracts/connection.d.ts +7 -6
  22. package/dist/contracts/internal.js +1 -1
  23. package/dist/contracts/location.d.ts +10 -0
  24. package/dist/dialects/pg/column.d.ts +13 -2
  25. package/dist/dialects/pg/ddl.d.ts +37 -1
  26. package/dist/dialects/pg/emit.d.ts +19 -1
  27. package/dist/dialects/pg/errors.d.ts +32 -1
  28. package/dist/dialects/pg/ext/citext.js +1 -1
  29. package/dist/dialects/pg/ext/index.js +1 -1
  30. package/dist/dialects/pg/ext/pg-trgm.js +1 -1
  31. package/dist/dialects/pg/filter-parse.d.ts +5 -4
  32. package/dist/dialects/pg/floor.d.ts +68 -0
  33. package/dist/dialects/pg/fn/index.js +2 -2
  34. package/dist/dialects/pg/index.d.ts +8 -2
  35. package/dist/dialects/pg/index.js +67 -171
  36. package/dist/dialects/pg/introspect.d.ts +7 -0
  37. package/dist/dialects/pg/keys.d.ts +11 -8
  38. package/dist/dialects/pg/model.d.ts +47 -2
  39. package/dist/dialects/pg/morph.d.ts +43 -0
  40. package/dist/dialects/pg/operator-fit.d.ts +2 -2
  41. package/dist/dialects/pg/operators.d.ts +14 -7
  42. package/dist/dialects/pg/ops/bucket.d.ts +65 -0
  43. package/dist/dialects/pg/ops/inc.d.ts +2 -2
  44. package/dist/dialects/pg/ops/matches.d.ts +9 -12
  45. package/dist/dialects/pg/ops/relevance.d.ts +13 -0
  46. package/dist/dialects/pg/ops/search-query.d.ts +22 -0
  47. package/dist/dialects/pg/ops/window.d.ts +103 -0
  48. package/dist/dialects/pg/owner.d.ts +42 -0
  49. package/dist/dialects/pg/path-endpoint.d.ts +20 -0
  50. package/dist/dialects/pg/preset.d.ts +1 -1
  51. package/dist/dialects/pg/relations.d.ts +100 -3
  52. package/dist/dialects/pg/role/check.d.ts +3 -0
  53. package/dist/dialects/pg/role/index.d.ts +71 -6
  54. package/dist/dialects/pg/role/sql.d.ts +11 -0
  55. package/dist/dialects/pg/schema.d.ts +33 -3
  56. package/dist/dialects/pg/table.d.ts +25 -3
  57. package/dist/dialects/pg/tenancy.d.ts +45 -3
  58. package/dist/dialects/pg/view/client.d.ts +19 -1
  59. package/dist/dialects/pg/view/index.d.ts +4 -0
  60. package/dist/dialects/pg/view/index.js +21 -178
  61. package/dist/dialects/pg/view/refresh.d.ts +24 -0
  62. package/dist/runtime/aggregate.d.ts +8 -2
  63. package/dist/runtime/batch.d.ts +1 -1
  64. package/dist/runtime/bucket-group.d.ts +70 -0
  65. package/dist/runtime/conflict.d.ts +24 -6
  66. package/dist/runtime/drift.d.ts +9 -0
  67. package/dist/runtime/include.d.ts +0 -8
  68. package/dist/runtime/inflight.d.ts +14 -0
  69. package/dist/runtime/page.d.ts +4 -1
  70. package/dist/runtime/pg/bun.js +12 -5
  71. package/dist/runtime/pg/pg.js +5 -5
  72. package/dist/runtime/pg/pglite.d.ts +1 -0
  73. package/dist/runtime/pg/pglite.js +9 -8
  74. package/dist/runtime/pg/postgresjs.js +5 -5
  75. package/dist/runtime/plan.d.ts +113 -15
  76. package/dist/runtime/predicate.d.ts +19 -0
  77. package/dist/runtime/read-stream.d.ts +13 -16
  78. package/dist/runtime/result-name.d.ts +17 -0
  79. package/dist/runtime/safety/index.js +1 -1
  80. package/dist/runtime/server-check.d.ts +3 -3
  81. package/dist/runtime/sort-bind.d.ts +21 -0
  82. package/dist/runtime/sort.d.ts +56 -0
  83. package/dist/runtime/sync.d.ts +70 -0
  84. package/dist/runtime/tenancy/composite.d.ts +26 -0
  85. package/dist/runtime/tenancy/context.d.ts +16 -0
  86. package/dist/runtime/tenancy/index.d.ts +9 -5
  87. package/dist/runtime/tenancy/index.js +1511 -38
  88. package/dist/runtime/tenancy/path.d.ts +87 -0
  89. package/dist/runtime/tenancy/rls.d.ts +67 -0
  90. package/dist/runtime/tenancy/via.d.ts +22 -0
  91. package/dist/runtime/text-search.d.ts +20 -0
  92. package/dist/runtime/traits/index.d.ts +80 -0
  93. package/dist/runtime/traits/index.js +187 -17
  94. package/dist/runtime/tree.d.ts +38 -0
  95. package/dist/runtime/types.d.ts +231 -23
  96. package/dist/runtime/validate/index.js +4 -4
  97. package/dist/runtime/version.d.ts +39 -0
  98. package/dist/runtime/window.d.ts +21 -0
  99. package/dist/runtime/write.d.ts +55 -3
  100. package/dist/shared/{krxx77g0.js → 14vx95q4.js} +12 -18
  101. package/dist/shared/1est4ezg.js +313 -0
  102. package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
  103. package/dist/shared/1w508jbr.js +1611 -0
  104. package/dist/shared/2c13q96h.js +18 -0
  105. package/dist/shared/2d3xq4ps.js +9 -0
  106. package/dist/shared/2shdbn8q.js +23 -0
  107. package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
  108. package/dist/shared/3v7t1yrv.js +208 -0
  109. package/dist/shared/5e3tf63j.js +220 -0
  110. package/dist/shared/5fe3kbsh.js +10 -0
  111. package/dist/shared/5v3xf80k.js +37 -0
  112. package/dist/shared/{51mvgj8w.js → 63qtkrca.js} +130 -3
  113. package/dist/shared/{gbtcc2d7.js → 67txcrcw.js} +62 -66
  114. package/dist/shared/79dt02vc.js +12 -0
  115. package/dist/shared/{v36c5g6p.js → 7k9grvf6.js} +407 -14
  116. package/dist/shared/7kms6fvj.js +20 -0
  117. package/dist/shared/7mnme5tn.js +8 -0
  118. package/dist/shared/7n7ddwt4.js +6 -0
  119. package/dist/shared/{87jvvhnt.js → 81ebdx9p.js} +48 -68
  120. package/dist/shared/{szm0cksa.js → 8skf0cam.js} +34 -6
  121. package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
  122. package/dist/shared/9a4ae4p8.js +31 -0
  123. package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
  124. package/dist/shared/9y3mmmh1.js +436 -0
  125. package/dist/shared/ab9gmbwy.js +213 -0
  126. package/dist/shared/{sycnx8gt.js → ax7qv55k.js} +18 -8
  127. package/dist/shared/{f5cw5q5r.js → aytqh5y2.js} +6 -4
  128. package/dist/shared/{fancm5pt.js → b5pftnn2.js} +138 -15
  129. package/dist/shared/{efmy2gcg.js → b76b8d95.js} +2 -2
  130. package/dist/shared/bdk4sty6.js +58 -0
  131. package/dist/shared/{32zqc1dw.js → bg3rym3g.js} +63 -32
  132. package/dist/shared/{0t22wwh1.js → bm22fvzr.js} +16 -14
  133. package/dist/shared/bz84tkzm.js +342 -0
  134. package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
  135. package/dist/shared/cn957f8d.js +179 -0
  136. package/dist/shared/{pf0d8f77.js → cnkky55j.js} +25 -14
  137. package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
  138. package/dist/shared/{nkaxvt9q.js → dkxgzaqd.js} +224 -19
  139. package/dist/shared/dzj09cye.js +10 -0
  140. package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
  141. package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
  142. package/dist/shared/exn3sd90.js +359 -0
  143. package/dist/shared/g6evj1j3.js +66 -0
  144. package/dist/shared/ga9j92qj.js +25 -0
  145. package/dist/shared/{qv2ydck9.js → gs74dbj5.js} +651 -76
  146. package/dist/shared/gzaveazc.js +285 -0
  147. package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
  148. package/dist/shared/{dyj86cmj.js → hyh73qk6.js} +3 -3
  149. package/dist/shared/je4axnm8.js +22 -0
  150. package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
  151. package/dist/shared/{6qd27mx0.js → jvd0mqag.js} +5 -5
  152. package/dist/shared/jznfax0y.js +155 -0
  153. package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
  154. package/dist/shared/{ps7a6h14.js → kr0jzbw2.js} +12 -8
  155. package/dist/shared/{janx09m5.js → ktz42yez.js} +20 -8
  156. package/dist/shared/{gde73es6.js → m6p12kbr.js} +56 -55
  157. package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
  158. package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
  159. package/dist/shared/{nxdp2ze3.js → mtaszv5a.js} +144 -12
  160. package/dist/shared/n816peh1.js +45 -0
  161. package/dist/shared/nbw1z4yd.js +18 -0
  162. package/dist/shared/{cctw17hj.js → p6qc5gcp.js} +38 -34
  163. package/dist/shared/{6rk2gen5.js → pbp1ss85.js} +20 -17
  164. package/dist/shared/pt94kz7f.js +6 -0
  165. package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
  166. package/dist/shared/q5c6ngn3.js +13 -0
  167. package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
  168. package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
  169. package/dist/shared/rhs3xe4k.js +7 -0
  170. package/dist/shared/{ntneex2a.js → rpycarcr.js} +6 -6
  171. package/dist/shared/{sdc7r2ww.js → rs73fca9.js} +8 -8
  172. package/dist/shared/{tm5ab8we.js → sfz1ksn6.js} +7 -4
  173. package/dist/shared/{6mnp99hx.js → svncdeh5.js} +16 -12
  174. package/dist/shared/{hf22e0wt.js → tbrvgw6z.js} +62 -42
  175. package/dist/shared/te5as7z7.js +622 -0
  176. package/dist/shared/{ga3sfy93.js → tsvww22q.js} +535 -200
  177. package/dist/shared/{47x8x9ze.js → ttsqgp4p.js} +20 -13
  178. package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
  179. package/dist/shared/vb6qfyve.js +152 -0
  180. package/dist/shared/{r2sp8hrc.js → vczs8gd4.js} +22 -13
  181. package/dist/shared/{1g0drakv.js → vqrjpcqn.js} +145 -3
  182. package/dist/shared/{2pqx26h8.js → w72kgg4q.js} +31 -22
  183. package/dist/shared/{96qcj21c.js → w79hsckn.js} +16 -51
  184. package/dist/shared/wa07eas9.js +730 -0
  185. package/dist/shared/{k8v5v5wj.js → x933k9a3.js} +75 -34
  186. package/dist/shared/{cr74e96e.js → xhfsfkgk.js} +62 -28
  187. package/dist/shared/xjk7hnn5.js +272 -0
  188. package/dist/shared/{5enne4ma.js → xnxsed62.js} +66 -113
  189. package/dist/shared/xqve9598.js +53 -0
  190. package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
  191. package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
  192. package/dist/shared/y6njgyda.js +249 -0
  193. package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
  194. package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
  195. package/dist/shared/z7s6fpxv.js +62 -0
  196. package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
  197. package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
  198. package/dist/shared/zm0ptry0.js +40 -0
  199. package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
  200. package/dist/shared/zp9fmend.js +145 -0
  201. package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
  202. package/dist/tooling/cli.js +41 -15
  203. package/dist/tooling/migrate/apply.d.ts +14 -0
  204. package/dist/tooling/migrate/check.d.ts +3 -4
  205. package/dist/tooling/migrate/classify.d.ts +4 -0
  206. package/dist/tooling/migrate/config.d.ts +3 -2
  207. package/dist/tooling/migrate/engine.d.ts +3 -2
  208. package/dist/tooling/migrate/files.d.ts +11 -1
  209. package/dist/tooling/migrate/index.js +14 -14
  210. package/dist/tooling/migrate/lint.d.ts +1 -1
  211. package/dist/tooling/migrate/lost.d.ts +28 -0
  212. package/dist/tooling/migrate/paths.d.ts +14 -0
  213. package/dist/tooling/migrate/plan.d.ts +6 -3
  214. package/dist/tooling/migrate/runner.d.ts +25 -0
  215. package/dist/tooling/migrate/sandbox.d.ts +57 -0
  216. package/dist/tooling/migrate/sql-lex.d.ts +20 -3
  217. package/dist/tooling/migrate/text.d.ts +42 -0
  218. package/dist/tooling/node-version.d.ts +21 -0
  219. package/dist/tooling/testing/facts.d.ts +33 -5
  220. package/dist/tooling/testing/index.d.ts +1 -1
  221. package/dist/tooling/testing/index.js +3 -3
  222. package/dist/tooling/testing/isolation.d.ts +11 -5
  223. package/package.json +8 -3
  224. package/dist/shared/7m88x3e9.js +0 -45
  225. package/dist/shared/7zwwyh0v.js +0 -448
  226. package/dist/shared/aj2qxyhj.js +0 -90
  227. package/dist/shared/caw8b9d8.js +0 -204
  228. package/dist/shared/jwtxdj06.js +0 -76
  229. package/dist/shared/kfjp0gck.js +0 -212
  230. package/dist/shared/q58y17hy.js +0 -21
  231. package/dist/shared/qm7cdtvr.js +0 -912
  232. package/dist/shared/r8x5qhd7.js +0 -86
  233. package/dist/shared/zqrnhwsq.js +0 -31
@@ -1,18 +1,27 @@
1
+ import {
2
+ DriverError2
3
+ } from "./cm3w0ywp.js";
4
+ import {
5
+ noTimeout
6
+ } from "./79dt02vc.js";
1
7
  import {
2
8
  noticeBuffer,
3
- WireSession,
4
- cursorStream
5
- } from "./4az561fn.js";
9
+ WireSession
10
+ } from "./1qa0qajz.js";
6
11
  import {
7
12
  BUNSQL_CAPABILITIES,
8
13
  driverErrors,
9
14
  rejectClosed,
10
15
  mapFailure,
11
16
  runCall
12
- } from "./cgbamx3e.js";
17
+ } from "./kb2sdhfb.js";
13
18
 
14
19
  // src/adapters/pg/bunsql.ts
15
20
  import { SQL } from "bun";
21
+ var clientPools = new WeakSet;
22
+ function markClientPool(pool) {
23
+ clientPools.add(pool);
24
+ }
16
25
  function open5(config) {
17
26
  const max = config.max ?? 10;
18
27
  const acquireMs = config.timeouts?.acquire;
@@ -22,6 +31,8 @@ function open5(config) {
22
31
  const isClosed = () => closed;
23
32
  const named = config.prepared === "named";
24
33
  const parked = [];
34
+ let dropped = 0;
35
+ let closures = 0;
25
36
  const sql = new SQL(config.url, {
26
37
  max,
27
38
  idleTimeout: 0,
@@ -33,24 +44,53 @@ function open5(config) {
33
44
  application_name: "okmodel",
34
45
  ...config.searchPath !== undefined ? { search_path: config.searchPath } : {}
35
46
  },
36
- ...config.ssl !== undefined ? { tls: config.ssl } : {}
47
+ ...config.ssl !== undefined ? { tls: config.ssl } : {},
48
+ onclose() {
49
+ dropped += 1;
50
+ closures += 1;
51
+ }
37
52
  });
38
53
  const root = new WireSession((text, params) => send2(sql, text, params), notices, isClosed, false, () => {
39
54
  counters.busy += 1;
40
55
  }, () => {
41
56
  counters.busy = Math.max(0, counters.busy - 1);
42
57
  });
43
- const held = { sql, parked, acquireMs, counters, notices, isClosed };
44
- const checkout = () => closed ? rejectClosed() : import("./jwtxdj06.js").then((mod) => mod.checkout(held));
45
- return {
58
+ const held = {
59
+ sql,
60
+ parked,
61
+ acquireMs,
62
+ counters,
63
+ notices,
64
+ isClosed,
65
+ closures: () => closures
66
+ };
67
+ const run = (text, params, watch) => {
68
+ const sent = dropped;
69
+ return root.query(text, params, watch).catch((error) => import("./ab9gmbwy.js").then((mod) => mod.recover(sql, error, text, root.depth(), clientPools.has(pool), dropped > sent, () => root.query(text, params, watch))));
70
+ };
71
+ const afterDrop = (text, params, watch) => {
72
+ if (dropped === 0)
73
+ return run(text, params, watch);
74
+ const seen = dropped;
75
+ return import("./ab9gmbwy.js").then((mod) => mod.drainClosed(sql).then(() => {
76
+ if (dropped === seen)
77
+ dropped = 0;
78
+ return run(text, params, watch);
79
+ }));
80
+ };
81
+ const checkout = () => closed ? rejectClosed() : import("./ab9gmbwy.js").then((mod) => mod.checkout(held));
82
+ const pool = {
46
83
  capabilities: BUNSQL_CAPABILITIES,
47
84
  execute(text, params, options) {
48
- return runCall(closed, options, async (watch) => {
49
- await releaseParked(parked);
50
- return root.query(text, params, watch);
51
- });
85
+ const refused = noTimeout(options);
86
+ if (refused !== undefined)
87
+ return refused;
88
+ return runCall(closed, options, (watch) => releaseParked(parked).then(() => afterDrop(text, params, watch)));
52
89
  },
53
90
  async batch(statements, options) {
91
+ const refused = noTimeout(options);
92
+ if (refused !== undefined)
93
+ return refused;
54
94
  const connection = await checkout();
55
95
  try {
56
96
  return await connection.batch(statements, options);
@@ -60,10 +100,13 @@ function open5(config) {
60
100
  },
61
101
  reserve: () => checkout(),
62
102
  stream(text, params) {
63
- return stream(text, params);
103
+ return async function* () {
104
+ const { streamRows } = await import("./ab9gmbwy.js");
105
+ yield* streamRows(checkout, text, params);
106
+ }();
64
107
  },
65
108
  listen(channel, onNotify) {
66
- return listen(channel, onNotify);
109
+ return import("./ab9gmbwy.js").then((mod) => mod.listen(sql, parked, closed, channel, onNotify));
67
110
  },
68
111
  stats: () => statsOf(counters, max),
69
112
  async close() {
@@ -72,31 +115,29 @@ function open5(config) {
72
115
  await sql.close();
73
116
  }
74
117
  };
75
- function stream(text, params) {
76
- return async function* () {
77
- const connection = await checkout();
78
- try {
79
- yield* cursorStream((statement, values) => connection.execute(statement, values), text, params);
80
- } finally {
81
- await connection.release();
82
- }
83
- }();
84
- }
85
- async function listen(channel, onNotify) {
86
- if (closed)
87
- return rejectClosed();
88
- await releaseParked(parked);
89
- const subscription = await sql.listen(channel, onNotify);
90
- return async () => {
91
- await subscription.unlisten();
92
- };
93
- }
118
+ return pool;
94
119
  }
95
120
  function send2(sql, text, params) {
121
+ const refused = refuseInt8(params);
122
+ if (refused !== undefined)
123
+ return refused;
96
124
  if (params === undefined || params.length === 0)
97
125
  return sql.unsafe(text).raw();
98
126
  return sql.unsafe(text, [...params]).raw();
99
127
  }
128
+ function refuseInt8(params) {
129
+ if (params === undefined)
130
+ return;
131
+ for (const value of params) {
132
+ if (value === null || value.length < 19 || !/^-?(?:0|[1-9]\d*)$/.test(value))
133
+ continue;
134
+ const parsed = BigInt(value);
135
+ if (parsed > 9223372036854775807n || parsed < -9223372036854775808n) {
136
+ return Promise.reject(new DriverError2("bigint out of range", { sqlstate: "22003" }));
137
+ }
138
+ }
139
+ return;
140
+ }
100
141
  async function reserve(sql, acquireMs, counters) {
101
142
  counters.waiting += 1;
102
143
  try {
@@ -146,4 +187,4 @@ function statsOf(counters, size) {
146
187
  };
147
188
  }
148
189
 
149
- export { open5, send2, reserve, park };
190
+ export { markClientPool, open5, send2, reserve, park };
@@ -5,13 +5,13 @@ import {
5
5
  assertBoundText,
6
6
  assertRegconfig,
7
7
  textArray
8
- } from "./n7mcc1gk.js";
8
+ } from "./zchaghkf.js";
9
9
  import {
10
10
  installOperatorSql,
11
11
  quote,
12
12
  isRecord,
13
- fail
14
- } from "./gbtcc2d7.js";
13
+ fail2
14
+ } from "./67txcrcw.js";
15
15
  import {
16
16
  isOperator,
17
17
  operatorName,
@@ -19,7 +19,7 @@ import {
19
19
  } from "./cn0n68ft.js";
20
20
 
21
21
  // src/runtime/operator-sql.ts
22
- function emitStructured(column, ref, name, value, sink) {
22
+ function emitStructured(column, ref, name, value, sink, order) {
23
23
  if (name === "contains" || name === "containedBy" || name === "overlaps") {
24
24
  emitContainment(column, ref, name, value, sink);
25
25
  return;
@@ -36,12 +36,20 @@ function emitStructured(column, ref, name, value, sink) {
36
36
  emitMatches(column, ref, value, sink);
37
37
  return;
38
38
  }
39
+ if (name === "relevance") {
40
+ if (order !== true)
41
+ fail2("OKM1121", `relevance on ${column.field} belongs in orderBy.`);
42
+ emitRelevance(column, ref, value, sink);
43
+ sink.text(" desc");
44
+ sink.mark(`o:${column.field}:relevance`);
45
+ return;
46
+ }
39
47
  if (name === "similar" || name === "wordSimilar") {
40
48
  emitTrigram(column, ref, name, value, sink);
41
49
  return;
42
50
  }
43
51
  assertOperatorFits(column, name);
44
- fail("OKM1121", `${name} is not a value operator on ${column.field}. Use has, none, or every on a relation.`);
52
+ fail2("OKM1121", `${name} is not a value operator on ${column.field}. Use has, none, or every on a relation.`);
45
53
  }
46
54
  function emitContainment(column, ref, name, value, sink) {
47
55
  assertOperatorFits(column, name);
@@ -56,7 +64,7 @@ function emitJsonKey(column, ref, name, value, sink) {
56
64
  assertOperatorFits(column, name);
57
65
  if (name === "hasKey") {
58
66
  if (typeof value !== "string")
59
- fail("OKM1121", `hasKey on ${column.field} needs a key.`);
67
+ fail2("OKM1121", `hasKey on ${column.field} needs a key.`);
60
68
  assertBoundText(value, `key on ${column.field}`);
61
69
  sink.text("jsonb_exists(");
62
70
  sink.text(ref);
@@ -66,7 +74,7 @@ function emitJsonKey(column, ref, name, value, sink) {
66
74
  return;
67
75
  }
68
76
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
69
- fail("OKM1121", `hasAnyKey on ${column.field} needs a list of keys.`);
77
+ fail2("OKM1121", `hasAnyKey on ${column.field} needs a list of keys.`);
70
78
  }
71
79
  sink.text("jsonb_exists_any(");
72
80
  sink.text(ref);
@@ -77,15 +85,15 @@ function emitJsonKey(column, ref, name, value, sink) {
77
85
  function emitPath(column, ref, value, sink) {
78
86
  assertOperatorFits(column, "path");
79
87
  if (!isRecord(value) || !Array.isArray(value.segments) || !isOperator(value.op)) {
80
- fail("OKM1121", `path on ${column.field} needs segments and a comparison.`);
88
+ fail2("OKM1121", `path on ${column.field} needs segments and a comparison.`);
81
89
  }
82
90
  const segments = value.segments;
83
91
  if (segments.length === 0 || segments.some((item) => typeof item !== "string")) {
84
- fail("OKM1121", `path on ${column.field} needs a list of segments.`);
92
+ fail2("OKM1121", `path on ${column.field} needs a list of segments.`);
85
93
  }
86
94
  const opName = operatorName(value.op);
87
95
  if (opName !== "eq" && opName !== "lt" && opName !== "lte" && opName !== "gt" && opName !== "gte") {
88
- fail("OKM1121", `path on ${column.field} compares with eq, lt, lte, gt, or gte.`);
96
+ fail2("OKM1121", `path on ${column.field} compares with eq, lt, lte, gt, or gte.`);
89
97
  }
90
98
  const operand = operatorValue(value.op);
91
99
  const cast = pathCast(column, operand);
@@ -106,7 +114,7 @@ function pathCast(column, operand) {
106
114
  return "boolean";
107
115
  if (typeof operand === "string")
108
116
  return "text";
109
- fail("OKM1121", `path on ${column.field} compares a string, number, or boolean.`);
117
+ fail2("OKM1121", `path on ${column.field} compares a string, number, or boolean.`);
110
118
  }
111
119
  function pathParam(operand) {
112
120
  if (typeof operand === "number")
@@ -117,35 +125,61 @@ function pathParam(operand) {
117
125
  return operand;
118
126
  return "";
119
127
  }
120
- function emitMatches(column, ref, value, sink) {
121
- assertOperatorFits(column, "matches");
122
- if (!isRecord(value) || typeof value.query !== "string") {
123
- fail("OKM1121", `matches on ${column.field} needs search text.`);
128
+ var MATCH_FN = {
129
+ natural: "websearch_to_tsquery",
130
+ "all-words": "plainto_tsquery",
131
+ phrase: "phraseto_tsquery",
132
+ advanced: "to_tsquery"
133
+ };
134
+ function readMatch(column, value, label) {
135
+ if (!isRecord(value) || typeof value.query !== "string" || value.query.length === 0) {
136
+ fail2("OKM1121", `${label} on ${column.field} needs text to look for.`);
124
137
  }
125
- assertNoControl(value.query, `matches on ${column.field}`);
126
- const mode = value.mode ?? "websearch";
127
- const fn = mode === "websearch" ? "websearch_to_tsquery" : mode === "plain" ? "plainto_tsquery" : mode === "phrase" ? "phraseto_tsquery" : undefined;
138
+ assertNoControl(value.query, `${label} on ${column.field}`);
139
+ const match = value.match ?? "natural";
140
+ const fn = typeof match === "string" ? MATCH_FN[match] : undefined;
128
141
  if (fn === undefined) {
129
- fail("OKM1121", `matches on ${column.field} mode must be websearch, plain, or phrase.`);
142
+ fail2("OKM1121", `${label} on ${column.field} match must be natural, all-words, phrase, or advanced.`);
130
143
  }
131
- sink.text(ref);
132
- sink.text(" @@ ");
133
- sink.text(fn);
144
+ if (value.language === undefined)
145
+ return { fn, language: undefined, query: value.query };
146
+ if (typeof value.language !== "string") {
147
+ fail2("OKM1121", `${label} on ${column.field} language must be a name such as english.`);
148
+ }
149
+ assertRegconfig(value.language);
150
+ return { fn, language: value.language, query: value.query };
151
+ }
152
+ function emitTsquery(sink, query) {
153
+ sink.mark(query.language === undefined ? `:${query.fn}` : `:${query.fn}:lang`);
154
+ sink.text(query.fn);
134
155
  sink.text("(");
135
- if (typeof value.config === "string") {
136
- assertRegconfig(value.config);
137
- sink.param(value.config);
156
+ if (query.language !== undefined) {
157
+ sink.param(query.language);
138
158
  sink.text("::regconfig, ");
139
159
  }
140
- sink.param(value.query);
160
+ sink.param(query.query);
161
+ sink.text(")");
162
+ }
163
+ function emitMatches(column, ref, value, sink) {
164
+ assertOperatorFits(column, "matches");
165
+ sink.text(ref);
166
+ sink.text(" @@ ");
167
+ emitTsquery(sink, readMatch(column, value, "matches"));
168
+ }
169
+ function emitRelevance(column, ref, value, sink) {
170
+ assertOperatorFits(column, "relevance");
171
+ sink.text("ts_rank(");
172
+ sink.text(ref);
173
+ sink.text(", ");
174
+ emitTsquery(sink, readMatch(column, value, "relevance"));
141
175
  sink.text(")");
142
176
  }
143
177
  function emitTrigram(column, ref, name, value, sink) {
144
178
  if (!isRecord(value) || typeof value.query !== "string" || typeof value.schema !== "string") {
145
- fail("OKM1121", `${name} on ${column.field} needs query text.`);
179
+ fail2("OKM1121", `${name} on ${column.field} needs query text.`);
146
180
  }
147
181
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value.schema)) {
148
- fail("OKM1121", `${name} on ${column.field} needs an extension schema name.`);
182
+ fail2("OKM1121", `${name} on ${column.field} needs an extension schema name.`);
149
183
  }
150
184
  sink.text(ref);
151
185
  sink.text(" operator(");
@@ -0,0 +1,272 @@
1
+ import {
2
+ readHandle,
3
+ readCall,
4
+ attachHttp
5
+ } from "./tbrvgw6z.js";
6
+ import {
7
+ decodeResult,
8
+ emitWhere,
9
+ emitOrder,
10
+ selectedColumns,
11
+ rejectKeys,
12
+ projectExpr,
13
+ indexes,
14
+ quote,
15
+ list,
16
+ isRecord,
17
+ fail2
18
+ } from "./67txcrcw.js";
19
+ import {
20
+ OkmError2,
21
+ throwNamed2
22
+ } from "./52szzakm.js";
23
+
24
+ // src/runtime/tree.ts
25
+ var OPTIONS = [
26
+ "where",
27
+ "select",
28
+ "orderBy",
29
+ "depth",
30
+ "self",
31
+ "relation",
32
+ "route",
33
+ "signal",
34
+ "timeout"
35
+ ];
36
+ function build2(session, table, options, mods, view) {
37
+ try {
38
+ return open(session, table, options, mods, view);
39
+ } catch (error) {
40
+ throw error instanceof OkmError2 ? attachHttp(session.http, error) : error;
41
+ }
42
+ }
43
+ function open(session, table, options, mods, view) {
44
+ const packed = readPacked(options);
45
+ const user = packed.user;
46
+ rejectKeys(user, OPTIONS, packed.walk);
47
+ const indexed = indexes(session.schema).get(table);
48
+ if (indexed === undefined)
49
+ fail2("OKM1120", `Table ${table} is not in the schema.`);
50
+ const edge = pickEdge(indexed, user.relation);
51
+ const identity = identityColumn2(session, indexed);
52
+ const depth = readDepth(user.depth);
53
+ const self = readSelf(user.self);
54
+ const id = userId(identity, packed.id);
55
+ const shared = {
56
+ ...user.where !== undefined ? { where: user.where } : {},
57
+ ...user.select !== undefined ? { select: user.select } : {},
58
+ ...user.orderBy !== undefined ? { orderBy: user.orderBy } : {},
59
+ ...user.signal !== undefined ? { signal: user.signal } : {},
60
+ ...user.timeout !== undefined ? { timeout: user.timeout } : {},
61
+ ...user.route !== undefined ? { route: user.route } : {}
62
+ };
63
+ const base = readCall("find", table, shared, mods.all, session.scope, session.schema.model[table], session.schema, view);
64
+ const spec = { direction: packed.walk, edge, identity, depth, self, id };
65
+ const call = {
66
+ ...base,
67
+ op: packed.walk,
68
+ build: (schema, planned, sink, outputs, source) => {
69
+ emitTree(schema, planned, sink, outputs, source, spec);
70
+ }
71
+ };
72
+ return readHandle(session, table, call, mods, (compiled, rows) => decodeResult(compiled, rows, table));
73
+ }
74
+ function emitTree(schema, table, sink, outputs, call, spec) {
75
+ const { direction, edge, identity, depth, self, id } = spec;
76
+ sink.mark(`walk:${direction}|rel:${edge.name}|self:${self ? "1" : "0"}|depth:${depth === undefined ? "all" : String(depth)}|`);
77
+ const selected = selectedColumns(table, call.select);
78
+ sink.text("with recursive walk as (select ");
79
+ emitKeyList(sink, "s", edge.parent, "k");
80
+ emitKeyList(sink, "s", edge.child, "f");
81
+ sink.text(", 0 as depth, array[s.");
82
+ sink.text(quote(identity.sql));
83
+ sink.text("] as seen from ");
84
+ sink.text(quote(table.model.sql));
85
+ sink.text(" s where s.");
86
+ sink.text(quote(identity.sql));
87
+ sink.text(" = ");
88
+ sink.param(identity.encode(id));
89
+ emitWhere(schema, table, undefined, sink, "s", 0, true);
90
+ sink.text(" union all select ");
91
+ let started = emitBare(sink, "c", edge.parent, false);
92
+ emitBare(sink, "c", edge.child, started);
93
+ sink.text(", w.depth + 1, w.seen || c.");
94
+ sink.text(quote(identity.sql));
95
+ sink.text(" from ");
96
+ sink.text(quote(table.model.sql));
97
+ sink.text(" c join walk w on ");
98
+ if (direction === "descendants")
99
+ emitStep(sink, "c", edge.child, edge.parent, "k");
100
+ else
101
+ emitStep(sink, "c", edge.parent, edge.child, "f");
102
+ sink.text(" where c.");
103
+ sink.text(quote(identity.sql));
104
+ sink.text(" <> all(w.seen)");
105
+ if (depth !== undefined) {
106
+ sink.text(" and w.depth < ");
107
+ sink.text(String(depth));
108
+ }
109
+ emitWhere(schema, table, undefined, sink, "c", 0, true);
110
+ sink.text(") select ");
111
+ let column = 0;
112
+ for (let index = 0;index < selected.length; index += 1) {
113
+ const item = selected[index];
114
+ if (item === undefined)
115
+ continue;
116
+ if (column > 0)
117
+ sink.text(", ");
118
+ sink.text(projectExpr(`t.${quote(item.sql)}`, item.dataType));
119
+ sink.mark(`s:${item.field}`);
120
+ outputs?.fields.push({ key: item.field, at: column, decode: item.decode });
121
+ column += 1;
122
+ }
123
+ if (column === 0)
124
+ sink.text("1");
125
+ sink.text(" from ");
126
+ sink.text(quote(table.model.sql));
127
+ sink.text(" t join walk w on ");
128
+ emitStep(sink, "t", edge.parent, edge.parent, "k");
129
+ if (self)
130
+ emitWhere(schema, table, call.where, sink, "t", 0, false);
131
+ else {
132
+ sink.text(" where w.depth > 0");
133
+ emitWhere(schema, table, call.where, sink, "t", 0, true);
134
+ }
135
+ if (call.orderBy !== undefined) {
136
+ emitOrder(table, call.orderBy, sink, "t");
137
+ return;
138
+ }
139
+ sink.text(" order by w.depth asc");
140
+ sink.mark("order:depth");
141
+ for (const field of table.model.primary) {
142
+ const item = table.columns.get(field);
143
+ if (item === undefined)
144
+ continue;
145
+ sink.text(", t.");
146
+ sink.text(quote(item.sql));
147
+ sink.text(" asc");
148
+ }
149
+ }
150
+ function emitKeyList(sink, alias, columns, prefix) {
151
+ for (let index = 0;index < columns.length; index += 1) {
152
+ const name = columns[index];
153
+ if (name === undefined)
154
+ continue;
155
+ if (index > 0 || prefix === "f")
156
+ sink.text(", ");
157
+ sink.text(alias);
158
+ sink.text(".");
159
+ sink.text(quote(name));
160
+ sink.text(" as ");
161
+ sink.text(prefix);
162
+ sink.text(String(index));
163
+ }
164
+ }
165
+ function emitBare(sink, alias, columns, lead) {
166
+ let started = lead;
167
+ for (const name of columns) {
168
+ if (started)
169
+ sink.text(", ");
170
+ started = true;
171
+ sink.text(alias);
172
+ sink.text(".");
173
+ sink.text(quote(name));
174
+ }
175
+ return started;
176
+ }
177
+ function emitStep(sink, alias, columns, against, prefix) {
178
+ for (let index = 0;index < columns.length; index += 1) {
179
+ const name = columns[index];
180
+ if (name === undefined || against[index] === undefined)
181
+ continue;
182
+ if (index > 0)
183
+ sink.text(" and ");
184
+ sink.text(alias);
185
+ sink.text(".");
186
+ sink.text(quote(name));
187
+ sink.text(" = w.");
188
+ sink.text(prefix);
189
+ sink.text(String(index));
190
+ }
191
+ }
192
+ function readPacked(options) {
193
+ if (!isRecord(options) || options.walk !== "descendants" && options.walk !== "ancestors") {
194
+ fail2("OKM1120", "descendants and ancestors are table methods.");
195
+ }
196
+ const user = options.options;
197
+ if (user === undefined)
198
+ return { id: options.id, walk: options.walk, user: {} };
199
+ if (!isRecord(user))
200
+ fail2("OKM1120", `${options.walk} options must be an object.`);
201
+ return { id: options.id, walk: options.walk, user };
202
+ }
203
+ function pickEdge(table, relation) {
204
+ const edges = selfEdges(table);
205
+ if (edges.length === 0) {
206
+ fail2("OKM1120", `${table.model.name} has no relation to itself.`, `Declare children: many("${table.model.name}") or parent: one("${table.model.name}").`);
207
+ }
208
+ const groups = new Set(edges.map((edge) => edge.child.join("\x00")));
209
+ if (relation === undefined) {
210
+ if (groups.size !== 1) {
211
+ fail2("OKM1120", `${table.model.name} has more than one relation to itself. Pass relation.`, `Accepted names: ${edges.map((edge) => edge.name).join(", ")}.`);
212
+ }
213
+ const only = edges[0];
214
+ if (only === undefined)
215
+ fail2("OKM1120", `${table.model.name} has no relation to itself.`);
216
+ return only;
217
+ }
218
+ if (typeof relation !== "string" || relation.length === 0) {
219
+ fail2("OKM1120", "relation must be a name.");
220
+ }
221
+ const found = edges.find((edge) => edge.name === relation);
222
+ if (found === undefined) {
223
+ throwNamed2("OKM1120", relation, edges.map((edge) => edge.name), `Relation ${relation} is not a self-relation of ${table.model.name}. Accepted names: ${list(edges.map((edge) => edge.name))}.`);
224
+ }
225
+ return found;
226
+ }
227
+ function selfEdges(table) {
228
+ const edges = [];
229
+ for (const relation of table.model.relations) {
230
+ if (relation.table !== table.model.name || relation.through !== undefined)
231
+ continue;
232
+ edges.push(relation.kind === "many" ? { name: relation.name, parent: relation.local, child: relation.remote } : { name: relation.name, parent: relation.remote, child: relation.local });
233
+ }
234
+ return edges;
235
+ }
236
+ function identityColumn2(session, table) {
237
+ const tenancy = session.schema.tenancy;
238
+ const keys = tenancy === undefined ? [] : tenancy.keys ?? [tenancy.key];
239
+ const fields = table.model.primary.filter((field) => !keys.includes(field));
240
+ if (fields.length !== 1) {
241
+ fail2("OKM1120", `${table.model.name} needs one primary key column besides the tenant key.`, "Use a single-column primary key.");
242
+ }
243
+ const field = fields[0];
244
+ const column = field === undefined ? undefined : table.columns.get(field);
245
+ if (column === undefined) {
246
+ fail2("OKM1120", `${table.model.name} needs one primary key column besides the tenant key.`);
247
+ }
248
+ return column;
249
+ }
250
+ function readDepth(value) {
251
+ if (value === undefined)
252
+ return;
253
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
254
+ fail2("OKM1120", "depth must be an integer from 0 up.");
255
+ }
256
+ return value;
257
+ }
258
+ function readSelf(value) {
259
+ if (value === undefined)
260
+ return false;
261
+ if (typeof value !== "boolean")
262
+ fail2("OKM1120", "self must be true or false.");
263
+ return value;
264
+ }
265
+ function userId(column, id) {
266
+ if (id === undefined || id === null) {
267
+ fail2("OKM1121", `${column.field} needs a value.`);
268
+ }
269
+ return id;
270
+ }
271
+
272
+ export { build2, identityColumn2 };