metal-orm 1.0.42 → 1.0.44
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 +195 -37
- package/dist/index.cjs +1014 -538
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1267 -371
- package/dist/index.d.ts +1267 -371
- package/dist/index.js +1012 -536
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/scripts/run-eslint.mjs +34 -0
- package/src/codegen/typescript.ts +32 -15
- package/src/core/ast/adapters.ts +8 -2
- package/src/core/ast/builders.ts +105 -76
- package/src/core/ast/expression-builders.ts +430 -392
- package/src/core/ast/expression-nodes.ts +14 -5
- package/src/core/ast/expression-visitor.ts +56 -14
- package/src/core/ast/helpers.ts +23 -0
- package/src/core/ast/join-node.ts +18 -2
- package/src/core/ast/query.ts +6 -6
- package/src/core/ast/window-functions.ts +10 -2
- package/src/core/ddl/dialects/base-schema-dialect.ts +37 -4
- package/src/core/ddl/dialects/index.ts +1 -0
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +5 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +3 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +14 -1
- package/src/core/ddl/dialects/render-reference.test.ts +69 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +10 -0
- package/src/core/ddl/introspect/catalogs/index.ts +1 -0
- package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
- package/src/core/ddl/introspect/context.ts +6 -0
- package/src/core/ddl/introspect/functions/postgres.ts +13 -0
- package/src/core/ddl/introspect/mssql.ts +53 -8
- package/src/core/ddl/introspect/mysql.ts +32 -6
- package/src/core/ddl/introspect/postgres.ts +102 -34
- package/src/core/ddl/introspect/registry.ts +14 -0
- package/src/core/ddl/introspect/run-select.ts +19 -4
- package/src/core/ddl/introspect/sqlite.ts +78 -11
- package/src/core/ddl/introspect/types.ts +0 -1
- package/src/core/ddl/introspect/utils.ts +21 -3
- package/src/core/ddl/naming-strategy.ts +6 -0
- package/src/core/ddl/schema-dialect.ts +20 -6
- package/src/core/ddl/schema-diff.ts +22 -0
- package/src/core/ddl/schema-generator.ts +26 -12
- package/src/core/ddl/schema-plan-executor.ts +6 -0
- package/src/core/ddl/schema-types.ts +6 -0
- package/src/core/ddl/sql-writing.ts +4 -4
- package/src/core/dialect/abstract.ts +19 -7
- package/src/core/dialect/base/function-table-formatter.ts +3 -2
- package/src/core/dialect/base/join-compiler.ts +5 -3
- package/src/core/dialect/base/returning-strategy.ts +1 -0
- package/src/core/dialect/base/sql-dialect.ts +3 -3
- package/src/core/dialect/mssql/functions.ts +24 -25
- package/src/core/dialect/mssql/index.ts +1 -4
- package/src/core/dialect/mysql/functions.ts +0 -1
- package/src/core/dialect/postgres/functions.ts +33 -34
- package/src/core/dialect/postgres/index.ts +1 -0
- package/src/core/dialect/sqlite/functions.ts +18 -19
- package/src/core/dialect/sqlite/index.ts +2 -0
- package/src/core/execution/db-executor.ts +1 -1
- package/src/core/execution/executors/mysql-executor.ts +2 -2
- package/src/core/execution/executors/postgres-executor.ts +1 -1
- package/src/core/execution/pooling/pool.ts +12 -5
- package/src/core/functions/datetime.ts +58 -34
- package/src/core/functions/numeric.ts +96 -31
- package/src/core/functions/standard-strategy.ts +35 -0
- package/src/core/functions/text.ts +84 -23
- package/src/core/functions/types.ts +23 -8
- package/src/decorators/bootstrap.ts +42 -11
- package/src/decorators/column.ts +20 -11
- package/src/decorators/decorator-metadata.ts +30 -9
- package/src/decorators/entity.ts +29 -5
- package/src/decorators/index.ts +3 -0
- package/src/decorators/relations.ts +34 -11
- package/src/orm/als.ts +34 -9
- package/src/orm/entity-context.ts +62 -8
- package/src/orm/entity-meta.ts +8 -8
- package/src/orm/entity-metadata.ts +131 -16
- package/src/orm/entity.ts +28 -29
- package/src/orm/execute.ts +19 -4
- package/src/orm/hydration.ts +42 -39
- package/src/orm/identity-map.ts +1 -1
- package/src/orm/lazy-batch.ts +74 -104
- package/src/orm/orm-session.ts +24 -23
- package/src/orm/orm.ts +2 -5
- package/src/orm/relation-change-processor.ts +12 -11
- package/src/orm/relations/belongs-to.ts +11 -11
- package/src/orm/relations/has-many.ts +54 -10
- package/src/orm/relations/has-one.ts +8 -7
- package/src/orm/relations/many-to-many.ts +13 -13
- package/src/orm/runtime-types.ts +4 -4
- package/src/orm/save-graph.ts +31 -25
- package/src/orm/unit-of-work.ts +17 -17
- package/src/query/index.ts +74 -0
- package/src/query/target.ts +46 -0
- package/src/query-builder/delete-query-state.ts +30 -0
- package/src/query-builder/delete.ts +64 -18
- package/src/query-builder/hydration-manager.ts +52 -5
- package/src/query-builder/insert-query-state.ts +30 -0
- package/src/query-builder/insert.ts +58 -10
- package/src/query-builder/query-ast-service.ts +7 -2
- package/src/query-builder/query-resolution.ts +78 -0
- package/src/query-builder/raw-column-parser.ts +7 -1
- package/src/query-builder/relation-alias.ts +7 -0
- package/src/query-builder/relation-conditions.ts +61 -48
- package/src/query-builder/relation-service.ts +68 -63
- package/src/query-builder/relation-utils.ts +3 -0
- package/src/query-builder/select/cte-facet.ts +40 -0
- package/src/query-builder/select/from-facet.ts +80 -0
- package/src/query-builder/select/join-facet.ts +62 -0
- package/src/query-builder/select/predicate-facet.ts +103 -0
- package/src/query-builder/select/projection-facet.ts +69 -0
- package/src/query-builder/select/relation-facet.ts +81 -0
- package/src/query-builder/select/setop-facet.ts +36 -0
- package/src/query-builder/select-helpers.ts +15 -2
- package/src/query-builder/select-query-builder-deps.ts +19 -1
- package/src/query-builder/select-query-state.ts +2 -1
- package/src/query-builder/select.ts +795 -1163
- package/src/query-builder/update-query-state.ts +52 -0
- package/src/query-builder/update.ts +69 -18
- package/src/schema/column.ts +26 -26
- package/src/schema/table-guards.ts +31 -0
- package/src/schema/table.ts +47 -18
- package/src/schema/types.ts +22 -22
|
@@ -1,392 +1,430 @@
|
|
|
1
|
-
import { SelectQueryNode } from './query.js';
|
|
2
|
-
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
-
import { ColumnRef } from './types.js';
|
|
4
|
-
import {
|
|
5
|
-
ColumnNode,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
if (
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
export
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
*
|
|
169
|
-
*/
|
|
170
|
-
export const
|
|
171
|
-
createBinaryExpression('
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Creates a
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
*
|
|
185
|
-
* @
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
*
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
*
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
operator: '
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
export const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
*
|
|
288
|
-
* @param
|
|
289
|
-
* @param
|
|
290
|
-
* @returns
|
|
291
|
-
*/
|
|
292
|
-
export const
|
|
293
|
-
left
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
*
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
):
|
|
316
|
-
type: '
|
|
317
|
-
left:
|
|
318
|
-
operator,
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
export const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
):
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
*
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
1
|
+
import { SelectQueryNode } from './query.js';
|
|
2
|
+
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
+
import { ColumnRef } from './types.js';
|
|
4
|
+
import {
|
|
5
|
+
ColumnNode,
|
|
6
|
+
LiteralNode,
|
|
7
|
+
JsonPathNode,
|
|
8
|
+
OperandNode,
|
|
9
|
+
CaseExpressionNode,
|
|
10
|
+
BinaryExpressionNode,
|
|
11
|
+
ExpressionNode,
|
|
12
|
+
LogicalExpressionNode,
|
|
13
|
+
NullExpressionNode,
|
|
14
|
+
InExpressionNode,
|
|
15
|
+
ExistsExpressionNode,
|
|
16
|
+
InExpressionRight,
|
|
17
|
+
ScalarSubqueryNode,
|
|
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
|
+
* Type guard to check if a value is a literal value
|
|
29
|
+
*/
|
|
30
|
+
const isLiteralValue = (value: unknown): value is LiteralValue =>
|
|
31
|
+
value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Converts a primitive value to a LiteralNode
|
|
36
|
+
*/
|
|
37
|
+
const toLiteralNode = (value: string | number | boolean | null): LiteralNode => ({
|
|
38
|
+
type: 'Literal',
|
|
39
|
+
value
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Converts a ColumnRef to a ColumnNode
|
|
44
|
+
* @throws Error if the ColumnRef doesn't have a table specified
|
|
45
|
+
*/
|
|
46
|
+
const columnRefToNode = (col: ColumnRef): ColumnNode => {
|
|
47
|
+
if (!col.table) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Column "${col.name}" requires a table reference. ` +
|
|
50
|
+
`Use columnOperand with a fully qualified ColumnRef or ColumnNode.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return { type: 'Column', table: col.table, name: col.name };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Unified conversion function: converts any valid input to an OperandNode
|
|
58
|
+
* @param value - Value to convert (OperandNode, ColumnRef, or literal value)
|
|
59
|
+
* @returns OperandNode representing the value
|
|
60
|
+
*/
|
|
61
|
+
const toOperandNode = (value: OperandNode | ColumnRef | LiteralValue): OperandNode => {
|
|
62
|
+
// Already an operand node
|
|
63
|
+
if (isOperandNode(value)) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Literal value
|
|
68
|
+
if (isLiteralValue(value)) {
|
|
69
|
+
return toLiteralNode(value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Must be ColumnRef
|
|
73
|
+
return columnRefToNode(value as ColumnRef);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Converts a primitive or existing operand into an operand node
|
|
78
|
+
* @param value - Value or operand to normalize
|
|
79
|
+
* @returns OperandNode representing the value
|
|
80
|
+
*/
|
|
81
|
+
export const valueToOperand = (value: ValueOperandInput): OperandNode => {
|
|
82
|
+
if (isOperandNode(value)) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
return toLiteralNode(value);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Converts various input types to an OperandNode
|
|
90
|
+
*/
|
|
91
|
+
const toOperand = (val: OperandNode | ColumnRef | LiteralValue): OperandNode => toOperandNode(val);
|
|
92
|
+
|
|
93
|
+
export const isValueOperandInput = (value: unknown): value is ValueOperandInput =>
|
|
94
|
+
isOperandNode(value) || isLiteralValue(value);
|
|
95
|
+
|
|
96
|
+
export type SelectQueryInput = SelectQueryNode | { getAST(): SelectQueryNode };
|
|
97
|
+
|
|
98
|
+
const hasQueryAst = (value: SelectQueryInput): value is { getAST(): SelectQueryNode } =>
|
|
99
|
+
typeof (value as { getAST?: unknown }).getAST === 'function';
|
|
100
|
+
|
|
101
|
+
const resolveSelectQueryNode = (query: SelectQueryInput): SelectQueryNode =>
|
|
102
|
+
hasQueryAst(query) ? query.getAST() : query;
|
|
103
|
+
|
|
104
|
+
const toScalarSubqueryNode = (query: SelectQueryInput): ScalarSubqueryNode => ({
|
|
105
|
+
type: 'ScalarSubquery',
|
|
106
|
+
query: resolveSelectQueryNode(query)
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Converts a ColumnRef or ColumnNode to a ColumnNode
|
|
111
|
+
* @param col - Column reference or node
|
|
112
|
+
* @returns ColumnNode
|
|
113
|
+
* @throws Error if ColumnRef doesn't have a table specified
|
|
114
|
+
*/
|
|
115
|
+
export const columnOperand = (col: ColumnRef | ColumnNode): ColumnNode => {
|
|
116
|
+
if (isOperandNode(col) && col.type === 'Column') {
|
|
117
|
+
return col;
|
|
118
|
+
}
|
|
119
|
+
return columnRefToNode(col as ColumnRef);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Marks a column reference as an outer-scope reference for correlated subqueries.
|
|
124
|
+
* Primarily semantic; SQL rendering still uses the provided table/alias name.
|
|
125
|
+
*/
|
|
126
|
+
export const outerRef = (col: ColumnRef | ColumnNode): ColumnNode => ({
|
|
127
|
+
...columnOperand(col),
|
|
128
|
+
scope: 'outer'
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* References a SELECT alias (useful for ORDER BY / GROUP BY).
|
|
133
|
+
*/
|
|
134
|
+
export const aliasRef = (name: string): AliasRefNode => ({
|
|
135
|
+
type: 'AliasRef',
|
|
136
|
+
name
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Creates an outer-scoped column reference using a specific table or alias name.
|
|
141
|
+
*/
|
|
142
|
+
export const correlateBy = (table: string, column: string): ColumnNode => outerRef({ name: column, table });
|
|
143
|
+
|
|
144
|
+
const createBinaryExpression = (
|
|
145
|
+
operator: SqlOperator,
|
|
146
|
+
left: OperandNode | ColumnRef,
|
|
147
|
+
right: OperandNode | ColumnRef | string | number | boolean | null,
|
|
148
|
+
escape?: string
|
|
149
|
+
): BinaryExpressionNode => {
|
|
150
|
+
const node: BinaryExpressionNode = {
|
|
151
|
+
type: 'BinaryExpression',
|
|
152
|
+
left: toOperandNode(left),
|
|
153
|
+
operator,
|
|
154
|
+
right: toOperand(right)
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (escape !== undefined) {
|
|
158
|
+
node.escape = toLiteralNode(escape);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return node;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Creates an equality expression (left = right)
|
|
166
|
+
* @param left - Left operand
|
|
167
|
+
* @param right - Right operand
|
|
168
|
+
* @returns Binary expression node with equality operator
|
|
169
|
+
*/
|
|
170
|
+
export const eq = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number | boolean): BinaryExpressionNode =>
|
|
171
|
+
createBinaryExpression('=', left, right);
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Creates a not equal expression (left != right)
|
|
175
|
+
*/
|
|
176
|
+
export const neq = (
|
|
177
|
+
left: OperandNode | ColumnRef,
|
|
178
|
+
right: OperandNode | ColumnRef | string | number | boolean
|
|
179
|
+
): BinaryExpressionNode => createBinaryExpression('!=', left, right);
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates a greater-than expression (left > right)
|
|
183
|
+
* @param left - Left operand
|
|
184
|
+
* @param right - Right operand
|
|
185
|
+
* @returns Binary expression node with greater-than operator
|
|
186
|
+
*/
|
|
187
|
+
export const gt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
188
|
+
createBinaryExpression('>', left, right);
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Creates a greater than or equal expression (left >= right)
|
|
192
|
+
*/
|
|
193
|
+
export const gte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
194
|
+
createBinaryExpression('>=', left, right);
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Creates a less-than expression (left < right)
|
|
198
|
+
* @param left - Left operand
|
|
199
|
+
* @param right - Right operand
|
|
200
|
+
* @returns Binary expression node with less-than operator
|
|
201
|
+
*/
|
|
202
|
+
export const lt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
203
|
+
createBinaryExpression('<', left, right);
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Creates a less than or equal expression (left <= right)
|
|
207
|
+
*/
|
|
208
|
+
export const lte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
209
|
+
createBinaryExpression('<=', left, right);
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Creates a LIKE pattern matching expression
|
|
213
|
+
* @param left - Left operand
|
|
214
|
+
* @param pattern - Pattern to match
|
|
215
|
+
* @param escape - Optional escape character
|
|
216
|
+
* @returns Binary expression node with LIKE operator
|
|
217
|
+
*/
|
|
218
|
+
export const like = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
219
|
+
createBinaryExpression('LIKE', left, pattern, escape);
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Creates a NOT LIKE pattern matching expression
|
|
223
|
+
* @param left - Left operand
|
|
224
|
+
* @param pattern - Pattern to match
|
|
225
|
+
* @param escape - Optional escape character
|
|
226
|
+
* @returns Binary expression node with NOT LIKE operator
|
|
227
|
+
*/
|
|
228
|
+
export const notLike = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
229
|
+
createBinaryExpression('NOT LIKE', left, pattern, escape);
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Creates a logical AND expression
|
|
233
|
+
* @param operands - Expressions to combine with AND
|
|
234
|
+
* @returns Logical expression node with AND operator
|
|
235
|
+
*/
|
|
236
|
+
export const and = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
237
|
+
type: 'LogicalExpression',
|
|
238
|
+
operator: 'AND',
|
|
239
|
+
operands
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Creates a logical OR expression
|
|
244
|
+
* @param operands - Expressions to combine with OR
|
|
245
|
+
* @returns Logical expression node with OR operator
|
|
246
|
+
*/
|
|
247
|
+
export const or = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
248
|
+
type: 'LogicalExpression',
|
|
249
|
+
operator: 'OR',
|
|
250
|
+
operands
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Creates an IS NULL expression
|
|
255
|
+
* @param left - Operand to check for null
|
|
256
|
+
* @returns Null expression node with IS NULL operator
|
|
257
|
+
*/
|
|
258
|
+
export const isNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
259
|
+
type: 'NullExpression',
|
|
260
|
+
left: toOperandNode(left),
|
|
261
|
+
operator: 'IS NULL'
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Creates an IS NOT NULL expression
|
|
266
|
+
* @param left - Operand to check for non-null
|
|
267
|
+
* @returns Null expression node with IS NOT NULL operator
|
|
268
|
+
*/
|
|
269
|
+
export const isNotNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
270
|
+
type: 'NullExpression',
|
|
271
|
+
left: toOperandNode(left),
|
|
272
|
+
operator: 'IS NOT NULL'
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const createInExpression = (
|
|
276
|
+
operator: 'IN' | 'NOT IN',
|
|
277
|
+
left: OperandNode | ColumnRef,
|
|
278
|
+
right: InExpressionRight
|
|
279
|
+
): InExpressionNode => ({
|
|
280
|
+
type: 'InExpression',
|
|
281
|
+
left: toOperandNode(left),
|
|
282
|
+
operator,
|
|
283
|
+
right
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Creates an IN expression (value IN list)
|
|
288
|
+
* @param left - Operand to check
|
|
289
|
+
* @param values - Values to check against
|
|
290
|
+
* @returns IN expression node
|
|
291
|
+
*/
|
|
292
|
+
export const inList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
293
|
+
createInExpression('IN', left, values.map(v => toOperand(v)));
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Creates a NOT IN expression (value NOT IN list)
|
|
297
|
+
* @param left - Operand to check
|
|
298
|
+
* @param values - Values to check against
|
|
299
|
+
* @returns NOT IN expression node
|
|
300
|
+
*/
|
|
301
|
+
export const notInList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
302
|
+
createInExpression('NOT IN', left, values.map(v => toOperand(v)));
|
|
303
|
+
|
|
304
|
+
export const inSubquery = (left: OperandNode | ColumnRef, subquery: SelectQueryInput): InExpressionNode =>
|
|
305
|
+
createInExpression('IN', left, toScalarSubqueryNode(subquery));
|
|
306
|
+
|
|
307
|
+
export const notInSubquery = (left: OperandNode | ColumnRef, subquery: SelectQueryInput): InExpressionNode =>
|
|
308
|
+
createInExpression('NOT IN', left, toScalarSubqueryNode(subquery));
|
|
309
|
+
|
|
310
|
+
const createBetweenExpression = (
|
|
311
|
+
operator: 'BETWEEN' | 'NOT BETWEEN',
|
|
312
|
+
left: OperandNode | ColumnRef,
|
|
313
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
314
|
+
upper: OperandNode | ColumnRef | string | number
|
|
315
|
+
): BetweenExpressionNode => ({
|
|
316
|
+
type: 'BetweenExpression',
|
|
317
|
+
left: toOperandNode(left),
|
|
318
|
+
operator,
|
|
319
|
+
lower: toOperand(lower),
|
|
320
|
+
upper: toOperand(upper)
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Creates a BETWEEN expression (value BETWEEN lower AND upper)
|
|
325
|
+
* @param left - Operand to check
|
|
326
|
+
* @param lower - Lower bound
|
|
327
|
+
* @param upper - Upper bound
|
|
328
|
+
* @returns BETWEEN expression node
|
|
329
|
+
*/
|
|
330
|
+
export const between = (
|
|
331
|
+
left: OperandNode | ColumnRef,
|
|
332
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
333
|
+
upper: OperandNode | ColumnRef | string | number
|
|
334
|
+
): BetweenExpressionNode => createBetweenExpression('BETWEEN', left, lower, upper);
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Creates a NOT BETWEEN expression (value NOT BETWEEN lower AND upper)
|
|
338
|
+
* @param left - Operand to check
|
|
339
|
+
* @param lower - Lower bound
|
|
340
|
+
* @param upper - Upper bound
|
|
341
|
+
* @returns NOT BETWEEN expression node
|
|
342
|
+
*/
|
|
343
|
+
export const notBetween = (
|
|
344
|
+
left: OperandNode | ColumnRef,
|
|
345
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
346
|
+
upper: OperandNode | ColumnRef | string | number
|
|
347
|
+
): BetweenExpressionNode => createBetweenExpression('NOT BETWEEN', left, lower, upper);
|
|
348
|
+
|
|
349
|
+
const createArithmeticExpression = (
|
|
350
|
+
operator: '+' | '-' | '*' | '/',
|
|
351
|
+
left: OperandNode | ColumnRef,
|
|
352
|
+
right: OperandNode | ColumnRef | string | number
|
|
353
|
+
): ArithmeticExpressionNode => ({
|
|
354
|
+
type: 'ArithmeticExpression',
|
|
355
|
+
left: toOperand(left),
|
|
356
|
+
operator,
|
|
357
|
+
right: toOperand(right)
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
export const add = (
|
|
361
|
+
left: OperandNode | ColumnRef,
|
|
362
|
+
right: OperandNode | ColumnRef | string | number
|
|
363
|
+
): ArithmeticExpressionNode => createArithmeticExpression('+', left, right);
|
|
364
|
+
|
|
365
|
+
export const sub = (
|
|
366
|
+
left: OperandNode | ColumnRef,
|
|
367
|
+
right: OperandNode | ColumnRef | string | number
|
|
368
|
+
): ArithmeticExpressionNode => createArithmeticExpression('-', left, right);
|
|
369
|
+
|
|
370
|
+
export const mul = (
|
|
371
|
+
left: OperandNode | ColumnRef,
|
|
372
|
+
right: OperandNode | ColumnRef | string | number
|
|
373
|
+
): ArithmeticExpressionNode => createArithmeticExpression('*', left, right);
|
|
374
|
+
|
|
375
|
+
export const div = (
|
|
376
|
+
left: OperandNode | ColumnRef,
|
|
377
|
+
right: OperandNode | ColumnRef | string | number
|
|
378
|
+
): ArithmeticExpressionNode => createArithmeticExpression('/', left, right);
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Creates a JSON path expression
|
|
382
|
+
* @param col - Source column
|
|
383
|
+
* @param path - JSON path expression
|
|
384
|
+
* @returns JSON path node
|
|
385
|
+
*/
|
|
386
|
+
export const jsonPath = (col: ColumnRef | ColumnNode, path: string): JsonPathNode => ({
|
|
387
|
+
type: 'JsonPath',
|
|
388
|
+
column: columnOperand(col),
|
|
389
|
+
path
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Creates a CASE expression
|
|
394
|
+
* @param conditions - Array of WHEN-THEN conditions
|
|
395
|
+
* @param elseValue - Optional ELSE value
|
|
396
|
+
* @returns CASE expression node
|
|
397
|
+
*/
|
|
398
|
+
export const caseWhen = (
|
|
399
|
+
conditions: { when: ExpressionNode; then: OperandNode | ColumnRef | string | number | boolean | null }[],
|
|
400
|
+
elseValue?: OperandNode | ColumnRef | string | number | boolean | null
|
|
401
|
+
): CaseExpressionNode => ({
|
|
402
|
+
type: 'CaseExpression',
|
|
403
|
+
conditions: conditions.map(c => ({
|
|
404
|
+
when: c.when,
|
|
405
|
+
then: toOperand(c.then)
|
|
406
|
+
})),
|
|
407
|
+
else: elseValue !== undefined ? toOperand(elseValue) : undefined
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Creates an EXISTS expression
|
|
412
|
+
* @param subquery - Subquery to check for existence
|
|
413
|
+
* @returns EXISTS expression node
|
|
414
|
+
*/
|
|
415
|
+
export const exists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
|
|
416
|
+
type: 'ExistsExpression',
|
|
417
|
+
operator: 'EXISTS',
|
|
418
|
+
subquery
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Creates a NOT EXISTS expression
|
|
423
|
+
* @param subquery - Subquery to check for non-existence
|
|
424
|
+
* @returns NOT EXISTS expression node
|
|
425
|
+
*/
|
|
426
|
+
export const notExists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
|
|
427
|
+
type: 'ExistsExpression',
|
|
428
|
+
operator: 'NOT EXISTS',
|
|
429
|
+
subquery
|
|
430
|
+
});
|