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.
- package/README.md +122 -39
- package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
- package/dist/cjs/adapters/index.d.ts +110 -0
- package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
- package/dist/cjs/cli/config.d.ts +181 -0
- package/dist/cjs/cli/config.js +32 -6
- package/dist/cjs/cli/destructive.d.ts +38 -0
- package/dist/cjs/cli/index.d.ts +359 -0
- package/dist/cjs/cli/index.js +228 -56
- package/dist/cjs/cli/loader.d.ts +61 -0
- package/dist/cjs/cli/mcp.d.ts +42 -0
- package/dist/cjs/cli/migrate.d.ts +356 -0
- package/dist/cjs/cli/migrate.js +131 -40
- package/dist/cjs/cli/observe-ui.d.ts +1 -0
- package/dist/cjs/cli/observe-ui.js +14 -5
- package/dist/cjs/cli/observe.d.ts +25 -0
- package/dist/cjs/cli/observe.js +49 -12
- package/dist/cjs/cli/pii-tags.d.ts +53 -0
- package/dist/cjs/cli/prisma-report.d.ts +33 -0
- package/dist/cjs/cli/prisma-report.js +73 -0
- package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
- package/dist/cjs/cli/prisma-resolve.js +1 -0
- package/dist/cjs/cli/prisma-schema.d.ts +176 -0
- package/dist/cjs/cli/prisma-schema.js +82 -4
- package/dist/cjs/cli/rate-limit.d.ts +32 -0
- package/dist/cjs/cli/rate-limit.js +45 -0
- package/dist/cjs/cli/studio-demo.d.ts +43 -0
- package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
- package/dist/cjs/cli/studio.d.ts +207 -0
- package/dist/cjs/cli/studio.js +136 -71
- package/dist/cjs/cli/ui.d.ts +73 -0
- package/dist/cjs/cli/ui.js +51 -9
- package/dist/cjs/client.d.ts +837 -0
- package/dist/cjs/client.js +3 -0
- package/dist/cjs/dialect.d.ts +516 -0
- package/dist/cjs/dialect.js +37 -12
- package/dist/cjs/errors.d.ts +370 -0
- package/dist/cjs/generate.d.ts +137 -0
- package/dist/cjs/generate.js +39 -6
- package/dist/cjs/index-advisor.d.ts +153 -0
- package/dist/cjs/index-stats.d.ts +384 -0
- package/dist/cjs/index.d.ts +55 -0
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/introspect.d.ts +269 -0
- package/dist/cjs/mssql.d.ts +232 -0
- package/dist/cjs/mssql.js +6 -0
- package/dist/cjs/mysql.d.ts +173 -0
- package/dist/cjs/mysql.js +16 -0
- package/dist/cjs/nested-write.d.ts +96 -0
- package/dist/cjs/nested-write.js +414 -24
- package/dist/cjs/observe.d.ts +115 -0
- package/dist/cjs/optional-peer-import.d.cts +72 -0
- package/dist/cjs/pipeline-submittable.d.ts +93 -0
- package/dist/cjs/pipeline.d.ts +71 -0
- package/dist/cjs/powdb-introspect.d.ts +84 -0
- package/dist/cjs/powdb.d.ts +931 -0
- package/dist/cjs/powdb.js +106 -21
- package/dist/cjs/powql.d.ts +592 -0
- package/dist/cjs/powql.js +42 -6
- package/dist/cjs/prisma-compat.d.ts +283 -0
- package/dist/cjs/prisma-compat.js +167 -9
- package/dist/cjs/query/aggregates.d.ts +92 -0
- package/dist/cjs/query/aggregates.js +7 -3
- package/dist/cjs/query/batched-loader.d.ts +193 -0
- package/dist/cjs/query/builder.d.ts +849 -0
- package/dist/cjs/query/builder.js +571 -65
- package/dist/cjs/query/compound-unique.d.ts +51 -0
- package/dist/cjs/query/deferred.d.ts +223 -0
- package/dist/cjs/query/filters.d.ts +201 -0
- package/dist/cjs/query/index.d.ts +14 -0
- package/dist/cjs/query/index.js +6 -1
- package/dist/cjs/query/relations.d.ts +609 -0
- package/dist/cjs/query/relations.js +693 -46
- package/dist/cjs/query/types.d.ts +1300 -0
- package/dist/cjs/query/utils.d.ts +209 -0
- package/dist/cjs/query/utils.js +208 -1
- package/dist/cjs/query/warn-registry.d.ts +68 -0
- package/dist/cjs/query/warn-registry.js +9 -0
- package/dist/cjs/query/where-compile.d.ts +139 -0
- package/dist/cjs/query/where.d.ts +548 -0
- package/dist/cjs/query/where.js +58 -22
- package/dist/cjs/query/writes.d.ts +172 -0
- package/dist/cjs/query/writes.js +105 -12
- package/dist/cjs/realtime.d.ts +70 -0
- package/dist/cjs/schema-builder.d.ts +354 -0
- package/dist/cjs/schema-metadata.d.ts +83 -0
- package/dist/cjs/schema-sql.d.ts +217 -0
- package/dist/cjs/schema-sql.js +23 -5
- package/dist/cjs/schema.d.ts +356 -0
- package/dist/cjs/schema.js +125 -0
- package/dist/cjs/seed.d.ts +15 -0
- package/dist/cjs/serverless.d.ts +142 -0
- package/dist/cjs/sqlite.d.ts +143 -0
- package/dist/cjs/sqlite.js +4 -0
- package/dist/cjs/typed-sql.d.ts +102 -0
- package/dist/cli/config.d.ts +18 -4
- package/dist/cli/config.js +31 -6
- package/dist/cli/index.d.ts +123 -0
- package/dist/cli/index.js +223 -58
- package/dist/cli/migrate.d.ts +59 -10
- package/dist/cli/migrate.js +128 -41
- package/dist/cli/observe-ui.d.ts +1 -1
- package/dist/cli/observe-ui.js +14 -5
- package/dist/cli/observe.d.ts +7 -1
- package/dist/cli/observe.js +48 -12
- package/dist/cli/prisma-report.d.ts +14 -0
- package/dist/cli/prisma-report.js +72 -0
- package/dist/cli/prisma-resolve.d.ts +6 -0
- package/dist/cli/prisma-resolve.js +1 -0
- package/dist/cli/prisma-schema.d.ts +62 -2
- package/dist/cli/prisma-schema.js +81 -4
- package/dist/cli/rate-limit.d.ts +32 -0
- package/dist/cli/rate-limit.js +40 -0
- package/dist/cli/studio.d.ts +5 -5
- package/dist/cli/studio.js +135 -70
- package/dist/cli/ui.d.ts +1 -1
- package/dist/cli/ui.js +51 -9
- package/dist/client.d.ts +40 -0
- package/dist/client.js +3 -0
- package/dist/dialect.d.ts +17 -1
- package/dist/dialect.js +37 -12
- package/dist/generate.js +40 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +6 -0
- package/dist/mysql.js +16 -0
- package/dist/nested-write.d.ts +2 -0
- package/dist/nested-write.js +415 -25
- package/dist/powdb.d.ts +4 -2
- package/dist/powdb.js +106 -21
- package/dist/powql.d.ts +5 -0
- package/dist/powql.js +42 -6
- package/dist/prisma-compat.d.ts +2 -0
- package/dist/prisma-compat.js +166 -8
- package/dist/query/aggregates.js +7 -3
- package/dist/query/builder.d.ts +292 -21
- package/dist/query/builder.js +570 -64
- package/dist/query/deferred.d.ts +39 -0
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +1 -1
- package/dist/query/relations.d.ts +173 -5
- package/dist/query/relations.js +688 -47
- package/dist/query/types.d.ts +123 -39
- package/dist/query/utils.d.ts +116 -0
- package/dist/query/utils.js +198 -0
- package/dist/query/warn-registry.d.ts +9 -0
- package/dist/query/warn-registry.js +9 -0
- package/dist/query/where.d.ts +38 -1
- package/dist/query/where.js +58 -23
- package/dist/query/writes.d.ts +42 -1
- package/dist/query/writes.js +104 -13
- package/dist/schema-sql.d.ts +14 -0
- package/dist/schema-sql.js +23 -5
- package/dist/schema.d.ts +38 -0
- package/dist/schema.js +123 -0
- package/dist/sqlite.js +4 -0
- package/package.json +77 -28
package/dist/query/builder.d.ts
CHANGED
|
@@ -13,6 +13,71 @@
|
|
|
13
13
|
import type pg from 'pg';
|
|
14
14
|
import type { SchemaMetadata } from '../schema.js';
|
|
15
15
|
import type { AggregateArgs, AggregateResult, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, GroupByResult, QueryResult, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs, WithClause } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Marginal cost of keeping a to-one relation on the JOIN plan, per parent row.
|
|
18
|
+
*
|
|
19
|
+
* A to-one relation compiled into the join plan is a CORRELATED subquery: the
|
|
20
|
+
* engine re-evaluates it once per parent row, so the join plan costs roughly
|
|
21
|
+
* `AUTO_JOIN_PENALTY_MS_PER_ROW * parentRows` more CPU than one flat follow-up
|
|
22
|
+
* query, no matter how well indexed the correlation column is. The batched plan
|
|
23
|
+
* pays that back as a second statement, i.e. one extra round trip.
|
|
24
|
+
*
|
|
25
|
+
* Break-even is therefore, to a first approximation:
|
|
26
|
+
*
|
|
27
|
+
* parentRows = roundTripMs / AUTO_JOIN_PENALTY_MS_PER_ROW
|
|
28
|
+
*
|
|
29
|
+
* Measured (PostgreSQL 17, hasOne over a UNIQUE FK, 10K-row parent table,
|
|
30
|
+
* median of 15 reps per point) at two very different link speeds:
|
|
31
|
+
*
|
|
32
|
+
* link RTT penalty/row break-even observed crossover
|
|
33
|
+
* ─────────────────── ──────── ───────────── ──────────── ──────────────────
|
|
34
|
+
* loopback TCP 0.118ms 0.000711ms ~166-236 between 200 and 400
|
|
35
|
+
* +1ms/direction 2.683ms 0.000717ms ~3744-3993 between 3000 and 5000
|
|
36
|
+
*
|
|
37
|
+
* The two things that matters most in that table: the per-row penalty is
|
|
38
|
+
* essentially IDENTICAL across the two links (it is a property of the plan, not
|
|
39
|
+
* the wire), while the break-even moved by 17x. So the break-even is a function
|
|
40
|
+
* of the deployment's round-trip time and NOTHING ELSE that is knowable at plan
|
|
41
|
+
* time. That is why this is expressed as a per-row cost and a round-trip time
|
|
42
|
+
* rather than as a hard-coded row count: a row count tuned on a Unix socket is
|
|
43
|
+
* off by ~20x for a cross-region deployment, and vice versa. Concretely, the
|
|
44
|
+
* previously shipped flat `1000` was simultaneously too HIGH on loopback
|
|
45
|
+
* (up to 1.44x slower than the better plan just under the cliff) and too LOW
|
|
46
|
+
* over a 2.7ms link (1.26x slower just above it).
|
|
47
|
+
*/
|
|
48
|
+
export declare const AUTO_JOIN_PENALTY_MS_PER_ROW = 0.0007;
|
|
49
|
+
/**
|
|
50
|
+
* Round-trip time assumed before this process has observed a real one, chosen
|
|
51
|
+
* as a typical same-region managed-Postgres latency (app and database in one
|
|
52
|
+
* region over TCP). It is stated as a LATENCY rather than a row count so the
|
|
53
|
+
* assumption is visible and re-derivable: at
|
|
54
|
+
* {@link AUTO_JOIN_PENALTY_MS_PER_ROW} it yields exactly the 1000-row default
|
|
55
|
+
* this heuristic has always shipped, so an unmeasured process behaves exactly
|
|
56
|
+
* as before.
|
|
57
|
+
*/
|
|
58
|
+
export declare const AUTO_ASSUMED_ROUND_TRIP_MS = 0.7;
|
|
59
|
+
/**
|
|
60
|
+
* Default parent-row ceiling under which `'auto'` keeps a to-one relation on
|
|
61
|
+
* the single-statement join plan: {@link AUTO_ASSUMED_ROUND_TRIP_MS} divided by
|
|
62
|
+
* {@link AUTO_JOIN_PENALTY_MS_PER_ROW}. Used until the process has measured its
|
|
63
|
+
* own round-trip time, and whenever measurement is unavailable.
|
|
64
|
+
*/
|
|
65
|
+
export declare const AUTO_TO_ONE_JOIN_MAX_ROWS: number;
|
|
66
|
+
/**
|
|
67
|
+
* Clamps on the MEASURED threshold (an explicit `autoToOneJoinMaxRows` is an
|
|
68
|
+
* instruction, not an estimate, and bypasses both).
|
|
69
|
+
*
|
|
70
|
+
* The lower clamp matters: on a very fast link the formula can drop the
|
|
71
|
+
* threshold to a few dozen rows, and the sweep shows the join plan winning by
|
|
72
|
+
* up to 1.83x on a handful of parent rows, where the second statement's fixed
|
|
73
|
+
* cost dwarfs everything. Holding the floor at 100 rows keeps those small
|
|
74
|
+
* queries on the join plan; the cost of doing so, in the band where batched has
|
|
75
|
+
* just started to win, is under 1.2x. The upper clamp is a sanity bound for a
|
|
76
|
+
* pathological latency reading (a 70ms measurement would otherwise ask for
|
|
77
|
+
* 100K rows).
|
|
78
|
+
*/
|
|
79
|
+
export declare const AUTO_TO_ONE_JOIN_ROWS_MIN = 100;
|
|
80
|
+
export declare const AUTO_TO_ONE_JOIN_ROWS_MAX = 100000;
|
|
16
81
|
export type { DeferredQuery, MiddlewareFn, QueryEvent, QueryEventListener, QueryInterfaceOptions, ReselectExecutor, } from './deferred.js';
|
|
17
82
|
import type { DeferredQuery, MiddlewareFn, QueryInterfaceOptions } from './deferred.js';
|
|
18
83
|
export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
@@ -57,6 +122,23 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
57
122
|
private readonly relationLoadStrategy;
|
|
58
123
|
/** Client-level default for {@link applyStableRelationOrder} (off unless configured). */
|
|
59
124
|
private readonly stableRelationOrder;
|
|
125
|
+
/**
|
|
126
|
+
* Client-level opt-in: apply an implicit primary-key ascending `ORDER BY` to a
|
|
127
|
+
* `findMany` that paginates (`limit`/`take`/`offset`) but declares no
|
|
128
|
+
* `orderBy`. OFF by default in core, see {@link applyImplicitPkOrdering}.
|
|
129
|
+
*/
|
|
130
|
+
private readonly implicitPkOrdering;
|
|
131
|
+
/**
|
|
132
|
+
* Explicitly configured parent-row ceiling for the `'auto'` to-one rule, or
|
|
133
|
+
* `undefined` to derive it from the observed round-trip time. See
|
|
134
|
+
* {@link autoToOneThreshold}.
|
|
135
|
+
*/
|
|
136
|
+
private readonly autoToOneJoinMaxRowsOption;
|
|
137
|
+
/**
|
|
138
|
+
* Deployment round-trip time in milliseconds, from which the to-one threshold
|
|
139
|
+
* is derived. See {@link autoToOneThreshold}.
|
|
140
|
+
*/
|
|
141
|
+
private readonly autoRoundTripMs;
|
|
60
142
|
/** Nested-relation JSON encoding: 'object' (default) or 'positional'. */
|
|
61
143
|
private readonly jsonEncoding;
|
|
62
144
|
/**
|
|
@@ -169,11 +251,23 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
169
251
|
* ROWS ONLY`. No params are pushed, so the collect path is unaffected.
|
|
170
252
|
*/
|
|
171
253
|
private limitOneClause;
|
|
254
|
+
/**
|
|
255
|
+
* Coerce a LIMIT/OFFSET argument and validate it as a non-negative safe
|
|
256
|
+
* integer. Numeric strings (`'5'`) coerce; everything else (`NaN`, a
|
|
257
|
+
* non-numeric string, a negative, a fractional or out-of-safe-range number)
|
|
258
|
+
* throws {@link ValidationError} (E003) naming the argument and the table.
|
|
259
|
+
*
|
|
260
|
+
* This runs on EVERY pagination path, parameterized as well as inlined: a
|
|
261
|
+
* bound `NaN` serializes as SQL NULL, and Postgres reads `LIMIT NULL` as
|
|
262
|
+
* "no limit", so an unvalidated value silently turns a paginated query into
|
|
263
|
+
* a full-table read (and a bad OFFSET silently disappears).
|
|
264
|
+
*/
|
|
265
|
+
private paginationValue;
|
|
172
266
|
/**
|
|
173
267
|
* Validate a LIMIT/OFFSET value as a non-negative integer and return it as an
|
|
174
268
|
* inline SQL literal. Used only on `dialect.inlineLimitOffset` engines (MySQL).
|
|
175
269
|
* The input is always a Turbine-controlled pagination value, never a raw user
|
|
176
|
-
* string
|
|
270
|
+
* string, and this guard guarantees the output is `String` of a validated
|
|
177
271
|
* integer, so inlining cannot inject SQL.
|
|
178
272
|
*/
|
|
179
273
|
private limitOffsetLiteral;
|
|
@@ -216,6 +310,97 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
216
310
|
* nothing stable to order by, so both are left untouched.
|
|
217
311
|
*/
|
|
218
312
|
private applyStableRelationOrder;
|
|
313
|
+
/**
|
|
314
|
+
* The primary key of this table as an ascending `orderBy`, in DECLARATION
|
|
315
|
+
* order (a composite PK orders on every column), or `undefined` for a PK-less
|
|
316
|
+
* table. Field names are the camelCase accessor names, so the emitted SQL goes
|
|
317
|
+
* through the normal column mapping.
|
|
318
|
+
*/
|
|
319
|
+
private pkOrderBy;
|
|
320
|
+
/**
|
|
321
|
+
* The field names a `cursor` actually seeks on (its own keys with a defined
|
|
322
|
+
* value), in the canonical sorted order the cursor conditions are built in.
|
|
323
|
+
* Empty for a missing cursor or one whose every value is `undefined` (which
|
|
324
|
+
* emits no seek condition at all, so it does not paginate).
|
|
325
|
+
*/
|
|
326
|
+
private cursorFields;
|
|
327
|
+
/**
|
|
328
|
+
* The ascending ordering implied by a `cursor`, or `undefined` when the shape
|
|
329
|
+
* is too ambiguous to order safely.
|
|
330
|
+
*
|
|
331
|
+
* A cursor seek emits `col > $n` per field (`<` when the orderBy says desc),
|
|
332
|
+
* so the ONLY ordering coherent with it is on the cursor's own field: ordering
|
|
333
|
+
* a seek on column X by column Y walks the table in an order the seek does not
|
|
334
|
+
* follow, which skips and repeats rows just as badly as no order at all. That
|
|
335
|
+
* is why this orders on the cursor field rather than blindly on the primary
|
|
336
|
+
* key when the two differ.
|
|
337
|
+
*
|
|
338
|
+
* Returns `undefined` (warn, inject nothing) for two shapes:
|
|
339
|
+
* - a MULTI-field cursor. `a > $1 AND b > $2` is a conjunction, not a proper
|
|
340
|
+
* composite keyset seek (`(a, b) > ($1, $2)`), so no single ORDER BY makes
|
|
341
|
+
* it correct. Injecting `(a asc, b asc)` would dress a broken seek up as a
|
|
342
|
+
* sound one.
|
|
343
|
+
* - a field that does not resolve to a real column. Column validation belongs
|
|
344
|
+
* to the normal build path, which raises a precise error; synthesizing an
|
|
345
|
+
* ORDER BY on it here would only change which error the caller sees.
|
|
346
|
+
*/
|
|
347
|
+
private cursorOrderBy;
|
|
348
|
+
/**
|
|
349
|
+
* Whether a findMany paginates (`limit` / `take` / `offset` / `cursor`) but
|
|
350
|
+
* declares no ordering, which makes the returned page NON-DETERMINISTIC:
|
|
351
|
+
* Postgres is free to return different rows for the same unordered `LIMIT`
|
|
352
|
+
* once the heap changes underneath it, so a row can appear on two pages or on
|
|
353
|
+
* none.
|
|
354
|
+
*
|
|
355
|
+
* `cursor` counts, and is the worst case rather than an exception: a keyset
|
|
356
|
+
* seek with no ORDER BY is exactly this bug (`WHERE id > $1 LIMIT $2` walks
|
|
357
|
+
* the heap in whatever order the plan happens to produce). An empty orderBy
|
|
358
|
+
* (`[]`, or an object whose every value is `undefined`) counts as absent,
|
|
359
|
+
* because it emits no ordering.
|
|
360
|
+
*
|
|
361
|
+
* `distinct` is still excluded: that path re-orders in an outer wrapper around
|
|
362
|
+
* a `DISTINCT ON` whose ordering picks the representative row, so an implicit
|
|
363
|
+
* key would change which rows come back, not just their order.
|
|
364
|
+
*/
|
|
365
|
+
private isUnorderedPage;
|
|
366
|
+
/**
|
|
367
|
+
* Opt-in (`implicitPkOrdering`) primary-key ascending ordering for a paginating
|
|
368
|
+
* findMany that declares no `orderBy`, making its pages deterministic.
|
|
369
|
+
*
|
|
370
|
+
* OFF by default in CORE, deliberately: turning it on would add an `ORDER BY`
|
|
371
|
+
* to SQL that existing applications already emit, changing both the rows a
|
|
372
|
+
* given page returns and the plan the engine picks. That is a breaking change
|
|
373
|
+
* in everything but the type signature, so it waits for a major. The
|
|
374
|
+
* `turbine-orm/prisma-compat` layer defaults it ON instead, because reproducing
|
|
375
|
+
* Prisma's semantics is that layer's whole contract.
|
|
376
|
+
*
|
|
377
|
+
* An explicit `orderBy` always wins, a PK-less table is left alone (nothing
|
|
378
|
+
* stable to order by), and a composite PK orders on every column in
|
|
379
|
+
* declaration order. A `cursor` query orders on the CURSOR's field instead
|
|
380
|
+
* (see {@link cursorOrderBy}), and is left alone when that shape is ambiguous.
|
|
381
|
+
* `distinct` shapes are skipped (see {@link isUnorderedPage}). With the flag
|
|
382
|
+
* off this returns `undefined` before touching anything, so the emitted SQL is
|
|
383
|
+
* byte-identical to before.
|
|
384
|
+
*/
|
|
385
|
+
private implicitPkOrderBy;
|
|
386
|
+
/**
|
|
387
|
+
* Dev-only, once per query shape: an unordered paginating findMany returns a
|
|
388
|
+
* non-deterministic page (see {@link isUnorderedPage}), and on real data it is
|
|
389
|
+
* also usually the slower plan (an unordered `LIMIT` can discard tens of
|
|
390
|
+
* thousands of heap rows that an index scan on the key would have skipped).
|
|
391
|
+
*
|
|
392
|
+
* Gated exactly like the other dev diagnostics (silent under
|
|
393
|
+
* `NODE_ENV=production`) and consistent with `warnOnUnlimited`: a per-call
|
|
394
|
+
* `warnOnUnlimited: false` silences it, `true` forces it past a config-level
|
|
395
|
+
* opt-out, and a config/per-table `warnOnUnlimited: false` silences it. Deduped
|
|
396
|
+
* process-wide through the shared warn registry, so it can never spam.
|
|
397
|
+
*
|
|
398
|
+
* Suppressed only when `implicitPkOrdering` will ACTUALLY order this query.
|
|
399
|
+
* The flag being on is not enough: a PK-less table and an ambiguous
|
|
400
|
+
* multi-field cursor both get no injected ordering, and those are precisely
|
|
401
|
+
* the shapes that still need saying out loud.
|
|
402
|
+
*/
|
|
403
|
+
private maybeWarnUnorderedPage;
|
|
219
404
|
/**
|
|
220
405
|
* Whether a relation can be served by the batched loader, i.e. all its
|
|
221
406
|
* correlation keys are single-column (the loader throws E017 on composite
|
|
@@ -234,18 +419,63 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
234
419
|
/** The `_count` verdict under `'auto'`: any counted probe unindexed + all single-key. */
|
|
235
420
|
private autoCountVerdict;
|
|
236
421
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
422
|
+
* Whether a query's parent set is potentially large at plan time, which is the
|
|
423
|
+
* only cardinality signal available before the base query runs. A `findMany`
|
|
424
|
+
* with no `limit`/`take` (or one above {@link autoToOneJoinMaxRows}) can return
|
|
425
|
+
* an arbitrary number of parent rows; a small `limit` bounds it. `findUnique` /
|
|
426
|
+
* `findFirst` pass `false` explicitly (their parent set is one row).
|
|
427
|
+
*/
|
|
428
|
+
private autoParentSetLarge;
|
|
429
|
+
/**
|
|
430
|
+
* The parent-row count at which `'auto'` stops preferring the single-statement
|
|
431
|
+
* join for a to-one relation.
|
|
432
|
+
*
|
|
433
|
+
* Resolution order:
|
|
434
|
+
* 1. an explicit `autoToOneJoinMaxRows` — an instruction, used verbatim
|
|
435
|
+
* (no clamping: the caller has measured their own workload);
|
|
436
|
+
* 2. the configured `autoRoundTripMs` divided by
|
|
437
|
+
* {@link AUTO_JOIN_PENALTY_MS_PER_ROW}, clamped to
|
|
438
|
+
* [{@link AUTO_TO_ONE_JOIN_ROWS_MIN}, {@link AUTO_TO_ONE_JOIN_ROWS_MAX}];
|
|
439
|
+
* 3. {@link AUTO_TO_ONE_JOIN_MAX_ROWS}, which is that same division applied
|
|
440
|
+
* to {@link AUTO_ASSUMED_ROUND_TRIP_MS}.
|
|
441
|
+
*
|
|
442
|
+
* Deriving it rather than hard-coding a row count is the whole point: the
|
|
443
|
+
* sweep in {@link AUTO_JOIN_PENALTY_MS_PER_ROW} shows the break-even moving
|
|
444
|
+
* 17x between a loopback link and a 2.7ms one while the per-row penalty stays
|
|
445
|
+
* put, so any single constant is wrong for someone by more than the margin it
|
|
446
|
+
* is trying to save. Placing the switch AT the break-even is also what removes
|
|
447
|
+
* the old cliff: two plans that cost the same at the boundary make the regret
|
|
448
|
+
* there ~1.0x, rising only as the true row count moves away from it — where
|
|
449
|
+
* the previous fixed 1000 put its WORST case (1.44x measured) immediately
|
|
450
|
+
* below its own switch point.
|
|
451
|
+
*
|
|
452
|
+
* Cheap enough to recompute per call (a division and two comparisons over
|
|
453
|
+
* readonly fields), so there is no cached copy to invalidate.
|
|
454
|
+
*/
|
|
455
|
+
private autoToOneThreshold;
|
|
456
|
+
/**
|
|
457
|
+
* Partition a top-level `with` clause under `'auto'`. A relation routes to
|
|
458
|
+
* `batchedWith` when it is fully batched-eligible AND either
|
|
459
|
+
*
|
|
460
|
+
* 1. its subtree has a PROVEN unindexed probe (index metadata only), or
|
|
461
|
+
* 2. it is TO-ONE and the parent set is potentially large
|
|
462
|
+
* ({@link AUTO_TO_ONE_JOIN_MAX_ROWS}), since a correlated to-one subquery
|
|
463
|
+
* is re-evaluated per parent row no matter how well indexed it is.
|
|
464
|
+
*
|
|
465
|
+
* Everything else (indexed to-many, composite-key, unknown) stays in `joinWith`
|
|
466
|
+
* (byte-identical join). The reserved `_count` key falls back on rule 1 only,
|
|
467
|
+
* and only for a large parent set: an inline `_count` is one correlated
|
|
468
|
+
* `COUNT(*)` per parent row, so the grouped follow-up wins exactly when there
|
|
469
|
+
* are many parents, while for a handful of parents the extra round-trip costs
|
|
470
|
+
* more than the repeated (small) scans. Also returns the engaged relations for
|
|
471
|
+
* the dev note.
|
|
242
472
|
*/
|
|
243
473
|
private partitionWithForAuto;
|
|
244
474
|
/**
|
|
245
475
|
* Plan the `'auto'` split for a query's `with` clause: normalize stable order,
|
|
246
476
|
* partition, and return the split ONLY when at least one relation falls back
|
|
247
477
|
* to batched. Returns `null` (→ run the plain join path, byte-identical, same
|
|
248
|
-
* cache keys) when
|
|
478
|
+
* cache keys) when nothing qualifies.
|
|
249
479
|
*/
|
|
250
480
|
private planAuto;
|
|
251
481
|
/** Dev-only once-per-relation note that `'auto'` engaged the batched fallback. */
|
|
@@ -459,14 +689,19 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
459
689
|
* method fall back to the full cursor path.
|
|
460
690
|
*
|
|
461
691
|
* **Cursor path:** Uses DECLARE CURSOR within a dedicated transaction on a
|
|
462
|
-
* single pooled connection. The cursor is
|
|
463
|
-
* connection released when iteration completes
|
|
464
|
-
* (
|
|
692
|
+
* single pooled connection. The cursor is CLOSEd (in the dialect's `finally`)
|
|
693
|
+
* and the connection released both when iteration completes normally and when
|
|
694
|
+
* it ends early (`break` from `for await`). An error mid-stream skips the
|
|
695
|
+
* CLOSE and rolls back instead, which drops the cursor with the transaction.
|
|
465
696
|
*
|
|
466
|
-
* **Snapshot semantics note:**
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
697
|
+
* **Snapshot semantics note:** Outside a transaction the speculative
|
|
698
|
+
* fast-path runs unwrapped, and an overflow opens the cursor in its own
|
|
699
|
+
* transaction, so the two fetches span two separate snapshots. Wrapping the
|
|
700
|
+
* call in `$transaction` gives strict single-snapshot semantics: both the
|
|
701
|
+
* speculative fetch and the cursor then run on the caller's connection
|
|
702
|
+
* inside the caller's transaction (the cursor path issues no BEGIN/COMMIT of
|
|
703
|
+
* its own and releases nothing, so the caller's transaction is intact when
|
|
704
|
+
* iteration finishes).
|
|
470
705
|
*
|
|
471
706
|
* @example
|
|
472
707
|
* ```ts
|
|
@@ -490,15 +725,15 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
490
725
|
private runInImplicitTx;
|
|
491
726
|
private buildNestedCtx;
|
|
492
727
|
private makeTxProxy;
|
|
493
|
-
delete(args: DeleteArgs<T>): Promise<T>;
|
|
494
|
-
upsert(args: UpsertArgs<T>): Promise<T>;
|
|
495
|
-
updateMany(args: UpdateManyArgs<T>): Promise<{
|
|
728
|
+
delete(args: DeleteArgs<T, R>): Promise<T>;
|
|
729
|
+
upsert(args: UpsertArgs<T, R>): Promise<T>;
|
|
730
|
+
updateMany(args: UpdateManyArgs<T, R>): Promise<{
|
|
496
731
|
count: number;
|
|
497
732
|
}>;
|
|
498
|
-
deleteMany(args: DeleteManyArgs<T>): Promise<{
|
|
733
|
+
deleteMany(args: DeleteManyArgs<T, R>): Promise<{
|
|
499
734
|
count: number;
|
|
500
735
|
}>;
|
|
501
|
-
count(args?: CountArgs<T>): Promise<number>;
|
|
736
|
+
count(args?: CountArgs<T, R>): Promise<number>;
|
|
502
737
|
buildCount(args?: CountArgs<T>): DeferredQuery<number>;
|
|
503
738
|
/**
|
|
504
739
|
* Group rows and compute per-group aggregates (Prisma-style). The result row
|
|
@@ -508,10 +743,10 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
508
743
|
* {@link GroupByResult}). Grouping by a JSON-path key yields a runtime alias
|
|
509
744
|
* that cannot be typed, so those columns are not projected onto the row type.
|
|
510
745
|
*/
|
|
511
|
-
groupBy<A extends GroupByArgs<T>>(args: A): Promise<GroupByResult<T, A>[]>;
|
|
746
|
+
groupBy<A extends GroupByArgs<T, R>>(args: A): Promise<GroupByResult<T, A>[]>;
|
|
512
747
|
buildGroupBy(args: GroupByArgs<T>): DeferredQuery<Record<string, unknown>[]>;
|
|
513
748
|
buildAggregate(args: AggregateArgs<T>): DeferredQuery<AggregateResult<T>>;
|
|
514
|
-
aggregate(args: AggregateArgs<T>): Promise<AggregateResult<T>>;
|
|
749
|
+
aggregate(args: AggregateArgs<T, R>): Promise<AggregateResult<T>>;
|
|
515
750
|
private resolveColumns;
|
|
516
751
|
withFingerprint(withClause: WithClause | undefined, table?: string, depth?: number): string;
|
|
517
752
|
private collectWithParams;
|
|
@@ -527,6 +762,42 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
527
762
|
private getCamelDateFields;
|
|
528
763
|
private makeNestedParser;
|
|
529
764
|
private buildSelectWithRelations;
|
|
765
|
+
/**
|
|
766
|
+
* Compile the `relationLoadStrategy: 'flatten'` plan for a findMany-shaped
|
|
767
|
+
* query, or `null` to emit exactly the SQL (and cache key) the default
|
|
768
|
+
* strategy emits.
|
|
769
|
+
*
|
|
770
|
+
* `'flatten'` compiles an eligible to-one relation to a `LEFT JOIN` with a
|
|
771
|
+
* prefixed scalar projection instead of a correlated `json_build_object`
|
|
772
|
+
* subquery. The correlated form is re-evaluated once per parent row, so its
|
|
773
|
+
* cost scales with the parent set no matter how well the FK is indexed; the
|
|
774
|
+
* join does not, and unlike `'batched'` it stays a single round trip.
|
|
775
|
+
*
|
|
776
|
+
* It is an EXPLICIT opt-in: `'auto'` is unchanged and never selects it.
|
|
777
|
+
*
|
|
778
|
+
* Query-shape gates (any of these routes the WHOLE query back to the default
|
|
779
|
+
* strategy, silently and byte-identically):
|
|
780
|
+
* - the resolved strategy is not `'flatten'`;
|
|
781
|
+
* - `jsonEncoding: 'positional'` (a flattened relation emits no JSON at all,
|
|
782
|
+
* so the two encodings are not composed in this version);
|
|
783
|
+
* - the dialect owns relation-subquery generation
|
|
784
|
+
* (`dialect.buildRelationSubquery`, i.e. SQL Server's `FOR JSON PATH`);
|
|
785
|
+
* - `distinct` (the `DISTINCT ON` rewrite re-orders in an outer wrapper, and
|
|
786
|
+
* the extra projected columns have not been proven safe there).
|
|
787
|
+
*
|
|
788
|
+
* `limit` / `offset` / `cursor` / `orderBy` need no gate: every flattened join
|
|
789
|
+
* is over a PROVABLY UNIQUE target key, so it matches at most one row per
|
|
790
|
+
* parent and cannot change the parent row count that pagination applies to.
|
|
791
|
+
*
|
|
792
|
+
* Per-relation eligibility lives in `planFlattenWith` / `planFlattenNode`.
|
|
793
|
+
* Only the findMany family is planned (`findMany`, `findFirst`,
|
|
794
|
+
* `findManyStream`, and pipelined `buildFindMany`); `findUnique` reads a single
|
|
795
|
+
* parent row, where the correlated subquery runs exactly once, so it stays on
|
|
796
|
+
* the default path.
|
|
797
|
+
*/
|
|
798
|
+
private planFlatten;
|
|
799
|
+
/** Dev-only once-only note that `'flatten'` was refused for the whole query. */
|
|
800
|
+
private warnFlattenBlocked;
|
|
530
801
|
/** Convert camelCase field name to snake_case column name (unquoted, for non-SQL uses) */
|
|
531
802
|
private toColumn;
|
|
532
803
|
/** Convert camelCase field name to a double-quoted SQL identifier */
|