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
@@ -0,0 +1,527 @@
1
+ "use strict";
2
+ /**
3
+ * `undefined` means absent, decided ONCE at the args seam.
4
+ *
5
+ * Every public operation (and its `build*` twin) runs its args through
6
+ * {@link pruneUndefinedArgs} before anything else reads them: the empty-`where`
7
+ * guards, the SQL-cache fingerprint, the SQL build and the param collect. A key
8
+ * whose value is `undefined` is removed, and so is an object (or combinator
9
+ * array) that BECOMES empty because of it, recursively, so
10
+ * `{ user: { email: undefined } }` is exactly `{}`. One pass up front, because
11
+ * consumers that each decide what `undefined` means end up disagreeing: a cache
12
+ * key that counted `{ gte: undefined }` while the builder skipped it served a
13
+ * `<=` template to a `>=` call.
14
+ *
15
+ * Pruned positions: `where` (combinators, relation filters, column operator
16
+ * objects including a nested `not`), `having`, `cursor`, `orderBy`, and every
17
+ * `with` relation's `where` / `orderBy`. Never `data` / `create` / `update`
18
+ * (a json column may legitimately receive `{}`), never an operand value (an
19
+ * `in` list, a JSON document, a vector), and never an object written empty
20
+ * (`{}`, `{ OR: [] }`), which keeps its own meaning. A column operator object
21
+ * left holding only modifiers (`mode`, `path`, `config`) is removed too:
22
+ * `{ contains: q, mode: 'insensitive' }` with `q` undefined is no filter.
23
+ *
24
+ * PowDB runs the same function from `PowqlInterface.normalizeArgs`, so the
25
+ * two engines cannot disagree about what `undefined` means.
26
+ *
27
+ * @module
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.CURSOR_INCLUSIVE = void 0;
31
+ exports.pruneUndefinedArgs = pruneUndefinedArgs;
32
+ exports.whereEmptiedByPruning = whereEmptiedByPruning;
33
+ exports.assertWhereNotEmptiedByPruning = assertWhereNotEmptiedByPruning;
34
+ exports.hasCursor = hasCursor;
35
+ exports.assertCursorWritten = assertCursorWritten;
36
+ exports.assertCursorNotEmptied = assertCursorNotEmptied;
37
+ exports.isCursorInclusive = isCursorInclusive;
38
+ const errors_js_1 = require("../errors.js");
39
+ const filters_js_1 = require("./filters.js");
40
+ const utils_js_1 = require("./utils.js");
41
+ const where_compile_js_1 = require("./where-compile.js");
42
+ /** Sentinel for "remove this key / element". Never escapes this module. */
43
+ const REMOVE = Symbol('turbine.prune.remove');
44
+ /** Keys that qualify an operator rather than state one. */
45
+ const MODIFIER_KEYS = new Set(['mode', 'path', 'config']);
46
+ /**
47
+ * Past this depth the pass stops descending and returns the node as written.
48
+ * The where walkers refuse anything deeper than {@link MAX_WHERE_DEPTH} with a
49
+ * typed error, so stopping here only hands that refusal the original shape;
50
+ * it never lets an unbounded walk through.
51
+ */
52
+ const PRUNE_DEPTH_LIMIT = where_compile_js_1.MAX_WHERE_DEPTH + 2;
53
+ function hasNoKeys(obj) {
54
+ for (const _ in obj)
55
+ return false;
56
+ return true;
57
+ }
58
+ /**
59
+ * Copy-on-write key replacement. Spread rather than a fresh literal so any
60
+ * symbol-keyed brand on the object survives the copy.
61
+ */
62
+ function withKey(current, original, key, next) {
63
+ const out = current ?? { ...original };
64
+ if (next === REMOVE)
65
+ delete out[key];
66
+ else
67
+ out[key] = next;
68
+ return out;
69
+ }
70
+ function isJsonColumn(meta, column) {
71
+ if (!meta || !column)
72
+ return false;
73
+ const type = (meta.pgTypes?.[column] ?? '').toLowerCase();
74
+ return type === 'json' || type === 'jsonb';
75
+ }
76
+ // ---------------------------------------------------------------------------
77
+ // where
78
+ // ---------------------------------------------------------------------------
79
+ /**
80
+ * Prune one where object scoped to `meta`'s table. Returns the input when
81
+ * nothing changed. The result may be `{}`; the CALLER decides whether an
82
+ * emptied object is removed (nested positions) or kept (the top level).
83
+ */
84
+ function pruneWhere(schema, meta, where, depth) {
85
+ if (depth > PRUNE_DEPTH_LIMIT)
86
+ return where;
87
+ let out;
88
+ for (const key of Object.keys(where)) {
89
+ const value = where[key];
90
+ let next = value;
91
+ if (value === undefined) {
92
+ next = REMOVE;
93
+ }
94
+ else if (key === 'AND' || key === 'OR' || key === 'NOT') {
95
+ next = pruneCombinator(schema, meta, value, depth + 1);
96
+ }
97
+ else if ((0, filters_js_1.isPlainRecord)(value)) {
98
+ next = pruneField(schema, meta, key, value, depth + 1);
99
+ }
100
+ if (next !== value)
101
+ out = withKey(out, where, key, next);
102
+ }
103
+ return out ?? where;
104
+ }
105
+ /**
106
+ * `AND` / `OR` / `NOT`: an object, or an array of objects. An `undefined`
107
+ * member is removed like an emptied one; any other non-object member is left
108
+ * for the where walk, which refuses it by name (`combinatorBranches`).
109
+ */
110
+ function pruneCombinator(schema, meta, value, depth) {
111
+ if (Array.isArray(value)) {
112
+ let out;
113
+ for (let i = 0; i < value.length; i++) {
114
+ const element = value[i];
115
+ let next = element;
116
+ if (element === undefined) {
117
+ next = REMOVE;
118
+ }
119
+ else if ((0, filters_js_1.isPlainRecord)(element)) {
120
+ const pruned = pruneWhere(schema, meta, element, depth);
121
+ next = pruned !== element && hasNoKeys(pruned) ? REMOVE : pruned;
122
+ }
123
+ if (next !== element && !out)
124
+ out = value.slice(0, i);
125
+ if (out && next !== REMOVE)
126
+ out.push(next);
127
+ }
128
+ if (!out)
129
+ return value;
130
+ // Every element was removed: the combinator itself said nothing.
131
+ return out.length === 0 ? REMOVE : out;
132
+ }
133
+ if ((0, filters_js_1.isPlainRecord)(value)) {
134
+ const next = pruneWhere(schema, meta, value, depth);
135
+ return next !== value && hasNoKeys(next) ? REMOVE : next;
136
+ }
137
+ return value;
138
+ }
139
+ /** One where key whose value is a plain object: a relation filter or a column filter. */
140
+ function pruneField(schema, meta, key, value, depth) {
141
+ // Relation first, matching the where walker's branch order.
142
+ const relation = meta ? (0, utils_js_1.resolveRelation)(meta.relations, key) : undefined;
143
+ if (relation)
144
+ return pruneRelationFilter(schema, relation.def, value, depth);
145
+ const column = meta ? (0, utils_js_1.resolveColumnName)(meta, key) : undefined;
146
+ // An unknown key is left for the builder, which names it in its error.
147
+ if (meta && column === undefined)
148
+ return value;
149
+ return pruneOperatorObject(value, !isJsonColumn(meta, column));
150
+ }
151
+ function pruneRelationFilter(schema, def, value, depth) {
152
+ const target = schema.tables[def.to];
153
+ let hasCardinalityKey = false;
154
+ for (const k of Object.keys(value)) {
155
+ if (filters_js_1.RELATION_FILTER_WRAPPER_SET.has(k)) {
156
+ hasCardinalityKey = true;
157
+ break;
158
+ }
159
+ }
160
+ if (!hasCardinalityKey) {
161
+ // A bare object on a to-one relation is an implicit `is`.
162
+ const next = pruneWhere(schema, target, value, depth);
163
+ return next !== value && hasNoKeys(next) ? REMOVE : next;
164
+ }
165
+ let out;
166
+ for (const k of Object.keys(value)) {
167
+ const v = value[k];
168
+ let next = v;
169
+ if (v === undefined) {
170
+ next = REMOVE;
171
+ }
172
+ else if (filters_js_1.RELATION_FILTER_WRAPPER_SET.has(k) && (0, filters_js_1.isPlainRecord)(v)) {
173
+ const pruned = pruneWhere(schema, target, v, depth);
174
+ next = pruned !== v && hasNoKeys(pruned) ? REMOVE : pruned;
175
+ }
176
+ if (next !== v)
177
+ out = withKey(out, value, k, next);
178
+ }
179
+ if (!out)
180
+ return value;
181
+ return hasNoKeys(out) ? REMOVE : out;
182
+ }
183
+ /**
184
+ * A column's operator / JSON / array / text-search / vector filter object. Only
185
+ * its own keys are stripped; operands are values and are never walked, except
186
+ * a nested operator object under `not` (on a non-JSON column) and a vector
187
+ * filter's `distance` block, whose keys are operators too.
188
+ */
189
+ function pruneOperatorObject(value, walkNot) {
190
+ let out;
191
+ for (const k of Object.keys(value)) {
192
+ const v = value[k];
193
+ let next = v;
194
+ if (v === undefined) {
195
+ next = REMOVE;
196
+ }
197
+ else if ((k === 'not' && walkNot) || k === 'distance') {
198
+ if ((0, filters_js_1.isPlainRecord)(v))
199
+ next = pruneOperatorObject(v, walkNot);
200
+ }
201
+ if (next !== v)
202
+ out = withKey(out, value, k, next);
203
+ }
204
+ if (!out)
205
+ return value;
206
+ // Nothing but modifiers (or nothing at all) survived.
207
+ return onlyModifiers(out) ? REMOVE : out;
208
+ }
209
+ // ---------------------------------------------------------------------------
210
+ // having, orderBy, cursor, with
211
+ // ---------------------------------------------------------------------------
212
+ /**
213
+ * Structural prune for positions whose values carry no JSON operands (`having`
214
+ * filters, orderBy entries): strip `undefined` at every plain-object level,
215
+ * drop emptied objects and emptied (or `undefined`) array elements. Arrays of
216
+ * scalars (a vector, a JSON path) are values and are left alone.
217
+ *
218
+ * `having` also drops an object stripped down to modifiers alone, the same
219
+ * rule `where` applies to a column operator object. orderBy does not: a
220
+ * JSON-path ordering is `{ path }` plus an optional direction.
221
+ */
222
+ function pruneStructural(value, depth, dropModifierOnly) {
223
+ if (depth > PRUNE_DEPTH_LIMIT)
224
+ return value;
225
+ if (Array.isArray(value)) {
226
+ let out;
227
+ for (let i = 0; i < value.length; i++) {
228
+ const element = value[i];
229
+ const next = element === undefined
230
+ ? REMOVE
231
+ : (0, filters_js_1.isPlainRecord)(element)
232
+ ? pruneStructural(element, depth + 1, dropModifierOnly)
233
+ : element;
234
+ if (next !== element && !out)
235
+ out = value.slice(0, i);
236
+ if (out && next !== REMOVE)
237
+ out.push(next);
238
+ }
239
+ if (!out)
240
+ return value;
241
+ return out.length === 0 ? REMOVE : out;
242
+ }
243
+ if (!(0, filters_js_1.isPlainRecord)(value))
244
+ return value;
245
+ let out;
246
+ for (const k of Object.keys(value)) {
247
+ const v = value[k];
248
+ const next = v === undefined ? REMOVE : pruneStructural(v, depth + 1, dropModifierOnly);
249
+ if (next !== v)
250
+ out = withKey(out, value, k, next);
251
+ }
252
+ if (!out)
253
+ return value;
254
+ if (hasNoKeys(out) || (dropModifierOnly && onlyModifiers(out)))
255
+ return REMOVE;
256
+ return out;
257
+ }
258
+ /** True when every key left is a modifier. */
259
+ function onlyModifiers(obj) {
260
+ for (const k of Object.keys(obj)) {
261
+ if (!MODIFIER_KEYS.has(k))
262
+ return false;
263
+ }
264
+ return true;
265
+ }
266
+ /** A cursor's values are scalars: only its own keys are stripped. */
267
+ function pruneCursor(cursor) {
268
+ let out;
269
+ for (const k of Object.keys(cursor)) {
270
+ if (cursor[k] === undefined)
271
+ out = withKey(out, cursor, k, REMOVE);
272
+ }
273
+ if (!out)
274
+ return cursor;
275
+ return hasNoKeys(out) ? REMOVE : out;
276
+ }
277
+ function pruneWith(schema, meta, withClause, depth) {
278
+ if (depth > PRUNE_DEPTH_LIMIT)
279
+ return withClause;
280
+ let out;
281
+ for (const key of Object.keys(withClause)) {
282
+ const spec = withClause[key];
283
+ let next = spec;
284
+ if (spec === undefined) {
285
+ next = REMOVE;
286
+ }
287
+ else if (key !== '_count' && (0, filters_js_1.isPlainRecord)(spec)) {
288
+ const relation = meta ? (0, utils_js_1.resolveRelation)(meta.relations, key) : undefined;
289
+ next = pruneWithOptions(schema, relation ? schema.tables[relation.def.to] : undefined, spec, depth + 1);
290
+ }
291
+ if (next !== spec)
292
+ out = withKey(out, withClause, key, next);
293
+ }
294
+ if (!out)
295
+ return withClause;
296
+ return hasNoKeys(out) ? REMOVE : out;
297
+ }
298
+ function pruneWithOptions(schema, target, spec, depth) {
299
+ let out;
300
+ for (const k of Object.keys(spec)) {
301
+ const v = spec[k];
302
+ let next = v;
303
+ if (v === undefined) {
304
+ next = REMOVE;
305
+ }
306
+ else if (k === 'where' && (0, filters_js_1.isPlainRecord)(v)) {
307
+ const pruned = pruneWhere(schema, target, v, depth);
308
+ next = pruned !== v && hasNoKeys(pruned) ? REMOVE : pruned;
309
+ }
310
+ else if (k === 'orderBy') {
311
+ next = pruneStructural(v, depth, false);
312
+ }
313
+ else if (k === 'with' && (0, filters_js_1.isPlainRecord)(v)) {
314
+ next = pruneWith(schema, target, v, depth);
315
+ }
316
+ if (next !== v)
317
+ out = withKey(out, spec, k, next);
318
+ }
319
+ // An emptied relation spec stays an (empty) options object: `{ posts: {} }`
320
+ // still loads the relation, which is what `{ posts: { where: undefined } }`
321
+ // asked for.
322
+ return out ?? spec;
323
+ }
324
+ // ---------------------------------------------------------------------------
325
+ // Pre-scan
326
+ // ---------------------------------------------------------------------------
327
+ /**
328
+ * Operand keys whose ARRAY value is a list of values (an `in` list, a JSON
329
+ * path, a vector). The prune never edits one, and they can be long, so the
330
+ * pre-scan does not read them. An object under one of these names is still
331
+ * scanned: it is a column called `to` or `path`, not an operand.
332
+ */
333
+ const OPERAND_LIST_KEYS = new Set(['in', 'notIn', 'has', 'hasSome', 'hasEvery', 'path', 'to']);
334
+ /** Past this the pre-scan answers yes and lets the prune, which has its own bound, decide. */
335
+ const SCAN_DEPTH_LIMIT = 4 * where_compile_js_1.MAX_WHERE_DEPTH;
336
+ /**
337
+ * Whether `value` holds an `undefined` the prune might remove. Read-only and
338
+ * schema-blind, so a call with nothing undefined (nearly every call) costs one
339
+ * pass and no allocation before {@link pruneUndefinedArgs} returns its input.
340
+ * It may answer yes for an `undefined` the prune leaves in place (inside a JSON
341
+ * document); that only costs the prune's own walk.
342
+ */
343
+ function holdsUndefined(value, depth) {
344
+ if (depth > SCAN_DEPTH_LIMIT)
345
+ return true;
346
+ if (Array.isArray(value)) {
347
+ for (let i = 0; i < value.length; i++) {
348
+ const element = value[i];
349
+ if (element === undefined)
350
+ return true;
351
+ if (typeof element === 'object' && element !== null && holdsUndefined(element, depth + 1))
352
+ return true;
353
+ }
354
+ return false;
355
+ }
356
+ // A class instance is a bound value, never walked (the isPlainRecord rule).
357
+ const proto = Object.getPrototypeOf(value);
358
+ if (proto !== Object.prototype && proto !== null)
359
+ return false;
360
+ const record = value;
361
+ for (const key in record) {
362
+ const v = record[key];
363
+ if (v === undefined)
364
+ return true;
365
+ if (typeof v !== 'object' || v === null)
366
+ continue;
367
+ if (Array.isArray(v) && OPERAND_LIST_KEYS.has(key))
368
+ continue;
369
+ if (holdsUndefined(v, depth + 1))
370
+ return true;
371
+ }
372
+ return false;
373
+ }
374
+ /** {@link holdsUndefined} for one top-level argument, which may be absent or a scalar. */
375
+ function argHoldsUndefined(value) {
376
+ return typeof value === 'object' && value !== null && holdsUndefined(value, 0);
377
+ }
378
+ // ---------------------------------------------------------------------------
379
+ // Public surface
380
+ // ---------------------------------------------------------------------------
381
+ /**
382
+ * Remove every `undefined` from the pruned positions of one operation's args
383
+ * (see the module comment). Returns `args` by reference when nothing changed.
384
+ *
385
+ * `table` is the operation's table; relation filters and `with` levels are
386
+ * resolved against `schema` so each sub-where is pruned against its own target.
387
+ */
388
+ function pruneUndefinedArgs(schema, table, args) {
389
+ if (!(0, filters_js_1.isPlainRecord)(args))
390
+ return args;
391
+ const src = args;
392
+ if (!argHoldsUndefined(src.where) &&
393
+ !argHoldsUndefined(src.having) &&
394
+ !argHoldsUndefined(src.cursor) &&
395
+ !argHoldsUndefined(src.orderBy) &&
396
+ !argHoldsUndefined(src.with)) {
397
+ return args;
398
+ }
399
+ const meta = schema.tables[table];
400
+ let out;
401
+ const where = src.where;
402
+ if ((0, filters_js_1.isPlainRecord)(where)) {
403
+ const next = pruneWhere(schema, meta, where, 0);
404
+ if (next !== where)
405
+ out = withKey(out, src, 'where', next);
406
+ }
407
+ const having = src.having;
408
+ if ((0, filters_js_1.isPlainRecord)(having)) {
409
+ const next = pruneStructural(having, 0, true);
410
+ if (next !== having)
411
+ out = withKey(out, src, 'having', next === REMOVE ? {} : next);
412
+ }
413
+ const cursor = src.cursor;
414
+ if ((0, filters_js_1.isPlainRecord)(cursor)) {
415
+ const next = pruneCursor(cursor);
416
+ if (next !== cursor)
417
+ out = withKey(out, src, 'cursor', next);
418
+ }
419
+ const orderBy = src.orderBy;
420
+ if (orderBy !== undefined && ((0, filters_js_1.isPlainRecord)(orderBy) || Array.isArray(orderBy))) {
421
+ const next = pruneStructural(orderBy, 0, false);
422
+ if (next !== orderBy)
423
+ out = withKey(out, src, 'orderBy', next);
424
+ }
425
+ const withClause = src.with;
426
+ if ((0, filters_js_1.isPlainRecord)(withClause)) {
427
+ const next = pruneWith(schema, meta, withClause, 0);
428
+ if (next !== withClause)
429
+ out = withKey(out, src, 'with', next);
430
+ }
431
+ return (out ?? args);
432
+ }
433
+ /**
434
+ * Whether pruning turned a `where` that HAD keys into one with none: every key
435
+ * the caller wrote was `undefined`. A `where: {}` written as `{}` is not
436
+ * emptied; it was empty already.
437
+ */
438
+ function whereEmptiedByPruning(original, pruned) {
439
+ if (original === pruned)
440
+ return false;
441
+ const before = (0, filters_js_1.isPlainRecord)(original) ? original.where : undefined;
442
+ const after = (0, filters_js_1.isPlainRecord)(pruned) ? pruned.where : undefined;
443
+ if (!(0, filters_js_1.isPlainRecord)(before) || hasNoKeys(before))
444
+ return false;
445
+ return before !== after && (!(0, filters_js_1.isPlainRecord)(after) || hasNoKeys(after));
446
+ }
447
+ /**
448
+ * Refuse a single-row read whose `where` was emptied by pruning. `findFirst`
449
+ * with every filter value `undefined` would otherwise return an arbitrary row,
450
+ * which on a lookup by a secret (a reset token, an invite code) is another
451
+ * user's row. `findMany` and `count` keep "undefined means absent".
452
+ */
453
+ function assertWhereNotEmptiedByPruning(table, operation, original, pruned) {
454
+ if (!whereEmptiedByPruning(original, pruned))
455
+ return;
456
+ throw new errors_js_1.ValidationError(`${operation} on "${table}" refused: every key in \`where\` was undefined, so this would return an ` +
457
+ 'arbitrary row rather than one matching your filter. Check that the values you filter on are defined. ' +
458
+ 'To ask for any row on purpose, omit `where` or pass `where: {}`.');
459
+ }
460
+ /**
461
+ * THE "has a cursor" test: a plain object holding at least one defined value.
462
+ * The page-order completion and the cursor planner both ask it (on PowDB too),
463
+ * so a page cannot be a cursor page to one and not to the other. A `cursor`
464
+ * written in a shape that names no row never reaches it as "no cursor": see
465
+ * {@link assertCursorWritten} and {@link assertCursorNotEmptied}.
466
+ */
467
+ function hasCursor(cursor) {
468
+ if (!(0, filters_js_1.isPlainRecord)(cursor))
469
+ return false;
470
+ for (const key of Object.keys(cursor)) {
471
+ if (cursor[key] !== undefined)
472
+ return true;
473
+ }
474
+ return false;
475
+ }
476
+ /**
477
+ * Refuse a `cursor` that is written but names no row: `null`, a value that is
478
+ * not an object, or `{}`. Read as "no cursor", such a page skipped both the
479
+ * cursor and the page tiebreaker, so a pager written as
480
+ * `cursor: last ? { id: last.id } : {}` cut its first page from a different
481
+ * order than every later page and skipped rows.
482
+ */
483
+ function assertCursorWritten(table, operation, cursor) {
484
+ if (cursor === undefined)
485
+ return;
486
+ if (!(0, filters_js_1.isPlainRecord)(cursor)) {
487
+ throw new errors_js_1.ValidationError(`${operation} on "${table}" refused: \`cursor\` takes an object naming the row to page after ` +
488
+ `(for example \`cursor: { id: lastRow.id }\`), received ${cursor === null ? 'null' : Array.isArray(cursor) ? 'an array' : `a ${typeof cursor}`}. ` +
489
+ 'Leave `cursor` out for the first page.');
490
+ }
491
+ if (hasNoKeys(cursor)) {
492
+ throw new errors_js_1.ValidationError(`${operation} on "${table}" refused: \`cursor: {}\` names no row. Leave \`cursor\` out for the first page, ` +
493
+ "or pass the last row's values (for example `cursor: { id: lastRow.id }`).");
494
+ }
495
+ }
496
+ /**
497
+ * Refuse a `cursor` whose every field was `undefined`. Read as absent it would
498
+ * restart the walk at the first page, so a pager whose last-row value went
499
+ * missing would re-read page one forever. Same rule and message on every engine.
500
+ * `operation` names the call in the message when the caller knows it; without
501
+ * it the message names no operation rather than a wrong one.
502
+ */
503
+ function assertCursorNotEmptied(table, original, pruned, operation) {
504
+ const before = (0, filters_js_1.isPlainRecord)(original) ? original.cursor : undefined;
505
+ if (!(0, filters_js_1.isPlainRecord)(before) || hasNoKeys(before))
506
+ return;
507
+ if (hasCursor((0, filters_js_1.isPlainRecord)(pruned) ? pruned.cursor : undefined))
508
+ return;
509
+ throw new errors_js_1.ValidationError(`${operation ? `${operation} on` : 'Query on'} "${table}" refused: every field of \`cursor\` was undefined, so ` +
510
+ "the page would restart at the first row. Pass the last row's values, or leave `cursor` out for the first page.");
511
+ }
512
+ /**
513
+ * Internal findMany flag: the page STARTS AT the cursor row instead of after
514
+ * it. Prisma's cursor is inclusive (its `skip: 1` idiom drops the cursor row),
515
+ * so `turbine-orm/prisma-compat` sets this; core's own `cursor` stays
516
+ * exclusive. A symbol key, so a request body spread into findMany args cannot
517
+ * set it (JSON.parse never produces a symbol) and the unknown-option check,
518
+ * which reads `Object.keys`, never sees it. `Symbol.for` so ESM and CJS copies
519
+ * of the package agree on it.
520
+ *
521
+ * @internal
522
+ */
523
+ exports.CURSOR_INCLUSIVE = Symbol.for('turbine-orm.cursorInclusive');
524
+ /** Whether `args` carries {@link CURSOR_INCLUSIVE}. @internal */
525
+ function isCursorInclusive(args) {
526
+ return typeof args === 'object' && args !== null && args[exports.CURSOR_INCLUSIVE] === true;
527
+ }
@@ -51,6 +51,7 @@
51
51
  *
52
52
  * @module
53
53
  */
54
+ import { type TurbineLogger } from '../logger.js';
54
55
  import type { AggregateArgs, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, UpdateArgs, UpdateManyArgs, UpsertArgs } from './types.js';
55
56
  /**
56
57
  * How a name-translating consumer (today: `turbine-orm/prisma-compat`) must
@@ -109,7 +110,15 @@ export declare function applyNativeOptions(table: Readonly<Record<string, Option
109
110
  /** The keys of `table` with the given kind, as a set. */
110
111
  export declare function optionKeysOfKind(table: Readonly<Record<string, OptionKind>>, ...kinds: OptionKind[]): string[];
111
112
  /**
112
- * Dev-mode warning for a key that is not part of the operation's option
113
+ * Keys an operation does not declare but REFUSES by name with its own error
114
+ * (E003 naming the key and the alternative), rather than ignoring. Warning
115
+ * "it is ignored" about one of these would contradict the error that follows,
116
+ * so the warning skips them. Every entry must have a refusal behind it;
117
+ * `src/test/fix-where-option-warnings.test.ts` checks that each one throws.
118
+ */
119
+ export declare const REFUSED_OPTION_KEYS: Readonly<Record<string, ReadonlySet<string>>>;
120
+ /**
121
+ * Advice for a key that is not part of the operation's option
113
122
  * surface, and is therefore doing nothing.
114
123
  *
115
124
  * The motivating case is `include`. It is Prisma's word for `with`, it is what
@@ -126,8 +135,11 @@ export declare function optionKeysOfKind(table: Readonly<Record<string, OptionKi
126
135
  * working query start throwing. A warning costs a correct program nothing and
127
136
  * tells an incorrect one exactly what happened.
128
137
  *
129
- * Dev-only, once per `table.operation.key` per process, and total: the whole
130
- * body is wrapped, because a diagnostic must never be the reason a query fails.
138
+ * Advice: emitted only when the client's `diagnostics.advice` is on. The
139
+ * caller passes its advice logger, or `null` when advice is off, so this
140
+ * module never reads the environment. Once per `table.operation.key` per
141
+ * process, and total: the whole body is wrapped, because a diagnostic must
142
+ * never be the reason a query fails.
131
143
  */
132
- export declare function warnUnknownQueryOptions(table: string, operation: string, args: unknown): void;
144
+ export declare function warnUnknownQueryOptions(table: string, operation: string, args: unknown, advice: TurbineLogger | null): void;
133
145
  export {};