turbine-orm 0.35.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.
- package/README.md +18 -16
- package/dist/cjs/cli/index.js +109 -16
- package/dist/cjs/cli/migrate.js +78 -3
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.js +333 -22
- package/dist/cjs/cli/ui.js +7 -1
- package/dist/cjs/dialect.js +1 -1
- package/dist/cjs/generate.js +23 -2
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/mssql.js +22 -5
- package/dist/cjs/powdb.js +41 -1
- package/dist/cjs/powql.js +80 -25
- package/dist/cjs/query/aggregates.js +683 -0
- package/dist/cjs/query/batched-loader.js +2 -0
- package/dist/cjs/query/builder.js +297 -4504
- package/dist/cjs/query/filters.js +12 -0
- package/dist/cjs/query/relations.js +1698 -0
- package/dist/cjs/query/where-compile.js +180 -0
- package/dist/cjs/query/where.js +1491 -0
- package/dist/cjs/query/writes.js +680 -0
- package/dist/cjs/schema-builder.js +6 -0
- package/dist/cjs/schema-metadata.js +4 -0
- package/dist/cjs/schema-sql.js +265 -3
- package/dist/cjs/sqlite.js +1 -1
- package/dist/cli/index.d.ts +8 -2
- package/dist/cli/index.js +111 -18
- package/dist/cli/migrate.d.ts +24 -1
- package/dist/cli/migrate.js +77 -3
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +46 -13
- package/dist/cli/studio.js +331 -23
- package/dist/cli/ui.js +7 -1
- package/dist/dialect.d.ts +15 -6
- package/dist/dialect.js +1 -1
- package/dist/generate.js +23 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +22 -5
- package/dist/powdb.d.ts +20 -0
- package/dist/powdb.js +40 -0
- package/dist/powql.d.ts +33 -1
- package/dist/powql.js +80 -25
- package/dist/query/aggregates.d.ts +74 -0
- package/dist/query/aggregates.js +641 -0
- package/dist/query/batched-loader.d.ts +6 -0
- package/dist/query/batched-loader.js +2 -0
- package/dist/query/builder.d.ts +62 -829
- package/dist/query/builder.js +302 -4509
- package/dist/query/deferred.d.ts +7 -0
- package/dist/query/filters.d.ts +7 -0
- package/dist/query/filters.js +11 -0
- package/dist/query/relations.d.ts +441 -0
- package/dist/query/relations.js +1627 -0
- package/dist/query/types.d.ts +15 -0
- package/dist/query/where-compile.d.ts +139 -0
- package/dist/query/where-compile.js +175 -0
- package/dist/query/where.d.ts +494 -0
- package/dist/query/where.js +1431 -0
- package/dist/query/writes.d.ts +131 -0
- package/dist/query/writes.js +626 -0
- package/dist/schema-builder.d.ts +18 -3
- package/dist/schema-builder.js +6 -0
- package/dist/schema-metadata.js +4 -0
- package/dist/schema-sql.d.ts +60 -3
- package/dist/schema-sql.js +261 -4
- package/dist/schema.d.ts +10 -0
- package/dist/sqlite.js +1 -1
- package/package.json +2 -2
|
@@ -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 {};
|