metal-orm 1.0.39 → 1.0.41

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 (52) hide show
  1. package/dist/index.cjs +1466 -189
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +723 -51
  4. package/dist/index.d.ts +723 -51
  5. package/dist/index.js +1457 -189
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/codegen/typescript.ts +66 -5
  9. package/src/core/ast/aggregate-functions.ts +15 -15
  10. package/src/core/ast/expression-builders.ts +378 -316
  11. package/src/core/ast/expression-nodes.ts +210 -186
  12. package/src/core/ast/expression-visitor.ts +40 -30
  13. package/src/core/ast/query.ts +164 -132
  14. package/src/core/ast/window-functions.ts +86 -86
  15. package/src/core/dialect/abstract.ts +509 -479
  16. package/src/core/dialect/base/groupby-compiler.ts +6 -6
  17. package/src/core/dialect/base/join-compiler.ts +9 -12
  18. package/src/core/dialect/base/orderby-compiler.ts +20 -6
  19. package/src/core/dialect/base/sql-dialect.ts +237 -138
  20. package/src/core/dialect/mssql/index.ts +164 -185
  21. package/src/core/dialect/sqlite/index.ts +39 -34
  22. package/src/core/execution/db-executor.ts +46 -6
  23. package/src/core/execution/executors/mssql-executor.ts +39 -22
  24. package/src/core/execution/executors/mysql-executor.ts +23 -6
  25. package/src/core/execution/executors/sqlite-executor.ts +29 -3
  26. package/src/core/execution/pooling/pool-types.ts +30 -0
  27. package/src/core/execution/pooling/pool.ts +268 -0
  28. package/src/core/functions/standard-strategy.ts +46 -37
  29. package/src/decorators/bootstrap.ts +7 -7
  30. package/src/index.ts +6 -0
  31. package/src/orm/domain-event-bus.ts +49 -0
  32. package/src/orm/entity-metadata.ts +9 -9
  33. package/src/orm/entity.ts +58 -0
  34. package/src/orm/orm-session.ts +465 -270
  35. package/src/orm/orm.ts +61 -11
  36. package/src/orm/pooled-executor-factory.ts +131 -0
  37. package/src/orm/query-logger.ts +6 -12
  38. package/src/orm/relation-change-processor.ts +75 -0
  39. package/src/orm/relations/many-to-many.ts +4 -2
  40. package/src/orm/save-graph.ts +303 -0
  41. package/src/orm/transaction-runner.ts +3 -3
  42. package/src/orm/unit-of-work.ts +128 -0
  43. package/src/query-builder/delete-query-state.ts +67 -38
  44. package/src/query-builder/delete.ts +37 -1
  45. package/src/query-builder/hydration-manager.ts +93 -79
  46. package/src/query-builder/insert-query-state.ts +131 -61
  47. package/src/query-builder/insert.ts +27 -1
  48. package/src/query-builder/query-ast-service.ts +207 -170
  49. package/src/query-builder/select-query-state.ts +169 -162
  50. package/src/query-builder/select.ts +15 -23
  51. package/src/query-builder/update-query-state.ts +114 -77
  52. package/src/query-builder/update.ts +38 -1
@@ -1,19 +1,28 @@
1
1
  import type { SelectQueryNode, OrderByNode } from './query.js';
2
2
  import { SqlOperator } from '../sql/sql.js';
3
3
  import { ColumnRef } from './types.js';
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
- */
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 reference to a SELECT alias (for ORDER BY / GROUP BY).
16
+ */
17
+ export interface AliasRefNode {
18
+ type: 'AliasRef';
19
+ /** Alias name to reference */
20
+ name: string;
21
+ }
22
+
23
+ /**
24
+ * AST node representing a column reference
25
+ */
17
26
  export interface ColumnNode {
18
27
  type: 'Column';
19
28
  /** Table name the column belongs to */
@@ -25,10 +34,10 @@ export interface ColumnNode {
25
34
  /** Optional scope marker (e.g., 'outer' for correlated references) */
26
35
  scope?: 'outer' | 'default';
27
36
  }
28
-
29
- /**
30
- * AST node representing a function call
31
- */
37
+
38
+ /**
39
+ * AST node representing a function call
40
+ */
32
41
  export interface FunctionNode {
33
42
  type: 'Function';
34
43
  /** Function name (e.g., COUNT, SUM) */
@@ -46,176 +55,191 @@ export interface FunctionNode {
46
55
  /** Optional DISTINCT modifier */
47
56
  distinct?: boolean;
48
57
  }
49
-
50
- /**
51
- * AST node representing a JSON path expression
52
- */
53
- export interface JsonPathNode {
54
- type: 'JsonPath';
55
- /** Source column */
56
- column: ColumnNode;
57
- /** JSON path expression */
58
- path: string;
59
- /** Optional alias for the result */
60
- alias?: string;
61
- }
62
-
63
- /**
64
- * AST node representing a scalar subquery
65
- */
66
- export interface ScalarSubqueryNode {
67
- type: 'ScalarSubquery';
68
- /** Subquery to execute */
69
- query: SelectQueryNode;
70
- /** Optional alias for the subquery result */
71
- alias?: string;
72
- }
73
-
74
- /**
75
- * AST node representing a CASE expression
76
- */
77
- export interface CaseExpressionNode {
78
- type: 'CaseExpression';
79
- /** WHEN-THEN conditions */
80
- conditions: { when: ExpressionNode; then: OperandNode }[];
81
- /** Optional ELSE clause */
82
- else?: OperandNode;
83
- /** Optional alias for the result */
84
- alias?: string;
85
- }
86
-
87
- /**
88
- * AST node representing a window function
89
- */
90
- export interface WindowFunctionNode {
91
- type: 'WindowFunction';
92
- /** Window function name (e.g., ROW_NUMBER, RANK) */
93
- name: string;
94
- /** Function arguments */
95
- args: (ColumnNode | LiteralNode | JsonPathNode)[];
96
- /** Optional PARTITION BY clause */
97
- partitionBy?: ColumnNode[];
98
- /** Optional ORDER BY clause */
99
- orderBy?: OrderByNode[];
100
- /** Optional alias for the result */
101
- alias?: string;
102
- }
103
-
104
- /**
105
- * Union type representing any operand that can be used in expressions
106
- */
107
- export type OperandNode =
108
- | ColumnNode
109
- | LiteralNode
110
- | FunctionNode
111
- | JsonPathNode
112
- | ScalarSubqueryNode
113
- | CaseExpressionNode
114
- | WindowFunctionNode;
115
-
116
- const operandTypes = new Set<OperandNode['type']>([
117
- 'Column',
118
- 'Literal',
119
- 'Function',
120
- 'JsonPath',
121
- 'ScalarSubquery',
122
- 'CaseExpression',
123
- 'WindowFunction'
124
- ]);
125
-
126
- export const isOperandNode = (node: any): node is OperandNode => node && operandTypes.has(node.type);
127
-
128
- export const isFunctionNode = (node: any): node is FunctionNode => node?.type === 'Function';
129
- export const isCaseExpressionNode = (node: any): node is CaseExpressionNode => node?.type === 'CaseExpression';
130
- export const isWindowFunctionNode = (node: any): node is WindowFunctionNode => node?.type === 'WindowFunction';
58
+
59
+ /**
60
+ * AST node representing a JSON path expression
61
+ */
62
+ export interface JsonPathNode {
63
+ type: 'JsonPath';
64
+ /** Source column */
65
+ column: ColumnNode;
66
+ /** JSON path expression */
67
+ path: string;
68
+ /** Optional alias for the result */
69
+ alias?: string;
70
+ }
71
+
72
+ /**
73
+ * AST node representing a scalar subquery
74
+ */
75
+ export interface ScalarSubqueryNode {
76
+ type: 'ScalarSubquery';
77
+ /** Subquery to execute */
78
+ query: SelectQueryNode;
79
+ /** Optional alias for the subquery result */
80
+ alias?: string;
81
+ }
82
+
83
+ export type InExpressionRight = OperandNode[] | ScalarSubqueryNode;
84
+
85
+ /**
86
+ * AST node representing a CASE expression
87
+ */
88
+ export interface CaseExpressionNode {
89
+ type: 'CaseExpression';
90
+ /** WHEN-THEN conditions */
91
+ conditions: { when: ExpressionNode; then: OperandNode }[];
92
+ /** Optional ELSE clause */
93
+ else?: OperandNode;
94
+ /** Optional alias for the result */
95
+ alias?: string;
96
+ }
97
+
98
+ /**
99
+ * AST node representing a window function
100
+ */
101
+ export interface WindowFunctionNode {
102
+ type: 'WindowFunction';
103
+ /** Window function name (e.g., ROW_NUMBER, RANK) */
104
+ name: string;
105
+ /** Function arguments */
106
+ args: (ColumnNode | LiteralNode | JsonPathNode)[];
107
+ /** Optional PARTITION BY clause */
108
+ partitionBy?: ColumnNode[];
109
+ /** Optional ORDER BY clause */
110
+ orderBy?: OrderByNode[];
111
+ /** Optional alias for the result */
112
+ alias?: string;
113
+ }
114
+
115
+ /**
116
+ * AST node representing an arithmetic expression (e.g., a + b)
117
+ */
118
+ export interface ArithmeticExpressionNode {
119
+ type: 'ArithmeticExpression';
120
+ left: OperandNode;
121
+ operator: '+' | '-' | '*' | '/';
122
+ right: OperandNode;
123
+ }
124
+
125
+ /**
126
+ * Union type representing any operand that can be used in expressions
127
+ */
128
+ export type OperandNode =
129
+ | AliasRefNode
130
+ | ColumnNode
131
+ | LiteralNode
132
+ | FunctionNode
133
+ | JsonPathNode
134
+ | ScalarSubqueryNode
135
+ | CaseExpressionNode
136
+ | WindowFunctionNode;
137
+
138
+ const operandTypes = new Set<OperandNode['type']>([
139
+ 'AliasRef',
140
+ 'Column',
141
+ 'Literal',
142
+ 'Function',
143
+ 'JsonPath',
144
+ 'ScalarSubquery',
145
+ 'CaseExpression',
146
+ 'WindowFunction'
147
+ ]);
148
+
149
+ export const isOperandNode = (node: any): node is OperandNode => node && operandTypes.has(node.type);
150
+
151
+ export const isFunctionNode = (node: any): node is FunctionNode => node?.type === 'Function';
152
+ export const isCaseExpressionNode = (node: any): node is CaseExpressionNode => node?.type === 'CaseExpression';
153
+ export const isWindowFunctionNode = (node: any): node is WindowFunctionNode => node?.type === 'WindowFunction';
131
154
  export const isExpressionSelectionNode = (
132
155
  node: ColumnRef | FunctionNode | CaseExpressionNode | WindowFunctionNode
133
156
  ): node is FunctionNode | CaseExpressionNode | WindowFunctionNode =>
134
157
  isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
135
-
136
- /**
137
- * AST node representing a binary expression (e.g., column = value)
138
- */
139
- export interface BinaryExpressionNode {
140
- type: 'BinaryExpression';
141
- /** Left operand */
142
- left: OperandNode;
143
- /** Comparison operator */
144
- operator: SqlOperator;
145
- /** Right operand */
146
- right: OperandNode;
147
- /** Optional escape character for LIKE expressions */
148
- escape?: LiteralNode;
149
- }
150
-
151
- /**
152
- * AST node representing a logical expression (AND/OR)
153
- */
154
- export interface LogicalExpressionNode {
155
- type: 'LogicalExpression';
156
- /** Logical operator (AND or OR) */
157
- operator: 'AND' | 'OR';
158
- /** Operands to combine */
159
- operands: ExpressionNode[];
160
- }
161
-
162
- /**
163
- * AST node representing a null check expression
164
- */
165
- export interface NullExpressionNode {
166
- type: 'NullExpression';
167
- /** Operand to check for null */
168
- left: OperandNode;
169
- /** Null check operator */
170
- operator: 'IS NULL' | 'IS NOT NULL';
171
- }
172
-
173
- /**
174
- * AST node representing an IN/NOT IN expression
175
- */
176
- export interface InExpressionNode {
177
- type: 'InExpression';
178
- /** Left operand to check */
179
- left: OperandNode;
180
- /** IN/NOT IN operator */
181
- operator: 'IN' | 'NOT IN';
182
- /** Values to check against */
183
- right: OperandNode[];
184
- }
185
-
186
- /**
187
- * AST node representing an EXISTS/NOT EXISTS expression
188
- */
189
- export interface ExistsExpressionNode {
190
- type: 'ExistsExpression';
191
- /** EXISTS/NOT EXISTS operator */
192
- operator: SqlOperator;
193
- /** Subquery to check */
194
- subquery: SelectQueryNode;
195
- }
196
-
197
- /**
198
- * AST node representing a BETWEEN/NOT BETWEEN expression
199
- */
200
- export interface BetweenExpressionNode {
201
- type: 'BetweenExpression';
202
- /** Operand to check */
203
- left: OperandNode;
204
- /** BETWEEN/NOT BETWEEN operator */
205
- operator: 'BETWEEN' | 'NOT BETWEEN';
206
- /** Lower bound */
207
- lower: OperandNode;
208
- /** Upper bound */
209
- upper: OperandNode;
210
- }
211
-
212
- /**
213
- * Union type representing any supported expression node
214
- */
215
- export type ExpressionNode =
216
- | BinaryExpressionNode
217
- | LogicalExpressionNode
218
- | NullExpressionNode
219
- | InExpressionNode
220
- | ExistsExpressionNode
221
- | BetweenExpressionNode;
158
+
159
+ /**
160
+ * AST node representing a binary expression (e.g., column = value)
161
+ */
162
+ export interface BinaryExpressionNode {
163
+ type: 'BinaryExpression';
164
+ /** Left operand */
165
+ left: OperandNode;
166
+ /** Comparison operator */
167
+ operator: SqlOperator;
168
+ /** Right operand */
169
+ right: OperandNode;
170
+ /** Optional escape character for LIKE expressions */
171
+ escape?: LiteralNode;
172
+ }
173
+
174
+ /**
175
+ * AST node representing a logical expression (AND/OR)
176
+ */
177
+ export interface LogicalExpressionNode {
178
+ type: 'LogicalExpression';
179
+ /** Logical operator (AND or OR) */
180
+ operator: 'AND' | 'OR';
181
+ /** Operands to combine */
182
+ operands: ExpressionNode[];
183
+ }
184
+
185
+ /**
186
+ * AST node representing a null check expression
187
+ */
188
+ export interface NullExpressionNode {
189
+ type: 'NullExpression';
190
+ /** Operand to check for null */
191
+ left: OperandNode;
192
+ /** Null check operator */
193
+ operator: 'IS NULL' | 'IS NOT NULL';
194
+ }
195
+
196
+ /**
197
+ * AST node representing an IN/NOT IN expression
198
+ */
199
+ export interface InExpressionNode {
200
+ type: 'InExpression';
201
+ /** Left operand to check */
202
+ left: OperandNode;
203
+ /** IN/NOT IN operator */
204
+ operator: 'IN' | 'NOT IN';
205
+ /** Values to check against */
206
+ right: InExpressionRight;
207
+ }
208
+
209
+ /**
210
+ * AST node representing an EXISTS/NOT EXISTS expression
211
+ */
212
+ export interface ExistsExpressionNode {
213
+ type: 'ExistsExpression';
214
+ /** EXISTS/NOT EXISTS operator */
215
+ operator: SqlOperator;
216
+ /** Subquery to check */
217
+ subquery: SelectQueryNode;
218
+ }
219
+
220
+ /**
221
+ * AST node representing a BETWEEN/NOT BETWEEN expression
222
+ */
223
+ export interface BetweenExpressionNode {
224
+ type: 'BetweenExpression';
225
+ /** Operand to check */
226
+ left: OperandNode;
227
+ /** BETWEEN/NOT BETWEEN operator */
228
+ operator: 'BETWEEN' | 'NOT BETWEEN';
229
+ /** Lower bound */
230
+ lower: OperandNode;
231
+ /** Upper bound */
232
+ upper: OperandNode;
233
+ }
234
+
235
+ /**
236
+ * Union type representing any supported expression node
237
+ */
238
+ export type ExpressionNode =
239
+ | BinaryExpressionNode
240
+ | LogicalExpressionNode
241
+ | NullExpressionNode
242
+ | InExpressionNode
243
+ | ExistsExpressionNode
244
+ | BetweenExpressionNode
245
+ | ArithmeticExpressionNode;
@@ -1,24 +1,26 @@
1
- import {
2
- BinaryExpressionNode,
3
- LogicalExpressionNode,
4
- NullExpressionNode,
5
- InExpressionNode,
6
- ExistsExpressionNode,
7
- BetweenExpressionNode,
8
- ExpressionNode,
9
- OperandNode,
10
- ColumnNode,
11
- LiteralNode,
12
- FunctionNode,
13
- JsonPathNode,
14
- ScalarSubqueryNode,
15
- CaseExpressionNode,
16
- WindowFunctionNode
17
- } from './expression-nodes.js';
18
-
19
- /**
20
- * Visitor for expression nodes
21
- */
1
+ import {
2
+ BinaryExpressionNode,
3
+ LogicalExpressionNode,
4
+ NullExpressionNode,
5
+ InExpressionNode,
6
+ ExistsExpressionNode,
7
+ BetweenExpressionNode,
8
+ ExpressionNode,
9
+ OperandNode,
10
+ ArithmeticExpressionNode,
11
+ ColumnNode,
12
+ LiteralNode,
13
+ FunctionNode,
14
+ JsonPathNode,
15
+ ScalarSubqueryNode,
16
+ CaseExpressionNode,
17
+ WindowFunctionNode,
18
+ AliasRefNode
19
+ } from './expression-nodes.js';
20
+
21
+ /**
22
+ * Visitor for expression nodes
23
+ */
22
24
  export interface ExpressionVisitor<R> {
23
25
  visitBinaryExpression?(node: BinaryExpressionNode): R;
24
26
  visitLogicalExpression?(node: LogicalExpressionNode): R;
@@ -26,6 +28,7 @@ export interface ExpressionVisitor<R> {
26
28
  visitInExpression?(node: InExpressionNode): R;
27
29
  visitExistsExpression?(node: ExistsExpressionNode): R;
28
30
  visitBetweenExpression?(node: BetweenExpressionNode): R;
31
+ visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
29
32
  otherwise?(node: ExpressionNode): R;
30
33
  }
31
34
 
@@ -40,6 +43,7 @@ export interface OperandVisitor<R> {
40
43
  visitScalarSubquery?(node: ScalarSubqueryNode): R;
41
44
  visitCaseExpression?(node: CaseExpressionNode): R;
42
45
  visitWindowFunction?(node: WindowFunctionNode): R;
46
+ visitAliasRef?(node: AliasRefNode): R;
43
47
  otherwise?(node: OperandNode): R;
44
48
  }
45
49
 
@@ -74,12 +78,12 @@ export const clearOperandDispatchers = (): void => operandDispatchers.clear();
74
78
  const unsupportedExpression = (node: ExpressionNode): never => {
75
79
  throw new Error(`Unsupported expression type "${(node as any)?.type ?? 'unknown'}"`);
76
80
  };
77
-
78
- const unsupportedOperand = (node: OperandNode): never => {
79
- throw new Error(`Unsupported operand type "${(node as any)?.type ?? 'unknown'}"`);
80
- };
81
- /**
82
- * Dispatches an expression node to the visitor
81
+
82
+ const unsupportedOperand = (node: OperandNode): never => {
83
+ throw new Error(`Unsupported operand type "${(node as any)?.type ?? 'unknown'}"`);
84
+ };
85
+ /**
86
+ * Dispatches an expression node to the visitor
83
87
  * @param node - Expression node to visit
84
88
  * @param visitor - Visitor implementation
85
89
  */
@@ -106,15 +110,18 @@ export const visitExpression = <R>(node: ExpressionNode, visitor: ExpressionVisi
106
110
  case 'BetweenExpression':
107
111
  if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node);
108
112
  break;
113
+ case 'ArithmeticExpression':
114
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
115
+ break;
109
116
  default:
110
117
  break;
111
118
  }
112
119
  if (visitor.otherwise) return visitor.otherwise(node);
113
120
  return unsupportedExpression(node);
114
121
  };
115
-
116
- /**
117
- * Dispatches an operand node to the visitor
122
+
123
+ /**
124
+ * Dispatches an operand node to the visitor
118
125
  * @param node - Operand node to visit
119
126
  * @param visitor - Visitor implementation
120
127
  */
@@ -144,6 +151,9 @@ export const visitOperand = <R>(node: OperandNode, visitor: OperandVisitor<R>):
144
151
  case 'WindowFunction':
145
152
  if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node);
146
153
  break;
154
+ case 'AliasRef':
155
+ if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
156
+ break;
147
157
  default:
148
158
  break;
149
159
  }