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

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.
@@ -1,53 +1,13 @@
1
- import type { Contract, ParamDescriptor, PlanMeta } from '@prisma-next/contract/types';
1
+ import type { Contract, PlanMeta } from '@prisma-next/contract/types';
2
2
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
- import type { AnyQueryAst, ParamRef } from '@prisma-next/sql-relational-core/ast';
3
+ import { type AnyQueryAst, collectOrderedParamRefs } from '@prisma-next/sql-relational-core/ast';
4
4
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
5
- import { ifDefined } from '@prisma-next/utils/defined';
6
5
 
7
- function resolveProjectionCodecs(
8
- contract: Contract<SqlStorage>,
9
- ast: AnyQueryAst,
10
- ): Record<string, string> | undefined {
11
- const codecs: Record<string, string> = {};
12
-
13
- if (ast.kind === 'select') {
14
- for (const item of ast.projection) {
15
- if (item.expr.kind === 'column-ref') {
16
- const table = contract.storage.tables[item.expr.table];
17
- const col = table?.columns[item.expr.column];
18
- if (col?.codecId) {
19
- codecs[item.alias] = col.codecId;
20
- }
21
- }
22
- }
23
- } else if (ast.returning) {
24
- const tableName = ast.table.name;
25
- const table = contract.storage.tables[tableName];
26
- if (!table) return undefined;
27
-
28
- for (const colRef of ast.returning) {
29
- const col = table.columns[colRef.column];
30
- if (col?.codecId) {
31
- codecs[colRef.column] = col.codecId;
32
- }
33
- }
34
- }
35
-
36
- return Object.keys(codecs).length > 0 ? codecs : undefined;
37
- }
38
-
39
- export function deriveParamsFromAst(ast: { collectParamRefs(): ParamRef[] }): {
6
+ export function deriveParamsFromAst(ast: AnyQueryAst): {
40
7
  params: unknown[];
41
- paramDescriptors: ParamDescriptor[];
42
8
  } {
43
- const collectedParams = [...new Set(ast.collectParamRefs())];
44
9
  return {
45
- params: collectedParams.map((p) => p.value),
46
- paramDescriptors: collectedParams.map((p) => ({
47
- ...ifDefined('name', p.name),
48
- ...ifDefined('codecId', p.codecId),
49
- source: 'dsl' as const,
50
- })),
10
+ params: collectOrderedParamRefs(ast).map((p) => p.value),
51
11
  };
52
12
  }
53
13
 
@@ -59,17 +19,13 @@ export function resolveTableColumns(contract: Contract<SqlStorage>, tableName: s
59
19
  return Object.keys(table.columns);
60
20
  }
61
21
 
62
- export function buildOrmPlanMeta(
63
- contract: Contract<SqlStorage>,
64
- paramDescriptors: readonly ParamDescriptor[] = [],
65
- ): PlanMeta {
22
+ export function buildOrmPlanMeta(contract: Contract<SqlStorage>): PlanMeta {
66
23
  return {
67
24
  target: contract.target,
68
25
  targetFamily: contract.targetFamily,
69
26
  storageHash: contract.storage.storageHash,
70
27
  ...(contract.profileHash !== undefined ? { profileHash: contract.profileHash } : {}),
71
28
  lane: 'orm-client',
72
- paramDescriptors: [...paramDescriptors],
73
29
  };
74
30
  }
75
31
 
@@ -77,26 +33,10 @@ export function buildOrmQueryPlan<Row>(
77
33
  contract: Contract<SqlStorage>,
78
34
  ast: AnyQueryAst,
79
35
  params: readonly unknown[],
80
- paramDescriptors: readonly ParamDescriptor[] = [],
81
36
  ): SqlQueryPlan<Row> {
82
- const projectionTypes = resolveProjectionCodecs(contract, ast);
83
- const codecAnnotations = projectionTypes
84
- ? { codecs: Object.freeze({ ...projectionTypes }) }
85
- : undefined;
86
- const limitAnnotation =
87
- ast.kind === 'select' && ast.limit !== undefined ? { limit: ast.limit } : undefined;
88
- const annotations =
89
- codecAnnotations || limitAnnotation
90
- ? Object.freeze({ ...codecAnnotations, ...limitAnnotation })
91
- : undefined;
92
-
93
37
  return Object.freeze({
94
38
  ast,
95
39
  params: [...params],
96
- meta: {
97
- ...buildOrmPlanMeta(contract, paramDescriptors),
98
- ...ifDefined('projectionTypes', projectionTypes),
99
- ...ifDefined('annotations', annotations),
100
- },
40
+ meta: buildOrmPlanMeta(contract),
101
41
  });
102
42
  }
@@ -8,6 +8,7 @@ import {
8
8
  InsertAst,
9
9
  InsertOnConflict,
10
10
  ParamRef,
11
+ ProjectionItem,
11
12
  TableSource,
12
13
  UpdateAst,
13
14
  } from '@prisma-next/sql-relational-core/ast';
@@ -19,13 +20,16 @@ function buildReturningColumns(
19
20
  contract: Contract<SqlStorage>,
20
21
  tableName: string,
21
22
  returningColumns: readonly string[] | undefined,
22
- ) {
23
+ ): ReadonlyArray<ProjectionItem> {
23
24
  const columns =
24
25
  returningColumns && returningColumns.length > 0
25
26
  ? [...returningColumns]
26
27
  : resolveTableColumns(contract, tableName);
27
28
 
28
- return columns.map((column) => ColumnRef.of(tableName, column));
29
+ const table = contract.storage.tables[tableName];
30
+ return columns.map((column) =>
31
+ ProjectionItem.of(column, ColumnRef.of(tableName, column), table?.columns[column]?.codecId),
32
+ );
29
33
  }
30
34
 
31
35
  function toParamAssignments(
@@ -114,8 +118,8 @@ export function compileInsertReturning(
114
118
  const ast = InsertAst.into(TableSource.named(tableName))
115
119
  .withRows(normalizedRows)
116
120
  .withReturning(buildReturningColumns(contract, tableName, returningColumns));
117
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
118
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
121
+ const { params } = deriveParamsFromAst(ast);
122
+ return buildOrmQueryPlan(contract, ast, params);
119
123
  }
120
124
 
121
125
  export function compileInsertCount(
@@ -125,8 +129,8 @@ export function compileInsertCount(
125
129
  ): SqlQueryPlan<Record<string, unknown>> {
126
130
  const { rows: normalizedRows } = normalizeInsertRows(contract, tableName, rows);
127
131
  const ast = InsertAst.into(TableSource.named(tableName)).withRows(normalizedRows);
128
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
129
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
132
+ const { params } = deriveParamsFromAst(ast);
133
+ return buildOrmQueryPlan(contract, ast, params);
130
134
  }
131
135
 
132
136
  function stripUndefinedValues(row: Record<string, unknown>): Record<string, unknown> {
@@ -224,8 +228,8 @@ export function compileUpsertReturning(
224
228
  .withOnConflict(onConflict)
225
229
  .withReturning(buildReturningColumns(contract, tableName, returningColumns));
226
230
 
227
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
228
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
231
+ const { params } = deriveParamsFromAst(ast);
232
+ return buildOrmQueryPlan(contract, ast, params);
229
233
  }
230
234
 
231
235
  export function compileUpdateReturning(
@@ -243,8 +247,8 @@ export function compileUpdateReturning(
243
247
  if (where) {
244
248
  ast = ast.withWhere(where);
245
249
  }
246
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
247
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
250
+ const { params } = deriveParamsFromAst(ast);
251
+ return buildOrmQueryPlan(contract, ast, params);
248
252
  }
249
253
 
250
254
  export function compileUpdateCount(
@@ -259,8 +263,8 @@ export function compileUpdateCount(
259
263
  if (where) {
260
264
  ast = ast.withWhere(where);
261
265
  }
262
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
263
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
266
+ const { params } = deriveParamsFromAst(ast);
267
+ return buildOrmQueryPlan(contract, ast, params);
264
268
  }
265
269
 
266
270
  export function compileDeleteReturning(
@@ -276,8 +280,8 @@ export function compileDeleteReturning(
276
280
  if (where) {
277
281
  ast = ast.withWhere(where);
278
282
  }
279
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
280
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
283
+ const { params } = deriveParamsFromAst(ast);
284
+ return buildOrmQueryPlan(contract, ast, params);
281
285
  }
282
286
 
283
287
  export function compileDeleteCount(
@@ -290,6 +294,6 @@ export function compileDeleteCount(
290
294
  if (where) {
291
295
  ast = ast.withWhere(where);
292
296
  }
293
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
294
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
297
+ const { params } = deriveParamsFromAst(ast);
298
+ return buildOrmQueryPlan(contract, ast, params);
295
299
  }
@@ -49,7 +49,10 @@ function buildProjection(
49
49
  ? [...selectedFields]
50
50
  : resolveTableColumns(contract, tableName);
51
51
 
52
- return columns.map((column) => ProjectionItem.of(column, ColumnRef.of(tableRef, column)));
52
+ const table = contract.storage.tables[tableName];
53
+ return columns.map((column) =>
54
+ ProjectionItem.of(column, ColumnRef.of(tableRef, column), table?.columns[column]?.codecId),
55
+ );
53
56
  }
54
57
 
55
58
  function createBoundaryExpr(tableName: string, entry: CursorOrderEntry): AnyExpression {
@@ -403,10 +406,17 @@ function buildMtiJoins(
403
406
  joins.push(join);
404
407
 
405
408
  const variantColumns = resolveTableColumns(contract, variant.table);
409
+ const variantTable = contract.storage.tables[variant.table];
406
410
  for (const col of variantColumns) {
407
411
  if (col === pkColumn) continue;
408
412
  const alias = `${variant.table}__${col}`;
409
- projection.push(ProjectionItem.of(alias, ColumnRef.of(variant.table, col)));
413
+ projection.push(
414
+ ProjectionItem.of(
415
+ alias,
416
+ ColumnRef.of(variant.table, col),
417
+ variantTable?.columns[col]?.codecId,
418
+ ),
419
+ );
410
420
  }
411
421
  }
412
422
 
@@ -437,8 +447,8 @@ export function compileSelect(
437
447
  : undefined,
438
448
  );
439
449
 
440
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
441
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
450
+ const { params } = deriveParamsFromAst(ast);
451
+ return buildOrmQueryPlan(contract, ast, params);
442
452
  }
443
453
 
444
454
  export function compileRelationSelect(
@@ -513,6 +523,6 @@ export function compileSelectWithIncludeStrategy(
513
523
  },
514
524
  );
515
525
 
516
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
517
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
526
+ const { params } = deriveParamsFromAst(ast);
527
+ return buildOrmQueryPlan(contract, ast, params);
518
528
  }
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,9 +16,9 @@ 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';
23
22
  import type { RowSelection } from './collection-internal-types';
24
23
 
25
24
  // ---------------------------------------------------------------------------
@@ -117,12 +116,6 @@ export type DefaultCollectionTypeState = {
117
116
  // CollectionContext — bundles lane context + runtime
118
117
  // ---------------------------------------------------------------------------
119
118
 
120
- export interface RuntimeScope {
121
- execute<Row = Record<string, unknown>>(
122
- plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
123
- ): AsyncIterableResult<Row>;
124
- }
125
-
126
119
  export interface RuntimeConnection extends RuntimeScope {
127
120
  release?(): Promise<void>;
128
121
  transaction?(): Promise<RuntimeTransaction>;
@@ -203,26 +196,6 @@ type QueryOperationReturnJsType<
203
196
  : unknown
204
197
  : unknown;
205
198
 
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
199
  type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Returns extends {
227
200
  readonly codecId: infer Id extends string;
228
201
  }
@@ -235,22 +208,51 @@ type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Ret
235
208
  : false
236
209
  : false;
237
210
 
211
+ /**
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.
215
+ */
216
+ type SpecOf<E> = E extends Expression<infer T> ? T : never;
217
+
218
+ type ImplReturnSpec<Impl> = Impl extends (...args: never[]) => infer Ret ? SpecOf<Ret> : never;
219
+
220
+ /**
221
+ * Builds the ORM column-method signature for an operation.
222
+ *
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.
231
+ */
238
232
  type QueryOperationMethod<Op, TCodecTypes extends Record<string, unknown>> = Op extends {
239
- readonly args: readonly [unknown, ...infer UserArgs];
240
- readonly returns: infer Returns;
233
+ readonly impl: (...args: never[]) => unknown;
241
234
  }
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
- >
235
+ ? Op['impl'] extends (first: never, ...rest: infer UserArgs extends readonly unknown[]) => unknown
236
+ ? ImplReturnSpec<Op['impl']> extends infer Returns
237
+ ? IsBooleanReturn<Returns, TCodecTypes> extends true
238
+ ? (...args: UserArgs) => AnyExpression
239
+ : (
240
+ ...args: UserArgs
241
+ ) => ComparisonMethods<
242
+ QueryOperationReturnJsType<Returns, TCodecTypes>,
243
+ QueryOperationReturnTraits<Returns, TCodecTypes>
244
+ >
245
+ : never
246
+ : never
250
247
  : never;
251
248
 
249
+ /**
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.
253
+ */
252
254
  type OpMatchesField<Op, CodecId extends string, CT extends Record<string, unknown>> = Op extends {
253
- readonly args: readonly [infer Self, ...(readonly unknown[])];
255
+ readonly self: infer Self;
254
256
  }
255
257
  ? Self extends { readonly codecId: CodecId }
256
258
  ? true
@@ -400,10 +402,11 @@ export type RelationFilterAccessor<
400
402
  };
401
403
 
402
404
  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
- > &
405
+ [K in keyof FieldsOf<TContract, ModelName> & string]: Expression<{
406
+ codecId: FieldCodecId<TContract, ModelName, K>;
407
+ nullable: FieldNullable<TContract, ModelName, K>;
408
+ }> &
409
+ ComparisonMethods<FieldJsType<TContract, ModelName, K>, FieldTraits<TContract, ModelName, K>> &
407
410
  FieldOperations<TContract, ModelName, K>;
408
411
  };
409
412
 
@@ -682,6 +685,16 @@ type FieldCodecId<
682
685
  ? Id
683
686
  : never;
684
687
 
688
+ type FieldNullable<
689
+ TContract extends Contract<SqlStorage>,
690
+ ModelName extends string,
691
+ FieldName extends string,
692
+ > = FieldStorageColumn<TContract, ModelName, FieldName> extends {
693
+ readonly nullable: infer N extends boolean;
694
+ }
695
+ ? N
696
+ : false;
697
+
685
698
  type FieldTraits<
686
699
  TContract extends Contract<SqlStorage>,
687
700
  ModelName extends string,
@@ -170,7 +170,11 @@ function bindSelectAst(contract: Contract<SqlStorage>, ast: SelectAst): SelectAs
170
170
  joins: ast.joins?.map((join) => bindJoin(contract, join)),
171
171
  projection: ast.projection.map(
172
172
  (projection) =>
173
- new ProjectionItem(projection.alias, bindProjectionExpr(contract, projection.expr)),
173
+ new ProjectionItem(
174
+ projection.alias,
175
+ bindProjectionExpr(contract, projection.expr),
176
+ projection.codecId,
177
+ ),
174
178
  ),
175
179
  where: ast.where ? bindWhereExprNode(contract, ast.where) : undefined,
176
180
  orderBy: ast.orderBy?.map((orderItem) => bindOrderByItem(contract, orderItem)),