metal-orm 1.0.89 → 1.0.91
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.
- package/dist/index.cjs +2968 -2983
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +784 -251
- package/dist/index.d.ts +784 -251
- package/dist/index.js +2913 -2975
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/src/codegen/typescript.ts +29 -40
- package/src/core/ast/expression-builders.ts +34 -53
- package/src/core/ast/expression-nodes.ts +51 -72
- package/src/core/ast/expression-visitor.ts +219 -252
- package/src/core/ast/expression.ts +20 -21
- package/src/core/ddl/introspect/utils.ts +45 -45
- package/src/core/dialect/abstract.ts +55 -81
- package/src/core/execution/db-executor.ts +4 -5
- package/src/core/execution/executors/mysql-executor.ts +7 -9
- package/src/decorators/bootstrap.ts +29 -26
- package/src/dto/apply-filter.ts +279 -0
- package/src/dto/dto-types.ts +229 -0
- package/src/dto/filter-types.ts +193 -0
- package/src/dto/index.ts +97 -0
- package/src/dto/openapi/generators/base.ts +29 -0
- package/src/dto/openapi/generators/column.ts +34 -0
- package/src/dto/openapi/generators/dto.ts +94 -0
- package/src/dto/openapi/generators/filter.ts +74 -0
- package/src/dto/openapi/generators/nested-dto.ts +532 -0
- package/src/dto/openapi/generators/pagination.ts +111 -0
- package/src/dto/openapi/generators/relation-filter.ts +210 -0
- package/src/dto/openapi/index.ts +17 -0
- package/src/dto/openapi/type-mappings.ts +191 -0
- package/src/dto/openapi/types.ts +90 -0
- package/src/dto/openapi/utilities.ts +45 -0
- package/src/dto/pagination-utils.ts +150 -0
- package/src/dto/transform.ts +197 -0
- package/src/index.ts +5 -3
- package/src/orm/entity-context.ts +9 -9
- package/src/orm/entity.ts +74 -74
- package/src/orm/orm-session.ts +159 -159
- package/src/orm/relation-change-processor.ts +3 -3
- package/src/orm/runtime-types.ts +5 -5
- package/src/orm/unit-of-work.ts +13 -25
- package/src/query-builder/query-ast-service.ts +287 -300
- package/src/query-builder/relation-filter-utils.ts +159 -160
- package/src/query-builder/select.ts +137 -192
- package/src/schema/column-types.ts +4 -4
- package/src/schema/types.ts +5 -1
- package/src/core/ast/ast-validation.ts +0 -19
- package/src/core/ast/param-proxy.ts +0 -47
- package/src/core/ast/query-visitor.ts +0 -273
- package/src/openapi/index.ts +0 -4
- package/src/openapi/query-parameters.ts +0 -207
- package/src/openapi/schema-extractor-input.ts +0 -193
- package/src/openapi/schema-extractor-output.ts +0 -427
- package/src/openapi/schema-extractor-utils.ts +0 -110
- package/src/openapi/schema-extractor.ts +0 -120
- package/src/openapi/schema-types.ts +0 -187
- package/src/openapi/type-mappers.ts +0 -227
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metal-orm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.91",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"engines": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"test": "vitest",
|
|
31
31
|
"test:ui": "vitest --ui",
|
|
32
32
|
"test:mysql": "vitest --run tests/e2e/mysql-memory.test.ts tests/e2e/decorators-mysql-memory.test.ts tests/e2e/save-graph-mysql-memory.test.ts",
|
|
33
|
+
"test:mysql:optimized": "vitest --run --config tests/e2e/mysql/vitest.config.ts",
|
|
33
34
|
"test:sqlite": "vitest --run tests/e2e/sqlite-memory.test.ts tests/e2e/decorators-sqlite-memory.test.ts tests/e2e/save-graph-sqlite-memory.test.ts",
|
|
34
35
|
"test:pglite": "vitest --run tests/e2e/pglite-memory.test.ts",
|
|
35
36
|
"test:e2e": "vitest tests/e2e",
|
|
@@ -58,8 +59,6 @@
|
|
|
58
59
|
}
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@electric-sql/pglite": "^0.3.14",
|
|
62
|
-
"@types/express": "^5.0.6",
|
|
63
62
|
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
|
64
63
|
"@typescript-eslint/parser": "^8.20.0",
|
|
65
64
|
"@vitest/ui": "^4.0.14",
|
|
@@ -70,9 +69,13 @@
|
|
|
70
69
|
"mysql2": "^3.15.3",
|
|
71
70
|
"pg": "^8.16.3",
|
|
72
71
|
"sqlite3": "^5.1.7",
|
|
72
|
+
"supertest": "^7.2.2",
|
|
73
73
|
"tedious": "^19.1.3",
|
|
74
74
|
"tsup": "^8.0.0",
|
|
75
75
|
"typescript": "^5.5.0",
|
|
76
76
|
"vitest": "^4.0.14"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@electric-sql/pglite": "^0.3.14"
|
|
77
80
|
}
|
|
78
81
|
}
|
|
@@ -17,14 +17,13 @@ import {
|
|
|
17
17
|
LiteralNode,
|
|
18
18
|
FunctionNode,
|
|
19
19
|
AliasRefNode,
|
|
20
|
-
CastExpressionNode,
|
|
21
|
-
CollateExpressionNode,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from '../core/ast/expression.js';
|
|
20
|
+
CastExpressionNode,
|
|
21
|
+
CollateExpressionNode,
|
|
22
|
+
ExpressionVisitor,
|
|
23
|
+
OperandVisitor,
|
|
24
|
+
visitExpression,
|
|
25
|
+
visitOperand
|
|
26
|
+
} from '../core/ast/expression.js';
|
|
28
27
|
import { SQL_OPERATOR_REGISTRY } from '../core/sql/sql-operator-config.js';
|
|
29
28
|
import { SqlOperator } from '../core/sql/sql.js';
|
|
30
29
|
import { isRelationAlias } from '../query-builder/relation-alias.js';
|
|
@@ -191,14 +190,13 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
191
190
|
case 'ScalarSubquery':
|
|
192
191
|
case 'CaseExpression':
|
|
193
192
|
case 'WindowFunction':
|
|
194
|
-
case 'Cast':
|
|
195
|
-
case 'Collate':
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
193
|
+
case 'Cast':
|
|
194
|
+
case 'Collate':
|
|
195
|
+
return this.printOperand(term);
|
|
196
|
+
default:
|
|
197
|
+
return this.printExpression(term);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
202
200
|
|
|
203
201
|
private getSelectionKey(selection: SelectionColumn, index: number): string {
|
|
204
202
|
if (selection.alias) {
|
|
@@ -246,17 +244,13 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
246
244
|
return this.printColumnOperand(node);
|
|
247
245
|
}
|
|
248
246
|
|
|
249
|
-
public visitLiteral(node: LiteralNode): string {
|
|
250
|
-
return this.printLiteralOperand(node);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
public
|
|
254
|
-
return this.
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
public visitFunction(node: FunctionNode): string {
|
|
258
|
-
return this.printFunctionOperand(node);
|
|
259
|
-
}
|
|
247
|
+
public visitLiteral(node: LiteralNode): string {
|
|
248
|
+
return this.printLiteralOperand(node);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
public visitFunction(node: FunctionNode): string {
|
|
252
|
+
return this.printFunctionOperand(node);
|
|
253
|
+
}
|
|
260
254
|
|
|
261
255
|
public visitJsonPath(node: JsonPathNode): string {
|
|
262
256
|
return this.printJsonPathOperand(node);
|
|
@@ -385,19 +379,14 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
385
379
|
* @param literal - Literal node
|
|
386
380
|
* @returns TypeScript code representation
|
|
387
381
|
*/
|
|
388
|
-
private printLiteralOperand(literal: LiteralNode): string {
|
|
389
|
-
if (literal.value === null) return 'null';
|
|
390
|
-
return typeof literal.value === 'string' ? `'${literal.value}'` : String(literal.value);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Prints a function operand to TypeScript code
|
|
400
|
-
* @param fn - Function node
|
|
382
|
+
private printLiteralOperand(literal: LiteralNode): string {
|
|
383
|
+
if (literal.value === null) return 'null';
|
|
384
|
+
return typeof literal.value === 'string' ? `'${literal.value}'` : String(literal.value);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Prints a function operand to TypeScript code
|
|
389
|
+
* @param fn - Function node
|
|
401
390
|
* @returns TypeScript code representation
|
|
402
391
|
*/
|
|
403
392
|
private printFunctionOperand(fn: FunctionNode): string {
|
|
@@ -2,14 +2,13 @@ import { SelectQueryNode } from './query.js';
|
|
|
2
2
|
import { SqlOperator, BitwiseOperator } from '../sql/sql.js';
|
|
3
3
|
import { ColumnRef } from './types.js';
|
|
4
4
|
import {
|
|
5
|
-
ColumnNode,
|
|
6
|
-
LiteralNode,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
BinaryExpressionNode,
|
|
5
|
+
ColumnNode,
|
|
6
|
+
LiteralNode,
|
|
7
|
+
JsonPathNode,
|
|
8
|
+
OperandNode,
|
|
9
|
+
CaseExpressionNode,
|
|
10
|
+
CastExpressionNode,
|
|
11
|
+
BinaryExpressionNode,
|
|
13
12
|
ExpressionNode,
|
|
14
13
|
LogicalExpressionNode,
|
|
15
14
|
NullExpressionNode,
|
|
@@ -33,36 +32,27 @@ export type TypedLike<T> = { tsType?: T } | { __tsType: T };
|
|
|
33
32
|
/**
|
|
34
33
|
* Type guard to check if a value is a literal value
|
|
35
34
|
*/
|
|
36
|
-
const isLiteralValue = (value: unknown): value is LiteralValue =>
|
|
37
|
-
value === null ||
|
|
38
|
-
typeof value === 'string' ||
|
|
39
|
-
typeof value === 'number' ||
|
|
40
|
-
typeof value === 'boolean' ||
|
|
41
|
-
value instanceof Date;
|
|
35
|
+
const isLiteralValue = (value: unknown): value is LiteralValue =>
|
|
36
|
+
value === null ||
|
|
37
|
+
typeof value === 'string' ||
|
|
38
|
+
typeof value === 'number' ||
|
|
39
|
+
typeof value === 'boolean' ||
|
|
40
|
+
value instanceof Date;
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
44
|
* Converts a primitive value to a LiteralNode
|
|
46
45
|
*/
|
|
47
|
-
const toLiteralNode = (value: LiteralValue): LiteralNode => ({
|
|
48
|
-
type: 'Literal',
|
|
49
|
-
value: value instanceof Date ? value.toISOString() : value
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (typeof name !== 'string') return undefined;
|
|
58
|
-
return { type: 'Param', name };
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Converts a ColumnRef to a ColumnNode
|
|
63
|
-
* @throws Error if the ColumnRef doesn't have a table specified
|
|
64
|
-
*/
|
|
65
|
-
const columnRefToNode = (col: ColumnRef): ColumnNode => {
|
|
46
|
+
const toLiteralNode = (value: LiteralValue): LiteralNode => ({
|
|
47
|
+
type: 'Literal',
|
|
48
|
+
value: value instanceof Date ? value.toISOString() : value
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Converts a ColumnRef to a ColumnNode
|
|
53
|
+
* @throws Error if the ColumnRef doesn't have a table specified
|
|
54
|
+
*/
|
|
55
|
+
const columnRefToNode = (col: ColumnRef): ColumnNode => {
|
|
66
56
|
if (!col.table) {
|
|
67
57
|
throw new Error(
|
|
68
58
|
`Column "${col.name}" requires a table reference. ` +
|
|
@@ -77,16 +67,11 @@ const columnRefToNode = (col: ColumnRef): ColumnNode => {
|
|
|
77
67
|
* @param value - Value to convert (OperandNode, ColumnRef, or literal value)
|
|
78
68
|
* @returns OperandNode representing the value
|
|
79
69
|
*/
|
|
80
|
-
const toOperandNode = (value: OperandNode | ColumnRef | LiteralValue): OperandNode => {
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Already an operand node
|
|
87
|
-
if (isOperandNode(value)) {
|
|
88
|
-
return value;
|
|
89
|
-
}
|
|
70
|
+
const toOperandNode = (value: OperandNode | ColumnRef | LiteralValue): OperandNode => {
|
|
71
|
+
// Already an operand node
|
|
72
|
+
if (isOperandNode(value)) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
90
75
|
|
|
91
76
|
// Literal value
|
|
92
77
|
if (isLiteralValue(value)) {
|
|
@@ -102,16 +87,12 @@ const toOperandNode = (value: OperandNode | ColumnRef | LiteralValue): OperandNo
|
|
|
102
87
|
* @param value - Value or operand to normalize
|
|
103
88
|
* @returns OperandNode representing the value
|
|
104
89
|
*/
|
|
105
|
-
export const valueToOperand = (value: ValueOperandInput): OperandNode => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
return toLiteralNode(value);
|
|
114
|
-
};
|
|
90
|
+
export const valueToOperand = (value: ValueOperandInput): OperandNode => {
|
|
91
|
+
if (isOperandNode(value)) {
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
return toLiteralNode(value);
|
|
95
|
+
};
|
|
115
96
|
|
|
116
97
|
/**
|
|
117
98
|
* Converts various input types to an OperandNode
|
|
@@ -2,23 +2,14 @@ import type { SelectQueryNode, OrderByNode } from './query.js';
|
|
|
2
2
|
import { SqlOperator, BitwiseOperator } from '../sql/sql.js';
|
|
3
3
|
import { ColumnRef } from './types.js';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* AST node representing a literal value
|
|
7
|
-
*/
|
|
8
|
-
export interface LiteralNode {
|
|
9
|
-
type: 'Literal';
|
|
10
|
-
/** The literal value (string, number, boolean, Date, or null) */
|
|
11
|
-
value: string | number | boolean | Date | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* AST node representing a named parameter placeholder
|
|
16
|
-
*/
|
|
17
|
-
export interface ParamNode {
|
|
18
|
-
type: 'Param';
|
|
19
|
-
/** Stable parameter name */
|
|
20
|
-
name: string;
|
|
21
|
-
}
|
|
5
|
+
/**
|
|
6
|
+
* AST node representing a literal value
|
|
7
|
+
*/
|
|
8
|
+
export interface LiteralNode {
|
|
9
|
+
type: 'Literal';
|
|
10
|
+
/** The literal value (string, number, boolean, Date, or null) */
|
|
11
|
+
value: string | number | boolean | Date | null;
|
|
12
|
+
}
|
|
22
13
|
|
|
23
14
|
/**
|
|
24
15
|
* AST node representing a reference to a SELECT alias (for ORDER BY / GROUP BY).
|
|
@@ -158,66 +149,54 @@ export interface ArithmeticExpressionNode {
|
|
|
158
149
|
/**
|
|
159
150
|
* Union type representing any operand that can be used in expressions
|
|
160
151
|
*/
|
|
161
|
-
export type OperandNode =
|
|
162
|
-
| AliasRefNode
|
|
163
|
-
| ColumnNode
|
|
164
|
-
| LiteralNode
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
| CastExpressionNode
|
|
152
|
+
export type OperandNode =
|
|
153
|
+
| AliasRefNode
|
|
154
|
+
| ColumnNode
|
|
155
|
+
| LiteralNode
|
|
156
|
+
| FunctionNode
|
|
157
|
+
| JsonPathNode
|
|
158
|
+
| ScalarSubqueryNode
|
|
159
|
+
| CaseExpressionNode
|
|
160
|
+
| CastExpressionNode
|
|
171
161
|
| WindowFunctionNode
|
|
172
162
|
| ArithmeticExpressionNode
|
|
173
163
|
| BitwiseExpressionNode
|
|
174
164
|
| CollateExpressionNode;
|
|
175
165
|
|
|
176
|
-
const operandTypes = new Set<OperandNode['type']>([
|
|
177
|
-
'AliasRef',
|
|
178
|
-
'Column',
|
|
179
|
-
'Literal',
|
|
180
|
-
'
|
|
181
|
-
'
|
|
182
|
-
'
|
|
183
|
-
'
|
|
184
|
-
'
|
|
185
|
-
'
|
|
186
|
-
'
|
|
187
|
-
'
|
|
188
|
-
'
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
export const isFunctionNode = (node: unknown): node is FunctionNode =>
|
|
211
|
-
isOperandNode(node) && getNodeType(node) === 'Function';
|
|
212
|
-
export const isCaseExpressionNode = (node: unknown): node is CaseExpressionNode =>
|
|
213
|
-
isOperandNode(node) && getNodeType(node) === 'CaseExpression';
|
|
214
|
-
|
|
215
|
-
export const isCastExpressionNode = (node: unknown): node is CastExpressionNode =>
|
|
216
|
-
isOperandNode(node) && getNodeType(node) === 'Cast';
|
|
217
|
-
export const isCollateExpressionNode = (node: unknown): node is CollateExpressionNode =>
|
|
218
|
-
isOperandNode(node) && getNodeType(node) === 'Collate';
|
|
219
|
-
export const isWindowFunctionNode = (node: unknown): node is WindowFunctionNode =>
|
|
220
|
-
isOperandNode(node) && getNodeType(node) === 'WindowFunction';
|
|
166
|
+
const operandTypes = new Set<OperandNode['type']>([
|
|
167
|
+
'AliasRef',
|
|
168
|
+
'Column',
|
|
169
|
+
'Literal',
|
|
170
|
+
'Function',
|
|
171
|
+
'JsonPath',
|
|
172
|
+
'ScalarSubquery',
|
|
173
|
+
'CaseExpression',
|
|
174
|
+
'Cast',
|
|
175
|
+
'WindowFunction',
|
|
176
|
+
'ArithmeticExpression',
|
|
177
|
+
'BitwiseExpression',
|
|
178
|
+
'Collate'
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
const hasTypeProperty = (value: unknown): value is { type?: string } =>
|
|
182
|
+
typeof value === 'object' && value !== null && 'type' in value;
|
|
183
|
+
|
|
184
|
+
export const isOperandNode = (node: unknown): node is OperandNode => {
|
|
185
|
+
if (!hasTypeProperty(node)) return false;
|
|
186
|
+
return operandTypes.has(node.type as OperandNode['type']);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const isFunctionNode = (node: unknown): node is FunctionNode =>
|
|
190
|
+
isOperandNode(node) && node.type === 'Function';
|
|
191
|
+
export const isCaseExpressionNode = (node: unknown): node is CaseExpressionNode =>
|
|
192
|
+
isOperandNode(node) && node.type === 'CaseExpression';
|
|
193
|
+
|
|
194
|
+
export const isCastExpressionNode = (node: unknown): node is CastExpressionNode =>
|
|
195
|
+
isOperandNode(node) && node.type === 'Cast';
|
|
196
|
+
export const isCollateExpressionNode = (node: unknown): node is CollateExpressionNode =>
|
|
197
|
+
isOperandNode(node) && node.type === 'Collate';
|
|
198
|
+
export const isWindowFunctionNode = (node: unknown): node is WindowFunctionNode =>
|
|
199
|
+
isOperandNode(node) && node.type === 'WindowFunction';
|
|
221
200
|
export const isExpressionSelectionNode = (
|
|
222
201
|
node: ColumnRef | FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode
|
|
223
202
|
): node is FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode =>
|