metal-orm 1.0.8 → 1.0.10

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.
Files changed (153) hide show
  1. package/README.md +341 -146
  2. package/dist/decorators/index.cjs +2564 -0
  3. package/dist/decorators/index.cjs.map +1 -0
  4. package/dist/decorators/index.d.cts +53 -0
  5. package/dist/decorators/index.d.ts +53 -0
  6. package/dist/decorators/index.js +2530 -0
  7. package/dist/decorators/index.js.map +1 -0
  8. package/dist/index.cjs +4227 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +701 -0
  11. package/dist/index.d.ts +701 -0
  12. package/dist/index.js +4131 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/select-654m4qy8.d.cts +1522 -0
  15. package/dist/select-654m4qy8.d.ts +1522 -0
  16. package/package.json +27 -20
  17. package/src/codegen/typescript.ts +405 -393
  18. package/src/core/ast/aggregate-functions.ts +30 -0
  19. package/src/core/ast/builders.ts +43 -0
  20. package/src/core/ast/expression-builders.ts +310 -0
  21. package/src/core/ast/expression-nodes.ts +211 -0
  22. package/src/core/ast/expression-visitor.ts +99 -0
  23. package/src/core/ast/expression.ts +5 -0
  24. package/src/{utils → core/ast}/join-node.ts +20 -20
  25. package/src/{ast → core/ast}/join.ts +18 -18
  26. package/src/{ast → core/ast}/query.ts +113 -113
  27. package/src/core/ast/window-functions.ts +140 -0
  28. package/src/{dialect → core/dialect}/abstract.ts +94 -94
  29. package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
  30. package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
  31. package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
  32. package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
  33. package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
  34. package/src/decorators/bootstrap.ts +126 -0
  35. package/src/decorators/column.ts +78 -0
  36. package/src/decorators/entity.ts +36 -0
  37. package/src/decorators/index.ts +4 -0
  38. package/src/decorators/relations.ts +107 -0
  39. package/src/global.d.ts +1 -0
  40. package/src/index.ts +22 -22
  41. package/src/orm/db-executor.ts +11 -0
  42. package/src/orm/domain-event-bus.ts +52 -0
  43. package/src/{runtime → orm}/entity-meta.ts +52 -52
  44. package/src/orm/entity-metadata.ts +140 -0
  45. package/src/{runtime → orm}/entity.ts +252 -252
  46. package/src/{runtime → orm}/execute.ts +36 -36
  47. package/src/{runtime → orm}/hydration.ts +103 -103
  48. package/src/orm/identity-map.ts +37 -0
  49. package/src/{runtime → orm}/lazy-batch.ts +205 -205
  50. package/src/orm/orm-context.ts +154 -0
  51. package/src/orm/relation-change-processor.ts +140 -0
  52. package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
  53. package/src/{runtime → orm}/relations/has-many.ts +111 -111
  54. package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
  55. package/src/orm/runtime-types.ts +39 -0
  56. package/src/orm/transaction-runner.ts +17 -0
  57. package/src/orm/unit-of-work.ts +232 -0
  58. package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
  59. package/src/{builder → query-builder}/delete-query-state.ts +38 -42
  60. package/src/{builder → query-builder}/delete.ts +46 -57
  61. package/src/{builder → query-builder}/hydration-manager.ts +87 -87
  62. package/src/{builder → query-builder}/hydration-planner.ts +182 -182
  63. package/src/{builder → query-builder}/insert-query-state.ts +51 -62
  64. package/src/{builder → query-builder}/insert.ts +48 -59
  65. package/src/{builder → query-builder}/query-ast-service.ts +208 -226
  66. package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
  67. package/src/{builder → query-builder}/relation-conditions.ts +112 -112
  68. package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
  69. package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
  70. package/src/{builder → query-builder}/relation-service.ts +284 -284
  71. package/src/{builder → query-builder}/relation-types.ts +21 -21
  72. package/src/{builder → query-builder}/relation-utils.ts +12 -12
  73. package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
  74. package/src/{builder → query-builder}/select-query-state.ts +179 -179
  75. package/src/{builder → query-builder}/select.ts +78 -69
  76. package/src/{builder → query-builder}/update-query-state.ts +55 -59
  77. package/src/{builder → query-builder}/update.ts +50 -61
  78. package/src/schema/column.ts +25 -25
  79. package/src/schema/relation.ts +116 -116
  80. package/src/schema/table.ts +34 -34
  81. package/src/schema/types.ts +76 -76
  82. package/.github/workflows/publish-metal-orm.yml +0 -38
  83. package/ROADMAP.md +0 -125
  84. package/docs/CHANGES.md +0 -104
  85. package/docs/advanced-features.md +0 -176
  86. package/docs/api-reference.md +0 -31
  87. package/docs/dml-operations.md +0 -156
  88. package/docs/getting-started.md +0 -171
  89. package/docs/hydration.md +0 -115
  90. package/docs/index.md +0 -36
  91. package/docs/multi-dialect-support.md +0 -59
  92. package/docs/query-builder.md +0 -135
  93. package/docs/runtime.md +0 -105
  94. package/docs/schema-definition.md +0 -112
  95. package/metadata.json +0 -5
  96. package/playground/api/playground-api.ts +0 -94
  97. package/playground/index.html +0 -15
  98. package/playground/src/App.css +0 -1
  99. package/playground/src/App.tsx +0 -114
  100. package/playground/src/components/CodeDisplay.tsx +0 -43
  101. package/playground/src/components/QueryExecutor.tsx +0 -189
  102. package/playground/src/components/ResultsTable.tsx +0 -67
  103. package/playground/src/components/ResultsTabs.tsx +0 -105
  104. package/playground/src/components/ScenarioList.tsx +0 -56
  105. package/playground/src/components/logo.svg +0 -45
  106. package/playground/src/data/scenarios.ts +0 -2
  107. package/playground/src/main.tsx +0 -9
  108. package/playground/src/services/PlaygroundApiService.ts +0 -60
  109. package/postcss.config.cjs +0 -5
  110. package/sql_sql-ansi-cheatsheet-2025.md +0 -264
  111. package/src/ast/expression.ts +0 -658
  112. package/src/builder/operations/cte-manager.ts +0 -34
  113. package/src/builder/operations/filter-manager.ts +0 -68
  114. package/src/builder/operations/join-manager.ts +0 -36
  115. package/src/builder/operations/pagination-manager.ts +0 -36
  116. package/src/playground/features/playground/api/types.ts +0 -16
  117. package/src/playground/features/playground/clients/MockClient.ts +0 -17
  118. package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
  119. package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
  120. package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
  121. package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
  122. package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
  123. package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
  124. package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
  125. package/src/playground/features/playground/data/scenarios/index.ts +0 -29
  126. package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
  127. package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
  128. package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
  129. package/src/playground/features/playground/data/scenarios/types.ts +0 -70
  130. package/src/playground/features/playground/data/schema.ts +0 -91
  131. package/src/playground/features/playground/data/seed.ts +0 -104
  132. package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
  133. package/src/runtime/orm-context.ts +0 -539
  134. package/tests/belongs-to-many.test.ts +0 -57
  135. package/tests/between.test.ts +0 -43
  136. package/tests/case-expression.test.ts +0 -58
  137. package/tests/complex-exists.test.ts +0 -230
  138. package/tests/cte.test.ts +0 -118
  139. package/tests/dml.test.ts +0 -206
  140. package/tests/exists.test.ts +0 -127
  141. package/tests/like.test.ts +0 -33
  142. package/tests/orm-runtime.test.ts +0 -254
  143. package/tests/postgres.test.ts +0 -30
  144. package/tests/right-join.test.ts +0 -89
  145. package/tests/subquery-having.test.ts +0 -193
  146. package/tests/window-function.test.ts +0 -151
  147. package/tsconfig.json +0 -30
  148. package/tsup.config.ts +0 -10
  149. package/vite.config.ts +0 -22
  150. package/vitest.config.ts +0 -14
  151. /package/src/{constants → core/sql}/sql.ts +0 -0
  152. /package/src/{runtime → orm}/als.ts +0 -0
  153. /package/src/{utils → query-builder}/relation-alias.ts +0 -0
@@ -1,658 +0,0 @@
1
- import { ColumnDef } from '../schema/column';
2
- import type { SelectQueryNode, OrderByNode } from './query';
3
- import { OrderDirection, SqlOperator } from '../constants/sql';
4
-
5
- /**
6
- * AST node representing a literal value
7
- */
8
- export interface LiteralNode {
9
- type: 'Literal';
10
- /** The literal value (string, number, boolean, or null) */
11
- value: string | number | boolean | null;
12
- }
13
-
14
- /**
15
- * AST node representing a column reference
16
- */
17
- export interface ColumnNode {
18
- type: 'Column';
19
- /** Table name the column belongs to */
20
- table: string;
21
- /** Column name */
22
- name: string;
23
- /** Optional alias for the column */
24
- alias?: string;
25
- }
26
-
27
- /**
28
- * AST node representing a function call
29
- */
30
- export interface FunctionNode {
31
- type: 'Function';
32
- /** Function name (e.g., COUNT, SUM) */
33
- name: string;
34
- /** Function arguments */
35
- args: (ColumnNode | LiteralNode | JsonPathNode)[];
36
- /** Optional alias for the function result */
37
- alias?: string;
38
- }
39
-
40
- /**
41
- * AST node representing a JSON path expression
42
- */
43
- export interface JsonPathNode {
44
- type: 'JsonPath';
45
- /** Source column */
46
- column: ColumnNode;
47
- /** JSON path expression */
48
- path: string;
49
- /** Optional alias for the result */
50
- alias?: string;
51
- }
52
-
53
- /**
54
- * AST node representing a scalar subquery
55
- */
56
- export interface ScalarSubqueryNode {
57
- type: 'ScalarSubquery';
58
- /** Subquery to execute */
59
- query: SelectQueryNode;
60
- /** Optional alias for the subquery result */
61
- alias?: string;
62
- }
63
-
64
- /**
65
- * AST node representing a CASE expression
66
- */
67
- export interface CaseExpressionNode {
68
- type: 'CaseExpression';
69
- /** WHEN-THEN conditions */
70
- conditions: { when: ExpressionNode; then: OperandNode }[];
71
- /** Optional ELSE clause */
72
- else?: OperandNode;
73
- /** Optional alias for the result */
74
- alias?: string;
75
- }
76
-
77
- /**
78
- * AST node representing a window function
79
- */
80
- export interface WindowFunctionNode {
81
- type: 'WindowFunction';
82
- /** Window function name (e.g., ROW_NUMBER, RANK) */
83
- name: string;
84
- /** Function arguments */
85
- args: (ColumnNode | LiteralNode | JsonPathNode)[];
86
- /** Optional PARTITION BY clause */
87
- partitionBy?: ColumnNode[];
88
- /** Optional ORDER BY clause */
89
- orderBy?: OrderByNode[];
90
- /** Optional alias for the result */
91
- alias?: string;
92
- }
93
-
94
- /**
95
- * Union type representing any operand that can be used in expressions
96
- */
97
- export type OperandNode = ColumnNode | LiteralNode | FunctionNode | JsonPathNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode;
98
-
99
- /**
100
- * Converts a primitive or existing operand into an operand node
101
- * @param value - Value or operand to normalize
102
- * @returns OperandNode representing the value
103
- */
104
- export const valueToOperand = (value: unknown): OperandNode => {
105
- if (
106
- value === null ||
107
- value === undefined ||
108
- typeof value === 'string' ||
109
- typeof value === 'number' ||
110
- typeof value === 'boolean'
111
- ) {
112
- return { type: 'Literal', value: value === undefined ? null : value } as LiteralNode;
113
- }
114
- return value as OperandNode;
115
- };
116
-
117
- /**
118
- * AST node representing a binary expression (e.g., column = value)
119
- */
120
- export interface BinaryExpressionNode {
121
- type: 'BinaryExpression';
122
- /** Left operand */
123
- left: OperandNode;
124
- /** Comparison operator */
125
- operator: SqlOperator;
126
- /** Right operand */
127
- right: OperandNode;
128
- /** Optional escape character for LIKE expressions */
129
- escape?: LiteralNode;
130
- }
131
-
132
- /**
133
- * AST node representing a logical expression (AND/OR)
134
- */
135
- export interface LogicalExpressionNode {
136
- type: 'LogicalExpression';
137
- /** Logical operator (AND or OR) */
138
- operator: 'AND' | 'OR';
139
- /** Operands to combine */
140
- operands: ExpressionNode[];
141
- }
142
-
143
- /**
144
- * AST node representing a null check expression
145
- */
146
- export interface NullExpressionNode {
147
- type: 'NullExpression';
148
- /** Operand to check for null */
149
- left: OperandNode;
150
- /** Null check operator */
151
- operator: 'IS NULL' | 'IS NOT NULL';
152
- }
153
-
154
- /**
155
- * AST node representing an IN/NOT IN expression
156
- */
157
- export interface InExpressionNode {
158
- type: 'InExpression';
159
- /** Left operand to check */
160
- left: OperandNode;
161
- /** IN/NOT IN operator */
162
- operator: 'IN' | 'NOT IN';
163
- /** Values to check against */
164
- right: OperandNode[];
165
- }
166
-
167
- /**
168
- * AST node representing an EXISTS/NOT EXISTS expression
169
- */
170
- export interface ExistsExpressionNode {
171
- type: 'ExistsExpression';
172
- /** EXISTS/NOT EXISTS operator */
173
- operator: SqlOperator;
174
- /** Subquery to check */
175
- subquery: SelectQueryNode;
176
- }
177
-
178
- /**
179
- * AST node representing a BETWEEN/NOT BETWEEN expression
180
- */
181
- export interface BetweenExpressionNode {
182
- type: 'BetweenExpression';
183
- /** Operand to check */
184
- left: OperandNode;
185
- /** BETWEEN/NOT BETWEEN operator */
186
- operator: 'BETWEEN' | 'NOT BETWEEN';
187
- /** Lower bound */
188
- lower: OperandNode;
189
- /** Upper bound */
190
- upper: OperandNode;
191
- }
192
-
193
- /**
194
- * Union type representing any supported expression node
195
- */
196
- export type ExpressionNode =
197
- | BinaryExpressionNode
198
- | LogicalExpressionNode
199
- | NullExpressionNode
200
- | InExpressionNode
201
- | ExistsExpressionNode
202
- | BetweenExpressionNode;
203
-
204
- const operandTypes = new Set<OperandNode['type']>([
205
- 'Column',
206
- 'Literal',
207
- 'Function',
208
- 'JsonPath',
209
- 'ScalarSubquery',
210
- 'CaseExpression',
211
- 'WindowFunction'
212
- ]);
213
-
214
- const isOperandNode = (node: any): node is OperandNode => {
215
- return node && operandTypes.has(node.type);
216
- };
217
-
218
- export const isFunctionNode = (node: any): node is FunctionNode => node?.type === 'Function';
219
- export const isCaseExpressionNode = (node: any): node is CaseExpressionNode => node?.type === 'CaseExpression';
220
- export const isWindowFunctionNode = (node: any): node is WindowFunctionNode => node?.type === 'WindowFunction';
221
- export const isExpressionSelectionNode = (
222
- node: ColumnDef | FunctionNode | CaseExpressionNode | WindowFunctionNode
223
- ): node is FunctionNode | CaseExpressionNode | WindowFunctionNode =>
224
- isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
225
-
226
- // Helper to convert Schema definition to AST Node
227
- const toNode = (col: ColumnDef | OperandNode): OperandNode => {
228
- if (isOperandNode(col)) return col as OperandNode;
229
- const def = col as ColumnDef;
230
- return { type: 'Column', table: def.table || 'unknown', name: def.name };
231
- };
232
-
233
- const toLiteralNode = (value: string | number | boolean | null): LiteralNode => ({
234
- type: 'Literal',
235
- value
236
- });
237
-
238
- const toOperand = (val: OperandNode | ColumnDef | string | number | boolean | null): OperandNode => {
239
- if (val === null) return { type: 'Literal', value: null };
240
- if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {
241
- return { type: 'Literal', value: val };
242
- }
243
- return toNode(val as OperandNode | ColumnDef);
244
- };
245
-
246
- // Factories
247
- const createBinaryExpression = (
248
- operator: SqlOperator,
249
- left: OperandNode | ColumnDef,
250
- right: OperandNode | ColumnDef | string | number | boolean | null,
251
- escape?: string
252
- ): BinaryExpressionNode => {
253
- const node: BinaryExpressionNode = {
254
- type: 'BinaryExpression',
255
- left: toNode(left),
256
- operator,
257
- right: toOperand(right)
258
- };
259
-
260
- if (escape !== undefined) {
261
- node.escape = toLiteralNode(escape);
262
- }
263
-
264
- return node;
265
- };
266
-
267
- /**
268
- * Creates an equality expression (left = right)
269
- * @param left - Left operand
270
- * @param right - Right operand
271
- * @returns Binary expression node with equality operator
272
- */
273
- export const eq = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDef | string | number): BinaryExpressionNode =>
274
- createBinaryExpression('=', left, right);
275
-
276
- /**
277
- * Creates a not equal expression (left != right)
278
- */
279
- export const neq = (
280
- left: OperandNode | ColumnDef,
281
- right: OperandNode | ColumnDef | string | number
282
- ): BinaryExpressionNode => createBinaryExpression('!=', left, right);
283
-
284
- /**
285
- * Creates a greater-than expression (left > right)
286
- * @param left - Left operand
287
- * @param right - Right operand
288
- * @returns Binary expression node with greater-than operator
289
- */
290
- export const gt = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDef | string | number): BinaryExpressionNode =>
291
- createBinaryExpression('>', left, right);
292
-
293
- /**
294
- * Creates a greater than or equal expression (left >= right)
295
- */
296
- export const gte = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDef | string | number): BinaryExpressionNode =>
297
- createBinaryExpression('>=', left, right);
298
-
299
- /**
300
- * Creates a less-than expression (left < right)
301
- * @param left - Left operand
302
- * @param right - Right operand
303
- * @returns Binary expression node with less-than operator
304
- */
305
- export const lt = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDef | string | number): BinaryExpressionNode =>
306
- createBinaryExpression('<', left, right);
307
-
308
- /**
309
- * Creates a less than or equal expression (left <= right)
310
- */
311
- export const lte = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDef | string | number): BinaryExpressionNode =>
312
- createBinaryExpression('<=', left, right);
313
-
314
- /**
315
- * Creates a LIKE pattern matching expression
316
- * @param left - Left operand
317
- * @param pattern - Pattern to match
318
- * @param escape - Optional escape character
319
- * @returns Binary expression node with LIKE operator
320
- */
321
- export const like = (left: OperandNode | ColumnDef, pattern: string, escape?: string): BinaryExpressionNode =>
322
- createBinaryExpression('LIKE', left, pattern, escape);
323
-
324
- /**
325
- * Creates a NOT LIKE pattern matching expression
326
- * @param left - Left operand
327
- * @param pattern - Pattern to match
328
- * @param escape - Optional escape character
329
- * @returns Binary expression node with NOT LIKE operator
330
- */
331
- export const notLike = (left: OperandNode | ColumnDef, pattern: string, escape?: string): BinaryExpressionNode =>
332
- createBinaryExpression('NOT LIKE', left, pattern, escape);
333
-
334
- /**
335
- * Creates a logical AND expression
336
- * @param operands - Expressions to combine with AND
337
- * @returns Logical expression node with AND operator
338
- */
339
- export const and = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
340
- type: 'LogicalExpression',
341
- operator: 'AND',
342
- operands
343
- });
344
-
345
- /**
346
- * Creates a logical OR expression
347
- * @param operands - Expressions to combine with OR
348
- * @returns Logical expression node with OR operator
349
- */
350
- export const or = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
351
- type: 'LogicalExpression',
352
- operator: 'OR',
353
- operands
354
- });
355
-
356
- /**
357
- * Creates an IS NULL expression
358
- * @param left - Operand to check for null
359
- * @returns Null expression node with IS NULL operator
360
- */
361
- export const isNull = (left: OperandNode | ColumnDef): NullExpressionNode => ({
362
- type: 'NullExpression',
363
- left: toNode(left),
364
- operator: 'IS NULL'
365
- });
366
-
367
- /**
368
- * Creates an IS NOT NULL expression
369
- * @param left - Operand to check for non-null
370
- * @returns Null expression node with IS NOT NULL operator
371
- */
372
- export const isNotNull = (left: OperandNode | ColumnDef): NullExpressionNode => ({
373
- type: 'NullExpression',
374
- left: toNode(left),
375
- operator: 'IS NOT NULL'
376
- });
377
-
378
- const createInExpression = (
379
- operator: 'IN' | 'NOT IN',
380
- left: OperandNode | ColumnDef,
381
- values: (string | number | LiteralNode)[]
382
- ): InExpressionNode => ({
383
- type: 'InExpression',
384
- left: toNode(left),
385
- operator,
386
- right: values.map(v => toOperand(v))
387
- });
388
-
389
- /**
390
- * Creates an IN expression (value IN list)
391
- * @param left - Operand to check
392
- * @param values - Values to check against
393
- * @returns IN expression node
394
- */
395
- export const inList = (left: OperandNode | ColumnDef, values: (string | number | LiteralNode)[]): InExpressionNode =>
396
- createInExpression('IN', left, values);
397
-
398
- /**
399
- * Creates a NOT IN expression (value NOT IN list)
400
- * @param left - Operand to check
401
- * @param values - Values to check against
402
- * @returns NOT IN expression node
403
- */
404
- export const notInList = (left: OperandNode | ColumnDef, values: (string | number | LiteralNode)[]): InExpressionNode =>
405
- createInExpression('NOT IN', left, values);
406
-
407
- const createBetweenExpression = (
408
- operator: 'BETWEEN' | 'NOT BETWEEN',
409
- left: OperandNode | ColumnDef,
410
- lower: OperandNode | ColumnDef | string | number,
411
- upper: OperandNode | ColumnDef | string | number
412
- ): BetweenExpressionNode => ({
413
- type: 'BetweenExpression',
414
- left: toNode(left),
415
- operator,
416
- lower: toOperand(lower),
417
- upper: toOperand(upper)
418
- });
419
-
420
- /**
421
- * Creates a BETWEEN expression (value BETWEEN lower AND upper)
422
- * @param left - Operand to check
423
- * @param lower - Lower bound
424
- * @param upper - Upper bound
425
- * @returns BETWEEN expression node
426
- */
427
- export const between = (
428
- left: OperandNode | ColumnDef,
429
- lower: OperandNode | ColumnDef | string | number,
430
- upper: OperandNode | ColumnDef | string | number
431
- ): BetweenExpressionNode => createBetweenExpression('BETWEEN', left, lower, upper);
432
-
433
- /**
434
- * Creates a NOT BETWEEN expression (value NOT BETWEEN lower AND upper)
435
- * @param left - Operand to check
436
- * @param lower - Lower bound
437
- * @param upper - Upper bound
438
- * @returns NOT BETWEEN expression node
439
- */
440
- export const notBetween = (
441
- left: OperandNode | ColumnDef,
442
- lower: OperandNode | ColumnDef | string | number,
443
- upper: OperandNode | ColumnDef | string | number
444
- ): BetweenExpressionNode => createBetweenExpression('NOT BETWEEN', left, lower, upper);
445
-
446
- /**
447
- * Creates a JSON path expression
448
- * @param col - Source column
449
- * @param path - JSON path expression
450
- * @returns JSON path node
451
- */
452
- export const jsonPath = (col: ColumnDef | ColumnNode, path: string): JsonPathNode => ({
453
- type: 'JsonPath',
454
- column: toNode(col) as ColumnNode,
455
- path
456
- });
457
-
458
- /**
459
- * Creates a COUNT function expression
460
- * @param col - Column to count
461
- * @returns Function node with COUNT
462
- */
463
- export const count = (col: ColumnDef | ColumnNode): FunctionNode => ({
464
- type: 'Function',
465
- name: 'COUNT',
466
- args: [toNode(col) as ColumnNode]
467
- });
468
-
469
- /**
470
- * Creates a SUM function expression
471
- * @param col - Column to sum
472
- * @returns Function node with SUM
473
- */
474
- export const sum = (col: ColumnDef | ColumnNode): FunctionNode => ({
475
- type: 'Function',
476
- name: 'SUM',
477
- args: [toNode(col) as ColumnNode]
478
- });
479
-
480
- /**
481
- * Creates an AVG function expression
482
- * @param col - Column to average
483
- * @returns Function node with AVG
484
- */
485
- export const avg = (col: ColumnDef | ColumnNode): FunctionNode => ({
486
- type: 'Function',
487
- name: 'AVG',
488
- args: [toNode(col) as ColumnNode]
489
- });
490
-
491
- /**
492
- * Creates an EXISTS expression
493
- * @param subquery - Subquery to check for existence
494
- * @returns EXISTS expression node
495
- */
496
- export const exists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
497
- type: 'ExistsExpression',
498
- operator: 'EXISTS',
499
- subquery
500
- });
501
-
502
- /**
503
- * Creates a NOT EXISTS expression
504
- * @param subquery - Subquery to check for non-existence
505
- * @returns NOT EXISTS expression node
506
- */
507
- export const notExists = (subquery: SelectQueryNode): ExistsExpressionNode => ({
508
- type: 'ExistsExpression',
509
- operator: 'NOT EXISTS',
510
- subquery
511
- });
512
-
513
- /**
514
- * Creates a CASE expression
515
- * @param conditions - Array of WHEN-THEN conditions
516
- * @param elseValue - Optional ELSE value
517
- * @returns CASE expression node
518
- */
519
- export const caseWhen = (
520
- conditions: { when: ExpressionNode; then: OperandNode | ColumnDef | string | number | boolean | null }[],
521
- elseValue?: OperandNode | ColumnDef | string | number | boolean | null
522
- ): CaseExpressionNode => ({
523
- type: 'CaseExpression',
524
- conditions: conditions.map(c => ({
525
- when: c.when,
526
- then: toOperand(c.then)
527
- })),
528
- else: elseValue !== undefined ? toOperand(elseValue) : undefined
529
- });
530
-
531
- // Window function factories
532
- const buildWindowFunction = (
533
- name: string,
534
- args: (ColumnNode | LiteralNode | JsonPathNode)[] = [],
535
- partitionBy?: ColumnNode[],
536
- orderBy?: OrderByNode[]
537
- ): WindowFunctionNode => {
538
- const node: WindowFunctionNode = {
539
- type: 'WindowFunction',
540
- name,
541
- args
542
- };
543
-
544
- if (partitionBy && partitionBy.length) {
545
- node.partitionBy = partitionBy;
546
- }
547
-
548
- if (orderBy && orderBy.length) {
549
- node.orderBy = orderBy;
550
- }
551
-
552
- return node;
553
- };
554
-
555
- /**
556
- * Creates a ROW_NUMBER window function
557
- * @returns Window function node for ROW_NUMBER
558
- */
559
- export const rowNumber = (): WindowFunctionNode => buildWindowFunction('ROW_NUMBER');
560
-
561
- /**
562
- * Creates a RANK window function
563
- * @returns Window function node for RANK
564
- */
565
- export const rank = (): WindowFunctionNode => buildWindowFunction('RANK');
566
-
567
- /**
568
- * Creates a DENSE_RANK window function
569
- * @returns Window function node for DENSE_RANK
570
- */
571
- export const denseRank = (): WindowFunctionNode => buildWindowFunction('DENSE_RANK');
572
-
573
- /**
574
- * Creates an NTILE window function
575
- * @param n - Number of buckets
576
- * @returns Window function node for NTILE
577
- */
578
- export const ntile = (n: number): WindowFunctionNode => buildWindowFunction('NTILE', [{ type: 'Literal', value: n }]);
579
-
580
- const columnOperand = (col: ColumnDef | ColumnNode): ColumnNode => toNode(col) as ColumnNode;
581
-
582
- /**
583
- * Creates a LAG window function
584
- * @param col - Column to lag
585
- * @param offset - Offset (defaults to 1)
586
- * @param defaultValue - Default value if no row exists
587
- * @returns Window function node for LAG
588
- */
589
- export const lag = (col: ColumnDef | ColumnNode, offset: number = 1, defaultValue?: any): WindowFunctionNode => {
590
- const args: (ColumnNode | LiteralNode | JsonPathNode)[] = [columnOperand(col), { type: 'Literal', value: offset }];
591
- if (defaultValue !== undefined) {
592
- args.push({ type: 'Literal', value: defaultValue });
593
- }
594
- return buildWindowFunction('LAG', args);
595
- };
596
-
597
- /**
598
- * Creates a LEAD window function
599
- * @param col - Column to lead
600
- * @param offset - Offset (defaults to 1)
601
- * @param defaultValue - Default value if no row exists
602
- * @returns Window function node for LEAD
603
- */
604
- export const lead = (col: ColumnDef | ColumnNode, offset: number = 1, defaultValue?: any): WindowFunctionNode => {
605
- const args: (ColumnNode | LiteralNode | JsonPathNode)[] = [columnOperand(col), { type: 'Literal', value: offset }];
606
- if (defaultValue !== undefined) {
607
- args.push({ type: 'Literal', value: defaultValue });
608
- }
609
- return buildWindowFunction('LEAD', args);
610
- };
611
-
612
- /**
613
- * Creates a FIRST_VALUE window function
614
- * @param col - Column to get first value from
615
- * @returns Window function node for FIRST_VALUE
616
- */
617
- export const firstValue = (col: ColumnDef | ColumnNode): WindowFunctionNode => buildWindowFunction('FIRST_VALUE', [columnOperand(col)]);
618
-
619
- /**
620
- * Creates a LAST_VALUE window function
621
- * @param col - Column to get last value from
622
- * @returns Window function node for LAST_VALUE
623
- */
624
- export const lastValue = (col: ColumnDef | ColumnNode): WindowFunctionNode => buildWindowFunction('LAST_VALUE', [columnOperand(col)]);
625
-
626
- /**
627
- * Creates a custom window function
628
- * @param name - Window function name
629
- * @param args - Function arguments
630
- * @param partitionBy - Optional PARTITION BY columns
631
- * @param orderBy - Optional ORDER BY clauses
632
- * @returns Window function node
633
- */
634
- export const windowFunction = (
635
- name: string,
636
- args: (ColumnDef | ColumnNode | LiteralNode | JsonPathNode)[] = [],
637
- partitionBy?: (ColumnDef | ColumnNode)[],
638
- orderBy?: { column: ColumnDef | ColumnNode, direction: OrderDirection }[]
639
- ): WindowFunctionNode => {
640
- const nodeArgs = args.map(arg => {
641
- if ((arg as LiteralNode).value !== undefined) {
642
- return arg as LiteralNode;
643
- }
644
- if ((arg as JsonPathNode).path) {
645
- return arg as JsonPathNode;
646
- }
647
- return columnOperand(arg as ColumnDef | ColumnNode);
648
- });
649
-
650
- const partitionNodes = partitionBy?.map(col => columnOperand(col)) ?? undefined;
651
- const orderNodes: OrderByNode[] | undefined = orderBy?.map(o => ({
652
- type: 'OrderBy',
653
- column: columnOperand(o.column),
654
- direction: o.direction
655
- }));
656
-
657
- return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
658
- };
@@ -1,34 +0,0 @@
1
- import { SelectQueryNode } from '../../ast/query';
2
- import { SelectQueryBuilderContext, SelectQueryBuilderEnvironment } from '../select-query-builder-deps';
3
-
4
- /**
5
- * Manages Common Table Expressions (CTEs) for query building
6
- */
7
- export class CteManager {
8
- /**
9
- * Creates a new CteManager instance
10
- * @param env - Query builder environment
11
- */
12
- constructor(private readonly env: SelectQueryBuilderEnvironment) {}
13
-
14
- /**
15
- * Adds a Common Table Expression (CTE) to the query
16
- * @param context - Current query context
17
- * @param name - Name of the CTE
18
- * @param query - Query for the CTE
19
- * @param columns - Optional column names for the CTE
20
- * @param recursive - Whether the CTE is recursive
21
- * @returns Updated query context with CTE
22
- */
23
- withCte(
24
- context: SelectQueryBuilderContext,
25
- name: string,
26
- query: SelectQueryNode,
27
- columns?: string[],
28
- recursive = false
29
- ): SelectQueryBuilderContext {
30
- const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
31
- const nextState = astService.withCte(name, query, columns, recursive);
32
- return { state: nextState, hydration: context.hydration };
33
- }
34
- }