@mikro-orm/entity-generator 7.0.0-dev.9 → 7.0.0-dev.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/DefineEntitySourceFile.d.ts +5 -0
- package/DefineEntitySourceFile.js +115 -0
- package/EntityGenerator.js +32 -17
- package/EntitySchemaSourceFile.d.ts +3 -2
- package/EntitySchemaSourceFile.js +47 -36
- package/NativeEnumSourceFile.d.ts +16 -0
- package/NativeEnumSourceFile.js +47 -0
- package/README.md +3 -2
- package/SourceFile.d.ts +4 -1
- package/SourceFile.js +138 -40
- package/package.json +5 -5
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Config, ReferenceKind, types, } from '@mikro-orm/core';
|
|
2
|
+
import { EntitySchemaSourceFile } from './EntitySchemaSourceFile.js';
|
|
3
|
+
export class DefineEntitySourceFile extends EntitySchemaSourceFile {
|
|
4
|
+
generate() {
|
|
5
|
+
const enumDefinitions = [];
|
|
6
|
+
for (const prop of Object.values(this.meta.properties)) {
|
|
7
|
+
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === ReferenceKind.SCALAR)) {
|
|
8
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
9
|
+
if (def.length) {
|
|
10
|
+
enumDefinitions.push(def);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
let ret = '';
|
|
15
|
+
if (!this.options.inferEntityType) {
|
|
16
|
+
ret += this.generateClassDefinition() + '\n';
|
|
17
|
+
}
|
|
18
|
+
if (enumDefinitions.length) {
|
|
19
|
+
ret += enumDefinitions.join('\n') + '\n';
|
|
20
|
+
}
|
|
21
|
+
const entitySchemaOptions = {};
|
|
22
|
+
if (this.options.inferEntityType) {
|
|
23
|
+
entitySchemaOptions.name = this.quote(this.meta.className);
|
|
24
|
+
if (this.meta.compositePK) {
|
|
25
|
+
entitySchemaOptions.primaryKeys = this.meta.getPrimaryProps().map(p => this.quote(p.name));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
entitySchemaOptions.class = this.meta.className;
|
|
30
|
+
}
|
|
31
|
+
Object.assign(entitySchemaOptions, (this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})));
|
|
32
|
+
const nameSuffix = this.options.inferEntityType ? '' : 'Schema';
|
|
33
|
+
const declLine = `export const ${this.meta.className + nameSuffix} = ${this.referenceCoreImport('defineEntity')}(`;
|
|
34
|
+
ret += declLine;
|
|
35
|
+
if (this.meta.indexes.length > 0) {
|
|
36
|
+
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
37
|
+
}
|
|
38
|
+
if (this.meta.uniques.length > 0) {
|
|
39
|
+
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
40
|
+
}
|
|
41
|
+
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyBuilder(prop)]));
|
|
42
|
+
// Force top level and properties to be indented, regardless of line length
|
|
43
|
+
entitySchemaOptions[Config] = true;
|
|
44
|
+
entitySchemaOptions.properties[Config] = true;
|
|
45
|
+
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
46
|
+
ret += ');\n';
|
|
47
|
+
if (this.options.inferEntityType) {
|
|
48
|
+
ret += `\nexport interface I${this.meta.className} extends ${this.referenceCoreImport('InferEntity')}<typeof ${this.meta.className}> {}\n`;
|
|
49
|
+
}
|
|
50
|
+
ret = `${this.generateImports()}\n\n${ret}`;
|
|
51
|
+
return ret;
|
|
52
|
+
}
|
|
53
|
+
getPropertyBuilder(prop) {
|
|
54
|
+
const options = this.getPropertyOptions(prop, false);
|
|
55
|
+
const p = this.referenceCoreImport('p');
|
|
56
|
+
let builder = '';
|
|
57
|
+
switch (prop.kind) {
|
|
58
|
+
case ReferenceKind.ONE_TO_ONE:
|
|
59
|
+
builder += `() => ${p}.oneToOne(${prop.type})`;
|
|
60
|
+
break;
|
|
61
|
+
case ReferenceKind.ONE_TO_MANY:
|
|
62
|
+
builder += `() => ${p}.oneToMany(${prop.type})`;
|
|
63
|
+
break;
|
|
64
|
+
case ReferenceKind.MANY_TO_ONE:
|
|
65
|
+
builder += `() => ${p}.manyToOne(${prop.type})`;
|
|
66
|
+
break;
|
|
67
|
+
case ReferenceKind.MANY_TO_MANY:
|
|
68
|
+
builder += `() => ${p}.manyToMany(${prop.type})`;
|
|
69
|
+
break;
|
|
70
|
+
case ReferenceKind.EMBEDDED:
|
|
71
|
+
builder += `() => ${p}.embedded(${prop.type})`;
|
|
72
|
+
break;
|
|
73
|
+
case ReferenceKind.SCALAR:
|
|
74
|
+
default: {
|
|
75
|
+
if (options.type && !(options.type in types)) {
|
|
76
|
+
builder += `${p}.type(${options.type})`;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
builder += options.type ? `${p}.${options.type}()` : p;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const simpleOptions = new Set([
|
|
84
|
+
'primary', 'ref', 'nullable', 'array', 'object', 'mapToPk', 'hidden', 'concurrencyCheck', 'lazy', 'eager',
|
|
85
|
+
'orphanRemoval', 'version', 'unsigned', 'returning', 'createForeignKeyConstraint', 'fixedOrder', 'owner',
|
|
86
|
+
'getter', 'setter', 'unique', 'index', 'hydrate', 'persist', 'autoincrement',
|
|
87
|
+
]);
|
|
88
|
+
const skipOptions = new Set(['entity', 'kind', 'type', 'items']);
|
|
89
|
+
const spreadOptions = new Set([
|
|
90
|
+
'fieldNames', 'joinColumns', 'inverseJoinColumns', 'referencedColumnNames', 'ownColumns', 'columnTypes',
|
|
91
|
+
'cascade', 'ignoreSchemaChanges', 'customOrder', 'groups', 'where', 'orderBy',
|
|
92
|
+
]);
|
|
93
|
+
const rename = {
|
|
94
|
+
fieldName: 'name',
|
|
95
|
+
};
|
|
96
|
+
for (const key of Object.keys(options)) {
|
|
97
|
+
if (typeof options[key] === 'undefined' || skipOptions.has(key)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const method = rename[key] ?? key;
|
|
101
|
+
const params = simpleOptions.has(key) && options[key] === true ? '' : options[key];
|
|
102
|
+
builder += `.${method}`;
|
|
103
|
+
if (key === 'enum') {
|
|
104
|
+
builder += `(${options.items})`;
|
|
105
|
+
}
|
|
106
|
+
else if (spreadOptions.has(key) && typeof params === 'string' && params.startsWith('[')) {
|
|
107
|
+
builder += `(${params.slice(1, -1)})`;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
builder += `(${params})`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return builder;
|
|
114
|
+
}
|
|
115
|
+
}
|
package/EntityGenerator.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { EntityMetadata, ReferenceKind, types, Utils, } from '@mikro-orm/core';
|
|
2
2
|
import { DatabaseSchema, } from '@mikro-orm/knex';
|
|
3
|
+
import { fs } from '@mikro-orm/core/fs-utils';
|
|
3
4
|
import { dirname, join } from 'node:path';
|
|
4
5
|
import { writeFile } from 'node:fs/promises';
|
|
6
|
+
import { DefineEntitySourceFile } from './DefineEntitySourceFile.js';
|
|
5
7
|
import { EntitySchemaSourceFile } from './EntitySchemaSourceFile.js';
|
|
8
|
+
import { NativeEnumSourceFile } from './NativeEnumSourceFile.js';
|
|
6
9
|
import { SourceFile } from './SourceFile.js';
|
|
7
10
|
export class EntityGenerator {
|
|
8
11
|
em;
|
|
@@ -32,28 +35,40 @@ export class EntityGenerator {
|
|
|
32
35
|
const metadata = await this.getEntityMetadata(schema, options);
|
|
33
36
|
const defaultPath = `${this.config.get('baseDir')}/generated-entities`;
|
|
34
37
|
const baseDir = Utils.normalizePath(options.path ?? defaultPath);
|
|
38
|
+
this.sources.length = 0;
|
|
39
|
+
const map = {
|
|
40
|
+
defineEntity: DefineEntitySourceFile,
|
|
41
|
+
entitySchema: EntitySchemaSourceFile,
|
|
42
|
+
decorators: SourceFile,
|
|
43
|
+
};
|
|
44
|
+
if (options.entityDefinition !== 'decorators') {
|
|
45
|
+
options.scalarTypeInDecorator = true;
|
|
46
|
+
}
|
|
35
47
|
for (const meta of metadata) {
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
this.sources.push(new EntitySchemaSourceFile(meta, this.namingStrategy, this.platform, { ...options, scalarTypeInDecorator: true }));
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
this.sources.push(new SourceFile(meta, this.namingStrategy, this.platform, options));
|
|
42
|
-
}
|
|
48
|
+
if (meta.pivotTable && !options.outputPurePivotTables && !this.referencedEntities.has(meta)) {
|
|
49
|
+
continue;
|
|
43
50
|
}
|
|
51
|
+
this.sources.push(new map[options.entityDefinition](meta, this.namingStrategy, this.platform, options));
|
|
44
52
|
}
|
|
53
|
+
for (const nativeEnum of Object.values(schema.getNativeEnums())) {
|
|
54
|
+
this.sources.push(new NativeEnumSourceFile({}, this.namingStrategy, this.platform, options, nativeEnum));
|
|
55
|
+
}
|
|
56
|
+
const files = this.sources.map(file => [file.getBaseName(), file.generate()]);
|
|
45
57
|
if (options.save) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
fs.ensureDir(baseDir);
|
|
59
|
+
const promises = [];
|
|
60
|
+
for (const [fileName, data] of files) {
|
|
61
|
+
promises.push((async () => {
|
|
62
|
+
const fileDir = dirname(fileName);
|
|
63
|
+
if (fileDir !== '.') {
|
|
64
|
+
fs.ensureDir(join(baseDir, fileDir));
|
|
65
|
+
}
|
|
66
|
+
await writeFile(join(baseDir, fileName), data, { flush: true });
|
|
67
|
+
})());
|
|
68
|
+
}
|
|
69
|
+
await Promise.all(promises);
|
|
55
70
|
}
|
|
56
|
-
return
|
|
71
|
+
return files.map(([, data]) => data);
|
|
57
72
|
}
|
|
58
73
|
async getEntityMetadata(schema, options) {
|
|
59
74
|
const metadata = schema.getTables()
|
|
@@ -2,7 +2,8 @@ import { type Dictionary, type EntityProperty } from '@mikro-orm/core';
|
|
|
2
2
|
import { SourceFile } from './SourceFile.js';
|
|
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
|
}
|
|
@@ -2,21 +2,56 @@ import { Config, ReferenceKind, } from '@mikro-orm/core';
|
|
|
2
2
|
import { SourceFile } from './SourceFile.js';
|
|
3
3
|
export class EntitySchemaSourceFile extends SourceFile {
|
|
4
4
|
generate() {
|
|
5
|
+
const classDefinition = this.generateClassDefinition();
|
|
6
|
+
const enumDefinitions = [];
|
|
7
|
+
for (const prop of Object.values(this.meta.properties)) {
|
|
8
|
+
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === ReferenceKind.SCALAR)) {
|
|
9
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
10
|
+
if (def.length) {
|
|
11
|
+
enumDefinitions.push(def);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
let ret = classDefinition;
|
|
16
|
+
if (enumDefinitions.length) {
|
|
17
|
+
ret += '\n' + enumDefinitions.join('\n');
|
|
18
|
+
}
|
|
19
|
+
ret += `\n`;
|
|
20
|
+
const entitySchemaOptions = {
|
|
21
|
+
class: this.meta.className,
|
|
22
|
+
...(this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})),
|
|
23
|
+
};
|
|
24
|
+
const declLine = `export const ${this.meta.className}Schema = new ${this.referenceCoreImport('EntitySchema')}(`;
|
|
25
|
+
ret += declLine;
|
|
26
|
+
if (this.meta.indexes.length > 0) {
|
|
27
|
+
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
28
|
+
}
|
|
29
|
+
if (this.meta.uniques.length > 0) {
|
|
30
|
+
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
31
|
+
}
|
|
32
|
+
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyOptions(prop)]));
|
|
33
|
+
// Force top level and properties to be indented, regardless of line length
|
|
34
|
+
entitySchemaOptions[Config] = true;
|
|
35
|
+
entitySchemaOptions.properties[Config] = true;
|
|
36
|
+
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
37
|
+
ret += ');\n';
|
|
38
|
+
ret = `${this.generateImports()}\n\n${ret}`;
|
|
39
|
+
return ret;
|
|
40
|
+
}
|
|
41
|
+
generateClassDefinition() {
|
|
5
42
|
let classBody = '';
|
|
6
|
-
if (this.meta.className === this.options.customBaseEntityName) {
|
|
43
|
+
if (!this.options.customBaseEntityName || this.meta.className === this.options.customBaseEntityName) {
|
|
7
44
|
const defineConfigTypeSettings = {};
|
|
8
45
|
defineConfigTypeSettings.forceObject = this.platform.getConfig().get('serialization').forceObject ?? false;
|
|
9
|
-
|
|
46
|
+
if (defineConfigTypeSettings.forceObject) {
|
|
47
|
+
classBody += `${' '.repeat(2)}[${this.referenceCoreImport('Config')}]?: ${this.referenceCoreImport('DefineConfig')}<${this.serializeObject(defineConfigTypeSettings)}>;\n`;
|
|
48
|
+
}
|
|
10
49
|
}
|
|
11
|
-
const enumDefinitions = [];
|
|
12
50
|
const eagerProperties = [];
|
|
13
51
|
const primaryProps = [];
|
|
14
52
|
const props = [];
|
|
15
53
|
for (const prop of Object.values(this.meta.properties)) {
|
|
16
54
|
props.push(this.getPropertyDefinition(prop, 2));
|
|
17
|
-
if (prop.enum && (typeof prop.kind === 'undefined' || prop.kind === ReferenceKind.SCALAR)) {
|
|
18
|
-
enumDefinitions.push(this.getEnumClassDefinition(prop, 2));
|
|
19
|
-
}
|
|
20
55
|
if (prop.eager) {
|
|
21
56
|
eagerProperties.push(prop);
|
|
22
57
|
}
|
|
@@ -38,33 +73,9 @@ export class EntitySchemaSourceFile extends SourceFile {
|
|
|
38
73
|
classBody += `${' '.repeat(2)}[${this.referenceCoreImport('EagerProps')}]?: ${eagerPropertyNames.join(' | ')};\n`;
|
|
39
74
|
}
|
|
40
75
|
classBody += `${props.join('')}`;
|
|
41
|
-
|
|
42
|
-
if (enumDefinitions.length) {
|
|
43
|
-
ret += '\n' + enumDefinitions.join('\n');
|
|
44
|
-
}
|
|
45
|
-
ret += `\n`;
|
|
46
|
-
const entitySchemaOptions = {
|
|
47
|
-
class: this.meta.className,
|
|
48
|
-
...(this.meta.embeddable ? this.getEmbeddableDeclOptions() : (this.meta.collection ? this.getEntityDeclOptions() : {})),
|
|
49
|
-
};
|
|
50
|
-
const declLine = `export const ${this.meta.className}Schema = new ${this.referenceCoreImport('EntitySchema')}(`;
|
|
51
|
-
ret += declLine;
|
|
52
|
-
if (this.meta.indexes.length > 0) {
|
|
53
|
-
entitySchemaOptions.indexes = this.meta.indexes.map(index => this.getIndexOptions(index));
|
|
54
|
-
}
|
|
55
|
-
if (this.meta.uniques.length > 0) {
|
|
56
|
-
entitySchemaOptions.uniques = this.meta.uniques.map(index => this.getUniqueOptions(index));
|
|
57
|
-
}
|
|
58
|
-
entitySchemaOptions.properties = Object.fromEntries(Object.entries(this.meta.properties).map(([name, prop]) => [name, this.getPropertyOptions(prop)]));
|
|
59
|
-
// Force top level and properties to be indented, regardless of line length
|
|
60
|
-
entitySchemaOptions[Config] = true;
|
|
61
|
-
entitySchemaOptions.properties[Config] = true;
|
|
62
|
-
ret += this.serializeObject(entitySchemaOptions, declLine.length > 80 ? undefined : 80 - declLine.length, 0);
|
|
63
|
-
ret += ');\n';
|
|
64
|
-
ret = `${this.generateImports()}\n\n${ret}`;
|
|
65
|
-
return ret;
|
|
76
|
+
return this.getEntityClass(classBody);
|
|
66
77
|
}
|
|
67
|
-
getPropertyOptions(prop) {
|
|
78
|
+
getPropertyOptions(prop, quote = true) {
|
|
68
79
|
const options = {};
|
|
69
80
|
if (prop.primary) {
|
|
70
81
|
options.primary = true;
|
|
@@ -79,7 +90,7 @@ export class EntitySchemaSourceFile extends SourceFile {
|
|
|
79
90
|
this.getOneToManyDecoratorOptions(options, prop);
|
|
80
91
|
}
|
|
81
92
|
else if (prop.kind === ReferenceKind.SCALAR || typeof prop.kind === 'undefined') {
|
|
82
|
-
this.getScalarPropertyDecoratorOptions(options, prop);
|
|
93
|
+
this.getScalarPropertyDecoratorOptions(options, prop, quote);
|
|
83
94
|
}
|
|
84
95
|
else if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
85
96
|
this.getEmbeddedPropertyDeclarationOptions(options, prop);
|
|
@@ -123,14 +134,14 @@ export class EntitySchemaSourceFile extends SourceFile {
|
|
|
123
134
|
processIndex('index');
|
|
124
135
|
processIndex('unique');
|
|
125
136
|
}
|
|
126
|
-
getScalarPropertyDecoratorOptions(options, prop) {
|
|
137
|
+
getScalarPropertyDecoratorOptions(options, prop, quote = true) {
|
|
127
138
|
if (prop.enum) {
|
|
128
139
|
options.enum = true;
|
|
129
140
|
options.items = `() => ${prop.runtimeType}`;
|
|
130
141
|
}
|
|
131
142
|
else {
|
|
132
|
-
options.type = this.quote(prop.type);
|
|
143
|
+
options.type = quote ? this.quote(prop.type) : prop.type;
|
|
133
144
|
}
|
|
134
|
-
super.getScalarPropertyDecoratorOptions(options, prop);
|
|
145
|
+
super.getScalarPropertyDecoratorOptions(options, prop, quote);
|
|
135
146
|
}
|
|
136
147
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EntityMetadata, GenerateOptions, NamingStrategy, Platform } from '@mikro-orm/core';
|
|
2
|
+
import { SourceFile } from './SourceFile.js';
|
|
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,47 @@
|
|
|
1
|
+
import { identifierRegex, SourceFile } from './SourceFile.js';
|
|
2
|
+
export class NativeEnumSourceFile extends SourceFile {
|
|
3
|
+
nativeEnum;
|
|
4
|
+
constructor(meta, namingStrategy, platform, options, nativeEnum) {
|
|
5
|
+
super(meta, namingStrategy, platform, options);
|
|
6
|
+
this.nativeEnum = nativeEnum;
|
|
7
|
+
}
|
|
8
|
+
generate() {
|
|
9
|
+
const enumClassName = this.namingStrategy.getEnumClassName(this.nativeEnum.name, undefined, this.nativeEnum.schema);
|
|
10
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(this.nativeEnum.name, undefined, this.nativeEnum.schema);
|
|
11
|
+
const padding = ' ';
|
|
12
|
+
const enumMode = this.options.enumMode;
|
|
13
|
+
const enumValues = this.nativeEnum.items;
|
|
14
|
+
if (enumMode === 'union-type') {
|
|
15
|
+
return `export type ${enumTypeName} = ${enumValues.map(item => this.quote(item)).join(' | ')};\n`;
|
|
16
|
+
}
|
|
17
|
+
let ret = '';
|
|
18
|
+
if (enumMode === 'dictionary') {
|
|
19
|
+
ret += `export const ${enumClassName} = {\n`;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
ret += `export enum ${enumClassName} {\n`;
|
|
23
|
+
}
|
|
24
|
+
for (const enumValue of enumValues) {
|
|
25
|
+
const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, this.nativeEnum.name, '', this.nativeEnum.schema);
|
|
26
|
+
if (enumMode === 'dictionary') {
|
|
27
|
+
ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${this.quote(enumValue)},\n`;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${this.quote(enumValue)},\n`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (enumMode === 'dictionary') {
|
|
34
|
+
ret += '} as const;\n';
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
ret += '}\n';
|
|
38
|
+
}
|
|
39
|
+
if (enumMode === 'dictionary') {
|
|
40
|
+
ret += `\nexport type ${enumTypeName} = (typeof ${enumClassName})[keyof typeof ${enumClassName}];\n`;
|
|
41
|
+
}
|
|
42
|
+
return ret;
|
|
43
|
+
}
|
|
44
|
+
getBaseName(extension = '.ts') {
|
|
45
|
+
return `${this.options.fileName(this.nativeEnum.name)}${extension}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
package/README.md
CHANGED
|
@@ -11,7 +11,6 @@ TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-or
|
|
|
11
11
|
[](https://discord.gg/w8bjxFHS7X)
|
|
12
12
|
[](https://www.npmjs.com/package/@mikro-orm/core)
|
|
13
13
|
[](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
|
|
14
|
-
[](https://codeclimate.com/github/mikro-orm/mikro-orm/maintainability)
|
|
15
14
|
[](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
|
|
16
15
|
|
|
17
16
|
## 🤔 Unit of What?
|
|
@@ -141,7 +140,7 @@ There is also auto-generated [CHANGELOG.md](CHANGELOG.md) file based on commit m
|
|
|
141
140
|
- [Composite and Foreign Keys as Primary Key](https://mikro-orm.io/docs/composite-keys)
|
|
142
141
|
- [Filters](https://mikro-orm.io/docs/filters)
|
|
143
142
|
- [Using `QueryBuilder`](https://mikro-orm.io/docs/query-builder)
|
|
144
|
-
- [
|
|
143
|
+
- [Populating relations](https://mikro-orm.io/docs/populating-relations)
|
|
145
144
|
- [Property Validation](https://mikro-orm.io/docs/property-validation)
|
|
146
145
|
- [Lifecycle Hooks](https://mikro-orm.io/docs/events#hooks)
|
|
147
146
|
- [Vanilla JS Support](https://mikro-orm.io/docs/usage-with-js)
|
|
@@ -382,6 +381,8 @@ See also the list of contributors who [participated](https://github.com/mikro-or
|
|
|
382
381
|
|
|
383
382
|
Please ⭐️ this repository if this project helped you!
|
|
384
383
|
|
|
384
|
+
> If you'd like to support my open-source work, consider sponsoring me directly at [github.com/sponsors/b4nan](https://github.com/sponsors/b4nan).
|
|
385
|
+
|
|
385
386
|
## 📝 License
|
|
386
387
|
|
|
387
388
|
Copyright © 2018 [Martin Adámek](https://github.com/b4nan).
|
package/SourceFile.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare class SourceFile {
|
|
|
9
9
|
protected readonly platform: Platform;
|
|
10
10
|
protected readonly options: GenerateOptions;
|
|
11
11
|
protected readonly coreImports: Set<string>;
|
|
12
|
+
protected readonly decoratorImports: Set<string>;
|
|
12
13
|
protected readonly entityImports: Set<string>;
|
|
14
|
+
protected readonly enumImports: Map<string, string[]>;
|
|
13
15
|
constructor(meta: EntityMetadata, namingStrategy: NamingStrategy, platform: Platform, options: GenerateOptions);
|
|
14
16
|
generate(): string;
|
|
15
17
|
protected getIndexOptions(index: EntityMetadata['indexes'][number], isAtEntityLevel?: boolean): IndexOptions<Dictionary, string>;
|
|
@@ -30,11 +32,12 @@ export declare class SourceFile {
|
|
|
30
32
|
protected getCommonDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
31
33
|
private propTypeBreakdowns;
|
|
32
34
|
private breakdownOfIType;
|
|
33
|
-
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
35
|
+
protected getScalarPropertyDecoratorOptions(options: Dictionary, prop: EntityProperty, quote?: boolean): void;
|
|
34
36
|
protected getManyToManyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
35
37
|
protected getOneToManyDecoratorOptions(options: Dictionary, prop: EntityProperty): void;
|
|
36
38
|
protected getEmbeddedPropertyDeclarationOptions(options: Dictionary, prop: EntityProperty): void;
|
|
37
39
|
protected getForeignKeyDecoratorOptions(options: OneToOneOptions<any, any>, prop: EntityProperty): void;
|
|
38
40
|
protected getDecoratorType(prop: EntityProperty): string;
|
|
39
41
|
protected referenceCoreImport(identifier: string): string;
|
|
42
|
+
protected referenceDecoratorImport(identifier: string): string;
|
|
40
43
|
}
|
package/SourceFile.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { Cascade, Config, DecimalType, ReferenceKind, SCALAR_TYPES, UnknownType, Utils, } from '@mikro-orm/core';
|
|
1
|
+
import { Cascade, Config, DecimalType, ReferenceKind, SCALAR_TYPES, UnknownType, Utils, inspect, } from '@mikro-orm/core';
|
|
2
2
|
import { parse, relative } from 'node:path';
|
|
3
|
-
import { inspect } from 'node:util';
|
|
4
3
|
import { POSSIBLE_TYPE_IMPORTS } from './CoreImportsHelper.js';
|
|
5
4
|
/**
|
|
6
5
|
* @see https://github.com/tc39/proposal-regexp-unicode-property-escapes#other-examples
|
|
7
6
|
*/
|
|
8
7
|
export const identifierRegex = /^(?:[$_\p{ID_Start}])(?:[$\u200C\u200D\p{ID_Continue}])*$/u;
|
|
9
|
-
const primitivesAndLibs = [...SCALAR_TYPES, '
|
|
8
|
+
const primitivesAndLibs = [...SCALAR_TYPES, 'unknown', 'object', 'any'];
|
|
10
9
|
export class SourceFile {
|
|
11
10
|
meta;
|
|
12
11
|
namingStrategy;
|
|
13
12
|
platform;
|
|
14
13
|
options;
|
|
15
14
|
coreImports = new Set();
|
|
15
|
+
decoratorImports = new Set();
|
|
16
16
|
entityImports = new Set();
|
|
17
|
+
enumImports = new Map();
|
|
17
18
|
constructor(meta, namingStrategy, platform, options) {
|
|
18
19
|
this.meta = meta;
|
|
19
20
|
this.namingStrategy = namingStrategy;
|
|
@@ -25,24 +26,24 @@ export class SourceFile {
|
|
|
25
26
|
if (this.meta.embeddable || this.meta.collection) {
|
|
26
27
|
if (this.meta.embeddable) {
|
|
27
28
|
const options = this.getEmbeddableDeclOptions();
|
|
28
|
-
ret += `@${this.
|
|
29
|
+
ret += `@${this.referenceDecoratorImport('Embeddable')}(${Utils.hasObjectKeys(options) ? this.serializeObject(options) : ''})\n`;
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
31
32
|
const options = this.getEntityDeclOptions();
|
|
32
|
-
ret += `@${this.
|
|
33
|
+
ret += `@${this.referenceDecoratorImport('Entity')}(${Utils.hasObjectKeys(options) ? this.serializeObject(options) : ''})\n`;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
for (const index of this.meta.indexes) {
|
|
36
37
|
if (index.properties?.length === 1 && typeof this.meta.properties[index.properties[0]] !== 'undefined') {
|
|
37
38
|
continue;
|
|
38
39
|
}
|
|
39
|
-
ret += `@${this.
|
|
40
|
+
ret += `@${this.referenceDecoratorImport('Index')}(${this.serializeObject(this.getIndexOptions(index))})\n`;
|
|
40
41
|
}
|
|
41
42
|
for (const index of this.meta.uniques) {
|
|
42
43
|
if (index.properties?.length === 1 && typeof this.meta.properties[index.properties[0]] !== 'undefined') {
|
|
43
44
|
continue;
|
|
44
45
|
}
|
|
45
|
-
ret += `@${this.
|
|
46
|
+
ret += `@${this.referenceDecoratorImport('Unique')}(${this.serializeObject(this.getUniqueOptions(index))})\n`;
|
|
46
47
|
}
|
|
47
48
|
let classHead = '';
|
|
48
49
|
if (this.meta.className === this.options.customBaseEntityName) {
|
|
@@ -65,7 +66,10 @@ export class SourceFile {
|
|
|
65
66
|
classBody += definition;
|
|
66
67
|
classBody += '\n';
|
|
67
68
|
if (prop.enum) {
|
|
68
|
-
|
|
69
|
+
const def = this.getEnumClassDefinition(prop, 2);
|
|
70
|
+
if (def.length) {
|
|
71
|
+
enumDefinitions.push(def);
|
|
72
|
+
}
|
|
69
73
|
}
|
|
70
74
|
if (prop.eager) {
|
|
71
75
|
eagerProperties.push(prop);
|
|
@@ -99,9 +103,12 @@ export class SourceFile {
|
|
|
99
103
|
if (typeof index.name === 'string') {
|
|
100
104
|
indexOpt.name = this.quote(index.name);
|
|
101
105
|
}
|
|
102
|
-
if (index.expression) {
|
|
106
|
+
if (typeof index.expression === 'string') {
|
|
103
107
|
indexOpt.expression = this.quote(index.expression);
|
|
104
108
|
}
|
|
109
|
+
else if (typeof index.expression === 'function') {
|
|
110
|
+
indexOpt.expression = `${index.expression}`.replace(')=>`', ') => `');
|
|
111
|
+
}
|
|
105
112
|
if (isAtEntityLevel && index.properties) {
|
|
106
113
|
indexOpt.properties = Utils.asArray(index.properties).map(prop => this.quote('' + prop));
|
|
107
114
|
}
|
|
@@ -112,9 +119,12 @@ export class SourceFile {
|
|
|
112
119
|
if (typeof index.name === 'string') {
|
|
113
120
|
uniqueOpt.name = this.quote(index.name);
|
|
114
121
|
}
|
|
115
|
-
if (index.expression) {
|
|
122
|
+
if (typeof index.expression === 'string') {
|
|
116
123
|
uniqueOpt.expression = this.quote(index.expression);
|
|
117
124
|
}
|
|
125
|
+
else if (typeof index.expression === 'function') {
|
|
126
|
+
uniqueOpt.expression = `${index.expression}`.replace(')=>`', ') => `');
|
|
127
|
+
}
|
|
118
128
|
if (isAtEntityLevel && index.properties) {
|
|
119
129
|
uniqueOpt.properties = Utils.asArray(index.properties).map(prop => this.quote('' + prop));
|
|
120
130
|
}
|
|
@@ -135,37 +145,61 @@ export class SourceFile {
|
|
|
135
145
|
return ret;
|
|
136
146
|
}).join(', '))} } from '@mikro-orm/core';`);
|
|
137
147
|
}
|
|
148
|
+
if (this.decoratorImports.size > 0) {
|
|
149
|
+
const type = this.options.decorators;
|
|
150
|
+
imports.add(`import { ${([...this.decoratorImports].sort().map(t => {
|
|
151
|
+
let ret = t;
|
|
152
|
+
if (this.options.coreImportsPrefix) {
|
|
153
|
+
const resolvedIdentifier = `${this.options.coreImportsPrefix}${t}`;
|
|
154
|
+
ret += ` as ${resolvedIdentifier}`;
|
|
155
|
+
}
|
|
156
|
+
return ret;
|
|
157
|
+
}).join(', '))} } from '@mikro-orm/decorators/${type}';`);
|
|
158
|
+
}
|
|
138
159
|
const extension = this.options.esmImport ? '.js' : '';
|
|
139
160
|
const { dir, base } = parse(`${this.options.path ?? '.'}/${this.getBaseName()}`);
|
|
140
161
|
const basePath = relative(dir, this.options.path ?? '.') || '.';
|
|
141
162
|
(this.options.extraImports?.(basePath, base) ?? []).forEach(v => this.entityImports.add(v));
|
|
142
163
|
const entityImports = [...this.entityImports].filter(e => e !== this.meta.className);
|
|
143
|
-
|
|
164
|
+
const importMap = new Map();
|
|
165
|
+
for (const entity of entityImports) {
|
|
144
166
|
const file = this.options.onImport?.(entity, basePath, extension, base) ?? {
|
|
145
167
|
path: `${basePath}/${this.options.fileName(entity)}${extension}`,
|
|
146
168
|
name: entity,
|
|
147
169
|
};
|
|
148
170
|
if (file.path === '') {
|
|
149
171
|
if (file.name === '') {
|
|
150
|
-
|
|
172
|
+
continue;
|
|
151
173
|
}
|
|
152
|
-
|
|
153
|
-
|
|
174
|
+
importMap.set(file.path, `import ${this.quote(file.name)};`);
|
|
175
|
+
continue;
|
|
154
176
|
}
|
|
155
177
|
if (file.name === '') {
|
|
156
|
-
|
|
157
|
-
|
|
178
|
+
importMap.set(file.path, `import * as ${entity} from ${this.quote(file.path)};`);
|
|
179
|
+
continue;
|
|
158
180
|
}
|
|
159
181
|
if (file.name === 'default') {
|
|
160
|
-
|
|
161
|
-
|
|
182
|
+
importMap.set(file.path, `import ${entity} from ${this.quote(file.path)};`);
|
|
183
|
+
continue;
|
|
162
184
|
}
|
|
163
185
|
if (file.name === entity) {
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
importMap.set(file.path, `import { ${entity} } from ${this.quote(file.path)};`);
|
|
187
|
+
continue;
|
|
166
188
|
}
|
|
167
|
-
|
|
168
|
-
}
|
|
189
|
+
importMap.set(file.path, `import { ${identifierRegex.test(file.name) ? file.name : this.quote(file.name)} as ${entity} } from ${this.quote(file.path)};`);
|
|
190
|
+
}
|
|
191
|
+
if (this.enumImports.size) {
|
|
192
|
+
for (const [name, exports] of this.enumImports.entries()) {
|
|
193
|
+
const file = this.options.onImport?.(name, basePath, extension, base) ?? {
|
|
194
|
+
path: `${basePath}/${this.options.fileName(name)}${extension}`,
|
|
195
|
+
name,
|
|
196
|
+
};
|
|
197
|
+
importMap.set(file.path, `import { ${exports.join(', ')} } from ${this.quote(file.path)};`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const key of [...importMap.keys()].sort()) {
|
|
201
|
+
imports.add(importMap.get(key));
|
|
202
|
+
}
|
|
169
203
|
return Array.from(imports.values()).join('\n');
|
|
170
204
|
}
|
|
171
205
|
getEntityClass(classBody) {
|
|
@@ -195,6 +229,7 @@ export class SourceFile {
|
|
|
195
229
|
getPropertyDefinition(prop, padLeft) {
|
|
196
230
|
const padding = ' '.repeat(padLeft);
|
|
197
231
|
const propName = identifierRegex.test(prop.name) ? prop.name : this.quote(prop.name);
|
|
232
|
+
const enumMode = this.options.enumMode;
|
|
198
233
|
let hiddenType = '';
|
|
199
234
|
if (prop.hidden) {
|
|
200
235
|
hiddenType += ` & ${this.referenceCoreImport('Hidden')}`;
|
|
@@ -212,7 +247,11 @@ export class SourceFile {
|
|
|
212
247
|
: (() => {
|
|
213
248
|
if (isScalar) {
|
|
214
249
|
if (prop.enum) {
|
|
215
|
-
|
|
250
|
+
const method = enumMode === 'ts-enum' ? 'getEnumClassName' : 'getEnumTypeName';
|
|
251
|
+
if (prop.nativeEnumName) {
|
|
252
|
+
return this.namingStrategy[method](prop.nativeEnumName, undefined, this.meta.schema);
|
|
253
|
+
}
|
|
254
|
+
return this.namingStrategy[method](prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
216
255
|
}
|
|
217
256
|
breakdownOfIType = this.breakdownOfIType(prop);
|
|
218
257
|
if (typeof breakdownOfIType !== 'undefined') {
|
|
@@ -247,8 +286,14 @@ export class SourceFile {
|
|
|
247
286
|
return `${padding}${ret};\n`;
|
|
248
287
|
}
|
|
249
288
|
if (prop.enum && typeof prop.default === 'string') {
|
|
289
|
+
if (enumMode === 'union-type') {
|
|
290
|
+
return `${padding}${ret} = ${this.quote(prop.default)};\n`;
|
|
291
|
+
}
|
|
292
|
+
const enumClassName = prop.nativeEnumName
|
|
293
|
+
? this.namingStrategy.getEnumClassName(prop.nativeEnumName, undefined, this.meta.schema)
|
|
294
|
+
: this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
250
295
|
const enumVal = this.namingStrategy.enumValueToEnumProperty(prop.default, prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
251
|
-
return `${padding}${ret} = ${
|
|
296
|
+
return `${padding}${ret} = ${enumClassName}${identifierRegex.test(enumVal) ? `.${enumVal}` : `[${this.quote(enumVal)}]`};\n`;
|
|
252
297
|
}
|
|
253
298
|
if (prop.fieldNames?.length > 1) {
|
|
254
299
|
// TODO: Composite FKs with default values require additions to default/defaultRaw that are not yet supported.
|
|
@@ -264,15 +309,51 @@ export class SourceFile {
|
|
|
264
309
|
return `${padding}${ret} = ${prop.ref ? this.referenceCoreImport('ref') : this.referenceCoreImport('rel')}(${propType}, ${defaultVal});\n`;
|
|
265
310
|
}
|
|
266
311
|
getEnumClassDefinition(prop, padLeft) {
|
|
312
|
+
const enumMode = this.options.enumMode;
|
|
313
|
+
if (prop.nativeEnumName) {
|
|
314
|
+
const imports = [];
|
|
315
|
+
if (enumMode !== 'union-type') {
|
|
316
|
+
imports.push(prop.runtimeType);
|
|
317
|
+
}
|
|
318
|
+
if (!this.options.inferEntityType && enumMode !== 'ts-enum') {
|
|
319
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(prop.nativeEnumName, undefined, this.meta.schema);
|
|
320
|
+
imports.push(enumTypeName);
|
|
321
|
+
}
|
|
322
|
+
this.enumImports.set(prop.runtimeType, imports);
|
|
323
|
+
return '';
|
|
324
|
+
}
|
|
267
325
|
const enumClassName = this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
326
|
+
const enumTypeName = this.namingStrategy.getEnumTypeName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
268
327
|
const padding = ' '.repeat(padLeft);
|
|
269
|
-
let ret = `export enum ${enumClassName} {\n`;
|
|
270
328
|
const enumValues = prop.items;
|
|
329
|
+
if (enumMode === 'union-type') {
|
|
330
|
+
return `export type ${enumTypeName} = ${enumValues.map(item => this.quote(item)).join(' | ')};\n`;
|
|
331
|
+
}
|
|
332
|
+
let ret = '';
|
|
333
|
+
if (enumMode === 'dictionary') {
|
|
334
|
+
ret += `export const ${enumClassName} = {\n`;
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
ret += `export enum ${enumClassName} {\n`;
|
|
338
|
+
}
|
|
271
339
|
for (const enumValue of enumValues) {
|
|
272
340
|
const enumName = this.namingStrategy.enumValueToEnumProperty(enumValue, prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
273
|
-
|
|
341
|
+
if (enumMode === 'dictionary') {
|
|
342
|
+
ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)}: ${this.quote(enumValue)},\n`;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
ret += `${padding}${identifierRegex.test(enumName) ? enumName : this.quote(enumName)} = ${this.quote(enumValue)},\n`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (enumMode === 'dictionary') {
|
|
349
|
+
ret += '} as const;\n';
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
ret += '}\n';
|
|
353
|
+
}
|
|
354
|
+
if (enumMode === 'dictionary') {
|
|
355
|
+
ret += `\nexport type ${enumTypeName} = (typeof ${enumClassName})[keyof typeof ${enumClassName}];\n`;
|
|
274
356
|
}
|
|
275
|
-
ret += '}\n';
|
|
276
357
|
return ret;
|
|
277
358
|
}
|
|
278
359
|
serializeObject(options, wordwrap, spaces, level = 0) {
|
|
@@ -312,7 +393,7 @@ export class SourceFile {
|
|
|
312
393
|
options.expression = this.quote(this.meta.expression);
|
|
313
394
|
}
|
|
314
395
|
else if (typeof this.meta.expression === 'function') {
|
|
315
|
-
options.expression =
|
|
396
|
+
options.expression = this.meta.expression.toString();
|
|
316
397
|
}
|
|
317
398
|
if (this.meta.repositoryClass) {
|
|
318
399
|
this.entityImports.add(this.meta.repositoryClass);
|
|
@@ -352,7 +433,7 @@ export class SourceFile {
|
|
|
352
433
|
getPropertyDecorator(prop, padLeft) {
|
|
353
434
|
const padding = ' '.repeat(padLeft);
|
|
354
435
|
const options = {};
|
|
355
|
-
let decorator = `@${this.
|
|
436
|
+
let decorator = `@${this.referenceDecoratorImport(this.getDecoratorType(prop))}`;
|
|
356
437
|
if (prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
357
438
|
this.getManyToManyDecoratorOptions(options, prop);
|
|
358
439
|
}
|
|
@@ -373,7 +454,7 @@ export class SourceFile {
|
|
|
373
454
|
decorator = [...indexes.sort(), decorator].map(d => padding + d).join('\n');
|
|
374
455
|
const decoratorArgs = [];
|
|
375
456
|
if (prop.formula) {
|
|
376
|
-
decoratorArgs.push(
|
|
457
|
+
decoratorArgs.push(prop.formula.toString());
|
|
377
458
|
}
|
|
378
459
|
if (Utils.hasObjectKeys(options)) {
|
|
379
460
|
decoratorArgs.push(`${this.serializeObject(options)}`);
|
|
@@ -402,26 +483,26 @@ export class SourceFile {
|
|
|
402
483
|
let propIndexIsNonTrivialIndex = false;
|
|
403
484
|
const nonTrivialIndexes = this.meta.indexes.filter(i => i.properties?.length === 1 && i.properties[0] === prop.name);
|
|
404
485
|
for (const i of nonTrivialIndexes) {
|
|
405
|
-
ret.push(`@${this.
|
|
486
|
+
ret.push(`@${this.referenceDecoratorImport('Index')}(${this.serializeObject(this.getIndexOptions(i, false))})`);
|
|
406
487
|
if (prop.index === i.name) {
|
|
407
488
|
propIndexIsNonTrivialIndex = true;
|
|
408
489
|
delete options.index;
|
|
409
490
|
}
|
|
410
491
|
}
|
|
411
492
|
if (prop.index && !options.index && !propIndexIsNonTrivialIndex) {
|
|
412
|
-
ret.push(`@${this.
|
|
493
|
+
ret.push(`@${this.referenceDecoratorImport('Index')}(${typeof prop.index === 'string' ? `{ name: ${this.quote(prop.index)} }` : ''})`);
|
|
413
494
|
}
|
|
414
495
|
let propIndexIsNonTrivialUnique = false;
|
|
415
496
|
const nonTrivialUnique = this.meta.uniques.filter(i => i.properties?.length === 1 && i.properties[0] === prop.name);
|
|
416
497
|
for (const i of nonTrivialUnique) {
|
|
417
|
-
ret.push(`@${this.
|
|
498
|
+
ret.push(`@${this.referenceDecoratorImport('Unique')}(${this.serializeObject(this.getUniqueOptions(i, false))})`);
|
|
418
499
|
if (prop.unique === i.name) {
|
|
419
500
|
propIndexIsNonTrivialUnique = true;
|
|
420
501
|
delete options.unique;
|
|
421
502
|
}
|
|
422
503
|
}
|
|
423
504
|
if (prop.unique && !options.unique && !propIndexIsNonTrivialUnique) {
|
|
424
|
-
ret.push(`@${this.
|
|
505
|
+
ret.push(`@${this.referenceDecoratorImport('Unique')}(${typeof prop.unique === 'string' ? `{ name: ${this.quote(prop.unique)} }` : ''})`);
|
|
425
506
|
}
|
|
426
507
|
return ret;
|
|
427
508
|
}
|
|
@@ -432,7 +513,7 @@ export class SourceFile {
|
|
|
432
513
|
if (prop.primary && (prop.enum || !(typeof prop.kind === 'undefined' || prop.kind === ReferenceKind.SCALAR))) {
|
|
433
514
|
options.primary = true;
|
|
434
515
|
}
|
|
435
|
-
['persist', 'hydrate'
|
|
516
|
+
['persist', 'hydrate']
|
|
436
517
|
.filter(key => prop[key] === false)
|
|
437
518
|
.forEach(key => options[key] = false);
|
|
438
519
|
['onCreate', 'onUpdate', 'serializer']
|
|
@@ -531,12 +612,23 @@ export class SourceFile {
|
|
|
531
612
|
this.propTypeBreakdowns.set(prop, r);
|
|
532
613
|
return r;
|
|
533
614
|
}
|
|
534
|
-
getScalarPropertyDecoratorOptions(options, prop) {
|
|
615
|
+
getScalarPropertyDecoratorOptions(options, prop, quote = true) {
|
|
535
616
|
if (prop.fieldNames[0] !== this.namingStrategy.propertyToColumnName(prop.name)) {
|
|
536
617
|
options.fieldName = this.quote(prop.fieldNames[0]);
|
|
537
618
|
}
|
|
538
619
|
if (prop.enum) {
|
|
539
|
-
options.
|
|
620
|
+
if (this.options.enumMode === 'union-type') {
|
|
621
|
+
options.items = `[${prop.items.map(item => this.quote(item)).join(', ')}]`;
|
|
622
|
+
}
|
|
623
|
+
else if (prop.nativeEnumName) {
|
|
624
|
+
const enumClassName = this.namingStrategy.getEnumClassName(prop.nativeEnumName, undefined, this.meta.schema);
|
|
625
|
+
options.items = `() => ${enumClassName}`;
|
|
626
|
+
options.nativeEnumName = this.quote(prop.nativeEnumName);
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
const enumClassName = this.namingStrategy.getEnumClassName(prop.fieldNames[0], this.meta.collection, this.meta.schema);
|
|
630
|
+
options.items = `() => ${enumClassName}`;
|
|
631
|
+
}
|
|
540
632
|
}
|
|
541
633
|
// For enum properties, we don't need a column type
|
|
542
634
|
// or the property length or other information in the decorator.
|
|
@@ -565,7 +657,7 @@ export class SourceFile {
|
|
|
565
657
|
return ((useDefault && !hasUsableNullDefault) || (prop.optional && !prop.nullable));
|
|
566
658
|
})() // also when there is the "| Opt" type modifier (because reflect-metadata can't extract the base)
|
|
567
659
|
) {
|
|
568
|
-
options.type = this.quote(prop.type);
|
|
660
|
+
options.type = quote ? this.quote(prop.type) : prop.type;
|
|
569
661
|
}
|
|
570
662
|
}
|
|
571
663
|
const columnTypeFromMappedRuntimeType = mappedRuntimeType.getColumnType({ ...prop, autoincrement: false }, this.platform);
|
|
@@ -592,7 +684,7 @@ export class SourceFile {
|
|
|
592
684
|
assign('length');
|
|
593
685
|
}
|
|
594
686
|
// those are already included in the `columnType` in most cases, and when that option is present, they would be ignored anyway
|
|
595
|
-
/* v8 ignore next
|
|
687
|
+
/* v8 ignore next */
|
|
596
688
|
if (mappedColumnType instanceof DecimalType && !options.columnType) {
|
|
597
689
|
assign('precision');
|
|
598
690
|
assign('scale');
|
|
@@ -666,7 +758,7 @@ export class SourceFile {
|
|
|
666
758
|
if (prop.array) {
|
|
667
759
|
options.array = true;
|
|
668
760
|
}
|
|
669
|
-
if (prop.object) {
|
|
761
|
+
if (prop.object && !prop.array) {
|
|
670
762
|
options.object = true;
|
|
671
763
|
}
|
|
672
764
|
if (prop.prefix === false || typeof prop.prefix === 'string') {
|
|
@@ -749,4 +841,10 @@ export class SourceFile {
|
|
|
749
841
|
? `${this.options.coreImportsPrefix}${identifier}`
|
|
750
842
|
: identifier;
|
|
751
843
|
}
|
|
844
|
+
referenceDecoratorImport(identifier) {
|
|
845
|
+
this.decoratorImports.add(identifier);
|
|
846
|
+
return this.options.coreImportsPrefix
|
|
847
|
+
? `${this.options.coreImportsPrefix}${identifier}`
|
|
848
|
+
: identifier;
|
|
849
|
+
}
|
|
752
850
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/entity-generator",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.91",
|
|
5
5
|
"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.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://mikro-orm.io",
|
|
40
40
|
"engines": {
|
|
41
|
-
"node": ">= 22.
|
|
41
|
+
"node": ">= 22.17.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "yarn clean && yarn compile && yarn copy",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@mikro-orm/knex": "7.0.0-dev.
|
|
53
|
+
"@mikro-orm/knex": "7.0.0-dev.91"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@mikro-orm/core": "^6.
|
|
56
|
+
"@mikro-orm/core": "^6.6.2"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@mikro-orm/core": "7.0.0-dev.
|
|
59
|
+
"@mikro-orm/core": "7.0.0-dev.91"
|
|
60
60
|
}
|
|
61
61
|
}
|