turbine-orm 0.81.0 → 0.90.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 (295) hide show
  1. package/README.md +26 -25
  2. package/dist/checkout.d.ts +27 -2
  3. package/dist/checkout.js +75 -4
  4. package/dist/cjs/checkout.d.ts +27 -2
  5. package/dist/cjs/checkout.js +76 -3
  6. package/dist/cjs/cli/code-first-tags.d.ts +62 -0
  7. package/dist/cjs/cli/code-first-tags.js +124 -0
  8. package/dist/cjs/cli/compile-query.js +9 -0
  9. package/dist/cjs/cli/config.d.ts +35 -6
  10. package/dist/cjs/cli/config.js +17 -1
  11. package/dist/cjs/cli/destructive.d.ts +7 -4
  12. package/dist/cjs/cli/destructive.js +224 -20
  13. package/dist/cjs/cli/error-catalog.js +36 -0
  14. package/dist/cjs/cli/error-text.d.ts +15 -0
  15. package/dist/cjs/cli/error-text.js +40 -0
  16. package/dist/cjs/cli/index.d.ts +62 -4
  17. package/dist/cjs/cli/index.js +568 -108
  18. package/dist/cjs/cli/local-server-guard.d.ts +53 -0
  19. package/dist/cjs/cli/local-server-guard.js +119 -0
  20. package/dist/cjs/cli/local-server-output.d.ts +41 -0
  21. package/dist/cjs/cli/local-server-output.js +103 -0
  22. package/dist/cjs/cli/mcp.d.ts +8 -0
  23. package/dist/cjs/cli/mcp.js +121 -32
  24. package/dist/cjs/cli/migrate.d.ts +113 -5
  25. package/dist/cjs/cli/migrate.js +270 -21
  26. package/dist/cjs/cli/observe.d.ts +6 -1
  27. package/dist/cjs/cli/observe.js +85 -55
  28. package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
  29. package/dist/cjs/cli/pii-predicate-guard.js +98 -37
  30. package/dist/cjs/cli/prisma-resolve.js +17 -13
  31. package/dist/cjs/cli/prisma-schema.js +12 -4
  32. package/dist/cjs/cli/studio-ui.generated.js +1 -1
  33. package/dist/cjs/cli/studio.d.ts +14 -2
  34. package/dist/cjs/cli/studio.js +244 -69
  35. package/dist/cjs/cli/ui.d.ts +1 -1
  36. package/dist/cjs/client.d.ts +558 -85
  37. package/dist/cjs/client.js +1270 -395
  38. package/dist/cjs/connection-guard.d.ts +13 -0
  39. package/dist/cjs/connection-guard.js +28 -0
  40. package/dist/cjs/connection-url.d.ts +51 -16
  41. package/dist/cjs/connection-url.js +67 -34
  42. package/dist/cjs/diagnostics.d.ts +81 -0
  43. package/dist/cjs/diagnostics.js +147 -0
  44. package/dist/cjs/dialect.d.ts +449 -20
  45. package/dist/cjs/dialect.js +117 -76
  46. package/dist/cjs/engine-config.d.ts +7 -6
  47. package/dist/cjs/errors.d.ts +126 -6
  48. package/dist/cjs/errors.js +256 -13
  49. package/dist/cjs/generate.d.ts +57 -7
  50. package/dist/cjs/generate.js +635 -279
  51. package/dist/cjs/global-filters-config.d.ts +59 -0
  52. package/dist/cjs/global-filters-config.js +367 -0
  53. package/dist/cjs/index.d.ts +9 -4
  54. package/dist/cjs/index.js +10 -2
  55. package/dist/cjs/introspect.d.ts +31 -6
  56. package/dist/cjs/introspect.js +108 -50
  57. package/dist/cjs/log-codes.d.ts +12 -0
  58. package/dist/cjs/log-codes.js +77 -0
  59. package/dist/cjs/logger.d.ts +87 -0
  60. package/dist/cjs/logger.js +98 -0
  61. package/dist/cjs/mssql.d.ts +8 -5
  62. package/dist/cjs/mssql.js +352 -65
  63. package/dist/cjs/mysql.d.ts +3 -5
  64. package/dist/cjs/mysql.js +420 -70
  65. package/dist/cjs/nested-write.d.ts +3 -0
  66. package/dist/cjs/nested-write.js +179 -114
  67. package/dist/cjs/pipeline-submittable.d.ts +12 -0
  68. package/dist/cjs/pipeline-submittable.js +118 -44
  69. package/dist/cjs/pipeline.js +21 -26
  70. package/dist/cjs/powdb-introspect.d.ts +5 -2
  71. package/dist/cjs/powdb-introspect.js +20 -15
  72. package/dist/cjs/powdb-shared.d.ts +36 -5
  73. package/dist/cjs/powdb-shared.js +67 -8
  74. package/dist/cjs/powdb.d.ts +4 -0
  75. package/dist/cjs/powdb.js +183 -51
  76. package/dist/cjs/powql.d.ts +394 -51
  77. package/dist/cjs/powql.js +1829 -284
  78. package/dist/cjs/prisma-compat.d.ts +23 -15
  79. package/dist/cjs/prisma-compat.js +507 -372
  80. package/dist/cjs/query/aggregates.d.ts +17 -1
  81. package/dist/cjs/query/aggregates.js +261 -29
  82. package/dist/cjs/query/batched-loader.d.ts +25 -6
  83. package/dist/cjs/query/batched-loader.js +103 -20
  84. package/dist/cjs/query/builder.d.ts +325 -184
  85. package/dist/cjs/query/builder.js +1452 -490
  86. package/dist/cjs/query/column-ref.d.ts +61 -0
  87. package/dist/cjs/query/column-ref.js +73 -0
  88. package/dist/cjs/query/compound-unique.d.ts +21 -0
  89. package/dist/cjs/query/compound-unique.js +98 -18
  90. package/dist/cjs/query/deferred.d.ts +53 -16
  91. package/dist/cjs/query/expr.d.ts +217 -0
  92. package/dist/cjs/query/expr.js +859 -0
  93. package/dist/cjs/query/filters.d.ts +155 -53
  94. package/dist/cjs/query/filters.js +613 -76
  95. package/dist/cjs/query/index.d.ts +2 -0
  96. package/dist/cjs/query/index.js +7 -1
  97. package/dist/cjs/query/json-value.d.ts +43 -0
  98. package/dist/cjs/query/json-value.js +59 -0
  99. package/dist/cjs/query/normalize-args.d.ts +87 -0
  100. package/dist/cjs/query/normalize-args.js +527 -0
  101. package/dist/cjs/query/option-surface.d.ts +16 -4
  102. package/dist/cjs/query/option-surface.js +57 -14
  103. package/dist/cjs/query/relation-names.d.ts +14 -0
  104. package/dist/cjs/query/relation-names.js +77 -18
  105. package/dist/cjs/query/relations.d.ts +30 -3
  106. package/dist/cjs/query/relations.js +219 -63
  107. package/dist/cjs/query/row-lock.d.ts +49 -0
  108. package/dist/cjs/query/row-lock.js +138 -0
  109. package/dist/cjs/query/sql-comment.d.ts +161 -0
  110. package/dist/cjs/query/sql-comment.js +381 -0
  111. package/dist/cjs/query/stream-idle.d.ts +132 -0
  112. package/dist/cjs/query/stream-idle.js +212 -0
  113. package/dist/cjs/query/table-client.d.ts +101 -0
  114. package/dist/cjs/query/table-client.js +74 -0
  115. package/dist/cjs/query/types.d.ts +677 -298
  116. package/dist/cjs/query/utils.d.ts +105 -6
  117. package/dist/cjs/query/utils.js +426 -19
  118. package/dist/cjs/query/warn-registry.d.ts +18 -0
  119. package/dist/cjs/query/warn-registry.js +18 -0
  120. package/dist/cjs/query/where-compile.d.ts +138 -14
  121. package/dist/cjs/query/where-compile.js +513 -29
  122. package/dist/cjs/query/where.d.ts +159 -59
  123. package/dist/cjs/query/where.js +716 -246
  124. package/dist/cjs/query/writes.d.ts +112 -50
  125. package/dist/cjs/query/writes.js +1498 -200
  126. package/dist/cjs/query-events.d.ts +4 -2
  127. package/dist/cjs/query-events.js +3 -1
  128. package/dist/cjs/realtime.d.ts +7 -3
  129. package/dist/cjs/realtime.js +13 -2
  130. package/dist/cjs/schema-builder.d.ts +55 -4
  131. package/dist/cjs/schema-builder.js +382 -18
  132. package/dist/cjs/schema-metadata.d.ts +21 -1
  133. package/dist/cjs/schema-metadata.js +29 -7
  134. package/dist/cjs/schema-sql.d.ts +75 -5
  135. package/dist/cjs/schema-sql.js +497 -45
  136. package/dist/cjs/schema.d.ts +26 -5
  137. package/dist/cjs/schema.js +110 -13
  138. package/dist/cjs/sql-placeholders.d.ts +56 -0
  139. package/dist/cjs/sql-placeholders.js +204 -0
  140. package/dist/cjs/sqlite.d.ts +75 -20
  141. package/dist/cjs/sqlite.js +593 -95
  142. package/dist/cjs/supplied-pool-types.d.ts +48 -0
  143. package/dist/cjs/supplied-pool-types.js +256 -0
  144. package/dist/cjs/transaction-control.d.ts +51 -0
  145. package/dist/cjs/transaction-control.js +316 -0
  146. package/dist/cjs/transaction-state.d.ts +342 -0
  147. package/dist/cjs/transaction-state.js +707 -0
  148. package/dist/cjs/typed-sql.d.ts +37 -3
  149. package/dist/cjs/typed-sql.js +102 -8
  150. package/dist/cli/code-first-tags.d.ts +62 -0
  151. package/dist/cli/code-first-tags.js +120 -0
  152. package/dist/cli/compile-query.js +9 -0
  153. package/dist/cli/config.d.ts +35 -6
  154. package/dist/cli/config.js +16 -1
  155. package/dist/cli/destructive.d.ts +7 -4
  156. package/dist/cli/destructive.js +224 -20
  157. package/dist/cli/error-catalog.js +36 -0
  158. package/dist/cli/error-text.d.ts +15 -0
  159. package/dist/cli/error-text.js +37 -0
  160. package/dist/cli/index.d.ts +62 -4
  161. package/dist/cli/index.js +569 -112
  162. package/dist/cli/local-server-guard.d.ts +53 -0
  163. package/dist/cli/local-server-guard.js +113 -0
  164. package/dist/cli/local-server-output.d.ts +41 -0
  165. package/dist/cli/local-server-output.js +98 -0
  166. package/dist/cli/mcp.d.ts +8 -0
  167. package/dist/cli/mcp.js +121 -34
  168. package/dist/cli/migrate.d.ts +113 -5
  169. package/dist/cli/migrate.js +261 -21
  170. package/dist/cli/observe.d.ts +6 -1
  171. package/dist/cli/observe.js +84 -54
  172. package/dist/cli/pii-predicate-guard.d.ts +43 -23
  173. package/dist/cli/pii-predicate-guard.js +100 -35
  174. package/dist/cli/prisma-resolve.js +15 -11
  175. package/dist/cli/prisma-schema.js +12 -4
  176. package/dist/cli/studio-ui.generated.js +1 -1
  177. package/dist/cli/studio.d.ts +14 -2
  178. package/dist/cli/studio.js +246 -71
  179. package/dist/cli/ui.d.ts +1 -1
  180. package/dist/client.d.ts +558 -85
  181. package/dist/client.js +1275 -400
  182. package/dist/connection-guard.d.ts +13 -0
  183. package/dist/connection-guard.js +27 -0
  184. package/dist/connection-url.d.ts +51 -16
  185. package/dist/connection-url.js +63 -34
  186. package/dist/diagnostics.d.ts +81 -0
  187. package/dist/diagnostics.js +144 -0
  188. package/dist/dialect.d.ts +449 -20
  189. package/dist/dialect.js +115 -43
  190. package/dist/engine-config.d.ts +7 -6
  191. package/dist/errors.d.ts +126 -6
  192. package/dist/errors.js +252 -12
  193. package/dist/generate.d.ts +57 -7
  194. package/dist/generate.js +635 -281
  195. package/dist/global-filters-config.d.ts +59 -0
  196. package/dist/global-filters-config.js +361 -0
  197. package/dist/index.d.ts +9 -4
  198. package/dist/index.js +4 -2
  199. package/dist/introspect.d.ts +31 -6
  200. package/dist/introspect.js +106 -50
  201. package/dist/log-codes.d.ts +12 -0
  202. package/dist/log-codes.js +74 -0
  203. package/dist/logger.d.ts +87 -0
  204. package/dist/logger.js +93 -0
  205. package/dist/mssql.d.ts +8 -5
  206. package/dist/mssql.js +354 -67
  207. package/dist/mysql.d.ts +3 -5
  208. package/dist/mysql.js +423 -73
  209. package/dist/nested-write.d.ts +3 -0
  210. package/dist/nested-write.js +177 -112
  211. package/dist/pipeline-submittable.d.ts +12 -0
  212. package/dist/pipeline-submittable.js +117 -44
  213. package/dist/pipeline.js +21 -26
  214. package/dist/powdb-introspect.d.ts +5 -2
  215. package/dist/powdb-introspect.js +21 -16
  216. package/dist/powdb-shared.d.ts +36 -5
  217. package/dist/powdb-shared.js +65 -8
  218. package/dist/powdb.d.ts +4 -0
  219. package/dist/powdb.js +183 -51
  220. package/dist/powql.d.ts +394 -51
  221. package/dist/powql.js +1836 -291
  222. package/dist/prisma-compat.d.ts +23 -15
  223. package/dist/prisma-compat.js +508 -373
  224. package/dist/query/aggregates.d.ts +17 -1
  225. package/dist/query/aggregates.js +263 -32
  226. package/dist/query/batched-loader.d.ts +25 -6
  227. package/dist/query/batched-loader.js +101 -21
  228. package/dist/query/builder.d.ts +325 -184
  229. package/dist/query/builder.js +1458 -495
  230. package/dist/query/column-ref.d.ts +61 -0
  231. package/dist/query/column-ref.js +66 -0
  232. package/dist/query/compound-unique.d.ts +21 -0
  233. package/dist/query/compound-unique.js +97 -19
  234. package/dist/query/deferred.d.ts +53 -16
  235. package/dist/query/expr.d.ts +217 -0
  236. package/dist/query/expr.js +848 -0
  237. package/dist/query/filters.d.ts +155 -53
  238. package/dist/query/filters.js +597 -72
  239. package/dist/query/index.d.ts +2 -0
  240. package/dist/query/index.js +4 -0
  241. package/dist/query/json-value.d.ts +43 -0
  242. package/dist/query/json-value.js +54 -0
  243. package/dist/query/normalize-args.d.ts +87 -0
  244. package/dist/query/normalize-args.js +517 -0
  245. package/dist/query/option-surface.d.ts +16 -4
  246. package/dist/query/option-surface.js +56 -13
  247. package/dist/query/relation-names.d.ts +14 -0
  248. package/dist/query/relation-names.js +77 -19
  249. package/dist/query/relations.d.ts +30 -3
  250. package/dist/query/relations.js +220 -67
  251. package/dist/query/row-lock.d.ts +49 -0
  252. package/dist/query/row-lock.js +131 -0
  253. package/dist/query/sql-comment.d.ts +161 -0
  254. package/dist/query/sql-comment.js +374 -0
  255. package/dist/query/stream-idle.d.ts +132 -0
  256. package/dist/query/stream-idle.js +203 -0
  257. package/dist/query/table-client.d.ts +101 -0
  258. package/dist/query/table-client.js +70 -0
  259. package/dist/query/types.d.ts +677 -298
  260. package/dist/query/utils.d.ts +105 -6
  261. package/dist/query/utils.js +414 -18
  262. package/dist/query/warn-registry.d.ts +18 -0
  263. package/dist/query/warn-registry.js +18 -0
  264. package/dist/query/where-compile.d.ts +138 -14
  265. package/dist/query/where-compile.js +508 -31
  266. package/dist/query/where.d.ts +159 -59
  267. package/dist/query/where.js +711 -248
  268. package/dist/query/writes.d.ts +112 -50
  269. package/dist/query/writes.js +1496 -202
  270. package/dist/query-events.d.ts +4 -2
  271. package/dist/query-events.js +3 -1
  272. package/dist/realtime.d.ts +7 -3
  273. package/dist/realtime.js +13 -2
  274. package/dist/schema-builder.d.ts +55 -4
  275. package/dist/schema-builder.js +381 -18
  276. package/dist/schema-metadata.d.ts +21 -1
  277. package/dist/schema-metadata.js +28 -7
  278. package/dist/schema-sql.d.ts +75 -5
  279. package/dist/schema-sql.js +494 -44
  280. package/dist/schema.d.ts +26 -5
  281. package/dist/schema.js +109 -13
  282. package/dist/sql-placeholders.d.ts +56 -0
  283. package/dist/sql-placeholders.js +200 -0
  284. package/dist/sqlite.d.ts +75 -20
  285. package/dist/sqlite.js +597 -99
  286. package/dist/supplied-pool-types.d.ts +48 -0
  287. package/dist/supplied-pool-types.js +247 -0
  288. package/dist/transaction-control.d.ts +51 -0
  289. package/dist/transaction-control.js +311 -0
  290. package/dist/transaction-state.d.ts +342 -0
  291. package/dist/transaction-state.js +696 -0
  292. package/dist/typed-sql.d.ts +37 -3
  293. package/dist/typed-sql.js +100 -8
  294. package/package.json +7 -4
  295. package/skills/turbine-orm/SKILL.md +56 -6
@@ -55,7 +55,10 @@
55
55
  * @module
56
56
  */
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.STITCH_ONLY_FIELDS = void 0;
58
59
  exports.defaultProjectionFields = defaultProjectionFields;
60
+ exports.stitchOnlyFields = stitchOnlyFields;
61
+ exports.markStitchOnly = markStitchOnly;
59
62
  exports.assertProjectionShape = assertProjectionShape;
60
63
  exports.includeKeysForBatching = includeKeysForBatching;
61
64
  exports.stripFields = stripFields;
@@ -250,14 +253,40 @@ includePii) {
250
253
  return hidden.size === 0 ? undefined : { hidden, visible };
251
254
  }
252
255
  /**
253
- * Adjust a `select`/`omit` pair so that `fields` are guaranteed present in the
254
- * query result, returning the adjusted projection plus the list of fields that
255
- * were added ONLY for stitching and must be stripped from the final entities.
256
+ * Key under which {@link includeKeysForBatching} records the fields IT added to
257
+ * a `select`, as a `ReadonlySet<string>` of field names.
256
258
  *
257
- * Used both for the base query (parent keys) and each follow-up query (child
258
- * keys) so a caller's `select: { title: true }` on a relation still stitches even
259
- * though the FK was not requested, and the FK never appears in the output.
259
+ * Why it exists: naming a PII-tagged column in `select` is refused unless the
260
+ * query passes `includePii: UNSAFE` (see `resolveProjection`), and the loader
261
+ * has to project a correlation or ordering column that may itself be tagged.
262
+ * That column is stripped from every entity before the caller sees it, so it is
263
+ * the one legitimate way a PII name reaches a `select` without the caller
264
+ * writing it. The marker is a symbol key: `Object.keys`, `Object.entries`,
265
+ * spreads of a parsed body and `JSON.stringify` never see one, and
266
+ * `JSON.parse` cannot produce one, so request data cannot forge the exemption.
260
267
  */
268
+ exports.STITCH_ONLY_FIELDS = Symbol.for('turbine.stitchOnlyFields');
269
+ /** The fields the batched loader (not the caller) added to this `select`, if any. */
270
+ function stitchOnlyFields(select) {
271
+ if (!select)
272
+ return undefined;
273
+ const marked = select[exports.STITCH_ONLY_FIELDS];
274
+ return marked instanceof Set ? marked : undefined;
275
+ }
276
+ /** Record `fields` on `select` as added by an engine loader, not by the caller. Returns `select`. */
277
+ function markStitchOnly(select, fields) {
278
+ // Non-enumerable, like the other engine-written markers: the select object is
279
+ // passed by reference from here to the child build, and an enumerable symbol
280
+ // would show up in deep-equality comparisons of the projection.
281
+ if (fields.length > 0) {
282
+ Object.defineProperty(select, exports.STITCH_ONLY_FIELDS, {
283
+ value: new Set(fields),
284
+ enumerable: false,
285
+ configurable: true,
286
+ });
287
+ }
288
+ return select;
289
+ }
261
290
  /**
262
291
  * The two projection SHAPE rules from `resolveProjection`, checked on the RAW
263
292
  * caller args BEFORE `includeKeysForBatching` adjusts them. The adjustment
@@ -279,6 +308,16 @@ function assertProjectionShape(table, select, omit) {
279
308
  throw new errors_js_1.ValidationError((0, utils_js_1.selectOmitExclusiveMessage)(table));
280
309
  }
281
310
  }
311
+ /**
312
+ * Adjust a `select`/`omit` pair so that `fields` are guaranteed present in the
313
+ * query result, returning the adjusted projection plus the list of fields that
314
+ * were added ONLY for stitching and must be stripped from the final entities.
315
+ *
316
+ * Used both for the base query (parent keys) and each follow-up query (child
317
+ * keys) so a caller's `select: { title: true }` on a relation still stitches even
318
+ * though the FK was not requested, and the FK never appears in the output. A
319
+ * returned `select` carries {@link STITCH_ONLY_FIELDS} for the fields added here.
320
+ */
282
321
  function includeKeysForBatching(
283
322
  /**
284
323
  * The table the projection is compiled against. `select` / `omit` keys are
@@ -331,7 +370,7 @@ defaultProjection) {
331
370
  next[f] = true;
332
371
  strip.push(f); // not requested by the caller, added only to stitch
333
372
  }
334
- return { select: next, omit, strip };
373
+ return { select: markStitchOnly(next, strip), omit, strip };
335
374
  }
336
375
  if (omit) {
337
376
  const next = { ...omit };
@@ -357,7 +396,7 @@ defaultProjection) {
357
396
  explicit[f] = true;
358
397
  for (const f of hiddenKeys)
359
398
  explicit[f] = true;
360
- return { select: explicit, omit: undefined, strip: hiddenKeys };
399
+ return { select: markStitchOnly(explicit, hiddenKeys), omit: undefined, strip: hiddenKeys };
361
400
  }
362
401
  return { select, omit, strip: [] };
363
402
  }
@@ -439,8 +478,22 @@ function resolveCountRelations(parentMeta, countSpec) {
439
478
  }
440
479
  return out;
441
480
  }
442
- /** Stringified stitch key, robust to number/uuid/bigint type drift across a join. */
481
+ /**
482
+ * Stringified stitch key, robust to number/uuid/bigint type drift across a join.
483
+ * A binary key is keyed by its bytes: `String()` of a Buffer decodes it as
484
+ * UTF-8, which maps different invalid sequences to the same replacement text.
485
+ * A Date by its instant, which `String()` truncates to the second.
486
+ */
443
487
  function keyOf(value) {
488
+ if (value instanceof Uint8Array) {
489
+ // No Buffer: this module runs on edge runtimes too.
490
+ let hex = '\u0000bytes:';
491
+ for (const byte of value)
492
+ hex += byte.toString(16).padStart(2, '0');
493
+ return hex;
494
+ }
495
+ if (value instanceof Date)
496
+ return `\u0000date:${value.getTime()}`;
444
497
  return String(value);
445
498
  }
446
499
  /**
@@ -609,6 +662,34 @@ function seedRelationKeys(parents, parentMeta, resolved, hasCount) {
609
662
  parent._count = existingCount ?? {};
610
663
  }
611
664
  }
665
+ /**
666
+ * A to-many relation's per-parent page (`skip` / `take` are folded into
667
+ * `offset` / `limit` at the args seam), validated as the join plan validates
668
+ * it: a non-negative integer, numeric strings coerced. Checked before anything
669
+ * runs, so both strategies accept and refuse the same values.
670
+ */
671
+ function relationPage(options, table) {
672
+ const check = (value, arg) => {
673
+ if (value === undefined)
674
+ return undefined;
675
+ const n = Number(value);
676
+ if (!Number.isSafeInteger(n) || n < 0) {
677
+ throw new errors_js_1.ValidationError(`${arg} on "${table}" must be a non-negative integer, received: ${String(value)}`);
678
+ }
679
+ return n;
680
+ };
681
+ return {
682
+ limit: check(options.limit, 'relation limit'),
683
+ offset: check(options.offset, 'relation offset'),
684
+ };
685
+ }
686
+ /** One parent's window of its own related rows. */
687
+ function pageOf(rows, page) {
688
+ if (page.limit === undefined && !page.offset)
689
+ return rows;
690
+ const start = page.offset ?? 0;
691
+ return rows.slice(start, page.limit === undefined ? undefined : start + page.limit);
692
+ }
612
693
  /**
613
694
  * hasMany / hasOne / belongsTo: one follow-up `SELECT ... WHERE childKey = ANY($1)`
614
695
  * (chunked), grouped by the correlation key and attached (array vs single-or-null).
@@ -630,6 +711,7 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
630
711
  assertCorrelationKeyProjected(parents, parentKeyField, relName, ctx.parentMeta.name);
631
712
  const keys = uniqueKeys(parents, parentKeyField);
632
713
  const single = rel.type === 'belongsTo' || rel.type === 'hasOne';
714
+ const page = single ? {} : relationPage(options, ctx.parentMeta.name);
633
715
  // The follow-up must project the child correlation key even if the caller's
634
716
  // select/omit excluded it; strip it back off afterwards so the shape matches join.
635
717
  //
@@ -648,7 +730,7 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
648
730
  // again afterwards). `null` means this relation keeps the client-side slice,
649
731
  // which is the case for every shape whose ordering does not force WHICH rows
650
732
  // the limit keeps. See {@link partitionOrderBy} and {@link boundedChildQuery}.
651
- const windowOrder = single || options.limit === undefined ? null : partitionOrderBy(targetMeta, options.orderBy);
733
+ const windowOrder = single || page.limit === undefined ? null : partitionOrderBy(targetMeta, options.orderBy);
652
734
  const pushDownLimit = windowOrder !== null && ctx.buildPartitionLimit !== undefined;
653
735
  // THE ONE PII EXCEPTION IN THE READ PATH, recorded here because the contract
654
736
  // in schema.ts says a PII column is excluded from every default projection
@@ -699,7 +781,8 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
699
781
  const chunkResults = await Promise.all(chunks.map(async (chunk) => {
700
782
  const deferred = buildChunk(chunk);
701
783
  const bounded = pushDownLimit
702
- ? boundedChildQuery(ctx, deferred, childKeyCol, windowOrder ?? [], options.limit)
784
+ ? // The first offset + limit rows of each parent; the slice below drops the offset.
785
+ boundedChildQuery(ctx, deferred, childKeyCol, windowOrder ?? [], (page.offset ?? 0) + page.limit)
703
786
  : deferred;
704
787
  const result = await ctx.exec(bounded.sql, bounded.params, bounded.preparedName);
705
788
  if (bounded !== deferred)
@@ -721,14 +804,13 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
721
804
  // what was true of the parent side until this week.
722
805
  assertCorrelationKeyProjected(allChildren, childKeyField, relName, targetMeta.name);
723
806
  const byKey = groupBy(allChildren, childKeyField);
724
- const limit = options.limit;
725
807
  for (const parent of parents) {
726
808
  const bucket = byKey.get(keyOf(parent[parentKeyField])) ?? [];
727
809
  if (single) {
728
810
  parent[relName] = bucket[0] ?? null;
729
811
  }
730
812
  else {
731
- parent[relName] = limit !== undefined ? bucket.slice(0, limit) : bucket;
813
+ parent[relName] = pageOf(bucket, page);
732
814
  }
733
815
  }
734
816
  stripFields(allChildren, proj.strip);
@@ -789,7 +871,7 @@ function boundedChildQuery(ctx, deferred, partitionColumn, orderBy, limit) {
789
871
  return {
790
872
  sql,
791
873
  params: [...deferred.params, limit],
792
- preparedName: deferred.preparedName ? (0, utils_js_1.sqlToPreparedName)(sql) : deferred.preparedName,
874
+ preparedName: deferred.preparedName ? (0, utils_js_1.boundedPreparedName)(sql) : deferred.preparedName,
793
875
  transform: deferred.transform,
794
876
  };
795
877
  }
@@ -829,6 +911,7 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
829
911
  const targetPkCol = targetMeta.primaryKey[0];
830
912
  const parentRefField = ctx.parentMeta.reverseColumnMap[sourceRefCol] ?? sourceRefCol;
831
913
  const targetPkField = targetMeta.reverseColumnMap[targetPkCol] ?? targetPkCol;
914
+ const page = relationPage(options, ctx.parentMeta.name);
832
915
  assertCorrelationKeyProjected(parents, parentRefField, relName, ctx.parentMeta.name);
833
916
  // No early return on zero parent keys: the code below flows through
834
917
  // naturally (zero junction chunks, zero target chunks), and the compile-only
@@ -920,7 +1003,7 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
920
1003
  // link, which spends exactly the bytes the pushdown exists to save; and the
921
1004
  // bound would still have to respect a `limit` measured per parent, not per
922
1005
  // fetched row. So the m2m loader keeps the slice below, on every engine.
923
- const limit = options.limit;
1006
+ const end = page.limit === undefined ? undefined : (page.offset ?? 0) + page.limit;
924
1007
  for (const parent of parents) {
925
1008
  const linked = new Set((targetsBySource.get(keyOf(parent[parentRefField])) ?? []).map(keyOf));
926
1009
  if (linked.size === 0) {
@@ -929,13 +1012,13 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
929
1012
  }
930
1013
  const out = [];
931
1014
  for (const t of targetsInOrder) {
932
- if (linked.has(keyOf(t[targetPkField]))) {
1015
+ // Checked before the push, so `limit: 0` keeps nothing.
1016
+ if (end !== undefined && out.length >= end)
1017
+ break;
1018
+ if (linked.has(keyOf(t[targetPkField])))
933
1019
  out.push(t);
934
- if (limit !== undefined && out.length >= limit)
935
- break;
936
- }
937
1020
  }
938
- parent[relName] = out;
1021
+ parent[relName] = pageOf(out, { offset: page.offset });
939
1022
  }
940
1023
  stripFields(targetsInOrder, proj.strip);
941
1024
  }