turbine-orm 0.34.0 → 0.36.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 (76) hide show
  1. package/README.md +18 -16
  2. package/dist/cjs/cli/index.js +109 -16
  3. package/dist/cjs/cli/migrate.js +78 -3
  4. package/dist/cjs/cli/studio-ui.generated.js +1 -1
  5. package/dist/cjs/cli/studio.js +333 -22
  6. package/dist/cjs/cli/ui.js +7 -1
  7. package/dist/cjs/client.js +26 -4
  8. package/dist/cjs/dialect.js +2 -1
  9. package/dist/cjs/errors.js +41 -1
  10. package/dist/cjs/generate.js +23 -2
  11. package/dist/cjs/index.js +4 -2
  12. package/dist/cjs/mssql.js +27 -5
  13. package/dist/cjs/mysql.js +4 -0
  14. package/dist/cjs/powdb.js +197 -25
  15. package/dist/cjs/powql.js +515 -51
  16. package/dist/cjs/query/aggregates.js +683 -0
  17. package/dist/cjs/query/batched-loader.js +2 -0
  18. package/dist/cjs/query/builder.js +361 -4508
  19. package/dist/cjs/query/filters.js +12 -0
  20. package/dist/cjs/query/relations.js +1698 -0
  21. package/dist/cjs/query/where-compile.js +180 -0
  22. package/dist/cjs/query/where.js +1491 -0
  23. package/dist/cjs/query/writes.js +680 -0
  24. package/dist/cjs/schema-builder.js +6 -0
  25. package/dist/cjs/schema-metadata.js +4 -0
  26. package/dist/cjs/schema-sql.js +265 -3
  27. package/dist/cjs/sqlite.js +4 -1
  28. package/dist/cli/index.d.ts +8 -2
  29. package/dist/cli/index.js +111 -18
  30. package/dist/cli/migrate.d.ts +24 -1
  31. package/dist/cli/migrate.js +77 -3
  32. package/dist/cli/studio-ui.generated.js +1 -1
  33. package/dist/cli/studio.d.ts +46 -13
  34. package/dist/cli/studio.js +331 -23
  35. package/dist/cli/ui.js +7 -1
  36. package/dist/client.d.ts +32 -5
  37. package/dist/client.js +26 -4
  38. package/dist/dialect.d.ts +28 -6
  39. package/dist/dialect.js +2 -1
  40. package/dist/errors.d.ts +36 -0
  41. package/dist/errors.js +39 -0
  42. package/dist/generate.js +23 -2
  43. package/dist/index.d.ts +3 -3
  44. package/dist/index.js +2 -2
  45. package/dist/mssql.js +27 -5
  46. package/dist/mysql.js +4 -0
  47. package/dist/powdb.d.ts +135 -9
  48. package/dist/powdb.js +197 -25
  49. package/dist/powql.d.ts +166 -4
  50. package/dist/powql.js +516 -52
  51. package/dist/query/aggregates.d.ts +74 -0
  52. package/dist/query/aggregates.js +641 -0
  53. package/dist/query/batched-loader.d.ts +6 -0
  54. package/dist/query/batched-loader.js +2 -0
  55. package/dist/query/builder.d.ts +98 -830
  56. package/dist/query/builder.js +366 -4513
  57. package/dist/query/deferred.d.ts +13 -2
  58. package/dist/query/filters.d.ts +7 -0
  59. package/dist/query/filters.js +11 -0
  60. package/dist/query/relations.d.ts +441 -0
  61. package/dist/query/relations.js +1627 -0
  62. package/dist/query/types.d.ts +25 -6
  63. package/dist/query/where-compile.d.ts +139 -0
  64. package/dist/query/where-compile.js +175 -0
  65. package/dist/query/where.d.ts +494 -0
  66. package/dist/query/where.js +1431 -0
  67. package/dist/query/writes.d.ts +131 -0
  68. package/dist/query/writes.js +626 -0
  69. package/dist/schema-builder.d.ts +18 -3
  70. package/dist/schema-builder.js +6 -0
  71. package/dist/schema-metadata.js +4 -0
  72. package/dist/schema-sql.d.ts +60 -3
  73. package/dist/schema-sql.js +261 -4
  74. package/dist/schema.d.ts +10 -0
  75. package/dist/sqlite.js +4 -1
  76. package/package.json +4 -4
@@ -0,0 +1,494 @@
1
+ /**
2
+ * turbine-orm: WHERE-clause compilation (extracted from builder.ts)
3
+ *
4
+ * The whole WHERE web: the top-level build/collect/fingerprint trio, the
5
+ * table-scoped trio for relation-filter EXISTS sub-wheres and relation
6
+ * `with`-clause wheres, the leaf JSON/array/vector/text-search clause builders,
7
+ * operator-clause + column-reference compilation, and the client-level
8
+ * global-filter helpers. All functions take a {@link BuilderCtx} as their first
9
+ * argument: the privacy-preserving view of the owning {@link QueryInterface}
10
+ * instance (built once in its constructor) exposing exactly the class-resident
11
+ * primitives this module needs. See builder.ts for the thin delegating methods.
12
+ */
13
+ import type pg from 'pg';
14
+ import type { Dialect } from '../dialect.js';
15
+ import { ValidationError } from '../errors.js';
16
+ import type { RelationDef, SchemaMetadata, TableMetadata } from '../schema.js';
17
+ import type { ArrayFilter, ColumnRef, GlobalFilters, JsonFilter, JsonPathOrderBy, SkipGlobalFilters, TextSearchFilter, VectorFilter, WhereClause, WhereOperator } from './types.js';
18
+ import { type SqlCacheEntry } from './utils.js';
19
+ import { type WhereHost, type WhereRecord } from './where-compile.js';
20
+ /**
21
+ * The privacy-preserving view of a {@link QueryInterface} instance passed as the
22
+ * first argument to every function in this module. Built once as an object
23
+ * literal in the QueryInterface constructor (mirroring the `whereHost`
24
+ * precedent). Data fields are live references to the instance's own state;
25
+ * `currentSkip` is a live getter (it is reassigned per `build*` call). The
26
+ * method members are the class-resident primitives these functions still need.
27
+ */
28
+ export interface BuilderCtx {
29
+ readonly dialect: Dialect;
30
+ readonly table: string;
31
+ readonly schema: SchemaMetadata;
32
+ readonly tableMeta: TableMetadata;
33
+ readonly whereHost: WhereHost;
34
+ readonly globalFilters?: GlobalFilters;
35
+ readonly scopedHostCache: Map<string, WhereHost>;
36
+ readonly columnPgTypeMap: Map<string, string>;
37
+ readonly columnArrayTypeMap: Map<string, string>;
38
+ readonly crossSchemaTypeColumns: Set<string>;
39
+ /**
40
+ * The active query's `skipGlobalFilters` opt-out. A live getter/setter over
41
+ * the owning instance's field: `build*` methods set it at their top, and the
42
+ * synchronous SQL-build + param-collect tree reads it deep inside
43
+ * `resolveGlobalFilter`.
44
+ */
45
+ currentSkip: SkipGlobalFilters | undefined;
46
+ q(name: string): string;
47
+ p(index: number): string;
48
+ inParam(values: unknown): unknown;
49
+ inClause(expr: string, paramRef: string, negated: boolean): string;
50
+ toColumn(field: string): string;
51
+ castAgg(expr: string, target: 'int' | 'float'): string;
52
+ parseRow(row: Record<string, unknown>, table: string): Record<string, unknown>;
53
+ nullsSuffix(nulls: 'first' | 'last' | undefined): string;
54
+ isRelationOrderByValue(value: unknown): boolean;
55
+ resolveOrderByColumn(table: string, meta: TableMetadata, key: string): string;
56
+ buildJsonPathOrderEntry(table: string, meta: TableMetadata, field: string, spec: JsonPathOrderBy, prefix: string, params?: unknown[]): string;
57
+ toSqlColumn(field: string): string;
58
+ mutationInsertId(result: pg.QueryResult): unknown;
59
+ acquireSql(cacheKey: string, build: (params: unknown[]) => string): SqlCacheEntry;
60
+ crossCheckCache(op: string, cacheKey: string, entry: SqlCacheEntry, build: (params: unknown[]) => string, collectedParams: unknown[]): void;
61
+ readonly jsonEncoding: 'object' | 'positional';
62
+ readonly camelDateFieldCache: Map<string, Set<string>>;
63
+ limitOneClause(): string;
64
+ buildPagination(limitPh: string | undefined, offsetPh: string | undefined, hasOrderBy: boolean): string;
65
+ paginationRef(value: unknown, params: unknown[]): string;
66
+ }
67
+ /**
68
+ * Column-reference resolution context threaded into
69
+ * {@link QueryInterface.buildOperatorClauses} / `collectOperatorParams`: the
70
+ * table whose fields a `{ col }` reference may name, plus the SQL prefix
71
+ * (`''` top-level, `"table".` in relation-filter subqueries, `t0.` against a
72
+ * relation alias) the compiled identifier must carry so it resolves in the
73
+ * same scope as the operator's own column.
74
+ */
75
+ interface ColumnRefContext {
76
+ meta: TableMetadata;
77
+ table: string;
78
+ prefix: string;
79
+ }
80
+ /**
81
+ * A table-scoped WHERE compilation context for a sub-where that is NOT the
82
+ * top-level `this.tableMeta` clause. Both relation-filter `EXISTS` sub-wheres
83
+ * (correlated against the bare target table, `"target".col`) and relation
84
+ * `with`-clause `where` filters (against a per-subquery alias, `t0.col`) compile
85
+ * an arbitrary target table's where against a column qualifier. They differ ONLY
86
+ * in that qualifier, the correlation parent handed to `buildRelationFilter`, and
87
+ * the unknown-column error wording — so a single scoped build/collect/fingerprint
88
+ * trio, driven by the SAME canonical {@link walkWhere} the top level uses, serves
89
+ * both. See `buildScopedWhere` / `collectScopedWhereParams` / `fingerprintScopedWhere`.
90
+ */
91
+ interface WhereScope {
92
+ /** The target table's metadata (column map, relations, types). */
93
+ meta: TableMetadata;
94
+ /** The target table name (used for host binding + error messages). */
95
+ table: string;
96
+ /** SQL prefix before `q(col)` — `"target".` for EXISTS sub-wheres, `t0.` for aliases. */
97
+ qualifier: string;
98
+ /** The `parentTable` correlation argument for nested `buildRelationFilter` calls. */
99
+ relationParent: string;
100
+ /** {@link WhereHost} bound to `meta`, so {@link walkWhere} enumerates this scope's keys. */
101
+ host: WhereHost;
102
+ /** Typed error for an unknown column reference (wording differs per scope). */
103
+ unknownColumn: (field: string) => ValidationError;
104
+ }
105
+ /**
106
+ * Produce a value-invariant fingerprint of a where clause.
107
+ * Same keys + same operator shapes + same combinator structure => same string.
108
+ * Different values (e.g. id=1 vs id=999) => identical fingerprint.
109
+ *
110
+ * @internal Exposed as package-private for testing via class access.
111
+ */
112
+ export declare function fingerprintWhere(qi: BuilderCtx, where: Record<string, unknown>): string;
113
+ /**
114
+ * Fingerprint the present branches of a normalized relation filter, in the
115
+ * fixed order some→every→none→is→isNot. A `null` branch tokenizes as
116
+ * `<branch>(null)`; a present branch recurses through
117
+ * {@link fingerprintRelFilter} so the FULL inner shape is captured (two
118
+ * different sub-wheres must never collide on one cached SQL text).
119
+ */
120
+ export declare function fingerprintRelationParts(qi: BuilderCtx, relDef: RelationDef, filterObj: WhereRecord): string[];
121
+ /**
122
+ * Fingerprint a relation filter sub-where for some/every/none. Thin wrapper
123
+ * over the unified {@link fingerprintScopedWhere}. When the target table is
124
+ * unknown, an empty-relations host makes every key scalar (matching the old
125
+ * `meta?.relations` short-circuit).
126
+ */
127
+ export declare function fingerprintRelFilter(qi: BuilderCtx, targetTable: string, subWhere: Record<string, unknown>): string;
128
+ /**
129
+ * Walk a where clause and push ONLY values into `params`, in the EXACT same
130
+ * order that `buildWhereClause` pushes them. Used on cache hit to fill params
131
+ * without rebuilding SQL.
132
+ *
133
+ * @internal Exposed as package-private for testing.
134
+ */
135
+ export declare function collectWhereParams(qi: BuilderCtx, where: Record<string, unknown>, params: unknown[]): void;
136
+ /**
137
+ * Push a scalar WHERE value's params, mirroring {@link buildScalarClause}'s
138
+ * emissions exactly. Both resolve the value's shape via the shared
139
+ * {@link classifyScalarForSql}, so a cache HIT binds each `$N` to the value
140
+ * the cached SQL expects. A JSON/array-shaped value on a non-JSON/array column
141
+ * (`jsonThrow`/`arrayThrow`) falls through to the equality path here, the
142
+ * same fall-through the collect path has always taken (the build path's typed
143
+ * error there is only reachable on a MISS, before anything is cached).
144
+ */
145
+ export declare function collectScalarParams(qi: BuilderCtx, key: string, value: unknown, params: unknown[]): void;
146
+ /**
147
+ * Param-collect mirror of {@link buildRelationFilter} for one relation-filter
148
+ * object (`{ some/every/none/is/isNot }`, already normalized). Pushes, per
149
+ * present branch and in the canonical order some→none→every→is→isNot, the
150
+ * branch's sub-where params THEN the target table's global-filter params —
151
+ * exactly the order buildRelationFilter emits. When no global filter applies
152
+ * the gf calls are no-ops, so this stays byte-identical to the pre-0.28 path.
153
+ * Shared by every collect site that mirrors buildRelationFilter
154
+ * (collectWhereParams, collectRelFilterParams, collectAliasWhereParams).
155
+ */
156
+ export declare function collectRelationFilterParams(qi: BuilderCtx, relDef: RelationDef, filterObj: Record<string, unknown>, params: unknown[]): void;
157
+ export declare function collectRelFilterParams(qi: BuilderCtx, targetTable: string, subWhere: Record<string, unknown>, params: unknown[]): void;
158
+ /**
159
+ * Collect params from operator clauses. Mirrors buildOperatorClauses:
160
+ * {@link ColumnRef} values compile into the SQL text, so they push NOTHING -
161
+ * but they re-run the same validation (unknown ref / insensitive mode) so a
162
+ * warmed cache can never skip a check the build path enforces.
163
+ */
164
+ export declare function collectOperatorParams(qi: BuilderCtx, column: string, op: WhereOperator, params: unknown[], refCtx?: ColumnRefContext): void;
165
+ /**
166
+ * Collect params from JSON filter. Mirrors buildJsonFilterClauses exactly:
167
+ * the `path` is bound at most once (its placeholder is shared by every
168
+ * extraction clause), then equals/contains/hasKey values, then the range
169
+ * comparison values in {@link JSON_RANGE_OPERATORS} order.
170
+ */
171
+ export declare function collectJsonFilterParams(qi: BuilderCtx, filter: JsonFilter, params: unknown[], column: string): void;
172
+ /** Collect params from array filter. Mirrors buildArrayFilterClauses. */
173
+ export declare function collectArrayFilterParams(_qi: BuilderCtx, filter: ArrayFilter, params: unknown[]): void;
174
+ /**
175
+ * Collect params for a vector distance WHERE filter. Mirrors
176
+ * {@link buildVectorFilterClauses}: the `$n::vector` query vector first, then
177
+ * the comparison threshold(s).
178
+ */
179
+ export declare function collectVectorFilterParams(qi: BuilderCtx, field: string, rawColumn: string, filter: VectorFilter, params: unknown[]): void;
180
+ /** Build WHERE clause from a where object (supports operators, NULL, OR) */
181
+ export declare function buildWhere<T extends object>(qi: BuilderCtx, where: WhereClause<T>): {
182
+ sql: string;
183
+ params: unknown[];
184
+ };
185
+ /**
186
+ * Resolve the configured global filter for `table`, evaluating a function
187
+ * filter, honoring the active query's `skipGlobalFilters`. Returns `null` when
188
+ * no filter applies, the query opted out, or the filter is empty.
189
+ */
190
+ export declare function resolveGlobalFilter(qi: BuilderCtx, table: string, skip?: SkipGlobalFilters | undefined): Record<string, unknown> | null;
191
+ /**
192
+ * AND-merge this table's resolved global filter into a user `where`. Either
193
+ * side may be absent. When no filter applies the user where is returned by
194
+ * reference, so fingerprints/SQL stay byte-identical to the pre-0.28 path.
195
+ */
196
+ export declare function mergeGlobalFilter(qi: BuilderCtx, userWhere: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
197
+ /**
198
+ * SQL clause for `targetTable`'s global filter rendered against `alias`
199
+ * (relation subqueries, `_count`, relation `orderBy`). Pushes its params to
200
+ * `params`; returns `''` when no filter applies. Mirror:
201
+ * {@link collectTargetGlobalFilterAlias}.
202
+ */
203
+ export declare function targetGlobalFilterAlias(qi: BuilderCtx, targetTable: string, alias: string, params: unknown[]): string;
204
+ /** Param-collect mirror of {@link targetGlobalFilterAlias}. */
205
+ export declare function collectTargetGlobalFilterAlias(qi: BuilderCtx, targetTable: string, params: unknown[]): void;
206
+ /**
207
+ * SQL clause for `targetTable`'s global filter rendered against the bare
208
+ * (unaliased) table name — the form used inside relation-filter `EXISTS`
209
+ * subqueries. Pushes its params; `''` when none. Mirror:
210
+ * {@link collectTargetGlobalFilterExists}.
211
+ */
212
+ export declare function targetGlobalFilterExists(qi: BuilderCtx, targetTable: string, params: unknown[]): string;
213
+ /** Param-collect mirror of {@link targetGlobalFilterExists}. */
214
+ export declare function collectTargetGlobalFilterExists(qi: BuilderCtx, targetTable: string, params: unknown[]): void;
215
+ /**
216
+ * Value-invariant SQL-cache-key segment for the active global-filter
217
+ * environment. Relation-subquery / relation-filter / `_count` / relation-
218
+ * `orderBy` global filters are rendered at build time but their SHAPE is not
219
+ * otherwise in the where/with fingerprint, so this segment guards the cache:
220
+ * two different filter shapes never collide on one cached SQL text, while two
221
+ * function-filter results of the SAME shape (differing only in values) share
222
+ * the entry and bind their own params. Empty (`''`) when no filter applies, so
223
+ * cache keys stay byte-identical when the feature is unused.
224
+ */
225
+ export declare function globalFilterCacheSegment(qi: BuilderCtx): string;
226
+ /**
227
+ * True when the USER-supplied `where` compiles to no predicate (`{}`,
228
+ * `{ id: undefined }`, `{ OR: [{ a: undefined }] }`, …). This is the exact
229
+ * signal the empty-`where` guard needs — the compiled emptiness, NOT the
230
+ * fingerprint (which is non-empty for an all-undefined `OR`/`AND`). It ignores
231
+ * any configured global filter, so a global filter never lets an unguarded
232
+ * mass mutation through.
233
+ */
234
+ export declare function userPredicateIsEmpty(qi: BuilderCtx, userWhere: Record<string, unknown>): boolean;
235
+ export declare function assertMutationHasPredicate(qi: BuilderCtx, operation: 'update' | 'updateMany' | 'delete' | 'deleteMany', whereSql: string, allowFullTableScan: boolean | undefined): void;
236
+ /**
237
+ * Build the inner WHERE expression (without the WHERE keyword).
238
+ * Returns null if no conditions exist.
239
+ * Supports: equality, operators, NULL, OR, AND, NOT, relation filters (some/every/none).
240
+ */
241
+ export declare function buildWhereClause(qi: BuilderCtx, where: Record<string, unknown>, params: unknown[]): string | null;
242
+ /**
243
+ * Emit the SQL clause(s) for one scalar WHERE key onto `andClauses`, pushing
244
+ * any params. The shape decision comes from the shared
245
+ * {@link classifyScalarForSql} so {@link collectScalarParams} pushes an
246
+ * identical param list on a cache hit. The `*Throw` branches preserve the
247
+ * strict-validation errors for a JSON/array operator on the wrong column type.
248
+ */
249
+ export declare function buildScalarClause(qi: BuilderCtx, key: string, value: unknown, params: unknown[], andClauses: string[]): void;
250
+ /**
251
+ * A {@link WhereHost} with no relations — used to fingerprint a sub-where
252
+ * whose target table is unknown (`schema.tables[t]` miss). `walkWhere` reads
253
+ * only `tableMeta.relations`, so every key falls to the scalar path, matching
254
+ * the pre-unification `meta?.relations` short-circuit.
255
+ */
256
+ export declare function emptyRelationsHost(qi: BuilderCtx, table: string): WhereHost;
257
+ export declare function scopedWhereHost(qi: BuilderCtx, meta: TableMetadata): WhereHost;
258
+ /** Build the scope for a relation-filter EXISTS sub-where over the bare target table. */
259
+ export declare function relationWhereScope(qi: BuilderCtx, targetTable: string, meta: TableMetadata): WhereScope;
260
+ /** Build the scope for a relation `with`-clause `where` compiled against `alias`. */
261
+ export declare function aliasWhereScope(qi: BuilderCtx, targetTable: string, meta: TableMetadata, alias: string): WhereScope;
262
+ /**
263
+ * Compile a scoped sub-where to SQL. Serves BOTH the relation-filter EXISTS
264
+ * body ({@link buildSubWhereForRelation}) and the relation `with`-clause
265
+ * `where` ({@link buildAliasWhere}) — the emitted SQL is byte-identical to the
266
+ * former hand-mirrored walkers, since it renders the same clauses in the same
267
+ * ({@link walkWhere}-canonical) key order.
268
+ */
269
+ export declare function buildScopedWhere(qi: BuilderCtx, scope: WhereScope, where: Record<string, unknown>, params: unknown[]): string | null;
270
+ /**
271
+ * Emit the SQL clause(s) for one scalar key of a scoped sub-where. Reproduces
272
+ * the null / JSON / array / operator / equality fall-through both former
273
+ * walkers shared (relation sub-wheres and alias wheres carry no vector or
274
+ * text-search scalar surface, so — unlike the top-level {@link buildScalarClause}
275
+ * — those shapes are not special-cased here and keep their historical
276
+ * equality-guard behavior).
277
+ */
278
+ export declare function buildScopedScalarClause(qi: BuilderCtx, scope: WhereScope, field: string, value: unknown, params: unknown[], clauses: string[]): void;
279
+ /**
280
+ * Cache-hit param-collect mirror of {@link buildScopedWhere}: pushes the exact
281
+ * same params in the exact same order (driven by the same {@link walkWhere}),
282
+ * without rebuilding SQL. Serves both {@link collectRelFilterParams} and
283
+ * {@link collectAliasWhereParams}.
284
+ */
285
+ export declare function collectScopedWhereParams(qi: BuilderCtx, scope: WhereScope, where: Record<string, unknown>, params: unknown[]): void;
286
+ /** Param-collect mirror of {@link buildScopedScalarClause}. */
287
+ export declare function collectScopedScalarParams(qi: BuilderCtx, scope: WhereScope, field: string, value: unknown, params: unknown[]): void;
288
+ /**
289
+ * Value-invariant fingerprint of a scoped sub-where. Same canonical
290
+ * {@link walkWhere} as {@link fingerprintWhere}, so two shapes that compile to
291
+ * different SQL never collide on one cached SQL string. Serves both
292
+ * {@link fingerprintRelFilter} and {@link fingerprintAliasWhere}. Fingerprint
293
+ * bytes are process-local cache keys (never persisted), so their exact text
294
+ * may differ from the pre-unification walkers as long as collisions stay
295
+ * impossible.
296
+ */
297
+ export declare function fingerprintScopedWhere(qi: BuilderCtx, host: WhereHost, where: Record<string, unknown>): string;
298
+ /**
299
+ * Build relation filter SQL: WHERE EXISTS / NOT EXISTS subquery
300
+ * Supports: some (EXISTS), every (NOT EXISTS ... NOT), none (NOT EXISTS)
301
+ */
302
+ export declare function buildRelationFilter(qi: BuilderCtx, _relName: string, relDef: RelationDef, filterObj: Record<string, unknown>, params: unknown[], parentTable?: string): string | null;
303
+ /**
304
+ * Build WHERE clause conditions for a relation filter subquery.
305
+ * Uses the target table's column mapping to resolve field names.
306
+ */
307
+ export declare function buildSubWhereForRelation(qi: BuilderCtx, targetTable: string, subWhere: Record<string, unknown>, params: unknown[]): string | null;
308
+ /**
309
+ * Resolve a column's Postgres type from an arbitrary table's metadata
310
+ * (relation targets, not just `qi.table`).
311
+ */
312
+ export declare function pgTypeForColumn(_qi: BuilderCtx, meta: TableMetadata, column: string): string;
313
+ /**
314
+ * The Postgres enum type name for a column, when the schema knows one.
315
+ *
316
+ * Introspection stores each column's `udt_name` in `pgTypes` and every
317
+ * database enum in `schema.enums` (typname → labels); a column whose type
318
+ * matches an enum key needs an explicit `::"EnumName"` cast on its write
319
+ * binds — bulk-insert forms like `UNNEST($1::text[])` otherwise type the
320
+ * value as text and Postgres refuses the implicit text→enum coercion
321
+ * ("column X is of type Y but expression is of type text").
322
+ *
323
+ * Postgres-only by construction: gated on the active dialect being
324
+ * `postgresql` AND on `schema.enums` having entries (only PG introspection
325
+ * produces them — `defineSchema` and the other engines leave it empty), so
326
+ * SQLite/MySQL/MSSQL/PowDB output is byte-identical.
327
+ */
328
+ export declare function enumTypeForColumn(qi: BuilderCtx, column: string): string | null;
329
+ /**
330
+ * `::"EnumName"` cast suffix for a write-bind placeholder on an enum
331
+ * column; `''` for every other column, so non-enum SQL stays byte-identical.
332
+ * The type name is an introspected identifier and is quoted via the dialect.
333
+ */
334
+ export declare function enumCastSuffix(qi: BuilderCtx, column: string): string;
335
+ /**
336
+ * Equality-fallthrough guard shared by every SQL-build path AND every
337
+ * cache-hit param-collect path. A plain object literal that matched no known
338
+ * filter shape on a non-JSON column is almost always a misspelled operator
339
+ * (`startWith` for `startsWith`); binding it as `col = $1` silently returns
340
+ * wrong rows. Class instances (Buffer for bytea, Decimal wrappers, ...) are
341
+ * legitimate bind values and pass through, as do objects on json/jsonb
342
+ * columns (object equality).
343
+ */
344
+ export declare function assertBindableEqualityValue(qi: BuilderCtx, rawColumn: string, value: unknown, columnPgType: string, table: string): void;
345
+ /**
346
+ * Build the user-supplied `where` filter of a relation `with` clause against
347
+ * the relation's table alias. Supports the same scalar surface as the
348
+ * top-level WHERE builder — equality, IS NULL, operator objects (incl.
349
+ * `mode: 'insensitive'`), and OR/AND/NOT combinators. Unknown operator
350
+ * objects throw via {@link assertBindableEqualityValue}.
351
+ *
352
+ * Param push order MUST mirror {@link collectAliasWhereParams} exactly, or
353
+ * cache hits and pipeline batching will desync.
354
+ */
355
+ export declare function buildAliasWhere(qi: BuilderCtx, targetTable: string, targetMeta: TableMetadata, alias: string, where: Record<string, unknown>, params: unknown[]): string | null;
356
+ /** Mirrors {@link buildAliasWhere} param-push order for the cache-hit collect path. */
357
+ export declare function collectAliasWhereParams(qi: BuilderCtx, targetTable: string, targetMeta: TableMetadata, where: Record<string, unknown>, params: unknown[]): void;
358
+ /**
359
+ * Value-invariant, shape-aware fingerprint for a relation `with` clause's
360
+ * `where` filter. Must distinguish every SQL shape {@link buildAliasWhere}
361
+ * can emit — equality vs null vs operator sets vs combinators — or two
362
+ * differently-shaped wheres would share one cached SQL string.
363
+ */
364
+ export declare function fingerprintAliasWhere(qi: BuilderCtx, where: Record<string, unknown>, targetTable?: string): string;
365
+ /**
366
+ * Validate a `{ col }` column reference against its table and return the
367
+ * resolved snake_case column name. Shared by the SQL-build path
368
+ * ({@link buildOperatorClauses}) and the cache-hit param-collect path
369
+ * (`collectOperatorParams`) so both always throw identically: a warmed
370
+ * cache can never skip the check.
371
+ */
372
+ export declare function resolveColumnRef(_qi: BuilderCtx, ref: ColumnRef, ctx: ColumnRefContext, mode?: 'default' | 'insensitive'): string;
373
+ /**
374
+ * Compile a `{ col }` reference to its quoted, prefix-matched SQL identifier.
375
+ * NO param is bound: the referenced column is part of the SQL text (and of
376
+ * the where fingerprint, via `fingerprintOperatorShape` in `filters.ts`).
377
+ */
378
+ export declare function columnRefSql(qi: BuilderCtx, ref: ColumnRef, ctx: ColumnRefContext | undefined, mode?: 'default' | 'insensitive'): string;
379
+ /**
380
+ * Build SQL clauses for a single operator object on a column.
381
+ * Each operator key becomes its own clause, all ANDed together.
382
+ *
383
+ * `equals`/`not`/`gt`/`gte`/`lt`/`lte` also accept a {@link ColumnRef}
384
+ * (`{ col: 'otherField' }`) which compiles to a column-to-column comparison
385
+ * against `refCtx`: no param bound, so `collectOperatorParams` mirrors by
386
+ * pushing nothing and the referenced name lives in the fingerprint.
387
+ */
388
+ export declare function buildOperatorClauses(qi: BuilderCtx, column: string, op: WhereOperator, params: unknown[], refCtx?: ColumnRefContext): string[];
389
+ /**
390
+ * Resolve a {@link VectorMetric} to its pgvector distance operator from a
391
+ * fixed allow-list, validating the target column is actually a `vector`
392
+ * column. Throws {@link ValidationError} for an unknown metric or a
393
+ * non-vector column — a user-supplied string can never become a SQL operator.
394
+ */
395
+ export declare function vectorOperator(qi: BuilderCtx, field: string, rawColumn: string, metric: string): string;
396
+ /**
397
+ * Validate and bind a query vector as a single `$n::vector` parameter.
398
+ * Every element must be a finite number (no NaN / Infinity / strings) so a
399
+ * malformed array can never produce a broken `::vector` literal, and the array
400
+ * is NEVER string-interpolated into the SQL text. Returns the `$n::vector`
401
+ * placeholder string.
402
+ */
403
+ export declare function pushVectorParam(qi: BuilderCtx, field: string, _rawColumn: string, to: unknown, params: unknown[]): string;
404
+ /**
405
+ * Prisma-compat: a plain object on a to-one relation key —
406
+ * `where: { vendor: { name: { contains: 'x' } } }` — is an implicit `is`
407
+ * filter. Normalize it to `{ is: obj }` so all downstream handling (SQL,
408
+ * params, fingerprint) sees one canonical shape. To-many relations still
409
+ * require an explicit `some`/`every`/`none` (a bare object there is
410
+ * ambiguous and was never valid in Prisma either).
411
+ */
412
+ export declare function normalizeRelationFilter(_qi: BuilderCtx, relDef: RelationDef, filterObj: Record<string, unknown>): Record<string, unknown>;
413
+ /**
414
+ * Case-insensitive json/jsonb column-type check. Postgres reports lowercase
415
+ * udt_names, but SQLite/MySQL introspection surfaces the DECLARED type
416
+ * (e.g. `JSON`), so every JSON-feature gate compares through this predicate
417
+ * — build and collect sides alike, keeping the SQL-cache lockstep.
418
+ */
419
+ export declare function isJsonColumnType(_qi: BuilderCtx, colType: string): boolean;
420
+ export declare function getColumnPgType(qi: BuilderCtx, column: string): string;
421
+ /**
422
+ * Get the Postgres base element type for an array column.
423
+ * E.g. '_text' → 'text', '_int4' → 'integer'
424
+ */
425
+ export declare function getArrayElementType(_qi: BuilderCtx, pgType: string): string;
426
+ /**
427
+ * Validate and enumerate the range comparisons (`gt`/`gte`/`lt`/`lte`) on a
428
+ * JSON filter, in the fixed {@link JSON_RANGE_OPERATORS} order. Shared by
429
+ * the SQL-build path ({@link buildJsonFilterClauses}) and the cache-hit
430
+ * param-collect path ({@link collectJsonFilterParams}) so both always agree
431
+ * on which params are pushed — and both throw identically for invalid
432
+ * shapes, so a warmed cache can never skip validation.
433
+ */
434
+ export declare function jsonRangeEntries(_qi: BuilderCtx, filter: JsonFilter, column: string): {
435
+ sqlOp: string;
436
+ value: number | string;
437
+ }[];
438
+ /**
439
+ * Build SQL clauses for JSONB filter operators on a column.
440
+ * Supports: path, equals, contains, hasKey, gt, gte, lt, lte.
441
+ *
442
+ * The `path` param is bound at most once and its placeholder is shared by
443
+ * every clause that extracts it (equals + range ops), so the param list
444
+ * stays byte-identical to {@link collectJsonFilterParams}.
445
+ */
446
+ export declare function buildJsonFilterClauses(qi: BuilderCtx, column: string, filter: JsonFilter, params: unknown[]): string[];
447
+ /**
448
+ * Bind value for a JSON path parameter, encoded per dialect. PostgreSQL's
449
+ * `#>>` takes a `text[]` (the segments as strings — or `nativeForm` when the
450
+ * caller has a specific native binding, e.g. JsonFilter's raw path array).
451
+ * Every other engine's JSON function (`json_extract` / `JSON_EXTRACT` /
452
+ * `JSON_VALUE`) takes a `'$'`-rooted JSONPath STRING: binding the raw array
453
+ * would arrive as `'["a"]'` (the driver shims JSON.stringify non-primitive
454
+ * params) and fail at runtime with the engine's bad-JSON-path error. The
455
+ * encoded path stays a bound parameter — never spliced into SQL text — so
456
+ * the build/collect param mirrors stay in lockstep and injection-safe.
457
+ */
458
+ export declare function jsonPathParam(qi: BuilderCtx, path: readonly (string | number)[], nativeForm?: unknown): unknown;
459
+ /**
460
+ * Cast an extracted JSON path text value to a numeric type for range
461
+ * comparison. PostgreSQL uses `(expr)::numeric` (exact — the right way to
462
+ * compare JSON numbers, and `::float` would lose precision on big ints);
463
+ * other dialects route through {@link Dialect.castAggregate} (SQLite/MySQL/
464
+ * SQL Server have no `::` operator) as a float cast.
465
+ */
466
+ export declare function castJsonNumeric(qi: BuilderCtx, extract: string): string;
467
+ /**
468
+ * Build SQL clauses for Array filter operators on a column.
469
+ * Supports: has, hasEvery, hasSome, isEmpty.
470
+ */
471
+ export declare function buildArrayFilterClauses(qi: BuilderCtx, column: string, filter: ArrayFilter, params: unknown[], pgType: string): string[];
472
+ /**
473
+ * Build SQL clauses for a pgvector distance WHERE filter:
474
+ *
475
+ * `"embedding" <-> $1::vector < $2`
476
+ *
477
+ * The query vector is bound as a `$n::vector` param (never interpolated), the
478
+ * metric maps to an operator via a fixed allow-list, and each comparison
479
+ * threshold (`lt`/`lte`/`gt`/`gte`) is its own bound param. Emits one clause
480
+ * per supplied comparator (all ANDed). Param push order matches
481
+ * {@link collectVectorFilterParams}.
482
+ */
483
+ export declare function buildVectorFilterClauses(qi: BuilderCtx, field: string, rawColumn: string, filter: VectorFilter, params: unknown[]): string[];
484
+ /**
485
+ * Build SQL clause for full-text search using to_tsvector @@ to_tsquery.
486
+ * The config name is validated to prevent injection (only alphanumeric + underscore).
487
+ */
488
+ export declare function buildTextSearchClause(qi: BuilderCtx, column: string, filter: TextSearchFilter, params: unknown[]): string;
489
+ /**
490
+ * Get the Postgres array type for a column (used by UNNEST in createMany).
491
+ * Uses pre-computed Map for O(1) lookup instead of linear scan.
492
+ */
493
+ export declare function getColumnArrayType(qi: BuilderCtx, column: string): string;
494
+ export {};