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

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.
@@ -7,6 +7,7 @@ import {
7
7
  LiteralExpr,
8
8
  } from '@prisma-next/sql-relational-core/ast';
9
9
  import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
10
+ import type { RuntimeScope } from '@prisma-next/sql-relational-core/types';
10
11
  import {
11
12
  getColumnToFieldMap,
12
13
  resolveFieldToColumn,
@@ -40,7 +41,6 @@ import type {
40
41
  RelationMutation,
41
42
  RelationMutator,
42
43
  RuntimeQueryable,
43
- RuntimeScope,
44
44
  } from './types';
45
45
  import { emptyState } from './types';
46
46
 
@@ -236,6 +236,15 @@ async function updateFirstGraph(
236
236
 
237
237
  const mappedUpdateData = mapModelDataToStorageRow(contract, modelName, scalarData);
238
238
  if (Object.keys(mappedUpdateData).length > 0) {
239
+ const tableName = resolveModelTableName(contract, modelName);
240
+ const appliedUpdateDefaults = context.applyMutationDefaults({
241
+ op: 'update',
242
+ table: tableName,
243
+ values: mappedUpdateData,
244
+ });
245
+ for (const def of appliedUpdateDefaults) {
246
+ mappedUpdateData[def.column] = def.value;
247
+ }
239
248
  const pkFilter = buildPrimaryKeyFilterFromRow(contract, modelName, existingRow);
240
249
  const pkWhere = shorthandToWhereExpr(
241
250
  context,
@@ -246,7 +255,6 @@ async function updateFirstGraph(
246
255
  throw new Error(`Failed to build primary key filter for model "${modelName}"`);
247
256
  }
248
257
 
249
- const tableName = resolveModelTableName(contract, modelName);
250
258
  const compiled = compileUpdateReturning(
251
259
  contract,
252
260
  tableName,
@@ -18,16 +18,30 @@ import { buildOrmQueryPlan, deriveParamsFromAst } from './query-plan-meta';
18
18
  import type { AggregateSelector } from './types';
19
19
  import { combineWhereExprs } from './where-utils';
20
20
 
21
- function toAggregateExpr(tableName: string, selector: AggregateSelector<unknown>): AggregateExpr {
21
+ function toAggregateProjection(
22
+ contract: Contract<SqlStorage>,
23
+ tableName: string,
24
+ selector: AggregateSelector<unknown>,
25
+ ): { expr: AggregateExpr; codecId: string | undefined } {
22
26
  if (selector.fn === 'count') {
23
- return AggregateExpr.count();
27
+ // count() returns a target-specific bigint; mapping isn't derivable here
28
+ // without target coupling, so we leave codecId unstamped.
29
+ return { expr: AggregateExpr.count(), codecId: undefined };
24
30
  }
25
31
 
26
32
  if (!selector.column) {
27
33
  throw new Error(`Aggregate selector "${selector.fn}" requires a field`);
28
34
  }
29
35
 
30
- return new AggregateExpr(selector.fn, ColumnRef.of(tableName, selector.column));
36
+ const expr = new AggregateExpr(selector.fn, ColumnRef.of(tableName, selector.column));
37
+ // min/max preserve the input column's type, so propagate the column codec.
38
+ // sum widens (int4 → int8 in Postgres) and avg → numeric; both need
39
+ // target+input-aware mapping that doesn't exist yet, so leave unstamped.
40
+ if (selector.fn === 'min' || selector.fn === 'max') {
41
+ const codecId = contract.storage.tables[tableName]?.columns[selector.column]?.codecId;
42
+ return { expr, codecId };
43
+ }
44
+ return { expr, codecId: undefined };
31
45
  }
32
46
 
33
47
  // ORM HAVING filters use literal binding (values inlined at plan-build time),
@@ -115,17 +129,18 @@ export function compileAggregate(
115
129
  throw new Error('aggregate() requires at least one aggregation selector');
116
130
  }
117
131
 
118
- const projection: ProjectionItem[] = entries.map(([alias, selector]) =>
119
- ProjectionItem.of(alias, toAggregateExpr(tableName, selector)),
120
- );
132
+ const projection: ProjectionItem[] = entries.map(([alias, selector]) => {
133
+ const { expr, codecId } = toAggregateProjection(contract, tableName, selector);
134
+ return ProjectionItem.of(alias, expr, codecId);
135
+ });
121
136
  let ast = SelectAst.from(TableSource.named(tableName)).withProjection(projection);
122
137
  const where = combineWhereExprs(filters);
123
138
  if (where) {
124
139
  ast = ast.withWhere(where);
125
140
  }
126
141
 
127
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
128
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
142
+ const { params } = deriveParamsFromAst(ast);
143
+ return buildOrmQueryPlan(contract, ast, params);
129
144
  }
130
145
 
131
146
  export function compileGroupedAggregate(
@@ -145,11 +160,15 @@ export function compileGroupedAggregate(
145
160
  throw new Error('groupBy().aggregate() requires at least one aggregation selector');
146
161
  }
147
162
 
163
+ const table = contract.storage.tables[tableName];
148
164
  const projection: ProjectionItem[] = [
149
- ...groupByColumns.map((column) => ProjectionItem.of(column, ColumnRef.of(tableName, column))),
150
- ...entries.map(([alias, selector]) =>
151
- ProjectionItem.of(alias, toAggregateExpr(tableName, selector)),
165
+ ...groupByColumns.map((column) =>
166
+ ProjectionItem.of(column, ColumnRef.of(tableName, column), table?.columns[column]?.codecId),
152
167
  ),
168
+ ...entries.map(([alias, selector]) => {
169
+ const { expr, codecId } = toAggregateProjection(contract, tableName, selector);
170
+ return ProjectionItem.of(alias, expr, codecId);
171
+ }),
153
172
  ];
154
173
 
155
174
  let ast = SelectAst.from(TableSource.named(tableName))
@@ -164,6 +183,6 @@ export function compileGroupedAggregate(
164
183
  ast = ast.withHaving(validateGroupedHavingExpr(havingExpr));
165
184
  }
166
185
 
167
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
168
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
186
+ const { params } = deriveParamsFromAst(ast);
187
+ return buildOrmQueryPlan(contract, ast, params);
169
188
  }
@@ -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(
@@ -47,7 +51,11 @@ function toParamAssignments(
47
51
  if (!codecId) {
48
52
  throw new Error(`Unknown column "${column}" in table "${tableName}"`);
49
53
  }
50
- 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
+ });
51
59
  }
52
60
 
53
61
  return { assignments };
@@ -93,7 +101,11 @@ function normalizeInsertRows(
93
101
  if (!codecId) {
94
102
  throw new Error(`Unknown column "${column}" in table "${tableName}"`);
95
103
  }
96
- 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
+ });
97
109
  continue;
98
110
  }
99
111
  normalizedRow[column] = new DefaultValueExpr();
@@ -114,8 +126,8 @@ export function compileInsertReturning(
114
126
  const ast = InsertAst.into(TableSource.named(tableName))
115
127
  .withRows(normalizedRows)
116
128
  .withReturning(buildReturningColumns(contract, tableName, returningColumns));
117
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
118
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
129
+ const { params } = deriveParamsFromAst(ast);
130
+ return buildOrmQueryPlan(contract, ast, params);
119
131
  }
120
132
 
121
133
  export function compileInsertCount(
@@ -125,8 +137,8 @@ export function compileInsertCount(
125
137
  ): SqlQueryPlan<Record<string, unknown>> {
126
138
  const { rows: normalizedRows } = normalizeInsertRows(contract, tableName, rows);
127
139
  const ast = InsertAst.into(TableSource.named(tableName)).withRows(normalizedRows);
128
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
129
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
140
+ const { params } = deriveParamsFromAst(ast);
141
+ return buildOrmQueryPlan(contract, ast, params);
130
142
  }
131
143
 
132
144
  function stripUndefinedValues(row: Record<string, unknown>): Record<string, unknown> {
@@ -139,11 +151,7 @@ function stripUndefinedValues(row: Record<string, unknown>): Record<string, unkn
139
151
  return result;
140
152
  }
141
153
 
142
- // Groups rows by their set of present columns so each group can be emitted as a
143
- // single INSERT statement. Groups are created in input order — rows with the same
144
- // signature that are non-adjacent produce separate groups. This is deliberate:
145
- // preserving insertion order ensures autogenerated/autoincrement columns are
146
- // 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.
147
155
  function groupRowsByColumnSignature(
148
156
  rows: readonly Record<string, unknown>[],
149
157
  ): ReadonlyArray<readonly Record<string, unknown>[]> {
@@ -224,8 +232,8 @@ export function compileUpsertReturning(
224
232
  .withOnConflict(onConflict)
225
233
  .withReturning(buildReturningColumns(contract, tableName, returningColumns));
226
234
 
227
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
228
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
235
+ const { params } = deriveParamsFromAst(ast);
236
+ return buildOrmQueryPlan(contract, ast, params);
229
237
  }
230
238
 
231
239
  export function compileUpdateReturning(
@@ -243,8 +251,8 @@ export function compileUpdateReturning(
243
251
  if (where) {
244
252
  ast = ast.withWhere(where);
245
253
  }
246
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
247
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
254
+ const { params } = deriveParamsFromAst(ast);
255
+ return buildOrmQueryPlan(contract, ast, params);
248
256
  }
249
257
 
250
258
  export function compileUpdateCount(
@@ -259,8 +267,8 @@ export function compileUpdateCount(
259
267
  if (where) {
260
268
  ast = ast.withWhere(where);
261
269
  }
262
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
263
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
270
+ const { params } = deriveParamsFromAst(ast);
271
+ return buildOrmQueryPlan(contract, ast, params);
264
272
  }
265
273
 
266
274
  export function compileDeleteReturning(
@@ -276,8 +284,8 @@ export function compileDeleteReturning(
276
284
  if (where) {
277
285
  ast = ast.withWhere(where);
278
286
  }
279
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
280
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
287
+ const { params } = deriveParamsFromAst(ast);
288
+ return buildOrmQueryPlan(contract, ast, params);
281
289
  }
282
290
 
283
291
  export function compileDeleteCount(
@@ -290,6 +298,6 @@ export function compileDeleteCount(
290
298
  if (where) {
291
299
  ast = ast.withWhere(where);
292
300
  }
293
- const { params, paramDescriptors } = deriveParamsFromAst(ast);
294
- return buildOrmQueryPlan(contract, ast, params, paramDescriptors);
301
+ const { params } = deriveParamsFromAst(ast);
302
+ return buildOrmQueryPlan(contract, ast, params);
295
303
  }
@@ -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
  }