turbine-orm 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +122 -39
  2. package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
  3. package/dist/cjs/adapters/index.d.ts +110 -0
  4. package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
  5. package/dist/cjs/cli/config.d.ts +181 -0
  6. package/dist/cjs/cli/config.js +32 -6
  7. package/dist/cjs/cli/destructive.d.ts +38 -0
  8. package/dist/cjs/cli/index.d.ts +359 -0
  9. package/dist/cjs/cli/index.js +228 -56
  10. package/dist/cjs/cli/loader.d.ts +61 -0
  11. package/dist/cjs/cli/mcp.d.ts +42 -0
  12. package/dist/cjs/cli/migrate.d.ts +356 -0
  13. package/dist/cjs/cli/migrate.js +131 -40
  14. package/dist/cjs/cli/observe-ui.d.ts +1 -0
  15. package/dist/cjs/cli/observe-ui.js +14 -5
  16. package/dist/cjs/cli/observe.d.ts +25 -0
  17. package/dist/cjs/cli/observe.js +49 -12
  18. package/dist/cjs/cli/pii-tags.d.ts +53 -0
  19. package/dist/cjs/cli/prisma-report.d.ts +33 -0
  20. package/dist/cjs/cli/prisma-report.js +73 -0
  21. package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
  22. package/dist/cjs/cli/prisma-resolve.js +1 -0
  23. package/dist/cjs/cli/prisma-schema.d.ts +176 -0
  24. package/dist/cjs/cli/prisma-schema.js +82 -4
  25. package/dist/cjs/cli/rate-limit.d.ts +32 -0
  26. package/dist/cjs/cli/rate-limit.js +45 -0
  27. package/dist/cjs/cli/studio-demo.d.ts +43 -0
  28. package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
  29. package/dist/cjs/cli/studio.d.ts +207 -0
  30. package/dist/cjs/cli/studio.js +136 -71
  31. package/dist/cjs/cli/ui.d.ts +73 -0
  32. package/dist/cjs/cli/ui.js +51 -9
  33. package/dist/cjs/client.d.ts +837 -0
  34. package/dist/cjs/client.js +3 -0
  35. package/dist/cjs/dialect.d.ts +516 -0
  36. package/dist/cjs/dialect.js +37 -12
  37. package/dist/cjs/errors.d.ts +370 -0
  38. package/dist/cjs/generate.d.ts +137 -0
  39. package/dist/cjs/generate.js +39 -6
  40. package/dist/cjs/index-advisor.d.ts +153 -0
  41. package/dist/cjs/index-stats.d.ts +384 -0
  42. package/dist/cjs/index.d.ts +55 -0
  43. package/dist/cjs/index.js +7 -2
  44. package/dist/cjs/introspect.d.ts +269 -0
  45. package/dist/cjs/mssql.d.ts +232 -0
  46. package/dist/cjs/mssql.js +6 -0
  47. package/dist/cjs/mysql.d.ts +173 -0
  48. package/dist/cjs/mysql.js +16 -0
  49. package/dist/cjs/nested-write.d.ts +96 -0
  50. package/dist/cjs/nested-write.js +414 -24
  51. package/dist/cjs/observe.d.ts +115 -0
  52. package/dist/cjs/optional-peer-import.d.cts +72 -0
  53. package/dist/cjs/pipeline-submittable.d.ts +93 -0
  54. package/dist/cjs/pipeline.d.ts +71 -0
  55. package/dist/cjs/powdb-introspect.d.ts +84 -0
  56. package/dist/cjs/powdb.d.ts +931 -0
  57. package/dist/cjs/powdb.js +106 -21
  58. package/dist/cjs/powql.d.ts +592 -0
  59. package/dist/cjs/powql.js +42 -6
  60. package/dist/cjs/prisma-compat.d.ts +283 -0
  61. package/dist/cjs/prisma-compat.js +167 -9
  62. package/dist/cjs/query/aggregates.d.ts +92 -0
  63. package/dist/cjs/query/aggregates.js +7 -3
  64. package/dist/cjs/query/batched-loader.d.ts +193 -0
  65. package/dist/cjs/query/builder.d.ts +849 -0
  66. package/dist/cjs/query/builder.js +571 -65
  67. package/dist/cjs/query/compound-unique.d.ts +51 -0
  68. package/dist/cjs/query/deferred.d.ts +223 -0
  69. package/dist/cjs/query/filters.d.ts +201 -0
  70. package/dist/cjs/query/index.d.ts +14 -0
  71. package/dist/cjs/query/index.js +6 -1
  72. package/dist/cjs/query/relations.d.ts +609 -0
  73. package/dist/cjs/query/relations.js +693 -46
  74. package/dist/cjs/query/types.d.ts +1300 -0
  75. package/dist/cjs/query/utils.d.ts +209 -0
  76. package/dist/cjs/query/utils.js +208 -1
  77. package/dist/cjs/query/warn-registry.d.ts +68 -0
  78. package/dist/cjs/query/warn-registry.js +9 -0
  79. package/dist/cjs/query/where-compile.d.ts +139 -0
  80. package/dist/cjs/query/where.d.ts +548 -0
  81. package/dist/cjs/query/where.js +58 -22
  82. package/dist/cjs/query/writes.d.ts +172 -0
  83. package/dist/cjs/query/writes.js +105 -12
  84. package/dist/cjs/realtime.d.ts +70 -0
  85. package/dist/cjs/schema-builder.d.ts +354 -0
  86. package/dist/cjs/schema-metadata.d.ts +83 -0
  87. package/dist/cjs/schema-sql.d.ts +217 -0
  88. package/dist/cjs/schema-sql.js +23 -5
  89. package/dist/cjs/schema.d.ts +356 -0
  90. package/dist/cjs/schema.js +125 -0
  91. package/dist/cjs/seed.d.ts +15 -0
  92. package/dist/cjs/serverless.d.ts +142 -0
  93. package/dist/cjs/sqlite.d.ts +143 -0
  94. package/dist/cjs/sqlite.js +4 -0
  95. package/dist/cjs/typed-sql.d.ts +102 -0
  96. package/dist/cli/config.d.ts +18 -4
  97. package/dist/cli/config.js +31 -6
  98. package/dist/cli/index.d.ts +123 -0
  99. package/dist/cli/index.js +223 -58
  100. package/dist/cli/migrate.d.ts +59 -10
  101. package/dist/cli/migrate.js +128 -41
  102. package/dist/cli/observe-ui.d.ts +1 -1
  103. package/dist/cli/observe-ui.js +14 -5
  104. package/dist/cli/observe.d.ts +7 -1
  105. package/dist/cli/observe.js +48 -12
  106. package/dist/cli/prisma-report.d.ts +14 -0
  107. package/dist/cli/prisma-report.js +72 -0
  108. package/dist/cli/prisma-resolve.d.ts +6 -0
  109. package/dist/cli/prisma-resolve.js +1 -0
  110. package/dist/cli/prisma-schema.d.ts +62 -2
  111. package/dist/cli/prisma-schema.js +81 -4
  112. package/dist/cli/rate-limit.d.ts +32 -0
  113. package/dist/cli/rate-limit.js +40 -0
  114. package/dist/cli/studio.d.ts +5 -5
  115. package/dist/cli/studio.js +135 -70
  116. package/dist/cli/ui.d.ts +1 -1
  117. package/dist/cli/ui.js +51 -9
  118. package/dist/client.d.ts +40 -0
  119. package/dist/client.js +3 -0
  120. package/dist/dialect.d.ts +17 -1
  121. package/dist/dialect.js +37 -12
  122. package/dist/generate.js +40 -7
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +1 -1
  125. package/dist/mssql.js +6 -0
  126. package/dist/mysql.js +16 -0
  127. package/dist/nested-write.d.ts +2 -0
  128. package/dist/nested-write.js +415 -25
  129. package/dist/powdb.d.ts +4 -2
  130. package/dist/powdb.js +106 -21
  131. package/dist/powql.d.ts +5 -0
  132. package/dist/powql.js +42 -6
  133. package/dist/prisma-compat.d.ts +2 -0
  134. package/dist/prisma-compat.js +166 -8
  135. package/dist/query/aggregates.js +7 -3
  136. package/dist/query/builder.d.ts +292 -21
  137. package/dist/query/builder.js +570 -64
  138. package/dist/query/deferred.d.ts +39 -0
  139. package/dist/query/index.d.ts +1 -1
  140. package/dist/query/index.js +1 -1
  141. package/dist/query/relations.d.ts +173 -5
  142. package/dist/query/relations.js +688 -47
  143. package/dist/query/types.d.ts +123 -39
  144. package/dist/query/utils.d.ts +116 -0
  145. package/dist/query/utils.js +198 -0
  146. package/dist/query/warn-registry.d.ts +9 -0
  147. package/dist/query/warn-registry.js +9 -0
  148. package/dist/query/where.d.ts +38 -1
  149. package/dist/query/where.js +58 -23
  150. package/dist/query/writes.d.ts +42 -1
  151. package/dist/query/writes.js +104 -13
  152. package/dist/schema-sql.d.ts +14 -0
  153. package/dist/schema-sql.js +23 -5
  154. package/dist/schema.d.ts +38 -0
  155. package/dist/schema.js +123 -0
  156. package/dist/sqlite.js +4 -0
  157. package/package.json +77 -28
@@ -0,0 +1,1300 @@
1
+ /**
2
+ * turbine-orm — Query builder types
3
+ *
4
+ * All exported type and interface definitions for the query builder module.
5
+ */
6
+ export type OrderDirection = 'asc' | 'desc';
7
+ /**
8
+ * How a query resolves its `with` relations.
9
+ *
10
+ * - `'join'`: one SQL statement with correlated
11
+ * `json_agg(json_build_object(...))` subqueries. One round-trip, an index
12
+ * seek per parent row when the child FK is indexed. On PowDB, `'join'`
13
+ * instead opts into native PowQL server-side joins where eligible.
14
+ * - `'batched'`: run the base query, then ONE flat follow-up query per
15
+ * relation (`WHERE fk = ANY($1)`), stitching children client-side. D levels
16
+ * cost D extra round-trips, but each is a single key-set lookup and rows come
17
+ * back flat (a win when FK columns are unindexed or result sets are huge).
18
+ * - `'auto'` (the implicit default on SQL engines since 0.41): per relation,
19
+ * use `'join'` unless the introspected metadata PROVES the probe columns are
20
+ * unindexed, in which case that relation falls back to the batched loader
21
+ * (where a correlated per-parent scan would be pathological). Requires
22
+ * DB-backed index metadata (a generated / introspected client); a code-first
23
+ * `defineSchema`-only client has no index info to prove anything, so `'auto'`
24
+ * behaves exactly like `'join'` there. An EXPLICIT `'join'` or `'batched'` at
25
+ * the client or query level always wins and disables the per-relation
26
+ * fallback. Output is byte-for-byte identical to `'join'` (the batched loader
27
+ * guarantees the same result SHAPE); child-array order for a to-many relation
28
+ * WITHOUT an `orderBy` may differ from the join plan (order was never
29
+ * guaranteed without `orderBy`, see `stableRelationOrder` to pin it).
30
+ * Composite-key relations stay on the join plan (the batched loader does not
31
+ * support them). Engagement emits a once-per-relation dev note and a
32
+ * `strategy` tag on the query event.
33
+ *
34
+ * Precedence: per-query arg > client `relationLoadStrategy` config > the engine
35
+ * default. On SQL engines the default is `'auto'`; on PowDB the default is the
36
+ * batched loaders (an ineligible relation falls back to them per-relation and
37
+ * silently even when `'join'` is requested). On PowDB, `'auto'` resolves to
38
+ * PowDB's own existing default (loaders / nested projections); it never selects
39
+ * a distinct PowQL code path.
40
+ */
41
+ export type RelationLoadStrategy = 'join' | 'batched' | 'auto' | 'flatten';
42
+ /**
43
+ * Reference to ANOTHER COLUMN of the same table inside a where operator,
44
+ * enabling column-to-column comparison:
45
+ *
46
+ * ```ts
47
+ * where: { currentVersionId: { equals: { col: 'publishedVersionId' } } }
48
+ * // → WHERE "current_version_id" = "published_version_id"
49
+ * ```
50
+ *
51
+ * Accepted by `equals`, `not`, `gt`, `gte`, `lt`, and `lte`. The referenced
52
+ * field resolves through the table's columnMap (camelCase accepted, same as a
53
+ * where key) and compiles to a quoted identifier: NO parameter is bound.
54
+ * An unknown referenced field throws {@link ValidationError} (E003).
55
+ *
56
+ * Notes:
57
+ * - `mode: 'insensitive'` cannot be combined with a column reference: it
58
+ * throws E003 (use `client.sql` for `lower(a) = lower(b)`).
59
+ * - On json/jsonb columns `equals` routes to the JSONB containment filter
60
+ * first, so `{ equals: { col } }` there is treated as a JSON value, not a
61
+ * column reference.
62
+ *
63
+ * `F` narrows the referenced name to the table's field names when the
64
+ * surrounding {@link WhereClause} knows the entity type.
65
+ */
66
+ export interface ColumnRef<F extends string = string> {
67
+ col: F;
68
+ }
69
+ /** Operator object for advanced where filtering */
70
+ export interface WhereOperator<V = unknown, F extends string = string> {
71
+ /**
72
+ * Explicit equality: `{ equals: value }` → `column = $n`.
73
+ * `{ equals: null }` → `column IS NULL`.
74
+ * `{ equals: { col: 'otherField' } }` → `column = "other_field"` ({@link ColumnRef}).
75
+ * On json/jsonb columns `equals` routes to the JSONB containment filter
76
+ * ({@link JsonFilter}) instead.
77
+ */
78
+ equals?: V | ColumnRef<F> | null;
79
+ gt?: V | ColumnRef<F>;
80
+ gte?: V | ColumnRef<F>;
81
+ lt?: V | ColumnRef<F>;
82
+ lte?: V | ColumnRef<F>;
83
+ not?: V | ColumnRef<F> | null;
84
+ in?: V[];
85
+ notIn?: V[];
86
+ contains?: string;
87
+ startsWith?: string;
88
+ endsWith?: string;
89
+ /** Set to 'insensitive' to use ILIKE instead of LIKE for string comparisons */
90
+ mode?: 'default' | 'insensitive';
91
+ }
92
+ /**
93
+ * A where value can be:
94
+ * - A plain value (equality: column = $N)
95
+ * - null (column IS NULL)
96
+ * - An operator object ({ gt: 5, lte: 10 })
97
+ * - A JSONB filter object ({ contains, equals, path, hasKey })
98
+ * - An array filter object ({ has, hasEvery, hasSome, isEmpty })
99
+ * - A text search filter object ({ search, config? })
100
+ * - A vector distance filter object ({ distance: { to, metric, lt } }) for pgvector columns
101
+ */
102
+ export type WhereValue<V = unknown, F extends string = string> = (V extends Array<infer U> ? TypedRelationFilter<U> : V extends Date ? V : V extends object ? V | TypedToOneFilter<V> | WhereClause<V> : V) | WhereOperator<V, F> | JsonFilter | ArrayFilter | TextSearchFilter | VectorFilter | null;
103
+ /**
104
+ * Relation filter on a to-many relation property.
105
+ *
106
+ * `UR` is the target entity's own relations map, so a nested relation filter
107
+ * (`posts: { some: { comments: { some: ... } } }`) stays key-checked at depth.
108
+ * It defaults to `{}` so the legacy single-generic spelling still works.
109
+ */
110
+ export interface TypedRelationFilter<U, UR extends object = {}> {
111
+ some?: WhereClause<U, UR>;
112
+ every?: WhereClause<U, UR>;
113
+ none?: WhereClause<U, UR>;
114
+ }
115
+ /**
116
+ * Relation filter on a to-one relation property. A bare object on a to-one
117
+ * relation key is also accepted at runtime (implicit `is`, Prisma-compatible).
118
+ *
119
+ * `VR` is the target entity's own relations map (see {@link TypedRelationFilter}).
120
+ */
121
+ export interface TypedToOneFilter<V, VR extends object = {}> {
122
+ is?: WhereClause<V, VR>;
123
+ isNot?: WhereClause<V, VR>;
124
+ }
125
+ /**
126
+ * The where-value accepted on a RELATION key, derived from the generated
127
+ * {@link RelationDescriptor} brand: to-many relations take `some`/`every`/`none`,
128
+ * to-one relations take `is`/`isNot` or a bare sub-where (implicit `is`).
129
+ *
130
+ * Legacy generated shapes (`posts: Post[]`, `profile: Profile | null`) carry no
131
+ * brand, so they degrade to `unknown` — the key is still recognised (no typo
132
+ * false-positive) but its value is not checked.
133
+ */
134
+ type RelationWhereValue<Rel> = Rel extends RelationDescriptor<infer Target, infer Cardinality, infer TR> ? Cardinality extends 'many' ? TypedRelationFilter<Target, TR & object> : TypedToOneFilter<Target, TR & object> | WhereClause<Target, TR & object> : unknown;
135
+ /**
136
+ * Where clause type: each field can be a plain value, null, or operator object.
137
+ * Special keys: OR / AND / NOT.
138
+ *
139
+ * **Key checking.** Historically this type carried a
140
+ * `[relationName: string]: unknown` index signature so relation filters
141
+ * (`where: { posts: { some: ... } }`) would typecheck — the relation names are
142
+ * NOT keys of the entity `T`. That index signature also annihilated
143
+ * excess-property checking, so `where: { emial: 'x' }` compiled silently.
144
+ *
145
+ * Passing `R` (the generated `*Relations` map, which every typed client
146
+ * already threads through `QueryInterface<T, R>`) removes the need for the
147
+ * index signature: the relation keys become real, explicitly enumerated
148
+ * properties, so a misspelled column OR relation is a compile error at the
149
+ * offending key while every legitimate filter shape still typechecks.
150
+ *
151
+ * When `R` is omitted / `{}` (the untyped escape hatch, `defineSchema`-only
152
+ * clients, and any call site that does not thread the relations map) the type
153
+ * degrades to exactly its historical permissive form.
154
+ */
155
+ export type WhereClause<T, R extends object = {}> = [keyof R] extends [never] ? LooseWhereClause<T> : StrictWhereClause<T, R>;
156
+ /** The historical, index-signature-carrying where clause. See {@link WhereClause}. */
157
+ export type LooseWhereClause<T> = {
158
+ [K in keyof T]?: WhereValue<T[K], Extract<keyof T, string>>;
159
+ } & {
160
+ OR?: LooseWhereClause<T>[];
161
+ AND?: LooseWhereClause<T>[];
162
+ NOT?: LooseWhereClause<T>;
163
+ /** Relation filters — keyed by relation name, value is { some, every, none } */
164
+ [relationName: string]: unknown;
165
+ };
166
+ /** Key-checked where clause: column keys from `T`, relation keys from `R`, no index signature. */
167
+ type StrictWhereClause<T, R extends object> = {
168
+ [K in keyof T]?: WhereValue<T[K], Extract<keyof T, string>>;
169
+ } & {
170
+ [K in keyof R]?: RelationWhereValue<R[K]>;
171
+ } & {
172
+ OR?: WhereClause<T, R>[];
173
+ AND?: WhereClause<T, R>[];
174
+ NOT?: WhereClause<T, R>;
175
+ };
176
+ /**
177
+ * Client-level automatic WHERE filters, keyed by table accessor (the name used
178
+ * in `db[name]` / `client.table(name)`). Each value is AND-merged into the
179
+ * compiled WHERE of every read and mutation on that table, and into every
180
+ * relation subquery that targets it — the mechanism behind soft-delete and
181
+ * multi-tenancy. A function value is evaluated at query-build time (per query),
182
+ * so a closure over per-request state (e.g. the current tenant id) enables
183
+ * request-scoped filters. `create`/`createMany` are never filtered.
184
+ */
185
+ export type GlobalFilters = {
186
+ [tableAccessor: string]: WhereClause<any> | (() => WhereClause<any>);
187
+ };
188
+ /**
189
+ * Per-query opt-out of the configured {@link GlobalFilters}. `true` skips the
190
+ * global filter on the query's own table AND on every relation target it
191
+ * touches; an array skips only the named table accessors (own table and/or
192
+ * relation targets). Global filters never satisfy the empty-`where` guard for
193
+ * `update`/`delete` — that guard always checks the user-supplied `where`.
194
+ */
195
+ export type SkipGlobalFilters = true | readonly string[];
196
+ /**
197
+ * Reserved key in a `with` clause that requests correlated relation counts.
198
+ * `_count: true` counts every to-many relation of the table; a record form
199
+ * (`_count: { posts: true }`) counts only the named to-many relations. Each
200
+ * selected relation resolves to a number on the result row's `_count` object.
201
+ */
202
+ export type WithCount = true | Record<string, true>;
203
+ /**
204
+ * Unparameterized with clause — accepts any relation name.
205
+ * Used internally by the query builder at runtime.
206
+ *
207
+ * The reserved `_count` key (see {@link WithCount}) is also accepted at runtime;
208
+ * the builder reads it via a cast so the narrow `true | WithOptions` element
209
+ * type is preserved for the relation-subquery machinery. Typed callers get a
210
+ * fully-typed `_count` through {@link TypedWithClause}.
211
+ */
212
+ export interface WithClause {
213
+ [relation: string]: true | WithOptions;
214
+ }
215
+ /**
216
+ * Relation-aware with clause. When R (the relations map) is provided,
217
+ * only keys from R are autocompleted. Used in public method signatures
218
+ * so the compiler can narrow the return type.
219
+ *
220
+ * For typed maps, each relation accepts either `true` (default include) or a
221
+ * {@link WithOptions} object whose nested `with` is keyed against the relation
222
+ * target's own relations interface — this is what enables deep
223
+ * `WithResult` inference.
224
+ */
225
+ export type TypedWithClause<R extends object = {}> = [keyof R] extends [never] ? WithClause : {
226
+ [K in keyof R]?: true | WithOptions<RelationRelations<R[K]> & object, RelationTarget<R[K]>>;
227
+ } & {
228
+ /** Reserved: correlated relation counts. `true` counts all to-many relations. */
229
+ _count?: true | {
230
+ [K in keyof R]?: true;
231
+ };
232
+ };
233
+ /**
234
+ * Options for an included relation.
235
+ *
236
+ * Generic over `NestedR` — the relations interface of the *target* entity —
237
+ * so the nested `with` clause is autocompleted with the correct relation keys
238
+ * and so {@link WithResult} can recursively infer the return type. Defaults to
239
+ * `{}` (no relation suggestions) for callers that use the unparameterized
240
+ * {@link WithClause}.
241
+ */
242
+ /**
243
+ * A single relation-`with` orderBy object: field → direction / sort spec /
244
+ * JSON-path ordering / relation ordering. The Prisma-style array form on
245
+ * {@link WithOptions.orderBy} is `WithOrderByObject[]`.
246
+ */
247
+ export type WithOrderByObject = Record<string, OrderDirection | OrderBySpec | JsonPathOrderBy | RelationOrderBy>;
248
+ /**
249
+ * The `where` accepted inside a relation `with` block. When the relation
250
+ * target entity is known (a typed client, via the {@link RelationDescriptor}
251
+ * brand the generator emits) this is a key-checked {@link WhereClause} over the
252
+ * TARGET entity and its own relations, so `with: { posts: { where: { titel } } }`
253
+ * is a compile error. When the target is unknown (the untyped
254
+ * {@link WithClause} escape hatch) it degrades to the historical open record.
255
+ */
256
+ export type WithWhere<NestedT, NestedR extends object> = [unknown] extends [NestedT] ? Record<string, unknown> : WhereClause<NestedT & object, NestedR>;
257
+ export interface WithOptions<NestedR extends object = {}, NestedT = unknown> {
258
+ with?: TypedWithClause<NestedR>;
259
+ /** Filter the related rows. Keys are checked against the relation target when it is known (see {@link WithWhere}). */
260
+ where?: WithWhere<NestedT, NestedR>;
261
+ /**
262
+ * Order the related rows. Accepts a single object (`{ a: 'asc', b: 'desc' }`)
263
+ * or a Prisma-style array of objects (`[{ a: 'asc' }, { b: 'desc' }]`, whose
264
+ * element order is the authoritative multi-key sort precedence).
265
+ */
266
+ orderBy?: WithOrderByObject | WithOrderByObject[];
267
+ limit?: number;
268
+ /** Only include these fields from the relation */
269
+ select?: Record<string, boolean>;
270
+ /** Exclude these fields from the relation */
271
+ omit?: Record<string, boolean>;
272
+ }
273
+ /**
274
+ * A relation descriptor used by generated `*Relations` interfaces to make deep
275
+ * `with` clause inference work. It bundles three pieces of information that
276
+ * `WithResult` needs to recurse through nested relations:
277
+ *
278
+ * - `__target` — the target entity type (e.g. `Post`)
279
+ * - `__cardinality`— `'many'` for hasMany, `'one'` for belongsTo / hasOne
280
+ * - `__relations` — the target entity's relations interface (for further recursion)
281
+ *
282
+ * **Generator contract (Track 3):** the code generator emits `*Relations`
283
+ * interfaces in the following shape so that `WithResult` can walk arbitrary
284
+ * nesting depth:
285
+ *
286
+ * ```ts
287
+ * export interface UserRelations {
288
+ * posts: RelationDescriptor<Post, 'many', PostRelations>;
289
+ * profile: RelationDescriptor<Profile, 'one', ProfileRelations>;
290
+ * }
291
+ * ```
292
+ *
293
+ * The brand fields are phantom — they exist only for type inference and have
294
+ * no runtime representation. The runtime always sees the parsed entity values
295
+ * (arrays for hasMany, single object or null for belongsTo / hasOne) — see the
296
+ * cardinality projection inside {@link WithResult}.
297
+ *
298
+ * **Backward compatibility:** legacy generated code emitted bare types
299
+ * (`posts: Post[]`, `profile: Profile | null`). `WithResult` still accepts that
300
+ * shape via a fallback branch — it just cannot recurse into nested `with` for
301
+ * those relations until the generator is updated.
302
+ *
303
+ * @typeParam Target - The entity type the relation points at.
304
+ * @typeParam Cardinality - `'many'` (array) or `'one'` (single object | null).
305
+ * @typeParam Relations - The target entity's own `*Relations` interface, or
306
+ * `{}` if the target has no relations of its own.
307
+ */
308
+ export interface RelationDescriptor<Target, Cardinality extends 'one' | 'many', Relations extends object = {}> {
309
+ readonly __target?: Target;
310
+ readonly __cardinality?: Cardinality;
311
+ readonly __relations?: Relations;
312
+ }
313
+ /** Extract the target entity from a relation descriptor or bare relation type. */
314
+ type RelationTarget<Rel> = Rel extends RelationDescriptor<infer Target, infer _C, infer _R> ? Target : Rel extends Array<infer Item> ? Item : Rel extends infer One | null ? One : Rel;
315
+ /** Extract the target's relations map from a relation descriptor (or `{}` for bare types). */
316
+ type RelationRelations<Rel> = Rel extends RelationDescriptor<infer _T, infer _C, infer R> ? R : {};
317
+ /** Project the target type into its runtime shape (array for many, single for one). */
318
+ type ApplyCardinality<Rel, Resolved> = Rel extends RelationDescriptor<infer _T, infer Cardinality, infer _R> ? Cardinality extends 'many' ? Resolved[] : Resolved | null : Rel extends Array<infer _Item> ? Resolved[] : Resolved | null;
319
+ /**
320
+ * Compute the result type when relations are included via `with`.
321
+ *
322
+ * Recursively walks the `with` clause, looking up each relation in `R` and:
323
+ *
324
+ * 1. If the relation is included with `true` (or no nested `with`), the
325
+ * relation's bare resolved type is grafted onto `T` (e.g. `posts: Post[]`).
326
+ * 2. If the relation is included with a nested `with: {...}`, the recursion
327
+ * looks up the target entity's relations interface (via the
328
+ * {@link RelationDescriptor} brand fields the generator emits) and
329
+ * recursively applies `WithResult` to the nested target. Cardinality is
330
+ * re-applied at each level so a hasMany relation stays an array even after
331
+ * deep nesting.
332
+ *
333
+ * **When `R` is `{}` (the default):** the recursion short-circuits and the
334
+ * function returns plain `T` — preserving the existing untyped escape hatch
335
+ * for callers that have not generated typed clients.
336
+ *
337
+ * **When `R` does not contain the requested relations:** the unknown keys are
338
+ * ignored (the runtime will throw a `RelationError`, but the type system stays
339
+ * permissive so the legacy `WithClause` index signature still typechecks).
340
+ *
341
+ * @typeParam T - Base entity type (e.g. `User`).
342
+ * @typeParam R - Relations map for `T` (e.g.
343
+ * `{ posts: RelationDescriptor<Post, 'many', PostRelations>; ... }`).
344
+ * Legacy bare shapes (`{ posts: Post[]; profile: Profile | null }`)
345
+ * are also accepted, but cannot recurse beyond one level.
346
+ * @typeParam W - The `with` clause the user passed (e.g. `{ posts: true }` or
347
+ * `{ posts: { with: { comments: true } } }`).
348
+ */
349
+ export type WithResult<T, R extends object, W> = [keyof R] extends [never] ? T : W extends object ? W extends {
350
+ _count: infer C;
351
+ } ? // `_count` requested — add the typed count object alongside any relations.
352
+ WithRelationAdditions<T, R, W> & {
353
+ _count: CountResult<C>;
354
+ } : WithRelationAdditions<T, R, W> : T;
355
+ /**
356
+ * The relation additions grafted onto `T` by a `with` clause (the `_count`
357
+ * reserved key is handled separately by {@link WithResult}). Kept as its own
358
+ * alias so the no-`_count` path stays byte-identical to the pre-`_count` type.
359
+ */
360
+ type WithRelationAdditions<T, R extends object, W> = [keyof W & keyof R] extends [never] ? T : T & {
361
+ [K in keyof W & keyof R]: W[K] extends true ? ApplyCardinality<R[K], RelationTarget<R[K]>> : W[K] extends {
362
+ with?: infer NestedW;
363
+ } ? NestedW extends object ? ApplyCardinality<R[K], WithResult<RelationTarget<R[K]>, RelationRelations<R[K]> & object, NestedW>> : ApplyCardinality<R[K], RelationTarget<R[K]>> : ApplyCardinality<R[K], RelationTarget<R[K]>>;
364
+ };
365
+ /**
366
+ * Compute the shape of the `_count` object on a result row. `_count: true`
367
+ * counts every to-many relation (keys unknown at the type level → an open
368
+ * `Record<string, number>`); the record form (`_count: { posts: true }`) yields
369
+ * `{ [K in selected]: number }`.
370
+ */
371
+ type CountResult<C> = C extends true ? Record<string, number> : C extends object ? {
372
+ [K in keyof C]: number;
373
+ } : Record<string, number>;
374
+ /**
375
+ * Key-validating companion for an inferred `select` / `omit` flag map.
376
+ *
377
+ * `select?: S` alone can never reject a typo: `S` is inferred FROM the object
378
+ * literal, so `{ emial: true }` simply becomes the inferred type and a
379
+ * misspelled column silently narrows the result to `Pick<T, never>`. Writing
380
+ * the property as `S & FieldFlags<T, S>` keeps `S` inferred exactly as before
381
+ * (the naked `S` member is still the inference site, so literal `true` values
382
+ * and the `TrueKeys` result narrowing are unchanged) while the mapped member
383
+ * maps every key that is NOT a field of `T` to `never`, which makes the
384
+ * supplied `true` unassignable and reports the typo at the offending key.
385
+ *
386
+ * A key that IS a field of `T` maps to plain `boolean`, so every legitimate
387
+ * flag map (`{ id: true }`, `{ id: true, email: false }`, `{}`) is unaffected.
388
+ *
389
+ * An OPEN flag map (`Record<string, boolean>`, which is what the internal
390
+ * pass-through signatures instantiate `S` with) has nothing to validate: it is
391
+ * returned unchanged so those instantiations stay assignable to each other.
392
+ */
393
+ export type FieldFlags<T, S> = S extends object ? string extends keyof S ? S : {
394
+ [K in keyof S]: K extends keyof T ? boolean : never;
395
+ } : S;
396
+ /** Extract keys from a boolean record where the value is `true`. */
397
+ type TrueKeys<S extends Record<string, boolean>> = {
398
+ [K in keyof S]: S[K] extends true ? K : never;
399
+ }[keyof S];
400
+ /** Pick only the fields from T that are selected (value = true) in S. */
401
+ export type SelectResult<T, S extends Record<string, boolean> | undefined> = S extends Record<string, boolean> ? Pick<T, Extract<keyof T, TrueKeys<S>>> : T;
402
+ /** Omit the fields from T that are marked (value = true) in O. */
403
+ export type OmitResult<T, O extends Record<string, boolean> | undefined> = O extends Record<string, boolean> ? Omit<T, Extract<keyof T, TrueKeys<O>>> : T;
404
+ /**
405
+ * Apply select or omit field narrowing to a base type. Select takes priority —
406
+ * when both are provided, only select is applied (matching runtime behavior).
407
+ */
408
+ export type FieldResult<T, S extends Record<string, boolean> | undefined, O extends Record<string, boolean> | undefined> = S extends Record<string, boolean> ? SelectResult<T, S> : OmitResult<T, O>;
409
+ /**
410
+ * Compute the full query result type: apply field narrowing to the base entity,
411
+ * then add relation additions from the `with` clause. Relations are unaffected
412
+ * by select/omit (they are separate JSON subqueries at the SQL level).
413
+ *
414
+ * Short-circuits to plain WithResult when neither select nor omit is provided,
415
+ * preserving exact type equality with the pre-narrowing era.
416
+ */
417
+ export type QueryResult<T, R extends object, W, S extends Record<string, boolean> | undefined, O extends Record<string, boolean> | undefined> = S extends undefined ? O extends undefined ? WithResult<T, R, W> : O extends Record<string, boolean> ? Omit<WithResult<T, R, W>, Exclude<Extract<keyof T, TrueKeys<O>>, keyof W>> : WithResult<T, R, W> : S extends Record<string, boolean> ? Pick<WithResult<T, R, W>, Extract<keyof T, TrueKeys<S>> | Exclude<keyof WithResult<T, R, W>, keyof T> | Extract<keyof W, keyof WithResult<T, R, W>>> : WithResult<T, R, W>;
418
+ export interface FindUniqueArgs<T, R extends object = {}, W extends TypedWithClause<R> = TypedWithClause<R>, S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined> {
419
+ /** Row selector. Keys are checked against `T` and `R` (see {@link WhereClause}). */
420
+ where: WhereClause<T, R>;
421
+ /** Only return these fields. Keys are checked against `T` (see {@link FieldFlags}). */
422
+ select?: S & FieldFlags<T, S>;
423
+ /** Exclude these fields. Keys are checked against `T` (see {@link FieldFlags}). */
424
+ omit?: O & FieldFlags<T, O>;
425
+ with?: W;
426
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
427
+ timeout?: number;
428
+ /** Override the client's relation-loading strategy for this query. See {@link RelationLoadStrategy}. */
429
+ relationLoadStrategy?: RelationLoadStrategy;
430
+ /** Override the client's {@link TurbineConfig.stableRelationOrder} for this query. */
431
+ stableRelationOrder?: boolean;
432
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
433
+ skipGlobalFilters?: SkipGlobalFilters;
434
+ /** Include PII-tagged columns in the result. See {@link FindManyArgs.includePii}. */
435
+ includePii?: boolean;
436
+ }
437
+ export interface FindManyArgs<T, R extends object = {}, W extends TypedWithClause<R> = TypedWithClause<R>, S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined> {
438
+ /** Row filter. Keys are checked against `T` and `R` (see {@link WhereClause}). */
439
+ where?: WhereClause<T, R>;
440
+ /** Only return these fields. Keys are checked against `T` (see {@link FieldFlags}). */
441
+ select?: S & FieldFlags<T, S>;
442
+ /** Exclude these fields. Keys are checked against `T` (see {@link FieldFlags}). */
443
+ omit?: O & FieldFlags<T, O>;
444
+ orderBy?: OrderByClause;
445
+ limit?: number;
446
+ offset?: number;
447
+ with?: W;
448
+ /** Cursor-based pagination: start after this row */
449
+ cursor?: Partial<T>;
450
+ /** Number of records to take (used with cursor) */
451
+ take?: number;
452
+ /** De-duplicate results by specified fields */
453
+ distinct?: (keyof T & string)[];
454
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
455
+ timeout?: number;
456
+ /** Override the client's relation-loading strategy for this query. See {@link RelationLoadStrategy}. */
457
+ relationLoadStrategy?: RelationLoadStrategy;
458
+ /**
459
+ * Override the client's {@link TurbineConfig.stableRelationOrder} for this
460
+ * query. When `true`, every to-many `with` relation that has no explicit
461
+ * `orderBy` is loaded ordered by the target table's primary key ascending, so
462
+ * unordered child arrays come back in a deterministic order. An explicit
463
+ * per-relation `orderBy` always wins. Off by default; when off the emitted SQL
464
+ * is byte-identical to before.
465
+ */
466
+ stableRelationOrder?: boolean;
467
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
468
+ skipGlobalFilters?: SkipGlobalFilters;
469
+ /**
470
+ * Per-call override of the unbounded-findMany warning. Pass `false` when
471
+ * this call intentionally reads the full table (the config-level
472
+ * `warnOnUnlimited` stays in effect for every other call); pass `true` to
473
+ * force the warning even when it is disabled in config.
474
+ */
475
+ warnOnUnlimited?: boolean;
476
+ /**
477
+ * Include PII-tagged columns (`defineSchema` `pii: true`) in the result.
478
+ *
479
+ * PII columns are EXCLUDED from default projections: they come back only when
480
+ * explicitly named in `select`, or when this flag is `true`. Set it to `true`
481
+ * to return every PII column at the top level AND at every nested `with`
482
+ * level of this query. Default `false`. Schemas with no PII-tagged columns are
483
+ * unaffected (the emitted SQL is byte-identical either way).
484
+ *
485
+ * Referencing a PII column in `where` / `orderBy` / `groupBy` / aggregates is
486
+ * always allowed regardless of this flag (the reference is explicit).
487
+ */
488
+ includePii?: boolean;
489
+ }
490
+ export interface FindManyStreamArgs<T, R extends object = {}, W extends TypedWithClause<R> = TypedWithClause<R>, S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined> extends FindManyArgs<T, R, W, S, O> {
491
+ /**
492
+ * Number of rows to fetch per internal FETCH batch (default: 1000).
493
+ *
494
+ * Trade-off: larger batches reduce network round-trips (important for
495
+ * high-latency connections like Neon) but increase per-batch memory.
496
+ * At 1000 rows x ~500 bytes/row the default is ~500 KB per batch.
497
+ *
498
+ * When the total result set fits within one batch, the stream avoids
499
+ * cursor overhead entirely (no BEGIN / DECLARE / CLOSE / COMMIT) by
500
+ * using a speculative `SELECT ... LIMIT batchSize+1` first.
501
+ */
502
+ batchSize?: number;
503
+ }
504
+ export interface CreateArgs<T, R extends object = {}> {
505
+ /**
506
+ * Row data. On typed clients, relation names additionally accept nested
507
+ * write ops ({@link NestedCreateOp}): `create` / `connect` / `connectOrCreate`.
508
+ */
509
+ data: CreateDataInput<T, R>;
510
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
511
+ timeout?: number;
512
+ }
513
+ export interface CreateManyArgs<T> {
514
+ data: Partial<T>[];
515
+ /** When true, adds ON CONFLICT DO NOTHING to skip duplicate rows */
516
+ skipDuplicates?: boolean;
517
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
518
+ timeout?: number;
519
+ }
520
+ /**
521
+ * Atomic update operators for a field.
522
+ *
523
+ * `set` works on any type; `increment`, `decrement`, `multiply`, and `divide`
524
+ * are only valid on numeric fields. They generate SQL like
525
+ * `col = col + $n` (and the corresponding `-`, `*`, `/` variants) instead of
526
+ * plain absolute assignments, so they are safe against concurrent writers —
527
+ * the database performs the math atomically.
528
+ *
529
+ * @example
530
+ * db.posts.update({ where: { id: 5 }, data: { viewCount: { increment: 1 } } });
531
+ */
532
+ export type UpdateOperatorInput<V> = {
533
+ set: V;
534
+ } | (V extends number ? {
535
+ increment: number;
536
+ } : never) | (V extends number ? {
537
+ decrement: number;
538
+ } : never) | (V extends number ? {
539
+ multiply: number;
540
+ } : never) | (V extends number ? {
541
+ divide: number;
542
+ } : never);
543
+ /**
544
+ * Update data — each field can be a plain value or an atomic operator object.
545
+ * Back-compatible with `Partial<T>`: plain values still typecheck unchanged.
546
+ */
547
+ export type UpdateInput<T> = {
548
+ [K in keyof T]?: T[K] | UpdateOperatorInput<T[K]>;
549
+ };
550
+ export interface UpdateArgs<T, R extends object = {}> {
551
+ /** Row selector. Keys are checked against `T` and `R` (see {@link WhereClause}). */
552
+ where: WhereClause<T, R>;
553
+ /**
554
+ * Update data. On typed clients, relation names additionally accept nested
555
+ * write ops ({@link NestedUpdateOp}): `create` / `connect` / `connectOrCreate`
556
+ * / `disconnect` / `set` / `delete` / `update` / `upsert`.
557
+ */
558
+ data: UpdateDataInput<T, R>;
559
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
560
+ timeout?: number;
561
+ /**
562
+ * Opt in to running this mutation when `where` resolves to an empty
563
+ * predicate (e.g. `{}` or `{ id: undefined }`). Default `false` — an
564
+ * empty predicate throws `ValidationError` to catch the common case of
565
+ * a filter value accidentally being `undefined`. Set this to `true` only
566
+ * when an unconditional mutation is the intended behaviour.
567
+ */
568
+ allowFullTableScan?: boolean;
569
+ /**
570
+ * Optimistic locking — prevents lost updates in concurrent scenarios.
571
+ * Specify the version field and its expected value. The update adds a
572
+ * WHERE check on the version and auto-increments it. If the row was
573
+ * modified by another transaction, throws `OptimisticLockError`.
574
+ *
575
+ * @example
576
+ * ```ts
577
+ * await db.posts.update({
578
+ * where: { id: 1 },
579
+ * data: { title: 'new title' },
580
+ * optimisticLock: { field: 'version', expected: 3 },
581
+ * });
582
+ * // Generates: UPDATE posts SET title=$1, version=version+1
583
+ * // WHERE id=$2 AND version=$3 RETURNING *
584
+ * ```
585
+ */
586
+ optimisticLock?: {
587
+ field: keyof T & string;
588
+ expected: number;
589
+ };
590
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
591
+ skipGlobalFilters?: SkipGlobalFilters;
592
+ }
593
+ export interface UpdateManyArgs<T, R extends object = {}> {
594
+ where: WhereClause<T, R>;
595
+ data: UpdateInput<T>;
596
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
597
+ timeout?: number;
598
+ /** See {@link UpdateArgs.allowFullTableScan}. */
599
+ allowFullTableScan?: boolean;
600
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
601
+ skipGlobalFilters?: SkipGlobalFilters;
602
+ }
603
+ export interface DeleteArgs<T, R extends object = {}> {
604
+ where: WhereClause<T, R>;
605
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
606
+ timeout?: number;
607
+ /** See {@link UpdateArgs.allowFullTableScan}. */
608
+ allowFullTableScan?: boolean;
609
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
610
+ skipGlobalFilters?: SkipGlobalFilters;
611
+ }
612
+ export interface DeleteManyArgs<T, R extends object = {}> {
613
+ where: WhereClause<T, R>;
614
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
615
+ timeout?: number;
616
+ /** See {@link UpdateArgs.allowFullTableScan}. */
617
+ allowFullTableScan?: boolean;
618
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
619
+ skipGlobalFilters?: SkipGlobalFilters;
620
+ }
621
+ export interface UpsertArgs<T, R extends object = {}> {
622
+ where: WhereClause<T, R>;
623
+ create: Partial<T>;
624
+ update: Partial<T>;
625
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
626
+ timeout?: number;
627
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
628
+ skipGlobalFilters?: SkipGlobalFilters;
629
+ }
630
+ /** `connectOrCreate` op: connect to the row matching `where`, or create it. */
631
+ export interface ConnectOrCreateOp<T, TR extends object = {}> {
632
+ where: Partial<T>;
633
+ create: CreateDataInput<T, TR>;
634
+ }
635
+ /** Nested write ops valid inside `create()` data for a relation field. */
636
+ export interface NestedCreateOp<T, TR extends object = {}> {
637
+ create?: CreateDataInput<T, TR> | CreateDataInput<T, TR>[];
638
+ connect?: Partial<T> | Partial<T>[];
639
+ connectOrCreate?: ConnectOrCreateOp<T, TR> | ConnectOrCreateOp<T, TR>[];
640
+ }
641
+ /** A nested `update` op item: update the related row(s) matching `where`. `where` is optional for belongsTo relations (derived from the parent's FK). */
642
+ export interface NestedUpdateOpItem<T, TR extends object = {}> {
643
+ where?: Partial<T>;
644
+ data: UpdateDataInput<T, TR>;
645
+ }
646
+ /** A nested `upsert` op item: update the row matching `where` or create it. */
647
+ export interface NestedUpsertOpItem<T, TR extends object = {}> {
648
+ where: Partial<T>;
649
+ create: CreateDataInput<T, TR>;
650
+ update: UpdateDataInput<T, TR>;
651
+ }
652
+ /** Nested write ops valid inside `update()` data for a relation field. */
653
+ export interface NestedUpdateOp<T, TR extends object = {}> {
654
+ create?: CreateDataInput<T, TR> | CreateDataInput<T, TR>[];
655
+ connect?: Partial<T> | Partial<T>[];
656
+ connectOrCreate?: ConnectOrCreateOp<T, TR> | ConnectOrCreateOp<T, TR>[];
657
+ disconnect?: Partial<T> | Partial<T>[];
658
+ set?: Partial<T>[];
659
+ delete?: Partial<T> | Partial<T>[];
660
+ update?: NestedUpdateOpItem<T, TR> | NestedUpdateOpItem<T, TR>[];
661
+ upsert?: NestedUpsertOpItem<T, TR> | NestedUpsertOpItem<T, TR>[];
662
+ }
663
+ /**
664
+ * `create()` data input. When the relations map `R` is known (typed clients),
665
+ * each relation name additionally accepts a {@link NestedCreateOp} for the
666
+ * relation's target entity — recursively, via the target's own relations map.
667
+ * When `R` is `{}` (untyped escape hatch) this collapses to plain `Partial<T>`.
668
+ */
669
+ export type CreateDataInput<T, R extends object = {}> = [keyof R] extends [never] ? Partial<T> : Partial<T> & {
670
+ [K in keyof R]?: NestedCreateOp<RelationTarget<R[K]> & object, RelationRelations<R[K]> & object>;
671
+ };
672
+ /**
673
+ * `update()` data input. Like {@link CreateDataInput} but relation fields
674
+ * accept the full {@link NestedUpdateOp} surface (disconnect / set / delete /
675
+ * update / upsert in addition to the create-context ops), and scalar fields
676
+ * accept atomic {@link UpdateOperatorInput} objects.
677
+ */
678
+ export type UpdateDataInput<T, R extends object = {}> = [keyof R] extends [never] ? UpdateInput<T> : UpdateInput<T> & {
679
+ [K in keyof R]?: NestedUpdateOp<RelationTarget<R[K]> & object, RelationRelations<R[K]> & object>;
680
+ };
681
+ export interface CountArgs<T, R extends object = {}> {
682
+ where?: WhereClause<T, R>;
683
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
684
+ timeout?: number;
685
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
686
+ skipGlobalFilters?: SkipGlobalFilters;
687
+ }
688
+ /**
689
+ * Numeric comparison operators usable inside a `having` filter. A bare number
690
+ * is shorthand for equality (`COUNT(*) = $n`); the operator object supports
691
+ * range and inequality comparisons. Mirrors the numeric subset of
692
+ * {@link WhereOperator} so the same SQL machinery can be reused.
693
+ */
694
+ export interface HavingNumericOperator {
695
+ equals?: number;
696
+ not?: number;
697
+ gt?: number;
698
+ gte?: number;
699
+ lt?: number;
700
+ lte?: number;
701
+ in?: number[];
702
+ notIn?: number[];
703
+ }
704
+ /** A single having predicate value: a bare number (equality) or an operator object. */
705
+ export type HavingFilter = number | HavingNumericOperator;
706
+ /**
707
+ * Per-field aggregate filters inside a {@link HavingClause}. Each aggregate
708
+ * function maps to a {@link HavingFilter} comparison on that field.
709
+ *
710
+ * @example
711
+ * viewCount: { _sum: { gt: 100 }, _avg: { lte: 50 } }
712
+ */
713
+ export interface HavingAggregateFilter {
714
+ _sum?: HavingFilter;
715
+ _avg?: HavingFilter;
716
+ _min?: HavingFilter;
717
+ _max?: HavingFilter;
718
+ _count?: HavingFilter;
719
+ }
720
+ /**
721
+ * HAVING clause for `groupBy` — filters whole groups by their aggregate values
722
+ * (the SQL `HAVING` clause). Follows Prisma's shape: each aggregable field maps
723
+ * to a {@link HavingAggregateFilter} (`field → aggregate → operator → value`),
724
+ * and the special top-level `_count` key (no field) filters on `COUNT(*)`.
725
+ *
726
+ * Implemented as a mapped type so the special `_count` key can carry a
727
+ * {@link HavingFilter} while every entity field carries a
728
+ * {@link HavingAggregateFilter} — without the index-signature conflict an
729
+ * intersection type would produce when `T` is a broad `Record<string, unknown>`.
730
+ *
731
+ * @example
732
+ * // groups with more than 5 rows whose summed viewCount is at least 100
733
+ * having: { _count: { gt: 5 }, viewCount: { _sum: { gte: 100 } } }
734
+ */
735
+ export type HavingClause<T> = {
736
+ /** Filter on `COUNT(*)` for the whole group. */
737
+ _count?: HavingFilter;
738
+ } & {
739
+ [K in keyof T & string]?: HavingAggregateFilter;
740
+ };
741
+ /**
742
+ * A JSON-path group key in {@link GroupByArgs.by}: groups by the value
743
+ * extracted at `path` from a json/jsonb column. Emits
744
+ * `(col #>> $n::text[]) AS "alias"` in SELECT and the same expression in
745
+ * GROUP BY (the path is bound as one text[] param, never interpolated).
746
+ * Result rows key by `alias` (default: the last path segment; a collision
747
+ * with another result key throws {@link ValidationError} E003).
748
+ */
749
+ export interface JsonPathGroupKey {
750
+ /** json/jsonb column (camelCase field name, columnMap-resolved). */
751
+ field: string;
752
+ /** JSON path into the column (each element a key or array index). Bound as one text[] param. */
753
+ path: (string | number)[];
754
+ /** Result key for the group value. Defaults to the last path segment. */
755
+ alias?: string;
756
+ }
757
+ /**
758
+ * A JSON-path aggregate target inside `_sum` / `_avg` / `_min` / `_max` of
759
+ * {@link GroupByArgs}: aggregates the value extracted at `path` from a
760
+ * json/jsonb column, e.g. `SUM((col #>> $n::text[])::numeric)`. The arg key
761
+ * is the result alias. `_sum`/`_avg` always cast numeric (a text sum is
762
+ * meaningless); `_min`/`_max` compare as text unless `type: 'numeric'`.
763
+ *
764
+ * Engine note: when a group has NO value at the path, SQL engines return
765
+ * `null` for `_sum` (SUM over zero rows), while PowDB returns `0` (engine
766
+ * sum semantics). Treat `null` and `0` totals as equivalent when a group can
767
+ * be empty at the path.
768
+ */
769
+ export interface JsonPathAggregateTarget {
770
+ /** json/jsonb column (camelCase field name, columnMap-resolved). */
771
+ field: string;
772
+ /** JSON path into the column (each element a key or array index). Bound as one text[] param. */
773
+ path: (string | number)[];
774
+ /** Comparison/aggregation kind. `_sum`/`_avg` are always numeric; `_min`/`_max` default to text. */
775
+ type?: 'numeric' | 'text';
776
+ }
777
+ /**
778
+ * Per-aggregate spec map for `_sum` / `_avg` / `_min` / `_max` in
779
+ * {@link GroupByArgs}: `true` keeps the existing plain-column behavior (the
780
+ * key is a column field name); a {@link JsonPathAggregateTarget} aggregates a
781
+ * JSON path (the key doubles as the result alias).
782
+ */
783
+ export type GroupByAggregateSpec<T> = Partial<Record<keyof T & string, boolean>> | Record<string, boolean | JsonPathAggregateTarget>;
784
+ /**
785
+ * DISTINCT ON row source for {@link GroupByArgs} (PostgreSQL only: other
786
+ * engines throw {@link UnsupportedFeatureError} E017): the groupBy runs over
787
+ * one representative row per `columns` combination instead of the raw table.
788
+ *
789
+ * ```sql
790
+ * FROM (
791
+ * SELECT DISTINCT ON ("instance_id") * FROM "versions"
792
+ * WHERE <args.where> ORDER BY "instance_id", "created_at" DESC
793
+ * ) AS "versions"
794
+ * ```
795
+ *
796
+ * `orderBy` is REQUIRED (it decides which row survives per combination:
797
+ * without it the picked row would be nondeterministic); the wrapper ORDER BY
798
+ * is `columns` first, then this orderBy. `args.where` applies INSIDE the
799
+ * wrapper (filter before picking).
800
+ */
801
+ export interface GroupByDistinctOn<T> {
802
+ /** DISTINCT ON columns: one surviving row per combination. */
803
+ columns: (keyof T & string)[];
804
+ /** Which row survives per combination (required for determinism). */
805
+ orderBy: Record<string, OrderDirection | OrderBySpec | JsonPathOrderBy>;
806
+ }
807
+ /** A per-field aggregate ordering block: field/alias → direction or sort spec. */
808
+ export type GroupByAggregateOrderBy = Record<string, OrderDirection | OrderBySpec>;
809
+ /**
810
+ * {@link GroupByArgs.orderBy}: order the result groups by any column the
811
+ * groupBy result contains.
812
+ *
813
+ * - A plain **by-column** field name, or a **JSON group-key alias** (explicit
814
+ * `alias`, else the last path segment): `{ region: 'asc' }`.
815
+ * - An **aggregate block**: `_count` takes a direction/spec directly
816
+ * (`{ _count: 'desc' }`); `_sum`/`_avg`/`_min`/`_max` take a field map keyed
817
+ * by a requested aggregate field/alias (`{ _sum: { amount: 'desc' } }`).
818
+ *
819
+ * An aggregate ordering that references an aggregate not requested in the same
820
+ * call (or an unknown by-key) throws {@link ValidationError} (E003). Every
821
+ * value accepts an {@link OrderBySpec} for `NULLS FIRST/LAST` placement
822
+ * (PostgreSQL / SQLite only).
823
+ */
824
+ export interface GroupByOrderBy {
825
+ /** Order by the group's row count (requires `_count` to be selected). */
826
+ _count?: OrderDirection | OrderBySpec;
827
+ /** Order by a requested `_sum` aggregate, keyed by its field/alias. */
828
+ _sum?: GroupByAggregateOrderBy;
829
+ /** Order by a requested `_avg` aggregate, keyed by its field/alias. */
830
+ _avg?: GroupByAggregateOrderBy;
831
+ /** Order by a requested `_min` aggregate, keyed by its field/alias. */
832
+ _min?: GroupByAggregateOrderBy;
833
+ /** Order by a requested `_max` aggregate, keyed by its field/alias. */
834
+ _max?: GroupByAggregateOrderBy;
835
+ /** A by-column field name or JSON group-key alias → direction or sort spec. */
836
+ [key: string]: OrderDirection | OrderBySpec | GroupByAggregateOrderBy | undefined;
837
+ }
838
+ export interface GroupByArgs<T, R extends object = {}> {
839
+ /** Group keys: plain column field names and/or JSON-path keys ({@link JsonPathGroupKey}). */
840
+ by: ((keyof T & string) | JsonPathGroupKey)[];
841
+ where?: WhereClause<T, R>;
842
+ /**
843
+ * PostgreSQL only: group over one representative row per column combination
844
+ * (`SELECT DISTINCT ON … ORDER BY …` row source). See {@link GroupByDistinctOn}.
845
+ */
846
+ distinctOn?: GroupByDistinctOn<T>;
847
+ /**
848
+ * Count each group. `true` (or omitted) → `_count: number` (COUNT(*)). The
849
+ * record form counts per selection: the reserved `_all: true` key → COUNT(*),
850
+ * and each entity field key → COUNT(that column), yielding
851
+ * `_count: { _all: n, field: n }` (Prisma parity). Ordering/HAVING on `_count`
852
+ * stays available whenever COUNT(*) is selected (`true`, omitted, or `_all`).
853
+ */
854
+ _count?: true | ({
855
+ _all?: true;
856
+ } & Partial<Record<keyof T & string, boolean>>);
857
+ /** Sum of numeric fields (or JSON paths: see {@link JsonPathAggregateTarget}) in each group */
858
+ _sum?: GroupByAggregateSpec<T>;
859
+ /** Average of numeric fields (or JSON paths) in each group */
860
+ _avg?: GroupByAggregateSpec<T>;
861
+ /** Minimum value of fields (or JSON paths) in each group */
862
+ _min?: GroupByAggregateSpec<T>;
863
+ /** Maximum value of fields (or JSON paths) in each group */
864
+ _max?: GroupByAggregateSpec<T>;
865
+ /** Filter whole groups by their aggregate values (SQL HAVING). JSON-path aggregates key by their alias. */
866
+ having?: HavingClause<T>;
867
+ /**
868
+ * Order the result groups. Keys may be any column the groupBy result actually
869
+ * contains: a plain by-column field name, a JSON group-key alias (explicit
870
+ * `alias`, or the last path segment when unaliased), or an aggregate block
871
+ * (`_count`, or `_sum`/`_avg`/`_min`/`_max` mapping a requested field/alias to
872
+ * its direction). Every value supports {@link OrderBySpec} for NULLS
873
+ * placement. See {@link GroupByOrderBy}.
874
+ *
875
+ * Accepts a single object or a Prisma-style array of objects
876
+ * (`[{ region: 'asc' }, { _count: 'desc' }]`, array order authoritative).
877
+ */
878
+ orderBy?: GroupByOrderBy | GroupByOrderBy[];
879
+ /**
880
+ * Cap the number of result groups (`LIMIT`, applied after `ORDER BY`). Useful
881
+ * for "top N groups" queries; pair with `orderBy` for a deterministic set.
882
+ */
883
+ limit?: number;
884
+ /**
885
+ * Skip this many result groups (`OFFSET`, applied after `ORDER BY`). Paginates
886
+ * grouped results; combine with `limit` and a deterministic `orderBy`.
887
+ */
888
+ offset?: number;
889
+ /**
890
+ * Opt in to grouping on / aggregating PII-tagged (`defineSchema` `pii: true`)
891
+ * columns. A PII column in `by`, and `_min` / `_max` over a PII column, return
892
+ * STORED VALUES, so without this they throw `ValidationError` (E003).
893
+ * `_count` (a count, not a value), `_sum` / `_avg`, and `where` / `orderBy` /
894
+ * `having` on PII columns stay allowed.
895
+ */
896
+ includePii?: boolean;
897
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
898
+ timeout?: number;
899
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
900
+ skipGlobalFilters?: SkipGlobalFilters;
901
+ }
902
+ /** The by-key union of a groupBy args type (array element type of `by`). */
903
+ type GroupByKeys<A> = A extends {
904
+ by: infer BY;
905
+ } ? (BY extends readonly unknown[] ? BY[number] : never) : never;
906
+ /** The subset of `by` keys that are plain string field names on the entity `T`. */
907
+ type GroupByFieldKeys<T, A> = Extract<GroupByKeys<A>, keyof T & string>;
908
+ /**
909
+ * `_sum` / `_avg` result block: every requested key maps to `number | null`
910
+ * (an aggregate over zero matching rows is null). Present only when the args
911
+ * actually requested the block. A JSON-path aggregate target keys by its arg
912
+ * key (the alias), so `keyof S` covers both plain columns and JSON aliases.
913
+ */
914
+ type GroupBySumAvgPart<A, Key extends '_sum' | '_avg'> = A extends {
915
+ [P in Key]: infer S;
916
+ } ? [S] extends [object] ? {
917
+ [P in Key]: {
918
+ [K in keyof S & string]: number | null;
919
+ };
920
+ } : unknown : unknown;
921
+ /**
922
+ * `_min` / `_max` result block: a requested key that is a real entity field
923
+ * carries that field's own type; a JSON-path alias (or unknown key) carries
924
+ * `unknown`.
925
+ */
926
+ type GroupByMinMaxPart<T, A, Key extends '_min' | '_max'> = A extends {
927
+ [P in Key]: infer S;
928
+ } ? [S] extends [object] ? {
929
+ [P in Key]: {
930
+ [K in keyof S & string]: K extends keyof T ? T[K] : unknown;
931
+ };
932
+ } : unknown : unknown;
933
+ /**
934
+ * The typed result-row shape of a `groupBy(args)` call, computed from the args
935
+ * literal `A` (Prisma / Drizzle parity). Each `by` field carries the entity's
936
+ * field type; `_count` is always present (a group always has a row count); and
937
+ * each requested `_sum` / `_avg` / `_min` / `_max` block maps its selected
938
+ * fields to properly typed values.
939
+ *
940
+ * JSON-path group keys (objects in `by`) resolve to a runtime alias that is not
941
+ * knowable at the type level, so they are not projected onto the row type: cast
942
+ * the result when grouping by a JSON path. Intersections with `unknown` (an
943
+ * absent aggregate block) collapse away, so an args literal with no aggregates
944
+ * yields exactly `{ [byField]: T[field] } & { _count: number }`.
945
+ */
946
+ export type GroupByResult<T, A> = {
947
+ [K in GroupByFieldKeys<T, A>]: T[K];
948
+ } & GroupByCountPart<A> & GroupBySumAvgPart<A, '_sum'> & GroupBySumAvgPart<A, '_avg'> & GroupByMinMaxPart<T, A, '_min'> & GroupByMinMaxPart<T, A, '_max'>;
949
+ /**
950
+ * The `_count` block on a groupBy result row. Scalar `_count: true` (or an
951
+ * omitted `_count`, which still selects COUNT(*) by default) yields a plain
952
+ * `number`; the record form (`_count: { _all: true, field: true }`) yields a
953
+ * per-selection object `{ _all: number, field: number }` (Prisma parity). Kept
954
+ * additive: existing `_count: true` / no-`_count` calls still infer `number`.
955
+ */
956
+ type GroupByCountPart<A> = A extends {
957
+ _count: infer C;
958
+ } ? C extends true ? {
959
+ _count: number;
960
+ } : [C] extends [object] ? {
961
+ _count: {
962
+ [K in keyof C & string]: number;
963
+ };
964
+ } : {
965
+ _count: number;
966
+ } : {
967
+ _count: number;
968
+ };
969
+ /** Arguments for the standalone aggregate method */
970
+ export interface AggregateArgs<T, R extends object = {}> {
971
+ where?: WhereClause<T, R>;
972
+ /**
973
+ * Count rows. `true` → `_count: number` (COUNT(*)). The record form counts per
974
+ * selection: the reserved `_all: true` key → COUNT(*), and each entity field
975
+ * key → COUNT(that column) (non-null count), yielding
976
+ * `_count: { _all: n, field: n }` (Prisma parity).
977
+ */
978
+ _count?: true | ({
979
+ _all?: true;
980
+ } & Partial<Record<keyof T & string, boolean>>);
981
+ /** Sum of numeric fields */
982
+ _sum?: Partial<Record<keyof T & string, boolean>>;
983
+ /** Average of numeric fields */
984
+ _avg?: Partial<Record<keyof T & string, boolean>>;
985
+ /** Minimum value of fields */
986
+ _min?: Partial<Record<keyof T & string, boolean>>;
987
+ /** Maximum value of fields */
988
+ _max?: Partial<Record<keyof T & string, boolean>>;
989
+ /**
990
+ * Opt in to aggregating PII-tagged (`defineSchema` `pii: true`) columns.
991
+ * `_min` / `_max` return a STORED VALUE, so without this they throw
992
+ * `ValidationError` (E003) on a PII column. `_count` (a count, not a value)
993
+ * and `_sum` / `_avg` (a computed total over many rows) stay allowed, as do
994
+ * `where` filters on PII columns.
995
+ */
996
+ includePii?: boolean;
997
+ /** Query timeout in milliseconds. Rejects with an error if exceeded. */
998
+ timeout?: number;
999
+ /** Opt out of configured {@link GlobalFilters}. See {@link SkipGlobalFilters}. */
1000
+ skipGlobalFilters?: SkipGlobalFilters;
1001
+ }
1002
+ /** Result type for aggregate queries */
1003
+ export interface AggregateResult<T> {
1004
+ _count?: number | Record<string, number>;
1005
+ _sum?: Partial<Record<keyof T & string, number | null>>;
1006
+ _avg?: Partial<Record<keyof T & string, number | null>>;
1007
+ _min?: Partial<Record<keyof T & string, unknown>>;
1008
+ _max?: Partial<Record<keyof T & string, unknown>>;
1009
+ }
1010
+ /** Relation filter operators for where clauses */
1011
+ export interface RelationFilter {
1012
+ some?: Record<string, unknown>;
1013
+ every?: Record<string, unknown>;
1014
+ none?: Record<string, unknown>;
1015
+ /** To-one relation match (bare objects on to-one keys are implicit `is`). */
1016
+ is?: Record<string, unknown>;
1017
+ isNot?: Record<string, unknown>;
1018
+ }
1019
+ /**
1020
+ * JSONB query operators for where clauses.
1021
+ *
1022
+ * PowDB (`turbine-orm/powdb`) semantic deltas. The PowDB engine evaluates
1023
+ * `->` path filters with full type knowledge, so a few behaviours differ from
1024
+ * the Postgres `#>>`-text driver (documented, never silently wrong):
1025
+ * - `{ path, equals: null }` matches JSON null OR a MISSING key on PowDB
1026
+ * (compiles to `is null`), whereas the PG driver compares extracted text
1027
+ * against the string `'null'` and matches only a JSON string `"null"`.
1028
+ * - equality is TYPE-STRICT on PowDB: `{ path, equals: 7 }` matches a stored
1029
+ * JSON int `7` but not `7.0` or the JSON string `"7"` (PG text-extraction
1030
+ * matches `equals: 7` against the string `"7"`). Range ops (`gt`/`lt`/…)
1031
+ * still coerce int/float numerically.
1032
+ * - a digit-only path segment (`path: ['tags', '0']`) is an ARRAY INDEX on
1033
+ * both PowDB and the SQL engines (a json object key that is literally `"0"`
1034
+ * is likewise addressed by index).
1035
+ * - `contains`, and `equals` WITHOUT a `path` (whole-document containment),
1036
+ * throw `UnsupportedFeatureError` (E017) on PowDB: PowQL has no containment
1037
+ * operator.
1038
+ */
1039
+ export interface JsonFilter {
1040
+ /**
1041
+ * Access nested path via `#>>` operator (Postgres) / `->` path (PowDB). A
1042
+ * digit-only segment (`'0'`) is treated as an array index on every engine.
1043
+ */
1044
+ path?: string[];
1045
+ /** Exact match: `column @> value::jsonb` (containment). On PowDB, requires `path` and compares the typed value (throws E017 without `path`). */
1046
+ equals?: unknown;
1047
+ /** Containment check: `column @> value::jsonb`. Unsupported on PowDB (E017: PowQL has no containment operator). */
1048
+ contains?: unknown;
1049
+ /** Key existence check: `column ? key`. */
1050
+ hasKey?: string;
1051
+ /**
1052
+ * Greater-than comparison of the value at `path` (required). Numbers cast
1053
+ * the extracted text to numeric — `(col #>> path)::numeric > $n` — while
1054
+ * strings compare as text.
1055
+ */
1056
+ gt?: number | string;
1057
+ /** Greater-than-or-equal comparison of the value at `path` (required). See {@link JsonFilter.gt}. */
1058
+ gte?: number | string;
1059
+ /** Less-than comparison of the value at `path` (required). See {@link JsonFilter.gt}. */
1060
+ lt?: number | string;
1061
+ /** Less-than-or-equal comparison of the value at `path` (required). See {@link JsonFilter.gt}. */
1062
+ lte?: number | string;
1063
+ }
1064
+ /** Array query operators for where clauses */
1065
+ export interface ArrayFilter {
1066
+ /** Check if array contains a single value: value = ANY(column) */
1067
+ has?: unknown;
1068
+ /** Check if array contains ALL values: column @> ARRAY[...] */
1069
+ hasEvery?: unknown[];
1070
+ /** Check if array has ANY of the values: column && ARRAY[...] */
1071
+ hasSome?: unknown[];
1072
+ /** Check if array is empty: array_length(column, 1) IS NULL */
1073
+ isEmpty?: boolean;
1074
+ }
1075
+ /** Full-text search filter using PostgreSQL to_tsvector / to_tsquery */
1076
+ export interface TextSearchFilter {
1077
+ /** The search query string passed to to_tsquery */
1078
+ search: string;
1079
+ /** PostgreSQL text search configuration name (defaults to 'english') */
1080
+ config?: string;
1081
+ }
1082
+ /**
1083
+ * Vector distance metric. Maps to a pgvector distance operator:
1084
+ *
1085
+ * - `'l2'` → `<->` (Euclidean / L2 distance)
1086
+ * - `'cosine'` → `<=>` (cosine distance)
1087
+ * - `'ip'` → `<#>` (negative inner product)
1088
+ *
1089
+ * This is a fixed allow-list — a value outside it is rejected with a
1090
+ * `ValidationError` so a user-supplied string can never become a SQL operator.
1091
+ */
1092
+ export type VectorMetric = 'l2' | 'cosine' | 'ip';
1093
+ /**
1094
+ * Distance threshold filter for a pgvector column inside a `where` clause:
1095
+ *
1096
+ * ```ts
1097
+ * where: { embedding: { distance: { to: [0.1, 0.2, 0.3], metric: 'l2', lt: 0.3 } } }
1098
+ * // → WHERE "embedding" <-> $1::vector < $2
1099
+ * ```
1100
+ *
1101
+ * `to` is always bound as a single `$n::vector` param (never interpolated) and
1102
+ * each element must be a finite number. Exactly one comparison
1103
+ * (`lt` / `lte` / `gt` / `gte`) is applied; the threshold is also a bound param.
1104
+ */
1105
+ export interface VectorDistanceFilter {
1106
+ /** The query vector to measure distance against. */
1107
+ to: number[];
1108
+ /** Distance metric → operator. */
1109
+ metric: VectorMetric;
1110
+ /** distance < threshold */
1111
+ lt?: number;
1112
+ /** distance <= threshold */
1113
+ lte?: number;
1114
+ /** distance > threshold */
1115
+ gt?: number;
1116
+ /** distance >= threshold */
1117
+ gte?: number;
1118
+ }
1119
+ /** Vector query operators for where clauses (pgvector). */
1120
+ export interface VectorFilter {
1121
+ /** Filter rows by distance from a query vector. */
1122
+ distance: VectorDistanceFilter;
1123
+ }
1124
+ /**
1125
+ * KNN ordering spec for a pgvector column inside an `orderBy` clause:
1126
+ *
1127
+ * ```ts
1128
+ * orderBy: { embedding: { distance: { to: [...], metric: 'cosine' } } }
1129
+ * // → ORDER BY "embedding" <=> $1::vector ASC
1130
+ * ```
1131
+ *
1132
+ * `distance` ASC ranks nearest-first (the default). Pass `direction: 'desc'`
1133
+ * to invert. The query vector `to` is bound as a `$n::vector` param.
1134
+ */
1135
+ export interface VectorOrderByDistance {
1136
+ to: number[];
1137
+ metric: VectorMetric;
1138
+ /** Sort direction for the computed distance. Defaults to `'asc'` (nearest first). */
1139
+ direction?: OrderDirection;
1140
+ }
1141
+ /** Per-column orderBy value: a plain direction or a vector-distance ordering. */
1142
+ export interface VectorOrderBy {
1143
+ distance: VectorOrderByDistance;
1144
+ }
1145
+ /**
1146
+ * Explicit ordering spec for a column: a direction plus an optional NULLS
1147
+ * placement. `{ sort: 'desc', nulls: 'last' }` compiles to
1148
+ * `ORDER BY "col" DESC NULLS LAST`. The plain `'asc' | 'desc'` shorthand is
1149
+ * still accepted and unchanged. `nulls` is only emitted on engines that
1150
+ * support the `NULLS FIRST/LAST` grammar (PostgreSQL, SQLite); requesting it
1151
+ * elsewhere throws {@link UnsupportedFeatureError} (E017).
1152
+ */
1153
+ export interface OrderBySpec {
1154
+ sort: OrderDirection;
1155
+ nulls?: 'first' | 'last';
1156
+ }
1157
+ /**
1158
+ * Ordering by a JSON path on a json/jsonb column of the SAME table:
1159
+ *
1160
+ * ```ts
1161
+ * orderBy: { data: { path: ['weight'], direction: 'asc', type: 'numeric' } }
1162
+ * // → ORDER BY ("data" #>> $n::text[])::numeric ASC
1163
+ * ```
1164
+ *
1165
+ * The path is bound as a single text[] parameter (never interpolated).
1166
+ * Comparison rule: values extracted from the path compare as TEXT by default;
1167
+ * pass `type: 'numeric'` to cast for numeric comparison (`::numeric` on
1168
+ * PostgreSQL). The column must be json/jsonb: anything else throws
1169
+ * {@link ValidationError} (E003). Non-Postgres engines route through the same
1170
+ * dialect JSON-extract hook the JSON where-filters use. Cross-relation
1171
+ * (lateral) JSON ordering is NOT supported: same-table columns only.
1172
+ */
1173
+ export interface JsonPathOrderBy {
1174
+ /** JSON path into the column (each element a key or array index). Bound as one text[] param. */
1175
+ path: (string | number)[];
1176
+ /** Sort direction. Defaults to `'asc'`. */
1177
+ direction?: OrderDirection;
1178
+ /** Comparison kind for the extracted value. Defaults to `'text'`; `'numeric'` adds a numeric cast. */
1179
+ type?: 'numeric' | 'text';
1180
+ /**
1181
+ * NULLS placement (PostgreSQL / SQLite only: see {@link OrderBySpec}).
1182
+ * Rows whose document lacks the path extract to NULL and sort LAST in BOTH
1183
+ * directions by default (matching pick-row ordering and the PowDB engine
1184
+ * contract, so ordering is predictable across drivers); set `nulls` to
1185
+ * override on PostgreSQL / SQLite.
1186
+ */
1187
+ nulls?: 'first' | 'last';
1188
+ }
1189
+ /**
1190
+ * Ordering by a relation, keyed by the relation name in an {@link OrderByClause}:
1191
+ *
1192
+ * - to-many (hasMany / manyToMany): `{ posts: { _count: 'desc' } }` — orders by
1193
+ * a correlated `COUNT(*)` of the related rows.
1194
+ * - to-one (belongsTo / hasOne): `{ author: { name: 'asc' } }` — orders by a
1195
+ * correlated scalar subquery on the target column (an {@link OrderBySpec} with
1196
+ * `nulls` is accepted too).
1197
+ */
1198
+ export type RelationOrderBy = {
1199
+ _count: OrderDirection;
1200
+ } | Record<string, OrderDirection | OrderBySpec>;
1201
+ /**
1202
+ * The ordering value extracted from the picked row in a
1203
+ * {@link RelationPickOrderBy}: either a plain target column name (camelCase,
1204
+ * columnMap-resolved) or a JSON path into a json/jsonb target column.
1205
+ * Values extracted from a JSON path compare as TEXT by default; pass
1206
+ * `type: 'numeric'` to add a numeric cast.
1207
+ */
1208
+ export type RelationPickBy = string | {
1209
+ /** json/jsonb column on the relation target. */
1210
+ field: string;
1211
+ /**
1212
+ * JSON path into the column (each element a key or array index). Bound
1213
+ * as ONE param: a text[] on PostgreSQL, a `'$'`-rooted JSONPath string
1214
+ * on engines whose JSON functions take one (SQLite/MySQL/SQL Server).
1215
+ */
1216
+ path: (string | number)[];
1217
+ /** Comparison kind for the extracted value. Defaults to `'text'`. */
1218
+ type?: 'numeric' | 'text';
1219
+ };
1220
+ /**
1221
+ * Pick-row relation ordering: order a parent query by a value read from ONE
1222
+ * related row of a hasMany relation, keyed by the relation name in an
1223
+ * {@link OrderByClause}. Compiles to a correlated scalar subquery in ORDER BY:
1224
+ *
1225
+ * ```ts
1226
+ * orderBy: {
1227
+ * versions: {
1228
+ * pick: { orderBy: { createdAt: 'desc' } }, // which related row
1229
+ * by: { field: 'data', path: ['title'] }, // value to sort the parents by
1230
+ * direction: 'asc',
1231
+ * nulls: 'last',
1232
+ * },
1233
+ * }
1234
+ * // → ORDER BY (SELECT ord0."data" #>> $n::text[] FROM "versions" ord0
1235
+ * // WHERE ord0."instance_id" = "instances"."id"
1236
+ * // ORDER BY ord0."created_at" DESC LIMIT 1) ASC NULLS LAST
1237
+ * ```
1238
+ *
1239
+ * `pick.orderBy` is REQUIRED (it makes the picked row deterministic) and
1240
+ * supports the same surface as a relation `with` orderBy on the target (plain
1241
+ * columns, {@link OrderBySpec} nulls, {@link JsonPathOrderBy}). `pick.where`
1242
+ * optionally filters the candidate rows before picking. hasMany relations
1243
+ * only; top-level findMany orderBy only (manyToMany, to-one relations, and
1244
+ * nested `with` orderBy throw {@link ValidationError} E003).
1245
+ */
1246
+ export interface RelationPickOrderBy {
1247
+ /** Which related row supplies the value. */
1248
+ pick: {
1249
+ /** Inner ORDER BY choosing the row (required for determinism). */
1250
+ orderBy: Record<string, OrderDirection | OrderBySpec | JsonPathOrderBy>;
1251
+ /** Optional filter on the candidate rows before picking. */
1252
+ where?: Record<string, unknown>;
1253
+ };
1254
+ /** The value on the picked row to order the parents by. */
1255
+ by: RelationPickBy;
1256
+ /** Sort direction for the parents. Defaults to `'asc'`. */
1257
+ direction?: OrderDirection;
1258
+ /**
1259
+ * NULLS placement (PostgreSQL / SQLite only: see {@link OrderBySpec}).
1260
+ *
1261
+ * A parent with NO related rows sorts by NULL. When `nulls` is not set,
1262
+ * pick ordering defaults to `NULLS LAST` in BOTH directions, so parents
1263
+ * with zero related rows always come last (Postgres's own DESC default is
1264
+ * NULLS FIRST, which would put every childless parent at the top of a
1265
+ * "highest first" sort). Set `nulls` explicitly to override.
1266
+ */
1267
+ nulls?: 'first' | 'last';
1268
+ /**
1269
+ * Physical plan for the pick. `'subquery'` (default) compiles a correlated
1270
+ * scalar subquery in ORDER BY. `'lateral'` (PostgreSQL only, E017 elsewhere)
1271
+ * compiles a `LEFT JOIN LATERAL (... LIMIT 1) ON true` and orders by the
1272
+ * joined value. Identical results; the lateral form can be significantly
1273
+ * faster on large parent sets where the ordering subquery dominates the plan.
1274
+ * Never falls back silently: contexts that cannot take a lateral (non-Postgres
1275
+ * engines, `distinct`, nested `with` orderBy, a parent column literally named
1276
+ * `__turbine_pick`) throw.
1277
+ */
1278
+ plan?: 'subquery' | 'lateral';
1279
+ }
1280
+ /**
1281
+ * A single orderBy object: maps each key to one of:
1282
+ * - a plain direction (`'asc'` / `'desc'`),
1283
+ * - an {@link OrderBySpec} (`{ sort, nulls }`) for NULLS placement,
1284
+ * - for json/jsonb columns, a JSON-path ordering ({@link JsonPathOrderBy}),
1285
+ * - for pgvector columns, a KNN distance ordering ({@link VectorOrderBy}),
1286
+ * - for a relation name, a {@link RelationOrderBy} (`_count` for to-many, a
1287
+ * target column for to-one) or a pick-row ordering
1288
+ * ({@link RelationPickOrderBy}, hasMany only).
1289
+ */
1290
+ export type OrderByObject = Record<string, OrderDirection | OrderBySpec | JsonPathOrderBy | VectorOrderBy | RelationOrderBy | RelationPickOrderBy>;
1291
+ /**
1292
+ * An orderBy clause. Either a single {@link OrderByObject}
1293
+ * (`{ a: 'asc', b: 'desc' }`, insertion order authoritative) or a Prisma-style
1294
+ * array of them (`[{ a: 'asc' }, { b: 'desc' }]`, array order authoritative).
1295
+ * The array form makes multi-key ordering independent of JS object key
1296
+ * iteration order. Both forms flatten through `orderByEntries` so build,
1297
+ * param-collect, and cache-fingerprint paths stay in lockstep.
1298
+ */
1299
+ export type OrderByClause = OrderByObject | OrderByObject[];
1300
+ export {};