@prisma-next/sql-orm-lane 0.3.0-dev.1 → 0.3.0-dev.11

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.
Files changed (83) hide show
  1. package/README.md +2 -2
  2. package/dist/exports/orm.d.ts +3 -5
  3. package/dist/exports/orm.d.ts.map +1 -0
  4. package/dist/index.d.ts +4 -42
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/mutations/delete-builder.d.ts +9 -0
  7. package/dist/mutations/delete-builder.d.ts.map +1 -0
  8. package/dist/mutations/insert-builder.d.ts +7 -0
  9. package/dist/mutations/insert-builder.d.ts.map +1 -0
  10. package/dist/mutations/update-builder.d.ts +9 -0
  11. package/dist/mutations/update-builder.d.ts.map +1 -0
  12. package/dist/orm/builder.d.ts +38 -0
  13. package/dist/orm/builder.d.ts.map +1 -0
  14. package/dist/orm/capabilities.d.ts +3 -0
  15. package/dist/orm/capabilities.d.ts.map +1 -0
  16. package/dist/orm/context.d.ts +5 -0
  17. package/dist/orm/context.d.ts.map +1 -0
  18. package/dist/orm/state.d.ts +45 -0
  19. package/dist/orm/state.d.ts.map +1 -0
  20. package/dist/orm-include-child.d.ts +35 -0
  21. package/dist/orm-include-child.d.ts.map +1 -0
  22. package/dist/orm-relation-filter.d.ts +19 -0
  23. package/dist/orm-relation-filter.d.ts.map +1 -0
  24. package/dist/{orm-DAnGd7z2.d.ts → orm-types.d.ts} +16 -27
  25. package/dist/orm-types.d.ts.map +1 -0
  26. package/dist/orm.d.ts +5 -0
  27. package/dist/orm.d.ts.map +1 -0
  28. package/dist/plan/lowering.d.ts +2 -0
  29. package/dist/plan/lowering.d.ts.map +1 -0
  30. package/dist/plan/plan-assembly.d.ts +24 -0
  31. package/dist/plan/plan-assembly.d.ts.map +1 -0
  32. package/dist/plan/result-typing.d.ts +2 -0
  33. package/dist/plan/result-typing.d.ts.map +1 -0
  34. package/dist/relations/include-plan.d.ts +38 -0
  35. package/dist/relations/include-plan.d.ts.map +1 -0
  36. package/dist/selection/join.d.ts +3 -0
  37. package/dist/selection/join.d.ts.map +1 -0
  38. package/dist/selection/ordering.d.ts +11 -0
  39. package/dist/selection/ordering.d.ts.map +1 -0
  40. package/dist/selection/pagination.d.ts +6 -0
  41. package/dist/selection/pagination.d.ts.map +1 -0
  42. package/dist/selection/predicates.d.ts +10 -0
  43. package/dist/selection/predicates.d.ts.map +1 -0
  44. package/dist/selection/projection.d.ts +28 -0
  45. package/dist/selection/projection.d.ts.map +1 -0
  46. package/dist/selection/select-builder.d.ts +22 -0
  47. package/dist/selection/select-builder.d.ts.map +1 -0
  48. package/dist/types/internal.d.ts +4 -0
  49. package/dist/types/internal.d.ts.map +1 -0
  50. package/dist/utils/ast.d.ts +2 -0
  51. package/dist/utils/ast.d.ts.map +1 -0
  52. package/dist/utils/errors.d.ts +29 -0
  53. package/dist/utils/errors.d.ts.map +1 -0
  54. package/dist/utils/param-descriptor.d.ts +10 -0
  55. package/dist/utils/param-descriptor.d.ts.map +1 -0
  56. package/package.json +16 -16
  57. package/src/exports/orm.ts +12 -0
  58. package/src/index.ts +11 -0
  59. package/src/mutations/delete-builder.ts +87 -0
  60. package/src/mutations/insert-builder.ts +148 -0
  61. package/src/mutations/update-builder.ts +141 -0
  62. package/src/orm/builder.ts +744 -0
  63. package/src/orm/capabilities.ts +14 -0
  64. package/src/orm/context.ts +10 -0
  65. package/src/orm/state.ts +52 -0
  66. package/src/orm-include-child.ts +169 -0
  67. package/src/orm-relation-filter.ts +93 -0
  68. package/src/orm-types.ts +271 -0
  69. package/src/orm.ts +51 -0
  70. package/src/plan/lowering.ts +1 -0
  71. package/src/plan/plan-assembly.ts +297 -0
  72. package/src/plan/result-typing.ts +1 -0
  73. package/src/relations/include-plan.ts +324 -0
  74. package/src/selection/join.ts +13 -0
  75. package/src/selection/ordering.ts +52 -0
  76. package/src/selection/pagination.ts +11 -0
  77. package/src/selection/predicates.ts +120 -0
  78. package/src/selection/projection.ts +136 -0
  79. package/src/selection/select-builder.ts +82 -0
  80. package/src/types/internal.ts +3 -0
  81. package/src/utils/ast.ts +12 -0
  82. package/src/utils/errors.ts +130 -0
  83. package/src/utils/param-descriptor.ts +19 -0
@@ -0,0 +1,297 @@
1
+ import type { ExecutionPlan, ParamDescriptor, PlanMeta } from '@prisma-next/contract/types';
2
+ import { planInvalid } from '@prisma-next/plan';
3
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
4
+ import type {
5
+ BinaryExpr,
6
+ ExistsExpr,
7
+ LoweredStatement,
8
+ OperationExpr,
9
+ SelectAst,
10
+ TableRef,
11
+ } from '@prisma-next/sql-relational-core/ast';
12
+ import { compact } from '@prisma-next/sql-relational-core/ast';
13
+ import type {
14
+ AnyColumnBuilder,
15
+ AnyOrderBuilder,
16
+ BinaryBuilder,
17
+ } from '@prisma-next/sql-relational-core/types';
18
+ import {
19
+ collectColumnRefs,
20
+ getColumnInfo,
21
+ getColumnMeta,
22
+ isOperationExpr,
23
+ } from '@prisma-next/sql-relational-core/utils/guards';
24
+ import type { IncludeState } from '../relations/include-plan';
25
+ import type { ProjectionState } from '../selection/projection';
26
+
27
+ export interface MetaBuildArgs {
28
+ readonly contract: SqlContract<SqlStorage>;
29
+ readonly table: TableRef;
30
+ readonly projection: ProjectionState;
31
+ readonly includes?: ReadonlyArray<IncludeState>;
32
+ readonly where?: BinaryBuilder;
33
+ readonly orderBy?: AnyOrderBuilder;
34
+ readonly paramDescriptors: ParamDescriptor[];
35
+ readonly paramCodecs?: Record<string, string>;
36
+ }
37
+
38
+ export function buildMeta(args: MetaBuildArgs): PlanMeta {
39
+ const refsColumns = new Map<string, { table: string; column: string }>();
40
+ const refsTables = new Set<string>([args.table.name]);
41
+
42
+ for (const column of args.projection.columns) {
43
+ const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
44
+ if (operationExpr) {
45
+ const allRefs = collectColumnRefs(operationExpr);
46
+ for (const ref of allRefs) {
47
+ refsColumns.set(`${ref.table}.${ref.column}`, {
48
+ table: ref.table,
49
+ column: ref.column,
50
+ });
51
+ }
52
+ } else {
53
+ const col = column as unknown as { table?: string; column?: string };
54
+ if (col.table && col.column) {
55
+ refsColumns.set(`${col.table}.${col.column}`, {
56
+ table: col.table,
57
+ column: col.column,
58
+ });
59
+ }
60
+ }
61
+ }
62
+
63
+ if (args.includes) {
64
+ for (const include of args.includes) {
65
+ refsTables.add(include.table.name);
66
+ const onLeft = include.on.left as unknown as { table: string; column: string };
67
+ const onRight = include.on.right as unknown as { table: string; column: string };
68
+ if (onLeft.table && onLeft.column && onRight.table && onRight.column) {
69
+ refsColumns.set(`${onLeft.table}.${onLeft.column}`, {
70
+ table: onLeft.table,
71
+ column: onLeft.column,
72
+ });
73
+ refsColumns.set(`${onRight.table}.${onRight.column}`, {
74
+ table: onRight.table,
75
+ column: onRight.column,
76
+ });
77
+ }
78
+ for (const column of include.childProjection.columns) {
79
+ const col = column as unknown as { table?: string; column?: string };
80
+ if (col.table && col.column) {
81
+ refsColumns.set(`${col.table}.${col.column}`, {
82
+ table: col.table,
83
+ column: col.column,
84
+ });
85
+ }
86
+ }
87
+ if (include.childWhere) {
88
+ const colInfo = getColumnInfo(include.childWhere.left);
89
+ refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
90
+ table: colInfo.table,
91
+ column: colInfo.column,
92
+ });
93
+ }
94
+ if (include.childOrderBy) {
95
+ const orderBy = include.childOrderBy as unknown as {
96
+ expr?: AnyColumnBuilder | OperationExpr;
97
+ };
98
+ if (orderBy.expr) {
99
+ const colInfo = getColumnInfo(orderBy.expr);
100
+ refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
101
+ table: colInfo.table,
102
+ column: colInfo.column,
103
+ });
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ if (args.where) {
110
+ const whereLeft = args.where.left;
111
+ const operationExpr = (whereLeft as { _operationExpr?: OperationExpr })._operationExpr;
112
+ if (operationExpr) {
113
+ const allRefs = collectColumnRefs(operationExpr);
114
+ for (const ref of allRefs) {
115
+ refsColumns.set(`${ref.table}.${ref.column}`, {
116
+ table: ref.table,
117
+ column: ref.column,
118
+ });
119
+ }
120
+ } else {
121
+ const colBuilder = whereLeft as unknown as { table?: string; column?: string };
122
+ if (colBuilder.table && colBuilder.column) {
123
+ refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
124
+ table: colBuilder.table,
125
+ column: colBuilder.column,
126
+ });
127
+ }
128
+ }
129
+ }
130
+
131
+ if (args.orderBy) {
132
+ const orderBy = args.orderBy as unknown as {
133
+ expr?: AnyColumnBuilder | OperationExpr;
134
+ };
135
+ const orderByExpr = orderBy.expr;
136
+ if (orderByExpr) {
137
+ if (isOperationExpr(orderByExpr)) {
138
+ const allRefs = collectColumnRefs(orderByExpr);
139
+ for (const ref of allRefs) {
140
+ refsColumns.set(`${ref.table}.${ref.column}`, {
141
+ table: ref.table,
142
+ column: ref.column,
143
+ });
144
+ }
145
+ } else {
146
+ const colBuilder = orderByExpr as unknown as { table?: string; column?: string };
147
+ if (colBuilder.table && colBuilder.column) {
148
+ refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
149
+ table: colBuilder.table,
150
+ column: colBuilder.column,
151
+ });
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ const includeAliases = new Set(args.includes?.map((inc) => inc.alias) ?? []);
158
+ const projectionMap = Object.fromEntries(
159
+ args.projection.aliases.map((alias, index) => {
160
+ if (includeAliases.has(alias)) {
161
+ return [alias, `include:${alias}`];
162
+ }
163
+ const column = args.projection.columns[index];
164
+ if (!column) {
165
+ throw planInvalid(`Missing column for alias ${alias} at index ${index}`);
166
+ }
167
+ const col = column as unknown as {
168
+ table?: string;
169
+ column?: string;
170
+ _operationExpr?: OperationExpr;
171
+ };
172
+ if (!col.table || !col.column) {
173
+ return [alias, `include:${alias}`];
174
+ }
175
+ const operationExpr = col._operationExpr;
176
+ if (operationExpr) {
177
+ return [alias, `operation:${operationExpr.method}`];
178
+ }
179
+ return [alias, `${col.table}.${col.column}`];
180
+ }),
181
+ );
182
+
183
+ const projectionTypes: Record<string, string> = {};
184
+ for (let i = 0; i < args.projection.aliases.length; i++) {
185
+ const alias = args.projection.aliases[i];
186
+ if (!alias || includeAliases.has(alias)) {
187
+ continue;
188
+ }
189
+ const col = args.projection.columns[i];
190
+ if (!col) {
191
+ continue;
192
+ }
193
+ const operationExpr = (col as { _operationExpr?: OperationExpr })._operationExpr;
194
+ if (operationExpr) {
195
+ if (operationExpr.returns.kind === 'typeId') {
196
+ projectionTypes[alias] = operationExpr.returns.type;
197
+ } else if (operationExpr.returns.kind === 'builtin') {
198
+ projectionTypes[alias] = operationExpr.returns.type;
199
+ }
200
+ } else {
201
+ const columnMeta = getColumnMeta(col);
202
+ const codecId = columnMeta?.codecId;
203
+ if (codecId) {
204
+ projectionTypes[alias] = codecId;
205
+ }
206
+ }
207
+ }
208
+
209
+ const projectionCodecs: Record<string, string> = {};
210
+ for (let i = 0; i < args.projection.aliases.length; i++) {
211
+ const alias = args.projection.aliases[i];
212
+ if (!alias || includeAliases.has(alias)) {
213
+ continue;
214
+ }
215
+ const column = args.projection.columns[i];
216
+ if (!column) {
217
+ continue;
218
+ }
219
+ const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
220
+ if (operationExpr) {
221
+ if (operationExpr.returns.kind === 'typeId') {
222
+ projectionCodecs[alias] = operationExpr.returns.type;
223
+ }
224
+ } else {
225
+ const columnMeta = getColumnMeta(column);
226
+ const codecId = columnMeta?.codecId;
227
+ if (codecId) {
228
+ projectionCodecs[alias] = codecId;
229
+ }
230
+ }
231
+ }
232
+
233
+ const allCodecs: Record<string, string> = {
234
+ ...projectionCodecs,
235
+ ...(args.paramCodecs ? args.paramCodecs : {}),
236
+ };
237
+
238
+ return Object.freeze(
239
+ compact({
240
+ target: args.contract.target,
241
+ targetFamily: args.contract.targetFamily,
242
+ coreHash: args.contract.coreHash,
243
+ lane: 'dsl',
244
+ refs: {
245
+ tables: Array.from(refsTables),
246
+ columns: Array.from(refsColumns.values()),
247
+ },
248
+ projection: projectionMap,
249
+ projectionTypes: Object.keys(projectionTypes).length > 0 ? projectionTypes : undefined,
250
+ annotations:
251
+ Object.keys(allCodecs).length > 0
252
+ ? Object.freeze({ codecs: Object.freeze(allCodecs) })
253
+ : undefined,
254
+ paramDescriptors: args.paramDescriptors,
255
+ profileHash: args.contract.profileHash,
256
+ }) as PlanMeta,
257
+ );
258
+ }
259
+
260
+ export function createPlan<Row>(
261
+ ast: SelectAst,
262
+ lowered: { body: LoweredStatement },
263
+ paramValues: unknown[],
264
+ planMeta: PlanMeta,
265
+ ): ExecutionPlan<Row> {
266
+ return Object.freeze({
267
+ ast,
268
+ sql: lowered.body.sql,
269
+ params: lowered.body.params ?? paramValues,
270
+ meta: {
271
+ ...planMeta,
272
+ lane: 'orm',
273
+ },
274
+ });
275
+ }
276
+
277
+ export function createPlanWithExists<Row>(
278
+ ast: SelectAst,
279
+ combinedWhere: BinaryExpr | ExistsExpr | undefined,
280
+ lowered: { body: LoweredStatement },
281
+ paramValues: unknown[],
282
+ planMeta: PlanMeta,
283
+ ): ExecutionPlan<Row> {
284
+ const modifiedAst: SelectAst = {
285
+ ...ast,
286
+ ...(combinedWhere !== undefined ? { where: combinedWhere } : {}),
287
+ };
288
+ return Object.freeze({
289
+ ast: modifiedAst,
290
+ sql: lowered.body.sql,
291
+ params: lowered.body.params ?? paramValues,
292
+ meta: {
293
+ ...planMeta,
294
+ lane: 'orm',
295
+ },
296
+ });
297
+ }
@@ -0,0 +1 @@
1
+ export type {};
@@ -0,0 +1,324 @@
1
+ import type { ParamDescriptor } from '@prisma-next/contract/types';
2
+ import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
3
+ import type {
4
+ BinaryExpr,
5
+ ColumnRef,
6
+ ExistsExpr,
7
+ IncludeAst,
8
+ OperationExpr,
9
+ ParamRef,
10
+ TableRef,
11
+ } from '@prisma-next/sql-relational-core/ast';
12
+ import { compact } from '@prisma-next/sql-relational-core/ast';
13
+ import type { QueryLaneContext } from '@prisma-next/sql-relational-core/query-lane-context';
14
+ import { schema } from '@prisma-next/sql-relational-core/schema';
15
+ import type {
16
+ AnyBinaryBuilder,
17
+ AnyColumnBuilder,
18
+ AnyOrderBuilder,
19
+ BuildOptions,
20
+ NestedProjection,
21
+ } from '@prisma-next/sql-relational-core/types';
22
+ import { checkIncludeCapabilities } from '../orm/capabilities';
23
+ import type { OrmIncludeState, RelationFilter } from '../orm/state';
24
+ import { buildJoinOnExpr } from '../selection/join';
25
+ import { buildChildOrderByClause } from '../selection/ordering';
26
+ import { buildWhereExpr } from '../selection/predicates';
27
+ import {
28
+ buildProjectionState,
29
+ type ProjectionInput,
30
+ type ProjectionState,
31
+ } from '../selection/projection';
32
+ import { createColumnRef, createSelectAst } from '../utils/ast';
33
+ import {
34
+ errorChildProjectionEmpty,
35
+ errorChildProjectionMustBeSpecified,
36
+ errorColumnNotFound,
37
+ errorJoinColumnsMustBeDefined,
38
+ errorMissingAlias,
39
+ errorMissingColumn,
40
+ errorModelNotFound,
41
+ errorMultiColumnJoinsNotSupported,
42
+ errorTableNotFound,
43
+ } from '../utils/errors';
44
+
45
+ export interface IncludeState {
46
+ readonly alias: string;
47
+ readonly table: TableRef;
48
+ readonly on: {
49
+ kind: 'join-on';
50
+ left: StorageColumn;
51
+ right: StorageColumn;
52
+ };
53
+ readonly childProjection: ProjectionState;
54
+ readonly childWhere?: AnyBinaryBuilder;
55
+ readonly childOrderBy?: AnyOrderBuilder;
56
+ readonly childLimit?: number;
57
+ }
58
+
59
+ interface BuildIncludeAstsInput {
60
+ readonly includes: OrmIncludeState[];
61
+ readonly contract: SqlContract<SqlStorage>;
62
+ readonly context: QueryLaneContext<SqlContract<SqlStorage>>;
63
+ readonly modelName: string;
64
+ readonly paramsMap: Record<string, unknown>;
65
+ readonly paramDescriptors: ParamDescriptor[];
66
+ readonly paramValues: unknown[];
67
+ readonly paramCodecs: Record<string, string>;
68
+ }
69
+
70
+ export function buildIncludeAsts(input: BuildIncludeAstsInput): {
71
+ includesAst: IncludeAst[];
72
+ includesForMeta: IncludeState[];
73
+ } {
74
+ const {
75
+ includes,
76
+ contract,
77
+ context,
78
+ modelName,
79
+ paramsMap,
80
+ paramDescriptors,
81
+ paramValues,
82
+ paramCodecs,
83
+ } = input;
84
+
85
+ const includesAst: IncludeAst[] = [];
86
+ const includesForMeta: IncludeState[] = [];
87
+
88
+ for (const includeState of includes) {
89
+ checkIncludeCapabilities(contract);
90
+
91
+ const parentTableName = contract.mappings.modelToTable?.[modelName];
92
+ if (!parentTableName) {
93
+ errorModelNotFound(modelName);
94
+ }
95
+
96
+ const parentSchemaHandle = schema(context);
97
+ const parentSchemaTable = parentSchemaHandle.tables[parentTableName];
98
+ if (!parentSchemaTable) {
99
+ errorTableNotFound(parentTableName);
100
+ }
101
+ const childSchemaHandle = schema(context);
102
+ const childSchemaTable = childSchemaHandle.tables[includeState.childTable.name];
103
+ if (!childSchemaTable) {
104
+ errorTableNotFound(includeState.childTable.name);
105
+ }
106
+
107
+ if (
108
+ includeState.relation.on.parentCols.length !== 1 ||
109
+ includeState.relation.on.childCols.length !== 1
110
+ ) {
111
+ errorMultiColumnJoinsNotSupported();
112
+ }
113
+ const parentColName = includeState.relation.on.parentCols[0];
114
+ const childColName = includeState.relation.on.childCols[0];
115
+ if (!parentColName || !childColName) {
116
+ errorJoinColumnsMustBeDefined();
117
+ }
118
+ const parentCol = parentSchemaTable.columns[parentColName];
119
+ const childCol = childSchemaTable.columns[childColName];
120
+ if (!parentCol) {
121
+ errorColumnNotFound(parentColName, parentTableName);
122
+ }
123
+ if (!childCol) {
124
+ errorColumnNotFound(childColName, includeState.childTable.name);
125
+ }
126
+
127
+ const onExpr = buildJoinOnExpr(
128
+ parentTableName,
129
+ parentColName,
130
+ includeState.childTable.name,
131
+ childColName,
132
+ );
133
+
134
+ if (!includeState.childProjection) {
135
+ errorChildProjectionMustBeSpecified();
136
+ }
137
+ const filteredProjection: Record<string, AnyColumnBuilder | NestedProjection> = {};
138
+ for (const [key, value] of Object.entries(includeState.childProjection)) {
139
+ if (value !== true && value !== false) {
140
+ filteredProjection[key] = value as AnyColumnBuilder | NestedProjection;
141
+ }
142
+ }
143
+ if (Object.keys(filteredProjection).length === 0) {
144
+ errorChildProjectionEmpty();
145
+ }
146
+ const childProjectionState = buildProjectionState(
147
+ includeState.childTable,
148
+ filteredProjection as ProjectionInput,
149
+ );
150
+
151
+ let childWhere: BinaryExpr | undefined;
152
+ if (includeState.childWhere) {
153
+ const whereResult = buildWhereExpr(
154
+ includeState.childWhere,
155
+ contract,
156
+ paramsMap,
157
+ paramDescriptors,
158
+ paramValues,
159
+ );
160
+ childWhere = whereResult.expr;
161
+ if (whereResult.codecId && whereResult.paramName) {
162
+ paramCodecs[whereResult.paramName] = whereResult.codecId;
163
+ }
164
+ }
165
+
166
+ const childOrderBy = buildChildOrderByClause(includeState.childOrderBy);
167
+
168
+ const childProjectionItems: Array<{ alias: string; expr: ColumnRef | OperationExpr }> = [];
169
+ for (let i = 0; i < childProjectionState.aliases.length; i++) {
170
+ const alias = childProjectionState.aliases[i];
171
+ if (!alias) {
172
+ errorMissingAlias(i);
173
+ }
174
+ const column = childProjectionState.columns[i];
175
+ if (!column) {
176
+ errorMissingColumn(alias, i);
177
+ }
178
+ const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
179
+ if (operationExpr) {
180
+ childProjectionItems.push({ alias, expr: operationExpr });
181
+ } else {
182
+ const col = column as { table: string; column: string };
183
+ childProjectionItems.push({ alias, expr: createColumnRef(col.table, col.column) });
184
+ }
185
+ }
186
+
187
+ const includeAst: IncludeAst = compact({
188
+ kind: 'includeMany',
189
+ alias: includeState.alias,
190
+ child: compact({
191
+ table: includeState.childTable,
192
+ on: onExpr,
193
+ project: childProjectionItems,
194
+ where: childWhere,
195
+ orderBy: childOrderBy,
196
+ limit: includeState.childLimit,
197
+ }),
198
+ }) as IncludeAst;
199
+ includesAst.push(includeAst);
200
+
201
+ const includeForMeta: IncludeState = compact({
202
+ alias: includeState.alias,
203
+ table: includeState.childTable,
204
+ on: {
205
+ kind: 'join-on',
206
+ left: parentCol as unknown as StorageColumn,
207
+ right: childCol as unknown as StorageColumn,
208
+ },
209
+ childProjection: childProjectionState,
210
+ childWhere: includeState.childWhere,
211
+ childOrderBy: includeState.childOrderBy,
212
+ childLimit: includeState.childLimit,
213
+ }) as IncludeState;
214
+ includesForMeta.push(includeForMeta);
215
+ }
216
+
217
+ return { includesAst, includesForMeta };
218
+ }
219
+
220
+ export function buildExistsSubqueries(
221
+ relationFilters: RelationFilter[],
222
+ contract: SqlContract<SqlStorage>,
223
+ modelName: string,
224
+ options?: BuildOptions,
225
+ ): ExistsExpr[] {
226
+ const existsExprs: ExistsExpr[] = [];
227
+
228
+ for (const filter of relationFilters) {
229
+ const childTableName = contract.mappings.modelToTable?.[filter.childModelName];
230
+ if (!childTableName) {
231
+ errorModelNotFound(filter.childModelName);
232
+ }
233
+
234
+ const childTable: TableRef = { kind: 'table', name: childTableName };
235
+ const parentTableName = contract.mappings.modelToTable?.[modelName];
236
+ if (!parentTableName) {
237
+ errorModelNotFound(modelName);
238
+ }
239
+
240
+ const joinConditions: Array<{ left: ColumnRef; right: ColumnRef }> = [];
241
+ for (let i = 0; i < filter.relation.on.parentCols.length; i++) {
242
+ const parentCol = filter.relation.on.parentCols[i];
243
+ const childCol = filter.relation.on.childCols[i];
244
+ if (!parentCol || !childCol) {
245
+ continue;
246
+ }
247
+ joinConditions.push({
248
+ left: { kind: 'col', table: parentTableName, column: parentCol },
249
+ right: { kind: 'col', table: childTableName, column: childCol },
250
+ });
251
+ }
252
+
253
+ let childWhere: BinaryExpr | undefined;
254
+ if (filter.childWhere) {
255
+ const paramsMap = (options?.params ?? {}) as Record<string, unknown>;
256
+ const paramDescriptors: ParamDescriptor[] = [];
257
+ const paramValues: unknown[] = [];
258
+ const whereResult = buildWhereExpr(
259
+ filter.childWhere,
260
+ contract,
261
+ paramsMap,
262
+ paramDescriptors,
263
+ paramValues,
264
+ );
265
+ childWhere = whereResult.expr;
266
+ }
267
+
268
+ let subqueryWhere: BinaryExpr | undefined = childWhere;
269
+ if (joinConditions.length > 0) {
270
+ const firstJoinCondition = joinConditions[0];
271
+ if (firstJoinCondition) {
272
+ const joinWhere: BinaryExpr = {
273
+ kind: 'bin',
274
+ op: 'eq',
275
+ left: firstJoinCondition.left,
276
+ right: firstJoinCondition.right as unknown as ParamRef,
277
+ };
278
+ if (childWhere) {
279
+ subqueryWhere = joinWhere;
280
+ } else {
281
+ subqueryWhere = joinWhere;
282
+ }
283
+ }
284
+ }
285
+ const projectionColumn = joinConditions[0]?.right ?? createColumnRef(childTableName, 'id');
286
+ const subquery = createSelectAst({
287
+ from: childTable,
288
+ project: [{ alias: '_exists', expr: projectionColumn }],
289
+ where: subqueryWhere,
290
+ } as {
291
+ from: TableRef;
292
+ project: ReadonlyArray<{ alias: string; expr: ColumnRef }>;
293
+ where?: BinaryExpr | ExistsExpr;
294
+ });
295
+
296
+ const notExists = filter.filterType === 'none' || filter.filterType === 'every';
297
+
298
+ const existsExpr: ExistsExpr = {
299
+ kind: 'exists',
300
+ subquery,
301
+ not: notExists,
302
+ };
303
+
304
+ existsExprs.push(existsExpr);
305
+ }
306
+
307
+ return existsExprs;
308
+ }
309
+
310
+ export function combineWhereClauses(
311
+ mainWhere: BinaryExpr | ExistsExpr | undefined,
312
+ existsExprs: ExistsExpr[],
313
+ ): BinaryExpr | ExistsExpr | undefined {
314
+ if (existsExprs.length === 1) {
315
+ return existsExprs[0];
316
+ }
317
+ if (mainWhere) {
318
+ return mainWhere;
319
+ }
320
+ if (existsExprs.length > 0) {
321
+ return existsExprs[0];
322
+ }
323
+ return undefined;
324
+ }
@@ -0,0 +1,13 @@
1
+ import type { JoinOnExpr } from '@prisma-next/sql-relational-core/ast';
2
+ import { createColumnRef, createJoinOnExpr } from '../utils/ast';
3
+
4
+ export function buildJoinOnExpr(
5
+ parentTableName: string,
6
+ parentColName: string,
7
+ childTableName: string,
8
+ childColName: string,
9
+ ): JoinOnExpr {
10
+ const leftCol = createColumnRef(parentTableName, parentColName);
11
+ const rightCol = createColumnRef(childTableName, childColName);
12
+ return createJoinOnExpr(leftCol, rightCol);
13
+ }
@@ -0,0 +1,52 @@
1
+ import type { StorageColumn } from '@prisma-next/sql-contract/types';
2
+ import type { ColumnRef, Direction, OperationExpr } from '@prisma-next/sql-relational-core/ast';
3
+ import type { AnyOrderBuilder, OrderBuilder } from '@prisma-next/sql-relational-core/types';
4
+ import {
5
+ extractBaseColumnRef,
6
+ isOperationExpr,
7
+ } from '@prisma-next/sql-relational-core/utils/guards';
8
+ import { createColumnRef, createOrderByItem } from '../utils/ast';
9
+
10
+ export function buildOrderByClause(orderBy: AnyOrderBuilder | undefined):
11
+ | ReadonlyArray<{
12
+ expr: ColumnRef | OperationExpr;
13
+ dir: Direction;
14
+ }>
15
+ | undefined {
16
+ if (!orderBy) {
17
+ return undefined;
18
+ }
19
+
20
+ const orderByBuilder = orderBy as OrderBuilder<string, StorageColumn, unknown>;
21
+ const orderExpr = orderByBuilder.expr;
22
+ const expr: ColumnRef | OperationExpr = isOperationExpr(orderExpr)
23
+ ? orderExpr
24
+ : (() => {
25
+ const colBuilder = orderExpr as { table: string; column: string };
26
+ return createColumnRef(colBuilder.table, colBuilder.column);
27
+ })();
28
+ return [createOrderByItem(expr, orderByBuilder.dir)];
29
+ }
30
+
31
+ export function buildChildOrderByClause(orderBy: AnyOrderBuilder | undefined):
32
+ | ReadonlyArray<{
33
+ expr: ColumnRef | OperationExpr;
34
+ dir: Direction;
35
+ }>
36
+ | undefined {
37
+ if (!orderBy) {
38
+ return undefined;
39
+ }
40
+
41
+ const orderByBuilder = orderBy as OrderBuilder<string, StorageColumn, unknown>;
42
+ const orderExpr = orderByBuilder.expr;
43
+ const expr: ColumnRef | OperationExpr = (() => {
44
+ if (isOperationExpr(orderExpr)) {
45
+ const baseCol = extractBaseColumnRef(orderExpr);
46
+ return createColumnRef(baseCol.table, baseCol.column);
47
+ }
48
+ const colBuilder = orderExpr as { table: string; column: string };
49
+ return createColumnRef(colBuilder.table, colBuilder.column);
50
+ })();
51
+ return [createOrderByItem(expr, orderByBuilder.dir)];
52
+ }
@@ -0,0 +1,11 @@
1
+ export interface PaginationState {
2
+ limit?: number;
3
+ offset?: number;
4
+ }
5
+
6
+ export function createPaginationState(limit?: number, offset?: number): PaginationState {
7
+ return {
8
+ ...(limit !== undefined ? { limit } : {}),
9
+ ...(offset !== undefined ? { offset } : {}),
10
+ };
11
+ }