@mikro-orm/core 7.0.0-dev.6 → 7.0.0-dev.60
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 +85 -32
- package/EntityManager.js +281 -178
- package/MikroORM.d.ts +8 -8
- package/MikroORM.js +31 -74
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +2 -1
- package/cache/FileCacheAdapter.js +5 -4
- package/connections/Connection.d.ts +11 -7
- package/connections/Connection.js +16 -13
- package/decorators/Embedded.d.ts +5 -11
- package/decorators/Entity.d.ts +18 -3
- package/decorators/Indexed.d.ts +2 -2
- package/decorators/ManyToMany.d.ts +2 -0
- package/decorators/ManyToOne.d.ts +4 -0
- package/decorators/OneToOne.d.ts +4 -0
- package/decorators/Property.d.ts +53 -9
- package/decorators/Transactional.d.ts +3 -1
- package/decorators/Transactional.js +6 -3
- package/decorators/index.d.ts +1 -1
- package/drivers/DatabaseDriver.d.ts +11 -5
- package/drivers/DatabaseDriver.js +13 -4
- package/drivers/IDatabaseDriver.d.ts +29 -5
- package/entity/ArrayCollection.d.ts +6 -4
- package/entity/ArrayCollection.js +26 -9
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +3 -4
- package/entity/Collection.js +34 -17
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +9 -1
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +40 -22
- package/entity/EntityHelper.js +25 -8
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +69 -36
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityValidator.js +2 -2
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +32 -5
- package/entity/WrappedEntity.d.ts +0 -2
- package/entity/WrappedEntity.js +1 -5
- package/entity/defineEntity.d.ts +555 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +2 -0
- package/entity/index.js +2 -0
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +15 -3
- package/enums.d.ts +18 -5
- package/enums.js +13 -0
- package/errors.d.ts +6 -1
- package/errors.js +14 -4
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +35 -24
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +8 -4
- package/metadata/EntitySchema.js +40 -20
- package/metadata/MetadataDiscovery.d.ts +5 -7
- package/metadata/MetadataDiscovery.js +150 -155
- package/metadata/MetadataStorage.js +1 -1
- package/metadata/MetadataValidator.js +4 -3
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +39 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +7 -1
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/package.json +14 -7
- package/platforms/Platform.d.ts +5 -8
- package/platforms/Platform.js +4 -17
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +29 -11
- package/serialization/EntityTransformer.js +22 -12
- package/serialization/SerializationContext.js +14 -11
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +3 -0
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +1 -1
- package/types/DoubleType.js +1 -1
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +0 -3
- package/types/index.d.ts +1 -1
- package/typings.d.ts +94 -50
- package/typings.js +31 -31
- package/unit-of-work/ChangeSetComputer.js +8 -3
- package/unit-of-work/ChangeSetPersister.d.ts +4 -2
- package/unit-of-work/ChangeSetPersister.js +37 -16
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +110 -53
- package/utils/AbstractSchemaGenerator.js +3 -1
- package/utils/Configuration.d.ts +201 -184
- package/utils/Configuration.js +143 -151
- package/utils/ConfigurationLoader.d.ts +9 -22
- package/utils/ConfigurationLoader.js +53 -76
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +3 -0
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +53 -7
- package/utils/EntityComparator.d.ts +8 -4
- package/utils/EntityComparator.js +105 -58
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +66 -5
- package/utils/RawQueryFragment.d.ts +36 -4
- package/utils/RawQueryFragment.js +34 -13
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +13 -12
- package/utils/Utils.js +106 -66
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +52 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TransactionPropagation } from '../enums.js';
|
|
1
2
|
import { RequestContext } from '../utils/RequestContext.js';
|
|
2
3
|
import { resolveContextProvider } from '../utils/resolveContextProvider.js';
|
|
3
4
|
import { TransactionContext } from '../utils/TransactionContext.js';
|
|
@@ -6,6 +7,7 @@ import { TransactionContext } from '../utils/TransactionContext.js';
|
|
|
6
7
|
* The difference is that you can specify the context in which the transaction begins by providing `context` option,
|
|
7
8
|
* and if omitted, the transaction will begin in the current context implicitly.
|
|
8
9
|
* It works on async functions and can be nested with `em.transactional()`.
|
|
10
|
+
* Unlike `em.transactional()`, this decorator uses `REQUIRED` propagation by default, which means it will join existing transactions.
|
|
9
11
|
*/
|
|
10
12
|
export function Transactional(options = {}) {
|
|
11
13
|
return function (target, propertyKey, descriptor) {
|
|
@@ -14,10 +16,11 @@ export function Transactional(options = {}) {
|
|
|
14
16
|
throw new Error('@Transactional() should be use with async functions');
|
|
15
17
|
}
|
|
16
18
|
descriptor.value = async function (...args) {
|
|
17
|
-
const { context, ...txOptions } = options;
|
|
19
|
+
const { context, contextName, ...txOptions } = options;
|
|
20
|
+
txOptions.propagation ??= TransactionPropagation.REQUIRED;
|
|
18
21
|
const em = (await resolveContextProvider(this, context))
|
|
19
|
-
|| TransactionContext.getEntityManager()
|
|
20
|
-
|| RequestContext.getEntityManager();
|
|
22
|
+
|| TransactionContext.getEntityManager(contextName)
|
|
23
|
+
|| RequestContext.getEntityManager(contextName);
|
|
21
24
|
if (!em) {
|
|
22
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.`);
|
|
23
26
|
}
|
package/decorators/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './Entity.js';
|
|
|
3
3
|
export * from './OneToOne.js';
|
|
4
4
|
export * from './ManyToOne.js';
|
|
5
5
|
export * from './ManyToMany.js';
|
|
6
|
-
export { OneToMany, OneToManyOptions } from './OneToMany.js';
|
|
6
|
+
export { OneToMany, type OneToManyOptions } from './OneToMany.js';
|
|
7
7
|
export * from './Property.js';
|
|
8
8
|
export * from './Check.js';
|
|
9
9
|
export * from './Enum.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type CountOptions, type DeleteOptions, type DriverMethodOptions, EntityManagerType, type FindOneOptions, type FindOptions, type IDatabaseDriver, type LockOptions, type NativeInsertUpdateManyOptions, type NativeInsertUpdateOptions, type OrderDefinition } from './IDatabaseDriver.js';
|
|
2
|
-
import type { ConnectionType, Dictionary, EntityData, EntityDictionary, EntityMetadata, EntityProperty, FilterQuery, PopulateOptions, Primary } from '../typings.js';
|
|
1
|
+
import { type CountOptions, type DeleteOptions, type DriverMethodOptions, EntityManagerType, type FindOneOptions, type FindOptions, type IDatabaseDriver, type LockOptions, type NativeInsertUpdateManyOptions, type NativeInsertUpdateOptions, type OrderDefinition, type StreamOptions } from './IDatabaseDriver.js';
|
|
2
|
+
import type { ConnectionType, Dictionary, EntityData, EntityDictionary, EntityMetadata, EntityName, EntityProperty, FilterQuery, PopulateOptions, Primary } from '../typings.js';
|
|
3
3
|
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
4
4
|
import type { Connection, QueryResult, Transaction } from '../connections/Connection.js';
|
|
5
5
|
import { type Configuration, type ConnectionOptions } from '../utils/Configuration.js';
|
|
@@ -30,20 +30,25 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
|
|
|
30
30
|
abstract nativeDelete<T extends object>(entityName: string, where: FilterQuery<T>, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
|
|
31
31
|
abstract count<T extends object, P extends string = never>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T, P>): Promise<number>;
|
|
32
32
|
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
33
|
-
findVirtual<T extends object>(entityName:
|
|
33
|
+
findVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
|
|
34
34
|
countVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: CountOptions<T, any>): Promise<number>;
|
|
35
35
|
aggregate(entityName: string, pipeline: any[]): Promise<any[]>;
|
|
36
36
|
loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any, any>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
|
|
37
37
|
syncCollections<T extends object, O extends object>(collections: Iterable<Collection<T, O>>, options?: DriverMethodOptions): Promise<void>;
|
|
38
38
|
mapResult<T extends object>(result: EntityDictionary<T>, meta?: EntityMetadata<T>, populate?: PopulateOptions<T>[]): EntityData<T> | null;
|
|
39
|
-
connect(
|
|
40
|
-
|
|
39
|
+
connect(options?: {
|
|
40
|
+
skipOnConnect?: boolean;
|
|
41
|
+
}): Promise<C>;
|
|
42
|
+
reconnect(options?: {
|
|
43
|
+
skipOnConnect?: boolean;
|
|
44
|
+
}): Promise<C>;
|
|
41
45
|
getConnection(type?: ConnectionType): C;
|
|
42
46
|
close(force?: boolean): Promise<void>;
|
|
43
47
|
getPlatform(): Platform;
|
|
44
48
|
setMetadata(metadata: MetadataStorage): void;
|
|
45
49
|
getMetadata(): MetadataStorage;
|
|
46
50
|
getDependencies(): string[];
|
|
51
|
+
protected isPopulated<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T>, hint: PopulateOptions<T>, name?: string): boolean;
|
|
47
52
|
protected processCursorOptions<T extends object, P extends string>(meta: EntityMetadata<T>, options: FindOptions<T, P, any, any>, orderBy: OrderDefinition<T>): {
|
|
48
53
|
orderBy: OrderDefinition<T>[];
|
|
49
54
|
where: FilterQuery<T>;
|
|
@@ -55,6 +60,7 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
|
|
|
55
60
|
protected getPrimaryKeyFields(entityName: string): string[];
|
|
56
61
|
protected createReplicas(cb: (c: ConnectionOptions) => C): C[];
|
|
57
62
|
lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
|
|
63
|
+
abstract stream<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T>): AsyncIterableIterator<T>;
|
|
58
64
|
/**
|
|
59
65
|
* @inheritDoc
|
|
60
66
|
*/
|
|
@@ -65,14 +65,14 @@ export class DatabaseDriver {
|
|
|
65
65
|
}
|
|
66
66
|
return this.comparator.mapResult(meta.className, result);
|
|
67
67
|
}
|
|
68
|
-
async connect() {
|
|
69
|
-
await this.connection.connect();
|
|
68
|
+
async connect(options) {
|
|
69
|
+
await this.connection.connect(options);
|
|
70
70
|
await Promise.all(this.replicas.map(replica => replica.connect()));
|
|
71
71
|
return this.connection;
|
|
72
72
|
}
|
|
73
|
-
async reconnect() {
|
|
73
|
+
async reconnect(options) {
|
|
74
74
|
await this.close(true);
|
|
75
|
-
await this.connect();
|
|
75
|
+
await this.connect(options);
|
|
76
76
|
return this.connection;
|
|
77
77
|
}
|
|
78
78
|
getConnection(type = 'write') {
|
|
@@ -105,6 +105,15 @@ export class DatabaseDriver {
|
|
|
105
105
|
getDependencies() {
|
|
106
106
|
return this.dependencies;
|
|
107
107
|
}
|
|
108
|
+
isPopulated(meta, prop, hint, name) {
|
|
109
|
+
if (hint.field === prop.name || hint.field === name || hint.all) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (prop.embedded && hint.children && meta.properties[prop.embedded[0]].name === hint.field) {
|
|
113
|
+
return hint.children.some(c => this.isPopulated(meta, prop, c, prop.embedded[1]));
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
108
117
|
processCursorOptions(meta, options, orderBy) {
|
|
109
118
|
const { first, last, before, after, overfetch } = options;
|
|
110
119
|
const limit = first ?? last;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConnectionType, EntityData, EntityMetadata, EntityProperty, FilterQuery, Primary, Dictionary, QBFilterQuery, IPrimaryKey, PopulateOptions, EntityDictionary, AutoPath, ObjectQuery, FilterObject, Populate } from '../typings.js';
|
|
1
|
+
import type { ConnectionType, EntityData, EntityMetadata, EntityProperty, FilterQuery, Primary, Dictionary, QBFilterQuery, IPrimaryKey, PopulateOptions, EntityDictionary, AutoPath, ObjectQuery, FilterObject, Populate, EntityName } from '../typings.js';
|
|
2
2
|
import type { Connection, QueryResult, Transaction } from '../connections/Connection.js';
|
|
3
3
|
import type { FlushMode, LockMode, QueryOrderMap, QueryFlag, LoadStrategy, PopulateHint, PopulatePath } from '../enums.js';
|
|
4
4
|
import type { Platform } from '../platforms/Platform.js';
|
|
@@ -14,9 +14,13 @@ export interface IDatabaseDriver<C extends Connection = Connection> {
|
|
|
14
14
|
[EntityManagerType]: EntityManager<this>;
|
|
15
15
|
readonly config: Configuration;
|
|
16
16
|
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
17
|
-
connect(
|
|
17
|
+
connect(options?: {
|
|
18
|
+
skipOnConnect?: boolean;
|
|
19
|
+
}): Promise<C>;
|
|
18
20
|
close(force?: boolean): Promise<void>;
|
|
19
|
-
reconnect(
|
|
21
|
+
reconnect(options?: {
|
|
22
|
+
skipOnConnect?: boolean;
|
|
23
|
+
}): Promise<C>;
|
|
20
24
|
getConnection(type?: ConnectionType): C;
|
|
21
25
|
/**
|
|
22
26
|
* Finds selection of entities
|
|
@@ -27,6 +31,7 @@ export interface IDatabaseDriver<C extends Connection = Connection> {
|
|
|
27
31
|
*/
|
|
28
32
|
findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
|
|
29
33
|
findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
|
|
34
|
+
stream<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T>): AsyncIterableIterator<T>;
|
|
30
35
|
nativeInsert<T extends object>(entityName: string, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
31
36
|
nativeInsertMany<T extends object>(entityName: string, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
|
|
32
37
|
nativeUpdate<T extends object>(entityName: string, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
@@ -68,6 +73,18 @@ export type OrderDefinition<T> = (QueryOrderMap<T> & {
|
|
|
68
73
|
export interface FindAllOptions<T, P extends string = never, F extends string = '*', E extends string = never> extends FindOptions<T, P, F, E> {
|
|
69
74
|
where?: FilterQuery<T>;
|
|
70
75
|
}
|
|
76
|
+
export interface StreamOptions<Entity, Populate extends string = never, Fields extends string = '*', Exclude extends string = never> extends Omit<FindAllOptions<Entity, Populate, Fields, Exclude>, 'cache' | 'before' | 'after' | 'first' | 'last' | 'overfetch' | 'strategy'> {
|
|
77
|
+
/**
|
|
78
|
+
* When populating to-many relations, the ORM streams fully merged entities instead of yielding every row.
|
|
79
|
+
* You can opt out of this behavior by specifying `mergeResults: false`. This will yield every row from
|
|
80
|
+
* the SQL result, but still mapped to entities, meaning that to-many collections will contain at most
|
|
81
|
+
* a single item, and you will get duplicate root entities when they have multiple items in the populated
|
|
82
|
+
* collection.
|
|
83
|
+
*
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
mergeResults?: boolean;
|
|
87
|
+
}
|
|
71
88
|
export type FilterOptions = Dictionary<boolean | Dictionary> | string[] | boolean;
|
|
72
89
|
export interface LoadHint<Entity, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never> {
|
|
73
90
|
populate?: Populate<Entity, Hint>;
|
|
@@ -146,10 +163,13 @@ export interface FindOptions<Entity, Hint extends string = never, Fields extends
|
|
|
146
163
|
hintComments?: string | string[];
|
|
147
164
|
loggerContext?: LogContext;
|
|
148
165
|
logging?: LoggingOptions;
|
|
166
|
+
/** @internal used to apply filters to the auto-joined relations */
|
|
167
|
+
em?: EntityManager;
|
|
149
168
|
}
|
|
150
|
-
export interface FindByCursorOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'offset'> {
|
|
169
|
+
export interface FindByCursorOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never, I extends boolean = true> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'offset'> {
|
|
170
|
+
includeCount?: I;
|
|
151
171
|
}
|
|
152
|
-
export interface FindOneOptions<T
|
|
172
|
+
export interface FindOneOptions<T, P extends string = never, F extends string = '*', E extends string = never> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'lockMode'> {
|
|
153
173
|
lockMode?: LockMode;
|
|
154
174
|
lockVersion?: number | Date;
|
|
155
175
|
}
|
|
@@ -163,6 +183,7 @@ export interface NativeInsertUpdateOptions<T> {
|
|
|
163
183
|
schema?: string;
|
|
164
184
|
/** `nativeUpdate()` only option */
|
|
165
185
|
upsert?: boolean;
|
|
186
|
+
loggerContext?: LogContext;
|
|
166
187
|
}
|
|
167
188
|
export interface NativeInsertUpdateManyOptions<T> extends NativeInsertUpdateOptions<T> {
|
|
168
189
|
processCollections?: boolean;
|
|
@@ -197,6 +218,8 @@ export interface CountOptions<T extends object, P extends string = never> {
|
|
|
197
218
|
hintComments?: string | string[];
|
|
198
219
|
loggerContext?: LogContext;
|
|
199
220
|
logging?: LoggingOptions;
|
|
221
|
+
/** @internal used to apply filters to the auto-joined relations */
|
|
222
|
+
em?: EntityManager;
|
|
200
223
|
}
|
|
201
224
|
export interface UpdateOptions<T> {
|
|
202
225
|
filters?: FilterOptions;
|
|
@@ -218,6 +241,7 @@ export interface LockOptions extends DriverMethodOptions {
|
|
|
218
241
|
export interface DriverMethodOptions {
|
|
219
242
|
ctx?: Transaction;
|
|
220
243
|
schema?: string;
|
|
244
|
+
loggerContext?: LogContext;
|
|
221
245
|
}
|
|
222
246
|
export interface GetReferenceOptions {
|
|
223
247
|
wrapped?: boolean;
|
|
@@ -6,6 +6,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
6
6
|
protected readonly items: Set<T>;
|
|
7
7
|
protected initialized: boolean;
|
|
8
8
|
protected dirty: boolean;
|
|
9
|
+
protected partial: boolean;
|
|
9
10
|
protected snapshot: T[] | undefined;
|
|
10
11
|
protected _count?: number;
|
|
11
12
|
private _property?;
|
|
@@ -14,8 +15,8 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
14
15
|
getItems(): T[];
|
|
15
16
|
toArray<TT extends T>(): EntityDTO<TT>[];
|
|
16
17
|
toJSON(): EntityDTO<T>[];
|
|
17
|
-
getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string): U[];
|
|
18
|
-
add(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]):
|
|
18
|
+
getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string | string[]): U[];
|
|
19
|
+
add(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]): number;
|
|
19
20
|
/**
|
|
20
21
|
* @internal
|
|
21
22
|
*/
|
|
@@ -25,14 +26,14 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
25
26
|
/**
|
|
26
27
|
* @internal
|
|
27
28
|
*/
|
|
28
|
-
hydrate(items: T[], forcePropagate?: boolean): void;
|
|
29
|
+
hydrate(items: T[], forcePropagate?: boolean, partial?: boolean): void;
|
|
29
30
|
/**
|
|
30
31
|
* Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
|
|
31
32
|
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
|
32
33
|
* is not the same as `em.remove()`. If we want to delete the entity by removing it from collection, we need to enable `orphanRemoval: true`,
|
|
33
34
|
* which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
|
|
34
35
|
*/
|
|
35
|
-
remove(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]):
|
|
36
|
+
remove(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]): number;
|
|
36
37
|
/**
|
|
37
38
|
* Remove all items from the collection. Note that removing items from collection does not necessarily imply deleting the target entity,
|
|
38
39
|
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
|
@@ -83,6 +84,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
83
84
|
count(): number;
|
|
84
85
|
isInitialized(fully?: boolean): boolean;
|
|
85
86
|
isDirty(): boolean;
|
|
87
|
+
isPartial(): boolean;
|
|
86
88
|
isEmpty(): boolean;
|
|
87
89
|
setDirty(dirty?: boolean): void;
|
|
88
90
|
get length(): number;
|
|
@@ -9,6 +9,7 @@ export class ArrayCollection {
|
|
|
9
9
|
items = new Set();
|
|
10
10
|
initialized = true;
|
|
11
11
|
dirty = false;
|
|
12
|
+
partial = false; // mark partially loaded collections, propagation is disabled for those
|
|
12
13
|
snapshot = []; // used to create a diff of the collection at commit time, undefined marks overridden values so we need to wipe when flushing
|
|
13
14
|
_count;
|
|
14
15
|
_property;
|
|
@@ -40,28 +41,38 @@ export class ArrayCollection {
|
|
|
40
41
|
}
|
|
41
42
|
getIdentifiers(field) {
|
|
42
43
|
const items = this.getItems();
|
|
44
|
+
const targetMeta = this.property.targetMeta;
|
|
43
45
|
if (items.length === 0) {
|
|
44
46
|
return [];
|
|
45
47
|
}
|
|
46
|
-
field ??=
|
|
48
|
+
field ??= targetMeta.compositePK ? targetMeta.primaryKeys : (targetMeta.serializedPrimaryKey ?? targetMeta.primaryKeys[0]);
|
|
49
|
+
const cb = (i, f) => {
|
|
50
|
+
if (Utils.isEntity(i[f], true)) {
|
|
51
|
+
return wrap(i[f], true).getPrimaryKey();
|
|
52
|
+
}
|
|
53
|
+
return i[f];
|
|
54
|
+
};
|
|
47
55
|
return items.map(i => {
|
|
48
|
-
if (
|
|
49
|
-
return
|
|
56
|
+
if (Array.isArray(field)) {
|
|
57
|
+
return field.map(f => cb(i, f));
|
|
50
58
|
}
|
|
51
|
-
return i
|
|
59
|
+
return cb(i, field);
|
|
52
60
|
});
|
|
53
61
|
}
|
|
54
62
|
add(entity, ...entities) {
|
|
55
63
|
entities = Utils.asArray(entity).concat(entities);
|
|
64
|
+
let added = 0;
|
|
56
65
|
for (const item of entities) {
|
|
57
66
|
const entity = Reference.unwrapReference(item);
|
|
58
67
|
if (!this.contains(entity, false)) {
|
|
59
68
|
this.incrementCount(1);
|
|
60
69
|
this[this.items.size] = entity;
|
|
61
70
|
this.items.add(entity);
|
|
71
|
+
added++;
|
|
62
72
|
this.propagate(entity, 'add');
|
|
63
73
|
}
|
|
64
74
|
}
|
|
75
|
+
return added;
|
|
65
76
|
}
|
|
66
77
|
/**
|
|
67
78
|
* @internal
|
|
@@ -100,11 +111,12 @@ export class ArrayCollection {
|
|
|
100
111
|
/**
|
|
101
112
|
* @internal
|
|
102
113
|
*/
|
|
103
|
-
hydrate(items, forcePropagate) {
|
|
114
|
+
hydrate(items, forcePropagate, partial) {
|
|
104
115
|
for (let i = 0; i < this.items.size; i++) {
|
|
105
116
|
delete this[i];
|
|
106
117
|
}
|
|
107
118
|
this.initialized = true;
|
|
119
|
+
this.partial = !!partial;
|
|
108
120
|
this.items.clear();
|
|
109
121
|
this._count = 0;
|
|
110
122
|
this.add(items);
|
|
@@ -118,7 +130,7 @@ export class ArrayCollection {
|
|
|
118
130
|
*/
|
|
119
131
|
remove(entity, ...entities) {
|
|
120
132
|
entities = Utils.asArray(entity).concat(entities);
|
|
121
|
-
let
|
|
133
|
+
let removed = 0;
|
|
122
134
|
for (const item of entities) {
|
|
123
135
|
if (!item) {
|
|
124
136
|
continue;
|
|
@@ -128,12 +140,13 @@ export class ArrayCollection {
|
|
|
128
140
|
this.incrementCount(-1);
|
|
129
141
|
delete this[this.items.size]; // remove last item
|
|
130
142
|
this.propagate(entity, 'remove');
|
|
131
|
-
|
|
143
|
+
removed++;
|
|
132
144
|
}
|
|
133
145
|
}
|
|
134
|
-
if (
|
|
146
|
+
if (removed > 0) {
|
|
135
147
|
Object.assign(this, [...this.items]); // reassign array access
|
|
136
148
|
}
|
|
149
|
+
return removed;
|
|
137
150
|
}
|
|
138
151
|
/**
|
|
139
152
|
* Remove all items from the collection. Note that removing items from collection does not necessarily imply deleting the target entity,
|
|
@@ -147,6 +160,7 @@ export class ArrayCollection {
|
|
|
147
160
|
this.snapshot = undefined;
|
|
148
161
|
}
|
|
149
162
|
this.remove(this.items);
|
|
163
|
+
this.setDirty();
|
|
150
164
|
}
|
|
151
165
|
/**
|
|
152
166
|
* @internal
|
|
@@ -267,6 +281,9 @@ export class ArrayCollection {
|
|
|
267
281
|
isDirty() {
|
|
268
282
|
return this.dirty;
|
|
269
283
|
}
|
|
284
|
+
isPartial() {
|
|
285
|
+
return this.partial;
|
|
286
|
+
}
|
|
270
287
|
isEmpty() {
|
|
271
288
|
return this.count() === 0;
|
|
272
289
|
}
|
|
@@ -383,7 +400,7 @@ export class ArrayCollection {
|
|
|
383
400
|
/** @ignore */
|
|
384
401
|
[inspect.custom](depth = 2) {
|
|
385
402
|
const object = { ...this };
|
|
386
|
-
const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly'];
|
|
403
|
+
const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly', 'partial'];
|
|
387
404
|
hidden.forEach(k => delete object[k]);
|
|
388
405
|
const ret = inspect(object, { depth });
|
|
389
406
|
const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
|
package/entity/BaseEntity.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { type SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
|
6
6
|
import type { FindOneOptions } from '../drivers/IDatabaseDriver.js';
|
|
7
7
|
export declare abstract class BaseEntity {
|
|
8
8
|
isInitialized(): boolean;
|
|
9
|
-
isTouched(): boolean;
|
|
10
9
|
populated(populated?: boolean): void;
|
|
11
10
|
populate<Entity extends this = this, Hint extends string = never>(populate: AutoPath<Entity, Hint>[] | false, options?: EntityLoaderOptions<Entity>): Promise<Loaded<Entity, Hint>>;
|
|
12
11
|
toReference<Entity extends this = this>(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
|
package/entity/BaseEntity.js
CHANGED
package/entity/Collection.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { EntityDTO, EntityKey, FilterQuery, Loaded, LoadedCollection, Popul
|
|
|
2
2
|
import { ArrayCollection } from './ArrayCollection.js';
|
|
3
3
|
import { Reference } from './Reference.js';
|
|
4
4
|
import type { Transaction } from '../connections/Connection.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
|
|
6
6
|
import type { EntityLoaderOptions } from './EntityLoader.js';
|
|
7
7
|
export interface MatchingOptions<T extends object, P extends string = never> extends FindOptions<T, P> {
|
|
8
8
|
where?: FilterQuery<T>;
|
|
@@ -12,7 +12,6 @@ export interface MatchingOptions<T extends object, P extends string = never> ext
|
|
|
12
12
|
export declare class Collection<T extends object, O extends object = object> extends ArrayCollection<T, O> {
|
|
13
13
|
private readonly?;
|
|
14
14
|
private _populated?;
|
|
15
|
-
private _em?;
|
|
16
15
|
private _snapshot?;
|
|
17
16
|
constructor(owner: O, items?: T[], initialized?: boolean);
|
|
18
17
|
/**
|
|
@@ -40,11 +39,11 @@ export declare class Collection<T extends object, O extends object = object> ext
|
|
|
40
39
|
*/
|
|
41
40
|
getItems(check?: boolean): T[];
|
|
42
41
|
toJSON<TT extends T>(): EntityDTO<TT>[];
|
|
43
|
-
add<TT extends T>(entity: TT | Reference<TT> | Iterable<TT | Reference<TT>>, ...entities: (TT | Reference<TT>)[]):
|
|
42
|
+
add<TT extends T>(entity: TT | Reference<TT> | Iterable<TT | Reference<TT>>, ...entities: (TT | Reference<TT>)[]): number;
|
|
44
43
|
/**
|
|
45
44
|
* @inheritDoc
|
|
46
45
|
*/
|
|
47
|
-
remove<TT extends T>(entity: TT | Reference<TT> | Iterable<TT | Reference<TT>> | ((item: TT) => boolean), ...entities: (TT | Reference<TT>)[]):
|
|
46
|
+
remove<TT extends T>(entity: TT | Reference<TT> | Iterable<TT | Reference<TT>> | ((item: TT) => boolean), ...entities: (TT | Reference<TT>)[]): number;
|
|
48
47
|
contains<TT extends T>(item: TT | Reference<TT>, check?: boolean): boolean;
|
|
49
48
|
count(): number;
|
|
50
49
|
isEmpty(): boolean;
|
package/entity/Collection.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ArrayCollection } from './ArrayCollection.js';
|
|
2
2
|
import { Utils } from '../utils/Utils.js';
|
|
3
3
|
import { ValidationError } from '../errors.js';
|
|
4
|
-
import {
|
|
4
|
+
import { DataloaderType, ReferenceKind } from '../enums.js';
|
|
5
5
|
import { Reference } from './Reference.js';
|
|
6
6
|
import { helper } from './wrap.js';
|
|
7
|
+
import { QueryHelper } from '../utils/QueryHelper.js';
|
|
7
8
|
export class Collection extends ArrayCollection {
|
|
8
9
|
readonly;
|
|
9
10
|
_populated;
|
|
10
|
-
_em;
|
|
11
11
|
// this is for some reason needed for TS, otherwise it can fail with `Type instantiation is excessively deep and possibly infinite.`
|
|
12
12
|
_snapshot;
|
|
13
13
|
constructor(owner, items, initialized = true) {
|
|
@@ -33,6 +33,7 @@ export class Collection extends ArrayCollection {
|
|
|
33
33
|
async load(options = {}) {
|
|
34
34
|
if (this.isInitialized(true) && !options.refresh) {
|
|
35
35
|
const em = this.getEntityManager(this.items, false);
|
|
36
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
|
36
37
|
await em?.populate(this.items, options.populate, options);
|
|
37
38
|
this.setSerializationContext(options);
|
|
38
39
|
}
|
|
@@ -116,30 +117,33 @@ export class Collection extends ArrayCollection {
|
|
|
116
117
|
entities = Utils.asArray(entity).concat(entities);
|
|
117
118
|
const unwrapped = entities.map(i => Reference.unwrapReference(i));
|
|
118
119
|
unwrapped.forEach(entity => this.validateItemType(entity));
|
|
119
|
-
this.modify('add', unwrapped);
|
|
120
|
+
const added = this.modify('add', unwrapped);
|
|
120
121
|
this.cancelOrphanRemoval(unwrapped);
|
|
122
|
+
return added;
|
|
121
123
|
}
|
|
122
124
|
/**
|
|
123
125
|
* @inheritDoc
|
|
124
126
|
*/
|
|
125
127
|
remove(entity, ...entities) {
|
|
126
128
|
if (entity instanceof Function) {
|
|
129
|
+
let removed = 0;
|
|
127
130
|
for (const item of this.items) {
|
|
128
131
|
if (entity(item)) {
|
|
129
|
-
this.remove(item);
|
|
132
|
+
removed += this.remove(item);
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
|
-
return;
|
|
135
|
+
return removed;
|
|
133
136
|
}
|
|
134
137
|
entities = Utils.asArray(entity).concat(entities);
|
|
135
138
|
const unwrapped = entities.map(i => Reference.unwrapReference(i));
|
|
136
|
-
this.modify('remove', unwrapped);
|
|
139
|
+
const removed = this.modify('remove', unwrapped);
|
|
137
140
|
const em = this.getEntityManager(unwrapped, false);
|
|
138
141
|
if (this.property.orphanRemoval && em) {
|
|
139
142
|
for (const item of unwrapped) {
|
|
140
143
|
em.getUnitOfWork().scheduleOrphanRemoval(item);
|
|
141
144
|
}
|
|
142
145
|
}
|
|
146
|
+
return removed;
|
|
143
147
|
}
|
|
144
148
|
contains(item, check = true) {
|
|
145
149
|
if (check) {
|
|
@@ -218,13 +222,21 @@ export class Collection extends ArrayCollection {
|
|
|
218
222
|
return this;
|
|
219
223
|
}
|
|
220
224
|
const em = this.getEntityManager();
|
|
225
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
|
221
226
|
if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
|
|
222
227
|
const order = [...this.items]; // copy order of references
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
const orderBy = this.createOrderBy(options.orderBy);
|
|
229
|
+
const customOrder = orderBy.length > 0;
|
|
230
|
+
const pivotTable = this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable();
|
|
231
|
+
const loader = await em.getDataLoader(pivotTable ? 'm:n' : '1:m');
|
|
232
|
+
const items = await loader.load([this, { ...options, orderBy }]);
|
|
233
|
+
if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
|
|
234
|
+
this.initialized = true;
|
|
235
|
+
this.dirty = false;
|
|
236
|
+
if (!customOrder) {
|
|
237
|
+
this.reorderItems(items, order);
|
|
238
|
+
}
|
|
239
|
+
return this;
|
|
228
240
|
}
|
|
229
241
|
this.items.clear();
|
|
230
242
|
let i = 0;
|
|
@@ -254,18 +266,17 @@ export class Collection extends ArrayCollection {
|
|
|
254
266
|
}
|
|
255
267
|
getEntityManager(items = [], required = true) {
|
|
256
268
|
const wrapped = helper(this.owner);
|
|
257
|
-
let em =
|
|
269
|
+
let em = wrapped.__em;
|
|
270
|
+
// console.log('wat 1', em, this.owner);
|
|
258
271
|
if (!em) {
|
|
259
272
|
for (const i of items) {
|
|
273
|
+
// console.log('wat 2', i, i && helper(i).__em);
|
|
260
274
|
if (i && helper(i).__em) {
|
|
261
275
|
em = helper(i).__em;
|
|
262
276
|
break;
|
|
263
277
|
}
|
|
264
278
|
}
|
|
265
279
|
}
|
|
266
|
-
if (em) {
|
|
267
|
-
Object.defineProperty(this, '_em', { value: em });
|
|
268
|
-
}
|
|
269
280
|
if (!em && required) {
|
|
270
281
|
throw ValidationError.entityNotManaged(this.owner);
|
|
271
282
|
}
|
|
@@ -316,8 +327,14 @@ export class Collection extends ArrayCollection {
|
|
|
316
327
|
this.checkInitialized();
|
|
317
328
|
}
|
|
318
329
|
this.validateModification(items);
|
|
319
|
-
super[method](items);
|
|
320
|
-
|
|
330
|
+
const modified = super[method](items);
|
|
331
|
+
if (modified > 0) {
|
|
332
|
+
this.setDirty();
|
|
333
|
+
}
|
|
334
|
+
if (this.property.kind === ReferenceKind.ONE_TO_MANY && (method === 'add' || !this.property.orphanRemoval)) {
|
|
335
|
+
this.getEntityManager(items, false)?.persist(items);
|
|
336
|
+
}
|
|
337
|
+
return modified;
|
|
321
338
|
}
|
|
322
339
|
checkInitialized() {
|
|
323
340
|
if (!this.isInitialized()) {
|
|
@@ -36,7 +36,7 @@ export interface AssignOptions<Convert extends boolean> {
|
|
|
36
36
|
*/
|
|
37
37
|
onlyProperties?: boolean;
|
|
38
38
|
/**
|
|
39
|
-
* With `onlyOwnProperties` enabled, to-many relations are skipped, and payloads of
|
|
39
|
+
* With `onlyOwnProperties` enabled, inverse sides of to-many relations are skipped, and payloads of other relations are converted
|
|
40
40
|
* to foreign keys. Defaults to `false`.
|
|
41
41
|
*/
|
|
42
42
|
onlyOwnProperties?: boolean;
|
package/entity/EntityAssigner.js
CHANGED
|
@@ -42,9 +42,17 @@ export class EntityAssigner {
|
|
|
42
42
|
}
|
|
43
43
|
const prop = { ...props[propName], name: propName };
|
|
44
44
|
if (prop && options.onlyOwnProperties) {
|
|
45
|
-
if ([ReferenceKind.
|
|
45
|
+
if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
+
if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
49
|
+
if (!prop.owner) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
else if (value?.map) {
|
|
53
|
+
value = value.map((v) => Utils.extractPK(v, prop.targetMeta));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
48
56
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
49
57
|
value = Utils.extractPK(value, prop.targetMeta);
|
|
50
58
|
}
|
|
@@ -4,12 +4,18 @@ import type { EntityComparator } from '../utils/EntityComparator.js';
|
|
|
4
4
|
export interface FactoryOptions {
|
|
5
5
|
initialized?: boolean;
|
|
6
6
|
newEntity?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Property `onCreate` hooks are normally executed during `flush` operation.
|
|
9
|
+
* With this option, they will be processed early inside `em.create()` method.
|
|
10
|
+
*/
|
|
11
|
+
processOnCreateHooksEarly?: boolean;
|
|
7
12
|
merge?: boolean;
|
|
8
13
|
refresh?: boolean;
|
|
9
14
|
convertCustomTypes?: boolean;
|
|
10
15
|
recomputeSnapshot?: boolean;
|
|
11
16
|
schema?: string;
|
|
12
17
|
parentSchema?: string;
|
|
18
|
+
normalizeAccessors?: boolean;
|
|
13
19
|
}
|
|
14
20
|
export declare class EntityFactory {
|
|
15
21
|
private readonly em;
|
|
@@ -27,6 +33,7 @@ export declare class EntityFactory {
|
|
|
27
33
|
createEmbeddable<T extends object>(entityName: EntityName<T>, data: EntityData<T>, options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>): T;
|
|
28
34
|
getComparator(): EntityComparator;
|
|
29
35
|
private createEntity;
|
|
36
|
+
private assignDefaultValues;
|
|
30
37
|
private hydrate;
|
|
31
38
|
private findEntity;
|
|
32
39
|
private processDiscriminatorColumn;
|