@prisma-next/sql-orm-lane 0.3.0-pr.96.1 → 0.3.0-pr.96.4
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/dist/{chunk-3DNKIXXB.js → chunk-C4EECZ4E.js} +106 -119
- package/dist/chunk-C4EECZ4E.js.map +1 -0
- package/dist/exports/orm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/orm/state.d.ts +3 -3
- package/dist/orm/state.d.ts.map +1 -1
- package/dist/plan/plan-assembly.d.ts.map +1 -1
- package/dist/relations/include-plan.d.ts.map +1 -1
- package/dist/selection/predicates.d.ts.map +1 -1
- package/dist/selection/projection.d.ts +4 -4
- package/dist/selection/projection.d.ts.map +1 -1
- package/dist/selection/select-builder.d.ts +4 -4
- package/dist/selection/select-builder.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/orm/state.ts +3 -3
- package/src/plan/plan-assembly.ts +95 -80
- package/src/relations/include-plan.ts +5 -5
- package/src/selection/predicates.ts +25 -41
- package/src/selection/projection.ts +16 -10
- package/src/selection/select-builder.ts +22 -24
- package/dist/chunk-3DNKIXXB.js.map +0 -1
|
@@ -4,21 +4,22 @@ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
|
4
4
|
import type {
|
|
5
5
|
BinaryExpr,
|
|
6
6
|
ExistsExpr,
|
|
7
|
+
Expression,
|
|
7
8
|
LoweredStatement,
|
|
8
|
-
OperationExpr,
|
|
9
9
|
SelectAst,
|
|
10
10
|
TableRef,
|
|
11
11
|
} from '@prisma-next/sql-relational-core/ast';
|
|
12
12
|
import { compact } from '@prisma-next/sql-relational-core/ast';
|
|
13
13
|
import type {
|
|
14
|
-
|
|
14
|
+
AnyExpressionSource,
|
|
15
15
|
AnyOrderBuilder,
|
|
16
16
|
BinaryBuilder,
|
|
17
17
|
} from '@prisma-next/sql-relational-core/types';
|
|
18
18
|
import {
|
|
19
19
|
collectColumnRefs,
|
|
20
|
-
getColumnInfo,
|
|
21
20
|
getColumnMeta,
|
|
21
|
+
isColumnBuilder,
|
|
22
|
+
isExpressionBuilder,
|
|
22
23
|
isOperationExpr,
|
|
23
24
|
} from '@prisma-next/sql-relational-core/utils/guards';
|
|
24
25
|
import type { IncludeState } from '../relations/include-plan';
|
|
@@ -35,30 +36,67 @@ export interface MetaBuildArgs {
|
|
|
35
36
|
readonly paramCodecs?: Record<string, string>;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Extracts column references from an ExpressionSource (ColumnBuilder or ExpressionBuilder).
|
|
41
|
+
* Skips entries with empty table or column names (e.g., placeholder columns for includes).
|
|
42
|
+
*/
|
|
43
|
+
function collectRefsFromExpressionSource(
|
|
44
|
+
source: AnyExpressionSource,
|
|
45
|
+
refsColumns: Map<string, { table: string; column: string }>,
|
|
46
|
+
): void {
|
|
47
|
+
if (isExpressionBuilder(source)) {
|
|
48
|
+
const allRefs = collectColumnRefs(source.expr);
|
|
49
|
+
for (const ref of allRefs) {
|
|
50
|
+
// Skip empty table/column (placeholders for includes)
|
|
51
|
+
if (ref.table && ref.column) {
|
|
47
52
|
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
48
53
|
table: ref.table,
|
|
49
54
|
column: ref.column,
|
|
50
55
|
});
|
|
51
56
|
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
}
|
|
58
|
+
} else if (isColumnBuilder(source)) {
|
|
59
|
+
const col = source as unknown as { table: string; column: string };
|
|
60
|
+
// Skip empty table/column (placeholders for includes)
|
|
61
|
+
if (col.table && col.column) {
|
|
62
|
+
refsColumns.set(`${col.table}.${col.column}`, {
|
|
63
|
+
table: col.table,
|
|
64
|
+
column: col.column,
|
|
65
|
+
});
|
|
60
66
|
}
|
|
61
67
|
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extracts column references from an Expression (AST node).
|
|
72
|
+
*/
|
|
73
|
+
function collectRefsFromExpression(
|
|
74
|
+
expr: Expression,
|
|
75
|
+
refsColumns: Map<string, { table: string; column: string }>,
|
|
76
|
+
): void {
|
|
77
|
+
if (isOperationExpr(expr)) {
|
|
78
|
+
const allRefs = collectColumnRefs(expr);
|
|
79
|
+
for (const ref of allRefs) {
|
|
80
|
+
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
81
|
+
table: ref.table,
|
|
82
|
+
column: ref.column,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
} else if (expr.kind === 'col') {
|
|
86
|
+
refsColumns.set(`${expr.table}.${expr.column}`, {
|
|
87
|
+
table: expr.table,
|
|
88
|
+
column: expr.column,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
94
|
+
const refsColumns = new Map<string, { table: string; column: string }>();
|
|
95
|
+
const refsTables = new Set<string>([args.table.name]);
|
|
96
|
+
|
|
97
|
+
for (const column of args.projection.columns) {
|
|
98
|
+
collectRefsFromExpressionSource(column, refsColumns);
|
|
99
|
+
}
|
|
62
100
|
|
|
63
101
|
if (args.includes) {
|
|
64
102
|
for (const include of args.includes) {
|
|
@@ -85,32 +123,21 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
|
85
123
|
}
|
|
86
124
|
}
|
|
87
125
|
if (include.childWhere) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
table: colInfo.table,
|
|
91
|
-
column: colInfo.column,
|
|
92
|
-
});
|
|
126
|
+
// childWhere.left is Expression (already converted at builder creation time)
|
|
127
|
+
collectRefsFromExpression(include.childWhere.left, refsColumns);
|
|
93
128
|
}
|
|
94
129
|
if (include.childOrderBy) {
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
}
|
|
130
|
+
// childOrderBy.expr is Expression (already converted at builder creation time)
|
|
131
|
+
collectRefsFromExpression(include.childOrderBy.expr, refsColumns);
|
|
105
132
|
}
|
|
106
133
|
}
|
|
107
134
|
}
|
|
108
135
|
|
|
109
136
|
if (args.where) {
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
const allRefs = collectColumnRefs(
|
|
137
|
+
// args.where.left is Expression (already converted at builder creation time)
|
|
138
|
+
const leftExpr: Expression = args.where.left;
|
|
139
|
+
if (isOperationExpr(leftExpr)) {
|
|
140
|
+
const allRefs = collectColumnRefs(leftExpr);
|
|
114
141
|
for (const ref of allRefs) {
|
|
115
142
|
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
116
143
|
table: ref.table,
|
|
@@ -118,39 +145,31 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
|
118
145
|
});
|
|
119
146
|
}
|
|
120
147
|
} else {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
127
|
-
}
|
|
148
|
+
// leftExpr is ColumnRef
|
|
149
|
+
refsColumns.set(`${leftExpr.table}.${leftExpr.column}`, {
|
|
150
|
+
table: leftExpr.table,
|
|
151
|
+
column: leftExpr.column,
|
|
152
|
+
});
|
|
128
153
|
}
|
|
129
154
|
}
|
|
130
155
|
|
|
131
156
|
if (args.orderBy) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
}
|
|
157
|
+
// args.orderBy.expr is Expression (already converted at builder creation time)
|
|
158
|
+
const orderByExpr: Expression = args.orderBy.expr;
|
|
159
|
+
if (isOperationExpr(orderByExpr)) {
|
|
160
|
+
const allRefs = collectColumnRefs(orderByExpr);
|
|
161
|
+
for (const ref of allRefs) {
|
|
162
|
+
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
163
|
+
table: ref.table,
|
|
164
|
+
column: ref.column,
|
|
165
|
+
});
|
|
153
166
|
}
|
|
167
|
+
} else {
|
|
168
|
+
// orderByExpr is ColumnRef
|
|
169
|
+
refsColumns.set(`${orderByExpr.table}.${orderByExpr.column}`, {
|
|
170
|
+
table: orderByExpr.table,
|
|
171
|
+
column: orderByExpr.column,
|
|
172
|
+
});
|
|
154
173
|
}
|
|
155
174
|
}
|
|
156
175
|
|
|
@@ -164,18 +183,14 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
|
164
183
|
if (!column) {
|
|
165
184
|
throw planInvalid(`Missing column for alias ${alias} at index ${index}`);
|
|
166
185
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
};
|
|
186
|
+
if (isExpressionBuilder(column)) {
|
|
187
|
+
return [alias, `operation:${column.expr.method}`];
|
|
188
|
+
}
|
|
189
|
+
// column is ColumnBuilder
|
|
190
|
+
const col = column as unknown as { table?: string; column?: string };
|
|
172
191
|
if (!col.table || !col.column) {
|
|
173
192
|
return [alias, `include:${alias}`];
|
|
174
193
|
}
|
|
175
|
-
const operationExpr = col._operationExpr;
|
|
176
|
-
if (operationExpr) {
|
|
177
|
-
return [alias, `operation:${operationExpr.method}`];
|
|
178
|
-
}
|
|
179
194
|
return [alias, `${col.table}.${col.column}`];
|
|
180
195
|
}),
|
|
181
196
|
);
|
|
@@ -190,8 +205,8 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
|
190
205
|
if (!col) {
|
|
191
206
|
continue;
|
|
192
207
|
}
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
if (isExpressionBuilder(col)) {
|
|
209
|
+
const operationExpr = col.expr;
|
|
195
210
|
if (operationExpr.returns.kind === 'typeId') {
|
|
196
211
|
projectionTypes[alias] = operationExpr.returns.type;
|
|
197
212
|
} else if (operationExpr.returns.kind === 'builtin') {
|
|
@@ -216,8 +231,8 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
|
|
|
216
231
|
if (!column) {
|
|
217
232
|
continue;
|
|
218
233
|
}
|
|
219
|
-
|
|
220
|
-
|
|
234
|
+
if (isExpressionBuilder(column)) {
|
|
235
|
+
const operationExpr = column.expr;
|
|
221
236
|
if (operationExpr.returns.kind === 'typeId') {
|
|
222
237
|
projectionCodecs[alias] = operationExpr.returns.type;
|
|
223
238
|
}
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
BuildOptions,
|
|
20
20
|
NestedProjection,
|
|
21
21
|
} from '@prisma-next/sql-relational-core/types';
|
|
22
|
+
import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
|
|
22
23
|
import { checkIncludeCapabilities } from '../orm/capabilities';
|
|
23
24
|
import type { OrmIncludeState, RelationFilter } from '../orm/state';
|
|
24
25
|
import { buildJoinOnExpr } from '../selection/join';
|
|
@@ -175,12 +176,11 @@ export function buildIncludeAsts(input: BuildIncludeAstsInput): {
|
|
|
175
176
|
if (!column) {
|
|
176
177
|
errorMissingColumn(alias, i);
|
|
177
178
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
childProjectionItems.push({ alias, expr: operationExpr });
|
|
179
|
+
if (isExpressionBuilder(column)) {
|
|
180
|
+
childProjectionItems.push({ alias, expr: column.expr });
|
|
181
181
|
} else {
|
|
182
|
-
|
|
183
|
-
childProjectionItems.push({ alias, expr:
|
|
182
|
+
// ColumnBuilder - use toExpr() to get ColumnRef
|
|
183
|
+
childProjectionItems.push({ alias, expr: column.toExpr() });
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import type { ParamDescriptor } from '@prisma-next/contract/types';
|
|
2
2
|
import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
|
|
3
|
-
import type {
|
|
4
|
-
BinaryExpr,
|
|
5
|
-
ColumnRef,
|
|
6
|
-
OperationExpr,
|
|
7
|
-
ParamRef,
|
|
8
|
-
} from '@prisma-next/sql-relational-core/ast';
|
|
3
|
+
import type { BinaryExpr, Expression, ParamRef } from '@prisma-next/sql-relational-core/ast';
|
|
9
4
|
import { augmentDescriptorWithColumnMeta } from '@prisma-next/sql-relational-core/plan';
|
|
10
5
|
import type { BinaryBuilder, ParamPlaceholder } from '@prisma-next/sql-relational-core/types';
|
|
11
6
|
import {
|
|
12
|
-
getColumnInfo,
|
|
13
|
-
getColumnMeta,
|
|
14
|
-
getOperationExpr,
|
|
15
7
|
isColumnBuilder,
|
|
8
|
+
isExpressionBuilder,
|
|
16
9
|
isParamPlaceholder,
|
|
17
10
|
} from '@prisma-next/sql-relational-core/utils/guards';
|
|
18
|
-
import { createBinaryExpr,
|
|
11
|
+
import { createBinaryExpr, createParamRef } from '../utils/ast';
|
|
19
12
|
import {
|
|
20
13
|
errorFailedToBuildWhereClause,
|
|
21
14
|
errorMissingParameter,
|
|
@@ -33,16 +26,17 @@ export function buildWhereExpr(
|
|
|
33
26
|
codecId?: string;
|
|
34
27
|
paramName: string;
|
|
35
28
|
} {
|
|
36
|
-
let leftExpr:
|
|
29
|
+
let leftExpr: Expression;
|
|
37
30
|
let codecId: string | undefined;
|
|
38
|
-
let rightExpr:
|
|
31
|
+
let rightExpr: Expression | ParamRef;
|
|
39
32
|
let paramName: string;
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
// where.left is now an Expression (ColumnRef or OperationExpr)
|
|
35
|
+
leftExpr = where.left;
|
|
36
|
+
|
|
37
|
+
// If leftExpr is a ColumnRef, extract codecId from contract
|
|
38
|
+
if (leftExpr.kind === 'col') {
|
|
39
|
+
const { table, column } = leftExpr;
|
|
46
40
|
|
|
47
41
|
const contractTable = contract.storage.tables[table];
|
|
48
42
|
if (!contractTable) {
|
|
@@ -55,12 +49,9 @@ export function buildWhereExpr(
|
|
|
55
49
|
if (columnMeta) {
|
|
56
50
|
codecId = columnMeta.codecId;
|
|
57
51
|
}
|
|
58
|
-
leftExpr = createColumnRef(table, column);
|
|
59
|
-
} else {
|
|
60
|
-
errorFailedToBuildWhereClause();
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
// Handle where.right - can be ParamPlaceholder or
|
|
54
|
+
// Handle where.right - can be ParamPlaceholder or AnyExpressionSource
|
|
64
55
|
if (isParamPlaceholder(where.right)) {
|
|
65
56
|
// Handle param placeholder (existing logic)
|
|
66
57
|
const placeholder: ParamPlaceholder = where.right;
|
|
@@ -73,42 +64,35 @@ export function buildWhereExpr(
|
|
|
73
64
|
const value = paramsMap[paramName];
|
|
74
65
|
const index = values.push(value);
|
|
75
66
|
|
|
76
|
-
// Construct descriptor
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
// Construct descriptor from where.left Expression
|
|
68
|
+
// For ColumnRef, we can extract table/column directly
|
|
69
|
+
// For OperationExpr, we extract the base column reference
|
|
70
|
+
if (leftExpr.kind === 'col') {
|
|
71
|
+
const { table, column } = leftExpr;
|
|
79
72
|
const contractTable = contract.storage.tables[table];
|
|
80
73
|
const columnMeta = contractTable?.columns[column];
|
|
81
|
-
const builderColumnMeta = getColumnMeta(where.left);
|
|
82
74
|
|
|
83
75
|
descriptors.push({
|
|
84
76
|
name: paramName,
|
|
85
77
|
source: 'dsl',
|
|
86
78
|
refs: { table, column },
|
|
87
|
-
...(typeof
|
|
88
|
-
? { nullable:
|
|
79
|
+
...(columnMeta && typeof columnMeta.nullable === 'boolean'
|
|
80
|
+
? { nullable: columnMeta.nullable }
|
|
89
81
|
: {}),
|
|
90
82
|
});
|
|
91
83
|
|
|
92
84
|
augmentDescriptorWithColumnMeta(descriptors, columnMeta);
|
|
93
85
|
}
|
|
86
|
+
// For OperationExpr, we don't create descriptors since we can't reliably extract column info
|
|
94
87
|
|
|
95
88
|
rightExpr = createParamRef(index, paramName);
|
|
96
|
-
} else if (isColumnBuilder(where.right)) {
|
|
97
|
-
// Handle
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const contractTable = contract.storage.tables[table];
|
|
101
|
-
if (!contractTable) {
|
|
102
|
-
errorUnknownTable(table);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// If column not found in contract, still build expression
|
|
106
|
-
// This allows flexibility when columnMeta is available on the column builder
|
|
107
|
-
rightExpr = createColumnRef(table, column);
|
|
108
|
-
// Use a placeholder paramName for column references (not used for params)
|
|
89
|
+
} else if (isColumnBuilder(where.right) || isExpressionBuilder(where.right)) {
|
|
90
|
+
// Handle ExpressionSource on the right - use toExpr() to get the Expression
|
|
91
|
+
rightExpr = where.right.toExpr();
|
|
92
|
+
// Use a placeholder paramName for expression references (not used for params)
|
|
109
93
|
paramName = '';
|
|
110
94
|
} else {
|
|
111
|
-
// where.right is neither ParamPlaceholder nor
|
|
95
|
+
// where.right is neither ParamPlaceholder nor ExpressionSource - invalid state
|
|
112
96
|
errorFailedToBuildWhereClause();
|
|
113
97
|
}
|
|
114
98
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { TableRef } from '@prisma-next/sql-relational-core/ast';
|
|
2
2
|
import type {
|
|
3
3
|
AnyBinaryBuilder,
|
|
4
|
-
|
|
4
|
+
AnyExpressionSource,
|
|
5
5
|
AnyOrderBuilder,
|
|
6
6
|
JoinOnPredicate,
|
|
7
7
|
NestedProjection,
|
|
8
8
|
} from '@prisma-next/sql-relational-core/types';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
isColumnBuilder,
|
|
11
|
+
isExpressionBuilder,
|
|
12
|
+
} from '@prisma-next/sql-relational-core/utils/guards';
|
|
10
13
|
import {
|
|
11
14
|
errorAliasCollision,
|
|
12
15
|
errorAliasPathEmpty,
|
|
@@ -18,10 +21,10 @@ import {
|
|
|
18
21
|
|
|
19
22
|
export interface ProjectionState {
|
|
20
23
|
readonly aliases: string[];
|
|
21
|
-
readonly columns:
|
|
24
|
+
readonly columns: AnyExpressionSource[];
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
export type ProjectionInput = Record<string,
|
|
27
|
+
export type ProjectionInput = Record<string, AnyExpressionSource | boolean | NestedProjection>;
|
|
25
28
|
|
|
26
29
|
function generateAlias(path: string[]): string {
|
|
27
30
|
if (path.length === 0) {
|
|
@@ -58,14 +61,14 @@ export function flattenProjection(
|
|
|
58
61
|
projection: NestedProjection,
|
|
59
62
|
tracker: AliasTracker,
|
|
60
63
|
currentPath: string[] = [],
|
|
61
|
-
): { aliases: string[]; columns:
|
|
64
|
+
): { aliases: string[]; columns: AnyExpressionSource[] } {
|
|
62
65
|
const aliases: string[] = [];
|
|
63
|
-
const columns:
|
|
66
|
+
const columns: AnyExpressionSource[] = [];
|
|
64
67
|
|
|
65
68
|
for (const [key, value] of Object.entries(projection)) {
|
|
66
69
|
const path = [...currentPath, key];
|
|
67
70
|
|
|
68
|
-
if (isColumnBuilder(value)) {
|
|
71
|
+
if (isColumnBuilder(value) || isExpressionBuilder(value)) {
|
|
69
72
|
const alias = tracker.register(path);
|
|
70
73
|
aliases.push(alias);
|
|
71
74
|
columns.push(value);
|
|
@@ -96,7 +99,7 @@ export function buildProjectionState(
|
|
|
96
99
|
): ProjectionState {
|
|
97
100
|
const tracker = new AliasTracker();
|
|
98
101
|
const aliases: string[] = [];
|
|
99
|
-
const columns:
|
|
102
|
+
const columns: AnyExpressionSource[] = [];
|
|
100
103
|
|
|
101
104
|
for (const [key, value] of Object.entries(projection)) {
|
|
102
105
|
if (value === true) {
|
|
@@ -114,8 +117,11 @@ export function buildProjectionState(
|
|
|
114
117
|
codecId: 'core/json@1',
|
|
115
118
|
nullable: true,
|
|
116
119
|
},
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
toExpr() {
|
|
121
|
+
return { kind: 'col', table: matchingInclude.table.name, column: '' };
|
|
122
|
+
},
|
|
123
|
+
} as AnyExpressionSource);
|
|
124
|
+
} else if (isColumnBuilder(value) || isExpressionBuilder(value)) {
|
|
119
125
|
const alias = tracker.register([key]);
|
|
120
126
|
aliases.push(alias);
|
|
121
127
|
columns.push(value);
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BinaryExpr,
|
|
3
|
-
ColumnRef,
|
|
4
3
|
Direction,
|
|
5
4
|
ExistsExpr,
|
|
5
|
+
Expression,
|
|
6
6
|
IncludeAst,
|
|
7
7
|
IncludeRef,
|
|
8
|
-
OperationExpr,
|
|
9
8
|
SelectAst,
|
|
10
9
|
TableRef,
|
|
11
10
|
} from '@prisma-next/sql-relational-core/ast';
|
|
11
|
+
import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
|
|
12
12
|
import type { IncludeState } from '../relations/include-plan';
|
|
13
|
-
import {
|
|
13
|
+
import { createSelectAst, createTableRef } from '../utils/ast';
|
|
14
14
|
import { errorInvalidColumn, errorMissingAlias, errorMissingColumn } from '../utils/errors';
|
|
15
15
|
import type { ProjectionState } from './projection';
|
|
16
16
|
|
|
17
17
|
export function buildProjectionItems(
|
|
18
18
|
projectionState: ProjectionState,
|
|
19
19
|
includesForMeta: ReadonlyArray<IncludeState>,
|
|
20
|
-
): Array<{ alias: string; expr:
|
|
21
|
-
const projectEntries: Array<{ alias: string; expr:
|
|
20
|
+
): Array<{ alias: string; expr: Expression | IncludeRef }> {
|
|
21
|
+
const projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }> = [];
|
|
22
22
|
for (let i = 0; i < projectionState.aliases.length; i++) {
|
|
23
23
|
const alias = projectionState.aliases[i];
|
|
24
24
|
if (!alias) {
|
|
@@ -35,25 +35,23 @@ export function buildProjectionItems(
|
|
|
35
35
|
alias,
|
|
36
36
|
expr: { kind: 'includeRef', alias },
|
|
37
37
|
});
|
|
38
|
+
} else if (isExpressionBuilder(column)) {
|
|
39
|
+
// ExpressionBuilder (operation result) - use its expr
|
|
40
|
+
projectEntries.push({
|
|
41
|
+
alias,
|
|
42
|
+
expr: column.expr,
|
|
43
|
+
});
|
|
38
44
|
} else {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
} else {
|
|
46
|
-
const col = column as { table: string; column: string };
|
|
47
|
-
const tableName = col.table;
|
|
48
|
-
const columnName = col.column;
|
|
49
|
-
if (!tableName || !columnName) {
|
|
50
|
-
errorInvalidColumn(alias, i);
|
|
51
|
-
}
|
|
52
|
-
projectEntries.push({
|
|
53
|
-
alias,
|
|
54
|
-
expr: createColumnRef(tableName, columnName),
|
|
55
|
-
});
|
|
45
|
+
// ColumnBuilder - use toExpr() to get ColumnRef
|
|
46
|
+
const expr = column.toExpr();
|
|
47
|
+
// Validate the expression has valid table and column values
|
|
48
|
+
if (expr.kind === 'col' && (!expr.table || !expr.column)) {
|
|
49
|
+
errorInvalidColumn(alias, i);
|
|
56
50
|
}
|
|
51
|
+
projectEntries.push({
|
|
52
|
+
alias,
|
|
53
|
+
expr,
|
|
54
|
+
});
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
return projectEntries;
|
|
@@ -61,11 +59,11 @@ export function buildProjectionItems(
|
|
|
61
59
|
|
|
62
60
|
export function buildSelectAst(params: {
|
|
63
61
|
table: TableRef;
|
|
64
|
-
projectEntries: Array<{ alias: string; expr:
|
|
62
|
+
projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }>;
|
|
65
63
|
includesAst?: ReadonlyArray<IncludeAst>;
|
|
66
64
|
whereExpr?: BinaryExpr | ExistsExpr;
|
|
67
65
|
orderByClause?: ReadonlyArray<{
|
|
68
|
-
expr:
|
|
66
|
+
expr: Expression;
|
|
69
67
|
dir: Direction;
|
|
70
68
|
}>;
|
|
71
69
|
limit?: number;
|