@prisma-next/sql-orm-client 0.5.0-dev.60 → 0.5.0-dev.61

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/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@prisma-next/sql-orm-client",
3
- "version": "0.5.0-dev.60",
3
+ "version": "0.5.0-dev.61",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "ORM client for Prisma Next — fluent, type-safe model collections",
8
8
  "dependencies": {
9
- "@prisma-next/contract": "0.5.0-dev.60",
10
- "@prisma-next/framework-components": "0.5.0-dev.60",
11
- "@prisma-next/sql-relational-core": "0.5.0-dev.60",
12
- "@prisma-next/operations": "0.5.0-dev.60",
13
- "@prisma-next/sql-runtime": "0.5.0-dev.60",
14
- "@prisma-next/sql-operations": "0.5.0-dev.60",
15
- "@prisma-next/utils": "0.5.0-dev.60",
16
- "@prisma-next/sql-contract": "0.5.0-dev.60"
9
+ "@prisma-next/contract": "0.5.0-dev.61",
10
+ "@prisma-next/framework-components": "0.5.0-dev.61",
11
+ "@prisma-next/operations": "0.5.0-dev.61",
12
+ "@prisma-next/sql-operations": "0.5.0-dev.61",
13
+ "@prisma-next/sql-relational-core": "0.5.0-dev.61",
14
+ "@prisma-next/sql-contract": "0.5.0-dev.61",
15
+ "@prisma-next/utils": "0.5.0-dev.61",
16
+ "@prisma-next/sql-runtime": "0.5.0-dev.61"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/pg": "8.16.0",
@@ -21,17 +21,17 @@
21
21
  "tsdown": "0.18.4",
22
22
  "typescript": "5.9.3",
23
23
  "vitest": "4.0.17",
24
- "@prisma-next/adapter-postgres": "0.5.0-dev.60",
25
- "@prisma-next/driver-postgres": "0.5.0-dev.60",
26
- "@prisma-next/cli": "0.5.0-dev.60",
27
- "@prisma-next/ids": "0.5.0-dev.60",
28
- "@prisma-next/sql-contract-ts": "0.5.0-dev.60",
29
- "@prisma-next/target-postgres": "0.5.0-dev.60",
30
- "@prisma-next/family-sql": "0.5.0-dev.60",
31
- "@prisma-next/test-utils": "0.0.1",
24
+ "@prisma-next/adapter-postgres": "0.5.0-dev.61",
25
+ "@prisma-next/cli": "0.5.0-dev.61",
26
+ "@prisma-next/driver-postgres": "0.5.0-dev.61",
27
+ "@prisma-next/extension-pgvector": "0.5.0-dev.61",
28
+ "@prisma-next/family-sql": "0.5.0-dev.61",
29
+ "@prisma-next/sql-contract-ts": "0.5.0-dev.61",
30
+ "@prisma-next/ids": "0.5.0-dev.61",
31
+ "@prisma-next/target-postgres": "0.5.0-dev.61",
32
32
  "@prisma-next/tsconfig": "0.0.0",
33
33
  "@prisma-next/tsdown": "0.0.0",
34
- "@prisma-next/extension-pgvector": "0.5.0-dev.60"
34
+ "@prisma-next/test-utils": "0.0.1"
35
35
  },
36
36
  "files": [
37
37
  "dist",
@@ -51,7 +51,11 @@ function toParamAssignments(
51
51
  if (!codecId) {
52
52
  throw new Error(`Unknown column "${column}" in table "${tableName}"`);
53
53
  }
54
- assignments[column] = ParamRef.of(value, { name: column, codecId });
54
+ assignments[column] = ParamRef.of(value, {
55
+ name: column,
56
+ codecId,
57
+ refs: { table: tableName, column },
58
+ });
55
59
  }
56
60
 
57
61
  return { assignments };
@@ -97,7 +101,11 @@ function normalizeInsertRows(
97
101
  if (!codecId) {
98
102
  throw new Error(`Unknown column "${column}" in table "${tableName}"`);
99
103
  }
100
- normalizedRow[column] = ParamRef.of(row[column], { name: column, codecId });
104
+ normalizedRow[column] = ParamRef.of(row[column], {
105
+ name: column,
106
+ codecId,
107
+ refs: { table: tableName, column },
108
+ });
101
109
  continue;
102
110
  }
103
111
  normalizedRow[column] = new DefaultValueExpr();
@@ -143,11 +151,7 @@ function stripUndefinedValues(row: Record<string, unknown>): Record<string, unkn
143
151
  return result;
144
152
  }
145
153
 
146
- // Groups rows by their set of present columns so each group can be emitted as a
147
- // single INSERT statement. Groups are created in input order — rows with the same
148
- // signature that are non-adjacent produce separate groups. This is deliberate:
149
- // preserving insertion order ensures autogenerated/autoincrement columns are
150
- // assigned in the same order as the caller's input.
154
+ // Groups rows by their set of present columns so each group can be emitted as a single INSERT statement. Groups are created in input order — rows with the same signature that are non-adjacent produce separate groups. This is deliberate: preserving insertion order ensures autogenerated/autoincrement columns are assigned in the same order as the caller's input.
151
155
  function groupRowsByColumnSignature(
152
156
  rows: readonly Record<string, unknown>[],
153
157
  ): ReadonlyArray<readonly Record<string, unknown>[]> {
package/src/types.ts CHANGED
@@ -19,12 +19,9 @@ import {
19
19
  import type { Expression } from '@prisma-next/sql-relational-core/expression';
20
20
  import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
21
21
  import type { ComputeColumnJsType, RuntimeScope } from '@prisma-next/sql-relational-core/types';
22
+ import { ifDefined } from '@prisma-next/utils/defined';
22
23
  import type { RowSelection } from './collection-internal-types';
23
24
 
24
- // ---------------------------------------------------------------------------
25
- // Comparison / Filter / Order / Include
26
- // ---------------------------------------------------------------------------
27
-
28
25
  export type AggregateFn = 'count' | 'sum' | 'avg' | 'min' | 'max';
29
26
 
30
27
  export interface IncludeScalar<Result> extends RowSelection<Result> {
@@ -64,10 +61,6 @@ export interface IncludeExpr {
64
61
  readonly combine: Readonly<Record<string, IncludeCombineBranch>> | undefined;
65
62
  }
66
63
 
67
- // ---------------------------------------------------------------------------
68
- // CollectionState — plain data, no query builder types
69
- // ---------------------------------------------------------------------------
70
-
71
64
  export interface CollectionState {
72
65
  readonly filters: readonly AnyExpression[];
73
66
  readonly includes: readonly IncludeExpr[];
@@ -112,10 +105,6 @@ export type DefaultCollectionTypeState = {
112
105
  readonly variantName: undefined;
113
106
  };
114
107
 
115
- // ---------------------------------------------------------------------------
116
- // CollectionContext — bundles lane context + runtime
117
- // ---------------------------------------------------------------------------
118
-
119
108
  export interface RuntimeConnection extends RuntimeScope {
120
109
  release?(): Promise<void>;
121
110
  transaction?(): Promise<RuntimeTransaction>;
@@ -136,10 +125,6 @@ export interface CollectionContext<TContract extends Contract<SqlStorage>> {
136
125
  readonly context: ExecutionContext<TContract>;
137
126
  }
138
127
 
139
- // ---------------------------------------------------------------------------
140
- // ModelAccessor — type-safe proxy for where() callbacks
141
- // ---------------------------------------------------------------------------
142
-
143
128
  export type ComparisonMethodFns<T> = {
144
129
  eq(value: T): AnyExpression;
145
130
  neq(value: T): AnyExpression;
@@ -157,8 +142,7 @@ export type ComparisonMethodFns<T> = {
157
142
  };
158
143
 
159
144
  /**
160
- * Trait-gated comparison methods. Only methods whose required traits are
161
- * all present in `Traits` are included.
145
+ * Trait-gated comparison methods. Only methods whose required traits are all present in `Traits` are included.
162
146
  *
163
147
  * - `traits: []` → always available (isNull, isNotNull)
164
148
  */
@@ -168,10 +152,6 @@ export type ComparisonMethods<T, Traits> = {
168
152
  : never]: ComparisonMethodFns<T>[K];
169
153
  };
170
154
 
171
- // ---------------------------------------------------------------------------
172
- // Extension operation result — returned by calling an extension method
173
- // ---------------------------------------------------------------------------
174
-
175
155
  type QueryOperationReturnTraits<
176
156
  Returns,
177
157
  TCodecTypes extends Record<string, unknown>,
@@ -209,9 +189,7 @@ type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Ret
209
189
  : false;
210
190
 
211
191
  /**
212
- * Extract the `{codecId, nullable}` spec carried inside an `Expression<T>`.
213
- * Used to recover the op's return spec from its impl signature so the
214
- * pre-existing `QueryOperationReturn*` helpers can consume it unchanged.
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.
215
193
  */
216
194
  type SpecOf<E> = E extends Expression<infer T> ? T : never;
217
195
 
@@ -220,14 +198,8 @@ type ImplReturnSpec<Impl> = Impl extends (...args: never[]) => infer Ret ? SpecO
220
198
  /**
221
199
  * Builds the ORM column-method signature for an operation.
222
200
  *
223
- * - User args: drops the impl's first parameter (the column is bound at access
224
- * time) and forwards the rest unchanged. Each remaining arg keeps its
225
- * authored `CodecExpression` / `TraitExpression` shape — so callers can pass
226
- * a raw JS value, another column handle (which itself implements
227
- * `Expression`), or `null` when nullable.
228
- * - Return: predicate ops (boolean-traited return) yield `AnyExpression`;
229
- * non-predicate ops yield `ComparisonMethods<JsType, Traits>` of the return
230
- * codec.
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.
231
203
  */
232
204
  type QueryOperationMethod<Op, TCodecTypes extends Record<string, unknown>> = Op extends {
233
205
  readonly impl: (...args: never[]) => unknown;
@@ -247,9 +219,7 @@ type QueryOperationMethod<Op, TCodecTypes extends Record<string, unknown>> = Op
247
219
  : never;
248
220
 
249
221
  /**
250
- * Tests whether an operation's `self` dispatch hint reaches a field with the
251
- * given codec identity. Codec hints match by identity; trait hints match when
252
- * every required trait is present in the field codec's trait set.
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.
253
223
  */
254
224
  type OpMatchesField<Op, CodecId extends string, CT extends Record<string, unknown>> = Op extends {
255
225
  readonly self: infer Self;
@@ -285,21 +255,43 @@ type FieldOperations<
285
255
  : unknown
286
256
  : unknown;
287
257
 
288
- // ---------------------------------------------------------------------------
289
- // COMPARISON_METHODS_METAsingle source of truth for traits + factories
290
- // ---------------------------------------------------------------------------
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
+ }
291
273
 
292
- function param(codecId: string | undefined, value: unknown): ParamRef {
293
- 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
+ });
294
284
  }
295
285
 
296
- function paramList(codecId: string | undefined, values: readonly unknown[]): ListExpression {
297
- 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)));
298
292
  }
299
293
 
300
- // never[] is intentional: factories have heterogeneous signatures (value: unknown,
301
- // values: readonly unknown[], pattern: string, etc.) but are only called through
302
- // 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.
303
295
  type MethodFactory = (
304
296
  left: AnyExpression,
305
297
  codecId: string | undefined,
@@ -312,12 +304,16 @@ type ComparisonMethodMeta = {
312
304
 
313
305
  function scalarComparisonMethod(op: BinaryOp) {
314
306
  return ((left, codecId) => (value: unknown) =>
315
- new BinaryExpr(op, left, param(codecId, value))) satisfies MethodFactory;
307
+ new BinaryExpr(op, left, param(codecId, value, refsFromLeft(left)))) satisfies MethodFactory;
316
308
  }
317
309
 
318
310
  function listComparisonMethod(op: BinaryOp) {
319
311
  return ((left, codecId) => (values: readonly unknown[]) =>
320
- 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;
321
317
  }
322
318
 
323
319
  /**
@@ -422,18 +418,10 @@ export type ModelAccessor<
422
418
  ModelName extends string,
423
419
  > = ScalarModelAccessor<TContract, ModelName> & RelationModelAccessor<TContract, ModelName>;
424
420
 
425
- // ---------------------------------------------------------------------------
426
- // DefaultModelRow — all scalar fields with JS types
427
- // ---------------------------------------------------------------------------
428
-
429
421
  export type DefaultModelRow<TContract extends Contract<SqlStorage>, ModelName extends string> = {
430
422
  [K in keyof FieldsOf<TContract, ModelName> & string]: FieldJsType<TContract, ModelName, K>;
431
423
  };
432
424
 
433
- // ---------------------------------------------------------------------------
434
- // InferRootRow — discriminated union for polymorphic base models
435
- // ---------------------------------------------------------------------------
436
-
437
425
  type Simplify<T> = { [K in keyof T]: T[K] } & {};
438
426
 
439
427
  type VariantRow<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
@@ -554,10 +542,6 @@ export type ShorthandWhereFilter<
554
542
  | undefined;
555
543
  }>;
556
544
 
557
- // ---------------------------------------------------------------------------
558
- // Helpers for extracting fields / types from the contract
559
- // ---------------------------------------------------------------------------
560
-
561
545
  type ModelsOf<TContract extends Contract<SqlStorage>> =
562
546
  TContract['models'] extends Record<string, unknown> ? TContract['models'] : Record<string, never>;
563
547
 
@@ -671,10 +655,6 @@ type FieldStorageColumn<
671
655
  FieldName extends string,
672
656
  > = ResolvedStorageColumn<TContract, ModelName, FieldName>;
673
657
 
674
- // ---------------------------------------------------------------------------
675
- // Field trait resolution from contract CodecTypes
676
- // ---------------------------------------------------------------------------
677
-
678
658
  type FieldCodecId<
679
659
  TContract extends Contract<SqlStorage>,
680
660
  ModelName extends string,
@@ -795,10 +775,6 @@ export type CreateInput<TContract extends Contract<SqlStorage>, ModelName extend
795
775
  > &
796
776
  RelationMutationFields<TContract, ModelName>;
797
777
 
798
- // ---------------------------------------------------------------------------
799
- // Polymorphic write gating
800
- // ---------------------------------------------------------------------------
801
-
802
778
  type IsPolymorphicBase<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
803
779
  TContract,
804
780
  ModelName
@@ -1070,10 +1046,6 @@ export type MutationUpdateInput<
1070
1046
  ModelName extends string,
1071
1047
  > = Partial<DefaultModelRow<TContract, ModelName>> & RelationMutationFields<TContract, ModelName>;
1072
1048
 
1073
- // ---------------------------------------------------------------------------
1074
- // Relation helpers
1075
- // ---------------------------------------------------------------------------
1076
-
1077
1049
  type ModelRelations<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
1078
1050
  TContract,
1079
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 {
@@ -174,6 +177,7 @@ function bindSelectAst(contract: Contract<SqlStorage>, ast: SelectAst): SelectAs
174
177
  projection.alias,
175
178
  bindProjectionExpr(contract, projection.expr),
176
179
  projection.codecId,
180
+ projection.refs,
177
181
  ),
178
182
  ),
179
183
  where: ast.where ? bindWhereExprNode(contract, ast.where) : undefined,