metal-orm 1.0.17 → 1.0.18
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/README.md +4 -3
- package/dist/decorators/index.cjs +192 -46
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -1
- package/dist/decorators/index.d.ts +1 -1
- package/dist/decorators/index.js +192 -46
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +245 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -29
- package/dist/index.d.ts +16 -29
- package/dist/index.js +243 -66
- package/dist/index.js.map +1 -1
- package/dist/{select-BPCn6MOH.d.cts → select-BuMpVcVt.d.cts} +83 -11
- package/dist/{select-BPCn6MOH.d.ts → select-BuMpVcVt.d.ts} +83 -11
- package/package.json +4 -1
- package/src/codegen/naming-strategy.ts +15 -10
- package/src/core/ast/builders.ts +23 -3
- package/src/core/ast/expression-builders.ts +14 -1
- package/src/core/ast/expression-nodes.ts +11 -9
- package/src/core/ast/join-node.ts +5 -3
- package/src/core/ast/join.ts +16 -16
- package/src/core/ast/query.ts +44 -29
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +18 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +11 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +9 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
- package/src/core/dialect/base/sql-dialect.ts +58 -46
- package/src/core/dialect/mssql/index.ts +53 -28
- package/src/core/dialect/sqlite/index.ts +22 -13
- package/src/query-builder/column-selector.ts +9 -7
- package/src/query-builder/query-ast-service.ts +59 -38
- package/src/query-builder/relation-conditions.ts +38 -34
- package/src/query-builder/relation-manager.ts +8 -3
- package/src/query-builder/relation-service.ts +59 -46
- package/src/query-builder/select-query-state.ts +19 -7
- package/src/query-builder/select.ts +215 -135
- package/src/schema/column.ts +75 -39
- package/src/schema/types.ts +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TableDef } from '../schema/table.js';
|
|
2
2
|
import { ColumnDef } from '../schema/column.js';
|
|
3
|
-
import { SelectQueryNode, CommonTableExpressionNode, SetOperationKind, SetOperationNode } from '../core/ast/query.js';
|
|
3
|
+
import { SelectQueryNode, CommonTableExpressionNode, SetOperationKind, SetOperationNode, TableSourceNode } from '../core/ast/query.js';
|
|
4
4
|
import { buildColumnNode } from '../core/ast/builders.js';
|
|
5
5
|
import {
|
|
6
6
|
ColumnNode,
|
|
@@ -47,30 +47,36 @@ export class QueryAstService {
|
|
|
47
47
|
* @param columns - Columns to select (key: alias, value: column definition or expression)
|
|
48
48
|
* @returns Column selection result with updated state and added columns
|
|
49
49
|
*/
|
|
50
|
-
select(
|
|
51
|
-
columns: Record<string, ColumnDef | FunctionNode | CaseExpressionNode | WindowFunctionNode>
|
|
52
|
-
): ColumnSelectionResult {
|
|
53
|
-
const existingAliases = new Set(
|
|
54
|
-
this.state.ast.columns.map(c => (c as ColumnNode).alias || (c as ColumnNode).name)
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
50
|
+
select(
|
|
51
|
+
columns: Record<string, ColumnDef | FunctionNode | CaseExpressionNode | WindowFunctionNode>
|
|
52
|
+
): ColumnSelectionResult {
|
|
53
|
+
const existingAliases = new Set(
|
|
54
|
+
this.state.ast.columns.map(c => (c as ColumnNode).alias || (c as ColumnNode).name)
|
|
55
|
+
);
|
|
56
|
+
const from = this.state.ast.from;
|
|
57
|
+
const rootTableName = from.type === 'Table' && from.alias ? from.alias : this.table.name;
|
|
58
|
+
|
|
59
|
+
const newCols = Object.entries(columns).reduce<ProjectionNode[]>((acc, [alias, val]) => {
|
|
60
|
+
if (existingAliases.has(alias)) return acc;
|
|
61
|
+
|
|
62
|
+
if (isExpressionSelectionNode(val)) {
|
|
63
|
+
acc.push({ ...(val as FunctionNode | CaseExpressionNode | WindowFunctionNode), alias } as ProjectionNode);
|
|
64
|
+
return acc;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const colDef = val as ColumnDef;
|
|
68
|
+
const resolvedTable =
|
|
69
|
+
colDef.table && colDef.table === this.table.name && from.type === 'Table' && from.alias
|
|
70
|
+
? from.alias
|
|
71
|
+
: colDef.table || rootTableName;
|
|
72
|
+
acc.push({
|
|
73
|
+
type: 'Column',
|
|
74
|
+
table: resolvedTable,
|
|
75
|
+
name: colDef.name,
|
|
76
|
+
alias
|
|
77
|
+
} as ColumnNode);
|
|
78
|
+
return acc;
|
|
79
|
+
}, []);
|
|
74
80
|
|
|
75
81
|
const nextState = this.state.withColumns(newCols);
|
|
76
82
|
return { state: nextState, addedColumns: newCols };
|
|
@@ -81,11 +87,13 @@ export class QueryAstService {
|
|
|
81
87
|
* @param cols - Raw column expressions
|
|
82
88
|
* @returns Column selection result with updated state and added columns
|
|
83
89
|
*/
|
|
84
|
-
selectRaw(cols: string[]): ColumnSelectionResult {
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
selectRaw(cols: string[]): ColumnSelectionResult {
|
|
91
|
+
const from = this.state.ast.from;
|
|
92
|
+
const defaultTable = from.type === 'Table' && from.alias ? from.alias : this.table.name;
|
|
93
|
+
const newCols = cols.map(col => parseRawColumn(col, defaultTable, this.state.ast.ctes));
|
|
94
|
+
const nextState = this.state.withColumns(newCols);
|
|
95
|
+
return { state: nextState, addedColumns: newCols };
|
|
96
|
+
}
|
|
89
97
|
|
|
90
98
|
/**
|
|
91
99
|
* Adds a Common Table Expression (CTE) to the query
|
|
@@ -121,6 +129,15 @@ export class QueryAstService {
|
|
|
121
129
|
};
|
|
122
130
|
return this.state.withSetOperation(op);
|
|
123
131
|
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Replaces the FROM clause for the current query.
|
|
135
|
+
* @param from - Table source to use in the FROM clause
|
|
136
|
+
* @returns Updated query state with new FROM
|
|
137
|
+
*/
|
|
138
|
+
withFrom(from: TableSourceNode): SelectQueryState {
|
|
139
|
+
return this.state.withFrom(from);
|
|
140
|
+
}
|
|
124
141
|
|
|
125
142
|
/**
|
|
126
143
|
* Selects a subquery as a column
|
|
@@ -157,10 +174,12 @@ export class QueryAstService {
|
|
|
157
174
|
* @param col - Column to group by
|
|
158
175
|
* @returns Updated query state with GROUP BY clause
|
|
159
176
|
*/
|
|
160
|
-
withGroupBy(col: ColumnDef | ColumnNode): SelectQueryState {
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
177
|
+
withGroupBy(col: ColumnDef | ColumnNode): SelectQueryState {
|
|
178
|
+
const from = this.state.ast.from;
|
|
179
|
+
const tableRef = from.type === 'Table' && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
180
|
+
const node = buildColumnNode(tableRef, col);
|
|
181
|
+
return this.state.withGroupBy([node]);
|
|
182
|
+
}
|
|
164
183
|
|
|
165
184
|
/**
|
|
166
185
|
* Adds a HAVING clause to the query
|
|
@@ -178,10 +197,12 @@ export class QueryAstService {
|
|
|
178
197
|
* @param direction - Order direction (ASC/DESC)
|
|
179
198
|
* @returns Updated query state with ORDER BY clause
|
|
180
199
|
*/
|
|
181
|
-
withOrderBy(col: ColumnDef | ColumnNode, direction: OrderDirection): SelectQueryState {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
withOrderBy(col: ColumnDef | ColumnNode, direction: OrderDirection): SelectQueryState {
|
|
201
|
+
const from = this.state.ast.from;
|
|
202
|
+
const tableRef = from.type === 'Table' && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
203
|
+
const node = buildColumnNode(tableRef, col);
|
|
204
|
+
return this.state.withOrderBy([{ type: 'OrderBy', column: node, direction }]);
|
|
205
|
+
}
|
|
185
206
|
|
|
186
207
|
/**
|
|
187
208
|
* Adds a DISTINCT clause to the query
|
|
@@ -21,25 +21,26 @@ const assertNever = (value: never): never => {
|
|
|
21
21
|
* @param relation - Relation definition
|
|
22
22
|
* @returns Expression node representing the join condition
|
|
23
23
|
*/
|
|
24
|
-
const baseRelationCondition = (root: TableDef, relation: RelationDef): ExpressionNode => {
|
|
25
|
-
const
|
|
24
|
+
const baseRelationCondition = (root: TableDef, relation: RelationDef, rootAlias?: string): ExpressionNode => {
|
|
25
|
+
const rootTable = rootAlias || root.name;
|
|
26
|
+
const defaultLocalKey =
|
|
26
27
|
relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne
|
|
27
28
|
? findPrimaryKey(root)
|
|
28
29
|
: findPrimaryKey(relation.target);
|
|
29
|
-
const localKey = relation.localKey || defaultLocalKey;
|
|
30
|
+
const localKey = relation.localKey || defaultLocalKey;
|
|
30
31
|
|
|
31
32
|
switch (relation.type) {
|
|
32
33
|
case RelationKinds.HasMany:
|
|
33
34
|
case RelationKinds.HasOne:
|
|
34
35
|
return eq(
|
|
35
36
|
{ type: 'Column', table: relation.target.name, name: relation.foreignKey },
|
|
36
|
-
{ type: 'Column', table:
|
|
37
|
+
{ type: 'Column', table: rootTable, name: localKey }
|
|
38
|
+
);
|
|
39
|
+
case RelationKinds.BelongsTo:
|
|
40
|
+
return eq(
|
|
41
|
+
{ type: 'Column', table: relation.target.name, name: localKey },
|
|
42
|
+
{ type: 'Column', table: rootTable, name: relation.foreignKey }
|
|
37
43
|
);
|
|
38
|
-
case RelationKinds.BelongsTo:
|
|
39
|
-
return eq(
|
|
40
|
-
{ type: 'Column', table: relation.target.name, name: localKey },
|
|
41
|
-
{ type: 'Column', table: root.name, name: relation.foreignKey }
|
|
42
|
-
);
|
|
43
44
|
case RelationKinds.BelongsToMany:
|
|
44
45
|
throw new Error('BelongsToMany relations do not support the standard join condition builder');
|
|
45
46
|
default:
|
|
@@ -50,20 +51,22 @@ const baseRelationCondition = (root: TableDef, relation: RelationDef): Expressio
|
|
|
50
51
|
/**
|
|
51
52
|
* Builds the join nodes required to include a BelongsToMany relation.
|
|
52
53
|
*/
|
|
53
|
-
export const buildBelongsToManyJoins = (
|
|
54
|
-
root: TableDef,
|
|
55
|
-
relationName: string,
|
|
56
|
-
relation: BelongsToManyRelation,
|
|
57
|
-
joinKind: JoinKind,
|
|
58
|
-
extra?: ExpressionNode
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
export const buildBelongsToManyJoins = (
|
|
55
|
+
root: TableDef,
|
|
56
|
+
relationName: string,
|
|
57
|
+
relation: BelongsToManyRelation,
|
|
58
|
+
joinKind: JoinKind,
|
|
59
|
+
extra?: ExpressionNode,
|
|
60
|
+
rootAlias?: string
|
|
61
|
+
): JoinNode[] => {
|
|
62
|
+
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
63
|
+
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
64
|
+
const rootTable = rootAlias || root.name;
|
|
65
|
+
|
|
66
|
+
const pivotCondition = eq(
|
|
67
|
+
{ type: 'Column', table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
|
|
68
|
+
{ type: 'Column', table: rootTable, name: rootKey }
|
|
69
|
+
);
|
|
67
70
|
|
|
68
71
|
const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
|
|
69
72
|
|
|
@@ -93,14 +96,15 @@ export const buildBelongsToManyJoins = (
|
|
|
93
96
|
* @param extra - Optional additional expression to combine with AND
|
|
94
97
|
* @returns Expression node representing the complete join condition
|
|
95
98
|
*/
|
|
96
|
-
export const buildRelationJoinCondition = (
|
|
97
|
-
root: TableDef,
|
|
98
|
-
relation: RelationDef,
|
|
99
|
-
extra?: ExpressionNode
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
export const buildRelationJoinCondition = (
|
|
100
|
+
root: TableDef,
|
|
101
|
+
relation: RelationDef,
|
|
102
|
+
extra?: ExpressionNode,
|
|
103
|
+
rootAlias?: string
|
|
104
|
+
): ExpressionNode => {
|
|
105
|
+
const base = baseRelationCondition(root, relation, rootAlias);
|
|
106
|
+
return extra ? and(base, extra) : base;
|
|
107
|
+
};
|
|
104
108
|
|
|
105
109
|
/**
|
|
106
110
|
* Builds a relation correlation condition for subqueries
|
|
@@ -108,6 +112,6 @@ export const buildRelationJoinCondition = (
|
|
|
108
112
|
* @param relation - Relation definition
|
|
109
113
|
* @returns Expression node representing the correlation condition
|
|
110
114
|
*/
|
|
111
|
-
export const buildRelationCorrelation = (root: TableDef, relation: RelationDef): ExpressionNode => {
|
|
112
|
-
return baseRelationCondition(root, relation);
|
|
113
|
-
};
|
|
115
|
+
export const buildRelationCorrelation = (root: TableDef, relation: RelationDef, rootAlias?: string): ExpressionNode => {
|
|
116
|
+
return baseRelationCondition(root, relation, rootAlias);
|
|
117
|
+
};
|
|
@@ -67,9 +67,14 @@ export class RelationManager {
|
|
|
67
67
|
* @param ast - Query AST to modify
|
|
68
68
|
* @returns Modified query AST with relation correlation
|
|
69
69
|
*/
|
|
70
|
-
applyRelationCorrelation(
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
applyRelationCorrelation(
|
|
71
|
+
context: SelectQueryBuilderContext,
|
|
72
|
+
relationName: string,
|
|
73
|
+
ast: SelectQueryNode,
|
|
74
|
+
additionalCorrelation?: ExpressionNode
|
|
75
|
+
): SelectQueryNode {
|
|
76
|
+
return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
|
|
77
|
+
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
75
80
|
* Creates a relation service instance
|
|
@@ -70,17 +70,17 @@ export class RelationService {
|
|
|
70
70
|
* @param predicate - Optional predicate expression
|
|
71
71
|
* @returns Relation result with updated state and hydration
|
|
72
72
|
*/
|
|
73
|
-
match(
|
|
74
|
-
relationName: string,
|
|
75
|
-
predicate?: ExpressionNode
|
|
76
|
-
): RelationResult {
|
|
77
|
-
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
78
|
-
const pk = findPrimaryKey(this.table);
|
|
79
|
-
const distinctCols: ColumnNode[] = [{ type: 'Column', table: this.
|
|
80
|
-
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
81
|
-
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
82
|
-
return { state: nextState, hydration: joined.hydration };
|
|
83
|
-
}
|
|
73
|
+
match(
|
|
74
|
+
relationName: string,
|
|
75
|
+
predicate?: ExpressionNode
|
|
76
|
+
): RelationResult {
|
|
77
|
+
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
78
|
+
const pk = findPrimaryKey(this.table);
|
|
79
|
+
const distinctCols: ColumnNode[] = [{ type: 'Column', table: this.rootTableName(), name: pk }];
|
|
80
|
+
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
81
|
+
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
82
|
+
return { state: nextState, hydration: joined.hydration };
|
|
83
|
+
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* Includes a relation in the query result
|
|
@@ -190,17 +190,22 @@ export class RelationService {
|
|
|
190
190
|
* @param ast - Query AST to modify
|
|
191
191
|
* @returns Modified query AST with relation correlation
|
|
192
192
|
*/
|
|
193
|
-
applyRelationCorrelation(
|
|
194
|
-
relationName: string,
|
|
195
|
-
ast: SelectQueryNode
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
193
|
+
applyRelationCorrelation(
|
|
194
|
+
relationName: string,
|
|
195
|
+
ast: SelectQueryNode,
|
|
196
|
+
additionalCorrelation?: ExpressionNode
|
|
197
|
+
): SelectQueryNode {
|
|
198
|
+
const relation = this.getRelation(relationName);
|
|
199
|
+
const rootAlias = this.state.ast.from.type === 'Table' ? this.state.ast.from.alias : undefined;
|
|
200
|
+
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
201
|
+
if (additionalCorrelation) {
|
|
202
|
+
correlation = and(correlation, additionalCorrelation);
|
|
203
|
+
}
|
|
204
|
+
const whereInSubquery = ast.where
|
|
205
|
+
? and(correlation, ast.where)
|
|
206
|
+
: correlation;
|
|
207
|
+
|
|
208
|
+
return {
|
|
204
209
|
...ast,
|
|
205
210
|
where: whereInSubquery
|
|
206
211
|
};
|
|
@@ -214,26 +219,28 @@ export class RelationService {
|
|
|
214
219
|
* @param extraCondition - Additional join condition
|
|
215
220
|
* @returns Updated query state with join
|
|
216
221
|
*/
|
|
217
|
-
private withJoin(
|
|
218
|
-
state: SelectQueryState,
|
|
219
|
-
relationName: string,
|
|
220
|
-
joinKind: JoinKind,
|
|
221
|
-
extraCondition?: ExpressionNode
|
|
222
|
-
): SelectQueryState {
|
|
223
|
-
const relation = this.getRelation(relationName);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
222
|
+
private withJoin(
|
|
223
|
+
state: SelectQueryState,
|
|
224
|
+
relationName: string,
|
|
225
|
+
joinKind: JoinKind,
|
|
226
|
+
extraCondition?: ExpressionNode
|
|
227
|
+
): SelectQueryState {
|
|
228
|
+
const relation = this.getRelation(relationName);
|
|
229
|
+
const rootAlias = state.ast.from.type === 'Table' ? state.ast.from.alias : undefined;
|
|
230
|
+
if (relation.type === RelationKinds.BelongsToMany) {
|
|
231
|
+
const joins = buildBelongsToManyJoins(
|
|
232
|
+
this.table,
|
|
233
|
+
relationName,
|
|
234
|
+
relation as BelongsToManyRelation,
|
|
235
|
+
joinKind,
|
|
236
|
+
extraCondition,
|
|
237
|
+
rootAlias
|
|
238
|
+
);
|
|
239
|
+
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
243
|
+
const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
|
|
237
244
|
|
|
238
245
|
return this.astService(state).withJoin(joinNode);
|
|
239
246
|
}
|
|
@@ -277,9 +284,15 @@ export class RelationService {
|
|
|
277
284
|
* @param state - Current query state
|
|
278
285
|
* @returns QueryAstService instance
|
|
279
286
|
*/
|
|
280
|
-
private astService(state: SelectQueryState = this.state): QueryAstService {
|
|
281
|
-
return this.createQueryAstService(this.table, state);
|
|
282
|
-
}
|
|
283
|
-
|
|
287
|
+
private astService(state: SelectQueryState = this.state): QueryAstService {
|
|
288
|
+
return this.createQueryAstService(this.table, state);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private rootTableName(): string {
|
|
292
|
+
const from = this.state.ast.from;
|
|
293
|
+
if (from.type === 'Table' && from.alias) return from.alias;
|
|
294
|
+
return this.table.name;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
284
297
|
|
|
285
298
|
export type { RelationResult } from './relation-projection-helper.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TableDef } from '../schema/table.js';
|
|
2
|
-
import { SelectQueryNode, CommonTableExpressionNode, OrderByNode, SetOperationNode } from '../core/ast/query.js';
|
|
2
|
+
import { SelectQueryNode, CommonTableExpressionNode, OrderByNode, SetOperationNode, TableSourceNode } from '../core/ast/query.js';
|
|
3
3
|
import {
|
|
4
4
|
ColumnNode,
|
|
5
5
|
ExpressionNode,
|
|
@@ -74,12 +74,24 @@ export class SelectQueryState {
|
|
|
74
74
|
* @param join - Join node to add
|
|
75
75
|
* @returns New SelectQueryState with added join
|
|
76
76
|
*/
|
|
77
|
-
withJoin(join: JoinNode): SelectQueryState {
|
|
78
|
-
return this.clone({
|
|
79
|
-
...this.ast,
|
|
80
|
-
joins: [...(this.ast.joins ?? []), join]
|
|
81
|
-
});
|
|
82
|
-
}
|
|
77
|
+
withJoin(join: JoinNode): SelectQueryState {
|
|
78
|
+
return this.clone({
|
|
79
|
+
...this.ast,
|
|
80
|
+
joins: [...(this.ast.joins ?? []), join]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Replaces the FROM clause.
|
|
86
|
+
* @param from - Table source for the FROM clause
|
|
87
|
+
* @returns New SelectQueryState with updated FROM
|
|
88
|
+
*/
|
|
89
|
+
withFrom(from: TableSourceNode): SelectQueryState {
|
|
90
|
+
return this.clone({
|
|
91
|
+
...this.ast,
|
|
92
|
+
from
|
|
93
|
+
});
|
|
94
|
+
}
|
|
83
95
|
|
|
84
96
|
/**
|
|
85
97
|
* Adds a WHERE clause to the query
|