@mikro-orm/entity-generator 6.5.10-dev.9 → 6.6.1-dev.0
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/DefineEntitySourceFile.d.ts +5 -0
- package/DefineEntitySourceFile.js +119 -0
- package/EntityGenerator.js +33 -16
- package/EntitySchemaSourceFile.d.ts +3 -2
- package/EntitySchemaSourceFile.js +47 -36
- package/NativeEnumSourceFile.d.ts +16 -0
- package/NativeEnumSourceFile.js +51 -0
- package/SourceFile.d.ts +2 -1
- package/SourceFile.js +97 -22
- package/package.json +4 -4
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefineEntitySourceFile = void 0;
|
|
4
|
+
const core_1 = require("@mikro-orm/core");
|
|
5
|
+
const EntitySchemaSourceFile_1 = require("./EntitySchemaSourceFile");
|
|
6
|
+
class DefineEntitySourceFile extends EntitySchemaSourceFile_1.EntitySchemaSourceFile {
|
|
7
|
+
generate() {
|
|
8
|
+
const enumDefinitions = [];
|
|
9
|
+
for (const prop of Object.values(this.meta.properties)) {
|
|
10
|
+
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR)) {
|
|
11
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
12
|
+
if (def.length) {
|
|
13
|
+
enumDefinitions.push(def);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let ret = '';
|
|
18
|
+
if (!this.options.inferEntityType) {
|
|
19
|
+
ret += this.generateClassDefinition() + '\n';
|
|
20
|
+
}
|
|
21
|
+
if (enumDefinitions.length) {
|
|
22
|
+
ret += enumDefinitions.join('\n') + '\n';
|
|
23
|
+
}
|
|
24
|
+
const entitySchemaOptions = {};
|
|
25
|
+
if (this.options.inferEntityType) {
|
|
26
|
+
entitySchemaOptions.name = this.quote(this.meta.className);
|
|
27
|
+
if (this.meta.compositePK) {
|
|
28
|
+
entitySchemaOptions.primaryKeys = this.meta.getPrimaryProps().map(p => this.quote(p.name));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
entitySchemaOptions.class = this.meta.className;
|
|
33
|
+
}
|
|
34
|
+
Object.assign(entitySchemaOptions, (this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})));
|
|
35
|
+
const nameSuffix = this.options.inferEntityType ? '' : 'Schema';
|
|
36
|
+
const declLine = `export const ${this.meta.className + nameSuffix} = ${this.referenceCoreImport('defineEntity')}(`;
|
|
37
|
+
ret += declLine;
|
|
38
|
+
if (this.meta.indexes.length > 0) {
|
|
39
|
+
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
40
|
+
}
|
|
41
|
+
if (this.meta.uniques.length > 0) {
|
|
42
|
+
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
43
|
+
}
|
|
44
|
+
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyBuilder(prop)]));
|
|
45
|
+
// Force top level and properties to be indented, regardless of line length
|
|
46
|
+
entitySchemaOptions[core_1.Config] = true;
|
|
47
|
+
entitySchemaOptions.properties[core_1.Config] = true;
|
|
48
|
+
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
49
|
+
ret += ');\n';
|
|
50
|
+
if (this.options.inferEntityType) {
|
|
51
|
+
ret += `\nexport interface I${this.meta.className} extends ${this.referenceCoreImport('InferEntity')}<typeof ${this.meta.className}> {}\n`;
|
|
52
|
+
}
|
|
53
|
+
ret = `${this.generateImports()}\n\n${ret}`;
|
|
54
|
+
return ret;
|
|
55
|
+
}
|
|
56
|
+
getPropertyBuilder(prop) {
|
|
57
|
+
const options = this.getPropertyOptions(prop, false);
|
|
58
|
+
const p = this.referenceCoreImport('p');
|
|
59
|
+
let builder = '';
|
|
60
|
+
switch (prop.kind) {
|
|
61
|
+
case core_1.ReferenceKind.ONE_TO_ONE:
|
|
62
|
+
builder += `() => ${p}.oneToOne(${prop.type})`;
|
|
63
|
+
break;
|
|
64
|
+
case core_1.ReferenceKind.ONE_TO_MANY:
|
|
65
|
+
builder += `() => ${p}.oneToMany(${prop.type})`;
|
|
66
|
+
break;
|
|
67
|
+
case core_1.ReferenceKind.MANY_TO_ONE:
|
|
68
|
+
builder += `() => ${p}.manyToOne(${prop.type})`;
|
|
69
|
+
break;
|
|
70
|
+
case core_1.ReferenceKind.MANY_TO_MANY:
|
|
71
|
+
builder += `() => ${p}.manyToMany(${prop.type})`;
|
|
72
|
+
break;
|
|
73
|
+
case core_1.ReferenceKind.EMBEDDED:
|
|
74
|
+
builder += `() => ${p}.embedded(${prop.type})`;
|
|
75
|
+
break;
|
|
76
|
+
case core_1.ReferenceKind.SCALAR:
|
|
77
|
+
default: {
|
|
78
|
+
if (options.type && !(options.type in core_1.types)) {
|
|
79
|
+
builder += `${p}.type(${options.type})`;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
builder += options.type ? `${p}.${options.type}()` : p;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const simpleOptions = new Set([
|
|
87
|
+
'primary', 'ref', 'nullable', 'array', 'object', 'mapToPk', 'hidden', 'concurrencyCheck', 'lazy', 'eager',
|
|
88
|
+
'orphanRemoval', 'version', 'unsigned', 'returning', 'createForeignKeyConstraint', 'fixedOrder', 'owner',
|
|
89
|
+
'getter', 'setter', 'unique', 'index', 'hydrate', 'persist', 'autoincrement',
|
|
90
|
+
]);
|
|
91
|
+
const skipOptions = new Set(['entity', 'kind', 'type', 'items']);
|
|
92
|
+
const spreadOptions = new Set([
|
|
93
|
+
'fieldNames', 'joinColumns', 'inverseJoinColumns', 'referencedColumnNames', 'ownColumns', 'columnTypes',
|
|
94
|
+
'cascade', 'ignoreSchemaChanges', 'customOrder', 'groups', 'where', 'orderBy',
|
|
95
|
+
]);
|
|
96
|
+
const rename = {
|
|
97
|
+
fieldName: 'name',
|
|
98
|
+
};
|
|
99
|
+
for (const key of Object.keys(options)) {
|
|
100
|
+
if (typeof options[key] === 'undefined' || skipOptions.has(key)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const method = rename[key] ?? key;
|
|
104
|
+
const params = simpleOptions.has(key) && options[key] === true ? '' : options[key];
|
|
105
|
+
builder += `.${method}`;
|
|
106
|
+
if (key === 'enum') {
|
|
107
|
+
builder += `(${options.items})`;
|
|
108
|
+
}
|
|
109
|
+
else if (spreadOptions.has(key) && typeof params === 'string' && params.startsWith('[')) {
|
|
110
|
+
builder += `(${params.slice(1, -1)})`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
builder += `(${params})`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return builder;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.DefineEntitySourceFile = DefineEntitySourceFile;
|
package/EntityGenerator.js
CHANGED
|
@@ -5,7 +5,9 @@ const core_1 = require("@mikro-orm/core");
|
|
|
5
5
|
const knex_1 = require("@mikro-orm/knex");
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
7
|
const fs_extra_1 = require("fs-extra");
|
|
8
|
+
const DefineEntitySourceFile_1 = require("./DefineEntitySourceFile");
|
|
8
9
|
const EntitySchemaSourceFile_1 = require("./EntitySchemaSourceFile");
|
|
10
|
+
const NativeEnumSourceFile_1 = require("./NativeEnumSourceFile");
|
|
9
11
|
const SourceFile_1 = require("./SourceFile");
|
|
10
12
|
class EntityGenerator {
|
|
11
13
|
em;
|
|
@@ -35,28 +37,43 @@ class EntityGenerator {
|
|
|
35
37
|
const metadata = await this.getEntityMetadata(schema, options);
|
|
36
38
|
const defaultPath = `${this.config.get('baseDir')}/generated-entities`;
|
|
37
39
|
const baseDir = core_1.Utils.normalizePath(options.path ?? defaultPath);
|
|
40
|
+
this.sources.length = 0;
|
|
41
|
+
if (options.entitySchema) {
|
|
42
|
+
options.entityDefinition = 'entitySchema';
|
|
43
|
+
}
|
|
44
|
+
const map = {
|
|
45
|
+
defineEntity: DefineEntitySourceFile_1.DefineEntitySourceFile,
|
|
46
|
+
entitySchema: EntitySchemaSourceFile_1.EntitySchemaSourceFile,
|
|
47
|
+
decorators: SourceFile_1.SourceFile,
|
|
48
|
+
};
|
|
49
|
+
if (options.entityDefinition !== 'decorators') {
|
|
50
|
+
options.scalarTypeInDecorator = true;
|
|
51
|
+
}
|
|
38
52
|
for (const meta of metadata) {
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
this.sources.push(new EntitySchemaSourceFile_1.EntitySchemaSourceFile(meta, this.namingStrategy, this.platform, { ...options, scalarTypeInDecorator: true }));
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
this.sources.push(new SourceFile_1.SourceFile(meta, this.namingStrategy, this.platform, options));
|
|
45
|
-
}
|
|
53
|
+
if (meta.pivotTable && !options.outputPurePivotTables && !this.referencedEntities.has(meta)) {
|
|
54
|
+
continue;
|
|
46
55
|
}
|
|
56
|
+
this.sources.push(new map[options.entityDefinition](meta, this.namingStrategy, this.platform, options));
|
|
47
57
|
}
|
|
58
|
+
for (const nativeEnum of Object.values(schema.getNativeEnums())) {
|
|
59
|
+
this.sources.push(new NativeEnumSourceFile_1.NativeEnumSourceFile({}, this.namingStrategy, this.platform, options, nativeEnum));
|
|
60
|
+
}
|
|
61
|
+
const files = this.sources.map(file => [file.getBaseName(), file.generate()]);
|
|
48
62
|
if (options.save) {
|
|
49
63
|
await (0, fs_extra_1.ensureDir)(baseDir);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
const promises = [];
|
|
65
|
+
for (const [fileName, data] of files) {
|
|
66
|
+
promises.push((async () => {
|
|
67
|
+
const fileDir = (0, node_path_1.dirname)(fileName);
|
|
68
|
+
if (fileDir !== '.') {
|
|
69
|
+
await (0, fs_extra_1.ensureDir)((0, node_path_1.join)(baseDir, fileDir));
|
|
70
|
+
}
|
|
71
|
+
await (0, fs_extra_1.writeFile)((0, node_path_1.join)(baseDir, fileName), data, { flush: true });
|
|
72
|
+
})());
|
|
73
|
+
}
|
|
74
|
+
await Promise.all(promises);
|
|
58
75
|
}
|
|
59
|
-
return
|
|
76
|
+
return files.map(([, data]) => data);
|
|
60
77
|
}
|
|
61
78
|
async getEntityMetadata(schema, options) {
|
|
62
79
|
const metadata = schema.getTables()
|
|
@@ -2,7 +2,8 @@ import { type Dictionary, type EntityProperty } from '@mikro-orm/core';
|
|
|
2
2
|
import { SourceFile } from './SourceFile';
|
|
3
3
|
export declare class EntitySchemaSourceFile extends SourceFile {
|
|
4
4
|
generate(): string;
|
|
5
|
-
|
|
5
|
+
protected generateClassDefinition(): string;
|
|
6
|
+
protected getPropertyOptions(prop: EntityProperty, quote?: boolean): Dictionary;
|
|
6
7
|
protected getPropertyIndexesOptions(prop: EntityProperty, options: Dictionary): void;
|
|
7
|
-
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
8
|
+
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty, quote?: boolean): void;
|
|
8
9
|
}
|
|
@@ -5,21 +5,56 @@ const core_1 = require("@mikro-orm/core");
|
|
|
5
5
|
const SourceFile_1 = require("./SourceFile");
|
|
6
6
|
class EntitySchemaSourceFile extends SourceFile_1.SourceFile {
|
|
7
7
|
generate() {
|
|
8
|
+
const classDefinition = this.generateClassDefinition();
|
|
9
|
+
const enumDefinitions = [];
|
|
10
|
+
for (const prop of Object.values(this.meta.properties)) {
|
|
11
|
+
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR)) {
|
|
12
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
13
|
+
if (def.length) {
|
|
14
|
+
enumDefinitions.push(def);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
let ret = classDefinition;
|
|
19
|
+
if (enumDefinitions.length) {
|
|
20
|
+
ret += '\n' + enumDefinitions.join('\n');
|
|
21
|
+
}
|
|
22
|
+
ret += `\n`;
|
|
23
|
+
const entitySchemaOptions = {
|
|
24
|
+
class: this.meta.className,
|
|
25
|
+
...(this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})),
|
|
26
|
+
};
|
|
27
|
+
const declLine = `export const ${this.meta.className}Schema = new ${this.referenceCoreImport('EntitySchema')}(`;
|
|
28
|
+
ret += declLine;
|
|
29
|
+
if (this.meta.indexes.length > 0) {
|
|
30
|
+
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
31
|
+
}
|
|
32
|
+
if (this.meta.uniques.length > 0) {
|
|
33
|
+
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
34
|
+
}
|
|
35
|
+
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyOptions(prop)]));
|
|
36
|
+
// Force top level and properties to be indented, regardless of line length
|
|
37
|
+
entitySchemaOptions[core_1.Config] = true;
|
|
38
|
+
entitySchemaOptions.properties[core_1.Config] = true;
|
|
39
|
+
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
40
|
+
ret += ');\n';
|
|
41
|
+
ret = `${this.generateImports()}\n\n${ret}`;
|
|
42
|
+
return ret;
|
|
43
|
+
}
|
|
44
|
+
generateClassDefinition() {
|
|
8
45
|
let classBody = '';
|
|
9
|
-
if (this.meta.className === this.options.customBaseEntityName) {
|
|
46
|
+
if (!this.options.customBaseEntityName || this.meta.className === this.options.customBaseEntityName) {
|
|
10
47
|
const defineConfigTypeSettings = {};
|
|
11
48
|
defineConfigTypeSettings.forceObject = this.platform.getConfig().get('serialization').forceObject ?? false;
|
|
12
|
-
|
|
49
|
+
if (defineConfigTypeSettings.forceObject) {
|
|
50
|
+
classBody += `${' '.repeat(2)}[${this.referenceCoreImport('Config')}]?: ${this.referenceCoreImport('DefineConfig')}<${this.serializeObject(defineConfigTypeSettings)}>;\n`;
|
|
51
|
+
}
|
|
13
52
|
}
|
|
14
|
-
const enumDefinitions = [];
|
|
15
53
|
const eagerProperties = [];
|
|
16
54
|
const primaryProps = [];
|
|
17
55
|
const props = [];
|
|
18
56
|
for (const prop of Object.values(this.meta.properties)) {
|
|
19
57
|
props.push(this.getPropertyDefinition(prop, 2));
|
|
20
|
-
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === core_1.ReferenceKind.SCALAR)) {
|
|
21
|
-
enumDefinitions.push(this.getEnumClassDefinition(prop, 2));
|
|
22
|
-
}
|
|
23
58
|
if (prop.eager) {
|
|
24
59
|
eagerProperties.push(prop);
|
|
25
60
|
}
|
|
@@ -41,33 +76,9 @@ class EntitySchemaSourceFile extends SourceFile_1.SourceFile {
|
|
|
41
76
|
classBody += `${' '.repeat(2)}[${this.referenceCoreImport('EagerProps')}]?: ${eagerPropertyNames.join(' | ')};\n`;
|
|
42
77
|
}
|
|
43
78
|
classBody += `${props.join('')}`;
|
|
44
|
-
|
|
45
|
-
if (enumDefinitions.length) {
|
|
46
|
-
ret += '\n' + enumDefinitions.join('\n');
|
|
47
|
-
}
|
|
48
|
-
ret += `\n`;
|
|
49
|
-
const entitySchemaOptions = {
|
|
50
|
-
class: this.meta.className,
|
|
51
|
-
...(this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})),
|
|
52
|
-
};
|
|
53
|
-
const declLine = `export const ${this.meta.className}Schema = new ${this.referenceCoreImport('EntitySchema')}(`;
|
|
54
|
-
ret += declLine;
|
|
55
|
-
if (this.meta.indexes.length > 0) {
|
|
56
|
-
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
57
|
-
}
|
|
58
|
-
if (this.meta.uniques.length > 0) {
|
|
59
|
-
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
60
|
-
}
|
|
61
|
-
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyOptions(prop)]));
|
|
62
|
-
// Force top level and properties to be indented, regardless of line length
|
|
63
|
-
entitySchemaOptions[core_1.Config] = true;
|
|
64
|
-
entitySchemaOptions.properties[core_1.Config] = true;
|
|
65
|
-
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
66
|
-
ret += ');\n';
|
|
67
|
-
ret = `${this.generateImports()}\n\n${ret}`;
|
|
68
|
-
return ret;
|
|
79
|
+
return this.getEntityClass(classBody);
|
|
69
80
|
}
|
|
70
|
-
getPropertyOptions(prop) {
|
|
81
|
+
getPropertyOptions(prop, quote = true) {
|
|
71
82
|
const options = {};
|
|
72
83
|
if (prop.primary) {
|
|
73
84
|
options.primary = true;
|
|
@@ -82,7 +93,7 @@ class EntitySchemaSourceFile extends SourceFile_1.SourceFile {
|
|
|
82
93
|
this.getOneToManyDecoratorOptions(options, prop);
|
|
83
94
|
}
|
|
84
95
|
else if (prop.kind === core_1.ReferenceKind.SCALAR || typeof prop.kind === 'undefined') {
|
|
85
|
-
this.getScalarPropertyDecoratorOptions(options, prop);
|
|
96
|
+
this.getScalarPropertyDecoratorOptions(options, prop, quote);
|
|
86
97
|
}
|
|
87
98
|
else if (prop.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
88
99
|
this.getEmbeddedPropertyDeclarationOptions(options, prop);
|
|
@@ -126,15 +137,15 @@ class EntitySchemaSourceFile extends SourceFile_1.SourceFile {
|
|
|
126
137
|
processIndex('index');
|
|
127
138
|
processIndex('unique');
|
|
128
139
|
}
|
|
129
|
-
getScalarPropertyDecoratorOptions(options, prop) {
|
|
140
|
+
getScalarPropertyDecoratorOptions(options, prop, quote = true) {
|
|
130
141
|
if (prop.enum) {
|
|
131
142
|
options.enum = true;
|
|
132
143
|
options.items = `() => ${prop.runtimeType}`;
|
|
133
144
|
}
|
|
134
145
|
else {
|
|
135
|
-
options.type = this.quote(prop.type);
|
|
146
|
+
options.type = quote ? this.quote(prop.type) : prop.type;
|
|
136
147
|
}
|
|
137
|
-
super.getScalarPropertyDecoratorOptions(options, prop);
|
|
148
|
+
super.getScalarPropertyDecoratorOptions(options, prop, quote);
|
|
138
149
|
}
|
|
139
150
|
}
|
|
140
151
|
exports.EntitySchemaSourceFile = EntitySchemaSourceFile;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EntityMetadata, GenerateOptions, NamingStrategy, Platform } from '@mikro-orm/core';
|
|
2
|
+
import { SourceFile } from './SourceFile';
|
|
3
|
+
export declare class NativeEnumSourceFile extends SourceFile {
|
|
4
|
+
protected readonly nativeEnum: {
|
|
5
|
+
name: string;
|
|
6
|
+
schema?: string;
|
|
7
|
+
items: string[];
|
|
8
|
+
};
|
|
9
|
+
constructor(meta: EntityMetadata, namingStrategy: NamingStrategy, platform: Platform, options: GenerateOptions, nativeEnum: {
|
|
10
|
+
name: string;
|
|
11
|
+
schema?: string;
|
|
12
|
+
items: string[];
|
|
13
|
+
});
|
|
14
|
+
generate(): string;
|
|
15
|
+
getBaseName(extension?: string): string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NativeEnumSourceFile = void 0;
|
|
4
|
+
const SourceFile_1 = require("./SourceFile");
|
|
5
|
+
class NativeEnumSourceFile extends SourceFile_1.SourceFile {
|
|
6
|
+
nativeEnum;
|
|
7
|
+
constructor(meta, namingStrategy, platform, options, nativeEnum) {
|
|
8
|
+
super(meta, namingStrategy, platform, options);
|
|
9
|
+
this.nativeEnum = nativeEnum;
|
|
10
|
+
}
|
|
11
|
+
generate() {
|
|
12
|
+
const enumClassName = this.namingStrategy.getEnumClassName(this.nativeEnum.name, undefined, this.nativeEnum.schema);
|
|
13
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(this.nativeEnum.name, undefined, this.nativeEnum.schema);
|
|
14
|
+
const padding = ' ';
|
|
15
|
+
const enumMode = this.options.enumMode;
|
|
16
|
+
const enumValues = this.nativeEnum.items;
|
|
17
|
+
if (enumMode === 'union-type') {
|
|
18
|
+
return `export type ${enumTypeName} = ${enumValues.map(item => this.quote(item)).join(' | ')};\n`;
|
|
19
|
+
}
|
|
20
|
+
let ret = '';
|
|
21
|
+
if (enumMode === 'dictionary') {
|
|
22
|
+
ret += `export const ${enumClassName} = {\n`;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
ret += `export enum ${enumClassName} {\n`;
|
|
26
|
+
}
|
|
27
|
+
for (const enumValue of enumValues) {
|
|
28
|
+
const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, this.nativeEnum.name, '', this.nativeEnum.schema);
|
|
29
|
+
if (enumMode === 'dictionary') {
|
|
30
|
+
ret += `${padding}${SourceFile_1.identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${this.quote(enumValue)},\n`;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
ret += `${padding}${SourceFile_1.identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${this.quote(enumValue)},\n`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (enumMode === 'dictionary') {
|
|
37
|
+
ret += '} as const;\n';
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
ret += '}\n';
|
|
41
|
+
}
|
|
42
|
+
if (enumMode === 'dictionary') {
|
|
43
|
+
ret += `\nexport type ${enumTypeName} = (typeof ${enumClassName})[keyof typeof ${enumClassName}];\n`;
|
|
44
|
+
}
|
|
45
|
+
return ret;
|
|
46
|
+
}
|
|
47
|
+
getBaseName(extension = '.ts') {
|
|
48
|
+
return `${this.options.fileName(this.nativeEnum.name)}${extension}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.NativeEnumSourceFile = NativeEnumSourceFile;
|
package/SourceFile.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare class SourceFile {
|
|
|
10
10
|
protected readonly options: GenerateOptions;
|
|
11
11
|
protected readonly coreImports: Set<string>;
|
|
12
12
|
protected readonly entityImports: Set<string>;
|
|
13
|
+
protected readonly enumImports: Map<string, string[]>;
|
|
13
14
|
constructor(meta: EntityMetadata, namingStrategy: NamingStrategy, platform: Platform, options: GenerateOptions);
|
|
14
15
|
generate(): string;
|
|
15
16
|
protected getIndexOptions(index: EntityMetadata['indexes'][number], isAtEntityLevel?: boolean): IndexOptions<Dictionary, string>;
|
|
@@ -30,7 +31,7 @@ export declare class SourceFile {
|
|
|
30
31
|
protected getCommonDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
31
32
|
private propTypeBreakdowns;
|
|
32
33
|
private breakdownOfIType;
|
|
33
|
-
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
34
|
+
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty, quote?: boolean): void;
|
|
34
35
|
protected getManyToManyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
35
36
|
protected getOneToManyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
36
37
|
protected getEmbeddedPropertyDeclarationOptions(options: Dictionary, prop: EntityProperty): void;
|
package/SourceFile.js
CHANGED
|
@@ -17,6 +17,7 @@ class SourceFile {
|
|
|
17
17
|
options;
|
|
18
18
|
coreImports = new Set();
|
|
19
19
|
entityImports = new Set();
|
|
20
|
+
enumImports = new Map();
|
|
20
21
|
constructor(meta, namingStrategy, platform, options) {
|
|
21
22
|
this.meta = meta;
|
|
22
23
|
this.namingStrategy = namingStrategy;
|
|
@@ -68,7 +69,10 @@ class SourceFile {
|
|
|
68
69
|
classBody += definition;
|
|
69
70
|
classBody += '\n';
|
|
70
71
|
if (prop.enum) {
|
|
71
|
-
|
|
72
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
73
|
+
if (def.length) {
|
|
74
|
+
enumDefinitions.push(def);
|
|
75
|
+
}
|
|
72
76
|
}
|
|
73
77
|
if (prop.eager) {
|
|
74
78
|
eagerProperties.push(prop);
|
|
@@ -149,32 +153,45 @@ class SourceFile {
|
|
|
149
153
|
const basePath = (0, node_path_1.relative)(dir, this.options.path ?? '.') || '.';
|
|
150
154
|
(this.options.extraImports?.(basePath, base) ?? []).forEach(v => this.entityImports.add(v));
|
|
151
155
|
const entityImports = [...this.entityImports].filter(e => e !== this.meta.className);
|
|
152
|
-
|
|
156
|
+
const importMap = new Map();
|
|
157
|
+
for (const entity of entityImports) {
|
|
153
158
|
const file = this.options.onImport?.(entity, basePath, extension, base) ?? {
|
|
154
159
|
path: `${basePath}/${this.options.fileName(entity)}${extension}`,
|
|
155
160
|
name: entity,
|
|
156
161
|
};
|
|
157
162
|
if (file.path === '') {
|
|
158
163
|
if (file.name === '') {
|
|
159
|
-
|
|
164
|
+
continue;
|
|
160
165
|
}
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
importMap.set(file.path, `import ${this.quote(file.name)};`);
|
|
167
|
+
continue;
|
|
163
168
|
}
|
|
164
169
|
if (file.name === '') {
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
importMap.set(file.path, `import * as ${entity} from ${this.quote(file.path)};`);
|
|
171
|
+
continue;
|
|
167
172
|
}
|
|
168
173
|
if (file.name === 'default') {
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
importMap.set(file.path, `import ${entity} from ${this.quote(file.path)};`);
|
|
175
|
+
continue;
|
|
171
176
|
}
|
|
172
177
|
if (file.name === entity) {
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
importMap.set(file.path, `import { ${entity} } from ${this.quote(file.path)};`);
|
|
179
|
+
continue;
|
|
175
180
|
}
|
|
176
|
-
|
|
177
|
-
}
|
|
181
|
+
importMap.set(file.path, `import { ${exports.identifierRegex.test(file.name) ? file.name : this.quote(file.name)} as ${entity} } from ${this.quote(file.path)};`);
|
|
182
|
+
}
|
|
183
|
+
if (this.enumImports.size) {
|
|
184
|
+
for (const [name, exports] of this.enumImports.entries()) {
|
|
185
|
+
const file = this.options.onImport?.(name, basePath, extension, base) ?? {
|
|
186
|
+
path: `${basePath}/${this.options.fileName(name)}${extension}`,
|
|
187
|
+
name,
|
|
188
|
+
};
|
|
189
|
+
importMap.set(file.path, `import { ${exports.join(', ')} } from ${this.quote(file.path)};`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
for (const key of [...importMap.keys()].sort()) {
|
|
193
|
+
imports.add(importMap.get(key));
|
|
194
|
+
}
|
|
178
195
|
return Array.from(imports.values()).join('\n');
|
|
179
196
|
}
|
|
180
197
|
getEntityClass(classBody) {
|
|
@@ -204,6 +221,7 @@ class SourceFile {
|
|
|
204
221
|
getPropertyDefinition(prop, padLeft) {
|
|
205
222
|
const padding = ' '.repeat(padLeft);
|
|
206
223
|
const propName = exports.identifierRegex.test(prop.name) ? prop.name : this.quote(prop.name);
|
|
224
|
+
const enumMode = this.options.enumMode;
|
|
207
225
|
let hiddenType = '';
|
|
208
226
|
if (prop.hidden) {
|
|
209
227
|
hiddenType += ` & ${this.referenceCoreImport('Hidden')}`;
|
|
@@ -221,7 +239,11 @@ class SourceFile {
|
|
|
221
239
|
: (() => {
|
|
222
240
|
if (isScalar) {
|
|
223
241
|
if (prop.enum) {
|
|
224
|
-
|
|
242
|
+
const method = enumMode === 'ts-enum' ? 'getEnumClassName' : 'getEnumTypeName';
|
|
243
|
+
if (prop.nativeEnumName) {
|
|
244
|
+
return this.namingStrategy[method](prop.nativeEnumName, undefined, this.meta.schema);
|
|
245
|
+
}
|
|
246
|
+
return this.namingStrategy[method](prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
225
247
|
}
|
|
226
248
|
breakdownOfIType = this.breakdownOfIType(prop);
|
|
227
249
|
if (typeof breakdownOfIType !== 'undefined') {
|
|
@@ -256,8 +278,14 @@ class SourceFile {
|
|
|
256
278
|
return `${padding}${ret};\n`;
|
|
257
279
|
}
|
|
258
280
|
if (prop.enum && typeof prop.default === 'string') {
|
|
281
|
+
if (enumMode === 'union-type') {
|
|
282
|
+
return `${padding}${ret} = ${this.quote(prop.default)};\n`;
|
|
283
|
+
}
|
|
284
|
+
const enumClassName = prop.nativeEnumName
|
|
285
|
+
? this.namingStrategy.getEnumClassName(prop.nativeEnumName, undefined, this.meta.schema)
|
|
286
|
+
: this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
259
287
|
const enumVal = this.namingStrategy.enumValueToEnumProperty(prop.default, prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
260
|
-
return `${padding}${ret} = ${
|
|
288
|
+
return `${padding}${ret} = ${enumClassName}${exports.identifierRegex.test(enumVal) ? `.${enumVal}` : `[${this.quote(enumVal)}]`};\n`;
|
|
261
289
|
}
|
|
262
290
|
if (prop.fieldNames?.length > 1) {
|
|
263
291
|
// TODO: Composite FKs with default values require additions to default/defaultRaw that are not yet supported.
|
|
@@ -273,15 +301,51 @@ class SourceFile {
|
|
|
273
301
|
return `${padding}${ret} = ${prop.ref ? this.referenceCoreImport('ref') : this.referenceCoreImport('rel')}(${propType}, ${defaultVal});\n`;
|
|
274
302
|
}
|
|
275
303
|
getEnumClassDefinition(prop, padLeft) {
|
|
304
|
+
const enumMode = this.options.enumMode;
|
|
305
|
+
if (prop.nativeEnumName) {
|
|
306
|
+
const imports = [];
|
|
307
|
+
if (enumMode !== 'union-type') {
|
|
308
|
+
imports.push(prop.runtimeType);
|
|
309
|
+
}
|
|
310
|
+
if (!this.options.inferEntityType && enumMode !== 'ts-enum') {
|
|
311
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(prop.nativeEnumName, undefined, this.meta.schema);
|
|
312
|
+
imports.push(enumTypeName);
|
|
313
|
+
}
|
|
314
|
+
this.enumImports.set(prop.runtimeType, imports);
|
|
315
|
+
return '';
|
|
316
|
+
}
|
|
276
317
|
const enumClassName = this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
318
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
277
319
|
const padding = ' '.repeat(padLeft);
|
|
278
|
-
let ret = `export enum ${enumClassName} {\n`;
|
|
279
320
|
const enumValues = prop.items;
|
|
321
|
+
if (enumMode === 'union-type') {
|
|
322
|
+
return `export type ${enumTypeName} = ${enumValues.map(item => this.quote(item)).join(' | ')};\n`;
|
|
323
|
+
}
|
|
324
|
+
let ret = '';
|
|
325
|
+
if (enumMode === 'dictionary') {
|
|
326
|
+
ret += `export const ${enumClassName} = {\n`;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
ret += `export enum ${enumClassName} {\n`;
|
|
330
|
+
}
|
|
280
331
|
for (const enumValue of enumValues) {
|
|
281
332
|
const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
282
|
-
|
|
333
|
+
if (enumMode === 'dictionary') {
|
|
334
|
+
ret += `${padding}${exports.identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${this.quote(enumValue)},\n`;
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
ret += `${padding}${exports.identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${this.quote(enumValue)},\n`;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (enumMode === 'dictionary') {
|
|
341
|
+
ret += '} as const;\n';
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
ret += '}\n';
|
|
345
|
+
}
|
|
346
|
+
if (enumMode === 'dictionary') {
|
|
347
|
+
ret += `\nexport type ${enumTypeName} = (typeof ${enumClassName})[keyof typeof ${enumClassName}];\n`;
|
|
283
348
|
}
|
|
284
|
-
ret += '}\n';
|
|
285
349
|
return ret;
|
|
286
350
|
}
|
|
287
351
|
serializeObject(options, wordwrap, spaces, level = 0) {
|
|
@@ -540,12 +604,23 @@ class SourceFile {
|
|
|
540
604
|
this.propTypeBreakdowns.set(prop, r);
|
|
541
605
|
return r;
|
|
542
606
|
}
|
|
543
|
-
getScalarPropertyDecoratorOptions(options, prop) {
|
|
607
|
+
getScalarPropertyDecoratorOptions(options, prop, quote = true) {
|
|
544
608
|
if (prop.fieldNames[0] !== this.namingStrategy.propertyToColumnName(prop.name)) {
|
|
545
609
|
options.fieldName = this.quote(prop.fieldNames[0]);
|
|
546
610
|
}
|
|
547
611
|
if (prop.enum) {
|
|
548
|
-
options.
|
|
612
|
+
if (this.options.enumMode === 'union-type') {
|
|
613
|
+
options.items = `[${prop.items.map(item => this.quote(item)).join(', ')}]`;
|
|
614
|
+
}
|
|
615
|
+
else if (prop.nativeEnumName) {
|
|
616
|
+
const enumClassName = this.namingStrategy.getEnumClassName(prop.nativeEnumName, undefined, this.meta.schema);
|
|
617
|
+
options.items = `() => ${enumClassName}`;
|
|
618
|
+
options.nativeEnumName = this.quote(prop.nativeEnumName);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
const enumClassName = this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
622
|
+
options.items = `() => ${enumClassName}`;
|
|
623
|
+
}
|
|
549
624
|
}
|
|
550
625
|
// For enum properties, we don't need a column type
|
|
551
626
|
// or the property length or other information in the decorator.
|
|
@@ -574,7 +649,7 @@ class SourceFile {
|
|
|
574
649
|
return ((useDefault && !hasUsableNullDefault) || (prop.optional && !prop.nullable));
|
|
575
650
|
})() // also when there is the "| Opt" type modifier (because reflect-metadata can't extract the base)
|
|
576
651
|
) {
|
|
577
|
-
options.type = this.quote(prop.type);
|
|
652
|
+
options.type = quote ? this.quote(prop.type) : prop.type;
|
|
578
653
|
}
|
|
579
654
|
}
|
|
580
655
|
const columnTypeFromMappedRuntimeType = mappedRuntimeType.getColumnType({ ...prop, autoincrement: false }, this.platform);
|
|
@@ -675,7 +750,7 @@ class SourceFile {
|
|
|
675
750
|
if (prop.array) {
|
|
676
751
|
options.array = true;
|
|
677
752
|
}
|
|
678
|
-
if (prop.object) {
|
|
753
|
+
if (prop.object && !prop.array) {
|
|
679
754
|
options.object = true;
|
|
680
755
|
}
|
|
681
756
|
if (prop.prefix === false || typeof prop.prefix === 'string') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/entity-generator",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.1-dev.0",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -58,13 +58,13 @@
|
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@mikro-orm/knex": "6.
|
|
61
|
+
"@mikro-orm/knex": "6.6.1-dev.0",
|
|
62
62
|
"fs-extra": "11.3.2"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@mikro-orm/core": "^6.
|
|
65
|
+
"@mikro-orm/core": "^6.6.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@mikro-orm/core": "6.
|
|
68
|
+
"@mikro-orm/core": "6.6.1-dev.0"
|
|
69
69
|
}
|
|
70
70
|
}
|