metal-orm 1.1.10 → 1.1.16

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 (192) hide show
  1. package/README.md +758 -769
  2. package/dist/index.cjs +106 -43
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +5 -5
  5. package/dist/index.d.ts +5 -5
  6. package/dist/index.js +106 -43
  7. package/dist/index.js.map +1 -1
  8. package/package.json +100 -96
  9. package/scripts/generate-entities/render.mjs +21 -12
  10. package/scripts/generate-entities/schema.mjs +209 -195
  11. package/scripts/generate-entities/tree-detection.mjs +159 -153
  12. package/scripts/inflection/pt-br.mjs +468 -468
  13. package/scripts/run-eslint.mjs +33 -34
  14. package/scripts/show-sql-seed.sql +102 -0
  15. package/scripts/show-sql.mjs +321 -325
  16. package/src/bulk/bulk-delete-executor.ts +3 -5
  17. package/src/bulk/bulk-insert-executor.ts +7 -7
  18. package/src/bulk/bulk-update-executor.ts +2 -2
  19. package/src/bulk/bulk-upsert-executor.ts +5 -7
  20. package/src/codegen/naming-strategy.ts +54 -54
  21. package/src/codegen/typescript.ts +482 -482
  22. package/src/core/ast/adapters.ts +1 -1
  23. package/src/core/ast/builders.ts +123 -123
  24. package/src/core/ast/expression-builders.ts +745 -745
  25. package/src/core/ast/expression-nodes.ts +304 -304
  26. package/src/core/ast/expression-visitor.ts +212 -212
  27. package/src/core/ast/expression.ts +20 -20
  28. package/src/core/ast/helpers.ts +14 -14
  29. package/src/core/ast/join.ts +18 -18
  30. package/src/core/ast/query.ts +200 -200
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
  35. package/src/core/ddl/dialects/render-reference.test.ts +70 -70
  36. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
  37. package/src/core/ddl/introspect/catalogs/index.ts +5 -5
  38. package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
  39. package/src/core/ddl/introspect/context.ts +15 -15
  40. package/src/core/ddl/introspect/functions/postgres.ts +35 -35
  41. package/src/core/ddl/introspect/mysql.ts +113 -36
  42. package/src/core/ddl/introspect/registry.ts +40 -40
  43. package/src/core/ddl/introspect/run-select.ts +35 -35
  44. package/src/core/ddl/introspect/utils.ts +56 -56
  45. package/src/core/ddl/naming-strategy.ts +16 -16
  46. package/src/core/ddl/schema-dialect.ts +56 -56
  47. package/src/core/ddl/schema-diff.ts +234 -234
  48. package/src/core/ddl/schema-generator.ts +1 -1
  49. package/src/core/ddl/schema-introspect.ts +25 -25
  50. package/src/core/ddl/sql-writing.ts +171 -171
  51. package/src/core/dialect/abstract.ts +541 -541
  52. package/src/core/dialect/base/cte-compiler.ts +33 -33
  53. package/src/core/dialect/base/function-table-formatter.ts +103 -103
  54. package/src/core/dialect/base/groupby-compiler.ts +21 -21
  55. package/src/core/dialect/base/join-compiler.ts +25 -25
  56. package/src/core/dialect/base/orderby-compiler.ts +35 -35
  57. package/src/core/dialect/base/pagination-strategy.ts +32 -32
  58. package/src/core/dialect/base/returning-strategy.ts +57 -57
  59. package/src/core/dialect/base/sql-dialect.ts +294 -294
  60. package/src/core/dialect/dialect-factory.ts +91 -91
  61. package/src/core/dialect/mssql/functions.ts +120 -120
  62. package/src/core/dialect/mssql/index.ts +317 -317
  63. package/src/core/dialect/mysql/functions.ts +103 -103
  64. package/src/core/dialect/mysql/index.ts +105 -105
  65. package/src/core/dialect/postgres/functions.ts +108 -108
  66. package/src/core/dialect/postgres/index.ts +91 -91
  67. package/src/core/dialect/sqlite/functions.ts +129 -129
  68. package/src/core/dialect/sqlite/index.ts +67 -67
  69. package/src/core/driver/database-driver.ts +19 -19
  70. package/src/core/driver/mssql-driver.ts +23 -23
  71. package/src/core/driver/mysql-driver.ts +23 -23
  72. package/src/core/driver/postgres-driver.ts +23 -23
  73. package/src/core/driver/sqlite-driver.ts +23 -23
  74. package/src/core/execution/db-executor.ts +92 -92
  75. package/src/core/execution/executors/better-sqlite3-executor.ts +94 -94
  76. package/src/core/execution/executors/mssql-executor.ts +184 -184
  77. package/src/core/execution/executors/mysql-executor.ts +88 -88
  78. package/src/core/execution/executors/postgres-executor.ts +26 -26
  79. package/src/core/execution/executors/sqlite-executor.ts +42 -42
  80. package/src/core/execution/pooling/pool-types.ts +30 -30
  81. package/src/core/execution/pooling/pool.ts +275 -275
  82. package/src/core/functions/array.ts +35 -35
  83. package/src/core/functions/control-flow.ts +79 -79
  84. package/src/core/functions/datetime.ts +237 -237
  85. package/src/core/functions/json.ts +70 -70
  86. package/src/core/functions/numeric.ts +297 -297
  87. package/src/core/functions/text.ts +334 -334
  88. package/src/core/functions/types.ts +33 -33
  89. package/src/core/hydration/types.ts +51 -51
  90. package/src/core/sql/sql-operator-config.ts +39 -39
  91. package/src/core/sql/sql.ts +152 -152
  92. package/src/decorators/column-decorator.ts +87 -87
  93. package/src/decorators/decorator-metadata.ts +143 -143
  94. package/src/decorators/entity.ts +93 -93
  95. package/src/decorators/index.ts +39 -39
  96. package/src/decorators/relations.ts +231 -231
  97. package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
  98. package/src/decorators/transformers/transformer-decorators.ts +134 -134
  99. package/src/decorators/transformers/transformer-executor.ts +171 -171
  100. package/src/decorators/transformers/transformer-metadata.ts +73 -73
  101. package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
  102. package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
  103. package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
  104. package/src/decorators/validators/country-validator-registry.ts +64 -64
  105. package/src/decorators/validators/country-validators-decorators.ts +203 -203
  106. package/src/decorators/validators/country-validators.ts +105 -105
  107. package/src/decorators/validators/validator-metadata.ts +59 -59
  108. package/src/dto/dto-types.ts +226 -226
  109. package/src/dto/filter-types.ts +141 -141
  110. package/src/dto/index.ts +95 -95
  111. package/src/dto/openapi/generators/base.ts +29 -29
  112. package/src/dto/openapi/generators/column.ts +37 -37
  113. package/src/dto/openapi/generators/dto.ts +91 -91
  114. package/src/dto/openapi/generators/filter.ts +75 -75
  115. package/src/dto/openapi/generators/nested-dto.ts +618 -618
  116. package/src/dto/openapi/generators/pagination.ts +111 -111
  117. package/src/dto/openapi/generators/relation-filter.ts +228 -228
  118. package/src/dto/openapi/index.ts +12 -12
  119. package/src/dto/openapi/types.ts +101 -101
  120. package/src/dto/openapi/utilities.ts +95 -95
  121. package/src/dto/pagination-utils.ts +150 -150
  122. package/src/dto/transform.ts +197 -197
  123. package/src/index.ts +86 -86
  124. package/src/orm/als.ts +58 -58
  125. package/src/orm/domain-event-bus.ts +119 -119
  126. package/src/orm/entity-context.ts +86 -86
  127. package/src/orm/entity-materializer.ts +159 -159
  128. package/src/orm/entity-meta.ts +97 -97
  129. package/src/orm/entity-registry.ts +39 -39
  130. package/src/orm/entity-relation-cache.ts +39 -39
  131. package/src/orm/execute.ts +194 -194
  132. package/src/orm/execution-context.ts +18 -18
  133. package/src/orm/hydration-context.ts +26 -26
  134. package/src/orm/hydration.ts +112 -112
  135. package/src/orm/identity-map.ts +61 -61
  136. package/src/orm/interceptor-pipeline.ts +16 -16
  137. package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
  138. package/src/orm/lazy-batch/belongs-to.ts +108 -108
  139. package/src/orm/lazy-batch/has-many.ts +69 -69
  140. package/src/orm/lazy-batch/has-one.ts +68 -68
  141. package/src/orm/lazy-batch/shared.ts +125 -125
  142. package/src/orm/orm-session.ts +620 -620
  143. package/src/orm/orm.ts +34 -34
  144. package/src/orm/pooled-executor-factory.ts +121 -121
  145. package/src/orm/query-logger.ts +40 -40
  146. package/src/orm/relation-change-processor.ts +420 -420
  147. package/src/orm/relations/belongs-to.ts +143 -143
  148. package/src/orm/relations/has-many.ts +204 -204
  149. package/src/orm/relations/has-one.ts +174 -174
  150. package/src/orm/relations/many-to-many.ts +288 -288
  151. package/src/orm/relations/morph-many.ts +156 -156
  152. package/src/orm/relations/morph-one.ts +151 -151
  153. package/src/orm/relations/morph-to.ts +162 -162
  154. package/src/orm/runtime-types.ts +92 -92
  155. package/src/orm/save-graph.ts +561 -561
  156. package/src/orm/transaction-runner.ts +24 -24
  157. package/src/orm/unit-of-work.ts +426 -426
  158. package/src/query/index.ts +69 -69
  159. package/src/query/target.ts +46 -46
  160. package/src/query-builder/column-selector.ts +81 -81
  161. package/src/query-builder/delete.ts +141 -141
  162. package/src/query-builder/insert-query-state.ts +149 -149
  163. package/src/query-builder/insert.ts +117 -117
  164. package/src/query-builder/query-ast-service.ts +287 -287
  165. package/src/query-builder/query-resolution.ts +78 -78
  166. package/src/query-builder/raw-column-parser.ts +38 -38
  167. package/src/query-builder/relation-filter-utils.ts +153 -153
  168. package/src/query-builder/relation-join-planner.ts +10 -10
  169. package/src/query-builder/relation-manager.ts +87 -87
  170. package/src/query-builder/relation-projection-helper.ts +102 -102
  171. package/src/query-builder/relation-types.ts +9 -9
  172. package/src/query-builder/relation-utils.ts +15 -15
  173. package/src/query-builder/select/cte-facet.ts +40 -40
  174. package/src/query-builder/select/from-facet.ts +80 -80
  175. package/src/query-builder/select/join-facet.ts +62 -62
  176. package/src/query-builder/select/predicate-facet.ts +104 -104
  177. package/src/query-builder/select/projection-facet.ts +70 -70
  178. package/src/query-builder/select/relation-facet.ts +81 -81
  179. package/src/query-builder/select/setop-facet.ts +36 -36
  180. package/src/query-builder/select-helpers.ts +1 -1
  181. package/src/query-builder/select-query-builder-deps.ts +130 -130
  182. package/src/query-builder/select-query-state.ts +207 -207
  183. package/src/query-builder/update.ts +151 -151
  184. package/src/schema/column-types.ts +322 -322
  185. package/src/schema/table-guards.ts +37 -37
  186. package/src/schema/table.ts +281 -281
  187. package/src/tree/index.ts +13 -13
  188. package/src/tree/nested-set-strategy.ts +545 -545
  189. package/src/tree/tree-decorator.ts +397 -397
  190. package/src/tree/tree-manager.ts +754 -754
  191. package/src/tree/tree-query.ts +427 -427
  192. 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
+ }