turbine-orm 0.25.0 → 0.27.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.
@@ -13,7 +13,7 @@
13
13
  import type pg from 'pg';
14
14
  import type { Dialect } from '../dialect.js';
15
15
  import type { SchemaMetadata } from '../schema.js';
16
- import type { AggregateArgs, AggregateResult, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, QueryResult, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs, WithClause } from './types.js';
16
+ import type { AggregateArgs, AggregateResult, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, QueryResult, RelationLoadStrategy, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs, WithClause } from './types.js';
17
17
  /**
18
18
  * Runs a SQL statement and resolves its raw result. Passed to a
19
19
  * {@link DeferredQuery.reselect} plan so it can run the write and the follow-up
@@ -94,6 +94,26 @@ export interface QueryInterfaceOptions {
94
94
  sqlCache?: boolean;
95
95
  /** SQL dialect implementation. Defaults to PostgreSQL. */
96
96
  dialect?: Dialect;
97
+ /**
98
+ * Interpret offset-less timestamp strings (Postgres `timestamp` without
99
+ * time zone, and the JSON emitted by nested-relation subqueries) as UTC.
100
+ * This is the Prisma/Rails/Django convention and makes results independent
101
+ * of the server's local time zone. Default: `true`. Set `false` to restore
102
+ * the pre-0.26 behavior (JS local-time interpretation).
103
+ */
104
+ utcTimestamps?: boolean;
105
+ /**
106
+ * Client-level default relation-loading strategy for `with` clauses. Per-query
107
+ * `relationLoadStrategy` args override this; both default to `'join'`.
108
+ */
109
+ relationLoadStrategy?: RelationLoadStrategy;
110
+ /**
111
+ * How nested-relation subqueries encode each row's JSON: `'object'` (default,
112
+ * `json_build_object`) or `'positional'` (`json_build_array`, key-less — see
113
+ * {@link Dialect.buildJsonArray}). Positional is Postgres-only in v1; a
114
+ * `with` clause on any other dialect throws `UnsupportedFeatureError` (E017).
115
+ */
116
+ jsonEncoding?: 'object' | 'positional';
97
117
  /** @internal Set by TransactionClient — signals that this QI runs inside an active transaction. */
98
118
  _txScoped?: boolean;
99
119
  /** @internal Callback from TurbineClient for query event emission. */
@@ -117,9 +137,14 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
117
137
  private readonly middlewares;
118
138
  private readonly defaultLimit?;
119
139
  private readonly warnOnUnlimited;
140
+ private readonly utcTimestamps;
120
141
  private readonly preparedStatementsEnabled;
121
142
  private readonly sqlCacheEnabled;
122
143
  private readonly dialect;
144
+ /** Client-level default relation-loading strategy ('join' unless configured). */
145
+ private readonly relationLoadStrategy;
146
+ /** Nested-relation JSON encoding: 'object' (default) or 'positional'. */
147
+ private readonly jsonEncoding;
123
148
  /**
124
149
  * Tracks tables that have already triggered an unlimited-query warning so
125
150
  * the user is not spammed once per row. Per-instance state — each
@@ -204,6 +229,34 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
204
229
  private inClause;
205
230
  /** The single bound parameter for an `IN` list (PG: the array; SQLite: a JSON string). */
206
231
  private inParam;
232
+ /**
233
+ * Resolve the effective relation-loading strategy for a query: the per-query
234
+ * arg wins, then the client-level default, then `'join'`. Only meaningful when
235
+ * a `with` clause is present; the callers gate on that.
236
+ */
237
+ private resolveLoadStrategy;
238
+ /**
239
+ * Build the {@link RelationLoadContext} the batched loader needs, closing over
240
+ * this interface's pool/dialect/executor. Child readers are constructed on the
241
+ * SAME pool (so they join an active transaction) with `defaultLimit` cleared
242
+ * and unlimited-warnings silenced — a relation load must fetch every matching
243
+ * child, and the per-relation `limit` is applied client-side by the loader.
244
+ */
245
+ private batchedContext;
246
+ /**
247
+ * Run a findMany with the batched strategy: execute the base query WITHOUT
248
+ * relation subqueries (all other clauses intact), then load each relation via
249
+ * one flat follow-up query and stitch client-side. Parent stitch keys the
250
+ * caller's `select`/`omit` excluded are added for the base query and stripped
251
+ * from the returned rows, so the shape matches the join strategy exactly.
252
+ */
253
+ private runFindManyBatched;
254
+ /**
255
+ * Build the base findMany args for a batched run: drop `with`, and ensure every
256
+ * parent correlation key needed for stitching is projected (returning the list
257
+ * of keys that must be stripped from the output afterwards).
258
+ */
259
+ private prepareBatchedBase;
207
260
  /**
208
261
  * Return cache hit/miss statistics for this QueryInterface instance.
209
262
  * Useful for monitoring and benchmarking.
@@ -275,6 +328,13 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
275
328
  */
276
329
  private executeWithMiddleware;
277
330
  findUnique<W extends TypedWithClause<R> = {}, S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined>(args: FindUniqueArgs<T, R, W, S, O>): Promise<QueryResult<T, R, W, S, O> | null>;
331
+ /**
332
+ * Batched-strategy findUnique: fetch the single base row without relation
333
+ * subqueries (adding any parent stitch keys the projection excluded), then load
334
+ * its relations via one follow-up query each and stitch. Mirrors the join
335
+ * strategy's shape for the one row.
336
+ */
337
+ private runFindUniqueBatched;
278
338
  buildFindUnique<W extends TypedWithClause<R> = {}>(args: FindUniqueArgs<T, R, W, Record<string, boolean> | undefined, Record<string, boolean> | undefined>): DeferredQuery<T | null>;
279
339
  findMany<W extends TypedWithClause<R> = {}, S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined>(args?: FindManyArgs<T, R, W, S, O>): Promise<QueryResult<T, R, W, S, O>[]>;
280
340
  /**
@@ -582,10 +642,67 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
582
642
  * memoized per table. Used so nested relation rows (camelCase keys) coerce
583
643
  * dates the same way top-level rows do.
584
644
  */
645
+ /**
646
+ * Prisma-compat: a plain object on a to-one relation key —
647
+ * `where: { vendor: { name: { contains: 'x' } } }` — is an implicit `is`
648
+ * filter. Normalize it to `{ is: obj }` so all downstream handling (SQL,
649
+ * params, fingerprint) sees one canonical shape. To-many relations still
650
+ * require an explicit `some`/`every`/`none` (a bare object there is
651
+ * ambiguous and was never valid in Prisma either).
652
+ */
653
+ private normalizeRelationFilter;
585
654
  private getCamelDateFields;
586
655
  private parseRow;
587
656
  /** Parse a row that may contain JSON nested relation columns */
588
657
  private parseNestedRow;
658
+ /**
659
+ * Resolve the emitted column list for a relation, honoring `select` / `omit`.
660
+ * Shared by {@link buildRelationSubquery} (json order) and
661
+ * {@link buildRelationShape} (decode key order) so they can never diverge.
662
+ */
663
+ private resolveTargetColumns;
664
+ /**
665
+ * Render a single relation row's JSON: a keyed object (`'object'`) or a
666
+ * positional array (`'positional'`). The array drops the keys but keeps the
667
+ * exact expression order, so {@link RelationShape.keys} maps positions back.
668
+ */
669
+ private buildJsonRow;
670
+ /**
671
+ * Build the top-level relation shapes for a `with` clause, mirroring
672
+ * {@link buildSelectWithRelations}: same relation iteration order, same
673
+ * per-relation column resolution, same nested recursion.
674
+ */
675
+ private buildRelationShapes;
676
+ /**
677
+ * Recursively describe one relation's positional layout: the camelCase key
678
+ * order (scalar columns first, then nested relation slots in the same order
679
+ * {@link buildRelationSubquery} appends them), the nested sub-shapes, and the
680
+ * cardinality (single object for belongsTo/hasOne, array for the rest).
681
+ */
682
+ private buildRelationShape;
683
+ /**
684
+ * Build the row parser for a `with` clause. In object mode this is just
685
+ * {@link parseNestedRow}. In positional mode it decodes each relation's
686
+ * positional arrays into the object form first (shapes built once, not per
687
+ * row), then delegates to parseNestedRow for date/snake-camel coercion.
688
+ */
689
+ private makeNestedParser;
690
+ /**
691
+ * Return a shallow copy of a top-level row with each relation column decoded
692
+ * from its positional array(s) into the object representation. Only relation
693
+ * columns are positional — base scalar columns stay object-keyed — so the
694
+ * result is exactly what the object encoding would have handed parseNestedRow.
695
+ */
696
+ private decodePositionalRelations;
697
+ /**
698
+ * Decode one relation's positional JSON value. `json_agg` returns the value as
699
+ * a JSON string at the top level (JSON.parse once); nested relation slots are
700
+ * already-parsed arrays. A `'many'` value is an array of positional arrays; a
701
+ * `'one'` value is a single positional array or null.
702
+ */
703
+ private decodePositionalValue;
704
+ /** Map one positional array back to a keyed object using the shape's key order. */
705
+ private decodePositionalObject;
589
706
  /**
590
707
  * Build a SELECT clause that includes both base columns and nested relation subqueries.
591
708
  *