@prisma-next/sql-orm-client 0.5.0-dev.8 → 0.5.0-dev.85

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/src/types.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { Contract, ExecutionPlan } from '@prisma-next/contract/types';
2
- import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
1
+ import type { Contract } from '@prisma-next/contract/types';
3
2
  import type {
4
3
  ExtractCodecTypes,
5
4
  ExtractQueryOperationTypes,
@@ -17,15 +16,12 @@ import {
17
16
  OrderByItem,
18
17
  ParamRef,
19
18
  } from '@prisma-next/sql-relational-core/ast';
20
- import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
19
+ import type { Expression } from '@prisma-next/sql-relational-core/expression';
21
20
  import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
22
- import type { ComputeColumnJsType } from '@prisma-next/sql-relational-core/types';
21
+ import type { ComputeColumnJsType, RuntimeScope } from '@prisma-next/sql-relational-core/types';
22
+ import { ifDefined } from '@prisma-next/utils/defined';
23
23
  import type { RowSelection } from './collection-internal-types';
24
24
 
25
- // ---------------------------------------------------------------------------
26
- // Comparison / Filter / Order / Include
27
- // ---------------------------------------------------------------------------
28
-
29
25
  export type AggregateFn = 'count' | 'sum' | 'avg' | 'min' | 'max';
30
26
 
31
27
  export interface IncludeScalar<Result> extends RowSelection<Result> {
@@ -65,10 +61,6 @@ export interface IncludeExpr {
65
61
  readonly combine: Readonly<Record<string, IncludeCombineBranch>> | undefined;
66
62
  }
67
63
 
68
- // ---------------------------------------------------------------------------
69
- // CollectionState — plain data, no query builder types
70
- // ---------------------------------------------------------------------------
71
-
72
64
  export interface CollectionState {
73
65
  readonly filters: readonly AnyExpression[];
74
66
  readonly includes: readonly IncludeExpr[];
@@ -113,16 +105,6 @@ export type DefaultCollectionTypeState = {
113
105
  readonly variantName: undefined;
114
106
  };
115
107
 
116
- // ---------------------------------------------------------------------------
117
- // CollectionContext — bundles lane context + runtime
118
- // ---------------------------------------------------------------------------
119
-
120
- export interface RuntimeScope {
121
- execute<Row = Record<string, unknown>>(
122
- plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
123
- ): AsyncIterableResult<Row>;
124
- }
125
-
126
108
  export interface RuntimeConnection extends RuntimeScope {
127
109
  release?(): Promise<void>;
128
110
  transaction?(): Promise<RuntimeTransaction>;
@@ -143,10 +125,6 @@ export interface CollectionContext<TContract extends Contract<SqlStorage>> {
143
125
  readonly context: ExecutionContext<TContract>;
144
126
  }
145
127
 
146
- // ---------------------------------------------------------------------------
147
- // ModelAccessor — type-safe proxy for where() callbacks
148
- // ---------------------------------------------------------------------------
149
-
150
128
  export type ComparisonMethodFns<T> = {
151
129
  eq(value: T): AnyExpression;
152
130
  neq(value: T): AnyExpression;
@@ -164,8 +142,7 @@ export type ComparisonMethodFns<T> = {
164
142
  };
165
143
 
166
144
  /**
167
- * Trait-gated comparison methods. Only methods whose required traits are
168
- * all present in `Traits` are included.
145
+ * Trait-gated comparison methods. Only methods whose required traits are all present in `Traits` are included.
169
146
  *
170
147
  * - `traits: []` → always available (isNull, isNotNull)
171
148
  */
@@ -175,10 +152,6 @@ export type ComparisonMethods<T, Traits> = {
175
152
  : never]: ComparisonMethodFns<T>[K];
176
153
  };
177
154
 
178
- // ---------------------------------------------------------------------------
179
- // Extension operation result — returned by calling an extension method
180
- // ---------------------------------------------------------------------------
181
-
182
155
  type QueryOperationReturnTraits<
183
156
  Returns,
184
157
  TCodecTypes extends Record<string, unknown>,
@@ -203,26 +176,6 @@ type QueryOperationReturnJsType<
203
176
  : unknown
204
177
  : unknown;
205
178
 
206
- type CodecArgJsType<Arg, TCodecTypes extends Record<string, unknown>> = Arg extends {
207
- readonly codecId: infer CId extends string;
208
- readonly nullable: infer N;
209
- }
210
- ? CId extends keyof TCodecTypes
211
- ? TCodecTypes[CId] extends { readonly output: infer O }
212
- ? N extends true
213
- ? O | null
214
- : O
215
- : unknown
216
- : unknown
217
- : unknown;
218
-
219
- type MapArgsToJsTypes<
220
- Args extends readonly unknown[],
221
- TCodecTypes extends Record<string, unknown>,
222
- > = Args extends readonly [infer Head, ...infer Tail]
223
- ? [CodecArgJsType<Head, TCodecTypes>, ...MapArgsToJsTypes<Tail, TCodecTypes>]
224
- : [];
225
-
226
179
  type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Returns extends {
227
180
  readonly codecId: infer Id extends string;
228
181
  }
@@ -235,22 +188,41 @@ type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Ret
235
188
  : false
236
189
  : false;
237
190
 
191
+ /**
192
+ * Extract the `{codecId, nullable}` spec carried inside an `Expression<T>`. Used to recover the op's return spec from its impl signature so the pre-existing `QueryOperationReturn*` helpers can consume it unchanged.
193
+ */
194
+ type SpecOf<E> = E extends Expression<infer T> ? T : never;
195
+
196
+ type ImplReturnSpec<Impl> = Impl extends (...args: never[]) => infer Ret ? SpecOf<Ret> : never;
197
+
198
+ /**
199
+ * Builds the ORM column-method signature for an operation.
200
+ *
201
+ * - User args: drops the impl's first parameter (the column is bound at access time) and forwards the rest unchanged. Each remaining arg keeps its authored `CodecExpression` / `TraitExpression` shape — so callers can pass a raw JS value, another column handle (which itself implements `Expression`), or `null` when nullable.
202
+ * - Return: predicate ops (boolean-traited return) yield `AnyExpression`; non-predicate ops yield `ComparisonMethods<JsType, Traits>` of the return codec.
203
+ */
238
204
  type QueryOperationMethod<Op, TCodecTypes extends Record<string, unknown>> = Op extends {
239
- readonly args: readonly [unknown, ...infer UserArgs];
240
- readonly returns: infer Returns;
205
+ readonly impl: (...args: never[]) => unknown;
241
206
  }
242
- ? IsBooleanReturn<Returns, TCodecTypes> extends true
243
- ? (...args: MapArgsToJsTypes<UserArgs, TCodecTypes>) => AnyExpression
244
- : (
245
- ...args: MapArgsToJsTypes<UserArgs, TCodecTypes>
246
- ) => ComparisonMethods<
247
- QueryOperationReturnJsType<Returns, TCodecTypes>,
248
- QueryOperationReturnTraits<Returns, TCodecTypes>
249
- >
207
+ ? Op['impl'] extends (first: never, ...rest: infer UserArgs extends readonly unknown[]) => unknown
208
+ ? ImplReturnSpec<Op['impl']> extends infer Returns
209
+ ? IsBooleanReturn<Returns, TCodecTypes> extends true
210
+ ? (...args: UserArgs) => AnyExpression
211
+ : (
212
+ ...args: UserArgs
213
+ ) => ComparisonMethods<
214
+ QueryOperationReturnJsType<Returns, TCodecTypes>,
215
+ QueryOperationReturnTraits<Returns, TCodecTypes>
216
+ >
217
+ : never
218
+ : never
250
219
  : never;
251
220
 
221
+ /**
222
+ * Tests whether an operation's `self` dispatch hint reaches a field with the given codec identity. Codec hints match by identity; trait hints match when every required trait is present in the field codec's trait set.
223
+ */
252
224
  type OpMatchesField<Op, CodecId extends string, CT extends Record<string, unknown>> = Op extends {
253
- readonly args: readonly [infer Self, ...(readonly unknown[])];
225
+ readonly self: infer Self;
254
226
  }
255
227
  ? Self extends { readonly codecId: CodecId }
256
228
  ? true
@@ -283,21 +255,43 @@ type FieldOperations<
283
255
  : unknown
284
256
  : unknown;
285
257
 
286
- // ---------------------------------------------------------------------------
287
- // COMPARISON_METHODS_METAsingle source of truth for traits + factories
288
- // ---------------------------------------------------------------------------
258
+ /**
259
+ * Resolve the unique column ref carried by `left` so its surrounding `ParamRef` can dispatch through `forColumn`. The previous implementation only matched bare `column-ref` expressions, which lost refs the moment the expression got wrapped (`upper(f.id)`, `BinaryExpr`, function-call expressions, etc.) and column-aware dispatch (AC-5) silently degraded for any predicate that touched a computed column.
260
+ *
261
+ * Walking via `collectColumnRefs()` and accepting only a single unambiguous ref gives `eq(upper(f.id), value)` and friends correct dispatch without inventing refs for ambiguous shapes (e.g. `eq(concat(f.firstName, f.lastName), value)` returns `undefined` and falls through to the codec-id path, which is correct for non-parameterized comparisons).
262
+ */
263
+ function refsFromLeft(left: AnyExpression): { table: string; column: string } | undefined {
264
+ if (left.kind === 'column-ref') {
265
+ return { table: left.table, column: left.column };
266
+ }
267
+ const columnRefs = left.collectColumnRefs();
268
+ if (columnRefs.length !== 1) return undefined;
269
+ const single = columnRefs[0];
270
+ if (!single) return undefined;
271
+ return { table: single.table, column: single.column };
272
+ }
289
273
 
290
- function param(codecId: string | undefined, value: unknown): ParamRef {
291
- return codecId ? ParamRef.of(value, { codecId }) : ParamRef.of(value);
274
+ function param(
275
+ codecId: string | undefined,
276
+ value: unknown,
277
+ refs: { table: string; column: string } | undefined,
278
+ ): ParamRef {
279
+ if (codecId === undefined && refs === undefined) return ParamRef.of(value);
280
+ return ParamRef.of(value, {
281
+ ...ifDefined('codecId', codecId),
282
+ ...ifDefined('refs', refs),
283
+ });
292
284
  }
293
285
 
294
- function paramList(codecId: string | undefined, values: readonly unknown[]): ListExpression {
295
- return ListExpression.of(values.map((value) => param(codecId, value)));
286
+ function paramList(
287
+ codecId: string | undefined,
288
+ values: readonly unknown[],
289
+ refs: { table: string; column: string } | undefined,
290
+ ): ListExpression {
291
+ return ListExpression.of(values.map((value) => param(codecId, value, refs)));
296
292
  }
297
293
 
298
- // never[] is intentional: factories have heterogeneous signatures (value: unknown,
299
- // values: readonly unknown[], pattern: string, etc.) but are only called through
300
- // the typed ComparisonMethodFns interface, never through this type directly.
294
+ // never[] is intentional: factories have heterogeneous signatures (value: unknown, values: readonly unknown[], pattern: string, etc.) but are only called through the typed ComparisonMethodFns interface, never through this type directly.
301
295
  type MethodFactory = (
302
296
  left: AnyExpression,
303
297
  codecId: string | undefined,
@@ -310,12 +304,16 @@ type ComparisonMethodMeta = {
310
304
 
311
305
  function scalarComparisonMethod(op: BinaryOp) {
312
306
  return ((left, codecId) => (value: unknown) =>
313
- new BinaryExpr(op, left, param(codecId, value))) satisfies MethodFactory;
307
+ new BinaryExpr(op, left, param(codecId, value, refsFromLeft(left)))) satisfies MethodFactory;
314
308
  }
315
309
 
316
310
  function listComparisonMethod(op: BinaryOp) {
317
311
  return ((left, codecId) => (values: readonly unknown[]) =>
318
- new BinaryExpr(op, left, paramList(codecId, values))) satisfies MethodFactory;
312
+ new BinaryExpr(
313
+ op,
314
+ left,
315
+ paramList(codecId, values, refsFromLeft(left)),
316
+ )) satisfies MethodFactory;
319
317
  }
320
318
 
321
319
  /**
@@ -400,10 +398,11 @@ export type RelationFilterAccessor<
400
398
  };
401
399
 
402
400
  type ScalarModelAccessor<TContract extends Contract<SqlStorage>, ModelName extends string> = {
403
- [K in keyof FieldsOf<TContract, ModelName> & string]: ComparisonMethods<
404
- FieldJsType<TContract, ModelName, K>,
405
- FieldTraits<TContract, ModelName, K>
406
- > &
401
+ [K in keyof FieldsOf<TContract, ModelName> & string]: Expression<{
402
+ codecId: FieldCodecId<TContract, ModelName, K>;
403
+ nullable: FieldNullable<TContract, ModelName, K>;
404
+ }> &
405
+ ComparisonMethods<FieldJsType<TContract, ModelName, K>, FieldTraits<TContract, ModelName, K>> &
407
406
  FieldOperations<TContract, ModelName, K>;
408
407
  };
409
408
 
@@ -419,18 +418,10 @@ export type ModelAccessor<
419
418
  ModelName extends string,
420
419
  > = ScalarModelAccessor<TContract, ModelName> & RelationModelAccessor<TContract, ModelName>;
421
420
 
422
- // ---------------------------------------------------------------------------
423
- // DefaultModelRow — all scalar fields with JS types
424
- // ---------------------------------------------------------------------------
425
-
426
421
  export type DefaultModelRow<TContract extends Contract<SqlStorage>, ModelName extends string> = {
427
422
  [K in keyof FieldsOf<TContract, ModelName> & string]: FieldJsType<TContract, ModelName, K>;
428
423
  };
429
424
 
430
- // ---------------------------------------------------------------------------
431
- // InferRootRow — discriminated union for polymorphic base models
432
- // ---------------------------------------------------------------------------
433
-
434
425
  type Simplify<T> = { [K in keyof T]: T[K] } & {};
435
426
 
436
427
  type VariantRow<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
@@ -551,10 +542,6 @@ export type ShorthandWhereFilter<
551
542
  | undefined;
552
543
  }>;
553
544
 
554
- // ---------------------------------------------------------------------------
555
- // Helpers for extracting fields / types from the contract
556
- // ---------------------------------------------------------------------------
557
-
558
545
  type ModelsOf<TContract extends Contract<SqlStorage>> =
559
546
  TContract['models'] extends Record<string, unknown> ? TContract['models'] : Record<string, never>;
560
547
 
@@ -668,10 +655,6 @@ type FieldStorageColumn<
668
655
  FieldName extends string,
669
656
  > = ResolvedStorageColumn<TContract, ModelName, FieldName>;
670
657
 
671
- // ---------------------------------------------------------------------------
672
- // Field trait resolution from contract CodecTypes
673
- // ---------------------------------------------------------------------------
674
-
675
658
  type FieldCodecId<
676
659
  TContract extends Contract<SqlStorage>,
677
660
  ModelName extends string,
@@ -682,6 +665,16 @@ type FieldCodecId<
682
665
  ? Id
683
666
  : never;
684
667
 
668
+ type FieldNullable<
669
+ TContract extends Contract<SqlStorage>,
670
+ ModelName extends string,
671
+ FieldName extends string,
672
+ > = FieldStorageColumn<TContract, ModelName, FieldName> extends {
673
+ readonly nullable: infer N extends boolean;
674
+ }
675
+ ? N
676
+ : false;
677
+
685
678
  type FieldTraits<
686
679
  TContract extends Contract<SqlStorage>,
687
680
  ModelName extends string,
@@ -782,10 +775,6 @@ export type CreateInput<TContract extends Contract<SqlStorage>, ModelName extend
782
775
  > &
783
776
  RelationMutationFields<TContract, ModelName>;
784
777
 
785
- // ---------------------------------------------------------------------------
786
- // Polymorphic write gating
787
- // ---------------------------------------------------------------------------
788
-
789
778
  type IsPolymorphicBase<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
790
779
  TContract,
791
780
  ModelName
@@ -1057,10 +1046,6 @@ export type MutationUpdateInput<
1057
1046
  ModelName extends string,
1058
1047
  > = Partial<DefaultModelRow<TContract, ModelName>> & RelationMutationFields<TContract, ModelName>;
1059
1048
 
1060
- // ---------------------------------------------------------------------------
1061
- // Relation helpers
1062
- // ---------------------------------------------------------------------------
1063
-
1064
1049
  type ModelRelations<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
1065
1050
  TContract,
1066
1051
  ModelName
@@ -122,7 +122,10 @@ function createParamRef(
122
122
  if (!codecId) {
123
123
  throw new Error(`Unknown column "${columnRef.column}" in table "${columnRef.table}"`);
124
124
  }
125
- return ParamRef.of(value, { codecId });
125
+ return ParamRef.of(value, {
126
+ codecId,
127
+ refs: { table: columnRef.table, column: columnRef.column },
128
+ });
126
129
  }
127
130
 
128
131
  function createExpressionBinder(contract: Contract<SqlStorage>): ExpressionRewriter {
@@ -170,7 +173,12 @@ function bindSelectAst(contract: Contract<SqlStorage>, ast: SelectAst): SelectAs
170
173
  joins: ast.joins?.map((join) => bindJoin(contract, join)),
171
174
  projection: ast.projection.map(
172
175
  (projection) =>
173
- new ProjectionItem(projection.alias, bindProjectionExpr(contract, projection.expr)),
176
+ new ProjectionItem(
177
+ projection.alias,
178
+ bindProjectionExpr(contract, projection.expr),
179
+ projection.codecId,
180
+ projection.refs,
181
+ ),
174
182
  ),
175
183
  where: ast.where ? bindWhereExprNode(contract, ast.where) : undefined,
176
184
  orderBy: ast.orderBy?.map((orderItem) => bindOrderByItem(contract, orderItem)),