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
@@ -52,9 +52,10 @@
52
52
  * @module
53
53
  */
54
54
  // Runtime imports, and the only ones in this file: the unknown-key warning at
55
- // the bottom needs the once-per-process registry and the name suggester. Both
56
- // are leaves that do not import this module, so the type-only shape of
57
- // everything above is unaffected.
55
+ // the bottom needs the logger, the once-per-process registry and the name
56
+ // suggester. All are leaves that do not import this module, so the type-only
57
+ // shape of everything above is unaffected.
58
+ import { logTo } from '../logger.js';
58
59
  import { suggestKey } from './utils.js';
59
60
  import { shouldWarnOnce, WARN_NS } from './warn-registry.js';
60
61
  export const FIND_UNIQUE_OPTIONS = {
@@ -78,6 +79,9 @@ export const FIND_UNIQUE_OPTIONS = {
78
79
  // schema's naming space, so THE ONE RULE puts it here rather than in the
79
80
  // hand-translated set.
80
81
  jsonEncoding: 'native',
82
+ // A lock mode and a wait flag: no schema name in the value, so compat
83
+ // forwards it unchanged.
84
+ lock: 'native',
81
85
  };
82
86
  export const FIND_MANY_OPTIONS = {
83
87
  where: 'prisma',
@@ -105,12 +109,17 @@ export const FIND_MANY_OPTIONS = {
105
109
  forceCustomPlan: 'native',
106
110
  // See FIND_UNIQUE_OPTIONS: an encoding name carries no schema name.
107
111
  jsonEncoding: 'native',
112
+ lock: 'native',
108
113
  };
114
+ // Streams take findMany's surface minus `lock` (a cursor cannot hold its rows
115
+ // locked across fetches), so the spread drops it by name.
116
+ const { lock: _streamsTakeNoLock, ...FIND_MANY_STREAM_BASE } = FIND_MANY_OPTIONS;
109
117
  export const FIND_MANY_STREAM_OPTIONS = {
110
- ...FIND_MANY_OPTIONS,
111
- // No streaming delegate exists on the compat surface, so this is not a known
112
- // key there and passing it is reported rather than quietly ignored.
118
+ ...FIND_MANY_STREAM_BASE,
119
+ // No streaming delegate exists on the compat surface, so these are not known
120
+ // keys there and passing one is reported rather than quietly ignored.
113
121
  batchSize: 'internal',
122
+ idleTimeoutMs: 'internal',
114
123
  };
115
124
  export const CREATE_OPTIONS = {
116
125
  data: 'prisma',
@@ -122,7 +131,13 @@ export const CREATE_OPTIONS = {
122
131
  export const CREATE_MANY_OPTIONS = {
123
132
  data: 'prisma',
124
133
  skipDuplicates: 'prisma',
134
+ // Field names (the target, the update columns, the projection), and compat's
135
+ // createMany does not expose them, so they are not known keys there.
136
+ onConflict: 'internal',
137
+ select: 'internal',
138
+ omit: 'internal',
125
139
  timeout: 'native',
140
+ skipGlobalFilters: 'native',
126
141
  };
127
142
  export const UPDATE_OPTIONS = {
128
143
  where: 'prisma',
@@ -182,6 +197,8 @@ export const AGGREGATE_OPTIONS = {
182
197
  _avg: 'prisma',
183
198
  _min: 'prisma',
184
199
  _max: 'prisma',
200
+ // Field names in the keys, and Prisma has no percentile aggregate.
201
+ _percentile: 'internal',
185
202
  timeout: 'native',
186
203
  skipGlobalFilters: 'native',
187
204
  includePii: 'native',
@@ -197,6 +214,7 @@ export const GROUP_BY_OPTIONS = {
197
214
  _avg: 'prisma',
198
215
  _min: 'prisma',
199
216
  _max: 'prisma',
217
+ _percentile: 'internal',
200
218
  // `{ columns, orderBy }`, both in FIELD-NAME space. See THE ONE RULE.
201
219
  distinctOn: 'prisma',
202
220
  limit: 'nativeAlias',
@@ -278,7 +296,25 @@ const PRISMA_SPELLING = {
278
296
  include: 'with',
279
297
  };
280
298
  /**
281
- * Dev-mode warning for a key that is not part of the operation's option
299
+ * Keys an operation does not declare but REFUSES by name with its own error
300
+ * (E003 naming the key and the alternative), rather than ignoring. Warning
301
+ * "it is ignored" about one of these would contradict the error that follows,
302
+ * so the warning skips them. Every entry must have a refusal behind it;
303
+ * `src/test/fix-where-option-warnings.test.ts` checks that each one throws.
304
+ */
305
+ export const REFUSED_OPTION_KEYS = {
306
+ // A bounded batch is not what these statements do (assertNoBulkWritePaging).
307
+ updateMany: new Set(['limit', 'take', 'offset', 'skip', 'optimisticLock']),
308
+ deleteMany: new Set(['limit', 'take', 'offset', 'skip', 'optimisticLock']),
309
+ // `optimisticLock` is an `update` option (assertNoOptimisticLock).
310
+ upsert: new Set(['optimisticLock']),
311
+ delete: new Set(['optimisticLock']),
312
+ // A streaming cursor cannot hold its rows locked across fetches.
313
+ findManyStream: new Set(['lock']),
314
+ findManyStreamBatches: new Set(['lock']),
315
+ };
316
+ /**
317
+ * Advice for a key that is not part of the operation's option
282
318
  * surface, and is therefore doing nothing.
283
319
  *
284
320
  * The motivating case is `include`. It is Prisma's word for `with`, it is what
@@ -295,17 +331,21 @@ const PRISMA_SPELLING = {
295
331
  * working query start throwing. A warning costs a correct program nothing and
296
332
  * tells an incorrect one exactly what happened.
297
333
  *
298
- * Dev-only, once per `table.operation.key` per process, and total: the whole
299
- * body is wrapped, because a diagnostic must never be the reason a query fails.
334
+ * Advice: emitted only when the client's `diagnostics.advice` is on. The
335
+ * caller passes its advice logger, or `null` when advice is off, so this
336
+ * module never reads the environment. Once per `table.operation.key` per
337
+ * process, and total: the whole body is wrapped, because a diagnostic must
338
+ * never be the reason a query fails.
300
339
  */
301
- export function warnUnknownQueryOptions(table, operation, args) {
302
- if (process.env.NODE_ENV === 'production')
340
+ export function warnUnknownQueryOptions(table, operation, args, advice) {
341
+ if (!advice)
303
342
  return;
304
343
  if (args === null || typeof args !== 'object' || Array.isArray(args))
305
344
  return;
306
345
  const known = OPERATION_TABLE[operation];
307
346
  if (!known)
308
347
  return;
348
+ const refused = REFUSED_OPTION_KEYS[operation];
309
349
  try {
310
350
  for (const key of Object.keys(args)) {
311
351
  // `{ ...maybeOptions }` routinely materializes keys with no value.
@@ -314,13 +354,16 @@ export function warnUnknownQueryOptions(table, operation, args) {
314
354
  continue;
315
355
  if (Object.hasOwn(known, key))
316
356
  continue;
357
+ // Refused with its own error, which is the diagnostic; not ignored.
358
+ if (refused?.has(key))
359
+ continue;
317
360
  if (!shouldWarnOnce(WARN_NS.unknownQueryOption, `${table}.${operation}.${key}`))
318
361
  continue;
319
362
  const prismaSpelling = PRISMA_SPELLING[key];
320
363
  const suggestion = prismaSpelling ?? suggestKey(key, Object.keys(known));
321
364
  const because = prismaSpelling ? ` Turbine spells this "${prismaSpelling}".` : '';
322
- console.warn(`[turbine] unknown option "${key}" in ${table}.${operation}(), it is ignored.${because}` +
323
- (!prismaSpelling && suggestion ? ` Did you mean "${suggestion}"?` : ''));
365
+ logTo(advice, 'warn', `unknown option "${key}" in ${table}.${operation}(), it is ignored.${because}` +
366
+ (!prismaSpelling && suggestion ? ` Did you mean "${suggestion}"?` : ''), { code: 'unknown-query-option', table, operation, key });
324
367
  }
325
368
  }
326
369
  catch {
@@ -68,3 +68,17 @@ export declare function normalizeWithClause(schema: SchemaMetadata, table: strin
68
68
  * byte-identical.
69
69
  */
70
70
  export declare function applyStableRelationOrderTo(schema: SchemaMetadata, withClause: WithClause, table: string, depth?: number): WithClause;
71
+ /**
72
+ * Fold Prisma's `take` / `skip` into `limit` / `offset` inside every `with`
73
+ * level, by the same rule {@link normalizePagination} applies at the top level
74
+ * (both spellings of one bound with different values throw). Runs once, before
75
+ * any walker reads the tree, so the fingerprint, the join build, the batched
76
+ * loader and the row parser all see `limit` / `offset` and never the aliases.
77
+ *
78
+ * A per-relation `offset` on a to-one relation is refused: the relation is a
79
+ * single row or `null`, so there is nothing to skip past, and silently
80
+ * returning the row anyway would ignore what the caller wrote.
81
+ *
82
+ * Returns the input by reference when nothing changed.
83
+ */
84
+ export declare function normalizeWithPagination(schema: SchemaMetadata, table: string, withClause: WithClause | undefined, depth?: number): WithClause | undefined;
@@ -41,8 +41,9 @@
41
41
  * available relations; rejecting it here would move that error away from its
42
42
  * context and change which error type callers see.
43
43
  */
44
+ import { ValidationError } from '../errors.js';
44
45
  import { isEmptyOrderBy } from './filters.js';
45
- import { resolveRelation, resolveRelationDef } from './utils.js';
46
+ import { normalizePagination, resolveRelation, resolveRelationDef } from './utils.js';
46
47
  /** Depth cap mirroring the builder's own, so a cyclic `with` cannot spin here. */
47
48
  const MAX_DEPTH = 12;
48
49
  /**
@@ -57,27 +58,36 @@ export function normalizeWithClause(schema, table, withClause, depth = 0) {
57
58
  const meta = schema.tables[table];
58
59
  if (!meta)
59
60
  return withClause;
60
- let changed = false;
61
- const out = {};
62
- for (const [key, spec] of Object.entries(withClause)) {
61
+ // The copy is allocated only once something changes (the common call
62
+ // spells every relation the declared way and allocates nothing); the keys
63
+ // before that point are copied in order, so the result is the same object
64
+ // the eager version built.
65
+ let out;
66
+ const source = withClause;
67
+ const keys = Object.keys(source);
68
+ for (let i = 0; i < keys.length; i++) {
69
+ const key = keys[i];
70
+ const spec = source[key];
71
+ let name = key;
72
+ let nextSpec;
63
73
  if (key === '_count') {
64
- const nextCount = normalizeCount(meta, spec);
65
- if (nextCount !== spec)
66
- changed = true;
67
- out[key] = nextCount;
68
- continue;
74
+ nextSpec = normalizeCount(meta, spec);
69
75
  }
70
- const resolved = resolveRelation(meta.relations, key);
71
- // Unknown key: keep it verbatim and let the builder raise E005 by name.
72
- const name = resolved?.name ?? key;
73
- if (name !== key)
74
- changed = true;
75
- const nextSpec = resolved ? normalizeSpec(schema, resolved.def.to, spec, depth) : spec;
76
- if (nextSpec !== spec)
77
- changed = true;
78
- out[name] = nextSpec;
76
+ else {
77
+ const resolved = resolveRelation(meta.relations, key);
78
+ // Unknown key: keep it verbatim and let the builder raise E005 by name.
79
+ name = resolved?.name ?? key;
80
+ nextSpec = resolved ? normalizeSpec(schema, resolved.def.to, spec, depth) : spec;
81
+ }
82
+ if (out === undefined && (name !== key || nextSpec !== spec)) {
83
+ out = {};
84
+ for (let j = 0; j < i; j++)
85
+ out[keys[j]] = source[keys[j]];
86
+ }
87
+ if (out !== undefined)
88
+ out[name] = nextSpec;
79
89
  }
80
- return changed ? out : withClause;
90
+ return out ?? withClause;
81
91
  }
82
92
  /** A relation's `with` options, normalizing its nested `with` against the TARGET table. */
83
93
  function normalizeSpec(schema, target, spec, depth) {
@@ -174,3 +184,51 @@ export function applyStableRelationOrderTo(schema, withClause, table, depth = 0)
174
184
  }
175
185
  return out ?? withClause;
176
186
  }
187
+ /**
188
+ * Fold Prisma's `take` / `skip` into `limit` / `offset` inside every `with`
189
+ * level, by the same rule {@link normalizePagination} applies at the top level
190
+ * (both spellings of one bound with different values throw). Runs once, before
191
+ * any walker reads the tree, so the fingerprint, the join build, the batched
192
+ * loader and the row parser all see `limit` / `offset` and never the aliases.
193
+ *
194
+ * A per-relation `offset` on a to-one relation is refused: the relation is a
195
+ * single row or `null`, so there is nothing to skip past, and silently
196
+ * returning the row anyway would ignore what the caller wrote.
197
+ *
198
+ * Returns the input by reference when nothing changed.
199
+ */
200
+ export function normalizeWithPagination(schema, table, withClause, depth = 0) {
201
+ if (!withClause || typeof withClause !== 'object' || depth > MAX_DEPTH)
202
+ return withClause;
203
+ const meta = schema.tables[table];
204
+ if (!meta)
205
+ return withClause;
206
+ let out;
207
+ // Object.keys, not Object.entries: no [key, value] pair allocated per key.
208
+ const keys = Object.keys(withClause);
209
+ for (let i = 0; i < keys.length; i++) {
210
+ const key = keys[i];
211
+ const spec = withClause[key];
212
+ if (key === '_count' || spec === null || typeof spec !== 'object')
213
+ continue;
214
+ const rel = resolveRelation(meta.relations, key);
215
+ if (!rel)
216
+ continue; // unknown relation: the builder raises E005 by name
217
+ const folded = normalizePagination(spec);
218
+ const offset = folded.offset;
219
+ if (offset !== undefined && (rel.def.type === 'belongsTo' || rel.def.type === 'hasOne')) {
220
+ throw new ValidationError(`\`offset\` (or \`skip\`) on the to-one relation "${rel.name}" of "${table}" has nothing to skip: ` +
221
+ 'a to-one relation is a single row or null. Remove it, or page the relation from its own table.');
222
+ }
223
+ const nested = folded.with;
224
+ const nextNested = nested ? normalizeWithPagination(schema, rel.def.to, nested, depth + 1) : nested;
225
+ let next = folded;
226
+ if (nextNested !== nested)
227
+ next = { ...folded, with: nextNested };
228
+ if (next !== spec) {
229
+ out ??= { ...withClause };
230
+ out[key] = next;
231
+ }
232
+ }
233
+ return out ?? withClause;
234
+ }
@@ -33,6 +33,14 @@ export interface RelationShape {
33
33
  nested: Record<string, RelationShape>;
34
34
  cardinality: 'many' | 'one';
35
35
  }
36
+ /**
37
+ * The E003 text for a PII-tagged column named in `select` without
38
+ * `includePii: UNSAFE`. Shared by every projection path through
39
+ * {@link resolveProjection}, so a top-level read, a `with` relation (join,
40
+ * batched, flatten and positional alike) and a single-row write refuse in the
41
+ * same words. The write path is named because it cannot pass the opt-in at all.
42
+ */
43
+ export declare function piiSelectRefusedMessage(table: string, field: string): string;
36
44
  /**
37
45
  * Resolve `select` / `omit` into a list of snake_case column names, for the
38
46
  * query's own table and for a relation target alike. `null` means "no
@@ -76,6 +84,11 @@ export declare function resolveColumns(qi: BuilderCtx, select?: Record<string, b
76
84
  * is a shared authority rather than a guard repeated per walker.
77
85
  */
78
86
  export declare function relationOptions(spec: true | WithOptions): WithOptions;
87
+ /**
88
+ * A to-many relation's `offset` (`skip` is folded into it at the args seam by
89
+ * `normalizeWithPagination`, which also refuses it on a to-one relation).
90
+ */
91
+ export declare function relationOffset(opts: WithOptions): unknown;
79
92
  /**
80
93
  * Produce a fingerprint for a `with` clause tree. Recursion mirrors
81
94
  * buildSelectWithRelations / buildRelationSubquery.
@@ -116,9 +129,9 @@ export declare function buildOrderBy(qi: BuilderCtx, orderBy: OrderByClause, par
116
129
  export declare function isRelationOrderByValue(_qi: BuilderCtx, value: unknown): boolean;
117
130
  /**
118
131
  * Render the ` NULLS FIRST` / ` NULLS LAST` suffix for a column ordering.
119
- * Only PostgreSQL and SQLite support the `NULLS FIRST/LAST` grammar, on any
120
- * other engine a caller asking for explicit nulls placement gets a clear
121
- * {@link UnsupportedFeatureError} (E017) instead of broken SQL.
132
+ * On an engine without the `NULLS FIRST/LAST` grammar (`nullsOrderingClause`:
133
+ * PostgreSQL and SQLite have it) a caller asking for explicit nulls placement
134
+ * gets a clear {@link UnsupportedFeatureError} (E017) instead of broken SQL.
122
135
  */
123
136
  export declare function nullsSuffix(qi: BuilderCtx, nulls: 'first' | 'last' | undefined): string;
124
137
  /**
@@ -171,6 +184,20 @@ export declare function buildRelationOrderBy(qi: BuilderCtx, relName: string, va
171
184
  table: string;
172
185
  parentRef: string;
173
186
  }, lateralSink?: string[]): string;
187
+ /**
188
+ * Param-collect mirror of a TO-ONE relation orderBy entry, done by running
189
+ * {@link buildRelationOrderBy} and discarding its SQL. The build pushes the
190
+ * target's global filter once per ordered column and, for a chained
191
+ * `{ author: { org: { name } } }` ordering, once more per hop table, in hop
192
+ * order. A hand-written mirror that pushed one filter per column bound too few
193
+ * params (and in the wrong order) as soon as a hop table had a filter, so this
194
+ * mirror is the build itself and cannot drift from it.
195
+ */
196
+ export declare function collectToOneRelationOrderParams(qi: BuilderCtx, relName: string, value: Record<string, unknown>, params: unknown[], ctx?: {
197
+ meta: TableMetadata;
198
+ table: string;
199
+ parentRef: string;
200
+ }): void;
174
201
  /**
175
202
  * Validate a {@link RelationPickOrderBy} entry's scope and shape. Shared by
176
203
  * the SQL-build path ({@link buildRelationPickOrderBy}) and the cache-hit