metal-orm 1.0.39 → 1.0.40
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/index.cjs +230 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -24
- package/dist/index.d.ts +71 -24
- package/dist/index.js +225 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/typescript.ts +60 -3
- package/src/core/ast/aggregate-functions.ts +15 -15
- package/src/core/ast/expression-builders.ts +357 -316
- package/src/core/ast/expression-nodes.ts +208 -186
- package/src/core/ast/expression-visitor.ts +40 -30
- package/src/core/ast/query.ts +142 -132
- package/src/core/ast/window-functions.ts +86 -86
- package/src/core/dialect/abstract.ts +505 -479
- package/src/core/dialect/base/groupby-compiler.ts +6 -6
- package/src/core/dialect/base/orderby-compiler.ts +20 -6
- package/src/core/dialect/base/sql-dialect.ts +154 -136
- package/src/core/dialect/mssql/index.ts +172 -161
- package/src/core/functions/standard-strategy.ts +46 -37
- package/src/query-builder/hydration-manager.ts +93 -79
- package/src/query-builder/query-ast-service.ts +207 -170
- package/src/query-builder/select-query-state.ts +169 -162
- package/src/query-builder/select.ts +15 -23
|
@@ -1,68 +1,70 @@
|
|
|
1
|
-
import { SelectQueryNode } from './query.js';
|
|
2
|
-
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
-
import { ColumnRef } from './types.js';
|
|
4
|
-
import {
|
|
5
|
-
ColumnNode,
|
|
6
|
-
FunctionNode,
|
|
7
|
-
LiteralNode,
|
|
8
|
-
JsonPathNode,
|
|
9
|
-
OperandNode,
|
|
10
|
-
CaseExpressionNode,
|
|
11
|
-
WindowFunctionNode,
|
|
12
|
-
BinaryExpressionNode,
|
|
13
|
-
ExpressionNode,
|
|
14
|
-
LogicalExpressionNode,
|
|
15
|
-
NullExpressionNode,
|
|
16
|
-
InExpressionNode,
|
|
17
|
-
ExistsExpressionNode,
|
|
18
|
-
BetweenExpressionNode,
|
|
19
|
-
isOperandNode
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
import { SelectQueryNode } from './query.js';
|
|
2
|
+
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
+
import { ColumnRef } from './types.js';
|
|
4
|
+
import {
|
|
5
|
+
ColumnNode,
|
|
6
|
+
FunctionNode,
|
|
7
|
+
LiteralNode,
|
|
8
|
+
JsonPathNode,
|
|
9
|
+
OperandNode,
|
|
10
|
+
CaseExpressionNode,
|
|
11
|
+
WindowFunctionNode,
|
|
12
|
+
BinaryExpressionNode,
|
|
13
|
+
ExpressionNode,
|
|
14
|
+
LogicalExpressionNode,
|
|
15
|
+
NullExpressionNode,
|
|
16
|
+
InExpressionNode,
|
|
17
|
+
ExistsExpressionNode,
|
|
18
|
+
BetweenExpressionNode,
|
|
19
|
+
isOperandNode,
|
|
20
|
+
AliasRefNode,
|
|
21
|
+
ArithmeticExpressionNode
|
|
22
|
+
} from './expression-nodes.js';
|
|
23
|
+
|
|
24
|
+
export type LiteralValue = LiteralNode['value'];
|
|
25
|
+
export type ValueOperandInput = OperandNode | LiteralValue;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Converts a primitive or existing operand into an operand node
|
|
29
|
+
* @param value - Value or operand to normalize
|
|
30
|
+
* @returns OperandNode representing the value
|
|
31
|
+
*/
|
|
32
|
+
export const valueToOperand = (value: ValueOperandInput): OperandNode => {
|
|
33
|
+
if (isOperandNode(value)) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
type: 'Literal',
|
|
39
|
+
value
|
|
40
|
+
} as LiteralNode;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const toNode = (col: ColumnRef | OperandNode): OperandNode => {
|
|
44
|
+
if (isOperandNode(col)) return col as OperandNode;
|
|
45
|
+
const def = col as ColumnRef;
|
|
46
|
+
return { type: 'Column', table: def.table || 'unknown', name: def.name };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const toLiteralNode = (value: string | number | boolean | null): LiteralNode => ({
|
|
50
|
+
type: 'Literal',
|
|
51
|
+
value
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const isLiteralValue = (value: unknown): value is LiteralValue =>
|
|
55
|
+
value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
56
|
+
|
|
57
|
+
export const isValueOperandInput = (value: unknown): value is ValueOperandInput =>
|
|
58
|
+
isOperandNode(value) || isLiteralValue(value);
|
|
59
|
+
|
|
60
|
+
const toOperand = (val: OperandNode | ColumnRef | LiteralValue): OperandNode => {
|
|
61
|
+
if (isLiteralValue(val)) {
|
|
62
|
+
return valueToOperand(val);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return toNode(val);
|
|
66
|
+
};
|
|
67
|
+
|
|
66
68
|
export const columnOperand = (col: ColumnRef | ColumnNode): ColumnNode => toNode(col) as ColumnNode;
|
|
67
69
|
/**
|
|
68
70
|
* Marks a column reference as an outer-scope reference for correlated subqueries.
|
|
@@ -73,258 +75,297 @@ export const outerRef = (col: ColumnRef | ColumnNode): ColumnNode => ({
|
|
|
73
75
|
scope: 'outer'
|
|
74
76
|
});
|
|
75
77
|
|
|
78
|
+
/**
|
|
79
|
+
* References a SELECT alias (useful for ORDER BY / GROUP BY).
|
|
80
|
+
*/
|
|
81
|
+
export const aliasRef = (name: string): AliasRefNode => ({
|
|
82
|
+
type: 'AliasRef',
|
|
83
|
+
name
|
|
84
|
+
});
|
|
85
|
+
|
|
76
86
|
/**
|
|
77
87
|
* Creates an outer-scoped column reference using a specific table or alias name.
|
|
78
88
|
*/
|
|
79
89
|
export const correlateBy = (table: string, column: string): ColumnNode => outerRef({ name: column, table });
|
|
80
|
-
|
|
81
|
-
const createBinaryExpression = (
|
|
82
|
-
operator: SqlOperator,
|
|
83
|
-
left: OperandNode | ColumnRef,
|
|
84
|
-
right: OperandNode | ColumnRef | string | number | boolean | null,
|
|
85
|
-
escape?: string
|
|
86
|
-
): BinaryExpressionNode => {
|
|
87
|
-
const node: BinaryExpressionNode = {
|
|
88
|
-
type: 'BinaryExpression',
|
|
89
|
-
left: toNode(left),
|
|
90
|
-
operator,
|
|
91
|
-
right: toOperand(right)
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
if (escape !== undefined) {
|
|
95
|
-
node.escape = toLiteralNode(escape);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return node;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Creates an equality expression (left = right)
|
|
103
|
-
* @param left - Left operand
|
|
104
|
-
* @param right - Right operand
|
|
105
|
-
* @returns Binary expression node with equality operator
|
|
106
|
-
*/
|
|
107
|
-
export const eq = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number | boolean): BinaryExpressionNode =>
|
|
108
|
-
createBinaryExpression('=', left, right);
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Creates a not equal expression (left != right)
|
|
112
|
-
*/
|
|
113
|
-
export const neq = (
|
|
114
|
-
left: OperandNode | ColumnRef,
|
|
115
|
-
right: OperandNode | ColumnRef | string | number | boolean
|
|
116
|
-
): BinaryExpressionNode => createBinaryExpression('!=', left, right);
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Creates a greater-than expression (left > right)
|
|
120
|
-
* @param left - Left operand
|
|
121
|
-
* @param right - Right operand
|
|
122
|
-
* @returns Binary expression node with greater-than operator
|
|
123
|
-
*/
|
|
124
|
-
export const gt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
125
|
-
createBinaryExpression('>', left, right);
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Creates a greater than or equal expression (left >= right)
|
|
129
|
-
*/
|
|
130
|
-
export const gte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
131
|
-
createBinaryExpression('>=', left, right);
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Creates a less-than expression (left < right)
|
|
135
|
-
* @param left - Left operand
|
|
136
|
-
* @param right - Right operand
|
|
137
|
-
* @returns Binary expression node with less-than operator
|
|
138
|
-
*/
|
|
139
|
-
export const lt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
140
|
-
createBinaryExpression('<', left, right);
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Creates a less than or equal expression (left <= right)
|
|
144
|
-
*/
|
|
145
|
-
export const lte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
146
|
-
createBinaryExpression('<=', left, right);
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Creates a LIKE pattern matching expression
|
|
150
|
-
* @param left - Left operand
|
|
151
|
-
* @param pattern - Pattern to match
|
|
152
|
-
* @param escape - Optional escape character
|
|
153
|
-
* @returns Binary expression node with LIKE operator
|
|
154
|
-
*/
|
|
155
|
-
export const like = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
156
|
-
createBinaryExpression('LIKE', left, pattern, escape);
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Creates a NOT LIKE pattern matching expression
|
|
160
|
-
* @param left - Left operand
|
|
161
|
-
* @param pattern - Pattern to match
|
|
162
|
-
* @param escape - Optional escape character
|
|
163
|
-
* @returns Binary expression node with NOT LIKE operator
|
|
164
|
-
*/
|
|
165
|
-
export const notLike = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
166
|
-
createBinaryExpression('NOT LIKE', left, pattern, escape);
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Creates a logical AND expression
|
|
170
|
-
* @param operands - Expressions to combine with AND
|
|
171
|
-
* @returns Logical expression node with AND operator
|
|
172
|
-
*/
|
|
173
|
-
export const and = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
174
|
-
type: 'LogicalExpression',
|
|
175
|
-
operator: 'AND',
|
|
176
|
-
operands
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Creates a logical OR expression
|
|
181
|
-
* @param operands - Expressions to combine with OR
|
|
182
|
-
* @returns Logical expression node with OR operator
|
|
183
|
-
*/
|
|
184
|
-
export const or = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
185
|
-
type: 'LogicalExpression',
|
|
186
|
-
operator: 'OR',
|
|
187
|
-
operands
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Creates an IS NULL expression
|
|
192
|
-
* @param left - Operand to check for null
|
|
193
|
-
* @returns Null expression node with IS NULL operator
|
|
194
|
-
*/
|
|
195
|
-
export const isNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
196
|
-
type: 'NullExpression',
|
|
197
|
-
left: toNode(left),
|
|
198
|
-
operator: 'IS NULL'
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Creates an IS NOT NULL expression
|
|
203
|
-
* @param left - Operand to check for non-null
|
|
204
|
-
* @returns Null expression node with IS NOT NULL operator
|
|
205
|
-
*/
|
|
206
|
-
export const isNotNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
207
|
-
type: 'NullExpression',
|
|
208
|
-
left: toNode(left),
|
|
209
|
-
operator: 'IS NOT NULL'
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
const createInExpression = (
|
|
213
|
-
operator: 'IN' | 'NOT IN',
|
|
214
|
-
left: OperandNode | ColumnRef,
|
|
215
|
-
values: (string | number | LiteralNode)[]
|
|
216
|
-
): InExpressionNode => ({
|
|
217
|
-
type: 'InExpression',
|
|
218
|
-
left: toNode(left),
|
|
219
|
-
operator,
|
|
220
|
-
right: values.map(v => toOperand(v))
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Creates an IN expression (value IN list)
|
|
225
|
-
* @param left - Operand to check
|
|
226
|
-
* @param values - Values to check against
|
|
227
|
-
* @returns IN expression node
|
|
228
|
-
*/
|
|
229
|
-
export const inList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
230
|
-
createInExpression('IN', left, values);
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Creates a NOT IN expression (value NOT IN list)
|
|
234
|
-
* @param left - Operand to check
|
|
235
|
-
* @param values - Values to check against
|
|
236
|
-
* @returns NOT IN expression node
|
|
237
|
-
*/
|
|
238
|
-
export const notInList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
239
|
-
createInExpression('NOT IN', left, values);
|
|
240
|
-
|
|
241
|
-
const createBetweenExpression = (
|
|
242
|
-
operator: 'BETWEEN' | 'NOT BETWEEN',
|
|
243
|
-
left: OperandNode | ColumnRef,
|
|
244
|
-
lower: OperandNode | ColumnRef | string | number,
|
|
245
|
-
upper: OperandNode | ColumnRef | string | number
|
|
246
|
-
): BetweenExpressionNode => ({
|
|
247
|
-
type: 'BetweenExpression',
|
|
248
|
-
left: toNode(left),
|
|
249
|
-
operator,
|
|
250
|
-
lower: toOperand(lower),
|
|
251
|
-
upper: toOperand(upper)
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Creates a BETWEEN expression (value BETWEEN lower AND upper)
|
|
256
|
-
* @param left - Operand to check
|
|
257
|
-
* @param lower - Lower bound
|
|
258
|
-
* @param upper - Upper bound
|
|
259
|
-
* @returns BETWEEN expression node
|
|
260
|
-
*/
|
|
261
|
-
export const between = (
|
|
262
|
-
left: OperandNode | ColumnRef,
|
|
263
|
-
lower: OperandNode | ColumnRef | string | number,
|
|
264
|
-
upper: OperandNode | ColumnRef | string | number
|
|
265
|
-
): BetweenExpressionNode => createBetweenExpression('BETWEEN', left, lower, upper);
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Creates a NOT BETWEEN expression (value NOT BETWEEN lower AND upper)
|
|
269
|
-
* @param left - Operand to check
|
|
270
|
-
* @param lower - Lower bound
|
|
271
|
-
* @param upper - Upper bound
|
|
272
|
-
* @returns NOT BETWEEN expression node
|
|
273
|
-
*/
|
|
274
|
-
export const notBetween = (
|
|
275
|
-
left: OperandNode | ColumnRef,
|
|
276
|
-
lower: OperandNode | ColumnRef | string | number,
|
|
277
|
-
upper: OperandNode | ColumnRef | string | number
|
|
278
|
-
): BetweenExpressionNode => createBetweenExpression('NOT BETWEEN', left, lower, upper);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
*
|
|
313
|
-
* @
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
*
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
90
|
+
|
|
91
|
+
const createBinaryExpression = (
|
|
92
|
+
operator: SqlOperator,
|
|
93
|
+
left: OperandNode | ColumnRef,
|
|
94
|
+
right: OperandNode | ColumnRef | string | number | boolean | null,
|
|
95
|
+
escape?: string
|
|
96
|
+
): BinaryExpressionNode => {
|
|
97
|
+
const node: BinaryExpressionNode = {
|
|
98
|
+
type: 'BinaryExpression',
|
|
99
|
+
left: toNode(left),
|
|
100
|
+
operator,
|
|
101
|
+
right: toOperand(right)
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (escape !== undefined) {
|
|
105
|
+
node.escape = toLiteralNode(escape);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return node;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Creates an equality expression (left = right)
|
|
113
|
+
* @param left - Left operand
|
|
114
|
+
* @param right - Right operand
|
|
115
|
+
* @returns Binary expression node with equality operator
|
|
116
|
+
*/
|
|
117
|
+
export const eq = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number | boolean): BinaryExpressionNode =>
|
|
118
|
+
createBinaryExpression('=', left, right);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Creates a not equal expression (left != right)
|
|
122
|
+
*/
|
|
123
|
+
export const neq = (
|
|
124
|
+
left: OperandNode | ColumnRef,
|
|
125
|
+
right: OperandNode | ColumnRef | string | number | boolean
|
|
126
|
+
): BinaryExpressionNode => createBinaryExpression('!=', left, right);
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Creates a greater-than expression (left > right)
|
|
130
|
+
* @param left - Left operand
|
|
131
|
+
* @param right - Right operand
|
|
132
|
+
* @returns Binary expression node with greater-than operator
|
|
133
|
+
*/
|
|
134
|
+
export const gt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
135
|
+
createBinaryExpression('>', left, right);
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates a greater than or equal expression (left >= right)
|
|
139
|
+
*/
|
|
140
|
+
export const gte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
141
|
+
createBinaryExpression('>=', left, right);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a less-than expression (left < right)
|
|
145
|
+
* @param left - Left operand
|
|
146
|
+
* @param right - Right operand
|
|
147
|
+
* @returns Binary expression node with less-than operator
|
|
148
|
+
*/
|
|
149
|
+
export const lt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
150
|
+
createBinaryExpression('<', left, right);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Creates a less than or equal expression (left <= right)
|
|
154
|
+
*/
|
|
155
|
+
export const lte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
156
|
+
createBinaryExpression('<=', left, right);
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates a LIKE pattern matching expression
|
|
160
|
+
* @param left - Left operand
|
|
161
|
+
* @param pattern - Pattern to match
|
|
162
|
+
* @param escape - Optional escape character
|
|
163
|
+
* @returns Binary expression node with LIKE operator
|
|
164
|
+
*/
|
|
165
|
+
export const like = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
166
|
+
createBinaryExpression('LIKE', left, pattern, escape);
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Creates a NOT LIKE pattern matching expression
|
|
170
|
+
* @param left - Left operand
|
|
171
|
+
* @param pattern - Pattern to match
|
|
172
|
+
* @param escape - Optional escape character
|
|
173
|
+
* @returns Binary expression node with NOT LIKE operator
|
|
174
|
+
*/
|
|
175
|
+
export const notLike = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
176
|
+
createBinaryExpression('NOT LIKE', left, pattern, escape);
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Creates a logical AND expression
|
|
180
|
+
* @param operands - Expressions to combine with AND
|
|
181
|
+
* @returns Logical expression node with AND operator
|
|
182
|
+
*/
|
|
183
|
+
export const and = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
184
|
+
type: 'LogicalExpression',
|
|
185
|
+
operator: 'AND',
|
|
186
|
+
operands
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Creates a logical OR expression
|
|
191
|
+
* @param operands - Expressions to combine with OR
|
|
192
|
+
* @returns Logical expression node with OR operator
|
|
193
|
+
*/
|
|
194
|
+
export const or = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
195
|
+
type: 'LogicalExpression',
|
|
196
|
+
operator: 'OR',
|
|
197
|
+
operands
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Creates an IS NULL expression
|
|
202
|
+
* @param left - Operand to check for null
|
|
203
|
+
* @returns Null expression node with IS NULL operator
|
|
204
|
+
*/
|
|
205
|
+
export const isNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
206
|
+
type: 'NullExpression',
|
|
207
|
+
left: toNode(left),
|
|
208
|
+
operator: 'IS NULL'
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Creates an IS NOT NULL expression
|
|
213
|
+
* @param left - Operand to check for non-null
|
|
214
|
+
* @returns Null expression node with IS NOT NULL operator
|
|
215
|
+
*/
|
|
216
|
+
export const isNotNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
217
|
+
type: 'NullExpression',
|
|
218
|
+
left: toNode(left),
|
|
219
|
+
operator: 'IS NOT NULL'
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const createInExpression = (
|
|
223
|
+
operator: 'IN' | 'NOT IN',
|
|
224
|
+
left: OperandNode | ColumnRef,
|
|
225
|
+
values: (string | number | LiteralNode)[]
|
|
226
|
+
): InExpressionNode => ({
|
|
227
|
+
type: 'InExpression',
|
|
228
|
+
left: toNode(left),
|
|
229
|
+
operator,
|
|
230
|
+
right: values.map(v => toOperand(v))
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Creates an IN expression (value IN list)
|
|
235
|
+
* @param left - Operand to check
|
|
236
|
+
* @param values - Values to check against
|
|
237
|
+
* @returns IN expression node
|
|
238
|
+
*/
|
|
239
|
+
export const inList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
240
|
+
createInExpression('IN', left, values);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Creates a NOT IN expression (value NOT IN list)
|
|
244
|
+
* @param left - Operand to check
|
|
245
|
+
* @param values - Values to check against
|
|
246
|
+
* @returns NOT IN expression node
|
|
247
|
+
*/
|
|
248
|
+
export const notInList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
249
|
+
createInExpression('NOT IN', left, values);
|
|
250
|
+
|
|
251
|
+
const createBetweenExpression = (
|
|
252
|
+
operator: 'BETWEEN' | 'NOT BETWEEN',
|
|
253
|
+
left: OperandNode | ColumnRef,
|
|
254
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
255
|
+
upper: OperandNode | ColumnRef | string | number
|
|
256
|
+
): BetweenExpressionNode => ({
|
|
257
|
+
type: 'BetweenExpression',
|
|
258
|
+
left: toNode(left),
|
|
259
|
+
operator,
|
|
260
|
+
lower: toOperand(lower),
|
|
261
|
+
upper: toOperand(upper)
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Creates a BETWEEN expression (value BETWEEN lower AND upper)
|
|
266
|
+
* @param left - Operand to check
|
|
267
|
+
* @param lower - Lower bound
|
|
268
|
+
* @param upper - Upper bound
|
|
269
|
+
* @returns BETWEEN expression node
|
|
270
|
+
*/
|
|
271
|
+
export const between = (
|
|
272
|
+
left: OperandNode | ColumnRef,
|
|
273
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
274
|
+
upper: OperandNode | ColumnRef | string | number
|
|
275
|
+
): BetweenExpressionNode => createBetweenExpression('BETWEEN', left, lower, upper);
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Creates a NOT BETWEEN expression (value NOT BETWEEN lower AND upper)
|
|
279
|
+
* @param left - Operand to check
|
|
280
|
+
* @param lower - Lower bound
|
|
281
|
+
* @param upper - Upper bound
|
|
282
|
+
* @returns NOT BETWEEN expression node
|
|
283
|
+
*/
|
|
284
|
+
export const notBetween = (
|
|
285
|
+
left: OperandNode | ColumnRef,
|
|
286
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
287
|
+
upper: OperandNode | ColumnRef | string | number
|
|
288
|
+
): BetweenExpressionNode => createBetweenExpression('NOT BETWEEN', left, lower, upper);
|
|
289
|
+
|
|
290
|
+
const createArithmeticExpression = (
|
|
291
|
+
operator: '+' | '-' | '*' | '/',
|
|
292
|
+
left: OperandNode | ColumnRef,
|
|
293
|
+
right: OperandNode | ColumnRef | string | number
|
|
294
|
+
): ArithmeticExpressionNode => ({
|
|
295
|
+
type: 'ArithmeticExpression',
|
|
296
|
+
left: toOperand(left),
|
|
297
|
+
operator,
|
|
298
|
+
right: toOperand(right)
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
export const add = (
|
|
302
|
+
left: OperandNode | ColumnRef,
|
|
303
|
+
right: OperandNode | ColumnRef | string | number
|
|
304
|
+
): ArithmeticExpressionNode => createArithmeticExpression('+', left, right);
|
|
305
|
+
|
|
306
|
+
export const sub = (
|
|
307
|
+
left: OperandNode | ColumnRef,
|
|
308
|
+
right: OperandNode | ColumnRef | string | number
|
|
309
|
+
): ArithmeticExpressionNode => createArithmeticExpression('-', left, right);
|
|
310
|
+
|
|
311
|
+
export const mul = (
|
|
312
|
+
left: OperandNode | ColumnRef,
|
|
313
|
+
right: OperandNode | ColumnRef | string | number
|
|
314
|
+
): ArithmeticExpressionNode => createArithmeticExpression('*', left, right);
|
|
315
|
+
|
|
316
|
+
export const div = (
|
|
317
|
+
left: OperandNode | ColumnRef,
|
|
318
|
+
right: OperandNode | ColumnRef | string | number
|
|
319
|
+
): ArithmeticExpressionNode => createArithmeticExpression('/', left, right);
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Creates a JSON path expression
|
|
323
|
+
* @param col - Source column
|
|
324
|
+
* @param path - JSON path expression
|
|
325
|
+
* @returns JSON path node
|
|
326
|
+
*/
|
|
327
|
+
export const jsonPath = (col: ColumnRef | ColumnNode, path: string): JsonPathNode => ({
|
|
328
|
+
type: 'JsonPath',
|
|
329
|
+
column: columnOperand(col),
|
|
330
|
+
path
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Creates a CASE expression
|
|
335
|
+
* @param conditions - Array of WHEN-THEN conditions
|
|
336
|
+
* @param elseValue - Optional ELSE value
|
|
337
|
+
* @returns CASE expression node
|
|
338
|
+
*/
|
|
339
|
+
export const caseWhen = (
|
|
340
|
+
conditions: { when: ExpressionNode; then: OperandNode | ColumnRef | string | number | boolean | null }[],
|
|
341
|
+
elseValue?: OperandNode | ColumnRef | string | number | boolean | null
|
|
342
|
+
): CaseExpressionNode => ({
|
|
343
|
+
type: 'CaseExpression',
|
|
344
|
+
conditions: conditions.map(c => ({
|
|
345
|
+
when: c.when,
|
|
346
|
+
then: toOperand(c.then)
|
|
347
|
+
})),
|
|
348
|
+
else: elseValue !== undefined ? toOperand(elseValue) : undefined
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Creates an EXISTS expression
|
|
353
|
+
* @param subquery - Subquery to check for existence
|
|
354
|
+
* @returns EXISTS expression node
|
|
355
|
+
*/
|
|
356
|
+
export const exists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
|
|
357
|
+
type: 'ExistsExpression',
|
|
358
|
+
operator: 'EXISTS',
|
|
359
|
+
subquery
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Creates a NOT EXISTS expression
|
|
364
|
+
* @param subquery - Subquery to check for non-existence
|
|
365
|
+
* @returns NOT EXISTS expression node
|
|
366
|
+
*/
|
|
367
|
+
export const notExists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
|
|
368
|
+
type: 'ExistsExpression',
|
|
369
|
+
operator: 'NOT EXISTS',
|
|
370
|
+
subquery
|
|
371
|
+
});
|