metal-orm 1.0.2 → 1.0.3
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 +20 -0
- package/package.json +1 -1
- package/src/ast/expression.ts +433 -175
- package/src/ast/join.ts +8 -1
- package/src/ast/query.ts +64 -9
- package/src/builder/hydration-manager.ts +42 -11
- package/src/builder/hydration-planner.ts +80 -31
- package/src/builder/operations/column-selector.ts +37 -1
- package/src/builder/operations/cte-manager.ts +16 -0
- package/src/builder/operations/filter-manager.ts +32 -0
- package/src/builder/operations/join-manager.ts +17 -7
- package/src/builder/operations/pagination-manager.ts +19 -0
- package/src/builder/operations/relation-manager.ts +58 -3
- package/src/builder/query-ast-service.ts +100 -29
- package/src/builder/relation-conditions.ts +30 -1
- package/src/builder/relation-projection-helper.ts +43 -1
- package/src/builder/relation-service.ts +68 -13
- package/src/builder/relation-types.ts +6 -0
- package/src/builder/select-query-builder-deps.ts +64 -3
- package/src/builder/select-query-state.ts +72 -0
- package/src/builder/select.ts +166 -0
- package/src/codegen/typescript.ts +142 -44
- package/src/constants/sql-operator-config.ts +36 -0
- package/src/constants/sql.ts +125 -58
- package/src/dialect/abstract.ts +97 -22
- package/src/dialect/mssql/index.ts +27 -0
- package/src/dialect/mysql/index.ts +22 -0
- package/src/dialect/postgres/index.ts +22 -0
- package/src/dialect/sqlite/index.ts +22 -0
- package/src/runtime/als.ts +15 -1
- package/src/runtime/hydration.ts +20 -15
- package/src/schema/column.ts +45 -5
- package/src/schema/relation.ts +49 -2
- package/src/schema/table.ts +27 -3
- package/src/utils/join-node.ts +20 -0
- package/src/utils/raw-column-parser.ts +32 -0
- package/src/utils/relation-alias.ts +43 -0
|
@@ -1,18 +1,60 @@
|
|
|
1
1
|
import { TableDef } from '../schema/table';
|
|
2
2
|
import { SelectQueryState } from './select-query-state';
|
|
3
3
|
import { HydrationManager } from './hydration-manager';
|
|
4
|
+
import { HydrationPlanner } from './hydration-planner';
|
|
4
5
|
import { QueryAstService } from './query-ast-service';
|
|
5
6
|
import { RelationService } from './relation-service';
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Context for query building operations
|
|
10
|
+
*/
|
|
7
11
|
export interface SelectQueryBuilderContext {
|
|
12
|
+
/**
|
|
13
|
+
* Current query state
|
|
14
|
+
*/
|
|
8
15
|
readonly state: SelectQueryState;
|
|
16
|
+
/**
|
|
17
|
+
* Hydration manager for the query
|
|
18
|
+
*/
|
|
9
19
|
readonly hydration: HydrationManager;
|
|
10
20
|
}
|
|
11
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Dependencies for query builder operations
|
|
24
|
+
*/
|
|
12
25
|
export interface SelectQueryBuilderDependencies {
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new query state
|
|
28
|
+
* @param table - Table definition
|
|
29
|
+
* @returns New query state
|
|
30
|
+
*/
|
|
13
31
|
createState: (table: TableDef) => SelectQueryState;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new hydration manager
|
|
34
|
+
* @param table - Table definition
|
|
35
|
+
* @returns New hydration manager
|
|
36
|
+
*/
|
|
14
37
|
createHydration: (table: TableDef) => HydrationManager;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new hydration planner
|
|
40
|
+
* @param table - Table definition
|
|
41
|
+
* @returns Hydration planner
|
|
42
|
+
*/
|
|
43
|
+
createHydrationPlanner: (table: TableDef) => HydrationPlanner;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new query AST service
|
|
46
|
+
* @param table - Table definition
|
|
47
|
+
* @param state - Query state
|
|
48
|
+
* @returns New query AST service
|
|
49
|
+
*/
|
|
15
50
|
createQueryAstService: (table: TableDef, state: SelectQueryState) => QueryAstService;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new relation service
|
|
53
|
+
* @param table - Table definition
|
|
54
|
+
* @param state - Query state
|
|
55
|
+
* @param hydration - Hydration manager
|
|
56
|
+
* @returns New relation service
|
|
57
|
+
*/
|
|
16
58
|
createRelationService: (
|
|
17
59
|
table: TableDef,
|
|
18
60
|
state: SelectQueryState,
|
|
@@ -20,14 +62,33 @@ export interface SelectQueryBuilderDependencies {
|
|
|
20
62
|
) => RelationService;
|
|
21
63
|
}
|
|
22
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Environment for query builder operations
|
|
67
|
+
*/
|
|
23
68
|
export interface SelectQueryBuilderEnvironment {
|
|
69
|
+
/**
|
|
70
|
+
* Table definition
|
|
71
|
+
*/
|
|
24
72
|
readonly table: TableDef;
|
|
73
|
+
/**
|
|
74
|
+
* Query builder dependencies
|
|
75
|
+
*/
|
|
25
76
|
readonly deps: SelectQueryBuilderDependencies;
|
|
26
77
|
}
|
|
27
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Default implementation of query builder dependencies
|
|
81
|
+
*/
|
|
82
|
+
const defaultCreateQueryAstService = (table: TableDef, state: SelectQueryState) => new QueryAstService(table, state);
|
|
83
|
+
const defaultCreateHydrationPlanner = (table: TableDef) => new HydrationPlanner(table);
|
|
84
|
+
const defaultCreateHydration = (table: TableDef) =>
|
|
85
|
+
new HydrationManager(table, defaultCreateHydrationPlanner(table));
|
|
86
|
+
|
|
28
87
|
export const defaultSelectQueryBuilderDependencies: SelectQueryBuilderDependencies = {
|
|
29
88
|
createState: table => new SelectQueryState(table),
|
|
30
|
-
createHydration:
|
|
31
|
-
|
|
32
|
-
|
|
89
|
+
createHydration: defaultCreateHydration,
|
|
90
|
+
createHydrationPlanner: defaultCreateHydrationPlanner,
|
|
91
|
+
createQueryAstService: defaultCreateQueryAstService,
|
|
92
|
+
createRelationService: (table, state, hydration) =>
|
|
93
|
+
new RelationService(table, state, hydration, defaultCreateQueryAstService)
|
|
33
94
|
};
|
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
} from '../ast/expression';
|
|
11
11
|
import { JoinNode } from '../ast/join';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Node types that can be used in query projections
|
|
15
|
+
*/
|
|
13
16
|
export type ProjectionNode =
|
|
14
17
|
| ColumnNode
|
|
15
18
|
| FunctionNode
|
|
@@ -17,10 +20,24 @@ export type ProjectionNode =
|
|
|
17
20
|
| CaseExpressionNode
|
|
18
21
|
| WindowFunctionNode;
|
|
19
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Manages the state of a SELECT query being built
|
|
25
|
+
*/
|
|
20
26
|
export class SelectQueryState {
|
|
27
|
+
/**
|
|
28
|
+
* Table definition for the query
|
|
29
|
+
*/
|
|
21
30
|
public readonly table: TableDef;
|
|
31
|
+
/**
|
|
32
|
+
* Abstract Syntax Tree (AST) representation of the query
|
|
33
|
+
*/
|
|
22
34
|
public readonly ast: SelectQueryNode;
|
|
23
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new SelectQueryState instance
|
|
38
|
+
* @param table - Table definition
|
|
39
|
+
* @param ast - Optional existing AST
|
|
40
|
+
*/
|
|
24
41
|
constructor(table: TableDef, ast?: SelectQueryNode) {
|
|
25
42
|
this.table = table;
|
|
26
43
|
this.ast = ast ?? {
|
|
@@ -31,10 +48,20 @@ export class SelectQueryState {
|
|
|
31
48
|
};
|
|
32
49
|
}
|
|
33
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new SelectQueryState with updated AST
|
|
53
|
+
* @param nextAst - Updated AST
|
|
54
|
+
* @returns New SelectQueryState instance
|
|
55
|
+
*/
|
|
34
56
|
private clone(nextAst: SelectQueryNode): SelectQueryState {
|
|
35
57
|
return new SelectQueryState(this.table, nextAst);
|
|
36
58
|
}
|
|
37
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Adds columns to the query
|
|
62
|
+
* @param newCols - Columns to add
|
|
63
|
+
* @returns New SelectQueryState with added columns
|
|
64
|
+
*/
|
|
38
65
|
withColumns(newCols: ProjectionNode[]): SelectQueryState {
|
|
39
66
|
return this.clone({
|
|
40
67
|
...this.ast,
|
|
@@ -42,6 +69,11 @@ export class SelectQueryState {
|
|
|
42
69
|
});
|
|
43
70
|
}
|
|
44
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Adds a join to the query
|
|
74
|
+
* @param join - Join node to add
|
|
75
|
+
* @returns New SelectQueryState with added join
|
|
76
|
+
*/
|
|
45
77
|
withJoin(join: JoinNode): SelectQueryState {
|
|
46
78
|
return this.clone({
|
|
47
79
|
...this.ast,
|
|
@@ -49,6 +81,11 @@ export class SelectQueryState {
|
|
|
49
81
|
});
|
|
50
82
|
}
|
|
51
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Adds a WHERE clause to the query
|
|
86
|
+
* @param predicate - WHERE predicate expression
|
|
87
|
+
* @returns New SelectQueryState with WHERE clause
|
|
88
|
+
*/
|
|
52
89
|
withWhere(predicate: ExpressionNode): SelectQueryState {
|
|
53
90
|
return this.clone({
|
|
54
91
|
...this.ast,
|
|
@@ -56,6 +93,11 @@ export class SelectQueryState {
|
|
|
56
93
|
});
|
|
57
94
|
}
|
|
58
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Adds a HAVING clause to the query
|
|
98
|
+
* @param predicate - HAVING predicate expression
|
|
99
|
+
* @returns New SelectQueryState with HAVING clause
|
|
100
|
+
*/
|
|
59
101
|
withHaving(predicate: ExpressionNode): SelectQueryState {
|
|
60
102
|
return this.clone({
|
|
61
103
|
...this.ast,
|
|
@@ -63,6 +105,11 @@ export class SelectQueryState {
|
|
|
63
105
|
});
|
|
64
106
|
}
|
|
65
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Adds GROUP BY columns to the query
|
|
110
|
+
* @param columns - Columns to group by
|
|
111
|
+
* @returns New SelectQueryState with GROUP BY clause
|
|
112
|
+
*/
|
|
66
113
|
withGroupBy(columns: ColumnNode[]): SelectQueryState {
|
|
67
114
|
return this.clone({
|
|
68
115
|
...this.ast,
|
|
@@ -70,6 +117,11 @@ export class SelectQueryState {
|
|
|
70
117
|
});
|
|
71
118
|
}
|
|
72
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Adds ORDER BY clauses to the query
|
|
122
|
+
* @param orderBy - ORDER BY nodes
|
|
123
|
+
* @returns New SelectQueryState with ORDER BY clause
|
|
124
|
+
*/
|
|
73
125
|
withOrderBy(orderBy: OrderByNode[]): SelectQueryState {
|
|
74
126
|
return this.clone({
|
|
75
127
|
...this.ast,
|
|
@@ -77,6 +129,11 @@ export class SelectQueryState {
|
|
|
77
129
|
});
|
|
78
130
|
}
|
|
79
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Adds DISTINCT columns to the query
|
|
134
|
+
* @param columns - Columns to make distinct
|
|
135
|
+
* @returns New SelectQueryState with DISTINCT clause
|
|
136
|
+
*/
|
|
80
137
|
withDistinct(columns: ColumnNode[]): SelectQueryState {
|
|
81
138
|
return this.clone({
|
|
82
139
|
...this.ast,
|
|
@@ -84,6 +141,11 @@ export class SelectQueryState {
|
|
|
84
141
|
});
|
|
85
142
|
}
|
|
86
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Adds a LIMIT clause to the query
|
|
146
|
+
* @param limit - Maximum number of rows to return
|
|
147
|
+
* @returns New SelectQueryState with LIMIT clause
|
|
148
|
+
*/
|
|
87
149
|
withLimit(limit: number): SelectQueryState {
|
|
88
150
|
return this.clone({
|
|
89
151
|
...this.ast,
|
|
@@ -91,6 +153,11 @@ export class SelectQueryState {
|
|
|
91
153
|
});
|
|
92
154
|
}
|
|
93
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Adds an OFFSET clause to the query
|
|
158
|
+
* @param offset - Number of rows to skip
|
|
159
|
+
* @returns New SelectQueryState with OFFSET clause
|
|
160
|
+
*/
|
|
94
161
|
withOffset(offset: number): SelectQueryState {
|
|
95
162
|
return this.clone({
|
|
96
163
|
...this.ast,
|
|
@@ -98,6 +165,11 @@ export class SelectQueryState {
|
|
|
98
165
|
});
|
|
99
166
|
}
|
|
100
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
170
|
+
* @param cte - CTE node to add
|
|
171
|
+
* @returns New SelectQueryState with CTE
|
|
172
|
+
*/
|
|
101
173
|
withCte(cte: CommonTableExpressionNode): SelectQueryState {
|
|
102
174
|
return this.clone({
|
|
103
175
|
...this.ast,
|
package/src/builder/select.ts
CHANGED
|
@@ -29,6 +29,10 @@ import { PaginationManager } from './operations/pagination-manager';
|
|
|
29
29
|
import { RelationManager, RelationIncludeOptions } from './operations/relation-manager';
|
|
30
30
|
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../constants/sql';
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Main query builder class for constructing SQL SELECT queries
|
|
34
|
+
* @typeParam T - Type of the result data
|
|
35
|
+
*/
|
|
32
36
|
export class SelectQueryBuilder<T> {
|
|
33
37
|
private readonly env: SelectQueryBuilderEnvironment;
|
|
34
38
|
private readonly context: SelectQueryBuilderContext;
|
|
@@ -39,6 +43,13 @@ export class SelectQueryBuilder<T> {
|
|
|
39
43
|
private readonly paginationManager: PaginationManager;
|
|
40
44
|
private readonly relationManager: RelationManager;
|
|
41
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new SelectQueryBuilder instance
|
|
48
|
+
* @param table - Table definition to query
|
|
49
|
+
* @param state - Optional initial query state
|
|
50
|
+
* @param hydration - Optional hydration manager
|
|
51
|
+
* @param dependencies - Optional query builder dependencies
|
|
52
|
+
*/
|
|
42
53
|
constructor(
|
|
43
54
|
table: TableDef,
|
|
44
55
|
state?: SelectQueryState,
|
|
@@ -75,51 +86,112 @@ export class SelectQueryBuilder<T> {
|
|
|
75
86
|
return new SelectQueryBuilder(table, undefined, undefined, this.env.deps);
|
|
76
87
|
}
|
|
77
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Selects specific columns for the query
|
|
91
|
+
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
92
|
+
* @returns New query builder instance with selected columns
|
|
93
|
+
*/
|
|
78
94
|
select(columns: Record<string, ColumnDef | FunctionNode | CaseExpressionNode | WindowFunctionNode>): SelectQueryBuilder<T> {
|
|
79
95
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
80
96
|
}
|
|
81
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Selects raw column expressions
|
|
100
|
+
* @param cols - Column expressions as strings
|
|
101
|
+
* @returns New query builder instance with raw column selections
|
|
102
|
+
*/
|
|
82
103
|
selectRaw(...cols: string[]): SelectQueryBuilder<T> {
|
|
83
104
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
84
105
|
}
|
|
85
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
109
|
+
* @param name - Name of the CTE
|
|
110
|
+
* @param query - Query builder or query node for the CTE
|
|
111
|
+
* @param columns - Optional column names for the CTE
|
|
112
|
+
* @returns New query builder instance with the CTE
|
|
113
|
+
*/
|
|
86
114
|
with(name: string, query: SelectQueryBuilder<any> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T> {
|
|
87
115
|
const subAst = this.resolveQueryNode(query);
|
|
88
116
|
const nextContext = this.cteManager.withCte(this.context, name, subAst, columns, false);
|
|
89
117
|
return this.clone(nextContext);
|
|
90
118
|
}
|
|
91
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Adds a recursive Common Table Expression (CTE) to the query
|
|
122
|
+
* @param name - Name of the CTE
|
|
123
|
+
* @param query - Query builder or query node for the CTE
|
|
124
|
+
* @param columns - Optional column names for the CTE
|
|
125
|
+
* @returns New query builder instance with the recursive CTE
|
|
126
|
+
*/
|
|
92
127
|
withRecursive(name: string, query: SelectQueryBuilder<any> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T> {
|
|
93
128
|
const subAst = this.resolveQueryNode(query);
|
|
94
129
|
const nextContext = this.cteManager.withCte(this.context, name, subAst, columns, true);
|
|
95
130
|
return this.clone(nextContext);
|
|
96
131
|
}
|
|
97
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Selects a subquery as a column
|
|
135
|
+
* @param alias - Alias for the subquery column
|
|
136
|
+
* @param sub - Query builder or query node for the subquery
|
|
137
|
+
* @returns New query builder instance with the subquery selection
|
|
138
|
+
*/
|
|
98
139
|
selectSubquery(alias: string, sub: SelectQueryBuilder<any> | SelectQueryNode): SelectQueryBuilder<T> {
|
|
99
140
|
const query = this.resolveQueryNode(sub);
|
|
100
141
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
101
142
|
}
|
|
102
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Adds an INNER JOIN to the query
|
|
146
|
+
* @param table - Table to join
|
|
147
|
+
* @param condition - Join condition expression
|
|
148
|
+
* @returns New query builder instance with the INNER JOIN
|
|
149
|
+
*/
|
|
103
150
|
innerJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T> {
|
|
104
151
|
const nextContext = this.joinManager.join(this.context, table, condition, JOIN_KINDS.INNER);
|
|
105
152
|
return this.clone(nextContext);
|
|
106
153
|
}
|
|
107
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Adds a LEFT JOIN to the query
|
|
157
|
+
* @param table - Table to join
|
|
158
|
+
* @param condition - Join condition expression
|
|
159
|
+
* @returns New query builder instance with the LEFT JOIN
|
|
160
|
+
*/
|
|
108
161
|
leftJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T> {
|
|
109
162
|
const nextContext = this.joinManager.join(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
110
163
|
return this.clone(nextContext);
|
|
111
164
|
}
|
|
112
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Adds a RIGHT JOIN to the query
|
|
168
|
+
* @param table - Table to join
|
|
169
|
+
* @param condition - Join condition expression
|
|
170
|
+
* @returns New query builder instance with the RIGHT JOIN
|
|
171
|
+
*/
|
|
113
172
|
rightJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T> {
|
|
114
173
|
const nextContext = this.joinManager.join(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
115
174
|
return this.clone(nextContext);
|
|
116
175
|
}
|
|
117
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Matches records based on a relationship
|
|
179
|
+
* @param relationName - Name of the relationship to match
|
|
180
|
+
* @param predicate - Optional predicate expression
|
|
181
|
+
* @returns New query builder instance with the relationship match
|
|
182
|
+
*/
|
|
118
183
|
match(relationName: string, predicate?: ExpressionNode): SelectQueryBuilder<T> {
|
|
119
184
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
120
185
|
return this.clone(nextContext);
|
|
121
186
|
}
|
|
122
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Joins a related table
|
|
190
|
+
* @param relationName - Name of the relationship to join
|
|
191
|
+
* @param joinKind - Type of join (defaults to INNER)
|
|
192
|
+
* @param extraCondition - Optional additional join condition
|
|
193
|
+
* @returns New query builder instance with the relationship join
|
|
194
|
+
*/
|
|
123
195
|
joinRelation(
|
|
124
196
|
relationName: string,
|
|
125
197
|
joinKind: JoinKind = JOIN_KINDS.INNER,
|
|
@@ -129,55 +201,113 @@ export class SelectQueryBuilder<T> {
|
|
|
129
201
|
return this.clone(nextContext);
|
|
130
202
|
}
|
|
131
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Includes related data in the query results
|
|
206
|
+
* @param relationName - Name of the relationship to include
|
|
207
|
+
* @param options - Optional include options
|
|
208
|
+
* @returns New query builder instance with the relationship inclusion
|
|
209
|
+
*/
|
|
132
210
|
include(relationName: string, options?: RelationIncludeOptions): SelectQueryBuilder<T> {
|
|
133
211
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
134
212
|
return this.clone(nextContext);
|
|
135
213
|
}
|
|
136
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Adds a WHERE condition to the query
|
|
217
|
+
* @param expr - Expression for the WHERE clause
|
|
218
|
+
* @returns New query builder instance with the WHERE condition
|
|
219
|
+
*/
|
|
137
220
|
where(expr: ExpressionNode): SelectQueryBuilder<T> {
|
|
138
221
|
const nextContext = this.filterManager.where(this.context, expr);
|
|
139
222
|
return this.clone(nextContext);
|
|
140
223
|
}
|
|
141
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Adds a GROUP BY clause to the query
|
|
227
|
+
* @param col - Column definition or column node to group by
|
|
228
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
229
|
+
*/
|
|
142
230
|
groupBy(col: ColumnDef | ColumnNode): SelectQueryBuilder<T> {
|
|
143
231
|
const nextContext = this.filterManager.groupBy(this.context, col);
|
|
144
232
|
return this.clone(nextContext);
|
|
145
233
|
}
|
|
146
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Adds a HAVING condition to the query
|
|
237
|
+
* @param expr - Expression for the HAVING clause
|
|
238
|
+
* @returns New query builder instance with the HAVING condition
|
|
239
|
+
*/
|
|
147
240
|
having(expr: ExpressionNode): SelectQueryBuilder<T> {
|
|
148
241
|
const nextContext = this.filterManager.having(this.context, expr);
|
|
149
242
|
return this.clone(nextContext);
|
|
150
243
|
}
|
|
151
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Adds an ORDER BY clause to the query
|
|
247
|
+
* @param col - Column definition or column node to order by
|
|
248
|
+
* @param direction - Order direction (defaults to ASC)
|
|
249
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
250
|
+
*/
|
|
152
251
|
orderBy(col: ColumnDef | ColumnNode, direction: OrderDirection = ORDER_DIRECTIONS.ASC): SelectQueryBuilder<T> {
|
|
153
252
|
const nextContext = this.filterManager.orderBy(this.context, col, direction);
|
|
154
253
|
return this.clone(nextContext);
|
|
155
254
|
}
|
|
156
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Adds a DISTINCT clause to the query
|
|
258
|
+
* @param cols - Columns to make distinct
|
|
259
|
+
* @returns New query builder instance with the DISTINCT clause
|
|
260
|
+
*/
|
|
157
261
|
distinct(...cols: (ColumnDef | ColumnNode)[]): SelectQueryBuilder<T> {
|
|
158
262
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
159
263
|
}
|
|
160
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Adds a LIMIT clause to the query
|
|
267
|
+
* @param n - Maximum number of rows to return
|
|
268
|
+
* @returns New query builder instance with the LIMIT clause
|
|
269
|
+
*/
|
|
161
270
|
limit(n: number): SelectQueryBuilder<T> {
|
|
162
271
|
const nextContext = this.paginationManager.limit(this.context, n);
|
|
163
272
|
return this.clone(nextContext);
|
|
164
273
|
}
|
|
165
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Adds an OFFSET clause to the query
|
|
277
|
+
* @param n - Number of rows to skip
|
|
278
|
+
* @returns New query builder instance with the OFFSET clause
|
|
279
|
+
*/
|
|
166
280
|
offset(n: number): SelectQueryBuilder<T> {
|
|
167
281
|
const nextContext = this.paginationManager.offset(this.context, n);
|
|
168
282
|
return this.clone(nextContext);
|
|
169
283
|
}
|
|
170
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Adds a WHERE EXISTS condition to the query
|
|
287
|
+
* @param subquery - Subquery to check for existence
|
|
288
|
+
* @returns New query builder instance with the WHERE EXISTS condition
|
|
289
|
+
*/
|
|
171
290
|
whereExists(subquery: SelectQueryBuilder<any> | SelectQueryNode): SelectQueryBuilder<T> {
|
|
172
291
|
const subAst = this.resolveQueryNode(subquery);
|
|
173
292
|
return this.where(exists(subAst));
|
|
174
293
|
}
|
|
175
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Adds a WHERE NOT EXISTS condition to the query
|
|
297
|
+
* @param subquery - Subquery to check for non-existence
|
|
298
|
+
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
299
|
+
*/
|
|
176
300
|
whereNotExists(subquery: SelectQueryBuilder<any> | SelectQueryNode): SelectQueryBuilder<T> {
|
|
177
301
|
const subAst = this.resolveQueryNode(subquery);
|
|
178
302
|
return this.where(notExists(subAst));
|
|
179
303
|
}
|
|
180
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Adds a WHERE EXISTS condition based on a relationship
|
|
307
|
+
* @param relationName - Name of the relationship to check
|
|
308
|
+
* @param callback - Optional callback to modify the relationship query
|
|
309
|
+
* @returns New query builder instance with the relationship existence check
|
|
310
|
+
*/
|
|
181
311
|
whereHas(
|
|
182
312
|
relationName: string,
|
|
183
313
|
callback?: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>
|
|
@@ -197,6 +327,12 @@ export class SelectQueryBuilder<T> {
|
|
|
197
327
|
return this.where(exists(finalSubAst));
|
|
198
328
|
}
|
|
199
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
332
|
+
* @param relationName - Name of the relationship to check
|
|
333
|
+
* @param callback - Optional callback to modify the relationship query
|
|
334
|
+
* @returns New query builder instance with the relationship non-existence check
|
|
335
|
+
*/
|
|
200
336
|
whereHasNot(
|
|
201
337
|
relationName: string,
|
|
202
338
|
callback?: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>
|
|
@@ -216,22 +352,52 @@ export class SelectQueryBuilder<T> {
|
|
|
216
352
|
return this.where(notExists(finalSubAst));
|
|
217
353
|
}
|
|
218
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Compiles the query to SQL for a specific dialect
|
|
357
|
+
* @param dialect - Database dialect to compile for
|
|
358
|
+
* @returns Compiled query with SQL and parameters
|
|
359
|
+
*/
|
|
219
360
|
compile(dialect: Dialect): CompiledQuery {
|
|
220
361
|
return dialect.compileSelect(this.context.state.ast);
|
|
221
362
|
}
|
|
222
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Converts the query to SQL string for a specific dialect
|
|
366
|
+
* @param dialect - Database dialect to generate SQL for
|
|
367
|
+
* @returns SQL string representation of the query
|
|
368
|
+
*/
|
|
223
369
|
toSql(dialect: Dialect): string {
|
|
224
370
|
return this.compile(dialect).sql;
|
|
225
371
|
}
|
|
226
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Gets the hydration plan for the query
|
|
375
|
+
* @returns Hydration plan or undefined if none exists
|
|
376
|
+
*/
|
|
227
377
|
getHydrationPlan(): HydrationPlan | undefined {
|
|
228
378
|
return this.context.hydration.getPlan();
|
|
229
379
|
}
|
|
230
380
|
|
|
381
|
+
/**
|
|
382
|
+
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
383
|
+
* @returns Query AST with hydration applied
|
|
384
|
+
*/
|
|
231
385
|
getAST(): SelectQueryNode {
|
|
232
386
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
233
387
|
}
|
|
234
388
|
}
|
|
235
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Creates a column node for use in expressions
|
|
392
|
+
* @param table - Table name
|
|
393
|
+
* @param name - Column name
|
|
394
|
+
* @returns ColumnNode with the specified table and name
|
|
395
|
+
*/
|
|
236
396
|
export const createColumn = (table: string, name: string): ColumnNode => ({ type: 'Column', table, name });
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Creates a literal value node for use in expressions
|
|
400
|
+
* @param val - Literal value (string or number)
|
|
401
|
+
* @returns LiteralNode with the specified value
|
|
402
|
+
*/
|
|
237
403
|
export const createLiteral = (val: string | number): LiteralNode => ({ type: 'Literal', value: val });
|