metal-orm 1.0.89 → 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.
- package/dist/index.cjs +2968 -2983
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +765 -246
- package/dist/index.d.ts +765 -246
- package/dist/index.js +2913 -2975
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- 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/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 +11 -8
- package/src/dto/apply-filter.ts +281 -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 +83 -0
- package/src/dto/openapi/utilities.ts +45 -0
- package/src/dto/pagination-utils.ts +150 -0
- package/src/dto/transform.ts +193 -0
- package/src/index.ts +67 -65
- 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/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
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import type { TableDef } from '../schema/table.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* OpenAPI 3.1 JSON Schema type representation
|
|
5
|
-
*/
|
|
6
|
-
export type JsonSchemaType =
|
|
7
|
-
| 'string'
|
|
8
|
-
| 'number'
|
|
9
|
-
| 'integer'
|
|
10
|
-
| 'boolean'
|
|
11
|
-
| 'object'
|
|
12
|
-
| 'array'
|
|
13
|
-
| 'null';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Common OpenAPI 3.1 JSON Schema formats
|
|
17
|
-
*/
|
|
18
|
-
export type JsonSchemaFormat =
|
|
19
|
-
| 'date-time'
|
|
20
|
-
| 'date'
|
|
21
|
-
| 'time'
|
|
22
|
-
| 'email'
|
|
23
|
-
| 'uuid'
|
|
24
|
-
| 'uri'
|
|
25
|
-
| 'binary'
|
|
26
|
-
| 'base64';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* OpenAPI 3.1 JSON Schema property definition
|
|
30
|
-
*/
|
|
31
|
-
export interface JsonSchemaProperty {
|
|
32
|
-
type?: JsonSchemaType | JsonSchemaType[];
|
|
33
|
-
format?: JsonSchemaFormat;
|
|
34
|
-
description?: string;
|
|
35
|
-
nullable?: boolean;
|
|
36
|
-
readOnly?: boolean;
|
|
37
|
-
writeOnly?: boolean;
|
|
38
|
-
minimum?: number;
|
|
39
|
-
maximum?: number;
|
|
40
|
-
minLength?: number;
|
|
41
|
-
maxLength?: number;
|
|
42
|
-
pattern?: string;
|
|
43
|
-
enum?: (string | number | boolean)[];
|
|
44
|
-
default?: unknown;
|
|
45
|
-
example?: unknown;
|
|
46
|
-
properties?: Record<string, JsonSchemaProperty>;
|
|
47
|
-
required?: string[];
|
|
48
|
-
items?: JsonSchemaProperty;
|
|
49
|
-
$ref?: string;
|
|
50
|
-
anyOf?: JsonSchemaProperty[];
|
|
51
|
-
allOf?: JsonSchemaProperty[];
|
|
52
|
-
oneOf?: JsonSchemaProperty[];
|
|
53
|
-
[key: string]: unknown;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* OpenAPI 3.1 parameter definition
|
|
58
|
-
*/
|
|
59
|
-
export interface OpenApiParameter {
|
|
60
|
-
name: string;
|
|
61
|
-
in: 'query' | 'path' | 'header' | 'cookie';
|
|
62
|
-
description?: string;
|
|
63
|
-
required?: boolean;
|
|
64
|
-
deprecated?: boolean;
|
|
65
|
-
allowEmptyValue?: boolean;
|
|
66
|
-
style?: string;
|
|
67
|
-
explode?: boolean;
|
|
68
|
-
schema?: JsonSchemaProperty;
|
|
69
|
-
[key: string]: unknown;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Complete OpenAPI 3.1 Schema for an entity or query result
|
|
74
|
-
*/
|
|
75
|
-
export interface OpenApiSchema {
|
|
76
|
-
type: 'object';
|
|
77
|
-
properties: Record<string, JsonSchemaProperty>;
|
|
78
|
-
required: string[];
|
|
79
|
-
description?: string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* OpenAPI 3.1 components container
|
|
84
|
-
*/
|
|
85
|
-
export interface OpenApiComponents {
|
|
86
|
-
schemas: Record<string, OpenApiSchema>;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Column-level schema flags
|
|
91
|
-
*/
|
|
92
|
-
export interface ColumnSchemaOptions {
|
|
93
|
-
/** Include description from column comments */
|
|
94
|
-
includeDescriptions?: boolean;
|
|
95
|
-
/** Include enum values for enum columns */
|
|
96
|
-
includeEnums?: boolean;
|
|
97
|
-
/** Include column examples if available */
|
|
98
|
-
includeExamples?: boolean;
|
|
99
|
-
/** Include column defaults */
|
|
100
|
-
includeDefaults?: boolean;
|
|
101
|
-
/** Include nullable flag when applicable */
|
|
102
|
-
includeNullable?: boolean;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Output schema generation options (query result)
|
|
107
|
-
*/
|
|
108
|
-
export interface OutputSchemaOptions extends ColumnSchemaOptions {
|
|
109
|
-
/** Use selected columns only (from select/include) vs full entity */
|
|
110
|
-
mode?: 'selected' | 'full';
|
|
111
|
-
/** Maximum depth for relation recursion */
|
|
112
|
-
maxDepth?: number;
|
|
113
|
-
/** Inline schemas vs $ref components */
|
|
114
|
-
refMode?: 'inline' | 'components';
|
|
115
|
-
/** Selected schemas inline vs components when refMode is components */
|
|
116
|
-
selectedRefMode?: 'inline' | 'components';
|
|
117
|
-
/** Customize component names */
|
|
118
|
-
componentName?: (table: TableDef) => string;
|
|
119
|
-
/** Emit output schema as a component $ref when refMode is components */
|
|
120
|
-
outputAsRef?: boolean;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export type InputRelationMode = 'ids' | 'objects' | 'mixed';
|
|
124
|
-
export type InputSchemaMode = 'create' | 'update';
|
|
125
|
-
|
|
126
|
-
export interface RelationSelection {
|
|
127
|
-
pick?: string[];
|
|
128
|
-
omit?: string[];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Input schema generation options (write payloads)
|
|
133
|
-
*/
|
|
134
|
-
export interface InputSchemaOptions extends ColumnSchemaOptions {
|
|
135
|
-
/** Create vs update payload shape */
|
|
136
|
-
mode?: InputSchemaMode;
|
|
137
|
-
/** Include relation payloads */
|
|
138
|
-
includeRelations?: boolean;
|
|
139
|
-
/** How relations are represented (ids, nested objects, or both) */
|
|
140
|
-
relationMode?: InputRelationMode;
|
|
141
|
-
/** Maximum depth for relation recursion */
|
|
142
|
-
maxDepth?: number;
|
|
143
|
-
/** Omit read-only/generated columns from input */
|
|
144
|
-
omitReadOnly?: boolean;
|
|
145
|
-
/** Exclude primary key columns from input */
|
|
146
|
-
excludePrimaryKey?: boolean;
|
|
147
|
-
/** Require primary key columns on update payloads */
|
|
148
|
-
requirePrimaryKey?: boolean;
|
|
149
|
-
/** Remove relation foreign keys pointing to the parent from nested inputs */
|
|
150
|
-
excludeRelationForeignKeys?: boolean;
|
|
151
|
-
/** Per-relation field selection for nested inputs */
|
|
152
|
-
relationSelections?: Record<string, RelationSelection>;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Schema generation options
|
|
157
|
-
*/
|
|
158
|
-
export interface SchemaOptions extends OutputSchemaOptions {
|
|
159
|
-
/** Input schema options, or false to skip input generation */
|
|
160
|
-
input?: InputSchemaOptions | false;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Input + output schema bundle
|
|
165
|
-
*/
|
|
166
|
-
export interface OpenApiSchemaBundle {
|
|
167
|
-
output: OpenApiSchema | JsonSchemaProperty;
|
|
168
|
-
input?: OpenApiSchema;
|
|
169
|
-
parameters?: OpenApiParameter[];
|
|
170
|
-
components?: OpenApiComponents;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Schema extraction context for handling circular references
|
|
175
|
-
*/
|
|
176
|
-
export interface SchemaExtractionContext {
|
|
177
|
-
/** Set of already visited tables to detect cycles */
|
|
178
|
-
visitedTables: Set<string>;
|
|
179
|
-
/** Map of table names to their generated schemas */
|
|
180
|
-
schemaCache: Map<string, OpenApiSchema>;
|
|
181
|
-
/** Current extraction depth */
|
|
182
|
-
depth: number;
|
|
183
|
-
/** Maximum depth to recurse */
|
|
184
|
-
maxDepth: number;
|
|
185
|
-
/** Component registry when using refMode=components */
|
|
186
|
-
components?: OpenApiComponents;
|
|
187
|
-
}
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import type { ColumnDef } from '../schema/column-types.js';
|
|
2
|
-
import type { ColumnSchemaOptions, JsonSchemaProperty, JsonSchemaType, JsonSchemaFormat } from './schema-types.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Maps SQL column types to OpenAPI JSON Schema types
|
|
6
|
-
*/
|
|
7
|
-
export const mapColumnType = (
|
|
8
|
-
column: ColumnDef,
|
|
9
|
-
options: ColumnSchemaOptions = {}
|
|
10
|
-
): JsonSchemaProperty => {
|
|
11
|
-
const resolved = resolveColumnOptions(options);
|
|
12
|
-
const sqlType = normalizeType(column.type);
|
|
13
|
-
const baseSchema = mapSqlTypeToBaseSchema(sqlType, column);
|
|
14
|
-
|
|
15
|
-
const schema: JsonSchemaProperty = {
|
|
16
|
-
...baseSchema,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
if (resolved.includeDescriptions && column.comment) {
|
|
20
|
-
schema.description = column.comment;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (resolved.includeNullable) {
|
|
24
|
-
schema.nullable = !column.notNull && !column.primary;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if ((sqlType === 'varchar' || sqlType === 'char') && column.args) {
|
|
28
|
-
schema.maxLength = column.args[0] as number | undefined;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if ((sqlType === 'decimal' || sqlType === 'float') && column.args) {
|
|
32
|
-
if (column.args.length >= 1) {
|
|
33
|
-
schema.minimum = -(10 ** (column.args[0] as number));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!resolved.includeEnums) {
|
|
38
|
-
delete schema.enum;
|
|
39
|
-
} else if (sqlType === 'enum' && column.args && column.args.length > 0) {
|
|
40
|
-
schema.enum = column.args as (string | number | boolean)[];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (resolved.includeDefaults && column.default !== undefined) {
|
|
44
|
-
schema.default = column.default;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return schema;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const normalizeType = (type: string): string => {
|
|
51
|
-
return type.toLowerCase();
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const mapSqlTypeToBaseSchema = (
|
|
55
|
-
sqlType: string,
|
|
56
|
-
column: ColumnDef
|
|
57
|
-
): Omit<JsonSchemaProperty, 'nullable' | 'description'> => {
|
|
58
|
-
const type = normalizeType(sqlType);
|
|
59
|
-
|
|
60
|
-
const hasCustomTsType = column.tsType !== undefined;
|
|
61
|
-
|
|
62
|
-
switch (type) {
|
|
63
|
-
case 'int':
|
|
64
|
-
case 'integer':
|
|
65
|
-
case 'bigint':
|
|
66
|
-
return {
|
|
67
|
-
type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : ('integer' as JsonSchemaType),
|
|
68
|
-
format: type === 'bigint' ? 'int64' : 'int32',
|
|
69
|
-
minimum: column.autoIncrement ? 1 : undefined,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
case 'decimal':
|
|
73
|
-
case 'float':
|
|
74
|
-
case 'double':
|
|
75
|
-
return {
|
|
76
|
-
type: hasCustomTsType ? inferTypeFromTsType(column.tsType) : ('number' as JsonSchemaType),
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
case 'varchar':
|
|
80
|
-
return {
|
|
81
|
-
type: 'string' as JsonSchemaType,
|
|
82
|
-
minLength: column.notNull ? 1 : undefined,
|
|
83
|
-
maxLength: column.args?.[0] as number | undefined,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
case 'text':
|
|
87
|
-
return {
|
|
88
|
-
type: 'string' as JsonSchemaType,
|
|
89
|
-
minLength: column.notNull ? 1 : undefined,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
case 'char':
|
|
93
|
-
return {
|
|
94
|
-
type: 'string' as JsonSchemaType,
|
|
95
|
-
minLength: column.notNull ? column.args?.[0] as number || 1 : undefined,
|
|
96
|
-
maxLength: column.args?.[0] as number,
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
case 'boolean':
|
|
100
|
-
return {
|
|
101
|
-
type: 'boolean' as JsonSchemaType,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
case 'json':
|
|
105
|
-
return {
|
|
106
|
-
anyOf: [
|
|
107
|
-
{ type: 'object' as JsonSchemaType },
|
|
108
|
-
{ type: 'array' as JsonSchemaType },
|
|
109
|
-
],
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
case 'blob':
|
|
113
|
-
case 'binary':
|
|
114
|
-
case 'varbinary':
|
|
115
|
-
return {
|
|
116
|
-
type: 'string' as JsonSchemaType,
|
|
117
|
-
format: 'base64' as JsonSchemaFormat,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
case 'date':
|
|
121
|
-
return {
|
|
122
|
-
type: 'string' as JsonSchemaType,
|
|
123
|
-
format: 'date' as JsonSchemaFormat,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
case 'datetime':
|
|
127
|
-
case 'timestamp':
|
|
128
|
-
return {
|
|
129
|
-
type: 'string' as JsonSchemaType,
|
|
130
|
-
format: 'date-time' as JsonSchemaFormat,
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
case 'timestamptz':
|
|
134
|
-
return {
|
|
135
|
-
type: 'string' as JsonSchemaType,
|
|
136
|
-
format: 'date-time' as JsonSchemaFormat,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
case 'uuid':
|
|
140
|
-
return {
|
|
141
|
-
type: 'string' as JsonSchemaType,
|
|
142
|
-
format: 'uuid' as JsonSchemaFormat,
|
|
143
|
-
pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
case 'enum':
|
|
147
|
-
return {
|
|
148
|
-
type: 'string' as JsonSchemaType,
|
|
149
|
-
enum: (column.args as (string | number | boolean)[]) || [],
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
default:
|
|
153
|
-
if (column.dialectTypes?.postgres && column.dialectTypes.postgres === 'bytea') {
|
|
154
|
-
return {
|
|
155
|
-
type: 'string' as JsonSchemaType,
|
|
156
|
-
format: 'base64' as JsonSchemaFormat,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
type: 'string' as JsonSchemaType,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const inferTypeFromTsType = (tsType: unknown): JsonSchemaType => {
|
|
167
|
-
if (typeof tsType === 'string') {
|
|
168
|
-
if (tsType === 'number') return 'number' as JsonSchemaType;
|
|
169
|
-
if (tsType === 'string') return 'string' as JsonSchemaType;
|
|
170
|
-
if (tsType === 'boolean') return 'boolean' as JsonSchemaType;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (typeof tsType === 'function') {
|
|
174
|
-
const typeStr = tsType.name?.toLowerCase();
|
|
175
|
-
if (typeStr === 'number') return 'number' as JsonSchemaType;
|
|
176
|
-
if (typeStr === 'string') return 'string' as JsonSchemaType;
|
|
177
|
-
if (typeStr === 'boolean') return 'boolean' as JsonSchemaType;
|
|
178
|
-
if (typeStr === 'array') return 'array' as JsonSchemaType;
|
|
179
|
-
if (typeStr === 'object') return 'object' as JsonSchemaType;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return 'string' as JsonSchemaType;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const resolveColumnOptions = (options: ColumnSchemaOptions): Required<ColumnSchemaOptions> => ({
|
|
186
|
-
includeDescriptions: options.includeDescriptions ?? false,
|
|
187
|
-
includeEnums: options.includeEnums ?? true,
|
|
188
|
-
includeExamples: options.includeExamples ?? false,
|
|
189
|
-
includeDefaults: options.includeDefaults ?? true,
|
|
190
|
-
includeNullable: options.includeNullable ?? true
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Maps relation type to array or single object
|
|
195
|
-
*/
|
|
196
|
-
export const mapRelationType = (
|
|
197
|
-
relationType: string
|
|
198
|
-
): { type: 'object' | 'array'; isNullable: boolean } => {
|
|
199
|
-
switch (relationType) {
|
|
200
|
-
case 'HAS_MANY':
|
|
201
|
-
case 'BELONGS_TO_MANY':
|
|
202
|
-
return { type: 'array', isNullable: false };
|
|
203
|
-
case 'HAS_ONE':
|
|
204
|
-
case 'BELONGS_TO':
|
|
205
|
-
return { type: 'object', isNullable: true };
|
|
206
|
-
default:
|
|
207
|
-
return { type: 'object', isNullable: true };
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Gets the OpenAPI format for temporal columns
|
|
213
|
-
*/
|
|
214
|
-
export const getTemporalFormat = (sqlType: string): JsonSchemaFormat | undefined => {
|
|
215
|
-
const type = normalizeType(sqlType);
|
|
216
|
-
|
|
217
|
-
switch (type) {
|
|
218
|
-
case 'date':
|
|
219
|
-
return 'date' as JsonSchemaFormat;
|
|
220
|
-
case 'datetime':
|
|
221
|
-
case 'timestamp':
|
|
222
|
-
case 'timestamptz':
|
|
223
|
-
return 'date-time' as JsonSchemaFormat;
|
|
224
|
-
default:
|
|
225
|
-
return undefined;
|
|
226
|
-
}
|
|
227
|
-
};
|