metal-orm 1.0.88 → 1.0.90

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 (49) hide show
  1. package/dist/index.cjs +3818 -3783
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +765 -236
  4. package/dist/index.d.ts +765 -236
  5. package/dist/index.js +3763 -3775
  6. package/dist/index.js.map +1 -1
  7. package/package.json +3 -2
  8. package/src/codegen/typescript.ts +29 -40
  9. package/src/core/ast/expression-builders.ts +34 -53
  10. package/src/core/ast/expression-nodes.ts +51 -72
  11. package/src/core/ast/expression-visitor.ts +219 -252
  12. package/src/core/ast/expression.ts +20 -21
  13. package/src/core/dialect/abstract.ts +55 -81
  14. package/src/core/execution/db-executor.ts +4 -5
  15. package/src/core/execution/executors/mysql-executor.ts +7 -9
  16. package/src/decorators/bootstrap.ts +11 -8
  17. package/src/dto/apply-filter.ts +281 -0
  18. package/src/dto/dto-types.ts +229 -0
  19. package/src/dto/filter-types.ts +193 -0
  20. package/src/dto/index.ts +97 -0
  21. package/src/dto/openapi/generators/base.ts +29 -0
  22. package/src/dto/openapi/generators/column.ts +34 -0
  23. package/src/dto/openapi/generators/dto.ts +94 -0
  24. package/src/dto/openapi/generators/filter.ts +74 -0
  25. package/src/dto/openapi/generators/nested-dto.ts +532 -0
  26. package/src/dto/openapi/generators/pagination.ts +111 -0
  27. package/src/dto/openapi/generators/relation-filter.ts +210 -0
  28. package/src/dto/openapi/index.ts +17 -0
  29. package/src/dto/openapi/type-mappings.ts +191 -0
  30. package/src/dto/openapi/types.ts +83 -0
  31. package/src/dto/openapi/utilities.ts +45 -0
  32. package/src/dto/pagination-utils.ts +150 -0
  33. package/src/dto/transform.ts +193 -0
  34. package/src/index.ts +67 -65
  35. package/src/orm/unit-of-work.ts +13 -25
  36. package/src/query-builder/query-ast-service.ts +287 -300
  37. package/src/query-builder/relation-filter-utils.ts +159 -160
  38. package/src/query-builder/select.ts +137 -192
  39. package/src/core/ast/ast-validation.ts +0 -19
  40. package/src/core/ast/param-proxy.ts +0 -47
  41. package/src/core/ast/query-visitor.ts +0 -273
  42. package/src/openapi/index.ts +0 -4
  43. package/src/openapi/query-parameters.ts +0 -207
  44. package/src/openapi/schema-extractor-input.ts +0 -139
  45. package/src/openapi/schema-extractor-output.ts +0 -427
  46. package/src/openapi/schema-extractor-utils.ts +0 -110
  47. package/src/openapi/schema-extractor.ts +0 -111
  48. package/src/openapi/schema-types.ts +0 -176
  49. package/src/openapi/type-mappers.ts +0 -227
@@ -1,252 +1,219 @@
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
- CastExpressionNode,
18
- WindowFunctionNode,
19
- CollateExpressionNode,
20
- AliasRefNode,
21
- BitwiseExpressionNode,
22
- ParamNode
23
- } from './expression-nodes.js';
24
- import type { SelectQueryNode } from './query.js';
25
-
26
- /**
27
- * Visitor for expression nodes
28
- */
29
- export interface ExpressionVisitor<R> {
30
- visitBinaryExpression?(node: BinaryExpressionNode): R;
31
- visitLogicalExpression?(node: LogicalExpressionNode): R;
32
- visitNullExpression?(node: NullExpressionNode): R;
33
- visitInExpression?(node: InExpressionNode): R;
34
- visitExistsExpression?(node: ExistsExpressionNode): R;
35
- visitBetweenExpression?(node: BetweenExpressionNode): R;
36
- visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
37
- visitBitwiseExpression?(node: BitwiseExpressionNode): R;
38
- visitOperand?(node: OperandNode): R;
39
- visitSelectQuery?(node: SelectQueryNode): R;
40
- otherwise?(node: ExpressionNode): R;
41
- }
42
-
43
- /**
44
- * Visitor for operand nodes
45
- */
46
- export interface OperandVisitor<R> {
47
- visitColumn?(node: ColumnNode): R;
48
- visitLiteral?(node: LiteralNode): R;
49
- visitParam?(node: ParamNode): R;
50
- visitFunction?(node: FunctionNode): R;
51
- visitJsonPath?(node: JsonPathNode): R;
52
- visitScalarSubquery?(node: ScalarSubqueryNode): R;
53
- visitCaseExpression?(node: CaseExpressionNode): R;
54
- visitCast?(node: CastExpressionNode): R;
55
- visitWindowFunction?(node: WindowFunctionNode): R;
56
- visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
57
- visitBitwiseExpression?(node: BitwiseExpressionNode): R;
58
- visitExpression?(node: ExpressionNode): R;
59
- visitSelectQuery?(node: SelectQueryNode): R;
60
- visitCollate?(node: CollateExpressionNode): R;
61
- visitAliasRef?(node: AliasRefNode): R;
62
- otherwise?(node: OperandNode): R;
63
- }
64
-
65
- type ExpressionDispatch = <R>(node: ExpressionNode, visitor: ExpressionVisitor<R>) => R;
66
- type OperandDispatch = <R>(node: OperandNode, visitor: OperandVisitor<R>) => R;
67
-
68
- /**
69
- * Registry class for managing dispatchers in an immutable way
70
- */
71
- class DispatcherRegistry<T> {
72
- private readonly dispatchers: ReadonlyMap<string, T>;
73
-
74
- constructor(dispatchers: Map<string, T> = new Map()) {
75
- this.dispatchers = dispatchers;
76
- }
77
-
78
- /**
79
- * Registers a new dispatcher and returns a new registry instance
80
- */
81
- register(type: string, dispatcher: T): DispatcherRegistry<T> {
82
- const newMap = new Map(this.dispatchers);
83
- newMap.set(type, dispatcher);
84
- return new DispatcherRegistry(newMap);
85
- }
86
-
87
- /**
88
- * Gets a dispatcher for the given type
89
- */
90
- get(type: string): T | undefined {
91
- return this.dispatchers.get(type);
92
- }
93
-
94
- /**
95
- * Returns a new empty registry
96
- */
97
- clear(): DispatcherRegistry<T> {
98
- return new DispatcherRegistry();
99
- }
100
- }
101
-
102
- let expressionRegistry = new DispatcherRegistry<ExpressionDispatch>();
103
- let operandRegistry = new DispatcherRegistry<OperandDispatch>();
104
-
105
- /**
106
- * Registers a dispatcher for a custom expression node type.
107
- * Allows new node kinds without modifying the core switch.
108
- */
109
- export const registerExpressionDispatcher = (type: string, dispatcher: ExpressionDispatch): void => {
110
- expressionRegistry = expressionRegistry.register(type, dispatcher);
111
- };
112
-
113
- /**
114
- * Registers a dispatcher for a custom operand node type.
115
- * Allows new node kinds without modifying the core switch.
116
- */
117
- export const registerOperandDispatcher = (type: string, dispatcher: OperandDispatch): void => {
118
- operandRegistry = operandRegistry.register(type, dispatcher);
119
- };
120
-
121
- export const hasExpressionDispatcher = (type: string): boolean =>
122
- expressionRegistry.get(type) !== undefined;
123
-
124
- export const hasOperandDispatcher = (type: string): boolean =>
125
- operandRegistry.get(type) !== undefined;
126
-
127
- /**
128
- * Clears all registered dispatchers. Primarily for tests.
129
- */
130
- export const clearExpressionDispatchers = (): void => {
131
- expressionRegistry = expressionRegistry.clear();
132
- };
133
-
134
- export const clearOperandDispatchers = (): void => {
135
- operandRegistry = operandRegistry.clear();
136
- };
137
-
138
- const getNodeType = (node: { type?: string } | null | undefined): string | undefined => {
139
- if (typeof node !== 'object' || node === null) return undefined;
140
- const descriptor = Object.getOwnPropertyDescriptor(node, 'type');
141
- if (descriptor && typeof descriptor.value === 'string') {
142
- return descriptor.value;
143
- }
144
- const type = node.type;
145
- return typeof type === 'string' ? type : undefined;
146
- };
147
-
148
- const unsupportedExpression = (node: ExpressionNode): never => {
149
- throw new Error(`Unsupported expression type "${getNodeType(node) ?? 'unknown'}"`);
150
- };
151
-
152
- const unsupportedOperand = (node: OperandNode): never => {
153
- throw new Error(`Unsupported operand type "${getNodeType(node) ?? 'unknown'}"`);
154
- };
155
- /**
156
- * Dispatches an expression node to the visitor
157
- * @param node - Expression node to visit
158
- * @param visitor - Visitor implementation
159
- */
160
- export const visitExpression = <R>(node: ExpressionNode, visitor: ExpressionVisitor<R>): R => {
161
- const type = getNodeType(node);
162
- const dynamic = type ? expressionRegistry.get(type) : undefined;
163
- if (dynamic) return dynamic(node, visitor);
164
-
165
- switch (type) {
166
- case 'BinaryExpression':
167
- if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node as BinaryExpressionNode);
168
- break;
169
- case 'LogicalExpression':
170
- if (visitor.visitLogicalExpression) return visitor.visitLogicalExpression(node as LogicalExpressionNode);
171
- break;
172
- case 'NullExpression':
173
- if (visitor.visitNullExpression) return visitor.visitNullExpression(node as NullExpressionNode);
174
- break;
175
- case 'InExpression':
176
- if (visitor.visitInExpression) return visitor.visitInExpression(node as InExpressionNode);
177
- break;
178
- case 'ExistsExpression':
179
- if (visitor.visitExistsExpression) return visitor.visitExistsExpression(node as ExistsExpressionNode);
180
- break;
181
- case 'BetweenExpression':
182
- if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node as BetweenExpressionNode);
183
- break;
184
- case 'ArithmeticExpression':
185
- if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node as ArithmeticExpressionNode);
186
- break;
187
- case 'BitwiseExpression':
188
- if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node as BitwiseExpressionNode);
189
- break;
190
- default:
191
- break;
192
- }
193
- if (visitor.otherwise) return visitor.otherwise(node);
194
- return unsupportedExpression(node);
195
- };
196
-
197
- /**
198
- * Dispatches an operand node to the visitor
199
- * @param node - Operand node to visit
200
- * @param visitor - Visitor implementation
201
- */
202
- export const visitOperand = <R>(node: OperandNode, visitor: OperandVisitor<R>): R => {
203
- const type = getNodeType(node);
204
- const dynamic = type ? operandRegistry.get(type) : undefined;
205
- if (dynamic) return dynamic(node, visitor);
206
-
207
- switch (type) {
208
- case 'Column':
209
- if (visitor.visitColumn) return visitor.visitColumn(node as ColumnNode);
210
- break;
211
- case 'Literal':
212
- if (visitor.visitLiteral) return visitor.visitLiteral(node as LiteralNode);
213
- break;
214
- case 'Param':
215
- if (visitor.visitParam) return visitor.visitParam(node as ParamNode);
216
- break;
217
- case 'Function':
218
- if (visitor.visitFunction) return visitor.visitFunction(node as FunctionNode);
219
- break;
220
- case 'JsonPath':
221
- if (visitor.visitJsonPath) return visitor.visitJsonPath(node as JsonPathNode);
222
- break;
223
- case 'ScalarSubquery':
224
- if (visitor.visitScalarSubquery) return visitor.visitScalarSubquery(node as ScalarSubqueryNode);
225
- break;
226
- case 'CaseExpression':
227
- if (visitor.visitCaseExpression) return visitor.visitCaseExpression(node as CaseExpressionNode);
228
- break;
229
- case 'WindowFunction':
230
- if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node as WindowFunctionNode);
231
- break;
232
- case 'AliasRef':
233
- if (visitor.visitAliasRef) return visitor.visitAliasRef(node as AliasRefNode);
234
- break;
235
- case 'Cast':
236
- if (visitor.visitCast) return visitor.visitCast(node as CastExpressionNode);
237
- break;
238
- case 'Collate':
239
- if (visitor.visitCollate) return visitor.visitCollate(node as CollateExpressionNode);
240
- break;
241
- case 'ArithmeticExpression':
242
- if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node as ArithmeticExpressionNode);
243
- break;
244
- case 'BitwiseExpression':
245
- if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node as BitwiseExpressionNode);
246
- break;
247
- default:
248
- break;
249
- }
250
- if (visitor.otherwise) return visitor.otherwise(node);
251
- return unsupportedOperand(node);
252
- };
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
+ CastExpressionNode,
18
+ WindowFunctionNode,
19
+ CollateExpressionNode,
20
+ AliasRefNode,
21
+ BitwiseExpressionNode
22
+ } from './expression-nodes.js';
23
+
24
+ /**
25
+ * Visitor for expression nodes
26
+ */
27
+ export interface ExpressionVisitor<R> {
28
+ visitBinaryExpression?(node: BinaryExpressionNode): R;
29
+ visitLogicalExpression?(node: LogicalExpressionNode): R;
30
+ visitNullExpression?(node: NullExpressionNode): R;
31
+ visitInExpression?(node: InExpressionNode): R;
32
+ visitExistsExpression?(node: ExistsExpressionNode): R;
33
+ visitBetweenExpression?(node: BetweenExpressionNode): R;
34
+ visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
35
+ visitBitwiseExpression?(node: BitwiseExpressionNode): R;
36
+ otherwise?(node: ExpressionNode): R;
37
+ }
38
+
39
+ /**
40
+ * Visitor for operand nodes
41
+ */
42
+ export interface OperandVisitor<R> {
43
+ visitColumn?(node: ColumnNode): R;
44
+ visitLiteral?(node: LiteralNode): R;
45
+ visitFunction?(node: FunctionNode): R;
46
+ visitJsonPath?(node: JsonPathNode): R;
47
+ visitScalarSubquery?(node: ScalarSubqueryNode): R;
48
+ visitCaseExpression?(node: CaseExpressionNode): R;
49
+ visitCast?(node: CastExpressionNode): R;
50
+ visitWindowFunction?(node: WindowFunctionNode): R;
51
+ visitCollate?(node: CollateExpressionNode): R;
52
+ visitAliasRef?(node: AliasRefNode): R;
53
+ otherwise?(node: OperandNode): R;
54
+ }
55
+
56
+ type ExpressionDispatch = <R>(node: ExpressionNode, visitor: ExpressionVisitor<R>) => R;
57
+ type OperandDispatch = <R>(node: OperandNode, visitor: OperandVisitor<R>) => R;
58
+
59
+ /**
60
+ * Registry class for managing dispatchers in an immutable way
61
+ */
62
+ class DispatcherRegistry<T> {
63
+ private readonly dispatchers: ReadonlyMap<string, T>;
64
+
65
+ constructor(dispatchers: Map<string, T> = new Map()) {
66
+ this.dispatchers = dispatchers;
67
+ }
68
+
69
+ /**
70
+ * Registers a new dispatcher and returns a new registry instance
71
+ */
72
+ register(type: string, dispatcher: T): DispatcherRegistry<T> {
73
+ const newMap = new Map(this.dispatchers);
74
+ newMap.set(type, dispatcher);
75
+ return new DispatcherRegistry(newMap);
76
+ }
77
+
78
+ /**
79
+ * Gets a dispatcher for the given type
80
+ */
81
+ get(type: string): T | undefined {
82
+ return this.dispatchers.get(type);
83
+ }
84
+
85
+ /**
86
+ * Returns a new empty registry
87
+ */
88
+ clear(): DispatcherRegistry<T> {
89
+ return new DispatcherRegistry();
90
+ }
91
+ }
92
+
93
+ let expressionRegistry = new DispatcherRegistry<ExpressionDispatch>();
94
+ let operandRegistry = new DispatcherRegistry<OperandDispatch>();
95
+
96
+ /**
97
+ * Registers a dispatcher for a custom expression node type.
98
+ * Allows new node kinds without modifying the core switch.
99
+ */
100
+ export const registerExpressionDispatcher = (type: string, dispatcher: ExpressionDispatch): void => {
101
+ expressionRegistry = expressionRegistry.register(type, dispatcher);
102
+ };
103
+
104
+ /**
105
+ * Registers a dispatcher for a custom operand node type.
106
+ * Allows new node kinds without modifying the core switch.
107
+ */
108
+ export const registerOperandDispatcher = (type: string, dispatcher: OperandDispatch): void => {
109
+ operandRegistry = operandRegistry.register(type, dispatcher);
110
+ };
111
+
112
+ /**
113
+ * Clears all registered dispatchers. Primarily for tests.
114
+ */
115
+ export const clearExpressionDispatchers = (): void => {
116
+ expressionRegistry = expressionRegistry.clear();
117
+ };
118
+
119
+ export const clearOperandDispatchers = (): void => {
120
+ operandRegistry = operandRegistry.clear();
121
+ };
122
+
123
+ const getNodeType = (node: { type?: string } | null | undefined): string | undefined =>
124
+ typeof node === 'object' && node !== null && typeof node.type === 'string' ? node.type : undefined;
125
+
126
+ const unsupportedExpression = (node: ExpressionNode): never => {
127
+ throw new Error(`Unsupported expression type "${getNodeType(node) ?? 'unknown'}"`);
128
+ };
129
+
130
+ const unsupportedOperand = (node: OperandNode): never => {
131
+ throw new Error(`Unsupported operand type "${getNodeType(node) ?? 'unknown'}"`);
132
+ };
133
+ /**
134
+ * Dispatches an expression node to the visitor
135
+ * @param node - Expression node to visit
136
+ * @param visitor - Visitor implementation
137
+ */
138
+ export const visitExpression = <R>(node: ExpressionNode, visitor: ExpressionVisitor<R>): R => {
139
+ const dynamic = expressionRegistry.get(node.type);
140
+ if (dynamic) return dynamic(node, visitor);
141
+
142
+ switch (node.type) {
143
+ case 'BinaryExpression':
144
+ if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node);
145
+ break;
146
+ case 'LogicalExpression':
147
+ if (visitor.visitLogicalExpression) return visitor.visitLogicalExpression(node);
148
+ break;
149
+ case 'NullExpression':
150
+ if (visitor.visitNullExpression) return visitor.visitNullExpression(node);
151
+ break;
152
+ case 'InExpression':
153
+ if (visitor.visitInExpression) return visitor.visitInExpression(node);
154
+ break;
155
+ case 'ExistsExpression':
156
+ if (visitor.visitExistsExpression) return visitor.visitExistsExpression(node);
157
+ break;
158
+ case 'BetweenExpression':
159
+ if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node);
160
+ break;
161
+ case 'ArithmeticExpression':
162
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
163
+ break;
164
+ case 'BitwiseExpression':
165
+ if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node);
166
+ break;
167
+ default:
168
+ break;
169
+ }
170
+ if (visitor.otherwise) return visitor.otherwise(node);
171
+ return unsupportedExpression(node);
172
+ };
173
+
174
+ /**
175
+ * Dispatches an operand node to the visitor
176
+ * @param node - Operand node to visit
177
+ * @param visitor - Visitor implementation
178
+ */
179
+ export const visitOperand = <R>(node: OperandNode, visitor: OperandVisitor<R>): R => {
180
+ const dynamic = operandRegistry.get(node.type);
181
+ if (dynamic) return dynamic(node, visitor);
182
+
183
+ switch (node.type) {
184
+ case 'Column':
185
+ if (visitor.visitColumn) return visitor.visitColumn(node);
186
+ break;
187
+ case 'Literal':
188
+ if (visitor.visitLiteral) return visitor.visitLiteral(node);
189
+ break;
190
+ case 'Function':
191
+ if (visitor.visitFunction) return visitor.visitFunction(node);
192
+ break;
193
+ case 'JsonPath':
194
+ if (visitor.visitJsonPath) return visitor.visitJsonPath(node);
195
+ break;
196
+ case 'ScalarSubquery':
197
+ if (visitor.visitScalarSubquery) return visitor.visitScalarSubquery(node);
198
+ break;
199
+ case 'CaseExpression':
200
+ if (visitor.visitCaseExpression) return visitor.visitCaseExpression(node);
201
+ break;
202
+ case 'WindowFunction':
203
+ if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node);
204
+ break;
205
+ case 'AliasRef':
206
+ if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
207
+ break;
208
+ case 'Cast':
209
+ if (visitor.visitCast) return visitor.visitCast(node);
210
+ break;
211
+ case 'Collate':
212
+ if (visitor.visitCollate) return visitor.visitCollate(node);
213
+ break;
214
+ default:
215
+ break;
216
+ }
217
+ if (visitor.otherwise) return visitor.otherwise(node);
218
+ return unsupportedOperand(node);
219
+ };
@@ -1,21 +1,20 @@
1
- /**
2
- * Expression AST nodes and builders.
3
- * Re-exports components for building and visiting SQL expression trees.
4
- */
5
- import type { CaseExpressionNode, FunctionNode, WindowFunctionNode } from './expression-nodes.js';
6
-
7
- export * from './expression-nodes.js';
8
- export * from './expression-builders.js';
9
- export * from './window-functions.js';
10
- export * from './aggregate-functions.js';
11
- export * from './expression-visitor.js';
12
- export * from './param-proxy.js';
13
- export type { ColumnRef, TableRef as AstTableRef } from './types.js';
14
- export * from './adapters.js';
15
-
16
- export type TypedExpression<T> =
17
- (FunctionNode | CaseExpressionNode | WindowFunctionNode) & { __tsType: T };
18
-
19
- export const asType = <T>(
20
- expr: FunctionNode | CaseExpressionNode | WindowFunctionNode
21
- ): TypedExpression<T> => expr as TypedExpression<T>;
1
+ /**
2
+ * Expression AST nodes and builders.
3
+ * Re-exports components for building and visiting SQL expression trees.
4
+ */
5
+ import type { CaseExpressionNode, FunctionNode, WindowFunctionNode } from './expression-nodes.js';
6
+
7
+ export * from './expression-nodes.js';
8
+ export * from './expression-builders.js';
9
+ export * from './window-functions.js';
10
+ export * from './aggregate-functions.js';
11
+ export * from './expression-visitor.js';
12
+ export type { ColumnRef, TableRef as AstTableRef } from './types.js';
13
+ export * from './adapters.js';
14
+
15
+ export type TypedExpression<T> =
16
+ (FunctionNode | CaseExpressionNode | WindowFunctionNode) & { __tsType: T };
17
+
18
+ export const asType = <T>(
19
+ expr: FunctionNode | CaseExpressionNode | WindowFunctionNode
20
+ ): TypedExpression<T> => expr as TypedExpression<T>;