@mikro-orm/core 7.1.14 → 7.1.15-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/EntityManager.js +6 -2
- package/entity/EntityRepository.js +5 -1
- package/errors.d.ts +1 -0
- package/errors.js +3 -0
- package/events/EventManager.js +6 -3
- package/metadata/MetadataDiscovery.js +1 -1
- package/metadata/MetadataStorage.js +17 -1
- package/package.json +1 -1
- package/types/Type.js +4 -4
- package/utils/QueryHelper.js +1 -1
- package/utils/Utils.d.ts +11 -1
- package/utils/Utils.js +16 -1
package/EntityManager.js
CHANGED
|
@@ -260,7 +260,7 @@ export class EntityManager {
|
|
|
260
260
|
addFilter(options) {
|
|
261
261
|
options = { ...options };
|
|
262
262
|
if (options.entity) {
|
|
263
|
-
options.entity = Utils.asArray(options.entity).map(n => Utils.
|
|
263
|
+
options.entity = Utils.asArray(options.entity).map(n => Utils.classOrName(n));
|
|
264
264
|
}
|
|
265
265
|
options.default ??= true;
|
|
266
266
|
this.getContext(false).#filters[options.name] = options;
|
|
@@ -2116,7 +2116,11 @@ export class EntityManager {
|
|
|
2116
2116
|
]) {
|
|
2117
2117
|
delete opts[k];
|
|
2118
2118
|
}
|
|
2119
|
-
|
|
2119
|
+
// the table name (plus discriminator value for STI) is stable across builds and processes,
|
|
2120
|
+
// unlike class names, which minifiers can mangle to the same short name for two entities
|
|
2121
|
+
const meta = this.metadata.find(entityName);
|
|
2122
|
+
const key = meta?.tableName ? [meta.schema, meta.tableName, meta.discriminatorValue] : Utils.className(entityName);
|
|
2123
|
+
return [key, method, opts, where];
|
|
2120
2124
|
}
|
|
2121
2125
|
/**
|
|
2122
2126
|
* @internal
|
|
@@ -223,7 +223,11 @@ export class EntityRepository {
|
|
|
223
223
|
}
|
|
224
224
|
const entityName = entities[0].constructor.name;
|
|
225
225
|
const repoType = Utils.className(this.entityName);
|
|
226
|
-
|
|
226
|
+
// compare class identity where possible, as minifiers can mangle two classes to the same name
|
|
227
|
+
const entityMeta = entities[0].__meta;
|
|
228
|
+
const repoMeta = this.getEntityManager().getMetadata?.().find(this.entityName);
|
|
229
|
+
const mismatch = entityMeta && repoMeta ? entityMeta.class !== repoMeta.class : entityName && repoType !== entityName;
|
|
230
|
+
if (mismatch) {
|
|
227
231
|
throw ValidationError.fromWrongRepositoryType(entityName, repoType, method);
|
|
228
232
|
}
|
|
229
233
|
}
|
package/errors.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
|
|
|
60
60
|
static duplicateFieldName(entityName: EntityName, names: [string, string][]): MetadataError;
|
|
61
61
|
static multipleDecorators(entityName: string, propertyName: string): MetadataError;
|
|
62
62
|
static missingMetadata(entity: string): MetadataError;
|
|
63
|
+
static ambiguousEntityName(className: string): MetadataError;
|
|
63
64
|
static invalidPrimaryKey(meta: EntityMetadata, prop: EntityProperty, requiredName: string): MetadataError;
|
|
64
65
|
static invalidManyToManyWithPivotEntity(meta1: EntityMetadata, prop1: EntityProperty, meta2: EntityMetadata, prop2: EntityProperty): MetadataError;
|
|
65
66
|
static targetIsAbstract(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
package/errors.js
CHANGED
|
@@ -195,6 +195,9 @@ export class MetadataError extends ValidationError {
|
|
|
195
195
|
static missingMetadata(entity) {
|
|
196
196
|
return new MetadataError(`Metadata for entity ${entity} not found`);
|
|
197
197
|
}
|
|
198
|
+
static ambiguousEntityName(className) {
|
|
199
|
+
return new MetadataError(`Entity name '${className}' is ambiguous, multiple discovered entity classes share it (possibly due to a minifier mangling class names). Use a class reference instead of a string name.`);
|
|
200
|
+
}
|
|
198
201
|
static invalidPrimaryKey(meta, prop, requiredName) {
|
|
199
202
|
return this.fromMessage(meta, prop, `has wrong field name, '${requiredName}' is required in current driver`);
|
|
200
203
|
}
|
package/events/EventManager.js
CHANGED
|
@@ -43,7 +43,10 @@ export class EventManager {
|
|
|
43
43
|
}));
|
|
44
44
|
for (const listener of this.#listeners[event] ?? new Set()) {
|
|
45
45
|
const entities = this.#entities.get(listener);
|
|
46
|
-
if (entities.size === 0 ||
|
|
46
|
+
if (entities.size === 0 ||
|
|
47
|
+
!entity ||
|
|
48
|
+
entities.has(entity.constructor) ||
|
|
49
|
+
entities.has(entity.constructor.name)) {
|
|
47
50
|
listeners.push(listener[event].bind(listener));
|
|
48
51
|
}
|
|
49
52
|
}
|
|
@@ -68,7 +71,7 @@ export class EventManager {
|
|
|
68
71
|
}
|
|
69
72
|
for (const listener of this.#listeners[event] ?? new Set()) {
|
|
70
73
|
const entities = this.#entities.get(listener);
|
|
71
|
-
if (entities.size === 0 || entities.has(meta.className)) {
|
|
74
|
+
if (entities.size === 0 || entities.has(meta.class) || entities.has(meta.className)) {
|
|
72
75
|
this.#cache.set(cacheKey, true);
|
|
73
76
|
return true;
|
|
74
77
|
}
|
|
@@ -84,6 +87,6 @@ export class EventManager {
|
|
|
84
87
|
if (!listener.getSubscribedEntities) {
|
|
85
88
|
return new Set();
|
|
86
89
|
}
|
|
87
|
-
return new Set(listener.getSubscribedEntities().map(name => Utils.
|
|
90
|
+
return new Set(listener.getSubscribedEntities().map(name => Utils.classOrName(name)));
|
|
88
91
|
}
|
|
89
92
|
}
|
|
@@ -2138,7 +2138,7 @@ export class MetadataDiscovery {
|
|
|
2138
2138
|
shouldForceConstructorUsage(meta) {
|
|
2139
2139
|
const forceConstructor = this.#config.get('forceEntityConstructor');
|
|
2140
2140
|
if (Array.isArray(forceConstructor)) {
|
|
2141
|
-
return forceConstructor.some(cls => Utils.
|
|
2141
|
+
return forceConstructor.some(cls => Utils.matchesEntity(cls, meta));
|
|
2142
2142
|
}
|
|
2143
2143
|
return forceConstructor;
|
|
2144
2144
|
}
|
|
@@ -17,6 +17,7 @@ export class MetadataStorage {
|
|
|
17
17
|
#idMap;
|
|
18
18
|
#classNameMap;
|
|
19
19
|
#uniqueNameMap;
|
|
20
|
+
#ambiguousNames = new Set();
|
|
20
21
|
constructor(metadata = {}) {
|
|
21
22
|
this.#idMap = {};
|
|
22
23
|
this.#uniqueNameMap = {};
|
|
@@ -64,6 +65,10 @@ export class MetadataStorage {
|
|
|
64
65
|
}
|
|
65
66
|
/** Returns metadata for the given entity, optionally initializing it if not found. */
|
|
66
67
|
get(entityName, init = false) {
|
|
68
|
+
// string lookups cannot be resolved when several classes were minified to the same name
|
|
69
|
+
if (typeof entityName === 'string' && this.#ambiguousNames.has(entityName)) {
|
|
70
|
+
throw MetadataError.ambiguousEntityName(entityName);
|
|
71
|
+
}
|
|
67
72
|
const exists = this.find(entityName);
|
|
68
73
|
if (exists) {
|
|
69
74
|
return exists;
|
|
@@ -99,7 +104,13 @@ export class MetadataStorage {
|
|
|
99
104
|
this.#metadataMap.set(entityName, meta);
|
|
100
105
|
this.#idMap[meta._id] = meta;
|
|
101
106
|
this.#uniqueNameMap[meta.uniqueName] = meta;
|
|
102
|
-
|
|
107
|
+
const className = Utils.className(entityName);
|
|
108
|
+
const existing = this.#classNameMap[className];
|
|
109
|
+
// track name collisions caused by minifiers mangling two classes to the same name
|
|
110
|
+
if (existing && existing !== meta && existing.class !== meta.class) {
|
|
111
|
+
this.#ambiguousNames.add(className);
|
|
112
|
+
}
|
|
113
|
+
this.#classNameMap[className] = meta;
|
|
103
114
|
return meta;
|
|
104
115
|
}
|
|
105
116
|
/** Removes metadata for the given entity from all internal maps. */
|
|
@@ -110,6 +121,11 @@ export class MetadataStorage {
|
|
|
110
121
|
delete this.#idMap[meta._id];
|
|
111
122
|
delete this.#uniqueNameMap[meta.uniqueName];
|
|
112
123
|
delete this.#classNameMap[meta.className];
|
|
124
|
+
// the name may still be ambiguous among the remaining metas
|
|
125
|
+
const remaining = new Set([...this.#metadataMap.values()].filter(m => m.className === meta.className).map(m => m.class));
|
|
126
|
+
if (remaining.size <= 1) {
|
|
127
|
+
this.#ambiguousNames.delete(meta.className);
|
|
128
|
+
}
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
131
|
/** Decorates all entity prototypes with helper methods (e.g. init, toJSON). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.15-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
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
package/types/Type.js
CHANGED
|
@@ -55,11 +55,11 @@ export class Type {
|
|
|
55
55
|
return prop.columnTypes?.[0] ?? platform.getTextTypeDeclarationSQL(prop);
|
|
56
56
|
}
|
|
57
57
|
static getType(cls) {
|
|
58
|
-
|
|
59
|
-
if (!Type.types.has(
|
|
60
|
-
Type.types.set(
|
|
58
|
+
// keyed by class reference, as minifiers can mangle two classes to the same name
|
|
59
|
+
if (!Type.types.has(cls)) {
|
|
60
|
+
Type.types.set(cls, new cls());
|
|
61
61
|
}
|
|
62
|
-
return Type.types.get(
|
|
62
|
+
return Type.types.get(cls);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Checks whether the argument is instance of `Type`.
|
package/utils/QueryHelper.js
CHANGED
|
@@ -305,7 +305,7 @@ export class QueryHelper {
|
|
|
305
305
|
return Utils.mergeConfig({}, propFilters, options);
|
|
306
306
|
}
|
|
307
307
|
static isFilterActive(meta, filterName, filter, options) {
|
|
308
|
-
if (filter.entity && !filter.entity.
|
|
308
|
+
if (filter.entity && !Utils.asArray(filter.entity).some(e => Utils.matchesEntity(e, meta))) {
|
|
309
309
|
return false;
|
|
310
310
|
}
|
|
311
311
|
if (options[filterName] === false) {
|
package/utils/Utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompiledFunctions, Dictionary, EntityData, EntityDictionary, EntityKey, EntityMetadata, EntityName, EntityProperty, Primary } from '../typings.js';
|
|
1
|
+
import type { CompiledFunctions, Dictionary, EntityCtor, EntityData, EntityDictionary, EntityKey, EntityMetadata, EntityName, EntityProperty, Primary } from '../typings.js';
|
|
2
2
|
import type { Platform } from '../platforms/Platform.js';
|
|
3
3
|
import { ScalarReference } from '../entity/Reference.js';
|
|
4
4
|
import { Collection } from '../entity/Collection.js';
|
|
@@ -129,6 +129,16 @@ export declare class Utils {
|
|
|
129
129
|
* Gets string name of given class.
|
|
130
130
|
*/
|
|
131
131
|
static className<T>(classOrName: string | EntityName<T>): string;
|
|
132
|
+
/**
|
|
133
|
+
* Normalizes an entity reference for identity-safe matching: keeps class references
|
|
134
|
+
* (minifiers can mangle two classes to the same name) and falls back to the class name otherwise.
|
|
135
|
+
*/
|
|
136
|
+
static classOrName<T>(classOrName: string | EntityName<T>): EntityCtor<T> | string;
|
|
137
|
+
/**
|
|
138
|
+
* Checks whether the given entity reference points at the given metadata,
|
|
139
|
+
* comparing classes by identity and strings by class name.
|
|
140
|
+
*/
|
|
141
|
+
static matchesEntity<T>(classOrName: string | EntityName<T>, meta: EntityMetadata<any>): boolean;
|
|
132
142
|
static extractChildElements(items: readonly string[], prefix: string, allSymbol?: string): string[];
|
|
133
143
|
/**
|
|
134
144
|
* Tries to detect TypeScript support.
|
package/utils/Utils.js
CHANGED
|
@@ -153,7 +153,7 @@ export function parseJsonSafe(value) {
|
|
|
153
153
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
154
154
|
export class Utils {
|
|
155
155
|
static PK_SEPARATOR = '~~~';
|
|
156
|
-
static #ORM_VERSION = '7.1.
|
|
156
|
+
static #ORM_VERSION = '7.1.15-dev.0';
|
|
157
157
|
/**
|
|
158
158
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
159
159
|
*/
|
|
@@ -565,6 +565,21 @@ export class Utils {
|
|
|
565
565
|
}
|
|
566
566
|
return classOrName.name;
|
|
567
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Normalizes an entity reference for identity-safe matching: keeps class references
|
|
570
|
+
* (minifiers can mangle two classes to the same name) and falls back to the class name otherwise.
|
|
571
|
+
*/
|
|
572
|
+
static classOrName(classOrName) {
|
|
573
|
+
return typeof classOrName === 'function' ? classOrName : Utils.className(classOrName);
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Checks whether the given entity reference points at the given metadata,
|
|
577
|
+
* comparing classes by identity and strings by class name.
|
|
578
|
+
*/
|
|
579
|
+
static matchesEntity(classOrName, meta) {
|
|
580
|
+
const ref = Utils.classOrName(classOrName);
|
|
581
|
+
return typeof ref === 'function' ? ref === meta.class : ref === meta.className;
|
|
582
|
+
}
|
|
568
583
|
static extractChildElements(items, prefix, allSymbol) {
|
|
569
584
|
return items
|
|
570
585
|
.filter(field => field === allSymbol || field.startsWith(`${prefix}.`))
|