@mikro-orm/core 7.1.0-dev.1 → 7.1.0-dev.10
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 +63 -11
- package/EntityManager.js +163 -18
- package/drivers/DatabaseDriver.d.ts +1 -0
- package/drivers/DatabaseDriver.js +3 -0
- package/drivers/IDatabaseDriver.d.ts +30 -1
- package/entity/BaseEntity.d.ts +2 -2
- package/entity/Collection.d.ts +6 -3
- package/entity/Collection.js +15 -4
- package/entity/EntityFactory.js +20 -1
- package/entity/EntityLoader.d.ts +3 -1
- package/entity/EntityLoader.js +39 -16
- package/entity/EntityRepository.d.ts +27 -9
- package/entity/EntityRepository.js +12 -0
- package/entity/WrappedEntity.d.ts +2 -2
- package/entity/defineEntity.d.ts +40 -9
- package/entity/defineEntity.js +0 -6
- package/entity/utils.js +4 -5
- package/errors.d.ts +2 -0
- package/errors.js +4 -0
- package/index.d.ts +2 -2
- package/index.js +1 -1
- package/metadata/MetadataDiscovery.d.ts +11 -0
- package/metadata/MetadataDiscovery.js +127 -9
- package/metadata/MetadataValidator.js +9 -0
- package/metadata/types.d.ts +10 -2
- package/naming-strategy/AbstractNamingStrategy.d.ts +1 -1
- package/naming-strategy/NamingStrategy.d.ts +1 -1
- package/package.json +1 -1
- package/platforms/Platform.d.ts +5 -0
- package/platforms/Platform.js +7 -0
- package/serialization/EntitySerializer.d.ts +18 -6
- package/serialization/EntitySerializer.js +31 -5
- package/typings.d.ts +108 -6
- package/typings.js +19 -2
- package/utils/AbstractMigrator.d.ts +11 -1
- package/utils/AbstractMigrator.js +203 -0
- package/utils/Configuration.d.ts +7 -0
- package/utils/Configuration.js +1 -0
- package/utils/DataloaderUtils.d.ts +10 -1
- package/utils/DataloaderUtils.js +78 -0
- package/utils/QueryHelper.d.ts +16 -0
- package/utils/QueryHelper.js +15 -0
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +1 -1
- package/utils/fs-utils.d.ts +2 -0
- package/utils/fs-utils.js +7 -1
package/entity/EntityFactory.js
CHANGED
|
@@ -316,11 +316,30 @@ export class EntityFactory {
|
|
|
316
316
|
else if (!onCreateOnly && prop.default != null && !isRaw(prop.default) && entity[prop.name] === undefined) {
|
|
317
317
|
entity[prop.name] = prop.default;
|
|
318
318
|
}
|
|
319
|
+
else if (!onCreateOnly &&
|
|
320
|
+
this.#config.get('initNullableProperties') &&
|
|
321
|
+
prop.nullable &&
|
|
322
|
+
prop.default == null &&
|
|
323
|
+
!prop.defaultRaw &&
|
|
324
|
+
entity[prop.name] === undefined) {
|
|
325
|
+
entity[prop.name] = (this.#config.get('forceUndefined') ? undefined : null);
|
|
326
|
+
}
|
|
319
327
|
if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
|
|
320
328
|
const items = prop.array ? entity[prop.name] : [entity[prop.name]];
|
|
321
329
|
for (const item of items) {
|
|
322
330
|
// Embedded sub-properties need all defaults since the DB can't apply them within JSON columns.
|
|
323
|
-
|
|
331
|
+
// For polymorphic embeddables, resolve the actual subtype to avoid setting
|
|
332
|
+
// properties from other subtypes (e.g. Cat's canMeow on a Dog instance).
|
|
333
|
+
let targetMeta = prop.targetMeta;
|
|
334
|
+
if (targetMeta.polymorphs && targetMeta.discriminatorColumn) {
|
|
335
|
+
const discValue = item[targetMeta.discriminatorColumn];
|
|
336
|
+
// eslint-disable-next-line eqeqeq
|
|
337
|
+
const resolved = targetMeta.polymorphs.find(m => m.discriminatorValue == discValue);
|
|
338
|
+
if (resolved) {
|
|
339
|
+
targetMeta = resolved;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
this.assignDefaultValues(item, targetMeta);
|
|
324
343
|
}
|
|
325
344
|
}
|
|
326
345
|
}
|
package/entity/EntityLoader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyEntity, AutoPath, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
|
|
1
|
+
import type { AnyEntity, AutoPath, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateHintOptions, PopulateOptions } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
|
|
4
4
|
import type { FilterOptions } from '../drivers/IDatabaseDriver.js';
|
|
@@ -37,6 +37,8 @@ export interface EntityLoaderOptions<Entity, Fields extends string = never, Excl
|
|
|
37
37
|
connectionType?: ConnectionType;
|
|
38
38
|
/** Logging options for the query. */
|
|
39
39
|
logging?: LoggingOptions;
|
|
40
|
+
/** Per-relation populate overrides (limit, offset, orderBy). */
|
|
41
|
+
populateHints?: Record<string, PopulateHintOptions>;
|
|
40
42
|
}
|
|
41
43
|
/** Responsible for batch-loading entity relations using either select-in or joined loading strategies. */
|
|
42
44
|
export declare class EntityLoader {
|
package/entity/EntityLoader.js
CHANGED
|
@@ -177,8 +177,9 @@ export class EntityLoader {
|
|
|
177
177
|
Utils.isObject(orderBy[prop.name]))
|
|
178
178
|
.flatMap(orderBy => orderBy[prop.name]);
|
|
179
179
|
const where = await this.extractChildCondition(options, prop);
|
|
180
|
+
const mergedOrderBy = populate.orderBy ? Utils.asArray(populate.orderBy) : innerOrderBy;
|
|
180
181
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && this.#driver.getPlatform().usesPivotTable()) {
|
|
181
|
-
const pivotOrderBy = QueryHelper.mergeOrderBy(
|
|
182
|
+
const pivotOrderBy = QueryHelper.mergeOrderBy(mergedOrderBy, prop.orderBy, prop.targetMeta?.orderBy);
|
|
182
183
|
const res = await this.findChildrenFromPivotTable(filtered, prop, options, pivotOrderBy, populate, !!ref);
|
|
183
184
|
return Utils.flatten(res);
|
|
184
185
|
}
|
|
@@ -188,10 +189,12 @@ export class EntityLoader {
|
|
|
188
189
|
const { items, partial } = await this.findChildren(options.filtered ?? entities, prop, populate, {
|
|
189
190
|
...options,
|
|
190
191
|
where,
|
|
191
|
-
orderBy:
|
|
192
|
+
orderBy: mergedOrderBy,
|
|
192
193
|
}, !!(ref || prop.mapToPk));
|
|
193
|
-
const
|
|
194
|
-
|
|
194
|
+
const hasLimit = populate.limit != null;
|
|
195
|
+
const isPartial = partial || hasLimit;
|
|
196
|
+
const customOrder = mergedOrderBy.length > 0 || !!prop.orderBy || !!prop.targetMeta?.orderBy;
|
|
197
|
+
this.initializeCollections(filtered, prop, field, items, customOrder, isPartial, hasLimit);
|
|
195
198
|
return items;
|
|
196
199
|
}
|
|
197
200
|
async populateScalar(meta, filtered, options) {
|
|
@@ -269,15 +272,15 @@ export class EntityLoader {
|
|
|
269
272
|
}));
|
|
270
273
|
return allItems;
|
|
271
274
|
}
|
|
272
|
-
initializeCollections(filtered, prop, field, children, customOrder, partial) {
|
|
275
|
+
initializeCollections(filtered, prop, field, children, customOrder, partial, readonly) {
|
|
273
276
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
274
|
-
this.initializeOneToMany(filtered, children, prop, field, partial);
|
|
277
|
+
this.initializeOneToMany(filtered, children, prop, field, partial, readonly);
|
|
275
278
|
}
|
|
276
279
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.#driver.getPlatform().usesPivotTable()) {
|
|
277
|
-
this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
|
|
280
|
+
this.initializeManyToMany(filtered, children, prop, field, customOrder, partial, readonly);
|
|
278
281
|
}
|
|
279
282
|
}
|
|
280
|
-
initializeOneToMany(filtered, children, prop, field, partial) {
|
|
283
|
+
initializeOneToMany(filtered, children, prop, field, partial, readonly) {
|
|
281
284
|
const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
|
|
282
285
|
const map = {};
|
|
283
286
|
for (const entity of filtered) {
|
|
@@ -293,14 +296,14 @@ export class EntityLoader {
|
|
|
293
296
|
}
|
|
294
297
|
for (const entity of filtered) {
|
|
295
298
|
const key = helper(entity).getSerializedPrimaryKey();
|
|
296
|
-
entity[field].hydrate(map[key], undefined, partial);
|
|
299
|
+
entity[field].hydrate(map[key], undefined, partial, readonly);
|
|
297
300
|
}
|
|
298
301
|
}
|
|
299
|
-
initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
|
|
302
|
+
initializeManyToMany(filtered, children, prop, field, customOrder, partial, readonly) {
|
|
300
303
|
if (prop.mappedBy) {
|
|
301
304
|
for (const entity of filtered) {
|
|
302
305
|
const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
|
|
303
|
-
entity[field].hydrate(items, true, partial);
|
|
306
|
+
entity[field].hydrate(items, true, partial, readonly);
|
|
304
307
|
}
|
|
305
308
|
}
|
|
306
309
|
else {
|
|
@@ -311,7 +314,7 @@ export class EntityLoader {
|
|
|
311
314
|
if (!customOrder) {
|
|
312
315
|
items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
|
|
313
316
|
}
|
|
314
|
-
entity[field].hydrate(items, true, partial);
|
|
317
|
+
entity[field].hydrate(items, true, partial, readonly);
|
|
315
318
|
}
|
|
316
319
|
}
|
|
317
320
|
}
|
|
@@ -375,7 +378,7 @@ export class EntityLoader {
|
|
|
375
378
|
where = { $and: [where, prop.where] };
|
|
376
379
|
}
|
|
377
380
|
const orderBy = QueryHelper.mergeOrderBy(options.orderBy, prop.orderBy);
|
|
378
|
-
const
|
|
381
|
+
const findOptions = {
|
|
379
382
|
filters,
|
|
380
383
|
convertCustomTypes,
|
|
381
384
|
lockMode,
|
|
@@ -394,7 +397,15 @@ export class EntityLoader {
|
|
|
394
397
|
refresh: refresh && !children.every(item => options.visited.has(item)),
|
|
395
398
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
396
399
|
visited: options.visited,
|
|
397
|
-
}
|
|
400
|
+
};
|
|
401
|
+
if (populate.limit != null) {
|
|
402
|
+
findOptions._partitionLimit = {
|
|
403
|
+
partitionBy: fk,
|
|
404
|
+
limit: populate.limit,
|
|
405
|
+
offset: populate.offset,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
const items = await this.#em.find(meta.class, where, findOptions);
|
|
398
409
|
// For targetKey relations, wire up loaded entities to parent references
|
|
399
410
|
// This is needed because the references were created under alternate key,
|
|
400
411
|
// but loaded entities are stored under PK, so they don't automatically merge
|
|
@@ -582,11 +593,18 @@ export class EntityLoader {
|
|
|
582
593
|
const options2 = { ...options, fields, exclude, populateFilter };
|
|
583
594
|
['limit', 'offset', 'first', 'last', 'before', 'after', 'overfetch'].forEach(prop => delete options2[prop]);
|
|
584
595
|
options2.populate = populate?.children ?? [];
|
|
596
|
+
if (populate?.limit != null) {
|
|
597
|
+
options2._partitionLimit = {
|
|
598
|
+
limit: populate.limit,
|
|
599
|
+
offset: populate.offset,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
585
602
|
if (!Utils.isEmpty(prop.where)) {
|
|
586
603
|
where = { $and: [where, prop.where] };
|
|
587
604
|
}
|
|
588
605
|
const map = await this.#driver.loadFromPivotTable(prop, ids, where, orderBy, this.#em.getTransactionContext(), options2, pivotJoin);
|
|
589
606
|
const children = [];
|
|
607
|
+
const isUnionTargetMN = QueryHelper.isUnionTargetPolymorphic(prop);
|
|
590
608
|
for (let i = 0; i < filtered.length; i++) {
|
|
591
609
|
const entity = filtered[i];
|
|
592
610
|
const items = map[Utils.getPrimaryKeyHash(ids[i])].map(item => {
|
|
@@ -596,7 +614,11 @@ export class EntityLoader {
|
|
|
596
614
|
schema: options.schema ?? this.#em.config.get('schema'),
|
|
597
615
|
});
|
|
598
616
|
}
|
|
599
|
-
|
|
617
|
+
// Union-target items carry their concrete class via `constructor` — dispatch to the right factory call.
|
|
618
|
+
const targetClass = isUnionTargetMN && item.constructor !== Object
|
|
619
|
+
? item.constructor
|
|
620
|
+
: prop.targetMeta.class;
|
|
621
|
+
const entity = this.#em.getEntityFactory().create(targetClass, item, {
|
|
600
622
|
refresh,
|
|
601
623
|
merge: true,
|
|
602
624
|
convertCustomTypes: true,
|
|
@@ -604,7 +626,8 @@ export class EntityLoader {
|
|
|
604
626
|
});
|
|
605
627
|
return this.#em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
|
|
606
628
|
});
|
|
607
|
-
|
|
629
|
+
const hasLimit = populate?.limit != null;
|
|
630
|
+
entity[prop.name].hydrate(items, true, hasLimit, hasLimit);
|
|
608
631
|
children.push(items);
|
|
609
632
|
}
|
|
610
633
|
return children;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { PopulatePath } from '../enums.js';
|
|
2
2
|
import type { CreateOptions, EntityManager, MergeOptions } from '../EntityManager.js';
|
|
3
3
|
import type { AssignOptions } from './EntityAssigner.js';
|
|
4
|
-
import type { EntityData,
|
|
5
|
-
import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, StreamOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
|
|
4
|
+
import type { Dictionary, EntityData, EntityDictionary, EntityKey, EntityName, FilterQuery, Loaded, Primary, AutoPath, RequiredEntityData, Ref, EntityType, EntityDTO, MergeSelected, FromEntityType, IsSubset, MergeLoaded, ArrayElement, IndexFilterQuery, WithUsingOptions } from '../typings.js';
|
|
5
|
+
import type { CountByOptions, CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, StreamOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
|
|
6
6
|
import type { EntityLoaderOptions } from './EntityLoader.js';
|
|
7
7
|
import type { Cursor } from '../utils/Cursor.js';
|
|
8
8
|
/** Repository class providing a type-safe API for querying and persisting a specific entity type. */
|
|
@@ -13,13 +13,17 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
13
13
|
/**
|
|
14
14
|
* Finds first entity matching your `where` query.
|
|
15
15
|
*/
|
|
16
|
-
findOne<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(where: FilterQuery<Entity
|
|
16
|
+
findOne<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(where: [Using] extends [never] ? FilterQuery<Entity> : IndexFilterQuery<Entity, Using>, options?: FindOneOptions<Entity, Hint, Fields, Excludes> & {
|
|
17
|
+
using?: Using | Using[];
|
|
18
|
+
}): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
|
17
19
|
/**
|
|
18
20
|
* Finds first entity matching your `where` query. If nothing is found, it will throw an error.
|
|
19
21
|
* You can override the factory for creating this method via `options.failHandler` locally
|
|
20
22
|
* or via `Configuration.findOneOrFailHandler` globally.
|
|
21
23
|
*/
|
|
22
|
-
findOneOrFail<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(where: FilterQuery<Entity>, options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes>
|
|
24
|
+
findOneOrFail<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(where: [Using] extends [never] ? FilterQuery<Entity> : IndexFilterQuery<Entity, Using>, options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes> & {
|
|
25
|
+
using?: Using | Using[];
|
|
26
|
+
}): Promise<Loaded<Entity, Hint, Fields, Excludes>>;
|
|
23
27
|
/**
|
|
24
28
|
* Creates or updates the entity, based on whether it is already present in the database.
|
|
25
29
|
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
|
@@ -72,24 +76,28 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
72
76
|
/**
|
|
73
77
|
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
|
74
78
|
*/
|
|
75
|
-
find<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(where: FilterQuery<Entity>, options?: FindOptions<Entity, Hint, Fields, Excludes>
|
|
79
|
+
find<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(where: [Using] extends [never] ? FilterQuery<Entity> : IndexFilterQuery<Entity, Using>, options?: FindOptions<Entity, Hint, Fields, Excludes> & {
|
|
80
|
+
using?: Using | Using[];
|
|
81
|
+
}): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
76
82
|
/**
|
|
77
83
|
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as tuple
|
|
78
84
|
* where first element is the array of entities, and the second is the count.
|
|
79
85
|
*/
|
|
80
|
-
findAndCount<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(where: FilterQuery<Entity
|
|
86
|
+
findAndCount<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(where: [Using] extends [never] ? FilterQuery<Entity> : IndexFilterQuery<Entity, Using>, options?: FindOptions<Entity, Hint, Fields, Excludes> & {
|
|
87
|
+
using?: Using | Using[];
|
|
88
|
+
}): Promise<[Loaded<Entity, Hint, Fields, Excludes>[], number]>;
|
|
81
89
|
/**
|
|
82
90
|
* @inheritDoc EntityManager.findByCursor
|
|
83
91
|
*/
|
|
84
|
-
findByCursor<Hint extends string = never, Fields extends string = never, Excludes extends string = never, IncludeCount extends boolean = true>(options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
|
92
|
+
findByCursor<Hint extends string = never, Fields extends string = never, Excludes extends string = never, IncludeCount extends boolean = true, Using extends string = never>(options: WithUsingOptions<FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>, Entity, Using>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
|
85
93
|
/**
|
|
86
94
|
* Finds all entities of given type. You can pass additional options via the `options` parameter.
|
|
87
95
|
*/
|
|
88
|
-
findAll<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(options?: FindAllOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
96
|
+
findAll<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(options?: WithUsingOptions<FindAllOptions<Entity, Hint, Fields, Excludes>, Entity, Using>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
89
97
|
/**
|
|
90
98
|
* @inheritDoc EntityManager.stream
|
|
91
99
|
*/
|
|
92
|
-
stream<Hint extends string = never, Fields extends string = never, Excludes extends string = never>(options?: StreamOptions<Entity, Hint, Fields, Excludes>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
|
|
100
|
+
stream<Hint extends string = never, Fields extends string = never, Excludes extends string = never, Using extends string = never>(options?: WithUsingOptions<StreamOptions<Entity, Hint, Fields, Excludes>, Entity, Using>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
|
|
93
101
|
/**
|
|
94
102
|
* @inheritDoc EntityManager.insert
|
|
95
103
|
*/
|
|
@@ -199,6 +207,16 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
199
207
|
* Returns total number of entities matching your `where` query.
|
|
200
208
|
*/
|
|
201
209
|
count<Hint extends string = never>(where?: FilterQuery<Entity>, options?: CountOptions<Entity, Hint>): Promise<number>;
|
|
210
|
+
/**
|
|
211
|
+
* Counts entities grouped by one or more properties.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```ts
|
|
215
|
+
* const counts = await repo.countBy('status');
|
|
216
|
+
* // { 'active': 5, 'inactive': 2 }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
countBy(groupBy: EntityKey<Entity> | readonly EntityKey<Entity>[], options?: CountByOptions<Entity>): Promise<Dictionary<number>>;
|
|
202
220
|
/** Returns the entity class name associated with this repository. */
|
|
203
221
|
getEntityName(): string;
|
|
204
222
|
/**
|
|
@@ -194,6 +194,18 @@ export class EntityRepository {
|
|
|
194
194
|
async count(where = {}, options = {}) {
|
|
195
195
|
return this.getEntityManager().count(this.entityName, where, options);
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Counts entities grouped by one or more properties.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* const counts = await repo.countBy('status');
|
|
203
|
+
* // { 'active': 5, 'inactive': 2 }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
async countBy(groupBy, options) {
|
|
207
|
+
return this.getEntityManager().countBy(this.entityName, groupBy, options);
|
|
208
|
+
}
|
|
197
209
|
/** Returns the entity class name associated with this repository. */
|
|
198
210
|
getEntityName() {
|
|
199
211
|
return Utils.className(this.entityName);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PopulatePath } from '../enums.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
|
-
import type { Dictionary, EntityData, EntityDictionary, EntityMetadata, IHydrator, EntityKey, PopulateOptions, Primary, AutoPath, Ref, AddEager, LoadedReference, EntityDTO, Loaded, SerializeDTO, FromEntityType, IsSubset, MergeSelected } from '../typings.js';
|
|
3
|
+
import type { Dictionary, EntityData, EntityDictionary, EntityMetadata, IHydrator, EntityKey, PopulateOptions, Primary, AutoPath, Ref, AddEager, LoadedReference, EntityDTO, Loaded, ExtractFieldsHint, ResolveSerializeFields, SerializeDTO, SerializeFieldsKeepPK, FromEntityType, IsSubset, MergeSelected } from '../typings.js';
|
|
4
4
|
import { Reference } from './Reference.js';
|
|
5
5
|
import { type AssignOptions } from './EntityAssigner.js';
|
|
6
6
|
import type { EntityLoaderOptions } from './EntityLoader.js';
|
|
@@ -54,7 +54,7 @@ export declare class WrappedEntity<Entity extends object> {
|
|
|
54
54
|
/** Converts the entity to a plain object representation, optionally excluding specified fields. */
|
|
55
55
|
toObject<Ignored extends EntityKey<Entity> = never>(ignoreFields?: Ignored[]): Omit<EntityDTO<Entity>, Ignored>;
|
|
56
56
|
/** Serializes the entity with control over which relations and fields to include or exclude. */
|
|
57
|
-
serialize<Hint extends string = never, Exclude extends string = never>(options?: SerializeOptions<Entity
|
|
57
|
+
serialize<Hint extends string = never, Exclude extends string = never, Fields extends string = never>(options?: SerializeOptions<FromEntityType<Entity>, Hint, Exclude, Fields>): SerializeDTO<FromEntityType<Entity>, Hint, Exclude, never, ResolveSerializeFields<Fields, ExtractFieldsHint<Entity>>, SerializeFieldsKeepPK<Fields>>;
|
|
58
58
|
/** Converts the entity to a plain object, including all properties regardless of serialization rules. */
|
|
59
59
|
toPOJO(): EntityDTO<Entity>;
|
|
60
60
|
/** Serializes the entity using its `toJSON` method (supports `JSON.stringify`). */
|
package/entity/defineEntity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EntityManager } from '../EntityManager.js';
|
|
2
2
|
import type { ColumnType, PropertyOptions, ReferenceOptions, EnumOptions, EmbeddedOptions, ManyToOneOptions, OneToManyOptions, OneToOneOptions, ManyToManyOptions, IndexColumnOptions } from '../metadata/types.js';
|
|
3
|
-
import type { AnyString, GeneratedColumnCallback, Constructor, CheckCallback, FilterQuery, EntityName, Dictionary, EntityMetadata, PrimaryKeyProp, EntityRepositoryType, Hidden, Opt, Primary, EntityClass, EntitySchemaWithMeta, InferEntity, MaybeReturnType, Ref, IndexCallback, FormulaCallback, EntityCtor, IsNever, IWrappedEntity, DefineConfig, Config, MaybePromise } from '../typings.js';
|
|
3
|
+
import type { AnyString, GeneratedColumnCallback, Constructor, CheckCallback, FilterQuery, EntityName, Dictionary, EntityMetadata, PrimaryKeyProp, EntityRepositoryType, Hidden, Opt, Primary, EntityClass, EntitySchemaWithMeta, InferEntity, MaybeReturnType, Ref, IndexCallback, TriggerCallback, FormulaCallback, EntityCtor, IsNever, IWrappedEntity, DefineConfig, Config, MaybePromise, IndexHints } from '../typings.js';
|
|
4
4
|
import type { Raw } from '../utils/RawQueryFragment.js';
|
|
5
5
|
import type { ScalarReference } from './Reference.js';
|
|
6
6
|
import type { SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
@@ -104,8 +104,16 @@ export interface PropertyChain<Value, Options> {
|
|
|
104
104
|
customOrder(...customOrder: string[] | number[] | boolean[]): PropertyChain<Value, Options>;
|
|
105
105
|
extra(extra: string): PropertyChain<Value, Options>;
|
|
106
106
|
ignoreSchemaChanges(...ignoreSchemaChanges: ('type' | 'extra' | 'default')[]): PropertyChain<Value, Options>;
|
|
107
|
-
index
|
|
108
|
-
|
|
107
|
+
/** Explicitly specify index on a property. When a string name is passed, it enables type-safe `using` in `FindOptions`. */
|
|
108
|
+
index<N extends string>(name: N): PropertyChain<Value, Omit<Options, 'index'> & {
|
|
109
|
+
index: N;
|
|
110
|
+
}>;
|
|
111
|
+
index(index?: boolean): PropertyChain<Value, Options>;
|
|
112
|
+
/** Set column as unique. When a string name is passed, it enables type-safe `using` in `FindOptions`. (SQL only) */
|
|
113
|
+
unique<N extends string>(name: N): PropertyChain<Value, Omit<Options, 'unique'> & {
|
|
114
|
+
unique: N;
|
|
115
|
+
}>;
|
|
116
|
+
unique(unique?: boolean): PropertyChain<Value, Options>;
|
|
109
117
|
comment(comment: string): PropertyChain<Value, Options>;
|
|
110
118
|
accessor(accessor?: string | boolean): PropertyChain<Value, Options>;
|
|
111
119
|
eager(eager?: boolean): HasKind<Options, 'm:1' | '1:m' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
@@ -127,9 +135,13 @@ export interface PropertyChain<Value, Options> {
|
|
|
127
135
|
pivotEntity(pivotEntity: () => EntityName): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
128
136
|
fixedOrder(fixedOrder?: boolean): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
129
137
|
fixedOrderColumn(fixedOrderColumn: string): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
130
|
-
array():
|
|
138
|
+
array(): Options extends {
|
|
139
|
+
kind: infer K extends string;
|
|
140
|
+
} ? K extends 'embedded' | 'enum' ? PropertyChain<Value, Omit<Options, 'array'> & {
|
|
131
141
|
array: true;
|
|
132
|
-
}> : never
|
|
142
|
+
}> : never : PropertyChain<Value, Omit<Options, 'array'> & {
|
|
143
|
+
array: true;
|
|
144
|
+
}>;
|
|
133
145
|
prefix(prefix: string | boolean): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
134
146
|
prefixMode(prefixMode: EmbeddedPrefixMode): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
135
147
|
object(object?: boolean): HasKind<Options, 'embedded'> extends true ? PropertyChain<Value, Options> : never;
|
|
@@ -334,12 +346,20 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
|
|
|
334
346
|
concurrencyCheck(concurrencyCheck?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
335
347
|
/**
|
|
336
348
|
* Explicitly specify index on a property.
|
|
349
|
+
* When a string name is passed, it is captured as a literal type for use with the `using` option in `FindOptions`.
|
|
337
350
|
*/
|
|
338
|
-
index
|
|
351
|
+
index<N extends string>(name: N): Pick<UniversalPropertyOptionsBuilder<Value, Omit<Options, 'index'> & {
|
|
352
|
+
index: N;
|
|
353
|
+
}, IncludeKeys>, IncludeKeys>;
|
|
354
|
+
index(index?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
339
355
|
/**
|
|
340
356
|
* Set column as unique for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
|
357
|
+
* When a string name is passed, it is captured as a literal type for use with the `using` option in `FindOptions`.
|
|
341
358
|
*/
|
|
342
|
-
unique
|
|
359
|
+
unique<N extends string>(name: N): Pick<UniversalPropertyOptionsBuilder<Value, Omit<Options, 'unique'> & {
|
|
360
|
+
unique: N;
|
|
361
|
+
}, IncludeKeys>, IncludeKeys>;
|
|
362
|
+
unique(unique?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
343
363
|
/**
|
|
344
364
|
* Specify column with check constraints. (Postgres driver only)
|
|
345
365
|
*
|
|
@@ -556,7 +576,7 @@ export type PropertyBuilders = {
|
|
|
556
576
|
/** Own keys + base entity keys (when TBase is not `never`). Guards against `keyof never = string | number | symbol`. */
|
|
557
577
|
type AllKeys<TProperties, TBase> = keyof TProperties | (IsNever<TBase> extends true ? never : keyof TBase);
|
|
558
578
|
/** Metadata descriptor for `defineEntity()`, combining entity options with property definitions. */
|
|
559
|
-
export interface EntityMetadataWithProperties<TName extends string, TTableName extends string, TProperties extends Record<string, any>, TPK extends (keyof TProperties)[] | undefined = undefined, TBase = never, TRepository = never, TForceObject extends boolean = false> extends Omit<Partial<EntityMetadata<InferEntityFromProperties<TProperties, TPK, TBase, TRepository>>>, 'properties' | 'extends' | 'primaryKeys' | 'hooks' | 'discriminatorColumn' | 'versionProperty' | 'concurrencyCheckKeys' | 'serializedPrimaryKey' | 'indexes' | 'uniques' | 'repository' | 'filters' | 'orderBy'> {
|
|
579
|
+
export interface EntityMetadataWithProperties<TName extends string, TTableName extends string, TProperties extends Record<string, any>, TPK extends (keyof TProperties)[] | undefined = undefined, TBase = never, TRepository = never, TForceObject extends boolean = false> extends Omit<Partial<EntityMetadata<InferEntityFromProperties<TProperties, TPK, TBase, TRepository>>>, 'properties' | 'extends' | 'primaryKeys' | 'hooks' | 'discriminatorColumn' | 'versionProperty' | 'concurrencyCheckKeys' | 'serializedPrimaryKey' | 'indexes' | 'uniques' | 'triggers' | 'repository' | 'filters' | 'orderBy'> {
|
|
560
580
|
name: TName;
|
|
561
581
|
tableName?: TTableName;
|
|
562
582
|
extends?: {
|
|
@@ -609,6 +629,15 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
|
|
|
609
629
|
fillFactor?: number;
|
|
610
630
|
disabled?: boolean;
|
|
611
631
|
}[];
|
|
632
|
+
triggers?: {
|
|
633
|
+
name?: string;
|
|
634
|
+
timing: 'before' | 'after' | 'instead of';
|
|
635
|
+
events: ('insert' | 'update' | 'delete' | 'truncate')[];
|
|
636
|
+
forEach?: 'row' | 'statement';
|
|
637
|
+
body?: string | Raw | TriggerCallback<InferEntityFromProperties<TProperties, TPK, TBase>>;
|
|
638
|
+
when?: string;
|
|
639
|
+
expression?: string;
|
|
640
|
+
}[];
|
|
612
641
|
}
|
|
613
642
|
/** Defines an entity schema using property builders, with full type inference from the property definitions. */
|
|
614
643
|
export declare function defineEntity<const TName extends string, const TTableName extends string, const TProperties extends Record<string, any>, const TPK extends (keyof TProperties)[] | undefined = undefined, const TBase = never, const TRepository = never, const TForceObject extends boolean = false>(meta: EntityMetadataWithProperties<TName, TTableName, TProperties, TPK, TBase, TRepository, TForceObject>): EntitySchemaWithMeta<TName, TTableName, InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject>, TBase, TProperties>;
|
|
@@ -665,7 +694,9 @@ export type InferEntityFromProperties<Properties extends Record<string, any>, PK
|
|
|
665
694
|
[Config]?: DefineConfig<{
|
|
666
695
|
forceObject: true;
|
|
667
696
|
}>;
|
|
668
|
-
} : {})
|
|
697
|
+
} : {}) & {
|
|
698
|
+
[IndexHints]?: [Properties];
|
|
699
|
+
};
|
|
669
700
|
type InferCombinedPrimaryKey<Properties extends Record<string, any>, PK, Base> = PK extends undefined ? CombinePrimaryKeys<InferPrimaryKey<Properties>, ExtractBasePrimaryKey<Base>> : PK;
|
|
670
701
|
type ExtractBasePrimaryKey<Base> = Base extends {
|
|
671
702
|
[PrimaryKeyProp]?: infer BasePK;
|
package/entity/defineEntity.js
CHANGED
|
@@ -191,15 +191,9 @@ export class UniversalPropertyOptionsBuilder {
|
|
|
191
191
|
concurrencyCheck(concurrencyCheck = true) {
|
|
192
192
|
return this.assignOptions({ concurrencyCheck });
|
|
193
193
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Explicitly specify index on a property.
|
|
196
|
-
*/
|
|
197
194
|
index(index = true) {
|
|
198
195
|
return this.assignOptions({ index });
|
|
199
196
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Set column as unique for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
|
202
|
-
*/
|
|
203
197
|
unique(unique = true) {
|
|
204
198
|
return this.assignOptions({ unique });
|
|
205
199
|
}
|
package/entity/utils.js
CHANGED
|
@@ -94,11 +94,10 @@ export function applyPopulateHints(populate, hints) {
|
|
|
94
94
|
if (!entry) {
|
|
95
95
|
continue;
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
entry.joinType = hint.joinType;
|
|
97
|
+
for (const key of Object.keys(hint)) {
|
|
98
|
+
if (hint[key] != null) {
|
|
99
|
+
entry[key] = hint[key];
|
|
100
|
+
}
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
103
|
}
|
package/errors.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
|
|
|
74
74
|
static viewEntityWithoutExpression(meta: EntityMetadata): MetadataError;
|
|
75
75
|
static mixedInheritanceStrategies(root: EntityMetadata, child: EntityMetadata): MetadataError;
|
|
76
76
|
static tptNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
|
77
|
+
/** Thrown when database triggers are defined on an entity using a driver that does not support them. */
|
|
78
|
+
static triggersNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
|
77
79
|
private static fromMessage;
|
|
78
80
|
}
|
|
79
81
|
/** Error thrown when an entity lookup fails to find the expected result. */
|
package/errors.js
CHANGED
|
@@ -243,6 +243,10 @@ export class MetadataError extends ValidationError {
|
|
|
243
243
|
static tptNotSupportedByDriver(meta) {
|
|
244
244
|
return new MetadataError(`Entity ${meta.className} uses TPT (Table-Per-Type) inheritance which is not supported by the current driver. TPT requires SQL JOINs and is only available with SQL drivers.`);
|
|
245
245
|
}
|
|
246
|
+
/** Thrown when database triggers are defined on an entity using a driver that does not support them. */
|
|
247
|
+
static triggersNotSupportedByDriver(meta) {
|
|
248
|
+
return new MetadataError(`Entity ${meta.className} defines database triggers which are not supported by the current driver. Triggers are only available with SQL drivers.`);
|
|
249
|
+
}
|
|
246
250
|
static fromMessage(meta, prop, message) {
|
|
247
251
|
return new MetadataError(`${meta.className}.${prop.name} ${message}`);
|
|
248
252
|
}
|
package/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* @module core
|
|
4
4
|
*/
|
|
5
|
-
export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, } from './typings.js';
|
|
6
|
-
export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, IndexCallback, FormulaCallback, FormulaTable, SchemaTable, SchemaColumns, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
|
|
5
|
+
export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, IndexHints, } from './typings.js';
|
|
6
|
+
export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IndexFilterQuery, ExtractIndexHints, IndexName, IndexColumns, WithUsingOptions, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, TriggerCallback, IndexCallback, FormulaCallback, FormulaTable, SchemaTable, SchemaColumns, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, TriggerDef, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
|
|
7
7
|
export * from './enums.js';
|
|
8
8
|
export * from './errors.js';
|
|
9
9
|
export * from './exceptions.js';
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* @module core
|
|
4
4
|
*/
|
|
5
|
-
export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, } from './typings.js';
|
|
5
|
+
export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, IndexHints, } from './typings.js';
|
|
6
6
|
export * from './enums.js';
|
|
7
7
|
export * from './errors.js';
|
|
8
8
|
export * from './exceptions.js';
|
|
@@ -54,6 +54,16 @@ export declare class MetadataDiscovery {
|
|
|
54
54
|
* Define properties for a polymorphic pivot table.
|
|
55
55
|
*/
|
|
56
56
|
private definePolymorphicPivotProperties;
|
|
57
|
+
/**
|
|
58
|
+
* Mirror of definePolymorphicPivotProperties for union-target M:N
|
|
59
|
+
* (e.g. Post.attachments -> Image | Video via shared pivot with a target-side discriminator).
|
|
60
|
+
*
|
|
61
|
+
* Pivot shape:
|
|
62
|
+
* (owner_fk..., discriminator_column, target_fk...)
|
|
63
|
+
* - owner side is a normal M:1 to the single owner entity
|
|
64
|
+
* - target side is a discriminator column + per-target-type virtual M:1 relations
|
|
65
|
+
*/
|
|
66
|
+
private defineUnionTargetPolymorphicPivotProperties;
|
|
57
67
|
/**
|
|
58
68
|
* Create a virtual M:1 relation from pivot to a polymorphic owner entity.
|
|
59
69
|
* This enables single-query join loading for inverse-side polymorphic M:N.
|
|
@@ -105,6 +115,7 @@ export declare class MetadataDiscovery {
|
|
|
105
115
|
private initAutoincrement;
|
|
106
116
|
private createSchemaTable;
|
|
107
117
|
private initCheckConstraints;
|
|
118
|
+
private initTriggers;
|
|
108
119
|
private initGeneratedColumn;
|
|
109
120
|
private getDefaultVersionValue;
|
|
110
121
|
private inferDefaultValue;
|