metal-orm 1.1.11 → 1.1.18

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 (182) hide show
  1. package/README.md +758 -769
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/package.json +100 -96
  5. package/scripts/generate-entities/schema.mjs +122 -122
  6. package/scripts/generate-entities/tree-detection.mjs +92 -92
  7. package/scripts/inflection/pt-br.mjs +468 -468
  8. package/scripts/run-eslint.mjs +33 -34
  9. package/scripts/show-sql-seed.sql +102 -0
  10. package/scripts/show-sql.mjs +321 -325
  11. package/src/codegen/naming-strategy.ts +54 -54
  12. package/src/codegen/typescript.ts +482 -482
  13. package/src/core/ast/adapters.ts +1 -1
  14. package/src/core/ast/builders.ts +123 -123
  15. package/src/core/ast/expression-builders.ts +745 -745
  16. package/src/core/ast/expression-nodes.ts +304 -304
  17. package/src/core/ast/expression-visitor.ts +212 -212
  18. package/src/core/ast/expression.ts +20 -20
  19. package/src/core/ast/helpers.ts +14 -14
  20. package/src/core/ast/join.ts +18 -18
  21. package/src/core/ast/query.ts +200 -200
  22. package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
  23. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
  24. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
  25. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
  26. package/src/core/ddl/dialects/render-reference.test.ts +70 -70
  27. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
  28. package/src/core/ddl/introspect/catalogs/index.ts +5 -5
  29. package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
  30. package/src/core/ddl/introspect/context.ts +15 -15
  31. package/src/core/ddl/introspect/functions/postgres.ts +35 -35
  32. package/src/core/ddl/introspect/registry.ts +40 -40
  33. package/src/core/ddl/introspect/run-select.ts +35 -35
  34. package/src/core/ddl/introspect/utils.ts +56 -56
  35. package/src/core/ddl/naming-strategy.ts +16 -16
  36. package/src/core/ddl/schema-dialect.ts +56 -56
  37. package/src/core/ddl/schema-diff.ts +234 -234
  38. package/src/core/ddl/schema-generator.ts +1 -1
  39. package/src/core/ddl/schema-introspect.ts +25 -25
  40. package/src/core/ddl/sql-writing.ts +171 -171
  41. package/src/core/dialect/abstract.ts +541 -541
  42. package/src/core/dialect/base/cte-compiler.ts +33 -33
  43. package/src/core/dialect/base/function-table-formatter.ts +103 -103
  44. package/src/core/dialect/base/groupby-compiler.ts +21 -21
  45. package/src/core/dialect/base/join-compiler.ts +25 -25
  46. package/src/core/dialect/base/orderby-compiler.ts +35 -35
  47. package/src/core/dialect/base/pagination-strategy.ts +32 -32
  48. package/src/core/dialect/base/returning-strategy.ts +57 -57
  49. package/src/core/dialect/base/sql-dialect.ts +294 -294
  50. package/src/core/dialect/dialect-factory.ts +91 -91
  51. package/src/core/dialect/mssql/functions.ts +120 -120
  52. package/src/core/dialect/mssql/index.ts +317 -317
  53. package/src/core/dialect/mysql/functions.ts +103 -103
  54. package/src/core/dialect/mysql/index.ts +105 -105
  55. package/src/core/dialect/postgres/functions.ts +108 -108
  56. package/src/core/dialect/postgres/index.ts +91 -91
  57. package/src/core/dialect/sqlite/functions.ts +129 -129
  58. package/src/core/dialect/sqlite/index.ts +67 -67
  59. package/src/core/driver/database-driver.ts +19 -19
  60. package/src/core/driver/mssql-driver.ts +23 -23
  61. package/src/core/driver/mysql-driver.ts +23 -23
  62. package/src/core/driver/postgres-driver.ts +23 -23
  63. package/src/core/driver/sqlite-driver.ts +23 -23
  64. package/src/core/execution/db-executor.ts +92 -92
  65. package/src/core/execution/executors/better-sqlite3-executor.ts +90 -90
  66. package/src/core/execution/executors/mssql-executor.ts +184 -184
  67. package/src/core/execution/executors/mysql-executor.ts +88 -88
  68. package/src/core/execution/executors/postgres-executor.ts +26 -26
  69. package/src/core/execution/executors/sqlite-executor.ts +42 -42
  70. package/src/core/execution/pooling/pool-types.ts +30 -30
  71. package/src/core/execution/pooling/pool.ts +275 -275
  72. package/src/core/functions/array.ts +35 -35
  73. package/src/core/functions/control-flow.ts +79 -79
  74. package/src/core/functions/datetime.ts +237 -237
  75. package/src/core/functions/json.ts +70 -70
  76. package/src/core/functions/numeric.ts +297 -297
  77. package/src/core/functions/text.ts +334 -334
  78. package/src/core/functions/types.ts +33 -33
  79. package/src/core/hydration/types.ts +51 -51
  80. package/src/core/sql/sql-operator-config.ts +39 -39
  81. package/src/core/sql/sql.ts +152 -152
  82. package/src/decorators/column-decorator.ts +87 -87
  83. package/src/decorators/decorator-metadata.ts +143 -143
  84. package/src/decorators/entity.ts +93 -93
  85. package/src/decorators/index.ts +39 -39
  86. package/src/decorators/relations.ts +231 -231
  87. package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
  88. package/src/decorators/transformers/transformer-decorators.ts +134 -134
  89. package/src/decorators/transformers/transformer-executor.ts +171 -171
  90. package/src/decorators/transformers/transformer-metadata.ts +73 -73
  91. package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
  92. package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
  93. package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
  94. package/src/decorators/validators/country-validator-registry.ts +64 -64
  95. package/src/decorators/validators/country-validators-decorators.ts +203 -203
  96. package/src/decorators/validators/country-validators.ts +105 -105
  97. package/src/decorators/validators/validator-metadata.ts +59 -59
  98. package/src/dto/dto-types.ts +226 -226
  99. package/src/dto/filter-types.ts +141 -141
  100. package/src/dto/index.ts +95 -95
  101. package/src/dto/openapi/generators/base.ts +29 -29
  102. package/src/dto/openapi/generators/column.ts +37 -37
  103. package/src/dto/openapi/generators/dto.ts +91 -91
  104. package/src/dto/openapi/generators/filter.ts +75 -75
  105. package/src/dto/openapi/generators/nested-dto.ts +618 -618
  106. package/src/dto/openapi/generators/pagination.ts +111 -111
  107. package/src/dto/openapi/generators/relation-filter.ts +228 -228
  108. package/src/dto/openapi/index.ts +12 -12
  109. package/src/dto/openapi/types.ts +101 -101
  110. package/src/dto/openapi/utilities.ts +95 -95
  111. package/src/dto/pagination-utils.ts +150 -150
  112. package/src/dto/transform.ts +197 -197
  113. package/src/index.ts +86 -86
  114. package/src/orm/als.ts +58 -58
  115. package/src/orm/domain-event-bus.ts +119 -119
  116. package/src/orm/entity-context.ts +86 -86
  117. package/src/orm/entity-materializer.ts +159 -159
  118. package/src/orm/entity-meta.ts +97 -97
  119. package/src/orm/entity-registry.ts +39 -39
  120. package/src/orm/entity-relation-cache.ts +39 -39
  121. package/src/orm/execute.ts +194 -194
  122. package/src/orm/execution-context.ts +18 -18
  123. package/src/orm/hydration-context.ts +26 -26
  124. package/src/orm/hydration.ts +112 -112
  125. package/src/orm/identity-map.ts +61 -61
  126. package/src/orm/interceptor-pipeline.ts +16 -16
  127. package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
  128. package/src/orm/lazy-batch/belongs-to.ts +108 -108
  129. package/src/orm/lazy-batch/has-many.ts +69 -69
  130. package/src/orm/lazy-batch/has-one.ts +68 -68
  131. package/src/orm/lazy-batch/shared.ts +125 -125
  132. package/src/orm/orm-session.ts +620 -620
  133. package/src/orm/orm.ts +34 -34
  134. package/src/orm/pooled-executor-factory.ts +121 -121
  135. package/src/orm/query-logger.ts +40 -40
  136. package/src/orm/relation-change-processor.ts +420 -420
  137. package/src/orm/relations/belongs-to.ts +143 -143
  138. package/src/orm/relations/has-many.ts +204 -204
  139. package/src/orm/relations/has-one.ts +174 -174
  140. package/src/orm/relations/many-to-many.ts +288 -288
  141. package/src/orm/relations/morph-many.ts +156 -156
  142. package/src/orm/relations/morph-one.ts +151 -151
  143. package/src/orm/relations/morph-to.ts +162 -162
  144. package/src/orm/runtime-types.ts +92 -92
  145. package/src/orm/save-graph.ts +561 -561
  146. package/src/orm/transaction-runner.ts +24 -24
  147. package/src/orm/unit-of-work.ts +426 -426
  148. package/src/query/index.ts +69 -69
  149. package/src/query/target.ts +46 -46
  150. package/src/query-builder/column-selector.ts +81 -81
  151. package/src/query-builder/delete.ts +141 -141
  152. package/src/query-builder/insert-query-state.ts +149 -149
  153. package/src/query-builder/insert.ts +117 -117
  154. package/src/query-builder/query-ast-service.ts +287 -287
  155. package/src/query-builder/query-resolution.ts +78 -78
  156. package/src/query-builder/raw-column-parser.ts +38 -38
  157. package/src/query-builder/relation-filter-utils.ts +153 -153
  158. package/src/query-builder/relation-join-planner.ts +10 -10
  159. package/src/query-builder/relation-manager.ts +87 -87
  160. package/src/query-builder/relation-projection-helper.ts +102 -102
  161. package/src/query-builder/relation-types.ts +9 -9
  162. package/src/query-builder/relation-utils.ts +15 -15
  163. package/src/query-builder/select/cte-facet.ts +40 -40
  164. package/src/query-builder/select/from-facet.ts +80 -80
  165. package/src/query-builder/select/join-facet.ts +62 -62
  166. package/src/query-builder/select/predicate-facet.ts +104 -104
  167. package/src/query-builder/select/projection-facet.ts +70 -70
  168. package/src/query-builder/select/relation-facet.ts +81 -81
  169. package/src/query-builder/select/setop-facet.ts +36 -36
  170. package/src/query-builder/select-helpers.ts +1 -1
  171. package/src/query-builder/select-query-builder-deps.ts +130 -130
  172. package/src/query-builder/select-query-state.ts +207 -207
  173. package/src/query-builder/update.ts +151 -151
  174. package/src/schema/column-types.ts +322 -322
  175. package/src/schema/table-guards.ts +37 -37
  176. package/src/schema/table.ts +281 -281
  177. package/src/tree/index.ts +13 -13
  178. package/src/tree/nested-set-strategy.ts +545 -545
  179. package/src/tree/tree-decorator.ts +397 -397
  180. package/src/tree/tree-manager.ts +754 -754
  181. package/src/tree/tree-query.ts +427 -427
  182. package/src/tree/tree-types.ts +299 -299
@@ -1,287 +1,287 @@
1
- import { TableDef } from '../schema/table.js';
2
- import { ColumnDef } from '../schema/column-types.js';
3
- import {
4
- SelectQueryNode,
5
- CommonTableExpressionNode,
6
- SetOperationKind,
7
- SetOperationNode,
8
- TableSourceNode,
9
- OrderingTerm
10
- } from '../core/ast/query.js';
11
- import { buildColumnNode } from '../core/ast/builders.js';
12
- import {
13
- AliasRefNode,
14
- ColumnNode,
15
- ExpressionNode,
16
- FunctionNode,
17
- CaseExpressionNode,
18
- CastExpressionNode,
19
- WindowFunctionNode,
20
- ScalarSubqueryNode,
21
- and,
22
- isExpressionSelectionNode,
23
- isOperandNode
24
- } from '../core/ast/expression.js';
25
- import { JoinNode } from '../core/ast/join.js';
26
- import { SelectQueryState, ProjectionNode } from './select-query-state.js';
27
- import { OrderDirection } from '../core/sql/sql.js';
28
- import { parseRawColumn } from './raw-column-parser.js';
29
-
30
- /**
31
- * Result of column selection operation
32
- */
33
- export interface ColumnSelectionResult {
34
- /**
35
- * Updated query state
36
- */
37
- state: SelectQueryState;
38
- /**
39
- * Columns that were added
40
- */
41
- addedColumns: ProjectionNode[];
42
- }
43
-
44
- /**
45
- * Service for manipulating query AST (Abstract Syntax Tree)
46
- */
47
- export class QueryAstService {
48
- /**
49
- * Creates a new QueryAstService instance
50
- * @param table - Table definition
51
- * @param state - Current query state
52
- */
53
- constructor(private readonly table: TableDef, private readonly state: SelectQueryState) { }
54
-
55
- /**
56
- * Selects columns for the query
57
- * @param columns - Columns to select (key: alias, value: column definition or expression)
58
- * @returns Column selection result with updated state and added columns
59
- */
60
- select(
61
- columns: Record<string, ColumnDef | FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode>
62
- ): ColumnSelectionResult {
63
- const existingAliases = new Set(
64
- this.state.ast.columns.map(c => (c as ColumnNode).alias || (c as ColumnNode).name)
65
- );
66
- const from = this.state.ast.from;
67
- const rootTableName = from.type === 'Table' && from.alias ? from.alias : this.table.name;
68
-
69
- const newCols = Object.entries(columns).reduce<ProjectionNode[]>((acc, [alias, val]) => {
70
- if (existingAliases.has(alias)) return acc;
71
-
72
- if (isExpressionSelectionNode(val)) {
73
- acc.push({ ...(val as FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode), alias } as ProjectionNode);
74
- return acc;
75
- }
76
-
77
- const colDef = val as ColumnDef;
78
- const resolvedTable =
79
- colDef.table && colDef.table === this.table.name && from.type === 'Table' && from.alias
80
- ? from.alias
81
- : colDef.table || rootTableName;
82
- acc.push({
83
- type: 'Column',
84
- table: resolvedTable,
85
- name: colDef.name,
86
- alias
87
- } as ColumnNode);
88
- return acc;
89
- }, []);
90
-
91
- const nextState = this.state.withColumns(newCols);
92
- return { state: nextState, addedColumns: newCols };
93
- }
94
-
95
- /**
96
- * Selects raw column expressions (best-effort parser for simple references/functions)
97
- * @param cols - Raw column expressions
98
- * @returns Column selection result with updated state and added columns
99
- */
100
- selectRaw(cols: string[]): ColumnSelectionResult {
101
- const from = this.state.ast.from;
102
- const defaultTable = from.type === 'Table' && from.alias ? from.alias : this.table.name;
103
- const newCols = cols.map(col => parseRawColumn(col, defaultTable, this.state.ast.ctes));
104
- const nextState = this.state.withColumns(newCols);
105
- return { state: nextState, addedColumns: newCols };
106
- }
107
-
108
- /**
109
- * Adds a Common Table Expression (CTE) to the query
110
- * @param name - Name of the CTE
111
- * @param query - Query for the CTE
112
- * @param columns - Optional column names for the CTE
113
- * @param recursive - Whether the CTE is recursive
114
- * @returns Updated query state with CTE
115
- */
116
- withCte(name: string, query: SelectQueryNode, columns?: string[], recursive = false): SelectQueryState {
117
- const cte: CommonTableExpressionNode = {
118
- type: 'CommonTableExpression',
119
- name,
120
- query,
121
- columns,
122
- recursive
123
- };
124
-
125
- return this.state.withCte(cte);
126
- }
127
-
128
- /**
129
- * Adds a set operation (UNION/UNION ALL/INTERSECT/EXCEPT) to the query
130
- * @param operator - Set operator
131
- * @param query - Right-hand side query
132
- * @returns Updated query state with set operation
133
- */
134
- withSetOperation(operator: SetOperationKind, query: SelectQueryNode): SelectQueryState {
135
- const op: SetOperationNode = {
136
- type: 'SetOperation',
137
- operator,
138
- query
139
- };
140
- return this.state.withSetOperation(op);
141
- }
142
-
143
- /**
144
- * Replaces the FROM clause for the current query.
145
- * @param from - Table source to use in the FROM clause
146
- * @returns Updated query state with new FROM
147
- */
148
- withFrom(from: TableSourceNode): SelectQueryState {
149
- return this.state.withFrom(from);
150
- }
151
-
152
- /**
153
- * Selects a subquery as a column
154
- * @param alias - Alias for the subquery
155
- * @param query - Subquery to select
156
- * @returns Updated query state with subquery selection
157
- */
158
- selectSubquery(alias: string, query: SelectQueryNode): SelectQueryState {
159
- const node: ScalarSubqueryNode = { type: 'ScalarSubquery', query, alias };
160
- return this.state.withColumns([node]);
161
- }
162
-
163
- /**
164
- * Adds a JOIN clause to the query
165
- * @param join - Join node to add
166
- * @returns Updated query state with JOIN
167
- */
168
- withJoin(join: JoinNode): SelectQueryState {
169
- return this.state.withJoin(join);
170
- }
171
-
172
- /**
173
- * Adds a WHERE clause to the query
174
- * @param expr - Expression for the WHERE clause
175
- * @returns Updated query state with WHERE clause
176
- */
177
- withWhere(expr: ExpressionNode): SelectQueryState {
178
- const combined = this.combineExpressions(this.state.ast.where, expr);
179
- return this.state.withWhere(combined);
180
- }
181
-
182
- /**
183
- * Adds a GROUP BY clause to the query
184
- * @param col - Column to group by
185
- * @returns Updated query state with GROUP BY clause
186
- */
187
- withGroupBy(col: ColumnDef | OrderingTerm): SelectQueryState {
188
- const term = this.normalizeOrderingTerm(col);
189
- return this.state.withGroupBy([term]);
190
- }
191
-
192
- /**
193
- * Adds a HAVING clause to the query
194
- * @param expr - Expression for the HAVING clause
195
- * @returns Updated query state with HAVING clause
196
- */
197
- withHaving(expr: ExpressionNode): SelectQueryState {
198
- const combined = this.combineExpressions(this.state.ast.having, expr);
199
- return this.state.withHaving(combined);
200
- }
201
-
202
- /**
203
- * Adds an ORDER BY clause to the query
204
- * @param col - Column to order by
205
- * @param direction - Order direction (ASC/DESC)
206
- * @returns Updated query state with ORDER BY clause
207
- */
208
- withOrderBy(
209
- term: ColumnDef | OrderingTerm,
210
- direction: OrderDirection,
211
- nulls?: 'FIRST' | 'LAST',
212
- collation?: string
213
- ): SelectQueryState {
214
- const normalized = this.normalizeOrderingTerm(term);
215
- return this.state.withOrderBy([{ type: 'OrderBy', term: normalized, direction, nulls, collation }]);
216
- }
217
-
218
- /**
219
- * Adds a DISTINCT clause to the query
220
- * @param cols - Columns to make distinct
221
- * @returns Updated query state with DISTINCT clause
222
- */
223
- withDistinct(cols: ColumnNode[]): SelectQueryState {
224
- return this.state.withDistinct(cols);
225
- }
226
-
227
- /**
228
- * Adds a LIMIT clause to the query
229
- * @param limit - Maximum number of rows to return
230
- * @returns Updated query state with LIMIT clause
231
- */
232
- withLimit(limit: number): SelectQueryState {
233
- return this.state.withLimit(limit);
234
- }
235
-
236
- /**
237
- * Adds an OFFSET clause to the query
238
- * @param offset - Number of rows to skip
239
- * @returns Updated query state with OFFSET clause
240
- */
241
- withOffset(offset: number): SelectQueryState {
242
- return this.state.withOffset(offset);
243
- }
244
-
245
- /**
246
- * Combines expressions with AND operator
247
- * @param existing - Existing expression
248
- * @param next - New expression to combine
249
- * @returns Combined expression
250
- */
251
- private combineExpressions(existing: ExpressionNode | undefined, next: ExpressionNode): ExpressionNode {
252
- return existing ? and(existing, next) : next;
253
- }
254
-
255
- /**
256
- * Normalizes an ordering term to a standard OrderingTerm
257
- * @param term - Column definition or ordering term to normalize
258
- * @returns Normalized ordering term
259
- */
260
- private normalizeOrderingTerm(term: ColumnDef | OrderingTerm): OrderingTerm {
261
- const from = this.state.ast.from;
262
- const tableRef = from.type === 'Table' && from.alias ? { ...this.table, alias: from.alias } : this.table;
263
- const termType = (term as { type?: string }).type;
264
- if (termType === 'Column') {
265
- return term as ColumnNode;
266
- }
267
- if (termType === 'AliasRef') {
268
- return term as AliasRefNode;
269
- }
270
- if (isOperandNode(term)) {
271
- return term as OrderingTerm;
272
- }
273
- if (
274
- termType === 'BinaryExpression' ||
275
- termType === 'LogicalExpression' ||
276
- termType === 'NullExpression' ||
277
- termType === 'InExpression' ||
278
- termType === 'ExistsExpression' ||
279
- termType === 'BetweenExpression' ||
280
- termType === 'ArithmeticExpression'
281
- ) {
282
- return term as ExpressionNode;
283
- }
284
- return buildColumnNode(tableRef, term as ColumnDef);
285
- }
286
-
287
- }
1
+ import { TableDef } from '../schema/table.js';
2
+ import { ColumnDef } from '../schema/column-types.js';
3
+ import {
4
+ SelectQueryNode,
5
+ CommonTableExpressionNode,
6
+ SetOperationKind,
7
+ SetOperationNode,
8
+ TableSourceNode,
9
+ OrderingTerm
10
+ } from '../core/ast/query.js';
11
+ import { buildColumnNode } from '../core/ast/builders.js';
12
+ import {
13
+ AliasRefNode,
14
+ ColumnNode,
15
+ ExpressionNode,
16
+ FunctionNode,
17
+ CaseExpressionNode,
18
+ CastExpressionNode,
19
+ WindowFunctionNode,
20
+ ScalarSubqueryNode,
21
+ and,
22
+ isExpressionSelectionNode,
23
+ isOperandNode
24
+ } from '../core/ast/expression.js';
25
+ import { JoinNode } from '../core/ast/join.js';
26
+ import { SelectQueryState, ProjectionNode } from './select-query-state.js';
27
+ import { OrderDirection } from '../core/sql/sql.js';
28
+ import { parseRawColumn } from './raw-column-parser.js';
29
+
30
+ /**
31
+ * Result of column selection operation
32
+ */
33
+ export interface ColumnSelectionResult {
34
+ /**
35
+ * Updated query state
36
+ */
37
+ state: SelectQueryState;
38
+ /**
39
+ * Columns that were added
40
+ */
41
+ addedColumns: ProjectionNode[];
42
+ }
43
+
44
+ /**
45
+ * Service for manipulating query AST (Abstract Syntax Tree)
46
+ */
47
+ export class QueryAstService {
48
+ /**
49
+ * Creates a new QueryAstService instance
50
+ * @param table - Table definition
51
+ * @param state - Current query state
52
+ */
53
+ constructor(private readonly table: TableDef, private readonly state: SelectQueryState) { }
54
+
55
+ /**
56
+ * Selects columns for the query
57
+ * @param columns - Columns to select (key: alias, value: column definition or expression)
58
+ * @returns Column selection result with updated state and added columns
59
+ */
60
+ select(
61
+ columns: Record<string, ColumnDef | FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode>
62
+ ): ColumnSelectionResult {
63
+ const existingAliases = new Set(
64
+ this.state.ast.columns.map(c => (c as ColumnNode).alias || (c as ColumnNode).name)
65
+ );
66
+ const from = this.state.ast.from;
67
+ const rootTableName = from.type === 'Table' && from.alias ? from.alias : this.table.name;
68
+
69
+ const newCols = Object.entries(columns).reduce<ProjectionNode[]>((acc, [alias, val]) => {
70
+ if (existingAliases.has(alias)) return acc;
71
+
72
+ if (isExpressionSelectionNode(val)) {
73
+ acc.push({ ...(val as FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode), alias } as ProjectionNode);
74
+ return acc;
75
+ }
76
+
77
+ const colDef = val as ColumnDef;
78
+ const resolvedTable =
79
+ colDef.table && colDef.table === this.table.name && from.type === 'Table' && from.alias
80
+ ? from.alias
81
+ : colDef.table || rootTableName;
82
+ acc.push({
83
+ type: 'Column',
84
+ table: resolvedTable,
85
+ name: colDef.name,
86
+ alias
87
+ } as ColumnNode);
88
+ return acc;
89
+ }, []);
90
+
91
+ const nextState = this.state.withColumns(newCols);
92
+ return { state: nextState, addedColumns: newCols };
93
+ }
94
+
95
+ /**
96
+ * Selects raw column expressions (best-effort parser for simple references/functions)
97
+ * @param cols - Raw column expressions
98
+ * @returns Column selection result with updated state and added columns
99
+ */
100
+ selectRaw(cols: string[]): ColumnSelectionResult {
101
+ const from = this.state.ast.from;
102
+ const defaultTable = from.type === 'Table' && from.alias ? from.alias : this.table.name;
103
+ const newCols = cols.map(col => parseRawColumn(col, defaultTable, this.state.ast.ctes));
104
+ const nextState = this.state.withColumns(newCols);
105
+ return { state: nextState, addedColumns: newCols };
106
+ }
107
+
108
+ /**
109
+ * Adds a Common Table Expression (CTE) to the query
110
+ * @param name - Name of the CTE
111
+ * @param query - Query for the CTE
112
+ * @param columns - Optional column names for the CTE
113
+ * @param recursive - Whether the CTE is recursive
114
+ * @returns Updated query state with CTE
115
+ */
116
+ withCte(name: string, query: SelectQueryNode, columns?: string[], recursive = false): SelectQueryState {
117
+ const cte: CommonTableExpressionNode = {
118
+ type: 'CommonTableExpression',
119
+ name,
120
+ query,
121
+ columns,
122
+ recursive
123
+ };
124
+
125
+ return this.state.withCte(cte);
126
+ }
127
+
128
+ /**
129
+ * Adds a set operation (UNION/UNION ALL/INTERSECT/EXCEPT) to the query
130
+ * @param operator - Set operator
131
+ * @param query - Right-hand side query
132
+ * @returns Updated query state with set operation
133
+ */
134
+ withSetOperation(operator: SetOperationKind, query: SelectQueryNode): SelectQueryState {
135
+ const op: SetOperationNode = {
136
+ type: 'SetOperation',
137
+ operator,
138
+ query
139
+ };
140
+ return this.state.withSetOperation(op);
141
+ }
142
+
143
+ /**
144
+ * Replaces the FROM clause for the current query.
145
+ * @param from - Table source to use in the FROM clause
146
+ * @returns Updated query state with new FROM
147
+ */
148
+ withFrom(from: TableSourceNode): SelectQueryState {
149
+ return this.state.withFrom(from);
150
+ }
151
+
152
+ /**
153
+ * Selects a subquery as a column
154
+ * @param alias - Alias for the subquery
155
+ * @param query - Subquery to select
156
+ * @returns Updated query state with subquery selection
157
+ */
158
+ selectSubquery(alias: string, query: SelectQueryNode): SelectQueryState {
159
+ const node: ScalarSubqueryNode = { type: 'ScalarSubquery', query, alias };
160
+ return this.state.withColumns([node]);
161
+ }
162
+
163
+ /**
164
+ * Adds a JOIN clause to the query
165
+ * @param join - Join node to add
166
+ * @returns Updated query state with JOIN
167
+ */
168
+ withJoin(join: JoinNode): SelectQueryState {
169
+ return this.state.withJoin(join);
170
+ }
171
+
172
+ /**
173
+ * Adds a WHERE clause to the query
174
+ * @param expr - Expression for the WHERE clause
175
+ * @returns Updated query state with WHERE clause
176
+ */
177
+ withWhere(expr: ExpressionNode): SelectQueryState {
178
+ const combined = this.combineExpressions(this.state.ast.where, expr);
179
+ return this.state.withWhere(combined);
180
+ }
181
+
182
+ /**
183
+ * Adds a GROUP BY clause to the query
184
+ * @param col - Column to group by
185
+ * @returns Updated query state with GROUP BY clause
186
+ */
187
+ withGroupBy(col: ColumnDef | OrderingTerm): SelectQueryState {
188
+ const term = this.normalizeOrderingTerm(col);
189
+ return this.state.withGroupBy([term]);
190
+ }
191
+
192
+ /**
193
+ * Adds a HAVING clause to the query
194
+ * @param expr - Expression for the HAVING clause
195
+ * @returns Updated query state with HAVING clause
196
+ */
197
+ withHaving(expr: ExpressionNode): SelectQueryState {
198
+ const combined = this.combineExpressions(this.state.ast.having, expr);
199
+ return this.state.withHaving(combined);
200
+ }
201
+
202
+ /**
203
+ * Adds an ORDER BY clause to the query
204
+ * @param col - Column to order by
205
+ * @param direction - Order direction (ASC/DESC)
206
+ * @returns Updated query state with ORDER BY clause
207
+ */
208
+ withOrderBy(
209
+ term: ColumnDef | OrderingTerm,
210
+ direction: OrderDirection,
211
+ nulls?: 'FIRST' | 'LAST',
212
+ collation?: string
213
+ ): SelectQueryState {
214
+ const normalized = this.normalizeOrderingTerm(term);
215
+ return this.state.withOrderBy([{ type: 'OrderBy', term: normalized, direction, nulls, collation }]);
216
+ }
217
+
218
+ /**
219
+ * Adds a DISTINCT clause to the query
220
+ * @param cols - Columns to make distinct
221
+ * @returns Updated query state with DISTINCT clause
222
+ */
223
+ withDistinct(cols: ColumnNode[]): SelectQueryState {
224
+ return this.state.withDistinct(cols);
225
+ }
226
+
227
+ /**
228
+ * Adds a LIMIT clause to the query
229
+ * @param limit - Maximum number of rows to return
230
+ * @returns Updated query state with LIMIT clause
231
+ */
232
+ withLimit(limit: number): SelectQueryState {
233
+ return this.state.withLimit(limit);
234
+ }
235
+
236
+ /**
237
+ * Adds an OFFSET clause to the query
238
+ * @param offset - Number of rows to skip
239
+ * @returns Updated query state with OFFSET clause
240
+ */
241
+ withOffset(offset: number): SelectQueryState {
242
+ return this.state.withOffset(offset);
243
+ }
244
+
245
+ /**
246
+ * Combines expressions with AND operator
247
+ * @param existing - Existing expression
248
+ * @param next - New expression to combine
249
+ * @returns Combined expression
250
+ */
251
+ private combineExpressions(existing: ExpressionNode | undefined, next: ExpressionNode): ExpressionNode {
252
+ return existing ? and(existing, next) : next;
253
+ }
254
+
255
+ /**
256
+ * Normalizes an ordering term to a standard OrderingTerm
257
+ * @param term - Column definition or ordering term to normalize
258
+ * @returns Normalized ordering term
259
+ */
260
+ private normalizeOrderingTerm(term: ColumnDef | OrderingTerm): OrderingTerm {
261
+ const from = this.state.ast.from;
262
+ const tableRef = from.type === 'Table' && from.alias ? { ...this.table, alias: from.alias } : this.table;
263
+ const termType = (term as { type?: string }).type;
264
+ if (termType === 'Column') {
265
+ return term as ColumnNode;
266
+ }
267
+ if (termType === 'AliasRef') {
268
+ return term as AliasRefNode;
269
+ }
270
+ if (isOperandNode(term)) {
271
+ return term as OrderingTerm;
272
+ }
273
+ if (
274
+ termType === 'BinaryExpression' ||
275
+ termType === 'LogicalExpression' ||
276
+ termType === 'NullExpression' ||
277
+ termType === 'InExpression' ||
278
+ termType === 'ExistsExpression' ||
279
+ termType === 'BetweenExpression' ||
280
+ termType === 'ArithmeticExpression'
281
+ ) {
282
+ return term as ExpressionNode;
283
+ }
284
+ return buildColumnNode(tableRef, term as ColumnDef);
285
+ }
286
+
287
+ }