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
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm: aggregate / groupBy compilation (extracted from builder.ts)
|
|
3
|
+
*
|
|
4
|
+
* buildAggregate + buildGroupBy and their helpers (HAVING clauses, groupBy
|
|
5
|
+
* ordering, DISTINCT-ON sources, JSON-path aggregate targets). All functions
|
|
6
|
+
* take a {@link BuilderCtx} first argument; WHERE compilation is reused from
|
|
7
|
+
* where.ts (via `whereMod`), and the shared orderBy / row-parse primitives
|
|
8
|
+
* stay class-resident, reached through the ctx. See builder.ts for the thin
|
|
9
|
+
* delegating methods (buildGroupBy / buildAggregate).
|
|
10
|
+
*/
|
|
11
|
+
import type { TableMetadata } from '../schema.js';
|
|
12
|
+
import type { DeferredQuery } from './deferred.js';
|
|
13
|
+
import type { AggregateArgs, AggregateResult, GroupByArgs, GroupByOrderBy, HavingClause, HavingFilter } from './types.js';
|
|
14
|
+
import type { BuilderCtx } from './where.js';
|
|
15
|
+
/**
|
|
16
|
+
* Enforce the PII contract on the aggregate surface. A PII-tagged
|
|
17
|
+
* (`defineSchema` `pii: true`) column is excluded from every default
|
|
18
|
+
* projection, and a value-returning aggregate is a projection by another name:
|
|
19
|
+
* `groupBy({ by: ['email'] })` emits one row per distinct plaintext email, and
|
|
20
|
+
* `_min`/`_max` return a stored cell verbatim. Both therefore REQUIRE the same
|
|
21
|
+
* `includePii: true` opt-in reads use.
|
|
22
|
+
*
|
|
23
|
+
* Deliberately NOT gated: `_count` (a count, never a value), `_sum` / `_avg`
|
|
24
|
+
* (a computed total across many rows, not a stored cell), and `where` /
|
|
25
|
+
* `orderBy` / `having` on PII columns (they return no values at all). Untagged
|
|
26
|
+
* schemas short-circuit on the `pii` lookup, so their SQL is byte-identical.
|
|
27
|
+
*
|
|
28
|
+
* Shared with the PowQL aggregate paths (src/powql.ts) so every engine applies
|
|
29
|
+
* one policy.
|
|
30
|
+
*/
|
|
31
|
+
export declare function assertAggregatePiiOptIn(table: string, meta: TableMetadata | undefined, field: string, column: string, usage: string, includePii: boolean | undefined): void;
|
|
32
|
+
export declare function buildGroupBy<T extends object>(qi: BuilderCtx, args: GroupByArgs<T>): DeferredQuery<Record<string, unknown>[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Compile a groupBy `orderBy` into an ORDER BY body. Unlike findMany ORDER BY
|
|
35
|
+
* ({@link buildOrderBy}, which validates keys against the table's physical
|
|
36
|
+
* columns), groupBy ordering targets the columns the RESULT actually
|
|
37
|
+
* contains: plain by-fields, JSON group-key aliases, and requested aggregates
|
|
38
|
+
* (`_count` / `_sum` / `_avg` / `_min` / `_max`). Each key re-emits the exact
|
|
39
|
+
* SELECT expression that produced it (`byOrderExprs` / `aggOrderExprs`),
|
|
40
|
+
* mirroring how HAVING re-emits aggregate expressions, so no dialect ever has
|
|
41
|
+
* to accept a SELECT-alias reference in ORDER BY, and any already-bound
|
|
42
|
+
* JSON-path placeholder is reused verbatim (ORDER BY is the last clause, so
|
|
43
|
+
* no `$n` renumbering). An aggregate key that was not requested, or an unknown
|
|
44
|
+
* by-key, throws {@link ValidationError} E003 listing the valid keys.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildGroupByOrderBy(qi: BuilderCtx, orderBy: GroupByOrderBy | GroupByOrderBy[], byOrderExprs: Map<string, string>, aggOrderExprs: Map<string, string>): string;
|
|
47
|
+
/**
|
|
48
|
+
* Validate a JSON-path target (group key or aggregate target) in groupBy:
|
|
49
|
+
* the field must resolve to a real json/jsonb column and the path must be a
|
|
50
|
+
* non-empty array of keys/indexes. Returns the resolved snake_case column.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveJsonPathTarget(qi: BuilderCtx, context: string, field: string, path: (string | number)[]): string;
|
|
53
|
+
/**
|
|
54
|
+
* Build the `distinctOn` row source for groupBy (PostgreSQL only: other
|
|
55
|
+
* engines throw {@link UnsupportedFeatureError} E017):
|
|
56
|
+
*
|
|
57
|
+
* ```sql
|
|
58
|
+
* (SELECT DISTINCT ON ("c1") * FROM "table"<WHERE> ORDER BY "c1", <orderBy>) AS "table"
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* The wrapper is aliased as the table name so every outer expression (group
|
|
62
|
+
* keys, aggregates, HAVING, ORDER BY) is byte-identical to the plain path.
|
|
63
|
+
* `distinctOn.orderBy` is required (it decides which row survives) and
|
|
64
|
+
* supports plain columns, {@link OrderBySpec} nulls, and JSON-path specs;
|
|
65
|
+
* JSON paths push their text[] param here, after the WHERE params.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildDistinctOnSource<T extends object>(qi: BuilderCtx, distinctOn: NonNullable<GroupByArgs<T>['distinctOn']>, whereSql: string, params: unknown[]): string;
|
|
68
|
+
/**
|
|
69
|
+
* Build the SQL fragments for a {@link HavingClause}.
|
|
70
|
+
*
|
|
71
|
+
* Each aggregate expression (`COUNT(*)`, `SUM("col")`, etc.) is constructed
|
|
72
|
+
* from a **schema-validated, quoted** column identifier: `qi.toColumn()`
|
|
73
|
+
* throws {@link ValidationError} for unknown fields and `qi.q()` quotes via
|
|
74
|
+
* the dialect, so no unvalidated identifier ever reaches the SQL string. Every
|
|
75
|
+
* comparison value is pushed onto the shared `params` array and referenced by
|
|
76
|
+
* a `$N` placeholder via {@link buildHavingNumericClauses} — there is no string
|
|
77
|
+
* interpolation of user values.
|
|
78
|
+
*
|
|
79
|
+
* `jsonAggExprs` (from {@link buildGroupBy}) maps `alias:aggKey` to the
|
|
80
|
+
* exact aggregate expression a JSON-path aggregate emitted in SELECT
|
|
81
|
+
* (including its already-bound path placeholder), so HAVING on a JSON-path
|
|
82
|
+
* aggregate alias reuses the same expression instead of resolving the alias
|
|
83
|
+
* as a column.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildHavingClauses<T extends object>(qi: BuilderCtx, having: HavingClause<T>, params: unknown[], jsonAggExprs?: Map<string, string>): string[];
|
|
86
|
+
/**
|
|
87
|
+
* Convert a single having filter into one or more parameterized SQL
|
|
88
|
+
* comparisons against the given aggregate expression. A bare number is
|
|
89
|
+
* shorthand for equality. Unknown operator keys throw {@link ValidationError}.
|
|
90
|
+
*/
|
|
91
|
+
export declare function buildHavingNumericClauses(qi: BuilderCtx, expr: string, filter: HavingFilter, params: unknown[]): string[];
|
|
92
|
+
export declare function buildAggregate<T extends object>(qi: BuilderCtx, args: AggregateArgs<T>): DeferredQuery<AggregateResult<T>>;
|
|
@@ -54,6 +54,7 @@ exports.buildAggregate = buildAggregate;
|
|
|
54
54
|
const errors_js_1 = require("../errors.js");
|
|
55
55
|
const schema_js_1 = require("../schema.js");
|
|
56
56
|
const filters_js_1 = require("./filters.js");
|
|
57
|
+
const utils_js_1 = require("./utils.js");
|
|
57
58
|
const whereMod = __importStar(require("./where.js"));
|
|
58
59
|
/**
|
|
59
60
|
* Enforce the PII contract on the aggregate surface. A PII-tagged
|
|
@@ -275,8 +276,8 @@ function buildGroupBy(qi, args) {
|
|
|
275
276
|
// no `$n` renumbering. `offset` without a deterministic `orderBy` yields an
|
|
276
277
|
// arbitrary window (same caveat as findMany).
|
|
277
278
|
if (args.limit !== undefined || args.offset !== undefined) {
|
|
278
|
-
const limitPh = args.limit !== undefined ? qi.paginationRef(args.limit, params) : undefined;
|
|
279
|
-
const offsetPh = args.offset !== undefined ? qi.paginationRef(args.offset, params) : undefined;
|
|
279
|
+
const limitPh = args.limit !== undefined ? qi.paginationRef(args.limit, params, 'limit') : undefined;
|
|
280
|
+
const offsetPh = args.offset !== undefined ? qi.paginationRef(args.offset, params, 'skip/offset') : undefined;
|
|
280
281
|
sql += qi.buildPagination(limitPh, offsetPh, args.orderBy !== undefined);
|
|
281
282
|
}
|
|
282
283
|
return {
|
|
@@ -556,7 +557,10 @@ function buildHavingClauses(qi, having, params, jsonAggExprs) {
|
|
|
556
557
|
for (const [aggKey, filter] of Object.entries(value)) {
|
|
557
558
|
if (filter === undefined)
|
|
558
559
|
continue;
|
|
559
|
-
|
|
560
|
+
// ownLookup, not a bare index: an inherited Object.prototype member
|
|
561
|
+
// ("constructor", "toString", …) would otherwise resolve to a truthy
|
|
562
|
+
// builtin and be spliced into the HAVING clause as its source text.
|
|
563
|
+
const fn = (0, utils_js_1.ownLookup)(aggFnByKey, aggKey);
|
|
560
564
|
if (!fn) {
|
|
561
565
|
throw new errors_js_1.ValidationError(`[turbine] Unknown aggregate "${aggKey}" in having for field "${key}" on table "${qi.table}". ` +
|
|
562
566
|
`Supported: ${Object.keys(aggFnByKey).join(', ')}.`);
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm — Batched relation loader (the `relationLoadStrategy: 'batched'` path)
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* Turbine's default `with`-clause strategy resolves nested relations in ONE SQL
|
|
7
|
+
* statement using correlated `json_agg(json_build_object(...))` subqueries — one
|
|
8
|
+
* probe per parent row (see `buildRelationSubquery` in builder.ts). That is the
|
|
9
|
+
* right default: a single round-trip, and when the child FK columns are indexed
|
|
10
|
+
* each probe is an index seek. But it degrades in two situations:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Missing FK index** — a correlated probe per parent row becomes
|
|
13
|
+
* N-parents × full-table-scan. A batched-loader ORM pays that missing index
|
|
14
|
+
* only ONCE (a single `WHERE fk = ANY($1)` seq-scan), which is why schemas
|
|
15
|
+
* migrated from those ORMs often lack the index the json_agg path needs.
|
|
16
|
+
* 2. **Huge unpaginated result sets** — the JSON wire format
|
|
17
|
+
* (`json_build_object` per row, re-serialized inside `json_agg`) is heavy to
|
|
18
|
+
* encode/decode compared with flat rows.
|
|
19
|
+
*
|
|
20
|
+
* This module implements the alternative, opt-in strategy: run the base query
|
|
21
|
+
* WITHOUT relation subqueries, collect the parent keys, then issue ONE flat
|
|
22
|
+
* follow-up query per relation (`SELECT ... FROM child WHERE fk = ANY($1)`),
|
|
23
|
+
* and stitch the children onto the parents in memory. D relation levels cost D
|
|
24
|
+
* extra round-trips instead of one, but each is a single indexed lookup over a
|
|
25
|
+
* key set, and rows come back flat.
|
|
26
|
+
*
|
|
27
|
+
* ## Design constraints (see CLAUDE.md)
|
|
28
|
+
*
|
|
29
|
+
* - **Same executor / connection path.** Every follow-up query runs through the
|
|
30
|
+
* caller's own executor ({@link RelationLoadContext.exec}) and child query
|
|
31
|
+
* interfaces built on the caller's pool. Inside a `$transaction` that pool is
|
|
32
|
+
* the pinned-connection `txPool`, so batched loads join the transaction — no
|
|
33
|
+
* separate pool checkout per query.
|
|
34
|
+
* - **Identical output shape.** The stitched result is byte-for-byte the same
|
|
35
|
+
* shape the join strategy produces: relation arrays for hasMany/manyToMany
|
|
36
|
+
* (`[]` when empty), single-or-null for hasOne/belongsTo, with the same
|
|
37
|
+
* camelCase keys and Date coercion — because the child rows are parsed by the
|
|
38
|
+
* very same `parseRow`/`buildFindMany` machinery via a child QueryInterface.
|
|
39
|
+
* - **Stitch keys never leak.** To stitch, the follow-up query must select the
|
|
40
|
+
* FK/PK it joins on even when the caller's `select`/`omit` excluded it; the
|
|
41
|
+
* loader adds those columns for the query and strips them from the returned
|
|
42
|
+
* entities afterwards ({@link includeKeysForBatching}).
|
|
43
|
+
*
|
|
44
|
+
* PowDB (powql.ts) has its own batched loaders for the same reasons — this is the
|
|
45
|
+
* clean Postgres/SQL implementation, deliberately NOT shared with PowQL.
|
|
46
|
+
*
|
|
47
|
+
* @module
|
|
48
|
+
*/
|
|
49
|
+
import type pg from 'pg';
|
|
50
|
+
import { type RelationDef, type SchemaMetadata, type TableMetadata } from '../schema.js';
|
|
51
|
+
import type { ReselectExecutor } from './builder.js';
|
|
52
|
+
import type { SkipGlobalFilters, WithClause, WithCount } from './types.js';
|
|
53
|
+
/**
|
|
54
|
+
* A DeferredQuery, minimally typed for what the loader consumes. Kept local to
|
|
55
|
+
* avoid a value import of builder.ts (which imports this module).
|
|
56
|
+
*/
|
|
57
|
+
interface Deferred {
|
|
58
|
+
sql: string;
|
|
59
|
+
params: unknown[];
|
|
60
|
+
preparedName?: string;
|
|
61
|
+
transform: (result: pg.QueryResult) => unknown;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The read surface the loader needs from a child QueryInterface: build (but do
|
|
65
|
+
* not execute) a flat findMany. The loader runs the built SQL through
|
|
66
|
+
* {@link RelationLoadContext.exec}, so execution stays on the caller's connection.
|
|
67
|
+
*/
|
|
68
|
+
export interface BatchedChildReader {
|
|
69
|
+
buildFindMany(args: Record<string, unknown>): Deferred;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Everything the loader needs from the owning QueryInterface, passed as closures
|
|
73
|
+
* so this module never imports builder.ts at runtime (it is imported BY it).
|
|
74
|
+
*/
|
|
75
|
+
export interface RelationLoadContext {
|
|
76
|
+
/** Metadata of the table whose rows are the current `parents`. */
|
|
77
|
+
parentMeta: TableMetadata;
|
|
78
|
+
schema: SchemaMetadata;
|
|
79
|
+
/** Build a child reader for `table`, bound to the caller's pool (tx-safe). */
|
|
80
|
+
makeChild: (table: string) => BatchedChildReader;
|
|
81
|
+
/** Run raw SQL through the caller's executor (same timeout/instrumentation path). */
|
|
82
|
+
exec: ReselectExecutor;
|
|
83
|
+
/** Quote an identifier via the active dialect. */
|
|
84
|
+
quote: (name: string) => string;
|
|
85
|
+
/** Build an `IN`/`ANY` predicate via the active dialect (PG: `expr = ANY($n)`). */
|
|
86
|
+
buildInClause: (expr: string, paramRef: string, negated: boolean) => string;
|
|
87
|
+
/** The single bound value for an `IN` list (PG: the array as-is). */
|
|
88
|
+
inClauseParam: (values: unknown[]) => unknown;
|
|
89
|
+
/** Placeholder for a 1-indexed parameter position (PG: `$n`). */
|
|
90
|
+
paramPlaceholder: (index: number) => string;
|
|
91
|
+
/**
|
|
92
|
+
* The query's `skipGlobalFilters` opt-out, threaded onto every child
|
|
93
|
+
* `buildFindMany` so relation row loads honor (or skip) the target table's
|
|
94
|
+
* global filter exactly as the join strategy would.
|
|
95
|
+
*/
|
|
96
|
+
skipGlobalFilters?: SkipGlobalFilters;
|
|
97
|
+
/**
|
|
98
|
+
* The query's `includePii` opt-in, threaded onto every child `buildFindMany`
|
|
99
|
+
* so a batched relation load excludes (or includes) PII-tagged columns exactly
|
|
100
|
+
* as the join strategy does at every nested level. Default `false`.
|
|
101
|
+
*/
|
|
102
|
+
includePii?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Render `table`'s global filter against `alias` for a raw follow-up query
|
|
105
|
+
* (the batched `_count`), numbering its `$n` placeholders AFTER
|
|
106
|
+
* `precedingParams` already-bound params. Returns `null` when no filter
|
|
107
|
+
* applies. Provided by the owning QueryInterface so this module needs no
|
|
108
|
+
* filter machinery of its own.
|
|
109
|
+
*/
|
|
110
|
+
tableGlobalFilter?: (table: string, alias: string, precedingParams: number) => {
|
|
111
|
+
clause: string;
|
|
112
|
+
params: unknown[];
|
|
113
|
+
} | null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The default projection of `meta` expressed in FIELD names: which fields the
|
|
117
|
+
* default (no `select`/`omit`) projection hides, and which it returns. Today the
|
|
118
|
+
* only hidden class is PII-tagged columns, and only when `includePii` is off.
|
|
119
|
+
*
|
|
120
|
+
* Returns `undefined` for the overwhelmingly common untagged case, so callers
|
|
121
|
+
* keep the `select: undefined, omit: undefined` fast path and the emitted SQL
|
|
122
|
+
* stays byte-identical.
|
|
123
|
+
*/
|
|
124
|
+
export declare function defaultProjectionFields(meta: TableMetadata, includePii: boolean | undefined): {
|
|
125
|
+
hidden: ReadonlySet<string>;
|
|
126
|
+
visible: string[];
|
|
127
|
+
} | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* Adjust a `select`/`omit` pair so that `fields` are guaranteed present in the
|
|
130
|
+
* query result, returning the adjusted projection plus the list of fields that
|
|
131
|
+
* were added ONLY for stitching and must be stripped from the final entities.
|
|
132
|
+
*
|
|
133
|
+
* Used both for the base query (parent keys) and each follow-up query (child
|
|
134
|
+
* keys) so a caller's `select: { title: true }` on a relation still stitches even
|
|
135
|
+
* though the FK was not requested — and the FK never appears in the output.
|
|
136
|
+
*/
|
|
137
|
+
export declare function includeKeysForBatching(select: Record<string, boolean> | undefined, omit: Record<string, boolean> | undefined, fields: string[],
|
|
138
|
+
/**
|
|
139
|
+
* The default projection for this table when it is NOT `select`/`omit`-driven:
|
|
140
|
+
* `hidden` are fields the default projection leaves out (today: PII-tagged
|
|
141
|
+
* columns without `includePii`), `visible` is everything it does return.
|
|
142
|
+
*
|
|
143
|
+
* Without this, a correlation key that is itself PII-tagged is absent from
|
|
144
|
+
* every row, the loader sees no keys, and it silently hands back empty
|
|
145
|
+
* relation arrays. Passing it turns that case into an explicit select that
|
|
146
|
+
* re-adds only the key, which is then stripped like any other stitch-only
|
|
147
|
+
* field, so no PII value ever reaches the caller.
|
|
148
|
+
*/
|
|
149
|
+
defaultProjection?: {
|
|
150
|
+
hidden: ReadonlySet<string>;
|
|
151
|
+
visible: string[];
|
|
152
|
+
}): {
|
|
153
|
+
select?: Record<string, boolean>;
|
|
154
|
+
omit?: Record<string, boolean>;
|
|
155
|
+
strip: string[];
|
|
156
|
+
};
|
|
157
|
+
/** Delete stitch-only key fields from each row (no-op when `fields` is empty). */
|
|
158
|
+
export declare function stripFields(rows: Record<string, unknown>[], fields: string[]): void;
|
|
159
|
+
/**
|
|
160
|
+
* The set of parent FIELD names a batched load of `withClause` needs present on
|
|
161
|
+
* each parent row in order to stitch (the local key of every requested relation).
|
|
162
|
+
* The caller adds these to the base query and strips the added ones afterwards.
|
|
163
|
+
*/
|
|
164
|
+
export declare function neededParentKeyFields(parentMeta: TableMetadata, withClause: WithClause): string[];
|
|
165
|
+
/**
|
|
166
|
+
* Resolve the set of to-many relations a `_count` spec selects. `true` counts
|
|
167
|
+
* every to-many relation (hasMany + manyToMany) of the table; the record form
|
|
168
|
+
* counts only the enabled names. Shared by the join builder and the batched
|
|
169
|
+
* loader so both count the exact same relations.
|
|
170
|
+
*
|
|
171
|
+
* Errors: E005 ({@link RelationError}) for an unknown relation name, E003
|
|
172
|
+
* ({@link ValidationError}) when a named relation is to-one.
|
|
173
|
+
*/
|
|
174
|
+
export declare function resolveCountRelations(parentMeta: TableMetadata, countSpec: WithCount): RelationDef[];
|
|
175
|
+
/**
|
|
176
|
+
* Reject pick-row relation ordering anywhere inside a `with` tree's orderBy —
|
|
177
|
+
* strategy parity with the join path, which throws this exact E003 at SQL
|
|
178
|
+
* build time (`pickOrderNestedError` in builder.ts). Without this guard the
|
|
179
|
+
* loaders would forward `options.orderBy` as the child reader's TOP-LEVEL
|
|
180
|
+
* findMany orderBy, where the pick shape compiles fine — so the same query
|
|
181
|
+
* would execute on 'batched' but throw on 'join'. Walks the whole tree up
|
|
182
|
+
* front so acceptance never depends on which levels have rows — the batched
|
|
183
|
+
* runners in builder.ts call this BEFORE the base query (a zero-row base
|
|
184
|
+
* result must still reject, exactly like the join strategy's build-time throw).
|
|
185
|
+
*/
|
|
186
|
+
export declare function rejectNestedPickOrder(withClause: WithClause): void;
|
|
187
|
+
/**
|
|
188
|
+
* Load every relation in `withClause` for `parents` and attach it onto each row
|
|
189
|
+
* in place. Mirrors the join strategy's output shape exactly. Recurses for nested
|
|
190
|
+
* `with` by re-running itself against the freshly-loaded child rows.
|
|
191
|
+
*/
|
|
192
|
+
export declare function loadRelationsBatched(ctx: RelationLoadContext, parents: Record<string, unknown>[], withClause: WithClause, timeout?: number, depth?: number, path?: string[]): Promise<void>;
|
|
193
|
+
export {};
|