turbine-orm 0.81.0 → 0.90.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 +26 -25
- package/dist/checkout.d.ts +27 -2
- package/dist/checkout.js +75 -4
- package/dist/cjs/checkout.d.ts +27 -2
- package/dist/cjs/checkout.js +76 -3
- package/dist/cjs/cli/code-first-tags.d.ts +62 -0
- package/dist/cjs/cli/code-first-tags.js +124 -0
- package/dist/cjs/cli/compile-query.js +9 -0
- package/dist/cjs/cli/config.d.ts +35 -6
- package/dist/cjs/cli/config.js +17 -1
- package/dist/cjs/cli/destructive.d.ts +7 -4
- package/dist/cjs/cli/destructive.js +224 -20
- package/dist/cjs/cli/error-catalog.js +36 -0
- package/dist/cjs/cli/error-text.d.ts +15 -0
- package/dist/cjs/cli/error-text.js +40 -0
- package/dist/cjs/cli/index.d.ts +62 -4
- package/dist/cjs/cli/index.js +568 -108
- package/dist/cjs/cli/local-server-guard.d.ts +53 -0
- package/dist/cjs/cli/local-server-guard.js +119 -0
- package/dist/cjs/cli/local-server-output.d.ts +41 -0
- package/dist/cjs/cli/local-server-output.js +103 -0
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +121 -32
- package/dist/cjs/cli/migrate.d.ts +113 -5
- package/dist/cjs/cli/migrate.js +270 -21
- package/dist/cjs/cli/observe.d.ts +6 -1
- package/dist/cjs/cli/observe.js +85 -55
- package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cjs/cli/pii-predicate-guard.js +98 -37
- package/dist/cjs/cli/prisma-resolve.js +17 -13
- package/dist/cjs/cli/prisma-schema.js +12 -4
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +14 -2
- package/dist/cjs/cli/studio.js +244 -69
- package/dist/cjs/cli/ui.d.ts +1 -1
- package/dist/cjs/client.d.ts +558 -85
- package/dist/cjs/client.js +1270 -395
- package/dist/cjs/connection-guard.d.ts +13 -0
- package/dist/cjs/connection-guard.js +28 -0
- package/dist/cjs/connection-url.d.ts +51 -16
- package/dist/cjs/connection-url.js +67 -34
- package/dist/cjs/diagnostics.d.ts +81 -0
- package/dist/cjs/diagnostics.js +147 -0
- package/dist/cjs/dialect.d.ts +449 -20
- package/dist/cjs/dialect.js +117 -76
- package/dist/cjs/engine-config.d.ts +7 -6
- package/dist/cjs/errors.d.ts +126 -6
- package/dist/cjs/errors.js +256 -13
- package/dist/cjs/generate.d.ts +57 -7
- package/dist/cjs/generate.js +635 -279
- package/dist/cjs/global-filters-config.d.ts +59 -0
- package/dist/cjs/global-filters-config.js +367 -0
- package/dist/cjs/index.d.ts +9 -4
- package/dist/cjs/index.js +10 -2
- package/dist/cjs/introspect.d.ts +31 -6
- package/dist/cjs/introspect.js +108 -50
- package/dist/cjs/log-codes.d.ts +12 -0
- package/dist/cjs/log-codes.js +77 -0
- package/dist/cjs/logger.d.ts +87 -0
- package/dist/cjs/logger.js +98 -0
- package/dist/cjs/mssql.d.ts +8 -5
- package/dist/cjs/mssql.js +352 -65
- package/dist/cjs/mysql.d.ts +3 -5
- package/dist/cjs/mysql.js +420 -70
- package/dist/cjs/nested-write.d.ts +3 -0
- package/dist/cjs/nested-write.js +179 -114
- package/dist/cjs/pipeline-submittable.d.ts +12 -0
- package/dist/cjs/pipeline-submittable.js +118 -44
- package/dist/cjs/pipeline.js +21 -26
- package/dist/cjs/powdb-introspect.d.ts +5 -2
- package/dist/cjs/powdb-introspect.js +20 -15
- package/dist/cjs/powdb-shared.d.ts +36 -5
- package/dist/cjs/powdb-shared.js +67 -8
- package/dist/cjs/powdb.d.ts +4 -0
- package/dist/cjs/powdb.js +183 -51
- package/dist/cjs/powql.d.ts +394 -51
- package/dist/cjs/powql.js +1829 -284
- package/dist/cjs/prisma-compat.d.ts +23 -15
- package/dist/cjs/prisma-compat.js +507 -372
- package/dist/cjs/query/aggregates.d.ts +17 -1
- package/dist/cjs/query/aggregates.js +261 -29
- package/dist/cjs/query/batched-loader.d.ts +25 -6
- package/dist/cjs/query/batched-loader.js +103 -20
- package/dist/cjs/query/builder.d.ts +325 -184
- package/dist/cjs/query/builder.js +1452 -490
- package/dist/cjs/query/column-ref.d.ts +61 -0
- package/dist/cjs/query/column-ref.js +73 -0
- package/dist/cjs/query/compound-unique.d.ts +21 -0
- package/dist/cjs/query/compound-unique.js +98 -18
- package/dist/cjs/query/deferred.d.ts +53 -16
- package/dist/cjs/query/expr.d.ts +217 -0
- package/dist/cjs/query/expr.js +859 -0
- package/dist/cjs/query/filters.d.ts +155 -53
- package/dist/cjs/query/filters.js +613 -76
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/json-value.d.ts +43 -0
- package/dist/cjs/query/json-value.js +59 -0
- package/dist/cjs/query/normalize-args.d.ts +87 -0
- package/dist/cjs/query/normalize-args.js +527 -0
- package/dist/cjs/query/option-surface.d.ts +16 -4
- package/dist/cjs/query/option-surface.js +57 -14
- package/dist/cjs/query/relation-names.d.ts +14 -0
- package/dist/cjs/query/relation-names.js +77 -18
- package/dist/cjs/query/relations.d.ts +30 -3
- package/dist/cjs/query/relations.js +219 -63
- package/dist/cjs/query/row-lock.d.ts +49 -0
- package/dist/cjs/query/row-lock.js +138 -0
- package/dist/cjs/query/sql-comment.d.ts +161 -0
- package/dist/cjs/query/sql-comment.js +381 -0
- package/dist/cjs/query/stream-idle.d.ts +132 -0
- package/dist/cjs/query/stream-idle.js +212 -0
- package/dist/cjs/query/table-client.d.ts +101 -0
- package/dist/cjs/query/table-client.js +74 -0
- package/dist/cjs/query/types.d.ts +677 -298
- package/dist/cjs/query/utils.d.ts +105 -6
- package/dist/cjs/query/utils.js +426 -19
- package/dist/cjs/query/warn-registry.d.ts +18 -0
- package/dist/cjs/query/warn-registry.js +18 -0
- package/dist/cjs/query/where-compile.d.ts +138 -14
- package/dist/cjs/query/where-compile.js +513 -29
- package/dist/cjs/query/where.d.ts +159 -59
- package/dist/cjs/query/where.js +716 -246
- package/dist/cjs/query/writes.d.ts +112 -50
- package/dist/cjs/query/writes.js +1498 -200
- package/dist/cjs/query-events.d.ts +4 -2
- package/dist/cjs/query-events.js +3 -1
- package/dist/cjs/realtime.d.ts +7 -3
- package/dist/cjs/realtime.js +13 -2
- package/dist/cjs/schema-builder.d.ts +55 -4
- package/dist/cjs/schema-builder.js +382 -18
- package/dist/cjs/schema-metadata.d.ts +21 -1
- package/dist/cjs/schema-metadata.js +29 -7
- package/dist/cjs/schema-sql.d.ts +75 -5
- package/dist/cjs/schema-sql.js +497 -45
- package/dist/cjs/schema.d.ts +26 -5
- package/dist/cjs/schema.js +110 -13
- package/dist/cjs/sql-placeholders.d.ts +56 -0
- package/dist/cjs/sql-placeholders.js +204 -0
- package/dist/cjs/sqlite.d.ts +75 -20
- package/dist/cjs/sqlite.js +593 -95
- package/dist/cjs/supplied-pool-types.d.ts +48 -0
- package/dist/cjs/supplied-pool-types.js +256 -0
- package/dist/cjs/transaction-control.d.ts +51 -0
- package/dist/cjs/transaction-control.js +316 -0
- package/dist/cjs/transaction-state.d.ts +342 -0
- package/dist/cjs/transaction-state.js +707 -0
- package/dist/cjs/typed-sql.d.ts +37 -3
- package/dist/cjs/typed-sql.js +102 -8
- package/dist/cli/code-first-tags.d.ts +62 -0
- package/dist/cli/code-first-tags.js +120 -0
- package/dist/cli/compile-query.js +9 -0
- package/dist/cli/config.d.ts +35 -6
- package/dist/cli/config.js +16 -1
- package/dist/cli/destructive.d.ts +7 -4
- package/dist/cli/destructive.js +224 -20
- package/dist/cli/error-catalog.js +36 -0
- package/dist/cli/error-text.d.ts +15 -0
- package/dist/cli/error-text.js +37 -0
- package/dist/cli/index.d.ts +62 -4
- package/dist/cli/index.js +569 -112
- package/dist/cli/local-server-guard.d.ts +53 -0
- package/dist/cli/local-server-guard.js +113 -0
- package/dist/cli/local-server-output.d.ts +41 -0
- package/dist/cli/local-server-output.js +98 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +121 -34
- package/dist/cli/migrate.d.ts +113 -5
- package/dist/cli/migrate.js +261 -21
- package/dist/cli/observe.d.ts +6 -1
- package/dist/cli/observe.js +84 -54
- package/dist/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cli/pii-predicate-guard.js +100 -35
- package/dist/cli/prisma-resolve.js +15 -11
- package/dist/cli/prisma-schema.js +12 -4
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +14 -2
- package/dist/cli/studio.js +246 -71
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +558 -85
- package/dist/client.js +1275 -400
- package/dist/connection-guard.d.ts +13 -0
- package/dist/connection-guard.js +27 -0
- package/dist/connection-url.d.ts +51 -16
- package/dist/connection-url.js +63 -34
- package/dist/diagnostics.d.ts +81 -0
- package/dist/diagnostics.js +144 -0
- package/dist/dialect.d.ts +449 -20
- package/dist/dialect.js +115 -43
- package/dist/engine-config.d.ts +7 -6
- package/dist/errors.d.ts +126 -6
- package/dist/errors.js +252 -12
- package/dist/generate.d.ts +57 -7
- package/dist/generate.js +635 -281
- package/dist/global-filters-config.d.ts +59 -0
- package/dist/global-filters-config.js +361 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/introspect.d.ts +31 -6
- package/dist/introspect.js +106 -50
- package/dist/log-codes.d.ts +12 -0
- package/dist/log-codes.js +74 -0
- package/dist/logger.d.ts +87 -0
- package/dist/logger.js +93 -0
- package/dist/mssql.d.ts +8 -5
- package/dist/mssql.js +354 -67
- package/dist/mysql.d.ts +3 -5
- package/dist/mysql.js +423 -73
- package/dist/nested-write.d.ts +3 -0
- package/dist/nested-write.js +177 -112
- package/dist/pipeline-submittable.d.ts +12 -0
- package/dist/pipeline-submittable.js +117 -44
- package/dist/pipeline.js +21 -26
- package/dist/powdb-introspect.d.ts +5 -2
- package/dist/powdb-introspect.js +21 -16
- package/dist/powdb-shared.d.ts +36 -5
- package/dist/powdb-shared.js +65 -8
- package/dist/powdb.d.ts +4 -0
- package/dist/powdb.js +183 -51
- package/dist/powql.d.ts +394 -51
- package/dist/powql.js +1836 -291
- package/dist/prisma-compat.d.ts +23 -15
- package/dist/prisma-compat.js +508 -373
- package/dist/query/aggregates.d.ts +17 -1
- package/dist/query/aggregates.js +263 -32
- package/dist/query/batched-loader.d.ts +25 -6
- package/dist/query/batched-loader.js +101 -21
- package/dist/query/builder.d.ts +325 -184
- package/dist/query/builder.js +1458 -495
- package/dist/query/column-ref.d.ts +61 -0
- package/dist/query/column-ref.js +66 -0
- package/dist/query/compound-unique.d.ts +21 -0
- package/dist/query/compound-unique.js +97 -19
- package/dist/query/deferred.d.ts +53 -16
- package/dist/query/expr.d.ts +217 -0
- package/dist/query/expr.js +848 -0
- package/dist/query/filters.d.ts +155 -53
- package/dist/query/filters.js +597 -72
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +4 -0
- package/dist/query/json-value.d.ts +43 -0
- package/dist/query/json-value.js +54 -0
- package/dist/query/normalize-args.d.ts +87 -0
- package/dist/query/normalize-args.js +517 -0
- package/dist/query/option-surface.d.ts +16 -4
- package/dist/query/option-surface.js +56 -13
- package/dist/query/relation-names.d.ts +14 -0
- package/dist/query/relation-names.js +77 -19
- package/dist/query/relations.d.ts +30 -3
- package/dist/query/relations.js +220 -67
- package/dist/query/row-lock.d.ts +49 -0
- package/dist/query/row-lock.js +131 -0
- package/dist/query/sql-comment.d.ts +161 -0
- package/dist/query/sql-comment.js +374 -0
- package/dist/query/stream-idle.d.ts +132 -0
- package/dist/query/stream-idle.js +203 -0
- package/dist/query/table-client.d.ts +101 -0
- package/dist/query/table-client.js +70 -0
- package/dist/query/types.d.ts +677 -298
- package/dist/query/utils.d.ts +105 -6
- package/dist/query/utils.js +414 -18
- package/dist/query/warn-registry.d.ts +18 -0
- package/dist/query/warn-registry.js +18 -0
- package/dist/query/where-compile.d.ts +138 -14
- package/dist/query/where-compile.js +508 -31
- package/dist/query/where.d.ts +159 -59
- package/dist/query/where.js +711 -248
- package/dist/query/writes.d.ts +112 -50
- package/dist/query/writes.js +1496 -202
- package/dist/query-events.d.ts +4 -2
- package/dist/query-events.js +3 -1
- package/dist/realtime.d.ts +7 -3
- package/dist/realtime.js +13 -2
- package/dist/schema-builder.d.ts +55 -4
- package/dist/schema-builder.js +381 -18
- package/dist/schema-metadata.d.ts +21 -1
- package/dist/schema-metadata.js +28 -7
- package/dist/schema-sql.d.ts +75 -5
- package/dist/schema-sql.js +494 -44
- package/dist/schema.d.ts +26 -5
- package/dist/schema.js +109 -13
- package/dist/sql-placeholders.d.ts +56 -0
- package/dist/sql-placeholders.js +200 -0
- package/dist/sqlite.d.ts +75 -20
- package/dist/sqlite.js +597 -99
- package/dist/supplied-pool-types.d.ts +48 -0
- package/dist/supplied-pool-types.js +247 -0
- package/dist/transaction-control.d.ts +51 -0
- package/dist/transaction-control.js +311 -0
- package/dist/transaction-state.d.ts +342 -0
- package/dist/transaction-state.js +696 -0
- package/dist/typed-sql.d.ts +37 -3
- package/dist/typed-sql.js +100 -8
- package/package.json +7 -4
- package/skills/turbine-orm/SKILL.md +56 -6
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
import { CircularRelationError, RelationError, UnsupportedFeatureError, ValidationError } from '../errors.js';
|
|
57
57
|
import { normalizeKeyColumns } from '../schema.js';
|
|
58
58
|
import { dedupeOrderEntries, isOrderBySpec, isRelationPickOrderBy, orderByEntries, sortedEntries } from './filters.js';
|
|
59
|
-
import { availableClause, markInternalCombinator, ownLookup, resolveColumnName, selectNamesNothingMessage, selectOmitExclusiveMessage,
|
|
59
|
+
import { availableClause, boundedPreparedName, markInternalCombinator, ownLookup, resolveColumnName, selectNamesNothingMessage, selectOmitExclusiveMessage, } from './utils.js';
|
|
60
60
|
/**
|
|
61
61
|
* Max parent keys per follow-up query. On Postgres the whole key set travels as
|
|
62
62
|
* ONE array parameter (`= ANY($1)`), so this is not a bind-parameter limit, it
|
|
@@ -240,14 +240,40 @@ includePii) {
|
|
|
240
240
|
return hidden.size === 0 ? undefined : { hidden, visible };
|
|
241
241
|
}
|
|
242
242
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* were added ONLY for stitching and must be stripped from the final entities.
|
|
243
|
+
* Key under which {@link includeKeysForBatching} records the fields IT added to
|
|
244
|
+
* a `select`, as a `ReadonlySet<string>` of field names.
|
|
246
245
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
246
|
+
* Why it exists: naming a PII-tagged column in `select` is refused unless the
|
|
247
|
+
* query passes `includePii: UNSAFE` (see `resolveProjection`), and the loader
|
|
248
|
+
* has to project a correlation or ordering column that may itself be tagged.
|
|
249
|
+
* That column is stripped from every entity before the caller sees it, so it is
|
|
250
|
+
* the one legitimate way a PII name reaches a `select` without the caller
|
|
251
|
+
* writing it. The marker is a symbol key: `Object.keys`, `Object.entries`,
|
|
252
|
+
* spreads of a parsed body and `JSON.stringify` never see one, and
|
|
253
|
+
* `JSON.parse` cannot produce one, so request data cannot forge the exemption.
|
|
250
254
|
*/
|
|
255
|
+
export const STITCH_ONLY_FIELDS = Symbol.for('turbine.stitchOnlyFields');
|
|
256
|
+
/** The fields the batched loader (not the caller) added to this `select`, if any. */
|
|
257
|
+
export function stitchOnlyFields(select) {
|
|
258
|
+
if (!select)
|
|
259
|
+
return undefined;
|
|
260
|
+
const marked = select[STITCH_ONLY_FIELDS];
|
|
261
|
+
return marked instanceof Set ? marked : undefined;
|
|
262
|
+
}
|
|
263
|
+
/** Record `fields` on `select` as added by an engine loader, not by the caller. Returns `select`. */
|
|
264
|
+
export function markStitchOnly(select, fields) {
|
|
265
|
+
// Non-enumerable, like the other engine-written markers: the select object is
|
|
266
|
+
// passed by reference from here to the child build, and an enumerable symbol
|
|
267
|
+
// would show up in deep-equality comparisons of the projection.
|
|
268
|
+
if (fields.length > 0) {
|
|
269
|
+
Object.defineProperty(select, STITCH_ONLY_FIELDS, {
|
|
270
|
+
value: new Set(fields),
|
|
271
|
+
enumerable: false,
|
|
272
|
+
configurable: true,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return select;
|
|
276
|
+
}
|
|
251
277
|
/**
|
|
252
278
|
* The two projection SHAPE rules from `resolveProjection`, checked on the RAW
|
|
253
279
|
* caller args BEFORE `includeKeysForBatching` adjusts them. The adjustment
|
|
@@ -269,6 +295,16 @@ export function assertProjectionShape(table, select, omit) {
|
|
|
269
295
|
throw new ValidationError(selectOmitExclusiveMessage(table));
|
|
270
296
|
}
|
|
271
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Adjust a `select`/`omit` pair so that `fields` are guaranteed present in the
|
|
300
|
+
* query result, returning the adjusted projection plus the list of fields that
|
|
301
|
+
* were added ONLY for stitching and must be stripped from the final entities.
|
|
302
|
+
*
|
|
303
|
+
* Used both for the base query (parent keys) and each follow-up query (child
|
|
304
|
+
* keys) so a caller's `select: { title: true }` on a relation still stitches even
|
|
305
|
+
* though the FK was not requested, and the FK never appears in the output. A
|
|
306
|
+
* returned `select` carries {@link STITCH_ONLY_FIELDS} for the fields added here.
|
|
307
|
+
*/
|
|
272
308
|
export function includeKeysForBatching(
|
|
273
309
|
/**
|
|
274
310
|
* The table the projection is compiled against. `select` / `omit` keys are
|
|
@@ -321,7 +357,7 @@ defaultProjection) {
|
|
|
321
357
|
next[f] = true;
|
|
322
358
|
strip.push(f); // not requested by the caller, added only to stitch
|
|
323
359
|
}
|
|
324
|
-
return { select: next, omit, strip };
|
|
360
|
+
return { select: markStitchOnly(next, strip), omit, strip };
|
|
325
361
|
}
|
|
326
362
|
if (omit) {
|
|
327
363
|
const next = { ...omit };
|
|
@@ -347,7 +383,7 @@ defaultProjection) {
|
|
|
347
383
|
explicit[f] = true;
|
|
348
384
|
for (const f of hiddenKeys)
|
|
349
385
|
explicit[f] = true;
|
|
350
|
-
return { select: explicit, omit: undefined, strip: hiddenKeys };
|
|
386
|
+
return { select: markStitchOnly(explicit, hiddenKeys), omit: undefined, strip: hiddenKeys };
|
|
351
387
|
}
|
|
352
388
|
return { select, omit, strip: [] };
|
|
353
389
|
}
|
|
@@ -429,8 +465,22 @@ export function resolveCountRelations(parentMeta, countSpec) {
|
|
|
429
465
|
}
|
|
430
466
|
return out;
|
|
431
467
|
}
|
|
432
|
-
/**
|
|
468
|
+
/**
|
|
469
|
+
* Stringified stitch key, robust to number/uuid/bigint type drift across a join.
|
|
470
|
+
* A binary key is keyed by its bytes: `String()` of a Buffer decodes it as
|
|
471
|
+
* UTF-8, which maps different invalid sequences to the same replacement text.
|
|
472
|
+
* A Date by its instant, which `String()` truncates to the second.
|
|
473
|
+
*/
|
|
433
474
|
function keyOf(value) {
|
|
475
|
+
if (value instanceof Uint8Array) {
|
|
476
|
+
// No Buffer: this module runs on edge runtimes too.
|
|
477
|
+
let hex = '\u0000bytes:';
|
|
478
|
+
for (const byte of value)
|
|
479
|
+
hex += byte.toString(16).padStart(2, '0');
|
|
480
|
+
return hex;
|
|
481
|
+
}
|
|
482
|
+
if (value instanceof Date)
|
|
483
|
+
return `\u0000date:${value.getTime()}`;
|
|
434
484
|
return String(value);
|
|
435
485
|
}
|
|
436
486
|
/**
|
|
@@ -599,6 +649,34 @@ function seedRelationKeys(parents, parentMeta, resolved, hasCount) {
|
|
|
599
649
|
parent._count = existingCount ?? {};
|
|
600
650
|
}
|
|
601
651
|
}
|
|
652
|
+
/**
|
|
653
|
+
* A to-many relation's per-parent page (`skip` / `take` are folded into
|
|
654
|
+
* `offset` / `limit` at the args seam), validated as the join plan validates
|
|
655
|
+
* it: a non-negative integer, numeric strings coerced. Checked before anything
|
|
656
|
+
* runs, so both strategies accept and refuse the same values.
|
|
657
|
+
*/
|
|
658
|
+
function relationPage(options, table) {
|
|
659
|
+
const check = (value, arg) => {
|
|
660
|
+
if (value === undefined)
|
|
661
|
+
return undefined;
|
|
662
|
+
const n = Number(value);
|
|
663
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
664
|
+
throw new ValidationError(`${arg} on "${table}" must be a non-negative integer, received: ${String(value)}`);
|
|
665
|
+
}
|
|
666
|
+
return n;
|
|
667
|
+
};
|
|
668
|
+
return {
|
|
669
|
+
limit: check(options.limit, 'relation limit'),
|
|
670
|
+
offset: check(options.offset, 'relation offset'),
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
/** One parent's window of its own related rows. */
|
|
674
|
+
function pageOf(rows, page) {
|
|
675
|
+
if (page.limit === undefined && !page.offset)
|
|
676
|
+
return rows;
|
|
677
|
+
const start = page.offset ?? 0;
|
|
678
|
+
return rows.slice(start, page.limit === undefined ? undefined : start + page.limit);
|
|
679
|
+
}
|
|
602
680
|
/**
|
|
603
681
|
* hasMany / hasOne / belongsTo: one follow-up `SELECT ... WHERE childKey = ANY($1)`
|
|
604
682
|
* (chunked), grouped by the correlation key and attached (array vs single-or-null).
|
|
@@ -620,6 +698,7 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
|
|
|
620
698
|
assertCorrelationKeyProjected(parents, parentKeyField, relName, ctx.parentMeta.name);
|
|
621
699
|
const keys = uniqueKeys(parents, parentKeyField);
|
|
622
700
|
const single = rel.type === 'belongsTo' || rel.type === 'hasOne';
|
|
701
|
+
const page = single ? {} : relationPage(options, ctx.parentMeta.name);
|
|
623
702
|
// The follow-up must project the child correlation key even if the caller's
|
|
624
703
|
// select/omit excluded it; strip it back off afterwards so the shape matches join.
|
|
625
704
|
//
|
|
@@ -638,7 +717,7 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
|
|
|
638
717
|
// again afterwards). `null` means this relation keeps the client-side slice,
|
|
639
718
|
// which is the case for every shape whose ordering does not force WHICH rows
|
|
640
719
|
// the limit keeps. See {@link partitionOrderBy} and {@link boundedChildQuery}.
|
|
641
|
-
const windowOrder = single ||
|
|
720
|
+
const windowOrder = single || page.limit === undefined ? null : partitionOrderBy(targetMeta, options.orderBy);
|
|
642
721
|
const pushDownLimit = windowOrder !== null && ctx.buildPartitionLimit !== undefined;
|
|
643
722
|
// THE ONE PII EXCEPTION IN THE READ PATH, recorded here because the contract
|
|
644
723
|
// in schema.ts says a PII column is excluded from every default projection
|
|
@@ -689,7 +768,8 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
|
|
|
689
768
|
const chunkResults = await Promise.all(chunks.map(async (chunk) => {
|
|
690
769
|
const deferred = buildChunk(chunk);
|
|
691
770
|
const bounded = pushDownLimit
|
|
692
|
-
?
|
|
771
|
+
? // The first offset + limit rows of each parent; the slice below drops the offset.
|
|
772
|
+
boundedChildQuery(ctx, deferred, childKeyCol, windowOrder ?? [], (page.offset ?? 0) + page.limit)
|
|
693
773
|
: deferred;
|
|
694
774
|
const result = await ctx.exec(bounded.sql, bounded.params, bounded.preparedName);
|
|
695
775
|
if (bounded !== deferred)
|
|
@@ -711,14 +791,13 @@ async function loadToOneOrMany(ctx, parents, rel, relName, options, timeout, dep
|
|
|
711
791
|
// what was true of the parent side until this week.
|
|
712
792
|
assertCorrelationKeyProjected(allChildren, childKeyField, relName, targetMeta.name);
|
|
713
793
|
const byKey = groupBy(allChildren, childKeyField);
|
|
714
|
-
const limit = options.limit;
|
|
715
794
|
for (const parent of parents) {
|
|
716
795
|
const bucket = byKey.get(keyOf(parent[parentKeyField])) ?? [];
|
|
717
796
|
if (single) {
|
|
718
797
|
parent[relName] = bucket[0] ?? null;
|
|
719
798
|
}
|
|
720
799
|
else {
|
|
721
|
-
parent[relName] =
|
|
800
|
+
parent[relName] = pageOf(bucket, page);
|
|
722
801
|
}
|
|
723
802
|
}
|
|
724
803
|
stripFields(allChildren, proj.strip);
|
|
@@ -779,7 +858,7 @@ function boundedChildQuery(ctx, deferred, partitionColumn, orderBy, limit) {
|
|
|
779
858
|
return {
|
|
780
859
|
sql,
|
|
781
860
|
params: [...deferred.params, limit],
|
|
782
|
-
preparedName: deferred.preparedName ?
|
|
861
|
+
preparedName: deferred.preparedName ? boundedPreparedName(sql) : deferred.preparedName,
|
|
783
862
|
transform: deferred.transform,
|
|
784
863
|
};
|
|
785
864
|
}
|
|
@@ -819,6 +898,7 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
|
|
|
819
898
|
const targetPkCol = targetMeta.primaryKey[0];
|
|
820
899
|
const parentRefField = ctx.parentMeta.reverseColumnMap[sourceRefCol] ?? sourceRefCol;
|
|
821
900
|
const targetPkField = targetMeta.reverseColumnMap[targetPkCol] ?? targetPkCol;
|
|
901
|
+
const page = relationPage(options, ctx.parentMeta.name);
|
|
822
902
|
assertCorrelationKeyProjected(parents, parentRefField, relName, ctx.parentMeta.name);
|
|
823
903
|
// No early return on zero parent keys: the code below flows through
|
|
824
904
|
// naturally (zero junction chunks, zero target chunks), and the compile-only
|
|
@@ -910,7 +990,7 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
|
|
|
910
990
|
// link, which spends exactly the bytes the pushdown exists to save; and the
|
|
911
991
|
// bound would still have to respect a `limit` measured per parent, not per
|
|
912
992
|
// fetched row. So the m2m loader keeps the slice below, on every engine.
|
|
913
|
-
const
|
|
993
|
+
const end = page.limit === undefined ? undefined : (page.offset ?? 0) + page.limit;
|
|
914
994
|
for (const parent of parents) {
|
|
915
995
|
const linked = new Set((targetsBySource.get(keyOf(parent[parentRefField])) ?? []).map(keyOf));
|
|
916
996
|
if (linked.size === 0) {
|
|
@@ -919,13 +999,13 @@ async function loadManyToMany(ctx, parents, rel, relName, options, timeout, dept
|
|
|
919
999
|
}
|
|
920
1000
|
const out = [];
|
|
921
1001
|
for (const t of targetsInOrder) {
|
|
922
|
-
|
|
1002
|
+
// Checked before the push, so `limit: 0` keeps nothing.
|
|
1003
|
+
if (end !== undefined && out.length >= end)
|
|
1004
|
+
break;
|
|
1005
|
+
if (linked.has(keyOf(t[targetPkField])))
|
|
923
1006
|
out.push(t);
|
|
924
|
-
if (limit !== undefined && out.length >= limit)
|
|
925
|
-
break;
|
|
926
|
-
}
|
|
927
1007
|
}
|
|
928
|
-
parent[relName] = out;
|
|
1008
|
+
parent[relName] = pageOf(out, { offset: page.offset });
|
|
929
1009
|
}
|
|
930
1010
|
stripFields(targetsInOrder, proj.strip);
|
|
931
1011
|
}
|