@mikro-orm/core 6.5.10-dev.10 → 6.5.10-dev.12
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.d.ts +9 -6
- package/EntityManager.js +33 -21
- package/entity/EntityLoader.js +19 -1
- package/package.json +2 -2
- package/typings.d.ts +1 -0
package/EntityManager.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type Configuration, Cursor } from './utils';
|
|
|
4
4
|
import { type AssignOptions, EntityFactory, EntityLoader, type EntityLoaderOptions, type EntityRepository, EntityValidator, Reference } from './entity';
|
|
5
5
|
import { UnitOfWork } from './unit-of-work';
|
|
6
6
|
import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from './drivers';
|
|
7
|
-
import type { AnyEntity, AnyString, ArrayElement, AutoPath, ConnectionType, Dictionary, EntityData, EntityDictionary, EntityDTO, EntityMetadata, EntityName, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MaybePromise, MergeLoaded, MergeSelected, NoInfer, ObjectQuery, Primary, Ref, RequiredEntityData, UnboxArray } from './typings';
|
|
7
|
+
import type { AnyEntity, AnyString, ArrayElement, AutoPath, ConnectionType, Dictionary, EntityData, EntityDictionary, EntityDTO, EntityMetadata, EntityName, FilterDef, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MaybePromise, MergeLoaded, MergeSelected, NoInfer, ObjectQuery, Primary, Ref, RequiredEntityData, UnboxArray } from './typings';
|
|
8
8
|
import { FlushMode, LockMode, PopulatePath, type TransactionOptions } from './enums';
|
|
9
9
|
import type { MetadataStorage } from './metadata';
|
|
10
10
|
import type { Transaction } from './connections';
|
|
@@ -83,19 +83,19 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
|
|
|
83
83
|
/**
|
|
84
84
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
85
85
|
*/
|
|
86
|
-
addFilter<T1>(name: string, cond: FilterQuery<T1> | ((args: Dictionary) => MaybePromise<FilterQuery<T1>>), entityName?: EntityName<T1> | [EntityName<T1>],
|
|
86
|
+
addFilter<T1>(name: string, cond: FilterQuery<T1> | ((args: Dictionary) => MaybePromise<FilterQuery<T1>>), entityName?: EntityName<T1> | [EntityName<T1>], options?: boolean | Partial<FilterDef>): void;
|
|
87
87
|
/**
|
|
88
88
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
89
89
|
*/
|
|
90
|
-
addFilter<T1, T2>(name: string, cond: FilterQuery<T1 | T2> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2>>), entityName?: [EntityName<T1>, EntityName<T2>],
|
|
90
|
+
addFilter<T1, T2>(name: string, cond: FilterQuery<T1 | T2> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2>>), entityName?: [EntityName<T1>, EntityName<T2>], options?: boolean | Partial<FilterDef>): void;
|
|
91
91
|
/**
|
|
92
92
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
93
93
|
*/
|
|
94
|
-
addFilter<T1, T2, T3>(name: string, cond: FilterQuery<T1 | T2 | T3> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2 | T3>>), entityName?: [EntityName<T1>, EntityName<T2>, EntityName<T3>],
|
|
94
|
+
addFilter<T1, T2, T3>(name: string, cond: FilterQuery<T1 | T2 | T3> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2 | T3>>), entityName?: [EntityName<T1>, EntityName<T2>, EntityName<T3>], options?: boolean | Partial<FilterDef>): void;
|
|
95
95
|
/**
|
|
96
96
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
97
97
|
*/
|
|
98
|
-
addFilter(name: string, cond: Dictionary | ((args: Dictionary) => MaybePromise<FilterQuery<AnyEntity>>), entityName?: EntityName<AnyEntity> | EntityName<AnyEntity>[],
|
|
98
|
+
addFilter(name: string, cond: Dictionary | ((args: Dictionary) => MaybePromise<FilterQuery<AnyEntity>>), entityName?: EntityName<AnyEntity> | EntityName<AnyEntity>[], options?: boolean | Partial<FilterDef>): void;
|
|
99
99
|
/**
|
|
100
100
|
* Sets filter parameter values globally inside context defined by this entity manager.
|
|
101
101
|
* If you want to set shared value for all contexts, be sure to use the root entity manager.
|
|
@@ -123,7 +123,10 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
|
|
|
123
123
|
/**
|
|
124
124
|
* When filters are active on M:1 or 1:1 relations, we need to ref join them eagerly as they might affect the FK value.
|
|
125
125
|
*/
|
|
126
|
-
protected autoJoinRefsForFilters<T extends object>(meta: EntityMetadata<T>, options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any
|
|
126
|
+
protected autoJoinRefsForFilters<T extends object>(meta: EntityMetadata<T>, options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, parent?: {
|
|
127
|
+
className: string;
|
|
128
|
+
propName: string;
|
|
129
|
+
}): Promise<void>;
|
|
127
130
|
/**
|
|
128
131
|
* @internal
|
|
129
132
|
*/
|
package/EntityManager.js
CHANGED
|
@@ -197,8 +197,8 @@ class EntityManager {
|
|
|
197
197
|
/**
|
|
198
198
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
199
199
|
*/
|
|
200
|
-
addFilter(name, cond, entityName,
|
|
201
|
-
|
|
200
|
+
addFilter(name, cond, entityName, options = true) {
|
|
201
|
+
options = typeof options === 'object' ? { name, cond, default: true, ...options } : { name, cond, default: options };
|
|
202
202
|
if (entityName) {
|
|
203
203
|
options.entity = utils_1.Utils.asArray(entityName).map(n => utils_1.Utils.className(n));
|
|
204
204
|
}
|
|
@@ -308,29 +308,29 @@ class EntityManager {
|
|
|
308
308
|
/**
|
|
309
309
|
* When filters are active on M:1 or 1:1 relations, we need to ref join them eagerly as they might affect the FK value.
|
|
310
310
|
*/
|
|
311
|
-
async autoJoinRefsForFilters(meta, options) {
|
|
312
|
-
if (!meta || !this.config.get('autoJoinRefsForFilters')) {
|
|
311
|
+
async autoJoinRefsForFilters(meta, options, parent) {
|
|
312
|
+
if (!meta || !this.config.get('autoJoinRefsForFilters') || options.filters === false) {
|
|
313
313
|
return;
|
|
314
314
|
}
|
|
315
|
-
const props = meta.relations.filter(prop => {
|
|
316
|
-
return !prop.object && [enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
317
|
-
&& ((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)));
|
|
318
|
-
});
|
|
319
315
|
const ret = options.populate;
|
|
320
|
-
for (const prop of
|
|
316
|
+
for (const prop of meta.relations) {
|
|
317
|
+
if (prop.object
|
|
318
|
+
|| ![enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
319
|
+
|| !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
320
|
+
|| (parent?.className === prop.targetMeta.root.className && parent.propName === prop.inversedBy)) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
321
323
|
const cond = await this.applyFilters(prop.type, {}, options.filters ?? {}, 'read', options);
|
|
322
324
|
if (!utils_1.Utils.isEmpty(cond)) {
|
|
323
325
|
const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
|
|
324
326
|
let found = false;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
found = true;
|
|
333
|
-
}
|
|
327
|
+
for (const hint of populated) {
|
|
328
|
+
if (!hint.all) {
|
|
329
|
+
hint.filter = true;
|
|
330
|
+
}
|
|
331
|
+
const strategy = (0, utils_2.getLoadingStrategy)(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
332
|
+
if (hint.field === `${prop.name}:ref` || (hint.filter && strategy === enums_1.LoadStrategy.JOINED)) {
|
|
333
|
+
found = true;
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
336
|
if (!found) {
|
|
@@ -338,6 +338,14 @@ class EntityManager {
|
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
+
for (const hint of ret) {
|
|
342
|
+
const [field, ref] = hint.field.split(':');
|
|
343
|
+
const prop = meta?.properties[field];
|
|
344
|
+
if (prop && !ref) {
|
|
345
|
+
hint.children ??= [];
|
|
346
|
+
await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { className: meta.root.className, propName: prop.name });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
341
349
|
}
|
|
342
350
|
/**
|
|
343
351
|
* @internal
|
|
@@ -376,13 +384,17 @@ class EntityManager {
|
|
|
376
384
|
else {
|
|
377
385
|
cond = filter.cond;
|
|
378
386
|
}
|
|
379
|
-
|
|
387
|
+
cond = utils_1.QueryHelper.processWhere({
|
|
380
388
|
where: cond,
|
|
381
389
|
entityName,
|
|
382
390
|
metadata: this.metadata,
|
|
383
391
|
platform: this.driver.getPlatform(),
|
|
384
392
|
aliased: type === 'read',
|
|
385
|
-
})
|
|
393
|
+
});
|
|
394
|
+
if (filter.strict) {
|
|
395
|
+
Object.defineProperty(cond, '__strict', { value: filter.strict, enumerable: false });
|
|
396
|
+
}
|
|
397
|
+
ret.push(cond);
|
|
386
398
|
}
|
|
387
399
|
const conds = [...ret, where].filter(c => utils_1.Utils.hasObjectKeys(c));
|
|
388
400
|
return conds.length > 1 ? { $and: conds } : conds[0];
|
|
@@ -1387,7 +1399,7 @@ class EntityManager {
|
|
|
1387
1399
|
const em = this.getContext();
|
|
1388
1400
|
em.prepareOptions(options);
|
|
1389
1401
|
const entityName = arr[0].constructor.name;
|
|
1390
|
-
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate }, options.validate);
|
|
1402
|
+
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
|
|
1391
1403
|
await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
|
|
1392
1404
|
return entities;
|
|
1393
1405
|
}
|
package/entity/EntityLoader.js
CHANGED
|
@@ -213,7 +213,7 @@ class EntityLoader {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
async findChildren(entities, prop, populate, options, ref) {
|
|
216
|
-
const children = this.getChildReferences(entities, prop, options, ref);
|
|
216
|
+
const children = Utils_1.Utils.unique(this.getChildReferences(entities, prop, options, ref));
|
|
217
217
|
const meta = prop.targetMeta;
|
|
218
218
|
let fk = Utils_1.Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
219
219
|
let schema = options.schema;
|
|
@@ -269,6 +269,24 @@ class EntityLoader {
|
|
|
269
269
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
270
270
|
visited: options.visited,
|
|
271
271
|
});
|
|
272
|
+
if ([enums_1.ReferenceKind.ONE_TO_ONE, enums_1.ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
|
|
273
|
+
const nullVal = this.em.config.get('forceUndefined') ? undefined : null;
|
|
274
|
+
const itemsMap = {};
|
|
275
|
+
const childrenMap = {};
|
|
276
|
+
for (const item of items) {
|
|
277
|
+
itemsMap[(0, wrap_1.helper)(item).getSerializedPrimaryKey()] ??= true;
|
|
278
|
+
}
|
|
279
|
+
for (const child of children) {
|
|
280
|
+
childrenMap[(0, wrap_1.helper)(child).getSerializedPrimaryKey()] ??= true;
|
|
281
|
+
}
|
|
282
|
+
for (const entity of entities) {
|
|
283
|
+
const key = (0, wrap_1.helper)(entity[prop.name] ?? {})?.getSerializedPrimaryKey();
|
|
284
|
+
if (childrenMap[key] != null && itemsMap[key] == null) {
|
|
285
|
+
entity[prop.name] = nullVal;
|
|
286
|
+
(0, wrap_1.helper)(entity).__originalEntityData[prop.name] = null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
272
290
|
for (const item of items) {
|
|
273
291
|
if (ref && !(0, wrap_1.helper)(item).__onLoadFired) {
|
|
274
292
|
(0, wrap_1.helper)(item).__initialized = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "6.5.10-dev.
|
|
3
|
+
"version": "6.5.10-dev.12",
|
|
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.3.2",
|
|
66
66
|
"globby": "11.1.0",
|
|
67
|
-
"mikro-orm": "6.5.10-dev.
|
|
67
|
+
"mikro-orm": "6.5.10-dev.12",
|
|
68
68
|
"reflect-metadata": "0.2.2"
|
|
69
69
|
}
|
|
70
70
|
}
|
package/typings.d.ts
CHANGED
|
@@ -710,6 +710,7 @@ export type FilterDef = {
|
|
|
710
710
|
default?: boolean;
|
|
711
711
|
entity?: string[];
|
|
712
712
|
args?: boolean;
|
|
713
|
+
strict?: boolean;
|
|
713
714
|
};
|
|
714
715
|
export type Populate<T, P extends string = never> = readonly AutoPath<T, P, `${PopulatePath}`>[] | false;
|
|
715
716
|
export type PopulateOptions<T> = {
|