@mikro-orm/core 6.3.14-dev.4 → 6.3.14-dev.40
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/decorators/CreateRequestContext.d.ts +3 -9
- package/decorators/CreateRequestContext.js +16 -43
- package/decorators/Property.d.ts +13 -0
- package/decorators/Transactional.d.ts +13 -0
- package/decorators/Transactional.js +31 -0
- package/decorators/index.d.ts +1 -0
- package/decorators/index.js +1 -0
- package/drivers/DatabaseDriver.js +3 -8
- package/entity/EntityFactory.js +4 -1
- package/entity/EntityHelper.js +8 -6
- package/index.mjs +1 -0
- package/package.json +2 -2
- package/serialization/EntitySerializer.js +19 -12
- package/serialization/EntityTransformer.js +21 -13
- package/types/DecimalType.d.ts +1 -0
- package/types/DecimalType.js +3 -0
- package/typings.d.ts +7 -0
- package/utils/DataloaderUtils.d.ts +2 -2
- package/utils/DataloaderUtils.js +13 -11
- package/utils/clone.js +1 -1
- package/utils/resolveContextProvider.d.ts +10 -0
- package/utils/resolveContextProvider.js +31 -0
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare function CreateRequestContext<T>(getContext?: MikroORM | Promise<MikroORM> | ((type: T) => MikroORM | Promise<MikroORM> | EntityManager | EntityRepository<any> | {
|
|
5
|
-
getEntityManager(): EntityManager;
|
|
6
|
-
}), respectExistingContext?: boolean): MethodDecorator;
|
|
7
|
-
export declare function EnsureRequestContext<T>(getContext?: MikroORM | Promise<MikroORM> | ((type: T) => MikroORM | Promise<MikroORM> | EntityManager | EntityRepository<any> | {
|
|
8
|
-
getEntityManager(): EntityManager;
|
|
9
|
-
})): MethodDecorator;
|
|
1
|
+
import type { ContextProvider } from '../typings';
|
|
2
|
+
export declare function CreateRequestContext<T extends object>(context?: ContextProvider<T>, respectExistingContext?: boolean): MethodDecorator;
|
|
3
|
+
export declare function EnsureRequestContext<T extends object>(context?: ContextProvider<T>): MethodDecorator;
|
|
@@ -2,59 +2,32 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CreateRequestContext = CreateRequestContext;
|
|
4
4
|
exports.EnsureRequestContext = EnsureRequestContext;
|
|
5
|
-
const MikroORM_1 = require("../MikroORM");
|
|
6
5
|
const RequestContext_1 = require("../utils/RequestContext");
|
|
7
|
-
const
|
|
8
|
-
const EntityRepository_1 = require("../entity/EntityRepository");
|
|
6
|
+
const resolveContextProvider_1 = require("../utils/resolveContextProvider");
|
|
9
7
|
const TransactionContext_1 = require("../utils/TransactionContext");
|
|
10
|
-
function CreateRequestContext(
|
|
8
|
+
function CreateRequestContext(context, respectExistingContext = false) {
|
|
11
9
|
return function (target, propertyKey, descriptor) {
|
|
12
10
|
const originalMethod = descriptor.value;
|
|
13
11
|
descriptor.value = async function (...args) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const provider = txContext ? TransactionContext_1.TransactionContext : RequestContext_1.RequestContext;
|
|
17
|
-
let orm;
|
|
18
|
-
let em;
|
|
19
|
-
if (typeof getContext === 'function') {
|
|
20
|
-
const context = await getContext(this);
|
|
21
|
-
orm = context ?? await this.orm;
|
|
22
|
-
em = context ?? await this.em;
|
|
23
|
-
}
|
|
24
|
-
else if (getContext) {
|
|
25
|
-
orm = em = await getContext;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
orm = await this.orm;
|
|
29
|
-
em = await this.em;
|
|
30
|
-
}
|
|
31
|
-
const create = async (em) => {
|
|
32
|
-
// reuse existing context if available for given respect `contextName`
|
|
33
|
-
if (respectExistingContext && RequestContext_1.RequestContext.getEntityManager(em.name)) {
|
|
34
|
-
return originalMethod.apply(this, args);
|
|
35
|
-
}
|
|
36
|
-
if (txContext) {
|
|
37
|
-
em = em.fork({ useContext: true });
|
|
38
|
-
}
|
|
39
|
-
return await provider.create(em, () => {
|
|
40
|
-
return originalMethod.apply(this, args);
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
if (em instanceof EntityManager_1.EntityManager) {
|
|
44
|
-
return await create(em);
|
|
45
|
-
}
|
|
46
|
-
if (orm instanceof EntityRepository_1.EntityRepository) {
|
|
47
|
-
return await create(orm.getEntityManager());
|
|
48
|
-
}
|
|
49
|
-
if (!(orm instanceof MikroORM_1.MikroORM)) {
|
|
12
|
+
const em = await (0, resolveContextProvider_1.resolveContextProvider)(this, context);
|
|
13
|
+
if (!em) {
|
|
50
14
|
const name = respectExistingContext ? 'EnsureRequestContext' : 'CreateRequestContext';
|
|
51
15
|
throw new Error(`@${name}() decorator can only be applied to methods of classes with \`orm: MikroORM\` property, \`em: EntityManager\` property, or with a callback parameter like \`@${name}(() => orm)\` that returns one of those types. The parameter will contain a reference to current \`this\`. Returning an EntityRepository from it is also supported.`);
|
|
52
16
|
}
|
|
53
|
-
|
|
17
|
+
// reuse existing context if available for given respect `contextName`
|
|
18
|
+
if (respectExistingContext && RequestContext_1.RequestContext.getEntityManager(em.name)) {
|
|
19
|
+
return originalMethod.apply(this, args);
|
|
20
|
+
}
|
|
21
|
+
// Otherwise, the outer tx context would be preferred.
|
|
22
|
+
const txContext = TransactionContext_1.TransactionContext.currentTransactionContext();
|
|
23
|
+
const provider = txContext ? TransactionContext_1.TransactionContext : RequestContext_1.RequestContext;
|
|
24
|
+
return txContext
|
|
25
|
+
? provider.create(em.fork({ useContext: true }), () => originalMethod.apply(this, args))
|
|
26
|
+
: provider.create(em, () => originalMethod.apply(this, args));
|
|
54
27
|
};
|
|
55
28
|
return descriptor;
|
|
56
29
|
};
|
|
57
30
|
}
|
|
58
|
-
function EnsureRequestContext(
|
|
59
|
-
return CreateRequestContext(
|
|
31
|
+
function EnsureRequestContext(context) {
|
|
32
|
+
return CreateRequestContext(context, true);
|
|
60
33
|
}
|
package/decorators/Property.d.ts
CHANGED
|
@@ -177,6 +177,19 @@ export interface PropertyOptions<Owner> {
|
|
|
177
177
|
* ```
|
|
178
178
|
*/
|
|
179
179
|
getter?: boolean;
|
|
180
|
+
/**
|
|
181
|
+
* When defining a property over a method (not a getter, a regular function), you can use this option to point
|
|
182
|
+
* to the method name.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```
|
|
186
|
+
* @Property({ getter: true })
|
|
187
|
+
* getFullName() {
|
|
188
|
+
* return this.firstName + this.lastName;
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
getterName?: keyof Owner;
|
|
180
193
|
/**
|
|
181
194
|
* Set to define serialized primary key for MongoDB. (virtual)
|
|
182
195
|
* Alias for `@SerializedPrimaryKey()` decorator.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TransactionOptions } from '../enums';
|
|
2
|
+
import type { ContextProvider } from '../typings';
|
|
3
|
+
type TransactionalOptions<T> = TransactionOptions & {
|
|
4
|
+
context?: ContextProvider<T>;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* This decorator wraps the method with `em.transactional()`, so you can provide `TransactionOptions` just like with `em.transactional()`.
|
|
8
|
+
* The difference is that you can specify the context in which the transaction begins by providing `context` option,
|
|
9
|
+
* and if omitted, the transaction will begin in the current context implicitly.
|
|
10
|
+
* It works on async functions and can be nested with `em.transactional()`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function Transactional<T extends object>(options?: TransactionalOptions<T>): MethodDecorator;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Transactional = Transactional;
|
|
4
|
+
const RequestContext_1 = require("../utils/RequestContext");
|
|
5
|
+
const resolveContextProvider_1 = require("../utils/resolveContextProvider");
|
|
6
|
+
const TransactionContext_1 = require("../utils/TransactionContext");
|
|
7
|
+
/**
|
|
8
|
+
* This decorator wraps the method with `em.transactional()`, so you can provide `TransactionOptions` just like with `em.transactional()`.
|
|
9
|
+
* The difference is that you can specify the context in which the transaction begins by providing `context` option,
|
|
10
|
+
* and if omitted, the transaction will begin in the current context implicitly.
|
|
11
|
+
* It works on async functions and can be nested with `em.transactional()`.
|
|
12
|
+
*/
|
|
13
|
+
function Transactional(options = {}) {
|
|
14
|
+
return function (target, propertyKey, descriptor) {
|
|
15
|
+
const originalMethod = descriptor.value;
|
|
16
|
+
if (originalMethod.constructor.name !== 'AsyncFunction') {
|
|
17
|
+
throw new Error('@Transactional() should be use with async functions');
|
|
18
|
+
}
|
|
19
|
+
descriptor.value = async function (...args) {
|
|
20
|
+
const { context, ...txOptions } = options;
|
|
21
|
+
const em = await (0, resolveContextProvider_1.resolveContextProvider)(this, context)
|
|
22
|
+
|| TransactionContext_1.TransactionContext.getEntityManager()
|
|
23
|
+
|| RequestContext_1.RequestContext.getEntityManager();
|
|
24
|
+
if (!em) {
|
|
25
|
+
throw new Error(`@Transactional() decorator can only be applied to methods of classes with \`orm: MikroORM\` property, \`em: EntityManager\` property, or with a callback parameter like \`@Transactional(() => orm)\` that returns one of those types. The parameter will contain a reference to current \`this\`. Returning an EntityRepository from it is also supported.`);
|
|
26
|
+
}
|
|
27
|
+
return em.transactional(() => originalMethod.apply(this, args), txOptions);
|
|
28
|
+
};
|
|
29
|
+
return descriptor;
|
|
30
|
+
};
|
|
31
|
+
}
|
package/decorators/index.d.ts
CHANGED
package/decorators/index.js
CHANGED
|
@@ -354,16 +354,11 @@ class DatabaseDriver {
|
|
|
354
354
|
*/
|
|
355
355
|
getTableName(meta, options, quote = true) {
|
|
356
356
|
const schema = this.getSchemaName(meta, options);
|
|
357
|
-
|
|
358
|
-
if (quote) {
|
|
359
|
-
return this.platform.quoteIdentifier(schema + '.' + meta.tableName);
|
|
360
|
-
}
|
|
361
|
-
return schema + '.' + meta.tableName;
|
|
362
|
-
}
|
|
357
|
+
const tableName = schema ? `${schema}.${meta.tableName}` : meta.tableName;
|
|
363
358
|
if (quote) {
|
|
364
|
-
return this.platform.quoteIdentifier(
|
|
359
|
+
return this.platform.quoteIdentifier(tableName);
|
|
365
360
|
}
|
|
366
|
-
return
|
|
361
|
+
return tableName;
|
|
367
362
|
}
|
|
368
363
|
/**
|
|
369
364
|
* @internal
|
package/entity/EntityFactory.js
CHANGED
|
@@ -69,6 +69,9 @@ class EntityFactory {
|
|
|
69
69
|
if (options.convertCustomTypes) {
|
|
70
70
|
for (const prop of meta.props) {
|
|
71
71
|
if (prop.customType?.ensureComparable(meta, prop) && data[prop.name]) {
|
|
72
|
+
if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils_1.Utils.isPlainObject(data[prop.name])) {
|
|
73
|
+
data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
|
|
74
|
+
}
|
|
72
75
|
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
|
|
73
76
|
}
|
|
74
77
|
}
|
|
@@ -244,7 +247,7 @@ class EntityFactory {
|
|
|
244
247
|
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
|
245
248
|
return undefined;
|
|
246
249
|
}
|
|
247
|
-
const pks = Utils_1.Utils.getOrderedPrimaryKeys(data, meta, this.platform
|
|
250
|
+
const pks = Utils_1.Utils.getOrderedPrimaryKeys(data, meta, this.platform);
|
|
248
251
|
return this.unitOfWork.getById(meta.className, pks, schema);
|
|
249
252
|
}
|
|
250
253
|
processDiscriminatorColumn(meta, data) {
|
package/entity/EntityHelper.js
CHANGED
|
@@ -176,10 +176,15 @@ class EntityHelper {
|
|
|
176
176
|
inverse.addWithoutPropagation(owner);
|
|
177
177
|
(0, wrap_1.helper)(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
|
|
178
178
|
}
|
|
179
|
-
if (prop.kind === enums_1.ReferenceKind.ONE_TO_ONE
|
|
179
|
+
if (prop.kind === enums_1.ReferenceKind.ONE_TO_ONE) {
|
|
180
180
|
if ((value != null && Reference_1.Reference.unwrapReference(inverse) !== owner) ||
|
|
181
|
-
(value == null && entity[prop2.name] != null)) {
|
|
182
|
-
|
|
181
|
+
(value == null && entity?.[prop2.name] != null)) {
|
|
182
|
+
if (entity && (!prop.owner || (0, wrap_1.helper)(entity).__initialized)) {
|
|
183
|
+
EntityHelper.propagateOneToOne(entity, owner, prop, prop2, value, old);
|
|
184
|
+
}
|
|
185
|
+
if (old && prop.orphanRemoval) {
|
|
186
|
+
(0, wrap_1.helper)(old).__em?.getUnitOfWork().scheduleOrphanRemoval(old);
|
|
187
|
+
}
|
|
183
188
|
}
|
|
184
189
|
}
|
|
185
190
|
}
|
|
@@ -203,9 +208,6 @@ class EntityHelper {
|
|
|
203
208
|
else {
|
|
204
209
|
entity[prop2.name] = Reference_1.Reference.wrapReference(owner, prop);
|
|
205
210
|
}
|
|
206
|
-
if (old && prop.orphanRemoval) {
|
|
207
|
-
(0, wrap_1.helper)(old).__em?.getUnitOfWork().scheduleOrphanRemoval(old);
|
|
208
|
-
}
|
|
209
211
|
if (old?.[prop2.name] != null) {
|
|
210
212
|
delete (0, wrap_1.helper)(old).__data[prop2.name];
|
|
211
213
|
}
|
package/index.mjs
CHANGED
|
@@ -162,6 +162,7 @@ export const TimeType = mod.TimeType;
|
|
|
162
162
|
export const TinyIntType = mod.TinyIntType;
|
|
163
163
|
export const TransactionContext = mod.TransactionContext;
|
|
164
164
|
export const TransactionEventBroadcaster = mod.TransactionEventBroadcaster;
|
|
165
|
+
export const Transactional = mod.Transactional;
|
|
165
166
|
export const Type = mod.Type;
|
|
166
167
|
export const Uint8ArrayType = mod.Uint8ArrayType;
|
|
167
168
|
export const UnderscoreNamingStrategy = mod.UnderscoreNamingStrategy;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "6.3.14-dev.
|
|
3
|
+
"version": "6.3.14-dev.40",
|
|
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",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"esprima": "4.0.1",
|
|
65
65
|
"fs-extra": "11.2.0",
|
|
66
66
|
"globby": "11.1.0",
|
|
67
|
-
"mikro-orm": "6.3.14-dev.
|
|
67
|
+
"mikro-orm": "6.3.14-dev.40",
|
|
68
68
|
"reflect-metadata": "0.2.2"
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -111,7 +111,7 @@ class EntitySerializer {
|
|
|
111
111
|
const parts = prop.split('.');
|
|
112
112
|
prop = parts[0];
|
|
113
113
|
const wrapped = (0, wrap_1.helper)(entity);
|
|
114
|
-
const property = wrapped.__meta.properties[prop];
|
|
114
|
+
const property = wrapped.__meta.properties[prop] ?? { name: prop };
|
|
115
115
|
const serializer = property?.serializer;
|
|
116
116
|
const value = entity[prop];
|
|
117
117
|
// getter method
|
|
@@ -127,10 +127,10 @@ class EntitySerializer {
|
|
|
127
127
|
return serializer(value);
|
|
128
128
|
}
|
|
129
129
|
if (Utils_1.Utils.isCollection(value)) {
|
|
130
|
-
return this.processCollection(
|
|
130
|
+
return this.processCollection(property, entity, options);
|
|
131
131
|
}
|
|
132
132
|
if (Utils_1.Utils.isEntity(value, true)) {
|
|
133
|
-
return this.processEntity(
|
|
133
|
+
return this.processEntity(property, entity, wrapped.__platform, options);
|
|
134
134
|
}
|
|
135
135
|
if (Utils_1.Utils.isScalarReference(value)) {
|
|
136
136
|
return value.unwrap();
|
|
@@ -158,17 +158,20 @@ class EntitySerializer {
|
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
static processEntity(prop, entity, platform, options) {
|
|
161
|
-
const child = Reference_1.Reference.unwrapReference(entity[prop]);
|
|
161
|
+
const child = Reference_1.Reference.unwrapReference(entity[prop.name]);
|
|
162
162
|
const wrapped = (0, wrap_1.helper)(child);
|
|
163
|
-
const populated = isPopulated(prop, options) && wrapped.isInitialized();
|
|
163
|
+
const populated = isPopulated(prop.name, options) && wrapped.isInitialized();
|
|
164
164
|
const expand = populated || !wrapped.__managed;
|
|
165
165
|
const meta = wrapped.__meta;
|
|
166
|
-
const childOptions = this.extractChildOptions(options, prop);
|
|
166
|
+
const childOptions = this.extractChildOptions(options, prop.name);
|
|
167
167
|
const visible = meta.primaryKeys.filter(prop => isVisible(meta, prop, childOptions));
|
|
168
168
|
if (expand) {
|
|
169
169
|
return this.serialize(child, childOptions);
|
|
170
170
|
}
|
|
171
|
-
|
|
171
|
+
let pk = wrapped.getPrimaryKey();
|
|
172
|
+
if (prop.customType) {
|
|
173
|
+
pk = prop.customType.toJSON(pk, wrapped.__platform);
|
|
174
|
+
}
|
|
172
175
|
if (options.forceObject || wrapped.__config.get('serialization').forceObject) {
|
|
173
176
|
return Utils_1.Utils.primaryKeyToObject(meta, pk, visible);
|
|
174
177
|
}
|
|
@@ -182,20 +185,24 @@ class EntitySerializer {
|
|
|
182
185
|
return platform.normalizePrimaryKey(pk);
|
|
183
186
|
}
|
|
184
187
|
static processCollection(prop, entity, options) {
|
|
185
|
-
const col = entity[prop];
|
|
188
|
+
const col = entity[prop.name];
|
|
186
189
|
if (!col.isInitialized()) {
|
|
187
190
|
return undefined;
|
|
188
191
|
}
|
|
189
192
|
return col.getItems(false).map(item => {
|
|
190
|
-
const populated = isPopulated(prop, options);
|
|
193
|
+
const populated = isPopulated(prop.name, options);
|
|
191
194
|
const wrapped = (0, wrap_1.helper)(item);
|
|
192
195
|
if (populated || !wrapped.__managed) {
|
|
193
|
-
return this.serialize(item, this.extractChildOptions(options, prop));
|
|
196
|
+
return this.serialize(item, this.extractChildOptions(options, prop.name));
|
|
197
|
+
}
|
|
198
|
+
let pk = wrapped.getPrimaryKey();
|
|
199
|
+
if (prop.customType) {
|
|
200
|
+
pk = prop.customType.toJSON(pk, wrapped.__platform);
|
|
194
201
|
}
|
|
195
202
|
if (options.forceObject || wrapped.__config.get('serialization').forceObject) {
|
|
196
|
-
return Utils_1.Utils.primaryKeyToObject(wrapped.__meta,
|
|
203
|
+
return Utils_1.Utils.primaryKeyToObject(wrapped.__meta, pk);
|
|
197
204
|
}
|
|
198
|
-
return
|
|
205
|
+
return pk;
|
|
199
206
|
});
|
|
200
207
|
}
|
|
201
208
|
}
|
|
@@ -108,7 +108,7 @@ class EntityTransformer {
|
|
|
108
108
|
}
|
|
109
109
|
static processProperty(prop, entity, raw, populated) {
|
|
110
110
|
const wrapped = (0, wrap_1.helper)(entity);
|
|
111
|
-
const property = wrapped.__meta.properties[prop];
|
|
111
|
+
const property = wrapped.__meta.properties[prop] ?? { name: prop };
|
|
112
112
|
const serializer = property?.serializer;
|
|
113
113
|
const value = entity[prop];
|
|
114
114
|
// getter method
|
|
@@ -123,10 +123,10 @@ class EntityTransformer {
|
|
|
123
123
|
return serializer(value);
|
|
124
124
|
}
|
|
125
125
|
if (Utils_1.Utils.isCollection(value)) {
|
|
126
|
-
return EntityTransformer.processCollection(
|
|
126
|
+
return EntityTransformer.processCollection(property, entity, raw, populated);
|
|
127
127
|
}
|
|
128
128
|
if (Utils_1.Utils.isEntity(value, true)) {
|
|
129
|
-
return EntityTransformer.processEntity(
|
|
129
|
+
return EntityTransformer.processEntity(property, entity, wrapped.__platform, raw, populated);
|
|
130
130
|
}
|
|
131
131
|
if (Utils_1.Utils.isScalarReference(value)) {
|
|
132
132
|
return value.unwrap();
|
|
@@ -151,7 +151,7 @@ class EntityTransformer {
|
|
|
151
151
|
return value;
|
|
152
152
|
}
|
|
153
153
|
static processEntity(prop, entity, platform, raw, populated) {
|
|
154
|
-
const child = entity[prop];
|
|
154
|
+
const child = entity[prop.name];
|
|
155
155
|
const wrapped = (0, wrap_1.helper)(child);
|
|
156
156
|
const meta = wrapped.__meta;
|
|
157
157
|
const visible = meta.primaryKeys.filter(prop => isVisible(meta, prop));
|
|
@@ -170,7 +170,10 @@ class EntityTransformer {
|
|
|
170
170
|
if (wrapped.isInitialized() && isPopulated() && child !== entity) {
|
|
171
171
|
return (0, wrap_1.wrap)(child).toJSON();
|
|
172
172
|
}
|
|
173
|
-
|
|
173
|
+
let pk = wrapped.getPrimaryKey();
|
|
174
|
+
if (prop.customType) {
|
|
175
|
+
pk = prop.customType.toJSON(pk, wrapped.__platform);
|
|
176
|
+
}
|
|
174
177
|
if (wrapped.__config.get('serialization').forceObject) {
|
|
175
178
|
return Utils_1.Utils.primaryKeyToObject(meta, pk, visible);
|
|
176
179
|
}
|
|
@@ -184,7 +187,7 @@ class EntityTransformer {
|
|
|
184
187
|
return platform.normalizePrimaryKey(pk);
|
|
185
188
|
}
|
|
186
189
|
static processCollection(prop, entity, raw, populated) {
|
|
187
|
-
const col = entity[prop];
|
|
190
|
+
const col = entity[prop.name];
|
|
188
191
|
if (raw && col.isInitialized(true)) {
|
|
189
192
|
return col.map(item => (0, wrap_1.helper)(item).toPOJO());
|
|
190
193
|
}
|
|
@@ -193,13 +196,18 @@ class EntityTransformer {
|
|
|
193
196
|
}
|
|
194
197
|
if (col.isInitialized()) {
|
|
195
198
|
const wrapped = (0, wrap_1.helper)(entity);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
const forceObject = wrapped.__config.get('serialization').forceObject;
|
|
200
|
+
return col.map(item => {
|
|
201
|
+
const wrapped = (0, wrap_1.helper)(item);
|
|
202
|
+
const pk = wrapped.getPrimaryKey();
|
|
203
|
+
if (prop.customType) {
|
|
204
|
+
return prop.customType.toJSON(pk, wrapped.__platform);
|
|
205
|
+
}
|
|
206
|
+
if (forceObject) {
|
|
207
|
+
return Utils_1.Utils.primaryKeyToObject(wrapped.__meta, pk);
|
|
208
|
+
}
|
|
209
|
+
return pk;
|
|
210
|
+
});
|
|
203
211
|
}
|
|
204
212
|
return undefined;
|
|
205
213
|
}
|
package/types/DecimalType.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class DecimalType extends Type<string | number, string> {
|
|
|
8
8
|
mode?: ("number" | "string") | undefined;
|
|
9
9
|
constructor(mode?: ("number" | "string") | undefined);
|
|
10
10
|
convertToJSValue(value: string): number | string;
|
|
11
|
+
compareValues(a: string, b: string): boolean;
|
|
11
12
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
12
13
|
compareAsType(): string;
|
|
13
14
|
}
|
package/types/DecimalType.js
CHANGED
package/typings.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Transaction } from './connections';
|
|
2
2
|
import { type Cascade, type DeferMode, type EventType, type LoadStrategy, type PopulatePath, type QueryOrderMap, ReferenceKind } from './enums';
|
|
3
3
|
import { type AssignOptions, type Collection, type EntityFactory, type EntityIdentifier, type EntityLoaderOptions, type EntityRepository, Reference, type ScalarReference } from './entity';
|
|
4
|
+
import type { MikroORM } from './MikroORM';
|
|
4
5
|
import type { SerializationContext, SerializeOptions } from './serialization';
|
|
5
6
|
import type { EntitySchema, MetadataStorage } from './metadata';
|
|
6
7
|
import type { Type, types } from './types';
|
|
@@ -786,4 +787,10 @@ export interface Seeder<T extends Dictionary = Dictionary> {
|
|
|
786
787
|
}
|
|
787
788
|
export type ConnectionType = 'read' | 'write';
|
|
788
789
|
export type MetadataProcessor = (metadata: EntityMetadata[], platform: Platform) => MaybePromise<void>;
|
|
790
|
+
/**
|
|
791
|
+
* The type of context that the user intends to inject.
|
|
792
|
+
*/
|
|
793
|
+
export type ContextProvider<T> = MaybePromise<MikroORM> | ((type: T) => MaybePromise<MikroORM | EntityManager | EntityRepository<any> | {
|
|
794
|
+
getEntityManager(): EntityManager;
|
|
795
|
+
}>);
|
|
789
796
|
export {};
|
|
@@ -23,7 +23,7 @@ export declare class DataloaderUtils {
|
|
|
23
23
|
static groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts: readonly [Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?][]): Map<string, Map<string, Set<Primary<any>>>>;
|
|
24
24
|
/**
|
|
25
25
|
* Turn the entity+options map into actual queries.
|
|
26
|
-
* The keys are the entity names + a
|
|
26
|
+
* The keys are the entity names + a stringified version of the options and the values are filter Maps which will be used as the values of an $or operator so we end up with a query per entity+opts.
|
|
27
27
|
* We must populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s).
|
|
28
28
|
* Together with the query the promises will also return the key which can be used to narrow down the results pertaining to a certain set of options.
|
|
29
29
|
*/
|
|
@@ -33,7 +33,7 @@ export declare class DataloaderUtils {
|
|
|
33
33
|
* First checks if the Entity type matches, then retrieves the inverse side of the relationship
|
|
34
34
|
* where the filtering will be done in order to match the target collection.
|
|
35
35
|
*/
|
|
36
|
-
static getColFilter<T, S extends T>(collection: Collection<any
|
|
36
|
+
static getColFilter<T, S extends T>(collection: Collection<any>): (result: T) => result is S;
|
|
37
37
|
/**
|
|
38
38
|
* Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
39
39
|
* makes one query per entity and maps each input collection to the corresponding result.
|
package/utils/DataloaderUtils.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.DataloaderUtils = void 0;
|
|
|
4
4
|
const Collection_1 = require("../entity/Collection");
|
|
5
5
|
const wrap_1 = require("../entity/wrap");
|
|
6
6
|
const enums_1 = require("../enums");
|
|
7
|
+
const Reference_1 = require("../entity/Reference");
|
|
7
8
|
class DataloaderUtils {
|
|
8
9
|
/**
|
|
9
10
|
* Groups identified references by entity and returns a Map with the
|
|
@@ -92,7 +93,7 @@ class DataloaderUtils {
|
|
|
92
93
|
}
|
|
93
94
|
/**
|
|
94
95
|
* Turn the entity+options map into actual queries.
|
|
95
|
-
* The keys are the entity names + a
|
|
96
|
+
* The keys are the entity names + a stringified version of the options and the values are filter Maps which will be used as the values of an $or operator so we end up with a query per entity+opts.
|
|
96
97
|
* We must populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s).
|
|
97
98
|
* Together with the query the promises will also return the key which can be used to narrow down the results pertaining to a certain set of options.
|
|
98
99
|
*/
|
|
@@ -139,20 +140,21 @@ class DataloaderUtils {
|
|
|
139
140
|
// There is no need to check if Entity matches because we already matched the key which is entity+options.
|
|
140
141
|
// This is the inverse side of the relationship where the filtering will be done in order to match the target collection
|
|
141
142
|
// Either inversedBy or mappedBy exist because we already checked in groupInversedOrMappedKeysByEntity
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if ((0, wrap_1.helper)(item).getSerializedPrimaryKey() === (0, wrap_1.helper)(collection.owner).getSerializedPrimaryKey()) {
|
|
143
|
+
const inverseProp = collection.property.inversedBy ?? collection.property.mappedBy;
|
|
144
|
+
const target = Reference_1.Reference.unwrapReference(result[inverseProp]);
|
|
145
|
+
if (target instanceof Collection_1.Collection) {
|
|
146
|
+
for (const item of target) {
|
|
147
|
+
if (item === collection.owner) {
|
|
148
148
|
return true;
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
-
else {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
else if (target) {
|
|
153
|
+
return target === collection.owner;
|
|
154
|
+
}
|
|
155
|
+
// FIXME https://github.com/mikro-orm/mikro-orm/issues/6031
|
|
156
|
+
if (!target && collection.property.kind === enums_1.ReferenceKind.MANY_TO_MANY) {
|
|
157
|
+
throw new Error(`Inverse side is required for M:N relations with dataloader: ${collection.owner.constructor.name}.${collection.property.name}`);
|
|
156
158
|
}
|
|
157
159
|
return false;
|
|
158
160
|
};
|
package/utils/clone.js
CHANGED
|
@@ -75,7 +75,7 @@ function clone(parent, respectCustomCloneMethod = true) {
|
|
|
75
75
|
child.lastIndex = parent.lastIndex;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
else if (parent instanceof Date
|
|
78
|
+
else if (parent instanceof Date) {
|
|
79
79
|
child = new Date(parent.getTime());
|
|
80
80
|
}
|
|
81
81
|
else if (Buffer.isBuffer(parent)) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { EntityManager } from '../EntityManager';
|
|
2
|
+
import { MikroORM } from '../MikroORM';
|
|
3
|
+
import type { ContextProvider, MaybePromise } from '../typings';
|
|
4
|
+
/**
|
|
5
|
+
* Find `EntityManager` in provided context, or else in instance's `orm` or `em` properties.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveContextProvider<T>(caller: T & {
|
|
8
|
+
orm?: MaybePromise<MikroORM>;
|
|
9
|
+
em?: MaybePromise<EntityManager>;
|
|
10
|
+
}, provider?: ContextProvider<T>): Promise<EntityManager | undefined>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveContextProvider = resolveContextProvider;
|
|
4
|
+
const EntityRepository_1 = require("../entity/EntityRepository");
|
|
5
|
+
const EntityManager_1 = require("../EntityManager");
|
|
6
|
+
const MikroORM_1 = require("../MikroORM");
|
|
7
|
+
function getEntityManager(caller, context) {
|
|
8
|
+
if (context instanceof EntityManager_1.EntityManager) {
|
|
9
|
+
return context;
|
|
10
|
+
}
|
|
11
|
+
if (context instanceof EntityRepository_1.EntityRepository) {
|
|
12
|
+
return context.getEntityManager();
|
|
13
|
+
}
|
|
14
|
+
if (context instanceof MikroORM_1.MikroORM) {
|
|
15
|
+
return context.em;
|
|
16
|
+
}
|
|
17
|
+
if (caller.em instanceof EntityManager_1.EntityManager) {
|
|
18
|
+
return caller.em;
|
|
19
|
+
}
|
|
20
|
+
if (caller.orm instanceof MikroORM_1.MikroORM) {
|
|
21
|
+
return caller.orm.em;
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find `EntityManager` in provided context, or else in instance's `orm` or `em` properties.
|
|
27
|
+
*/
|
|
28
|
+
async function resolveContextProvider(caller, provider) {
|
|
29
|
+
const context = typeof provider === 'function' ? await provider(caller) : await provider;
|
|
30
|
+
return getEntityManager({ orm: await caller.orm, em: await caller.em }, context);
|
|
31
|
+
}
|