@mikro-orm/core 7.3.0-dev.5 → 7.3.0-dev.7
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.
|
@@ -404,7 +404,7 @@ export class ObjectHydrator extends Hydrator {
|
|
|
404
404
|
const code = `// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n` +
|
|
405
405
|
`return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n` +
|
|
406
406
|
`${lines.join('\n')}\n}`;
|
|
407
|
-
const fnKey = `hydrator-${meta.
|
|
407
|
+
const fnKey = `hydrator-${meta.compiledName}-${type}-${normalizeAccessors}`;
|
|
408
408
|
const hydrator = Utils.createFunction(context, code, this.config.get('compiledFunctions'), fnKey);
|
|
409
409
|
this.#hydrators[key].set(meta.class, hydrator);
|
|
410
410
|
return hydrator;
|
|
@@ -1461,7 +1461,8 @@ export class MetadataDiscovery {
|
|
|
1461
1461
|
}
|
|
1462
1462
|
}
|
|
1463
1463
|
rootProp.stiFieldNameMap[meta.discriminatorValue] = prop.fieldNames[0];
|
|
1464
|
-
|
|
1464
|
+
// subtypes that only differ in type share the column
|
|
1465
|
+
rootProp.stiFieldNames = Utils.unique([...rootProp.stiFieldNames, ...prop.fieldNames]);
|
|
1465
1466
|
newProp.nullable = true;
|
|
1466
1467
|
newProp.name = name;
|
|
1467
1468
|
newProp.hydrate = false;
|
|
@@ -32,6 +32,13 @@ export declare class MetadataStorage {
|
|
|
32
32
|
getById<T>(id: number): EntityMetadata<T>;
|
|
33
33
|
/** Returns metadata by class name, optionally throwing if not found. */
|
|
34
34
|
getByClassName<T = any, V extends boolean = true>(className: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Returns the first registered metadata with the given table name, in registration order (entities sharing
|
|
37
|
+
* a table, like STI children, resolve to the one registered first). The index is built on first use, as table
|
|
38
|
+
* names are only final once discovery has finished.
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
getByTableName<T = any>(tableName: string): EntityMetadata<T> | undefined;
|
|
35
42
|
/** Returns metadata by unique name, optionally throwing if not found. */
|
|
36
43
|
getByUniqueName<T = any, V extends boolean = true>(uniqueName: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
|
|
37
44
|
private validate;
|
|
@@ -18,6 +18,8 @@ export class MetadataStorage {
|
|
|
18
18
|
#classNameMap;
|
|
19
19
|
#uniqueNameMap;
|
|
20
20
|
#ambiguousNames = new Set();
|
|
21
|
+
/** Built on first use by `getByTableName()`, dropped whenever an entity is registered or removed. */
|
|
22
|
+
#tableNameMap;
|
|
21
23
|
constructor(metadata = {}) {
|
|
22
24
|
this.#idMap = {};
|
|
23
25
|
this.#uniqueNameMap = {};
|
|
@@ -102,6 +104,7 @@ export class MetadataStorage {
|
|
|
102
104
|
/** Registers metadata for the given entity. */
|
|
103
105
|
set(entityName, meta) {
|
|
104
106
|
this.#metadataMap.set(entityName, meta);
|
|
107
|
+
this.#tableNameMap = undefined;
|
|
105
108
|
this.#idMap[meta._id] = meta;
|
|
106
109
|
this.#uniqueNameMap[meta.uniqueName] = meta;
|
|
107
110
|
const className = Utils.className(entityName);
|
|
@@ -110,6 +113,12 @@ export class MetadataStorage {
|
|
|
110
113
|
if (existing && existing !== meta && existing.class !== meta.class) {
|
|
111
114
|
this.#ambiguousNames.add(className);
|
|
112
115
|
}
|
|
116
|
+
// colliding names are numbered in storage order, which follows the discovery config, not module evaluation
|
|
117
|
+
const sameName = this.#ambiguousNames.has(className)
|
|
118
|
+
? [...new Set(this.#metadataMap.values())].filter(m => m.className === meta.className)
|
|
119
|
+
: [meta];
|
|
120
|
+
const ordinal = sameName.indexOf(meta);
|
|
121
|
+
meta.compiledName = ordinal > 0 ? `${meta.className}#${ordinal}` : meta.className;
|
|
113
122
|
this.#classNameMap[className] = meta;
|
|
114
123
|
return meta;
|
|
115
124
|
}
|
|
@@ -118,6 +127,7 @@ export class MetadataStorage {
|
|
|
118
127
|
const meta = this.find(entityName);
|
|
119
128
|
if (meta) {
|
|
120
129
|
this.#metadataMap.delete(meta.class);
|
|
130
|
+
this.#tableNameMap = undefined;
|
|
121
131
|
delete this.#idMap[meta._id];
|
|
122
132
|
delete this.#uniqueNameMap[meta.uniqueName];
|
|
123
133
|
delete this.#classNameMap[meta.className];
|
|
@@ -145,6 +155,23 @@ export class MetadataStorage {
|
|
|
145
155
|
getByClassName(className, validate = true) {
|
|
146
156
|
return this.validate(this.#classNameMap[className], className, validate);
|
|
147
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Returns the first registered metadata with the given table name, in registration order (entities sharing
|
|
160
|
+
* a table, like STI children, resolve to the one registered first). The index is built on first use, as table
|
|
161
|
+
* names are only final once discovery has finished.
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
164
|
+
getByTableName(tableName) {
|
|
165
|
+
if (!this.#tableNameMap) {
|
|
166
|
+
this.#tableNameMap = new Map();
|
|
167
|
+
for (const meta of this.#metadataMap.values()) {
|
|
168
|
+
if (!this.#tableNameMap.has(meta.tableName)) {
|
|
169
|
+
this.#tableNameMap.set(meta.tableName, meta);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return this.#tableNameMap.get(tableName);
|
|
174
|
+
}
|
|
148
175
|
/** Returns metadata by unique name, optionally throwing if not found. */
|
|
149
176
|
getByUniqueName(uniqueName, validate = true) {
|
|
150
177
|
return this.validate(this.#uniqueNameMap[uniqueName], uniqueName, validate);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.3.0-dev.
|
|
3
|
+
"version": "7.3.0-dev.7",
|
|
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/typings.d.ts
CHANGED
|
@@ -1259,6 +1259,8 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
|
|
|
1259
1259
|
orderBy?: QueryOrderMap<Entity> | QueryOrderMap<Entity>[];
|
|
1260
1260
|
/** @internal can be used for computed numeric cache keys */
|
|
1261
1261
|
readonly _id: number;
|
|
1262
|
+
/** @internal name that does not depend on module evaluation order (unlike `_id`), used to key `compiledFunctions` */
|
|
1263
|
+
compiledName?: string;
|
|
1262
1264
|
}
|
|
1263
1265
|
/** Options for `ISchemaGenerator.create()`. */
|
|
1264
1266
|
export interface CreateSchemaOptions {
|
|
@@ -95,7 +95,7 @@ export class EntityComparator {
|
|
|
95
95
|
lines.push(` return entity${this.wrap(pk)};`);
|
|
96
96
|
}
|
|
97
97
|
const code = `// compiled pk getter for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
98
|
-
const fnKey = `pkGetter-${meta.
|
|
98
|
+
const fnKey = `pkGetter-${meta.compiledName}`;
|
|
99
99
|
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
100
100
|
this.#pkGetters.set(meta, pkSerializer);
|
|
101
101
|
return pkSerializer;
|
|
@@ -147,7 +147,7 @@ export class EntityComparator {
|
|
|
147
147
|
}
|
|
148
148
|
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n` +
|
|
149
149
|
`return function(entity) {\n${lines.join('\n')}\n}`;
|
|
150
|
-
const fnKey = `pkGetterConverted-${meta.
|
|
150
|
+
const fnKey = `pkGetterConverted-${meta.compiledName}`;
|
|
151
151
|
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
152
152
|
this.#pkGettersConverted.set(meta, pkSerializer);
|
|
153
153
|
return pkSerializer;
|
|
@@ -206,7 +206,7 @@ export class EntityComparator {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
const code = `// compiled pk serializer for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
209
|
-
const fnKey = `pkSerializer-${meta.
|
|
209
|
+
const fnKey = `pkSerializer-${meta.compiledName}`;
|
|
210
210
|
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
211
211
|
this.#pkSerializers.set(meta, pkSerializer);
|
|
212
212
|
return pkSerializer;
|
|
@@ -236,7 +236,7 @@ export class EntityComparator {
|
|
|
236
236
|
})
|
|
237
237
|
.forEach(prop => lines.push(this.getPropertySnapshot(meta, prop, context, this.wrap(prop.name), this.wrap(prop.name), [prop.name])));
|
|
238
238
|
const code = `return function(entity) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
239
|
-
const fnKey = `snapshotGenerator-${meta.
|
|
239
|
+
const fnKey = `snapshotGenerator-${meta.compiledName}`;
|
|
240
240
|
const snapshotGenerator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
241
241
|
this.#snapshotGenerators.set(meta, snapshotGenerator);
|
|
242
242
|
return snapshotGenerator;
|
|
@@ -350,14 +350,27 @@ export class EntityComparator {
|
|
|
350
350
|
if (prop.embedded && (meta.embeddable || meta.properties[prop.embedded[0]].object)) {
|
|
351
351
|
continue;
|
|
352
352
|
}
|
|
353
|
+
let defined = `typeof ${this.propName(prop.fieldNames[0])} !== 'undefined'`;
|
|
354
|
+
// STI subtypes with conflicting columns share the property, so another subtype's null column must not override it
|
|
355
|
+
if (prop.renamedFrom) {
|
|
356
|
+
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
357
|
+
defined = `${this.propName(prop.fieldNames[0])} != null`;
|
|
358
|
+
// a column shared with a differently typed subtype is left for each subtype's hydrator to convert
|
|
359
|
+
if (meta.props.some(p => p !== prop && p.name === prop.name && p.fieldNames?.[0] === prop.fieldNames[0])) {
|
|
360
|
+
lines.push(`${padding} if (${defined}) {`);
|
|
361
|
+
lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])};`);
|
|
362
|
+
lines.push(`${padding} }`);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
353
366
|
if (prop.runtimeType === 'boolean') {
|
|
354
|
-
lines.push(`${padding} if (
|
|
367
|
+
lines.push(`${padding} if (${defined}) {`);
|
|
355
368
|
lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : !!${this.propName(prop.fieldNames[0])};`);
|
|
356
369
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
357
370
|
lines.push(`${padding} }`);
|
|
358
371
|
}
|
|
359
372
|
else if (prop.runtimeType === 'Date' && !this.#platform.isNumericProperty(prop)) {
|
|
360
|
-
lines.push(`${padding} if (
|
|
373
|
+
lines.push(`${padding} if (${defined}) {`);
|
|
361
374
|
context.set('parseDate', (value) => this.#platform.parseDate(value));
|
|
362
375
|
parseDate('ret' + this.wrap(prop.name), this.propName(prop.fieldNames[0]), padding);
|
|
363
376
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
@@ -372,13 +385,13 @@ export class EntityComparator {
|
|
|
372
385
|
}
|
|
373
386
|
return item == null ? item : this.getResultMapper(prop.targetMeta)(item);
|
|
374
387
|
});
|
|
375
|
-
lines.push(`${padding} if (
|
|
388
|
+
lines.push(`${padding} if (${defined}) {`);
|
|
376
389
|
lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : mapEmbeddedResult_${idx}(${this.propName(prop.fieldNames[0])});`);
|
|
377
390
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
378
391
|
lines.push(`${padding} }`);
|
|
379
392
|
}
|
|
380
393
|
else if (prop.kind !== ReferenceKind.EMBEDDED) {
|
|
381
|
-
lines.push(`${padding} if (
|
|
394
|
+
lines.push(`${padding} if (${defined}) {`);
|
|
382
395
|
lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])};`);
|
|
383
396
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
384
397
|
lines.push(`${padding} }`);
|
|
@@ -420,7 +433,7 @@ export class EntityComparator {
|
|
|
420
433
|
lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k] && ret[k] === undefined${knownKeysGuard}) ret[k] = result[k]; }`);
|
|
421
434
|
const code = `// compiled mapper for entity ${meta.className}\n` +
|
|
422
435
|
`return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
423
|
-
const fnKey = `resultMapper-${meta.
|
|
436
|
+
const fnKey = `resultMapper-${meta.compiledName}`;
|
|
424
437
|
const resultMapper = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
425
438
|
this.#mappers.set(meta, resultMapper);
|
|
426
439
|
return resultMapper;
|
|
@@ -703,7 +716,7 @@ export class EntityComparator {
|
|
|
703
716
|
lines.push(`}`);
|
|
704
717
|
const code = `// compiled comparator for entity ${meta.className}\n` +
|
|
705
718
|
`return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
|
|
706
|
-
const fnKey = `comparator-${meta.
|
|
719
|
+
const fnKey = `comparator-${meta.compiledName}`;
|
|
707
720
|
const comparator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
708
721
|
this.#comparators.set(meta, comparator);
|
|
709
722
|
return comparator;
|
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.3.0-dev.
|
|
156
|
+
static #ORM_VERSION = '7.3.0-dev.7';
|
|
157
157
|
/** Default session variable name backing an RLS filter argument (`current_setting('mikro.<filter>.<arg>')`). */
|
|
158
158
|
static getRlsSettingName(filterName, argName) {
|
|
159
159
|
return `mikro.${filterName}.${argName}`;
|