Initial commit - Event Planner application
This commit is contained in:
911
node_modules/@mikro-orm/core/EntityManager.d.ts
generated
vendored
Normal file
911
node_modules/@mikro-orm/core/EntityManager.d.ts
generated
vendored
Normal file
@@ -0,0 +1,911 @@
|
||||
import { type Configuration } from './utils/Configuration.js';
|
||||
import { Cursor } from './utils/Cursor.js';
|
||||
import { EntityFactory } from './entity/EntityFactory.js';
|
||||
import { type AssignOptions } from './entity/EntityAssigner.js';
|
||||
import { type EntityRepository } from './entity/EntityRepository.js';
|
||||
import { EntityLoader, type EntityLoaderOptions } from './entity/EntityLoader.js';
|
||||
import { Reference } from './entity/Reference.js';
|
||||
import { UnitOfWork } from './unit-of-work/UnitOfWork.js';
|
||||
import type {
|
||||
CountOptions,
|
||||
DeleteOptions,
|
||||
FilterOptions,
|
||||
FindAllOptions,
|
||||
FindByCursorOptions,
|
||||
FindOneOptions,
|
||||
FindOneOrFailOptions,
|
||||
FindOptions,
|
||||
GetReferenceOptions,
|
||||
IDatabaseDriver,
|
||||
LockOptions,
|
||||
NativeInsertUpdateOptions,
|
||||
StreamOptions,
|
||||
UpdateOptions,
|
||||
UpsertManyOptions,
|
||||
UpsertOptions,
|
||||
} from './drivers/IDatabaseDriver.js';
|
||||
import type {
|
||||
AnyString,
|
||||
ArrayElement,
|
||||
AutoPath,
|
||||
ConnectionType,
|
||||
Dictionary,
|
||||
EntityClass,
|
||||
EntityData,
|
||||
EntityDictionary,
|
||||
EntityDTO,
|
||||
EntityMetadata,
|
||||
EntityName,
|
||||
FilterDef,
|
||||
FilterQuery,
|
||||
FromEntityType,
|
||||
GetRepository,
|
||||
IHydrator,
|
||||
IsSubset,
|
||||
Loaded,
|
||||
MergeLoaded,
|
||||
MergeSelected,
|
||||
ObjectQuery,
|
||||
PopulateOptions,
|
||||
Primary,
|
||||
Ref,
|
||||
RequiredEntityData,
|
||||
UnboxArray,
|
||||
} from './typings.js';
|
||||
import { FlushMode, LockMode, PopulatePath, type TransactionOptions } from './enums.js';
|
||||
import type { MetadataStorage } from './metadata/MetadataStorage.js';
|
||||
import type { Transaction } from './connections/Connection.js';
|
||||
import { EventManager } from './events/EventManager.js';
|
||||
import type { EntityComparator } from './utils/EntityComparator.js';
|
||||
/**
|
||||
* The EntityManager is the central access point to ORM functionality. It is a facade to all different ORM subsystems
|
||||
* such as UnitOfWork, Query Language, and Repository API.
|
||||
* @template {IDatabaseDriver} Driver current driver type
|
||||
*/
|
||||
export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDriver> {
|
||||
#private;
|
||||
readonly config: Configuration;
|
||||
protected readonly driver: Driver;
|
||||
protected readonly metadata: MetadataStorage;
|
||||
protected readonly eventManager: EventManager;
|
||||
/** @internal */
|
||||
readonly '~entities'?: unknown;
|
||||
/** @internal */
|
||||
readonly _id: number;
|
||||
/** Whether this is the global (root) EntityManager instance. */
|
||||
readonly global = false;
|
||||
/** The context name of this EntityManager, derived from the ORM configuration. */
|
||||
readonly name: string;
|
||||
protected loggerContext?: Dictionary;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(
|
||||
config: Configuration,
|
||||
driver: Driver,
|
||||
metadata: MetadataStorage,
|
||||
useContext?: boolean,
|
||||
eventManager?: EventManager,
|
||||
);
|
||||
/**
|
||||
* Gets the Driver instance used by this EntityManager.
|
||||
* Driver is singleton, for one MikroORM instance, only one driver is created.
|
||||
*/
|
||||
getDriver(): Driver;
|
||||
/**
|
||||
* Gets the Connection instance, by default returns write connection
|
||||
*/
|
||||
getConnection(type?: ConnectionType): ReturnType<Driver['getConnection']>;
|
||||
/**
|
||||
* Gets the platform instance. Just like the driver, platform is singleton, one for a MikroORM instance.
|
||||
*/
|
||||
getPlatform(): ReturnType<Driver['getPlatform']>;
|
||||
/**
|
||||
* Gets repository for given entity. You can pass either string name or entity class reference.
|
||||
*/
|
||||
getRepository<Entity extends object, Repository extends EntityRepository<Entity> = EntityRepository<Entity>>(
|
||||
entityName: EntityName<Entity>,
|
||||
): GetRepository<Entity, Repository>;
|
||||
/**
|
||||
* Shortcut for `em.getRepository()`.
|
||||
*/
|
||||
repo<Entity extends object, Repository extends EntityRepository<Entity> = EntityRepository<Entity>>(
|
||||
entityName: EntityName<Entity>,
|
||||
): GetRepository<Entity, Repository>;
|
||||
/**
|
||||
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
||||
*/
|
||||
find<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = PopulatePath.ALL,
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
options?: FindOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
||||
/**
|
||||
* Finds all entities and returns an async iterable (async generator) that yields results one by one.
|
||||
* The results are merged and mapped to entity instances, without adding them to the identity map.
|
||||
* You can disable merging by passing the options `{ mergeResults: false }`.
|
||||
* With `mergeResults` disabled, to-many collections will contain at most one item, and you will get duplicate
|
||||
* root entities when there are multiple items in the populated collection.
|
||||
* This is useful for processing large datasets without loading everything into memory at once.
|
||||
*
|
||||
* ```ts
|
||||
* const stream = em.stream(Book, { populate: ['author'] });
|
||||
*
|
||||
* for await (const book of stream) {
|
||||
* // book is an instance of Book entity
|
||||
* console.log(book.title, book.author.name);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
stream<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
options?: StreamOptions<NoInfer<Entity>, Hint, Fields, Excludes>,
|
||||
): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
|
||||
/**
|
||||
* Finds all entities of given type, optionally matching the `where` condition provided in the `options` parameter.
|
||||
*/
|
||||
findAll<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
options?: FindAllOptions<NoInfer<Entity>, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
||||
private getPopulateWhere;
|
||||
/**
|
||||
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
||||
*/
|
||||
addFilter<T extends EntityName | readonly EntityName[]>(options: FilterDef<T>): void;
|
||||
/**
|
||||
* Sets filter parameter values globally inside context defined by this entity manager.
|
||||
* If you want to set shared value for all contexts, be sure to use the root entity manager.
|
||||
*/
|
||||
setFilterParams(name: string, args: Dictionary): void;
|
||||
/**
|
||||
* Returns filter parameters for given filter set in this context.
|
||||
*/
|
||||
getFilterParams<T extends Dictionary = Dictionary>(name: string): T;
|
||||
/**
|
||||
* Sets logger context for this entity manager.
|
||||
*/
|
||||
setLoggerContext(context: Dictionary): void;
|
||||
/**
|
||||
* Gets logger context for this entity manager.
|
||||
*/
|
||||
getLoggerContext<T extends Dictionary = Dictionary>(options?: { disableContextResolution?: boolean }): T;
|
||||
/** Sets the flush mode for this EntityManager. Pass `undefined` to reset to the global default. */
|
||||
setFlushMode(flushMode?: FlushMode | `${FlushMode}`): void;
|
||||
protected processWhere<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<Entity>,
|
||||
options: FindOptions<Entity, Hint, Fields, Excludes> | FindOneOptions<Entity, Hint, Fields, Excludes>,
|
||||
type: 'read' | 'update' | 'delete',
|
||||
): Promise<FilterQuery<Entity>>;
|
||||
protected processUnionWhere<Entity extends object, Hint extends string = never>(
|
||||
entityName: EntityName<Entity>,
|
||||
options:
|
||||
| FindOptions<Entity, Hint, any, any>
|
||||
| CountOptions<Entity, Hint>
|
||||
| UpdateOptions<Entity>
|
||||
| DeleteOptions<Entity>,
|
||||
type: 'read' | 'update' | 'delete',
|
||||
): Promise<void>;
|
||||
protected applyDiscriminatorCondition<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<Entity>,
|
||||
): FilterQuery<Entity>;
|
||||
protected createPopulateWhere<Entity extends object>(
|
||||
cond: ObjectQuery<Entity>,
|
||||
options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any> | CountOptions<Entity, any>,
|
||||
): ObjectQuery<Entity>;
|
||||
protected getJoinedFilters<Entity extends object>(
|
||||
meta: EntityMetadata<Entity>,
|
||||
options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any>,
|
||||
): Promise<ObjectQuery<Entity> | undefined>;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected autoJoinRefsForFilters<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>,
|
||||
parent?: {
|
||||
class: EntityClass;
|
||||
propName: string;
|
||||
},
|
||||
): Promise<void>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
applyFilters<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<Entity> | undefined,
|
||||
options: FilterOptions | undefined,
|
||||
type: 'read' | 'update' | 'delete',
|
||||
findOptions?: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any>,
|
||||
): Promise<FilterQuery<Entity> | undefined>;
|
||||
/**
|
||||
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as tuple
|
||||
* where the first element is the array of entities, and the second is the count.
|
||||
*/
|
||||
findAndCount<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
options?: FindOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<[Loaded<Entity, Hint, Fields, Excludes>[], number]>;
|
||||
/**
|
||||
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as {@apilink Cursor} object.
|
||||
* Supports `before`, `after`, `first` and `last` options while disallowing `limit` and `offset`. Explicit `orderBy` option
|
||||
* is required.
|
||||
*
|
||||
* Use `first` and `after` for forward pagination, or `last` and `before` for backward pagination.
|
||||
*
|
||||
* - `first` and `last` are numbers and serve as an alternative to `offset`, those options are mutually exclusive, use only one at a time
|
||||
* - `before` and `after` specify the previous cursor value, it can be one of the:
|
||||
* - `Cursor` instance
|
||||
* - opaque string provided by `startCursor/endCursor` properties
|
||||
* - POJO/entity instance
|
||||
*
|
||||
* ```ts
|
||||
* const currentCursor = await em.findByCursor(User, {
|
||||
* first: 10,
|
||||
* after: previousCursor, // cursor instance
|
||||
* orderBy: { id: 'desc' },
|
||||
* });
|
||||
*
|
||||
* // to fetch next page
|
||||
* const nextCursor = await em.findByCursor(User, {
|
||||
* first: 10,
|
||||
* after: currentCursor.endCursor, // opaque string
|
||||
* orderBy: { id: 'desc' },
|
||||
* });
|
||||
*
|
||||
* // to fetch next page
|
||||
* const nextCursor2 = await em.findByCursor(User, {
|
||||
* first: 10,
|
||||
* after: { id: lastSeenId }, // entity-like POJO
|
||||
* orderBy: { id: 'desc' },
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
|
||||
* returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
|
||||
* of pages.
|
||||
*
|
||||
* The `Cursor` object provides the following interface:
|
||||
*
|
||||
* ```ts
|
||||
* Cursor<User> {
|
||||
* items: [
|
||||
* User { ... },
|
||||
* User { ... },
|
||||
* User { ... },
|
||||
* ],
|
||||
* totalCount: 50, // not included if `includeCount: false`
|
||||
* startCursor: 'WzRd',
|
||||
* endCursor: 'WzZd',
|
||||
* hasPrevPage: true,
|
||||
* hasNextPage: true,
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
findByCursor<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
IncludeCount extends boolean = true,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>,
|
||||
): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
||||
/**
|
||||
* Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been
|
||||
* persisted. Returns the same entity instance (same object reference), but re-hydrated. If the entity is no longer
|
||||
* in database, the method throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
||||
*/
|
||||
refreshOrFail<
|
||||
Entity extends object,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entity: Entity,
|
||||
options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<MergeLoaded<Entity, Naked, Hint, Fields, Excludes, true>>;
|
||||
/**
|
||||
* Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been
|
||||
* persisted. Returns the same entity instance (same object reference), but re-hydrated. If the entity is no longer
|
||||
* in database, the method returns `null`.
|
||||
*/
|
||||
refresh<
|
||||
Entity extends object,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entity: Entity,
|
||||
options?: FindOneOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<MergeLoaded<Entity, Naked, Hint, Fields, Excludes, true> | null>;
|
||||
/**
|
||||
* Finds first entity matching your `where` query.
|
||||
*/
|
||||
findOne<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
options?: FindOneOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
||||
/**
|
||||
* Finds first entity matching your `where` query. If nothing found, it will throw an error.
|
||||
* If the `strict` option is specified and nothing is found or more than one matching entity is found, it will throw an error.
|
||||
* You can override the factory for creating this method via `options.failHandler` locally
|
||||
* or via `Configuration.findOneOrFailHandler` (`findExactlyOneOrFailHandler` when specifying `strict`) globally.
|
||||
*/
|
||||
findOneOrFail<
|
||||
Entity extends object,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>>;
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance. The method accepts either `entityName` together with the entity `data`, or just entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const author = await em.upsert(Author, { email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.upsert(Author, { email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
upsert<Entity extends object, Fields extends string = any>(
|
||||
entityNameOrEntity: EntityName<Entity> | Entity,
|
||||
data?: EntityData<Entity> | NoInfer<Entity>,
|
||||
options?: UpsertOptions<Entity, Fields>,
|
||||
): Promise<Entity>;
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance. The method accepts either `entityName` together with the entity `data`, or just entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const authors = await em.upsertMany(Author, [{ email: 'foo@bar.com', age: 33 }, ...]);
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com'), (666, 'lol@lol.lol') on conflict ("email") do update set "age" = excluded."age"
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.upsertMany(Author, [
|
||||
* { email: 'foo@bar.com', age: 33 },
|
||||
* { email: 'lol@lol.lol', age: 666 },
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
upsertMany<Entity extends object, Fields extends string = any>(
|
||||
entityNameOrEntity: EntityName<Entity> | Entity[],
|
||||
data?: (EntityData<Entity> | NoInfer<Entity>)[],
|
||||
options?: UpsertManyOptions<Entity, Fields>,
|
||||
): Promise<Entity[]>;
|
||||
/**
|
||||
* Runs your callback wrapped inside a database transaction.
|
||||
*
|
||||
* If a transaction is already active, a new savepoint (nested transaction) will be created by default. This behavior
|
||||
* can be controlled via the `propagation` option. Use the provided EntityManager instance for all operations that
|
||||
* should be part of the transaction. You can safely use a global EntityManager instance from a DI container, as this
|
||||
* method automatically creates an async context for the transaction.
|
||||
*
|
||||
* **Concurrency note:** When running multiple transactions concurrently (e.g. in parallel requests or jobs), use the
|
||||
* `clear: true` option. This ensures the callback runs in a clear fork of the EntityManager, providing full isolation
|
||||
* between concurrent transactional handlers. Using `clear: true` is an alternative to forking explicitly and calling
|
||||
* the method on the new fork – it already provides the necessary isolation for safe concurrent usage.
|
||||
*
|
||||
* **Propagation note:** Changes made within a transaction (whether top-level or nested) are always propagated to the
|
||||
* parent context, unless the parent context is a global one. If you want to avoid that, fork the EntityManager first
|
||||
* and then call this method on the fork.
|
||||
*
|
||||
* **Example:**
|
||||
* ```ts
|
||||
* await em.transactional(async (em) => {
|
||||
* const author = new Author('Jon');
|
||||
* em.persist(author);
|
||||
* // flush is called automatically at the end of the callback
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
transactional<T>(cb: (em: this) => T | Promise<T>, options?: TransactionOptions): Promise<T>;
|
||||
/**
|
||||
* Starts new transaction bound to this EntityManager. Use `ctx` parameter to provide the parent when nesting transactions.
|
||||
*/
|
||||
begin(options?: Omit<TransactionOptions, 'ignoreNestedTransactions'>): Promise<void>;
|
||||
/**
|
||||
* Commits the transaction bound to this EntityManager. Flushes before doing the actual commit query.
|
||||
*/
|
||||
commit(): Promise<void>;
|
||||
/**
|
||||
* Rollbacks the transaction bound to this EntityManager.
|
||||
*/
|
||||
rollback(): Promise<void>;
|
||||
/**
|
||||
* Runs your callback wrapped inside a database transaction.
|
||||
*/
|
||||
lock<T extends object>(entity: T, lockMode: LockMode, options?: LockOptions | number | Date): Promise<void>;
|
||||
/**
|
||||
* Fires native insert query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
insert<Entity extends object>(
|
||||
entityNameOrEntity: EntityName<Entity> | Entity,
|
||||
data?: RequiredEntityData<Entity> | Entity,
|
||||
options?: NativeInsertUpdateOptions<Entity>,
|
||||
): Promise<Primary<Entity>>;
|
||||
/**
|
||||
* Fires native multi-insert query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
insertMany<Entity extends object>(
|
||||
entityNameOrEntities: EntityName<Entity> | Entity[],
|
||||
data?: RequiredEntityData<Entity>[] | Entity[],
|
||||
options?: NativeInsertUpdateOptions<Entity>,
|
||||
): Promise<Primary<Entity>[]>;
|
||||
/**
|
||||
* Fires native update query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
nativeUpdate<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
data: EntityData<Entity>,
|
||||
options?: UpdateOptions<Entity>,
|
||||
): Promise<number>;
|
||||
/**
|
||||
* Fires native delete query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
nativeDelete<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
where: FilterQuery<NoInfer<Entity>>,
|
||||
options?: DeleteOptions<Entity>,
|
||||
): Promise<number>;
|
||||
/**
|
||||
* Maps raw database result to an entity and merges it to this EntityManager.
|
||||
*/
|
||||
map<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
result: EntityDictionary<Entity>,
|
||||
options?: {
|
||||
schema?: string;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Merges given entity to this EntityManager so it becomes managed. You can force refreshing of existing entities
|
||||
* via second parameter. By default, it will return already loaded entities without modifying them.
|
||||
*/
|
||||
merge<Entity extends object>(entity: Entity, options?: MergeOptions): Entity;
|
||||
/**
|
||||
* Merges given entity to this EntityManager so it becomes managed. You can force refreshing of existing entities
|
||||
* via second parameter. By default, it will return already loaded entities without modifying them.
|
||||
*/
|
||||
merge<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
data: EntityData<Entity> | EntityDTO<Entity>,
|
||||
options?: MergeOptions,
|
||||
): Entity;
|
||||
/**
|
||||
* Creates new instance of given entity and populates it with given data.
|
||||
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
||||
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
||||
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
||||
* the whole `data` parameter will be passed. This means we can also define `constructor(data: Partial<T>)` and
|
||||
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
||||
*
|
||||
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
||||
* symbol to omit some properties from this check without making them optional. Alternatively, use `partial: true`
|
||||
* in the options to disable the strict checks for required properties. This option has no effect on runtime.
|
||||
*
|
||||
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
||||
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
||||
*/
|
||||
create<
|
||||
Entity extends object,
|
||||
Convert extends boolean = false,
|
||||
Data extends RequiredEntityData<Entity, never, Convert> = RequiredEntityData<Entity, never, Convert>,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
data: Data & IsSubset<RequiredEntityData<Entity, never, Convert>, Data>,
|
||||
options?: CreateOptions<Convert>,
|
||||
): Entity;
|
||||
/**
|
||||
* Creates new instance of given entity and populates it with given data.
|
||||
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
||||
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
||||
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
||||
* the whole `data` parameter will be passed. This means we can also define `constructor(data: Partial<T>)` and
|
||||
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
||||
*
|
||||
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
||||
* symbol to omit some properties from this check without making them optional. Alternatively, use `partial: true`
|
||||
* in the options to disable the strict checks for required properties. This option has no effect on runtime.
|
||||
*
|
||||
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
||||
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
||||
*/
|
||||
create<
|
||||
Entity extends object,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Entity, Convert> = EntityData<Entity, Convert>,
|
||||
>(
|
||||
entityName: EntityName<Entity>,
|
||||
data: Data & IsSubset<EntityData<Entity, Convert>, Data>,
|
||||
options: CreateOptions<Convert> & {
|
||||
partial: true;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Shortcut for `wrap(entity).assign(data, { em })`
|
||||
*/
|
||||
assign<
|
||||
Entity extends object,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
|
||||
| EntityData<Naked, Convert>
|
||||
| Partial<EntityDTO<Naked>>,
|
||||
>(
|
||||
entity: Entity | Partial<Entity>,
|
||||
data: Data & IsSubset<EntityData<Naked, Convert>, Data>,
|
||||
options?: AssignOptions<Convert>,
|
||||
): MergeSelected<Entity, Naked, keyof Data & string>;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
||||
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
||||
*/
|
||||
getReference<Entity extends object, K extends string & keyof Entity>(
|
||||
entityName: EntityName<Entity>,
|
||||
id: Entity[K],
|
||||
options: Omit<GetReferenceOptions, 'key' | 'wrapped'> & {
|
||||
key: K;
|
||||
wrapped: true;
|
||||
},
|
||||
): Ref<Entity>;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
||||
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
||||
*/
|
||||
getReference<Entity extends object, K extends string & keyof Entity>(
|
||||
entityName: EntityName<Entity>,
|
||||
id: Entity[K],
|
||||
options: Omit<GetReferenceOptions, 'key'> & {
|
||||
key: K;
|
||||
wrapped?: false;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
id: Primary<Entity>,
|
||||
options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
||||
wrapped: true;
|
||||
},
|
||||
): Ref<Entity>;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference<Entity extends object>(entityName: EntityName<Entity>, id: Primary<Entity> | Primary<Entity>[]): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
id: Primary<Entity>,
|
||||
options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
||||
wrapped: false;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
id: Primary<Entity>,
|
||||
options?: GetReferenceOptions,
|
||||
): Entity | Reference<Entity>;
|
||||
/**
|
||||
* Returns total number of entities matching your `where` query.
|
||||
*/
|
||||
count<Entity extends object, Hint extends string = never>(
|
||||
entityName: EntityName<Entity>,
|
||||
where?: FilterQuery<NoInfer<Entity>>,
|
||||
options?: CountOptions<Entity, Hint>,
|
||||
): Promise<number>;
|
||||
/**
|
||||
* Tells the EntityManager to make an instance managed and persistent.
|
||||
* The entity will be entered into the database at or before transaction commit or as a result of the flush operation.
|
||||
*/
|
||||
persist<Entity extends object>(entity: Entity | Reference<Entity> | Iterable<Entity | Reference<Entity>>): this;
|
||||
/**
|
||||
* Marks entity for removal.
|
||||
* A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
|
||||
*
|
||||
* To remove entities by condition, use `em.nativeDelete()`.
|
||||
*/
|
||||
remove<Entity extends object>(entity: Entity | Reference<Entity> | Iterable<Entity | Reference<Entity>>): this;
|
||||
/**
|
||||
* Flushes all changes to objects that have been queued up to now to the database.
|
||||
* This effectively synchronizes the in-memory state of managed objects with the database.
|
||||
*/
|
||||
flush(): Promise<void>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
tryFlush<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
options: {
|
||||
flushMode?: FlushMode | AnyString;
|
||||
},
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Clears the EntityManager. All entities that are currently managed by this EntityManager become detached.
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* Checks whether given property can be populated on the entity.
|
||||
*/
|
||||
canPopulate<Entity extends object>(entityName: EntityName<Entity>, property: string): boolean;
|
||||
/**
|
||||
* Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
|
||||
*/
|
||||
populate<
|
||||
Entity extends object,
|
||||
Naked extends FromEntityType<UnboxArray<Entity>> = FromEntityType<UnboxArray<Entity>>,
|
||||
Hint extends string = never,
|
||||
Fields extends string = never,
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entities: Entity,
|
||||
populate: readonly AutoPath<Naked, Hint, PopulatePath.ALL>[] | false,
|
||||
options?: EntityLoaderOptions<Naked, Fields, Excludes>,
|
||||
): Promise<
|
||||
Entity extends object[]
|
||||
? MergeLoaded<ArrayElement<Entity>, Naked, Hint, Fields, Excludes>[]
|
||||
: MergeLoaded<Entity, Naked, Hint, Fields, Excludes>
|
||||
>;
|
||||
/**
|
||||
* Returns new EntityManager instance with its own identity map
|
||||
*/
|
||||
fork(options?: ForkOptions): this;
|
||||
/**
|
||||
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
|
||||
*/
|
||||
getUnitOfWork(useContext?: boolean): UnitOfWork;
|
||||
/**
|
||||
* Gets the EntityFactory used by the EntityManager.
|
||||
*/
|
||||
getEntityFactory(): EntityFactory;
|
||||
/**
|
||||
* @internal use `em.populate()` as the user facing API, this is exposed only for internal usage
|
||||
*/
|
||||
getEntityLoader(): EntityLoader;
|
||||
/**
|
||||
* Gets the Hydrator used by the EntityManager.
|
||||
*/
|
||||
getHydrator(): IHydrator;
|
||||
/**
|
||||
* Gets the EntityManager based on current transaction/request context.
|
||||
* @internal
|
||||
*/
|
||||
getContext(validate?: boolean): this;
|
||||
/** Gets the EventManager instance used by this EntityManager. */
|
||||
getEventManager(): EventManager;
|
||||
/**
|
||||
* Checks whether this EntityManager is currently operating inside a database transaction.
|
||||
*/
|
||||
isInTransaction(): boolean;
|
||||
/**
|
||||
* Gets the transaction context (driver dependent object used to make sure queries are executed on same connection).
|
||||
*/
|
||||
getTransactionContext<T extends Transaction = Transaction>(): T | undefined;
|
||||
/**
|
||||
* Sets the transaction context.
|
||||
*/
|
||||
setTransactionContext(ctx?: Transaction): void;
|
||||
/**
|
||||
* Resets the transaction context.
|
||||
*/
|
||||
resetTransactionContext(): void;
|
||||
/**
|
||||
* Gets the `MetadataStorage`.
|
||||
*/
|
||||
getMetadata(): MetadataStorage;
|
||||
/**
|
||||
* Gets the `EntityMetadata` instance when provided with the `entityName` parameter.
|
||||
*/
|
||||
getMetadata<Entity extends object>(entityName: EntityName<Entity>): EntityMetadata<Entity>;
|
||||
/**
|
||||
* Gets the EntityComparator.
|
||||
*/
|
||||
getComparator(): EntityComparator;
|
||||
private checkLockRequirements;
|
||||
private lockAndPopulate;
|
||||
private buildFields;
|
||||
/** @internal */
|
||||
preparePopulate<Entity extends object>(
|
||||
entityName: EntityName<Entity>,
|
||||
options: Pick<
|
||||
FindOptions<Entity, any, any, any>,
|
||||
'populate' | 'strategy' | 'fields' | 'flags' | 'filters' | 'exclude' | 'populateHints'
|
||||
>,
|
||||
validate?: boolean,
|
||||
): Promise<PopulateOptions<Entity>[]>;
|
||||
/**
|
||||
* when the entity is found in identity map, we check if it was partially loaded or we are trying to populate
|
||||
* some additional lazy properties, if so, we reload and merge the data from database
|
||||
*/
|
||||
protected shouldRefresh<T extends object, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
meta: EntityMetadata<T>,
|
||||
entity: T,
|
||||
options: FindOneOptions<T, P, F, E>,
|
||||
): boolean;
|
||||
protected prepareOptions(
|
||||
options: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any> | CountOptions<any, any>,
|
||||
): void;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
cacheKey<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any> | CountOptions<T, any>,
|
||||
method: string,
|
||||
where: FilterQuery<T>,
|
||||
): unknown[];
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
tryCache<T extends object, R>(
|
||||
entityName: EntityName<T>,
|
||||
config: boolean | number | [string, number] | undefined,
|
||||
key: unknown,
|
||||
refresh?: boolean,
|
||||
merge?: boolean,
|
||||
): Promise<
|
||||
| {
|
||||
data?: R | null;
|
||||
key: string;
|
||||
}
|
||||
| undefined
|
||||
>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
storeCache<T>(
|
||||
config: boolean | number | [string, number] | undefined,
|
||||
key: {
|
||||
key: string;
|
||||
},
|
||||
data: T | (() => T),
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Clears result cache for given cache key. If we want to be able to call this method,
|
||||
* we need to set the cache key explicitly when storing the cache.
|
||||
*
|
||||
* ```ts
|
||||
* // set the cache key to 'book-cache-key', with expiration of 60s
|
||||
* const res = await em.find(Book, { ... }, { cache: ['book-cache-key', 60_000] });
|
||||
*
|
||||
* // clear the cache key by name
|
||||
* await em.clearCache('book-cache-key');
|
||||
* ```
|
||||
*/
|
||||
clearCache(cacheKey: string): Promise<void>;
|
||||
/**
|
||||
* Returns the default schema of this EntityManager. Respects the context, so global EM will give you the contextual schema
|
||||
* if executed inside request context handler.
|
||||
*/
|
||||
get schema(): string | undefined;
|
||||
/**
|
||||
* Sets the default schema of this EntityManager. Respects the context, so global EM will set the contextual schema
|
||||
* if executed inside request context handler.
|
||||
*/
|
||||
set schema(schema: string | null | undefined);
|
||||
/** @internal */
|
||||
getDataLoader(type: 'ref' | '1:m' | 'm:n'): Promise<any>;
|
||||
/**
|
||||
* Returns the ID of this EntityManager. Respects the context, so global EM will give you the contextual ID
|
||||
* if executed inside request context handler.
|
||||
*/
|
||||
get id(): number;
|
||||
}
|
||||
export interface CreateOptions<Convert extends boolean> {
|
||||
/** creates a managed entity instance instead, bypassing the constructor call */
|
||||
managed?: boolean;
|
||||
/** create entity in a specific schema - alternatively, use `wrap(entity).setSchema()` */
|
||||
schema?: string;
|
||||
/** persist the entity automatically - this is the default behavior and is also configurable globally via `persistOnCreate` option */
|
||||
persist?: boolean;
|
||||
/** this option disables the strict typing which requires all mandatory properties to have value, it has no effect on runtime */
|
||||
partial?: boolean;
|
||||
/** convert raw database values based on mapped types (by default, already converted values are expected) */
|
||||
convertCustomTypes?: Convert;
|
||||
/**
|
||||
* Property `onCreate` hooks are normally executed during `flush` operation.
|
||||
* With this option, they will be processed early inside `em.create()` method.
|
||||
*/
|
||||
processOnCreateHooksEarly?: boolean;
|
||||
}
|
||||
export interface MergeOptions {
|
||||
refresh?: boolean;
|
||||
convertCustomTypes?: boolean;
|
||||
schema?: string;
|
||||
disableContextResolution?: boolean;
|
||||
validate?: boolean;
|
||||
cascade?: boolean /** @default true */;
|
||||
}
|
||||
export interface ForkOptions {
|
||||
/** do we want a clear identity map? defaults to true */
|
||||
clear?: boolean;
|
||||
/** use request context? should be used only for top level request scope EM, defaults to false */
|
||||
useContext?: boolean;
|
||||
/** do we want to use fresh EventManager instance? defaults to false (global instance) */
|
||||
freshEventManager?: boolean;
|
||||
/** do we want to clone current EventManager instance? defaults to false (global instance) */
|
||||
cloneEventManager?: boolean;
|
||||
/** use this flag to ignore the current async context - this is required if we want to call `em.fork()` inside the `getContext` handler */
|
||||
disableContextResolution?: boolean;
|
||||
/** set flush mode for this fork, overrides the global option can be overridden locally via FindOptions */
|
||||
flushMode?: FlushMode | `${FlushMode}`;
|
||||
/** disable transactions for this fork */
|
||||
disableTransactions?: boolean;
|
||||
/** should we keep the transaction context of the parent EM? */
|
||||
keepTransactionContext?: boolean;
|
||||
/** default schema to use for this fork */
|
||||
schema?: string;
|
||||
/** default logger context, can be overridden via {@apilink FindOptions} */
|
||||
loggerContext?: Dictionary;
|
||||
}
|
||||
1936
node_modules/@mikro-orm/core/EntityManager.js
generated
vendored
Normal file
1936
node_modules/@mikro-orm/core/EntityManager.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
node_modules/@mikro-orm/core/LICENSE
generated
vendored
Normal file
21
node_modules/@mikro-orm/core/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Martin Adámek
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
143
node_modules/@mikro-orm/core/MikroORM.d.ts
generated
vendored
Normal file
143
node_modules/@mikro-orm/core/MikroORM.d.ts
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
import type { EntityManagerType, IDatabaseDriver } from './drivers/IDatabaseDriver.js';
|
||||
import { type EntitySchema } from './metadata/EntitySchema.js';
|
||||
import { MetadataStorage } from './metadata/MetadataStorage.js';
|
||||
import { Configuration, type Options } from './utils/Configuration.js';
|
||||
import type { EntityManager } from './EntityManager.js';
|
||||
import type {
|
||||
AnyEntity,
|
||||
Constructor,
|
||||
EntityClass,
|
||||
EntityMetadata,
|
||||
EntityName,
|
||||
IEntityGenerator,
|
||||
IMigrator,
|
||||
ISeedManager,
|
||||
} from './typings.js';
|
||||
/** @internal */
|
||||
export declare function loadOptionalDependencies(options: Partial<Options>): Promise<void>;
|
||||
/**
|
||||
* The main class used to configure and bootstrap the ORM.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // import from driver package
|
||||
* import { MikroORM, defineEntity, p } from '@mikro-orm/sqlite';
|
||||
*
|
||||
* const User = defineEntity({
|
||||
* name: 'User',
|
||||
* properties: {
|
||||
* id: p.integer().primary(),
|
||||
* name: p.string(),
|
||||
* },
|
||||
* });
|
||||
*
|
||||
* const orm = new MikroORM({
|
||||
* entities: [User],
|
||||
* dbName: 'my.db',
|
||||
* });
|
||||
* await orm.schema.update();
|
||||
*
|
||||
* const em = orm.em.fork();
|
||||
* const u1 = em.create(User, { name: 'John' });
|
||||
* const u2 = em.create(User, { name: 'Ben' });
|
||||
* await em.flush();
|
||||
* ```
|
||||
*/
|
||||
export declare class MikroORM<
|
||||
Driver extends IDatabaseDriver = IDatabaseDriver,
|
||||
EM extends Driver[typeof EntityManagerType] & EntityManager<Driver> = Driver[typeof EntityManagerType] &
|
||||
EntityManager<Driver>,
|
||||
Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
|
||||
| string
|
||||
| EntityClass<AnyEntity>
|
||||
| EntitySchema
|
||||
)[],
|
||||
> {
|
||||
#private;
|
||||
/** The global EntityManager instance. If you are using `RequestContext` helper, it will automatically pick the request specific context under the hood */
|
||||
em: EM & {
|
||||
'~entities'?: Entities;
|
||||
};
|
||||
/** The database driver instance used by this ORM. */
|
||||
readonly driver: Driver;
|
||||
/** The ORM configuration instance. */
|
||||
readonly config: Configuration<Driver>;
|
||||
/**
|
||||
* Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
|
||||
* If you omit the `options` parameter, your CLI config will be used.
|
||||
*/
|
||||
static init<
|
||||
D extends IDatabaseDriver = IDatabaseDriver,
|
||||
EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>,
|
||||
Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
|
||||
| string
|
||||
| EntityClass<AnyEntity>
|
||||
| EntitySchema
|
||||
)[],
|
||||
>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
|
||||
/**
|
||||
* Synchronous variant of the `init` method with some limitations:
|
||||
* - folder-based discovery not supported
|
||||
* - ORM extensions are not autoloaded
|
||||
* - when metadata cache is enabled, `FileCacheAdapter` needs to be explicitly set in the config
|
||||
*/
|
||||
constructor(options: Partial<Options<Driver, EM, Entities>>);
|
||||
/**
|
||||
* Connects to the database.
|
||||
*/
|
||||
connect(): Promise<Driver>;
|
||||
/**
|
||||
* Reconnects, possibly to a different database.
|
||||
*/
|
||||
reconnect(options?: Partial<Options<Driver, EM, Entities>>): Promise<void>;
|
||||
/**
|
||||
* Checks whether the database connection is active.
|
||||
*/
|
||||
isConnected(): Promise<boolean>;
|
||||
/**
|
||||
* Checks whether the database connection is active, returns the reason if not.
|
||||
*/
|
||||
checkConnection(): Promise<
|
||||
| {
|
||||
ok: true;
|
||||
}
|
||||
| {
|
||||
ok: false;
|
||||
reason: string;
|
||||
error?: Error;
|
||||
}
|
||||
>;
|
||||
/**
|
||||
* Closes the database connection.
|
||||
*/
|
||||
close(force?: boolean): Promise<void>;
|
||||
/**
|
||||
* Gets the `MetadataStorage`.
|
||||
*/
|
||||
getMetadata(): MetadataStorage;
|
||||
/**
|
||||
* Gets the `EntityMetadata` instance when provided with the `entityName` parameter.
|
||||
*/
|
||||
getMetadata<Entity extends object>(entityName: EntityName<Entity>): EntityMetadata<Entity>;
|
||||
private createEntityManager;
|
||||
/**
|
||||
* Allows dynamically discovering new entity by reference, handy for testing schema diffing.
|
||||
*/
|
||||
discoverEntity<T extends Constructor | EntitySchema>(entities: T | T[], reset?: EntityName | EntityName[]): void;
|
||||
/**
|
||||
* Gets the SchemaGenerator.
|
||||
*/
|
||||
get schema(): ReturnType<ReturnType<Driver['getPlatform']>['getSchemaGenerator']>;
|
||||
/**
|
||||
* Gets the SeedManager
|
||||
*/
|
||||
get seeder(): ISeedManager;
|
||||
/**
|
||||
* Gets the Migrator.
|
||||
*/
|
||||
get migrator(): IMigrator;
|
||||
/**
|
||||
* Gets the EntityGenerator.
|
||||
*/
|
||||
get entityGenerator(): IEntityGenerator;
|
||||
}
|
||||
219
node_modules/@mikro-orm/core/MikroORM.js
generated
vendored
Normal file
219
node_modules/@mikro-orm/core/MikroORM.js
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
import { MetadataDiscovery } from './metadata/MetadataDiscovery.js';
|
||||
import { MetadataStorage } from './metadata/MetadataStorage.js';
|
||||
import { Configuration } from './utils/Configuration.js';
|
||||
import { loadEnvironmentVars } from './utils/env-vars.js';
|
||||
import { Utils } from './utils/Utils.js';
|
||||
import { colors } from './logging/colors.js';
|
||||
async function tryRegisterExtension(name, pkg, extensions) {
|
||||
try {
|
||||
const url = import.meta.resolve(pkg);
|
||||
const mod = await import(url);
|
||||
if (mod[name]) {
|
||||
extensions.push(mod[name]);
|
||||
}
|
||||
} catch {
|
||||
// not installed
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export async function loadOptionalDependencies(options) {
|
||||
await import('@mikro-orm/core/fs-utils').then(m => m.fs.init()).catch(() => null);
|
||||
const extensions = options.extensions ?? [];
|
||||
const exists = name => extensions.some(ext => ext.name === name);
|
||||
if (!exists('SeedManager')) {
|
||||
await tryRegisterExtension('SeedManager', '@mikro-orm/seeder', extensions);
|
||||
}
|
||||
if (!exists('Migrator')) {
|
||||
await tryRegisterExtension('Migrator', '@mikro-orm/migrations', extensions);
|
||||
}
|
||||
/* v8 ignore if */
|
||||
if (!exists('Migrator')) {
|
||||
await tryRegisterExtension('Migrator', '@mikro-orm/migrations-mongodb', extensions);
|
||||
}
|
||||
if (!exists('EntityGenerator')) {
|
||||
await tryRegisterExtension('EntityGenerator', '@mikro-orm/entity-generator', extensions);
|
||||
}
|
||||
options.extensions = extensions;
|
||||
const metadataCacheEnabled = options.metadataCache?.enabled || options.metadataProvider?.useCache?.();
|
||||
if (metadataCacheEnabled) {
|
||||
options.metadataCache ??= {};
|
||||
options.metadataCache.adapter ??= await import('@mikro-orm/core/fs-utils').then(m => m.FileCacheAdapter);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The main class used to configure and bootstrap the ORM.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // import from driver package
|
||||
* import { MikroORM, defineEntity, p } from '@mikro-orm/sqlite';
|
||||
*
|
||||
* const User = defineEntity({
|
||||
* name: 'User',
|
||||
* properties: {
|
||||
* id: p.integer().primary(),
|
||||
* name: p.string(),
|
||||
* },
|
||||
* });
|
||||
*
|
||||
* const orm = new MikroORM({
|
||||
* entities: [User],
|
||||
* dbName: 'my.db',
|
||||
* });
|
||||
* await orm.schema.update();
|
||||
*
|
||||
* const em = orm.em.fork();
|
||||
* const u1 = em.create(User, { name: 'John' });
|
||||
* const u2 = em.create(User, { name: 'Ben' });
|
||||
* await em.flush();
|
||||
* ```
|
||||
*/
|
||||
export class MikroORM {
|
||||
/** The global EntityManager instance. If you are using `RequestContext` helper, it will automatically pick the request specific context under the hood */
|
||||
em;
|
||||
/** The database driver instance used by this ORM. */
|
||||
driver;
|
||||
/** The ORM configuration instance. */
|
||||
config;
|
||||
#metadata;
|
||||
#logger;
|
||||
#discovery;
|
||||
/**
|
||||
* Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
|
||||
* If you omit the `options` parameter, your CLI config will be used.
|
||||
*/
|
||||
static async init(options) {
|
||||
/* v8 ignore next */
|
||||
if (!options) {
|
||||
throw new Error(`options parameter is required`);
|
||||
}
|
||||
options = { ...options };
|
||||
options.discovery ??= {};
|
||||
options.discovery.skipSyncDiscovery ??= true;
|
||||
await loadOptionalDependencies(options);
|
||||
const orm = new this(options);
|
||||
const preferTs = orm.config.get('preferTs', Utils.detectTypeScriptSupport());
|
||||
orm.#metadata = await orm.#discovery.discover(preferTs);
|
||||
orm.createEntityManager();
|
||||
return orm;
|
||||
}
|
||||
/**
|
||||
* Synchronous variant of the `init` method with some limitations:
|
||||
* - folder-based discovery not supported
|
||||
* - ORM extensions are not autoloaded
|
||||
* - when metadata cache is enabled, `FileCacheAdapter` needs to be explicitly set in the config
|
||||
*/
|
||||
constructor(options) {
|
||||
const env = loadEnvironmentVars();
|
||||
options = options.preferEnvVars ? Utils.merge(options, env) : Utils.merge(env, options);
|
||||
this.config = new Configuration(options);
|
||||
const discovery = this.config.get('discovery');
|
||||
this.driver = this.config.getDriver();
|
||||
this.#logger = this.config.getLogger();
|
||||
this.#logger.log('info', `MikroORM version: ${colors.green(Utils.getORMVersion())}`);
|
||||
this.#discovery = new MetadataDiscovery(new MetadataStorage(), this.driver.getPlatform(), this.config);
|
||||
this.driver.getPlatform().init(this);
|
||||
for (const extension of this.config.get('extensions')) {
|
||||
extension.register(this);
|
||||
}
|
||||
if (!discovery.skipSyncDiscovery) {
|
||||
this.#metadata = this.#discovery.discoverSync();
|
||||
this.createEntityManager();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Connects to the database.
|
||||
*/
|
||||
async connect() {
|
||||
await this.driver.connect();
|
||||
return this.driver;
|
||||
}
|
||||
/**
|
||||
* Reconnects, possibly to a different database.
|
||||
*/
|
||||
async reconnect(options = {}) {
|
||||
/* v8 ignore next */
|
||||
for (const key of Utils.keys(options)) {
|
||||
this.config.set(key, options[key]);
|
||||
}
|
||||
await this.driver.reconnect();
|
||||
}
|
||||
/**
|
||||
* Checks whether the database connection is active.
|
||||
*/
|
||||
async isConnected() {
|
||||
return this.driver.getConnection().isConnected();
|
||||
}
|
||||
/**
|
||||
* Checks whether the database connection is active, returns the reason if not.
|
||||
*/
|
||||
async checkConnection() {
|
||||
return this.driver.getConnection().checkConnection();
|
||||
}
|
||||
/**
|
||||
* Closes the database connection.
|
||||
*/
|
||||
async close(force = false) {
|
||||
await this.driver.close(force);
|
||||
await this.config.getMetadataCacheAdapter()?.close?.();
|
||||
await this.config.getResultCacheAdapter()?.close?.();
|
||||
}
|
||||
/**
|
||||
* Gets the `MetadataStorage` (without parameters) or `EntityMetadata` instance when provided with the `entityName` parameter.
|
||||
*/
|
||||
getMetadata(entityName) {
|
||||
if (entityName) {
|
||||
return this.#metadata.get(entityName);
|
||||
}
|
||||
return this.#metadata;
|
||||
}
|
||||
createEntityManager() {
|
||||
this.driver.setMetadata(this.#metadata);
|
||||
this.em = this.driver.createEntityManager();
|
||||
this.em.global = true;
|
||||
this.#metadata.decorate(this.em);
|
||||
this.driver.setMetadata(this.#metadata);
|
||||
}
|
||||
/**
|
||||
* Allows dynamically discovering new entity by reference, handy for testing schema diffing.
|
||||
*/
|
||||
discoverEntity(entities, reset) {
|
||||
for (const className of Utils.asArray(reset)) {
|
||||
this.#metadata.reset(className);
|
||||
this.#discovery.reset(className);
|
||||
}
|
||||
const tmp = this.#discovery.discoverReferences(Utils.asArray(entities));
|
||||
const metadata = this.#discovery.processDiscoveredEntities(tmp);
|
||||
for (const meta of metadata) {
|
||||
this.#metadata.set(meta.class, meta);
|
||||
meta.root = this.#metadata.get(meta.root.class);
|
||||
}
|
||||
this.#metadata.decorate(this.em);
|
||||
}
|
||||
/**
|
||||
* Gets the SchemaGenerator.
|
||||
*/
|
||||
get schema() {
|
||||
return this.config.getExtension('@mikro-orm/schema-generator');
|
||||
}
|
||||
/**
|
||||
* Gets the SeedManager
|
||||
*/
|
||||
get seeder() {
|
||||
return this.driver.getPlatform().getExtension('SeedManager', '@mikro-orm/seeder', '@mikro-orm/seeder', this.em);
|
||||
}
|
||||
/**
|
||||
* Gets the Migrator.
|
||||
*/
|
||||
get migrator() {
|
||||
return this.driver.getPlatform().getExtension('Migrator', '@mikro-orm/migrator', '@mikro-orm/migrations', this.em);
|
||||
}
|
||||
/**
|
||||
* Gets the EntityGenerator.
|
||||
*/
|
||||
get entityGenerator() {
|
||||
return this.driver
|
||||
.getPlatform()
|
||||
.getExtension('EntityGenerator', '@mikro-orm/entity-generator', '@mikro-orm/entity-generator', this.em);
|
||||
}
|
||||
}
|
||||
225
node_modules/@mikro-orm/core/README.md
generated
vendored
Normal file
225
node_modules/@mikro-orm/core/README.md
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
<h1 align="center">
|
||||
<a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
|
||||
</h1>
|
||||
|
||||
TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite (including libSQL), MSSQL and Oracle databases.
|
||||
|
||||
> Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
|
||||
|
||||
[](https://npmx.dev/package/@mikro-orm/core)
|
||||
[](https://npmx.dev/package/@mikro-orm/core)
|
||||
[](https://discord.gg/w8bjxFHS7X)
|
||||
[](https://npmx.dev/package/@mikro-orm/core)
|
||||
[](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
|
||||
[](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Install a driver package for your database:
|
||||
|
||||
```sh
|
||||
npm install @mikro-orm/postgresql # PostgreSQL
|
||||
npm install @mikro-orm/mysql # MySQL
|
||||
npm install @mikro-orm/mariadb # MariaDB
|
||||
npm install @mikro-orm/sqlite # SQLite
|
||||
npm install @mikro-orm/libsql # libSQL / Turso
|
||||
npm install @mikro-orm/mongodb # MongoDB
|
||||
npm install @mikro-orm/mssql # MS SQL Server
|
||||
npm install @mikro-orm/oracledb # Oracle
|
||||
```
|
||||
|
||||
> If you use additional packages like `@mikro-orm/cli`, `@mikro-orm/migrations`, or `@mikro-orm/entity-generator`, install `@mikro-orm/core` explicitly as well. See the [quick start guide](https://mikro-orm.io/docs/quick-start) for details.
|
||||
|
||||
### Define Entities
|
||||
|
||||
The recommended way to define entities is using [`defineEntity`](https://mikro-orm.io/docs/define-entity) with `setClass`:
|
||||
|
||||
```typescript
|
||||
import { defineEntity, p, MikroORM } from '@mikro-orm/postgresql';
|
||||
|
||||
const AuthorSchema = defineEntity({
|
||||
name: 'Author',
|
||||
properties: {
|
||||
id: p.integer().primary(),
|
||||
name: p.string(),
|
||||
email: p.string(),
|
||||
born: p.datetime().nullable(),
|
||||
books: () => p.oneToMany(Book).mappedBy('author'),
|
||||
},
|
||||
});
|
||||
|
||||
export class Author extends AuthorSchema.class {}
|
||||
AuthorSchema.setClass(Author);
|
||||
|
||||
const BookSchema = defineEntity({
|
||||
name: 'Book',
|
||||
properties: {
|
||||
id: p.integer().primary(),
|
||||
title: p.string(),
|
||||
author: () => p.manyToOne(Author).inversedBy('books'),
|
||||
},
|
||||
});
|
||||
|
||||
export class Book extends BookSchema.class {}
|
||||
BookSchema.setClass(Book);
|
||||
```
|
||||
|
||||
You can also define entities using [decorators](https://mikro-orm.io/docs/defining-entities) or [`EntitySchema`](https://mikro-orm.io/docs/entity-schema). See the [defining entities guide](https://mikro-orm.io/docs/defining-entities) for all options.
|
||||
|
||||
### Initialize and Use
|
||||
|
||||
```typescript
|
||||
import { MikroORM, RequestContext } from '@mikro-orm/postgresql';
|
||||
|
||||
const orm = await MikroORM.init({
|
||||
entities: [Author, Book],
|
||||
dbName: 'my-db',
|
||||
});
|
||||
|
||||
// Create new entities
|
||||
const author = orm.em.create(Author, {
|
||||
name: 'Jon Snow',
|
||||
email: 'snow@wall.st',
|
||||
});
|
||||
const book = orm.em.create(Book, {
|
||||
title: 'My Life on The Wall',
|
||||
author,
|
||||
});
|
||||
|
||||
// Flush persists all tracked changes in a single transaction
|
||||
await orm.em.flush();
|
||||
```
|
||||
|
||||
### Querying
|
||||
|
||||
```typescript
|
||||
// Find with relations
|
||||
const authors = await orm.em.findAll(Author, {
|
||||
populate: ['books'],
|
||||
orderBy: { name: 'asc' },
|
||||
});
|
||||
|
||||
// Type-safe QueryBuilder
|
||||
const qb = orm.em.createQueryBuilder(Author);
|
||||
const result = await qb
|
||||
.select('*')
|
||||
.where({ books: { title: { $like: '%Wall%' } } })
|
||||
.getResult();
|
||||
```
|
||||
|
||||
### Request Context
|
||||
|
||||
In web applications, use `RequestContext` to isolate the identity map per request:
|
||||
|
||||
```typescript
|
||||
const app = express();
|
||||
|
||||
app.use((req, res, next) => {
|
||||
RequestContext.create(orm.em, next);
|
||||
});
|
||||
```
|
||||
|
||||
More info about `RequestContext` is described [here](https://mikro-orm.io/docs/identity-map/#request-context).
|
||||
|
||||
## Unit of Work
|
||||
|
||||
> Unit of Work maintains a list of objects (_entities_) affected by a business transaction
|
||||
> and coordinates the writing out of changes. [(Martin Fowler)](https://www.martinfowler.com/eaaCatalog/unitOfWork.html)
|
||||
|
||||
When you call `em.flush()`, all computed changes are queried inside a database transaction. This means you can control transaction boundaries simply by making changes to your entities and calling `flush()` when ready.
|
||||
|
||||
```typescript
|
||||
const author = await em.findOneOrFail(Author, 1, {
|
||||
populate: ['books'],
|
||||
});
|
||||
author.name = 'Jon Snow II';
|
||||
author.books.getItems().forEach(book => book.title += ' (2nd ed.)');
|
||||
author.books.add(orm.em.create(Book, { title: 'New Book', author }));
|
||||
|
||||
// Flush computes change sets and executes them in a single transaction
|
||||
await em.flush();
|
||||
```
|
||||
|
||||
The above flush will execute:
|
||||
|
||||
```sql
|
||||
begin;
|
||||
update "author" set "name" = 'Jon Snow II' where "id" = 1;
|
||||
update "book"
|
||||
set "title" = case
|
||||
when ("id" = 1) then 'My Life on The Wall (2nd ed.)'
|
||||
when ("id" = 2) then 'Another Book (2nd ed.)'
|
||||
else "title" end
|
||||
where "id" in (1, 2);
|
||||
insert into "book" ("title", "author_id") values ('New Book', 1);
|
||||
commit;
|
||||
```
|
||||
|
||||
## Core Features
|
||||
|
||||
- [Clean and Simple Entity Definition](https://mikro-orm.io/docs/defining-entities) — decorators, `EntitySchema`, or `defineEntity`
|
||||
- [Identity Map](https://mikro-orm.io/docs/identity-map) and [Unit of Work](https://mikro-orm.io/docs/unit-of-work) — automatic change tracking
|
||||
- [Entity References](https://mikro-orm.io/docs/entity-references) and [Collections](https://mikro-orm.io/docs/collections)
|
||||
- [QueryBuilder](https://mikro-orm.io/docs/query-builder) and [Kysely Integration](https://mikro-orm.io/docs/kysely)
|
||||
- [Transactions](https://mikro-orm.io/docs/transactions) and [Cascading](https://mikro-orm.io/docs/cascading)
|
||||
- [Populating Relations](https://mikro-orm.io/docs/populating-relations) and [Loading Strategies](https://mikro-orm.io/docs/loading-strategies)
|
||||
- [Filters](https://mikro-orm.io/docs/filters) and [Lifecycle Hooks](https://mikro-orm.io/docs/events#hooks)
|
||||
- [Schema Generator](https://mikro-orm.io/docs/schema-generator) and [Migrations](https://mikro-orm.io/docs/migrations)
|
||||
- [Entity Generator](https://mikro-orm.io/docs/entity-generator) and [Seeding](https://mikro-orm.io/docs/seeding)
|
||||
- [Embeddables](https://mikro-orm.io/docs/embeddables), [Custom Types](https://mikro-orm.io/docs/custom-types), and [Serialization](https://mikro-orm.io/docs/serializing)
|
||||
- [Composite and Foreign Keys as Primary Key](https://mikro-orm.io/docs/composite-keys)
|
||||
- [Entity Constructors](https://mikro-orm.io/docs/entity-constructors) and [Property Validation](https://mikro-orm.io/docs/property-validation)
|
||||
- [Modelling Relationships](https://mikro-orm.io/docs/relationships) and [Vanilla JS Support](https://mikro-orm.io/docs/usage-with-js)
|
||||
|
||||
## Documentation
|
||||
|
||||
MikroORM documentation, included in this repo in the root directory, is built with [Docusaurus](https://docusaurus.io) and publicly hosted on GitHub Pages at https://mikro-orm.io.
|
||||
|
||||
There is also auto-generated [CHANGELOG.md](CHANGELOG.md) file based on commit messages (via `semantic-release`).
|
||||
|
||||
## Example Integrations
|
||||
|
||||
You can find example integrations for some popular frameworks in the [`mikro-orm-examples` repository](https://github.com/mikro-orm/mikro-orm-examples):
|
||||
|
||||
### TypeScript Examples
|
||||
|
||||
- [Express + MongoDB](https://github.com/mikro-orm/express-ts-example-app)
|
||||
- [Nest + MySQL](https://github.com/mikro-orm/nestjs-example-app)
|
||||
- [RealWorld example app (Nest + MySQL)](https://github.com/mikro-orm/nestjs-realworld-example-app)
|
||||
- [Koa + SQLite](https://github.com/mikro-orm/koa-ts-example-app)
|
||||
- [GraphQL + PostgreSQL](https://github.com/driescroons/mikro-orm-graphql-example)
|
||||
- [Inversify + PostgreSQL](https://github.com/PodaruDragos/inversify-example-app)
|
||||
- [NextJS + MySQL](https://github.com/jonahallibone/mikro-orm-nextjs)
|
||||
- [Accounts.js REST and GraphQL authentication + SQLite](https://github.com/darkbasic/mikro-orm-accounts-example)
|
||||
- [Nest + Shopify + PostgreSQL + GraphQL](https://github.com/Cloudshelf/Shopify_CSConnector)
|
||||
- [Elysia.js + libSQL + Bun](https://github.com/mikro-orm/elysia-bun-example-app)
|
||||
- [Electron.js + PostgreSQL](https://github.com/adnanlah/electron-mikro-orm-example-app)
|
||||
|
||||
### JavaScript Examples
|
||||
|
||||
- [Express + SQLite](https://github.com/mikro-orm/express-js-example-app)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions, issues and feature requests are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the process for submitting pull requests to us.
|
||||
|
||||
## Authors
|
||||
|
||||
**Martin Adámek**
|
||||
|
||||
- Twitter: [@B4nan](https://twitter.com/B4nan)
|
||||
- Github: [@b4nan](https://github.com/b4nan)
|
||||
|
||||
See also the list of contributors who [participated](https://github.com/mikro-orm/mikro-orm/contributors) in this project.
|
||||
|
||||
## Show Your Support
|
||||
|
||||
Please star this repository if this project helped you!
|
||||
|
||||
> If you'd like to support my open-source work, consider sponsoring me directly at [github.com/sponsors/b4nan](https://github.com/sponsors/b4nan).
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2018-present [Martin Adámek](https://github.com/b4nan).
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details.
|
||||
42
node_modules/@mikro-orm/core/cache/CacheAdapter.d.ts
generated
vendored
Normal file
42
node_modules/@mikro-orm/core/cache/CacheAdapter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/** Interface for async-capable cache storage used by result cache and metadata cache. */
|
||||
export interface CacheAdapter {
|
||||
/**
|
||||
* Gets the items under `name` key from the cache.
|
||||
*/
|
||||
get<T = any>(name: string): T | Promise<T | undefined> | undefined;
|
||||
/**
|
||||
* Sets the item to the cache. `origin` is used for cache invalidation and should reflect the change in data.
|
||||
*/
|
||||
set(name: string, data: any, origin: string, expiration?: number): void | Promise<void>;
|
||||
/**
|
||||
* Removes the item from cache.
|
||||
*/
|
||||
remove(name: string): void | Promise<void>;
|
||||
/**
|
||||
* Clears all items stored in the cache.
|
||||
*/
|
||||
clear(): void | Promise<void>;
|
||||
/**
|
||||
* Called inside `MikroORM.close()` Allows graceful shutdowns (e.g. for redis).
|
||||
*/
|
||||
close?(): void | Promise<void>;
|
||||
}
|
||||
/** Synchronous variant of CacheAdapter, used for metadata cache where async access is not needed. */
|
||||
export interface SyncCacheAdapter extends CacheAdapter {
|
||||
/**
|
||||
* Gets the items under `name` key from the cache.
|
||||
*/
|
||||
get<T = any>(name: string): T | undefined;
|
||||
/**
|
||||
* Sets the item to the cache. `origin` is used for cache invalidation and should reflect the change in data.
|
||||
*/
|
||||
set(name: string, data: any, origin: string, expiration?: number): void;
|
||||
/**
|
||||
* Removes the item from cache.
|
||||
*/
|
||||
remove(name: string): void;
|
||||
/**
|
||||
* Generates a combined cache from all existing entries.
|
||||
*/
|
||||
combine?(): string | void;
|
||||
}
|
||||
1
node_modules/@mikro-orm/core/cache/CacheAdapter.js
generated
vendored
Normal file
1
node_modules/@mikro-orm/core/cache/CacheAdapter.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
33
node_modules/@mikro-orm/core/cache/FileCacheAdapter.d.ts
generated
vendored
Normal file
33
node_modules/@mikro-orm/core/cache/FileCacheAdapter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { SyncCacheAdapter } from './CacheAdapter.js';
|
||||
export declare class FileCacheAdapter implements SyncCacheAdapter {
|
||||
#private;
|
||||
constructor(
|
||||
options:
|
||||
| {
|
||||
cacheDir: string;
|
||||
combined?: boolean | string;
|
||||
}
|
||||
| undefined,
|
||||
baseDir: string,
|
||||
pretty?: boolean,
|
||||
);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name: string): any;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name: string, data: any, origin: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear(): void;
|
||||
combine(): string | void;
|
||||
private path;
|
||||
private getHash;
|
||||
}
|
||||
91
node_modules/@mikro-orm/core/cache/FileCacheAdapter.js
generated
vendored
Normal file
91
node_modules/@mikro-orm/core/cache/FileCacheAdapter.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
||||
import { fs } from '../utils/fs-utils.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
export class FileCacheAdapter {
|
||||
#VERSION = Utils.getORMVersion();
|
||||
#cache = {};
|
||||
#options;
|
||||
#baseDir;
|
||||
#pretty;
|
||||
constructor(options = {}, baseDir, pretty = false) {
|
||||
this.#options = options;
|
||||
this.#baseDir = baseDir;
|
||||
this.#pretty = pretty;
|
||||
this.#options.cacheDir ??= process.cwd() + '/temp';
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name) {
|
||||
const path = this.path(name);
|
||||
if (!existsSync(path)) {
|
||||
return null;
|
||||
}
|
||||
const payload = fs.readJSONSync(path);
|
||||
const hash = this.getHash(payload.origin);
|
||||
if (!hash || payload.hash !== hash) {
|
||||
return null;
|
||||
}
|
||||
return payload.data;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name, data, origin) {
|
||||
if (this.#options.combined) {
|
||||
this.#cache[name.replace(/\.[jt]s$/, '')] = data;
|
||||
return;
|
||||
}
|
||||
const path = this.path(name);
|
||||
const hash = this.getHash(origin);
|
||||
writeFileSync(
|
||||
path,
|
||||
JSON.stringify({ data, origin, hash, version: this.#VERSION }, null, this.#pretty ? 2 : undefined),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name) {
|
||||
const path = this.path(name);
|
||||
unlinkSync(path);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear() {
|
||||
const path = this.path('*');
|
||||
const files = fs.glob(path);
|
||||
for (const file of files) {
|
||||
/* v8 ignore next */
|
||||
try {
|
||||
unlinkSync(file);
|
||||
} catch {
|
||||
// ignore if file is already gone
|
||||
}
|
||||
}
|
||||
this.#cache = {};
|
||||
}
|
||||
combine() {
|
||||
if (!this.#options.combined) {
|
||||
return;
|
||||
}
|
||||
let path = typeof this.#options.combined === 'string' ? this.#options.combined : './metadata.json';
|
||||
path = fs.normalizePath(this.#options.cacheDir, path);
|
||||
this.#options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
|
||||
writeFileSync(path, JSON.stringify(this.#cache, null, this.#pretty ? 2 : undefined));
|
||||
return path;
|
||||
}
|
||||
path(name) {
|
||||
fs.ensureDir(this.#options.cacheDir);
|
||||
return `${this.#options.cacheDir}/${name}.json`;
|
||||
}
|
||||
getHash(origin) {
|
||||
origin = fs.absolutePath(origin, this.#baseDir);
|
||||
if (!existsSync(origin)) {
|
||||
return null;
|
||||
}
|
||||
const contents = readFileSync(origin);
|
||||
return Utils.hash(contents.toString() + this.#VERSION);
|
||||
}
|
||||
}
|
||||
23
node_modules/@mikro-orm/core/cache/GeneratedCacheAdapter.d.ts
generated
vendored
Normal file
23
node_modules/@mikro-orm/core/cache/GeneratedCacheAdapter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { CacheAdapter } from './CacheAdapter.js';
|
||||
import type { Dictionary } from '../typings.js';
|
||||
/** Cache adapter backed by pre-generated static data, typically produced by the CLI cache:generate command. */
|
||||
export declare class GeneratedCacheAdapter implements CacheAdapter {
|
||||
#private;
|
||||
constructor(options: { data: Dictionary });
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get<T = any>(name: string): T | undefined;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name: string, data: any, origin: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear(): void;
|
||||
}
|
||||
33
node_modules/@mikro-orm/core/cache/GeneratedCacheAdapter.js
generated
vendored
Normal file
33
node_modules/@mikro-orm/core/cache/GeneratedCacheAdapter.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/** Cache adapter backed by pre-generated static data, typically produced by the CLI cache:generate command. */
|
||||
export class GeneratedCacheAdapter {
|
||||
#data;
|
||||
constructor(options) {
|
||||
this.#data = new Map(Object.entries(options.data));
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name) {
|
||||
const key = name.replace(/\.[jt]s$/, '');
|
||||
const data = this.#data.get(key);
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name, data, origin) {
|
||||
this.#data.set(name, { data });
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name) {
|
||||
this.#data.delete(name);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear() {
|
||||
this.#data.clear();
|
||||
}
|
||||
}
|
||||
22
node_modules/@mikro-orm/core/cache/MemoryCacheAdapter.d.ts
generated
vendored
Normal file
22
node_modules/@mikro-orm/core/cache/MemoryCacheAdapter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { CacheAdapter } from './CacheAdapter.js';
|
||||
/** In-memory cache adapter with time-based expiration. Used as the default result cache. */
|
||||
export declare class MemoryCacheAdapter implements CacheAdapter {
|
||||
#private;
|
||||
constructor(options: { expiration: number });
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get<T = any>(name: string): T | undefined;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name: string, data: any, origin: string, expiration?: number): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear(): void;
|
||||
}
|
||||
40
node_modules/@mikro-orm/core/cache/MemoryCacheAdapter.js
generated
vendored
Normal file
40
node_modules/@mikro-orm/core/cache/MemoryCacheAdapter.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/** In-memory cache adapter with time-based expiration. Used as the default result cache. */
|
||||
export class MemoryCacheAdapter {
|
||||
#data = new Map();
|
||||
#options;
|
||||
constructor(options) {
|
||||
this.#options = options;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name) {
|
||||
const data = this.#data.get(name);
|
||||
if (data) {
|
||||
if (data.expiration < Date.now()) {
|
||||
this.#data.delete(name);
|
||||
} else {
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name, data, origin, expiration) {
|
||||
this.#data.set(name, { data, expiration: Date.now() + (expiration ?? this.#options.expiration) });
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name) {
|
||||
this.#data.delete(name);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear() {
|
||||
this.#data.clear();
|
||||
}
|
||||
}
|
||||
20
node_modules/@mikro-orm/core/cache/NullCacheAdapter.d.ts
generated
vendored
Normal file
20
node_modules/@mikro-orm/core/cache/NullCacheAdapter.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { SyncCacheAdapter } from './CacheAdapter.js';
|
||||
/** No-op cache adapter that never stores or returns any data. Used to disable caching. */
|
||||
export declare class NullCacheAdapter implements SyncCacheAdapter {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name: string): any;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name: string, data: any, origin: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name: string): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear(): void;
|
||||
}
|
||||
27
node_modules/@mikro-orm/core/cache/NullCacheAdapter.js
generated
vendored
Normal file
27
node_modules/@mikro-orm/core/cache/NullCacheAdapter.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/** No-op cache adapter that never stores or returns any data. Used to disable caching. */
|
||||
export class NullCacheAdapter {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
get(name) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
set(name, data, origin) {
|
||||
// ignore
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
remove(name) {
|
||||
// ignore
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
clear() {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
4
node_modules/@mikro-orm/core/cache/index.d.ts
generated
vendored
Normal file
4
node_modules/@mikro-orm/core/cache/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export type * from './CacheAdapter.js';
|
||||
export * from './NullCacheAdapter.js';
|
||||
export * from './MemoryCacheAdapter.js';
|
||||
export * from './GeneratedCacheAdapter.js';
|
||||
3
node_modules/@mikro-orm/core/cache/index.js
generated
vendored
Normal file
3
node_modules/@mikro-orm/core/cache/index.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './NullCacheAdapter.js';
|
||||
export * from './MemoryCacheAdapter.js';
|
||||
export * from './GeneratedCacheAdapter.js';
|
||||
117
node_modules/@mikro-orm/core/connections/Connection.d.ts
generated
vendored
Normal file
117
node_modules/@mikro-orm/core/connections/Connection.d.ts
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
import { type Configuration, type ConnectionOptions } from '../utils/Configuration.js';
|
||||
import type { LogContext, Logger } from '../logging/Logger.js';
|
||||
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
||||
import type { ConnectionType, Dictionary, MaybePromise, Primary } from '../typings.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
import type { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
|
||||
import type { IsolationLevel } from '../enums.js';
|
||||
/** Abstract base class for database connections, providing transaction and query execution support. */
|
||||
export declare abstract class Connection {
|
||||
#private;
|
||||
protected readonly config: Configuration;
|
||||
protected readonly type: ConnectionType;
|
||||
protected metadata: MetadataStorage;
|
||||
protected platform: Platform;
|
||||
protected readonly options: ConnectionOptions;
|
||||
protected readonly logger: Logger;
|
||||
protected connected: boolean;
|
||||
constructor(config: Configuration, options?: ConnectionOptions, type?: ConnectionType);
|
||||
/**
|
||||
* Establishes connection to database
|
||||
*/
|
||||
abstract connect(options?: { skipOnConnect?: boolean }): void | Promise<void>;
|
||||
/**
|
||||
* Are we connected to the database
|
||||
*/
|
||||
abstract isConnected(): Promise<boolean>;
|
||||
/**
|
||||
* Are we connected to the database
|
||||
*/
|
||||
abstract checkConnection(): Promise<
|
||||
| {
|
||||
ok: true;
|
||||
}
|
||||
| {
|
||||
ok: false;
|
||||
reason: string;
|
||||
error?: Error;
|
||||
}
|
||||
>;
|
||||
/**
|
||||
* Closes the database connection (aka disconnect)
|
||||
*/
|
||||
close(force?: boolean): Promise<void>;
|
||||
/**
|
||||
* Ensure the connection exists, this is used to support lazy connect when using `new MikroORM()` instead of the async `init` method.
|
||||
*/
|
||||
ensureConnection(): Promise<void>;
|
||||
/**
|
||||
* Execute raw SQL queries, handy from running schema dump loaded from a file.
|
||||
* This method doesn't support transactions, as opposed to `orm.schema.execute()`, which is used internally.
|
||||
*/
|
||||
executeDump(dump: string): Promise<void>;
|
||||
protected onConnect(): Promise<void>;
|
||||
/** Executes a callback inside a transaction, committing on success and rolling back on failure. */
|
||||
transactional<T>(
|
||||
cb: (trx: Transaction) => Promise<T>,
|
||||
options?: {
|
||||
isolationLevel?: IsolationLevel | `${IsolationLevel}`;
|
||||
readOnly?: boolean;
|
||||
ctx?: Transaction;
|
||||
eventBroadcaster?: TransactionEventBroadcaster;
|
||||
loggerContext?: LogContext;
|
||||
},
|
||||
): Promise<T>;
|
||||
/** Begins a new database transaction and returns the transaction context. */
|
||||
begin(options?: {
|
||||
isolationLevel?: IsolationLevel | `${IsolationLevel}`;
|
||||
readOnly?: boolean;
|
||||
ctx?: Transaction;
|
||||
eventBroadcaster?: TransactionEventBroadcaster;
|
||||
loggerContext?: LogContext;
|
||||
}): Promise<Transaction>;
|
||||
/** Commits the given transaction. */
|
||||
commit(ctx: Transaction, eventBroadcaster?: TransactionEventBroadcaster, loggerContext?: LogContext): Promise<void>;
|
||||
/** Rolls back the given transaction. */
|
||||
rollback(ctx: Transaction, eventBroadcaster?: TransactionEventBroadcaster, loggerContext?: LogContext): Promise<void>;
|
||||
/** Executes a raw query and returns the result. */
|
||||
abstract execute<T>(
|
||||
query: string,
|
||||
params?: any[],
|
||||
method?: 'all' | 'get' | 'run',
|
||||
ctx?: Transaction,
|
||||
): Promise<QueryResult<T> | any | any[]>;
|
||||
/** Parses and returns the resolved connection configuration (host, port, user, etc.). */
|
||||
getConnectionOptions(): ConnectionConfig;
|
||||
/** Sets the metadata storage on this connection. */
|
||||
setMetadata(metadata: MetadataStorage): void;
|
||||
/** Sets the platform abstraction on this connection. */
|
||||
setPlatform(platform: Platform): void;
|
||||
/** Returns the platform abstraction for this connection. */
|
||||
getPlatform(): Platform;
|
||||
protected executeQuery<T>(query: string, cb: () => Promise<T>, context?: LogContext): Promise<T>;
|
||||
protected logQuery(query: string, context?: LogContext): void;
|
||||
}
|
||||
/** Result of a native database query (insert, update, delete). */
|
||||
export interface QueryResult<
|
||||
T = {
|
||||
id: number;
|
||||
},
|
||||
> {
|
||||
affectedRows: number;
|
||||
insertId: Primary<T>;
|
||||
row?: Dictionary;
|
||||
rows?: Dictionary[];
|
||||
insertedIds?: Primary<T>[];
|
||||
}
|
||||
/** Resolved database connection parameters. */
|
||||
export interface ConnectionConfig {
|
||||
host?: string;
|
||||
port?: number;
|
||||
user?: string;
|
||||
password?: string | (() => MaybePromise<string>);
|
||||
database?: string;
|
||||
schema?: string;
|
||||
}
|
||||
/** Opaque transaction context type, wrapping the driver-specific transaction object. */
|
||||
export type Transaction<T = any> = T & {};
|
||||
169
node_modules/@mikro-orm/core/connections/Connection.js
generated
vendored
Normal file
169
node_modules/@mikro-orm/core/connections/Connection.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
/** Abstract base class for database connections, providing transaction and query execution support. */
|
||||
export class Connection {
|
||||
config;
|
||||
type;
|
||||
metadata;
|
||||
platform;
|
||||
options;
|
||||
logger;
|
||||
connected = false;
|
||||
get #connectionLabel() {
|
||||
return {
|
||||
type: this.type,
|
||||
name: this.options.name || this.config.get('name') || this.options.host || this.options.dbName,
|
||||
};
|
||||
}
|
||||
constructor(config, options, type = 'write') {
|
||||
this.config = config;
|
||||
this.type = type;
|
||||
this.logger = this.config.getLogger();
|
||||
this.platform = this.config.getPlatform();
|
||||
if (options) {
|
||||
this.options = Utils.copy(options);
|
||||
} else {
|
||||
const props = [
|
||||
'dbName',
|
||||
'clientUrl',
|
||||
'host',
|
||||
'port',
|
||||
'user',
|
||||
'password',
|
||||
'multipleStatements',
|
||||
'pool',
|
||||
'schema',
|
||||
'driverOptions',
|
||||
];
|
||||
this.options = props.reduce((o, i) => {
|
||||
o[i] = this.config.get(i);
|
||||
return o;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Closes the database connection (aka disconnect)
|
||||
*/
|
||||
async close(force) {
|
||||
Object.keys(this.options)
|
||||
.filter(k => k !== 'name')
|
||||
.forEach(k => delete this.options[k]);
|
||||
}
|
||||
/**
|
||||
* Ensure the connection exists, this is used to support lazy connect when using `new MikroORM()` instead of the async `init` method.
|
||||
*/
|
||||
async ensureConnection() {
|
||||
if (!this.connected) {
|
||||
await this.connect();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Execute raw SQL queries, handy from running schema dump loaded from a file.
|
||||
* This method doesn't support transactions, as opposed to `orm.schema.execute()`, which is used internally.
|
||||
*/
|
||||
async executeDump(dump) {
|
||||
throw new Error(`Executing SQL dumps is not supported by current driver`);
|
||||
}
|
||||
async onConnect() {
|
||||
const schemaGenerator = this.config.getExtension('@mikro-orm/schema-generator');
|
||||
if (this.type === 'write' && schemaGenerator) {
|
||||
if (this.config.get('ensureDatabase')) {
|
||||
const options = this.config.get('ensureDatabase');
|
||||
await schemaGenerator.ensureDatabase(typeof options === 'boolean' ? {} : { ...options, forceCheck: true });
|
||||
}
|
||||
if (this.config.get('ensureIndexes')) {
|
||||
await schemaGenerator.ensureIndexes();
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Executes a callback inside a transaction, committing on success and rolling back on failure. */
|
||||
async transactional(cb, options) {
|
||||
throw new Error(`Transactions are not supported by current driver`);
|
||||
}
|
||||
/** Begins a new database transaction and returns the transaction context. */
|
||||
async begin(options) {
|
||||
throw new Error(`Transactions are not supported by current driver`);
|
||||
}
|
||||
/** Commits the given transaction. */
|
||||
async commit(ctx, eventBroadcaster, loggerContext) {
|
||||
throw new Error(`Transactions are not supported by current driver`);
|
||||
}
|
||||
/** Rolls back the given transaction. */
|
||||
async rollback(ctx, eventBroadcaster, loggerContext) {
|
||||
throw new Error(`Transactions are not supported by current driver`);
|
||||
}
|
||||
/** Parses and returns the resolved connection configuration (host, port, user, etc.). */
|
||||
getConnectionOptions() {
|
||||
const ret = {};
|
||||
if (this.options.clientUrl) {
|
||||
const url = new URL(this.options.clientUrl);
|
||||
this.options.host = ret.host = this.options.host ?? decodeURIComponent(url.hostname);
|
||||
this.options.port = ret.port = this.options.port ?? +url.port;
|
||||
this.options.user = ret.user = this.options.user ?? decodeURIComponent(url.username);
|
||||
this.options.password = ret.password = this.options.password ?? decodeURIComponent(url.password);
|
||||
this.options.dbName = ret.database = this.options.dbName ?? decodeURIComponent(url.pathname).replace(/^\//, '');
|
||||
if (this.options.schema || url.searchParams.has('schema')) {
|
||||
this.options.schema = ret.schema = this.options.schema ?? decodeURIComponent(url.searchParams.get('schema'));
|
||||
this.config.set('schema', ret.schema);
|
||||
}
|
||||
} else {
|
||||
const url = new URL(this.config.get('clientUrl'));
|
||||
this.options.host = ret.host = this.options.host ?? this.config.get('host', decodeURIComponent(url.hostname));
|
||||
this.options.port = ret.port = this.options.port ?? this.config.get('port', +url.port);
|
||||
this.options.user = ret.user = this.options.user ?? this.config.get('user', decodeURIComponent(url.username));
|
||||
this.options.password = ret.password =
|
||||
this.options.password ?? this.config.get('password', decodeURIComponent(url.password));
|
||||
this.options.dbName = ret.database =
|
||||
this.options.dbName ?? this.config.get('dbName', decodeURIComponent(url.pathname).replace(/^\//, ''));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/** Sets the metadata storage on this connection. */
|
||||
setMetadata(metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
/** Sets the platform abstraction on this connection. */
|
||||
setPlatform(platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
/** Returns the platform abstraction for this connection. */
|
||||
getPlatform() {
|
||||
return this.platform;
|
||||
}
|
||||
async executeQuery(query, cb, context) {
|
||||
const now = Date.now();
|
||||
try {
|
||||
const res = await cb();
|
||||
const took = Date.now() - now;
|
||||
const results = Array.isArray(res) ? res.length : undefined;
|
||||
const affected = Utils.isPlainObject(res) ? res.affectedRows : undefined;
|
||||
this.logQuery(query, { ...context, took, results, affected });
|
||||
return res;
|
||||
} catch (e) {
|
||||
const took = Date.now() - now;
|
||||
this.logQuery(query, { ...context, took, level: 'error' });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
logQuery(query, context = {}) {
|
||||
const connection = this.#connectionLabel;
|
||||
this.logger.logQuery({
|
||||
level: 'info',
|
||||
connection,
|
||||
...context,
|
||||
query,
|
||||
});
|
||||
const threshold = this.config.get('slowQueryThreshold');
|
||||
if (threshold != null && (context.took ?? 0) >= threshold) {
|
||||
this.config.getSlowQueryLogger().logQuery({
|
||||
...context,
|
||||
// `enabled: true` bypasses the debug-mode check in isEnabled(),
|
||||
// ensuring slow query logs are always emitted regardless of the `debug` setting.
|
||||
enabled: true,
|
||||
level: context.level ?? 'warning',
|
||||
namespace: 'slow-query',
|
||||
connection,
|
||||
query,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
1
node_modules/@mikro-orm/core/connections/index.d.ts
generated
vendored
Normal file
1
node_modules/@mikro-orm/core/connections/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Connection.js';
|
||||
1
node_modules/@mikro-orm/core/connections/index.js
generated
vendored
Normal file
1
node_modules/@mikro-orm/core/connections/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Connection.js';
|
||||
199
node_modules/@mikro-orm/core/drivers/DatabaseDriver.d.ts
generated
vendored
Normal file
199
node_modules/@mikro-orm/core/drivers/DatabaseDriver.d.ts
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
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';
|
||||
import type {
|
||||
ConnectionType,
|
||||
Constructor,
|
||||
Dictionary,
|
||||
EntityData,
|
||||
EntityDictionary,
|
||||
EntityMetadata,
|
||||
EntityName,
|
||||
EntityProperty,
|
||||
FilterQuery,
|
||||
PopulateOptions,
|
||||
Primary,
|
||||
} from '../typings.js';
|
||||
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
||||
import type { Connection, QueryResult, Transaction } from '../connections/Connection.js';
|
||||
import { type Configuration, type ConnectionOptions } from '../utils/Configuration.js';
|
||||
import { EntityComparator } from '../utils/EntityComparator.js';
|
||||
import { type QueryOrder } from '../enums.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
import type { Collection } from '../entity/Collection.js';
|
||||
import { EntityManager } from '../EntityManager.js';
|
||||
import { DriverException } from '../exceptions.js';
|
||||
import { MikroORM } from '../MikroORM.js';
|
||||
/** Abstract base class for all database drivers, implementing common driver logic. */
|
||||
export declare abstract class DatabaseDriver<C extends Connection> implements IDatabaseDriver<C> {
|
||||
readonly config: Configuration;
|
||||
protected readonly dependencies: string[];
|
||||
[EntityManagerType]: EntityManager<this>;
|
||||
protected readonly connection: C;
|
||||
protected readonly replicas: C[];
|
||||
protected readonly platform: Platform;
|
||||
protected comparator: EntityComparator;
|
||||
protected metadata: MetadataStorage;
|
||||
protected constructor(config: Configuration, dependencies: string[]);
|
||||
abstract find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: FindOptions<T, P, F, E>,
|
||||
): Promise<EntityData<T>[]>;
|
||||
abstract findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: FindOneOptions<T, P, F, E>,
|
||||
): Promise<EntityData<T> | null>;
|
||||
abstract nativeInsert<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityDictionary<T>,
|
||||
options?: NativeInsertUpdateOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
abstract nativeInsertMany<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityDictionary<T>[],
|
||||
options?: NativeInsertUpdateManyOptions<T>,
|
||||
transform?: (sql: string) => string,
|
||||
): Promise<QueryResult<T>>;
|
||||
abstract nativeUpdate<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
data: EntityDictionary<T>,
|
||||
options?: NativeInsertUpdateOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
nativeUpdateMany<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>[],
|
||||
data: EntityDictionary<T>[],
|
||||
options?: NativeInsertUpdateManyOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
abstract nativeDelete<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: DeleteOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
abstract count<T extends object, P extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: CountOptions<T, P>,
|
||||
): Promise<number>;
|
||||
/** Creates a new EntityManager instance bound to this driver. */
|
||||
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
||||
findVirtual<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options: FindOptions<T, any, any, any>,
|
||||
): Promise<EntityData<T>[]>;
|
||||
countVirtual<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options: CountOptions<T, any>,
|
||||
): Promise<number>;
|
||||
aggregate(entityName: EntityName, pipeline: any[]): Promise<any[]>;
|
||||
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[]>>;
|
||||
syncCollections<T extends object, O extends object>(
|
||||
collections: Iterable<Collection<T, O>>,
|
||||
options?: DriverMethodOptions,
|
||||
): Promise<void>;
|
||||
/** Maps raw database result to entity data, converting column names to property names. */
|
||||
mapResult<T extends object>(
|
||||
result: EntityDictionary<T>,
|
||||
meta?: EntityMetadata<T>,
|
||||
populate?: PopulateOptions<T>[],
|
||||
): EntityData<T> | null;
|
||||
/** Opens the primary connection and all read replicas. */
|
||||
connect(options?: { skipOnConnect?: boolean }): Promise<C>;
|
||||
/** Closes all connections and re-establishes them. */
|
||||
reconnect(options?: { skipOnConnect?: boolean }): Promise<C>;
|
||||
/** Returns the write connection or a random read replica. */
|
||||
getConnection(type?: ConnectionType): C;
|
||||
/** Closes the primary connection and all read replicas. */
|
||||
close(force?: boolean): Promise<void>;
|
||||
/** Returns the database platform abstraction for this driver. */
|
||||
getPlatform(): Platform;
|
||||
/** Sets the metadata storage and initializes the comparator for all connections. */
|
||||
setMetadata(metadata: MetadataStorage): void;
|
||||
/** Returns the metadata storage used by this driver. */
|
||||
getMetadata(): MetadataStorage;
|
||||
/** Returns the names of native database dependencies required by this driver. */
|
||||
getDependencies(): string[];
|
||||
protected isPopulated<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
prop: EntityProperty<T>,
|
||||
hint: PopulateOptions<T>,
|
||||
name?: string,
|
||||
): boolean;
|
||||
protected processCursorOptions<T extends object, P extends string>(
|
||||
meta: EntityMetadata<T>,
|
||||
options: FindOptions<T, P, any, any>,
|
||||
orderBy: OrderDefinition<T>,
|
||||
): {
|
||||
orderBy: OrderDefinition<T>[];
|
||||
where: FilterQuery<T>;
|
||||
};
|
||||
protected createCursorCondition<T extends object>(
|
||||
definition: (readonly [keyof T & string, QueryOrder])[],
|
||||
offsets: Dictionary[],
|
||||
inverse: boolean,
|
||||
meta: EntityMetadata<T>,
|
||||
): FilterQuery<T>;
|
||||
/** @internal */
|
||||
mapDataToFieldNames(
|
||||
data: Dictionary,
|
||||
stringifyJsonArrays: boolean,
|
||||
properties?: Record<string, EntityProperty>,
|
||||
convertCustomTypes?: boolean,
|
||||
object?: boolean,
|
||||
): Dictionary;
|
||||
protected inlineEmbeddables<T extends object>(meta: EntityMetadata<T>, data: T, where?: boolean): void;
|
||||
protected getPrimaryKeyFields<T>(meta: EntityMetadata<T>): string[];
|
||||
protected createReplicas(cb: (c: ConnectionOptions) => C): C[];
|
||||
/** Acquires a pessimistic lock on the given entity. */
|
||||
lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
|
||||
abstract stream<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options: StreamOptions<T>,
|
||||
): AsyncIterableIterator<T>;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
convertException(exception: Error): DriverException;
|
||||
protected rethrow<T>(promise: Promise<T>): Promise<T>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getTableName<T>(meta: EntityMetadata<T>, options: NativeInsertUpdateManyOptions<T>, quote?: boolean): string;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getSchemaName(
|
||||
meta?: EntityMetadata,
|
||||
options?: {
|
||||
schema?: string;
|
||||
parentSchema?: string;
|
||||
},
|
||||
): string | undefined;
|
||||
/** @internal */
|
||||
getORMClass(): Constructor<MikroORM>;
|
||||
}
|
||||
493
node_modules/@mikro-orm/core/drivers/DatabaseDriver.js
generated
vendored
Normal file
493
node_modules/@mikro-orm/core/drivers/DatabaseDriver.js
generated
vendored
Normal file
@@ -0,0 +1,493 @@
|
||||
import { EntityManagerType } from './IDatabaseDriver.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { Cursor } from '../utils/Cursor.js';
|
||||
import { EntityComparator } from '../utils/EntityComparator.js';
|
||||
import { isRaw, raw } from '../utils/RawQueryFragment.js';
|
||||
import { QueryOrderNumeric, ReferenceKind } from '../enums.js';
|
||||
import { EntityManager } from '../EntityManager.js';
|
||||
import { CursorError, ValidationError } from '../errors.js';
|
||||
import { DriverException } from '../exceptions.js';
|
||||
import { helper } from '../entity/wrap.js';
|
||||
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
||||
import { JsonType } from '../types/JsonType.js';
|
||||
import { MikroORM } from '../MikroORM.js';
|
||||
/** Abstract base class for all database drivers, implementing common driver logic. */
|
||||
export class DatabaseDriver {
|
||||
config;
|
||||
dependencies;
|
||||
[EntityManagerType];
|
||||
connection;
|
||||
replicas = [];
|
||||
platform;
|
||||
comparator;
|
||||
metadata;
|
||||
constructor(config, dependencies) {
|
||||
this.config = config;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
async nativeUpdateMany(entityName, where, data, options) {
|
||||
throw new Error(`Batch updates are not supported by ${this.constructor.name} driver`);
|
||||
}
|
||||
/** Creates a new EntityManager instance bound to this driver. */
|
||||
createEntityManager(useContext) {
|
||||
const EntityManagerClass = this.config.get('entityManager', EntityManager);
|
||||
return new EntityManagerClass(this.config, this, this.metadata, useContext);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
async findVirtual(entityName, where, options) {
|
||||
throw new Error(`Virtual entities are not supported by ${this.constructor.name} driver.`);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
async countVirtual(entityName, where, options) {
|
||||
throw new Error(`Counting virtual entities is not supported by ${this.constructor.name} driver.`);
|
||||
}
|
||||
async aggregate(entityName, pipeline) {
|
||||
throw new Error(`Aggregations are not supported by ${this.constructor.name} driver`);
|
||||
}
|
||||
async loadFromPivotTable(prop, owners, where, orderBy, ctx, options, pivotJoin) {
|
||||
throw new Error(`${this.constructor.name} does not use pivot tables`);
|
||||
}
|
||||
async syncCollections(collections, options) {
|
||||
for (const coll of collections) {
|
||||
/* v8 ignore else */
|
||||
if (!coll.property.owner) {
|
||||
if (coll.getSnapshot() === undefined) {
|
||||
throw ValidationError.cannotModifyInverseCollection(coll.owner, coll.property);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* v8 ignore next */
|
||||
{
|
||||
const pk = coll.property.targetMeta.primaryKeys[0];
|
||||
const data = { [coll.property.name]: coll.getIdentifiers(pk) };
|
||||
await this.nativeUpdate(coll.owner.constructor, helper(coll.owner).getPrimaryKey(), data, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Maps raw database result to entity data, converting column names to property names. */
|
||||
mapResult(result, meta, populate = []) {
|
||||
if (!result || !meta) {
|
||||
return result ?? null;
|
||||
}
|
||||
return this.comparator.mapResult(meta, result);
|
||||
}
|
||||
/** Opens the primary connection and all read replicas. */
|
||||
async connect(options) {
|
||||
await this.connection.connect(options);
|
||||
await Promise.all(this.replicas.map(replica => replica.connect()));
|
||||
return this.connection;
|
||||
}
|
||||
/** Closes all connections and re-establishes them. */
|
||||
async reconnect(options) {
|
||||
await this.close(true);
|
||||
await this.connect(options);
|
||||
return this.connection;
|
||||
}
|
||||
/** Returns the write connection or a random read replica. */
|
||||
getConnection(type = 'write') {
|
||||
if (type === 'write' || this.replicas.length === 0) {
|
||||
return this.connection;
|
||||
}
|
||||
const rand = Utils.randomInt(0, this.replicas.length - 1);
|
||||
return this.replicas[rand];
|
||||
}
|
||||
/** Closes the primary connection and all read replicas. */
|
||||
async close(force) {
|
||||
await Promise.all(this.replicas.map(replica => replica.close(force)));
|
||||
await this.connection.close(force);
|
||||
}
|
||||
/** Returns the database platform abstraction for this driver. */
|
||||
getPlatform() {
|
||||
return this.platform;
|
||||
}
|
||||
/** Sets the metadata storage and initializes the comparator for all connections. */
|
||||
setMetadata(metadata) {
|
||||
this.metadata = metadata;
|
||||
this.comparator = new EntityComparator(this.metadata, this.platform);
|
||||
this.connection.setMetadata(metadata);
|
||||
this.connection.setPlatform(this.platform);
|
||||
this.replicas.forEach(replica => {
|
||||
replica.setMetadata(metadata);
|
||||
replica.setPlatform(this.platform);
|
||||
});
|
||||
}
|
||||
/** Returns the metadata storage used by this driver. */
|
||||
getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
/** Returns the names of native database dependencies required by this driver. */
|
||||
getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
isPopulated(meta, prop, hint, name) {
|
||||
if (hint.field === prop.name || hint.field === name || hint.all) {
|
||||
return true;
|
||||
}
|
||||
if (prop.embedded && hint.children && meta.properties[prop.embedded[0]].name === hint.field) {
|
||||
return hint.children.some(c => this.isPopulated(meta, prop, c, prop.embedded[1]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
processCursorOptions(meta, options, orderBy) {
|
||||
const { first, last, before, after, overfetch } = options;
|
||||
const limit = first ?? last;
|
||||
const isLast = !first && !!last;
|
||||
const definition = Cursor.getDefinition(meta, orderBy);
|
||||
const $and = [];
|
||||
// allow POJO as well, we care only about the correct key being present
|
||||
const isCursor = (val, key) => {
|
||||
return !!val && typeof val === 'object' && key in val;
|
||||
};
|
||||
const createCursor = (val, key, inverse = false) => {
|
||||
let def = isCursor(val, key) ? val[key] : val;
|
||||
if (Utils.isPlainObject(def)) {
|
||||
def = Cursor.for(meta, def, orderBy);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
const offsets = def ? Cursor.decode(def) : [];
|
||||
if (definition.length === offsets.length) {
|
||||
return this.createCursorCondition(definition, offsets, inverse, meta);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return {};
|
||||
};
|
||||
if (after) {
|
||||
$and.push(createCursor(after, 'endCursor'));
|
||||
}
|
||||
if (before) {
|
||||
$and.push(createCursor(before, 'startCursor', true));
|
||||
}
|
||||
if (limit != null) {
|
||||
options.limit = limit + (overfetch ? 1 : 0);
|
||||
}
|
||||
const createOrderBy = (prop, direction) => {
|
||||
if (Utils.isPlainObject(direction)) {
|
||||
const value = Utils.getObjectQueryKeys(direction).reduce((o, key) => {
|
||||
Object.assign(o, createOrderBy(key, direction[key]));
|
||||
return o;
|
||||
}, {});
|
||||
return { [prop]: value };
|
||||
}
|
||||
const desc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
||||
const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
|
||||
return { [prop]: dir };
|
||||
};
|
||||
return {
|
||||
orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
|
||||
where: $and.length > 1 ? { $and } : { ...$and[0] },
|
||||
};
|
||||
}
|
||||
createCursorCondition(definition, offsets, inverse, meta) {
|
||||
const createCondition = (prop, direction, offset, eq = false, path = prop) => {
|
||||
if (Utils.isPlainObject(direction)) {
|
||||
if (offset === undefined) {
|
||||
throw CursorError.missingValue(meta.className, path);
|
||||
}
|
||||
const value = Utils.keys(direction).reduce((o, key) => {
|
||||
Object.assign(o, createCondition(key, direction[key], offset?.[key], eq, `${path}.${key}`));
|
||||
return o;
|
||||
}, {});
|
||||
return { [prop]: value };
|
||||
}
|
||||
const isDesc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
||||
const dirStr = direction.toString().toLowerCase();
|
||||
let nullsFirst;
|
||||
if (dirStr.includes('nulls first')) {
|
||||
nullsFirst = true;
|
||||
} else if (dirStr.includes('nulls last')) {
|
||||
nullsFirst = false;
|
||||
} else {
|
||||
// Default: NULLS LAST for ASC, NULLS FIRST for DESC (matches most databases)
|
||||
nullsFirst = isDesc;
|
||||
}
|
||||
const operator = Utils.xor(isDesc, inverse) ? '$lt' : '$gt';
|
||||
// For leaf-level properties, undefined means missing value
|
||||
if (offset === undefined) {
|
||||
throw CursorError.missingValue(meta.className, path);
|
||||
}
|
||||
// Handle null offset (intentional null cursor value)
|
||||
if (offset === null) {
|
||||
if (eq) {
|
||||
// Equal to null
|
||||
return { [prop]: null };
|
||||
}
|
||||
// Strict comparison with null cursor value
|
||||
// hasItemsAfterNull: forward + nullsFirst, or backward + nullsLast
|
||||
const hasItemsAfterNull = Utils.xor(nullsFirst, inverse);
|
||||
if (hasItemsAfterNull) {
|
||||
return { [prop]: { $ne: null } };
|
||||
}
|
||||
// No items after null in this direction, return impossible condition
|
||||
return { [prop]: [] };
|
||||
}
|
||||
// Non-null offset
|
||||
return { [prop]: { [operator + (eq ? 'e' : '')]: offset } };
|
||||
};
|
||||
const [order, ...otherOrders] = definition;
|
||||
const [offset, ...otherOffsets] = offsets;
|
||||
const [prop, direction] = order;
|
||||
if (!otherOrders.length) {
|
||||
return createCondition(prop, direction, offset);
|
||||
}
|
||||
return {
|
||||
...createCondition(prop, direction, offset, true),
|
||||
$or: [
|
||||
createCondition(prop, direction, offset),
|
||||
this.createCursorCondition(otherOrders, otherOffsets, inverse, meta),
|
||||
],
|
||||
};
|
||||
}
|
||||
/** @internal */
|
||||
mapDataToFieldNames(data, stringifyJsonArrays, properties, convertCustomTypes, object) {
|
||||
if (!properties || data == null) {
|
||||
return data;
|
||||
}
|
||||
data = Object.assign({}, data); // copy first
|
||||
Object.keys(data).forEach(k => {
|
||||
const prop = properties[k];
|
||||
if (!prop) {
|
||||
return;
|
||||
}
|
||||
if (prop.embeddedProps && !prop.object && !object) {
|
||||
const copy = data[k];
|
||||
delete data[k];
|
||||
Object.assign(
|
||||
data,
|
||||
this.mapDataToFieldNames(copy, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (prop.embeddedProps && (object || prop.object)) {
|
||||
const copy = data[k];
|
||||
delete data[k];
|
||||
if (prop.array) {
|
||||
data[prop.fieldNames[0]] = copy?.map(item =>
|
||||
this.mapDataToFieldNames(item, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes, true),
|
||||
);
|
||||
} else {
|
||||
data[prop.fieldNames[0]] = this.mapDataToFieldNames(
|
||||
copy,
|
||||
stringifyJsonArrays,
|
||||
prop.embeddedProps,
|
||||
convertCustomTypes,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if (stringifyJsonArrays && prop.array && !object) {
|
||||
data[prop.fieldNames[0]] = this.platform.convertJsonToDatabaseValue(data[prop.fieldNames[0]]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Handle polymorphic relations - convert tuple or PolymorphicRef to separate columns
|
||||
// Tuple format: ['discriminator', id] or ['discriminator', id1, id2] for composite keys
|
||||
// Must be checked BEFORE joinColumns array handling since polymorphic uses fieldNames (includes discriminator)
|
||||
if (prop.polymorphic && prop.fieldNames && prop.fieldNames.length >= 2) {
|
||||
let discriminator;
|
||||
let ids;
|
||||
if (Array.isArray(data[k]) && typeof data[k][0] === 'string' && prop.discriminatorMap?.[data[k][0]]) {
|
||||
// Tuple format: ['discriminator', ...ids]
|
||||
const [disc, ...rest] = data[k];
|
||||
discriminator = disc;
|
||||
ids = rest;
|
||||
} else if (data[k] instanceof PolymorphicRef) {
|
||||
// PolymorphicRef wrapper (internal use)
|
||||
discriminator = data[k].discriminator;
|
||||
const polyId = data[k].id;
|
||||
// Handle object-style composite key IDs like { tenantId: 1, orgId: 100 }
|
||||
if (polyId && typeof polyId === 'object' && !Array.isArray(polyId)) {
|
||||
const targetEntity = prop.discriminatorMap?.[discriminator];
|
||||
const targetMeta = this.metadata.get(targetEntity);
|
||||
ids = targetMeta.primaryKeys.map(pk => polyId[pk]);
|
||||
} else {
|
||||
ids = Utils.asArray(polyId);
|
||||
}
|
||||
}
|
||||
if (discriminator) {
|
||||
const discriminatorColumn = prop.fieldNames[0];
|
||||
const idColumns = prop.fieldNames.slice(1);
|
||||
delete data[k];
|
||||
data[discriminatorColumn] = discriminator;
|
||||
idColumns.forEach((col, idx) => {
|
||||
data[col] = ids[idx];
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (prop.joinColumns && Array.isArray(data[k])) {
|
||||
const copy = Utils.flatten(data[k]);
|
||||
delete data[k];
|
||||
prop.joinColumns.forEach((joinColumn, idx) => (data[joinColumn] = copy[idx]));
|
||||
return;
|
||||
}
|
||||
if (prop.joinColumns?.length > 1 && data[k] == null) {
|
||||
delete data[k];
|
||||
prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
|
||||
return;
|
||||
}
|
||||
if (
|
||||
prop.customType &&
|
||||
convertCustomTypes &&
|
||||
!(prop.customType instanceof JsonType && object) &&
|
||||
!isRaw(data[k])
|
||||
) {
|
||||
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
|
||||
fromQuery: true,
|
||||
key: k,
|
||||
mode: 'query-data',
|
||||
});
|
||||
}
|
||||
if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
|
||||
const quoted = this.platform.quoteValue(data[k]);
|
||||
const sql = prop.customType.convertToDatabaseValueSQL(quoted, this.platform);
|
||||
data[k] = raw(sql.replace(/\?/g, '\\?'));
|
||||
}
|
||||
if (prop.fieldNames) {
|
||||
Utils.renameKey(data, k, prop.fieldNames[0]);
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
inlineEmbeddables(meta, data, where) {
|
||||
/* v8 ignore next */
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
Utils.keys(data).forEach(k => {
|
||||
if (Utils.isOperator(k)) {
|
||||
Utils.asArray(data[k]).forEach(payload => this.inlineEmbeddables(meta, payload, where));
|
||||
}
|
||||
});
|
||||
meta.props.forEach(prop => {
|
||||
if (prop.kind === ReferenceKind.EMBEDDED && prop.object && !where && Utils.isObject(data[prop.name])) {
|
||||
return;
|
||||
}
|
||||
if (prop.kind === ReferenceKind.EMBEDDED && Utils.isObject(data[prop.name])) {
|
||||
const props = prop.embeddedProps;
|
||||
let unknownProp = false;
|
||||
Object.keys(data[prop.name]).forEach(kk => {
|
||||
// explicitly allow `$exists`, `$eq`, `$ne` and `$elemMatch` operators here as they can't be misused this way
|
||||
const operator = Object.keys(data[prop.name]).some(
|
||||
f => Utils.isOperator(f) && !['$exists', '$ne', '$eq', '$elemMatch'].includes(f),
|
||||
);
|
||||
if (operator) {
|
||||
throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.class, prop.name, data);
|
||||
}
|
||||
if (prop.object && where) {
|
||||
const inline = (payload, sub, path) => {
|
||||
if (sub.kind === ReferenceKind.EMBEDDED && Utils.isObject(payload[sub.embedded[1]])) {
|
||||
return Object.keys(payload[sub.embedded[1]]).forEach(kkk => {
|
||||
if (!sub.embeddedProps[kkk]) {
|
||||
throw ValidationError.invalidEmbeddableQuery(meta.class, kkk, sub.type);
|
||||
}
|
||||
inline(payload[sub.embedded[1]], sub.embeddedProps[kkk], [...path, sub.fieldNames[0]]);
|
||||
});
|
||||
}
|
||||
data[`${path.join('.')}.${sub.fieldNames[0]}`] = payload[sub.embedded[1]];
|
||||
};
|
||||
const parentPropName = kk.substring(0, kk.indexOf('.'));
|
||||
// we might be using some native JSON operator, e.g. with mongodb's `$geoWithin` or `$exists`
|
||||
if (props[kk]) {
|
||||
/* v8 ignore next */
|
||||
inline(data[prop.name], props[kk] || props[parentPropName], [prop.fieldNames[0]]);
|
||||
} else if (props[parentPropName]) {
|
||||
data[`${prop.fieldNames[0]}.${kk}`] = data[prop.name][kk];
|
||||
} else {
|
||||
unknownProp = true;
|
||||
}
|
||||
} else if (props[kk]) {
|
||||
data[props[kk].fieldNames[0]] = data[prop.name][props[kk].embedded[1]];
|
||||
} else {
|
||||
throw ValidationError.invalidEmbeddableQuery(meta.class, kk, prop.type);
|
||||
}
|
||||
});
|
||||
if (!unknownProp) {
|
||||
delete data[prop.name];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
getPrimaryKeyFields(meta) {
|
||||
return meta.getPrimaryProps().flatMap(pk => pk.fieldNames);
|
||||
}
|
||||
createReplicas(cb) {
|
||||
const replicas = this.config.get('replicas', []);
|
||||
const ret = [];
|
||||
const props = [
|
||||
'dbName',
|
||||
'clientUrl',
|
||||
'host',
|
||||
'port',
|
||||
'user',
|
||||
'password',
|
||||
'multipleStatements',
|
||||
'pool',
|
||||
'name',
|
||||
'driverOptions',
|
||||
];
|
||||
for (const conf of replicas) {
|
||||
const replicaConfig = Utils.copy(conf);
|
||||
for (const prop of props) {
|
||||
if (conf[prop]) {
|
||||
continue;
|
||||
}
|
||||
// do not copy options that can be inferred from explicitly provided `clientUrl`
|
||||
if (conf.clientUrl && ['clientUrl', 'host', 'port', 'user', 'password'].includes(prop)) {
|
||||
continue;
|
||||
}
|
||||
if (conf.clientUrl && prop === 'dbName' && new URL(conf.clientUrl).pathname) {
|
||||
continue;
|
||||
}
|
||||
replicaConfig[prop] = this.config.get(prop);
|
||||
}
|
||||
ret.push(cb(replicaConfig));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/** Acquires a pessimistic lock on the given entity. */
|
||||
async lockPessimistic(entity, options) {
|
||||
throw new Error(`Pessimistic locks are not supported by ${this.constructor.name} driver`);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
convertException(exception) {
|
||||
if (exception instanceof DriverException) {
|
||||
return exception;
|
||||
}
|
||||
return this.platform.getExceptionConverter().convertException(exception);
|
||||
}
|
||||
rethrow(promise) {
|
||||
return promise.catch(e => {
|
||||
throw this.convertException(e);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getTableName(meta, options, quote = true) {
|
||||
const schema = this.getSchemaName(meta, options);
|
||||
const tableName =
|
||||
schema && schema !== this.platform.getDefaultSchemaName() ? `${schema}.${meta.tableName}` : meta.tableName;
|
||||
if (quote) {
|
||||
return this.platform.quoteIdentifier(tableName);
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getSchemaName(meta, options) {
|
||||
if (meta?.schema && meta.schema !== '*') {
|
||||
return meta.schema;
|
||||
}
|
||||
if (options?.schema === '*') {
|
||||
return this.config.get('schema');
|
||||
}
|
||||
const schemaName = meta?.schema === '*' ? this.config.getSchema() : meta?.schema;
|
||||
return options?.schema ?? options?.parentSchema ?? schemaName ?? this.config.getSchema();
|
||||
}
|
||||
/** @internal */
|
||||
getORMClass() {
|
||||
return MikroORM;
|
||||
}
|
||||
}
|
||||
511
node_modules/@mikro-orm/core/drivers/IDatabaseDriver.d.ts
generated
vendored
Normal file
511
node_modules/@mikro-orm/core/drivers/IDatabaseDriver.d.ts
generated
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
import type {
|
||||
ConnectionType,
|
||||
Constructor,
|
||||
EntityData,
|
||||
EntityMetadata,
|
||||
EntityProperty,
|
||||
FilterQuery,
|
||||
Primary,
|
||||
Dictionary,
|
||||
IPrimaryKey,
|
||||
PopulateOptions,
|
||||
EntityDictionary,
|
||||
AutoPath,
|
||||
ObjectQuery,
|
||||
FilterObject,
|
||||
Populate,
|
||||
EntityName,
|
||||
PopulateHintOptions,
|
||||
Prefixes,
|
||||
} from '../typings.js';
|
||||
import type { Connection, QueryResult, Transaction } from '../connections/Connection.js';
|
||||
import type {
|
||||
FlushMode,
|
||||
LockMode,
|
||||
QueryOrderMap,
|
||||
QueryFlag,
|
||||
LoadStrategy,
|
||||
PopulateHint,
|
||||
PopulatePath,
|
||||
} from '../enums.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
||||
import type { Collection } from '../entity/Collection.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type { DriverException } from '../exceptions.js';
|
||||
import type { Configuration } from '../utils/Configuration.js';
|
||||
import type { MikroORM } from '../MikroORM.js';
|
||||
import type { LoggingOptions, LogContext } from '../logging/Logger.js';
|
||||
import type { Raw } from '../utils/RawQueryFragment.js';
|
||||
/** Symbol used to extract the EntityManager type from a driver instance. */
|
||||
export declare const EntityManagerType: unique symbol;
|
||||
/** Interface defining the contract for all database drivers. */
|
||||
export interface IDatabaseDriver<C extends Connection = Connection> {
|
||||
[EntityManagerType]: EntityManager<this>;
|
||||
readonly config: Configuration;
|
||||
/** Creates a new EntityManager instance for this driver. */
|
||||
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
||||
/** Opens a connection to the database. */
|
||||
connect(options?: { skipOnConnect?: boolean }): Promise<C>;
|
||||
/** Closes the database connection. */
|
||||
close(force?: boolean): Promise<void>;
|
||||
/** Closes and re-establishes the database connection. */
|
||||
reconnect(options?: { skipOnConnect?: boolean }): Promise<C>;
|
||||
/** Returns the underlying database connection (write or read replica). */
|
||||
getConnection(type?: ConnectionType): C;
|
||||
/**
|
||||
* Finds selection of entities
|
||||
*/
|
||||
find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: FindOptions<T, P, F, E>,
|
||||
): Promise<EntityData<T>[]>;
|
||||
/**
|
||||
* Finds single entity (table row, document)
|
||||
*/
|
||||
findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: FindOneOptions<T, P, F, E>,
|
||||
): Promise<EntityData<T> | null>;
|
||||
/** Finds entities backed by a virtual (expression-based) definition. */
|
||||
findVirtual<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options: FindOptions<T, any, any, any>,
|
||||
): Promise<EntityData<T>[]>;
|
||||
/** Returns an async iterator that streams query results one entity at a time. */
|
||||
stream<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options: StreamOptions<T>,
|
||||
): AsyncIterableIterator<T>;
|
||||
/** Inserts a single row into the database. */
|
||||
nativeInsert<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityDictionary<T>,
|
||||
options?: NativeInsertUpdateOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
/** Inserts multiple rows into the database in a single batch operation. */
|
||||
nativeInsertMany<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityDictionary<T>[],
|
||||
options?: NativeInsertUpdateManyOptions<T>,
|
||||
transform?: (sql: string) => string,
|
||||
): Promise<QueryResult<T>>;
|
||||
/** Updates rows matching the given condition. */
|
||||
nativeUpdate<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
data: EntityDictionary<T>,
|
||||
options?: NativeInsertUpdateOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
/** Updates multiple rows with different payloads in a single batch operation. */
|
||||
nativeUpdateMany<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>[],
|
||||
data: EntityDictionary<T>[],
|
||||
options?: NativeInsertUpdateManyOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
/** Deletes rows matching the given condition. */
|
||||
nativeDelete<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: NativeDeleteOptions<T>,
|
||||
): Promise<QueryResult<T>>;
|
||||
/** Persists changes to M:N collections (inserts/deletes pivot table rows). */
|
||||
syncCollections<T extends object, O extends object>(
|
||||
collections: Iterable<Collection<T, O>>,
|
||||
options?: DriverMethodOptions,
|
||||
): Promise<void>;
|
||||
/** Counts entities matching the given condition. */
|
||||
count<T extends object, P extends string = never>(
|
||||
entityName: EntityName<T>,
|
||||
where: FilterQuery<T>,
|
||||
options?: CountOptions<T, P>,
|
||||
): Promise<number>;
|
||||
/** Executes a MongoDB aggregation pipeline (MongoDB driver only). */
|
||||
aggregate(entityName: EntityName, pipeline: any[]): Promise<any[]>;
|
||||
/** Maps raw database result to entity data, converting column names to property names. */
|
||||
mapResult<T extends object>(
|
||||
result: EntityDictionary<T>,
|
||||
meta: EntityMetadata<T>,
|
||||
populate?: PopulateOptions<T>[],
|
||||
): EntityData<T> | null;
|
||||
/**
|
||||
* When driver uses pivot tables for M:N, this method will load identifiers for given collections from them
|
||||
*/
|
||||
loadFromPivotTable<T extends object, O extends object>(
|
||||
prop: EntityProperty,
|
||||
owners: Primary<O>[][],
|
||||
where?: FilterQuery<T>,
|
||||
orderBy?: OrderDefinition<T>,
|
||||
ctx?: Transaction,
|
||||
options?: FindOptions<T, any, any, any>,
|
||||
pivotJoin?: boolean,
|
||||
): Promise<Dictionary<T[]>>;
|
||||
/** Returns the database platform abstraction for this driver. */
|
||||
getPlatform(): Platform;
|
||||
/** Sets the metadata storage used by this driver. */
|
||||
setMetadata(metadata: MetadataStorage): void;
|
||||
/** Returns the metadata storage used by this driver. */
|
||||
getMetadata(): MetadataStorage;
|
||||
/**
|
||||
* Returns name of the underlying database dependencies (e.g. `mongodb` or `mysql2`)
|
||||
* for SQL drivers it also returns `knex` in the array as connectors are not used directly there
|
||||
*/
|
||||
getDependencies(): string[];
|
||||
/** Acquires a pessimistic lock on the given entity. */
|
||||
lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
|
||||
/**
|
||||
* Converts native db errors to standardized driver exceptions
|
||||
*/
|
||||
convertException(exception: Error): DriverException;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getSchemaName(
|
||||
meta?: EntityMetadata,
|
||||
options?: {
|
||||
schema?: string;
|
||||
parentSchema?: string;
|
||||
},
|
||||
): string | undefined;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getORMClass(): Constructor<MikroORM>;
|
||||
}
|
||||
/** Represents a field selector for entity queries (property name or wildcard). */
|
||||
export type EntityField<T, P extends string = PopulatePath.ALL> =
|
||||
| keyof T
|
||||
| PopulatePath.ALL
|
||||
| AutoPath<T, P, `${PopulatePath.ALL}`>;
|
||||
/** Defines the ordering for query results, either a single order map or an array of them. */
|
||||
export type OrderDefinition<T> =
|
||||
| (QueryOrderMap<T> & {
|
||||
0?: never;
|
||||
})
|
||||
| QueryOrderMap<T>[];
|
||||
/** Options for `em.findAll()`, extends FindOptions with an optional `where` clause. */
|
||||
export interface FindAllOptions<
|
||||
T,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends FindOptions<T, P, F, E> {
|
||||
where?: FilterQuery<T>;
|
||||
}
|
||||
/** Options for streaming query results via `em.stream()`. */
|
||||
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'
|
||||
> {
|
||||
/**
|
||||
* When populating to-many relations, the ORM streams fully merged entities instead of yielding every row.
|
||||
* You can opt out of this behavior by specifying `mergeResults: false`. This will yield every row from
|
||||
* the SQL result, but still mapped to entities, meaning that to-many collections will contain at most
|
||||
* a single item, and you will get duplicate root entities when they have multiple items in the populated
|
||||
* collection.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
mergeResults?: boolean;
|
||||
}
|
||||
/** Configuration for enabling/disabling named filters on a query. */
|
||||
export type FilterOptions = Dictionary<boolean | Dictionary> | string[] | boolean;
|
||||
/** Specifies which relations to populate and which fields to select or exclude. */
|
||||
export interface LoadHint<
|
||||
Entity,
|
||||
Hint extends string = never,
|
||||
Fields extends string = PopulatePath.ALL,
|
||||
Excludes extends string = never,
|
||||
> {
|
||||
populate?: Populate<Entity, Hint>;
|
||||
fields?: readonly AutoPath<Entity, Fields, `${PopulatePath.ALL}`>[];
|
||||
exclude?: readonly AutoPath<Entity, Excludes>[];
|
||||
}
|
||||
/** Options for `em.find()` queries, including population, ordering, pagination, and locking. */
|
||||
export interface FindOptions<
|
||||
Entity,
|
||||
Hint extends string = never,
|
||||
Fields extends string = PopulatePath.ALL,
|
||||
Excludes extends string = never,
|
||||
> extends LoadHint<Entity, Hint, Fields, Excludes> {
|
||||
/**
|
||||
* Where condition for populated relations. This will have no effect on the root entity.
|
||||
* With `select-in` strategy, this is applied only to the populate queries.
|
||||
* With `joined` strategy, those are applied as `join on` conditions.
|
||||
* When you use a nested condition on a to-many relation, it will produce a nested inner join,
|
||||
* discarding the collection items based on the child condition.
|
||||
*/
|
||||
populateWhere?: ObjectQuery<Entity> | PopulateHint | `${PopulateHint}`;
|
||||
/**
|
||||
* Filter condition for populated relations. This is similar to `populateWhere`, but will produce a `left join`
|
||||
* when nesting the condition. This is used for implementation of joined filters.
|
||||
*/
|
||||
populateFilter?: ObjectQuery<Entity>;
|
||||
/**
|
||||
* Index-friendly alternative to `$or` for conditions that span joined relations.
|
||||
* Each array element becomes an independent branch combined via `UNION ALL` subquery:
|
||||
* `WHERE pk IN (branch_1 UNION ALL branch_2 ... branch_N)`.
|
||||
* The database plans each branch independently, enabling per-table index usage
|
||||
* (e.g. GIN trigram indexes for fuzzy search across related entities).
|
||||
* sql only
|
||||
*/
|
||||
unionWhere?: ObjectQuery<Entity>[];
|
||||
/**
|
||||
* Strategy for combining `unionWhere` branches.
|
||||
* - `'union-all'` (default) — skips deduplication, faster for most use cases.
|
||||
* - `'union'` — deduplicates rows between branches; useful when branch overlap is very high.
|
||||
* sql only
|
||||
*/
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
/** Used for ordering of the populate queries. If not specified, the value of `options.orderBy` is used. */
|
||||
populateOrderBy?: OrderDefinition<Entity>;
|
||||
/** Per-relation overrides for populate loading behavior. Keys are populate paths (same as used in `populate`). */
|
||||
populateHints?: [Hint] extends [never]
|
||||
? never
|
||||
: {
|
||||
[K in Prefixes<Hint>]?: PopulateHintOptions;
|
||||
};
|
||||
/** Ordering of the results.Can be an object or array of objects, keys are property names, values are ordering (asc/desc) */
|
||||
orderBy?: OrderDefinition<Entity>;
|
||||
/** Control result caching for this query. Result cache is by default disabled, not to be confused with the identity map. */
|
||||
cache?: boolean | number | [string, number];
|
||||
/**
|
||||
* Limit the number of returned results. If you try to use limit/offset on a query that joins a to-many relation, pagination mechanism
|
||||
* will be triggered, resulting in a subquery condition, to apply this limit only to the root entities
|
||||
* instead of the cartesian product you get from a database in this case.
|
||||
*/
|
||||
limit?: number;
|
||||
/**
|
||||
* Sets the offset. If you try to use limit/offset on a query that joins a to-many relation, pagination mechanism
|
||||
* will be triggered, resulting in a subquery condition, to apply this limit only to the root entities
|
||||
* instead of the cartesian product you get from a database in this case.
|
||||
*/
|
||||
offset?: number;
|
||||
/** Fetch items `before` this cursor. */
|
||||
before?:
|
||||
| string
|
||||
| {
|
||||
startCursor: string | null;
|
||||
}
|
||||
| FilterObject<Entity>;
|
||||
/** Fetch items `after` this cursor. */
|
||||
after?:
|
||||
| string
|
||||
| {
|
||||
endCursor: string | null;
|
||||
}
|
||||
| FilterObject<Entity>;
|
||||
/** Fetch `first` N items. */
|
||||
first?: number;
|
||||
/** Fetch `last` N items. */
|
||||
last?: number;
|
||||
/** Fetch one more item than `first`/`last`, enabled automatically in `em.findByCursor` to check if there is a next page. */
|
||||
overfetch?: boolean;
|
||||
refresh?: boolean;
|
||||
convertCustomTypes?: boolean;
|
||||
disableIdentityMap?: boolean;
|
||||
schema?: string;
|
||||
flags?: QueryFlag[];
|
||||
/** sql only */
|
||||
groupBy?: string | string[];
|
||||
having?: FilterQuery<Entity>;
|
||||
/** sql only */
|
||||
strategy?: LoadStrategy | `${LoadStrategy}`;
|
||||
flushMode?: FlushMode | `${FlushMode}`;
|
||||
filters?: FilterOptions;
|
||||
/** sql only */
|
||||
lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
|
||||
/** sql only */
|
||||
lockTableAliases?: string[];
|
||||
ctx?: Transaction;
|
||||
connectionType?: ConnectionType;
|
||||
/** SQL: appended to FROM clause (e.g. `'force index(my_index)'`); MongoDB: index name or spec passed as `hint`. */
|
||||
indexHint?: string | Dictionary;
|
||||
/** sql only */
|
||||
comments?: string | string[];
|
||||
/** sql only */
|
||||
hintComments?: string | string[];
|
||||
/** SQL: collation name string applied as COLLATE to ORDER BY; MongoDB: CollationOptions object. */
|
||||
collation?: CollationOptions | string;
|
||||
/** mongodb only */
|
||||
maxTimeMS?: number;
|
||||
/** mongodb only */
|
||||
allowDiskUse?: boolean;
|
||||
loggerContext?: LogContext;
|
||||
logging?: LoggingOptions;
|
||||
/** @internal used to apply filters to the auto-joined relations */
|
||||
em?: EntityManager;
|
||||
}
|
||||
/** Options for cursor-based pagination via `em.findByCursor()`. */
|
||||
export interface FindByCursorOptions<
|
||||
T extends object,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
I extends boolean = true,
|
||||
> extends Omit<FindAllOptions<T, P, F, E>, 'limit' | 'offset'> {
|
||||
includeCount?: I;
|
||||
}
|
||||
/** Options for `em.findOne()`, extends FindOptions with optimistic lock version support. */
|
||||
export interface FindOneOptions<
|
||||
T,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'lockMode'> {
|
||||
lockMode?: LockMode;
|
||||
lockVersion?: number | Date;
|
||||
}
|
||||
/** Options for `em.findOneOrFail()`, adds a custom error handler for missing entities. */
|
||||
export interface FindOneOrFailOptions<
|
||||
T extends object,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends FindOneOptions<T, P, F, E> {
|
||||
failHandler?: (entityName: string, where: Dictionary | IPrimaryKey | any) => Error;
|
||||
strict?: boolean;
|
||||
}
|
||||
/** Options for native insert and update operations. */
|
||||
export interface NativeInsertUpdateOptions<T> {
|
||||
convertCustomTypes?: boolean;
|
||||
ctx?: Transaction;
|
||||
schema?: string;
|
||||
/** `nativeUpdate()` only option */
|
||||
upsert?: boolean;
|
||||
loggerContext?: LogContext;
|
||||
/** sql only */
|
||||
unionWhere?: ObjectQuery<T>[];
|
||||
/** sql only */
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
filters?: FilterOptions;
|
||||
/** @internal */
|
||||
em?: EntityManager;
|
||||
}
|
||||
/** Options for batch native insert and update operations. */
|
||||
export interface NativeInsertUpdateManyOptions<T> extends NativeInsertUpdateOptions<T> {
|
||||
processCollections?: boolean;
|
||||
}
|
||||
/** Options for `em.upsert()`, controlling conflict resolution behavior. */
|
||||
export interface UpsertOptions<Entity, Fields extends string = never> extends Omit<
|
||||
NativeInsertUpdateOptions<Entity>,
|
||||
'upsert'
|
||||
> {
|
||||
onConflictFields?: (keyof Entity)[] | Raw;
|
||||
onConflictAction?: 'ignore' | 'merge';
|
||||
onConflictMergeFields?: AutoPath<Entity, Fields, `${PopulatePath.ALL}`>[];
|
||||
onConflictExcludeFields?: AutoPath<Entity, Fields, `${PopulatePath.ALL}`>[];
|
||||
onConflictWhere?: FilterQuery<Entity>;
|
||||
disableIdentityMap?: boolean;
|
||||
}
|
||||
/** Options for `em.upsertMany()`, adds batch size control. */
|
||||
export interface UpsertManyOptions<Entity, Fields extends string = never> extends UpsertOptions<Entity, Fields> {
|
||||
batchSize?: number;
|
||||
}
|
||||
/** Options for `em.count()` queries. */
|
||||
export interface CountOptions<T extends object, P extends string = never> {
|
||||
filters?: FilterOptions;
|
||||
schema?: string;
|
||||
groupBy?: string | readonly string[];
|
||||
having?: FilterQuery<T>;
|
||||
cache?: boolean | number | [string, number];
|
||||
populate?: Populate<T, P>;
|
||||
populateWhere?: ObjectQuery<T> | PopulateHint | `${PopulateHint}`;
|
||||
populateFilter?: ObjectQuery<T>;
|
||||
/** @see FindOptions.unionWhere */
|
||||
unionWhere?: ObjectQuery<T>[];
|
||||
/** @see FindOptions.unionWhereStrategy */
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
ctx?: Transaction;
|
||||
connectionType?: ConnectionType;
|
||||
flushMode?: FlushMode | `${FlushMode}`;
|
||||
/** SQL: appended to FROM clause (e.g. `'force index(my_index)'`); MongoDB: index name or spec passed as `hint`. */
|
||||
indexHint?: string | Dictionary;
|
||||
/** sql only */
|
||||
comments?: string | string[];
|
||||
/** sql only */
|
||||
hintComments?: string | string[];
|
||||
/** SQL: collation name string applied as COLLATE; MongoDB: CollationOptions object. */
|
||||
collation?: CollationOptions | string;
|
||||
/** mongodb only */
|
||||
maxTimeMS?: number;
|
||||
loggerContext?: LogContext;
|
||||
logging?: LoggingOptions;
|
||||
/** @internal used to apply filters to the auto-joined relations */
|
||||
em?: EntityManager;
|
||||
}
|
||||
/** Options for `em.qb().update()` operations. */
|
||||
export interface UpdateOptions<T> {
|
||||
filters?: FilterOptions;
|
||||
schema?: string;
|
||||
ctx?: Transaction;
|
||||
/** sql only */
|
||||
unionWhere?: ObjectQuery<T>[];
|
||||
/** sql only */
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
}
|
||||
/** Options for `em.qb().delete()` operations. */
|
||||
export interface DeleteOptions<T> extends DriverMethodOptions {
|
||||
filters?: FilterOptions;
|
||||
/** sql only */
|
||||
unionWhere?: ObjectQuery<T>[];
|
||||
/** sql only */
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
/** @internal */
|
||||
em?: EntityManager;
|
||||
}
|
||||
/** Options for `em.nativeDelete()` operations. */
|
||||
export interface NativeDeleteOptions<T> extends DriverMethodOptions {
|
||||
filters?: FilterOptions;
|
||||
/** sql only */
|
||||
unionWhere?: ObjectQuery<T>[];
|
||||
/** sql only */
|
||||
unionWhereStrategy?: 'union-all' | 'union';
|
||||
/** @internal */
|
||||
em?: EntityManager;
|
||||
}
|
||||
/** Options for pessimistic and optimistic lock operations. */
|
||||
export interface LockOptions extends DriverMethodOptions {
|
||||
lockMode?: LockMode;
|
||||
lockVersion?: number | Date;
|
||||
lockTableAliases?: string[];
|
||||
logging?: LoggingOptions;
|
||||
}
|
||||
/** Base options shared by all driver methods (transaction context, schema, logging). */
|
||||
export interface DriverMethodOptions {
|
||||
ctx?: Transaction;
|
||||
schema?: string;
|
||||
loggerContext?: LogContext;
|
||||
}
|
||||
/** MongoDB-style collation options for locale-aware string comparison. */
|
||||
export interface CollationOptions {
|
||||
locale: string;
|
||||
caseLevel?: boolean;
|
||||
caseFirst?: string;
|
||||
strength?: number;
|
||||
numericOrdering?: boolean;
|
||||
alternate?: string;
|
||||
maxVariable?: string;
|
||||
backwards?: boolean;
|
||||
}
|
||||
/** Options for `em.getReference()`, controlling wrapping and type conversion. */
|
||||
export interface GetReferenceOptions {
|
||||
wrapped?: boolean;
|
||||
convertCustomTypes?: boolean;
|
||||
schema?: string;
|
||||
/**
|
||||
* Property name to use for identity map lookup instead of the primary key.
|
||||
* This is useful for creating references by unique non-PK properties.
|
||||
*/
|
||||
key?: string;
|
||||
}
|
||||
2
node_modules/@mikro-orm/core/drivers/IDatabaseDriver.js
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/drivers/IDatabaseDriver.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/** Symbol used to extract the EntityManager type from a driver instance. */
|
||||
export const EntityManagerType = Symbol('EntityManagerType');
|
||||
2
node_modules/@mikro-orm/core/drivers/index.d.ts
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/drivers/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './IDatabaseDriver.js';
|
||||
export * from './DatabaseDriver.js';
|
||||
2
node_modules/@mikro-orm/core/drivers/index.js
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/drivers/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './IDatabaseDriver.js';
|
||||
export * from './DatabaseDriver.js';
|
||||
129
node_modules/@mikro-orm/core/entity/BaseEntity.d.ts
generated
vendored
Normal file
129
node_modules/@mikro-orm/core/entity/BaseEntity.d.ts
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
import { type Ref } from './Reference.js';
|
||||
import type {
|
||||
AutoPath,
|
||||
EntityData,
|
||||
EntityDTO,
|
||||
Loaded,
|
||||
LoadedReference,
|
||||
AddEager,
|
||||
EntityKey,
|
||||
FromEntityType,
|
||||
IsSubset,
|
||||
MergeSelected,
|
||||
SerializeDTO,
|
||||
} from '../typings.js';
|
||||
import { type AssignOptions } from './EntityAssigner.js';
|
||||
import type { EntityLoaderOptions } from './EntityLoader.js';
|
||||
import { type SerializeOptions } from '../serialization/EntitySerializer.js';
|
||||
import type { FindOneOptions } from '../drivers/IDatabaseDriver.js';
|
||||
import type { PopulatePath } from '../enums.js';
|
||||
/** Base class for entities providing convenience methods like `assign()`, `toObject()`, and `populate()`. */
|
||||
export declare abstract class BaseEntity {
|
||||
/** Returns whether the entity has been fully loaded from the database. */
|
||||
isInitialized(): boolean;
|
||||
/** Marks the entity as populated or not for serialization purposes. */
|
||||
populated(populated?: boolean): void;
|
||||
/** Loads the specified relations on this entity. */
|
||||
populate<Entity extends this = this, Hint extends string = never, Fields extends string = never>(
|
||||
populate: AutoPath<Entity, Hint, PopulatePath.ALL>[] | false,
|
||||
options?: EntityLoaderOptions<Entity, Fields>,
|
||||
): Promise<Loaded<Entity, Hint>>;
|
||||
/** Returns a Reference wrapper for this entity. */
|
||||
toReference<Entity extends this = this>(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
|
||||
/**
|
||||
* Converts the entity to a plain object representation.
|
||||
*
|
||||
* **Note on typing with `Loaded` entities:** When called on a `Loaded<Entity, 'relation'>` type,
|
||||
* the return type will be `EntityDTO<Entity>` (with relations as primary keys), not
|
||||
* `EntityDTO<Loaded<Entity, 'relation'>>` (with loaded relations as nested objects).
|
||||
* This is a TypeScript limitation - the `this` type resolves to the class, not the `Loaded` wrapper.
|
||||
*
|
||||
* For correct typing that reflects loaded relations, use `wrap()`:
|
||||
* ```ts
|
||||
* const result = await em.find(User, {}, { populate: ['profile'] });
|
||||
* // Type: EntityDTO<User> (profile is number)
|
||||
* const obj1 = result[0].toObject();
|
||||
* // Type: EntityDTO<Loaded<User, 'profile'>> (profile is nested object)
|
||||
* const obj2 = wrap(result[0]).toObject();
|
||||
* ```
|
||||
*
|
||||
* Runtime values are correct in both cases - only the static types differ.
|
||||
*/
|
||||
toObject<Entity extends this = this>(): EntityDTO<Entity>;
|
||||
/**
|
||||
* Converts the entity to a plain object representation.
|
||||
*
|
||||
* **Note on typing with `Loaded` entities:** When called on a `Loaded<Entity, 'relation'>` type,
|
||||
* the return type will be `EntityDTO<Entity>` (with relations as primary keys), not
|
||||
* `EntityDTO<Loaded<Entity, 'relation'>>` (with loaded relations as nested objects).
|
||||
* This is a TypeScript limitation - the `this` type resolves to the class, not the `Loaded` wrapper.
|
||||
*
|
||||
* For correct typing that reflects loaded relations, use `wrap()`:
|
||||
* ```ts
|
||||
* const result = await em.find(User, {}, { populate: ['profile'] });
|
||||
* // Type: EntityDTO<User> (profile is number)
|
||||
* const obj1 = result[0].toObject();
|
||||
* // Type: EntityDTO<Loaded<User, 'profile'>> (profile is nested object)
|
||||
* const obj2 = wrap(result[0]).toObject();
|
||||
* ```
|
||||
*
|
||||
* Runtime values are correct in both cases - only the static types differ.
|
||||
*/
|
||||
toObject<Entity extends this = this>(ignoreFields: never[]): EntityDTO<Entity>;
|
||||
/**
|
||||
* Converts the entity to a plain object representation.
|
||||
*
|
||||
* **Note on typing with `Loaded` entities:** When called on a `Loaded<Entity, 'relation'>` type,
|
||||
* the return type will be `EntityDTO<Entity>` (with relations as primary keys), not
|
||||
* `EntityDTO<Loaded<Entity, 'relation'>>` (with loaded relations as nested objects).
|
||||
* This is a TypeScript limitation - the `this` type resolves to the class, not the `Loaded` wrapper.
|
||||
*
|
||||
* For correct typing that reflects loaded relations, use `wrap()`:
|
||||
* ```ts
|
||||
* const result = await em.find(User, {}, { populate: ['profile'] });
|
||||
* // Type: EntityDTO<User> (profile is number)
|
||||
* const obj1 = result[0].toObject();
|
||||
* // Type: EntityDTO<Loaded<User, 'profile'>> (profile is nested object)
|
||||
* const obj2 = wrap(result[0]).toObject();
|
||||
* ```
|
||||
*
|
||||
* Runtime values are correct in both cases - only the static types differ.
|
||||
*
|
||||
* @param ignoreFields - Array of field names to omit from the result.
|
||||
*/
|
||||
toObject<Entity extends this = this, Ignored extends EntityKey<Entity> = never>(
|
||||
ignoreFields: Ignored[],
|
||||
): Omit<EntityDTO<Entity>, Ignored>;
|
||||
/** Converts the entity to a plain object, including all properties regardless of serialization rules. */
|
||||
toPOJO<Entity extends this = this>(): EntityDTO<Entity>;
|
||||
/** Serializes the entity with control over which relations and fields to include or exclude. */
|
||||
serialize<
|
||||
Entity extends this = this,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Hint extends string = never,
|
||||
Exclude extends string = never,
|
||||
>(options?: SerializeOptions<Naked, Hint, Exclude>): SerializeDTO<Naked, Hint, Exclude>;
|
||||
/** Assigns the given data to this entity, updating its properties and relations. */
|
||||
assign<
|
||||
Entity extends this,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
|
||||
| EntityData<Naked, Convert>
|
||||
| Partial<EntityDTO<Naked>>,
|
||||
>(
|
||||
data: Data & IsSubset<EntityData<Naked>, Data>,
|
||||
options?: AssignOptions<Convert>,
|
||||
): MergeSelected<Entity, Naked, keyof Data & string>;
|
||||
/** Initializes (refreshes) the entity by reloading it from the database. Returns null if not found. */
|
||||
init<
|
||||
Entity extends this = this,
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
>(options?: FindOneOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
||||
/** Returns the database schema this entity belongs to. */
|
||||
getSchema(): string | undefined;
|
||||
/** Sets the database schema for this entity. */
|
||||
setSchema(schema?: string): void;
|
||||
}
|
||||
51
node_modules/@mikro-orm/core/entity/BaseEntity.js
generated
vendored
Normal file
51
node_modules/@mikro-orm/core/entity/BaseEntity.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Reference } from './Reference.js';
|
||||
import { EntityAssigner } from './EntityAssigner.js';
|
||||
import { EntitySerializer } from '../serialization/EntitySerializer.js';
|
||||
import { helper } from './wrap.js';
|
||||
/** Base class for entities providing convenience methods like `assign()`, `toObject()`, and `populate()`. */
|
||||
export class BaseEntity {
|
||||
/** Returns whether the entity has been fully loaded from the database. */
|
||||
isInitialized() {
|
||||
return helper(this).__initialized;
|
||||
}
|
||||
/** Marks the entity as populated or not for serialization purposes. */
|
||||
populated(populated = true) {
|
||||
helper(this).populated(populated);
|
||||
}
|
||||
/** Loads the specified relations on this entity. */
|
||||
async populate(populate, options = {}) {
|
||||
return helper(this).populate(populate, options);
|
||||
}
|
||||
/** Returns a Reference wrapper for this entity. */
|
||||
toReference() {
|
||||
return Reference.create(this);
|
||||
}
|
||||
toObject(ignoreFields) {
|
||||
return helper(this).toObject(ignoreFields);
|
||||
}
|
||||
/** Converts the entity to a plain object, including all properties regardless of serialization rules. */
|
||||
toPOJO() {
|
||||
return helper(this).toPOJO();
|
||||
}
|
||||
/** Serializes the entity with control over which relations and fields to include or exclude. */
|
||||
serialize(options) {
|
||||
return EntitySerializer.serialize(this, options);
|
||||
}
|
||||
/** Assigns the given data to this entity, updating its properties and relations. */
|
||||
assign(data, options = {}) {
|
||||
return EntityAssigner.assign(this, data, options);
|
||||
}
|
||||
/** Initializes (refreshes) the entity by reloading it from the database. Returns null if not found. */
|
||||
init(options) {
|
||||
return helper(this).init(options);
|
||||
}
|
||||
/** Returns the database schema this entity belongs to. */
|
||||
getSchema() {
|
||||
return helper(this).getSchema();
|
||||
}
|
||||
/** Sets the database schema for this entity. */
|
||||
setSchema(schema) {
|
||||
helper(this).setSchema(schema);
|
||||
}
|
||||
}
|
||||
Object.defineProperty(BaseEntity.prototype, '__baseEntity', { value: true, writable: false, enumerable: false });
|
||||
227
node_modules/@mikro-orm/core/entity/Collection.d.ts
generated
vendored
Normal file
227
node_modules/@mikro-orm/core/entity/Collection.d.ts
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
import type {
|
||||
EntityDTO,
|
||||
EntityKey,
|
||||
EntityProperty,
|
||||
FilterQuery,
|
||||
IPrimaryKey,
|
||||
Loaded,
|
||||
LoadedCollection,
|
||||
Populate,
|
||||
Primary,
|
||||
} from '../typings.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import type { Transaction } from '../connections/Connection.js';
|
||||
import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
|
||||
import type { EntityLoaderOptions } from './EntityLoader.js';
|
||||
/** Options for the `Collection.matching()` method to query a subset of collection items from the database. */
|
||||
export interface MatchingOptions<T extends object, P extends string = never> extends FindOptions<T, P> {
|
||||
/** Additional filtering conditions for the query. */
|
||||
where?: FilterQuery<T>;
|
||||
/** Whether to store the matched items in the collection (makes it read-only). */
|
||||
store?: boolean;
|
||||
/** Transaction context for the query. */
|
||||
ctx?: Transaction;
|
||||
}
|
||||
/** Represents a to-many relation (1:m or m:n) as an iterable, managed collection of entities. */
|
||||
export declare class Collection<T extends object, O extends object = object> {
|
||||
#private;
|
||||
readonly owner: O;
|
||||
[k: number]: T;
|
||||
constructor(owner: O, items?: T[], initialized?: boolean);
|
||||
/**
|
||||
* Creates new Collection instance, assigns it to the owning entity and sets the items to it (propagating them to their inverse sides)
|
||||
*/
|
||||
static create<T extends object, O extends object = object>(
|
||||
owner: O,
|
||||
prop: EntityKey<O>,
|
||||
items: undefined | T[],
|
||||
initialized: boolean,
|
||||
): Collection<T, O>;
|
||||
/**
|
||||
* Ensures the collection is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the Collection instance (itself), works the same as `Reference.load()`.
|
||||
*/
|
||||
load<TT extends T, P extends string = never>(
|
||||
options?: InitCollectionOptions<TT, P>,
|
||||
): Promise<LoadedCollection<Loaded<TT, P>>>;
|
||||
private setSerializationContext;
|
||||
/**
|
||||
* Initializes the collection and returns the items
|
||||
*/
|
||||
loadItems<TT extends T, P extends string = never>(options?: InitCollectionOptions<TT, P>): Promise<Loaded<TT, P>[]>;
|
||||
/**
|
||||
* Gets the count of collection items from database instead of counting loaded items.
|
||||
* The value is cached (unless you use the `where` option), use `refresh: true` to force reload it.
|
||||
*/
|
||||
loadCount(options?: LoadCountOptions<T> | boolean): Promise<number>;
|
||||
/** Queries a subset of the collection items from the database with custom filtering, ordering, and pagination. */
|
||||
matching<TT extends T, P extends string = never>(options: MatchingOptions<T, P>): Promise<Loaded<TT, P>[]>;
|
||||
/**
|
||||
* Returns the items (the collection must be initialized)
|
||||
*/
|
||||
getItems(check?: boolean): T[];
|
||||
/** Serializes the collection items to plain JSON objects. Returns an empty array if not initialized. */
|
||||
toJSON<TT extends T>(): EntityDTO<TT>[];
|
||||
/** Adds one or more items to the collection, propagating the change to the inverse side. Returns the number of items added. */
|
||||
add<TT extends T>(
|
||||
entity: TT | Reference<TT> | Iterable<TT | Reference<TT>>,
|
||||
...entities: (TT | Reference<TT>)[]
|
||||
): number;
|
||||
/**
|
||||
* Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
|
||||
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
||||
* 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`,
|
||||
* which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
|
||||
*/
|
||||
remove<TT extends T>(
|
||||
entity: TT | Reference<TT> | Iterable<TT | Reference<TT>> | ((item: TT) => boolean),
|
||||
...entities: (TT | Reference<TT>)[]
|
||||
): number;
|
||||
/** Checks whether the collection contains the given item. */
|
||||
contains<TT extends T>(item: TT | Reference<TT>, check?: boolean): boolean;
|
||||
/** Returns the number of items in the collection. Throws if the collection is not initialized. */
|
||||
count(): number;
|
||||
/** Returns true if the collection has no items. Throws if the collection is not initialized. */
|
||||
isEmpty(): boolean;
|
||||
/** Returns whether this collection should be included in serialization based on its populated state. */
|
||||
shouldPopulate(populated?: boolean): boolean;
|
||||
/** Marks the collection as populated or not for serialization purposes. */
|
||||
populated(populated?: boolean | undefined): void;
|
||||
/** Initializes the collection by loading its items from the database. */
|
||||
init<TT extends T, P extends string = never>(
|
||||
options?: InitCollectionOptions<TT, P>,
|
||||
): Promise<LoadedCollection<Loaded<TT, P>>>;
|
||||
private getEntityManager;
|
||||
private createCondition;
|
||||
private createManyToManyCondition;
|
||||
private createLoadCountCondition;
|
||||
private checkInitialized;
|
||||
/**
|
||||
* re-orders items after searching with `$in` operator
|
||||
*/
|
||||
private reorderItems;
|
||||
private cancelOrphanRemoval;
|
||||
private validateModification;
|
||||
/** Converts all items in the collection to plain DTO objects. */
|
||||
toArray<TT extends T>(): EntityDTO<TT>[];
|
||||
/** Returns the primary key values (or a specific field) of all items in the collection. */
|
||||
getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string | string[]): U[];
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
addWithoutPropagation(entity: T): void;
|
||||
/** Replaces all items in the collection with the given items. */
|
||||
set(items: Iterable<T | Reference<T>>): void;
|
||||
private compare;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
hydrate(items: T[], forcePropagate?: boolean, partial?: boolean): void;
|
||||
/**
|
||||
* Remove all items from the collection. Note that removing items from collection does not necessarily imply deleting the target entity,
|
||||
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
||||
* 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`,
|
||||
* which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
|
||||
*/
|
||||
removeAll(): void;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
removeWithoutPropagation(entity: T): void;
|
||||
/**
|
||||
* Extracts a slice of the collection items starting at position start to end (exclusive) of the collection.
|
||||
* If end is null it returns all elements from start to the end of the collection.
|
||||
*/
|
||||
slice(start?: number, end?: number): T[];
|
||||
/**
|
||||
* Tests for the existence of an element that satisfies the given predicate.
|
||||
*/
|
||||
exists(cb: (item: T) => boolean): boolean;
|
||||
/**
|
||||
* Returns the first element of this collection that satisfies the predicate.
|
||||
*/
|
||||
find<S extends T>(cb: (item: T, index: number) => item is S): S | undefined;
|
||||
/**
|
||||
* Returns the first element of this collection that satisfies the predicate.
|
||||
*/
|
||||
find(cb: (item: T, index: number) => boolean): T | undefined;
|
||||
/**
|
||||
* Extracts a subset of the collection items.
|
||||
*/
|
||||
filter<S extends T>(cb: (item: T, index: number) => item is S): S[];
|
||||
/**
|
||||
* Extracts a subset of the collection items.
|
||||
*/
|
||||
filter(cb: (item: T, index: number) => boolean): T[];
|
||||
/**
|
||||
* Maps the collection items based on your provided mapper function.
|
||||
*/
|
||||
map<R>(mapper: (item: T, index: number) => R): R[];
|
||||
/**
|
||||
* Maps the collection items based on your provided mapper function to a single object.
|
||||
*/
|
||||
reduce<R>(cb: (obj: R, item: T, index: number) => R, initial?: R): R;
|
||||
/**
|
||||
* Maps the collection items to a dictionary, indexed by the key you specify.
|
||||
* If there are more items with the same key, only the first one will be present.
|
||||
*/
|
||||
indexBy<K1 extends keyof T, K2 extends keyof T = never>(key: K1): Record<T[K1] & PropertyKey, T>;
|
||||
/**
|
||||
* Maps the collection items to a dictionary, indexed by the key you specify.
|
||||
* If there are more items with the same key, only the first one will be present.
|
||||
*/
|
||||
indexBy<K1 extends keyof T, K2 extends keyof T = never>(key: K1, valueKey: K2): Record<T[K1] & PropertyKey, T[K2]>;
|
||||
/** Returns whether the collection has been initialized. Pass `fully = true` to also check that all items are initialized. */
|
||||
isInitialized(fully?: boolean): boolean;
|
||||
isDirty(): boolean;
|
||||
/** Returns whether the collection was partially loaded (propagation is disabled for partial collections). */
|
||||
isPartial(): boolean;
|
||||
setDirty(dirty?: boolean): void;
|
||||
get length(): number;
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
takeSnapshot(forcePropagate?: boolean): void;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getSnapshot(): T[] | undefined;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get property(): EntityProperty;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
set property(prop: EntityProperty);
|
||||
protected propagate(item: T, method: 'add' | 'remove' | 'takeSnapshot'): void;
|
||||
protected propagateToInverseSide(item: T, method: 'add' | 'remove' | 'takeSnapshot'): void;
|
||||
protected propagateToOwningSide(item: T, method: 'add' | 'remove' | 'takeSnapshot'): void;
|
||||
protected shouldPropagateToCollection(
|
||||
collection: Collection<O, T>,
|
||||
method: 'add' | 'remove' | 'takeSnapshot',
|
||||
): boolean;
|
||||
protected incrementCount(value: number): void;
|
||||
}
|
||||
/** Options for initializing a collection via `init()` or `load()`. */
|
||||
export interface InitCollectionOptions<
|
||||
T,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends EntityLoaderOptions<T, F, E> {
|
||||
/** Whether to use the dataloader for batching collection loads. */
|
||||
dataloader?: boolean;
|
||||
/** Relations to populate on the loaded items. */
|
||||
populate?: Populate<T, P>;
|
||||
/** Populate only references (without loading full entities). Works only with M:N collections that use pivot table. */
|
||||
ref?: boolean;
|
||||
}
|
||||
/** Options for the `Collection.loadCount()` method. */
|
||||
export interface LoadCountOptions<T extends object> extends CountOptions<T, '*'> {
|
||||
/** Whether to reload the count from the database even if it is already cached. */
|
||||
refresh?: boolean;
|
||||
/** Additional filtering conditions for the count query. */
|
||||
where?: FilterQuery<T>;
|
||||
}
|
||||
747
node_modules/@mikro-orm/core/entity/Collection.js
generated
vendored
Normal file
747
node_modules/@mikro-orm/core/entity/Collection.js
generated
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { MetadataError, ValidationError } from '../errors.js';
|
||||
import { DataloaderType, ReferenceKind } from '../enums.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { helper, wrap } from './wrap.js';
|
||||
import { QueryHelper } from '../utils/QueryHelper.js';
|
||||
import { inspect } from '../logging/inspect.js';
|
||||
/** Represents a to-many relation (1:m or m:n) as an iterable, managed collection of entities. */
|
||||
export class Collection {
|
||||
owner;
|
||||
#items = new Set();
|
||||
#initialized = true;
|
||||
#dirty = false;
|
||||
#partial = false; // mark partially loaded collections, propagation is disabled for those
|
||||
#snapshot = []; // used to create a diff of the collection at commit time, undefined marks overridden values so we need to wipe when flushing
|
||||
#readonly;
|
||||
#count;
|
||||
#property;
|
||||
#populated;
|
||||
constructor(owner, items, initialized = true) {
|
||||
this.owner = owner;
|
||||
/* v8 ignore next */
|
||||
if (items) {
|
||||
let i = 0;
|
||||
this.#items = new Set(items);
|
||||
this.#items.forEach(item => (this[i++] = item));
|
||||
}
|
||||
this.#initialized = !!items || initialized;
|
||||
}
|
||||
/**
|
||||
* Creates new Collection instance, assigns it to the owning entity and sets the items to it (propagating them to their inverse sides)
|
||||
*/
|
||||
static create(owner, prop, items, initialized) {
|
||||
const coll = new Collection(owner, undefined, initialized);
|
||||
coll.property = helper(owner).__meta.properties[prop];
|
||||
owner[prop] = coll;
|
||||
if (items) {
|
||||
coll.set(items);
|
||||
}
|
||||
return coll;
|
||||
}
|
||||
/**
|
||||
* Ensures the collection is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the Collection instance (itself), works the same as `Reference.load()`.
|
||||
*/
|
||||
async load(options = {}) {
|
||||
if (this.isInitialized(true) && !options.refresh) {
|
||||
const em = this.getEntityManager(this.#items, false);
|
||||
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
||||
await em?.populate(this.#items, options.populate, options);
|
||||
this.setSerializationContext(options);
|
||||
} else {
|
||||
await this.init({ refresh: false, ...options });
|
||||
}
|
||||
return this;
|
||||
}
|
||||
setSerializationContext(options) {
|
||||
helper(this.owner).setSerializationContext({
|
||||
populate: Array.isArray(options.populate)
|
||||
? options.populate.map(hint => `${this.property.name}.${hint}`)
|
||||
: (options.populate ?? [this.property.name]),
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Initializes the collection and returns the items
|
||||
*/
|
||||
async loadItems(options) {
|
||||
await this.load(options);
|
||||
return this.getItems(false);
|
||||
}
|
||||
/**
|
||||
* Gets the count of collection items from database instead of counting loaded items.
|
||||
* The value is cached (unless you use the `where` option), use `refresh: true` to force reload it.
|
||||
*/
|
||||
async loadCount(options = {}) {
|
||||
options = typeof options === 'boolean' ? { refresh: options } : options;
|
||||
const { refresh, where, ...countOptions } = options;
|
||||
if (!refresh && !where && this.#count != null) {
|
||||
return this.#count;
|
||||
}
|
||||
const em = this.getEntityManager();
|
||||
if (
|
||||
!em.getPlatform().usesPivotTable() &&
|
||||
this.property.kind === ReferenceKind.MANY_TO_MANY &&
|
||||
this.property.owner
|
||||
) {
|
||||
return (this.#count = this.length);
|
||||
}
|
||||
const cond = this.createLoadCountCondition(where ?? {});
|
||||
const count = await em.count(this.property.targetMeta.class, cond, countOptions);
|
||||
if (!where) {
|
||||
this.#count = count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
/** Queries a subset of the collection items from the database with custom filtering, ordering, and pagination. */
|
||||
async matching(options) {
|
||||
const em = this.getEntityManager();
|
||||
const { where, ctx, ...opts } = options;
|
||||
let items;
|
||||
if (this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable()) {
|
||||
// M:N via pivot table bypasses em.find(), so merge all 3 levels here
|
||||
opts.orderBy = QueryHelper.mergeOrderBy(opts.orderBy, this.property.orderBy, this.property.targetMeta?.orderBy);
|
||||
options.populate = await em.preparePopulate(this.property.targetMeta.class, options);
|
||||
const cond = await em.applyFilters(this.property.targetMeta.class, where, options.filters ?? {}, 'read');
|
||||
const map = await em
|
||||
.getDriver()
|
||||
.loadFromPivotTable(this.property, [helper(this.owner).__primaryKeys], cond, opts.orderBy, ctx, options);
|
||||
items = map[helper(this.owner).getSerializedPrimaryKey()].map(item =>
|
||||
em.merge(this.property.targetMeta.class, item, { convertCustomTypes: true }),
|
||||
);
|
||||
await em.populate(items, options.populate, options);
|
||||
} else {
|
||||
// em.find() merges entity-level orderBy, so only merge runtime + relation here
|
||||
opts.orderBy = QueryHelper.mergeOrderBy(opts.orderBy, this.property.orderBy);
|
||||
items = await em.find(this.property.targetMeta.class, this.createCondition(where), opts);
|
||||
}
|
||||
if (options.store) {
|
||||
this.hydrate(items, true);
|
||||
this.setSerializationContext(options);
|
||||
this.populated();
|
||||
this.#readonly = true;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
/**
|
||||
* Returns the items (the collection must be initialized)
|
||||
*/
|
||||
getItems(check = true) {
|
||||
if (check) {
|
||||
this.checkInitialized();
|
||||
}
|
||||
return [...this.#items];
|
||||
}
|
||||
/** Serializes the collection items to plain JSON objects. Returns an empty array if not initialized. */
|
||||
toJSON() {
|
||||
if (!this.isInitialized()) {
|
||||
return [];
|
||||
}
|
||||
return this.toArray();
|
||||
}
|
||||
/** Adds one or more items to the collection, propagating the change to the inverse side. Returns the number of items added. */
|
||||
add(entity, ...entities) {
|
||||
entities = Utils.asArray(entity).concat(entities);
|
||||
const unwrapped = entities.map(i => Reference.unwrapReference(i));
|
||||
this.validateModification(unwrapped);
|
||||
const em = this.getEntityManager(entities, false);
|
||||
let added = 0;
|
||||
for (const item of entities) {
|
||||
const entity = Reference.unwrapReference(item);
|
||||
if (!this.contains(entity, false)) {
|
||||
this.incrementCount(1);
|
||||
this[this.#items.size] = entity;
|
||||
this.#items.add(entity);
|
||||
added++;
|
||||
this.#dirty = true;
|
||||
this.propagate(entity, 'add');
|
||||
}
|
||||
}
|
||||
if (this.property.kind === ReferenceKind.ONE_TO_MANY && em) {
|
||||
em.persist(entities);
|
||||
}
|
||||
this.cancelOrphanRemoval(unwrapped);
|
||||
return added;
|
||||
}
|
||||
/**
|
||||
* Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
|
||||
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
||||
* 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`,
|
||||
* which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
|
||||
*/
|
||||
remove(entity, ...entities) {
|
||||
if (entity instanceof Function) {
|
||||
let removed = 0;
|
||||
for (const item of this.#items) {
|
||||
if (entity(item)) {
|
||||
removed += this.remove(item);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
this.checkInitialized();
|
||||
entities = Utils.asArray(entity).concat(entities);
|
||||
const unwrapped = entities.map(i => Reference.unwrapReference(i));
|
||||
this.validateModification(unwrapped);
|
||||
const em = this.getEntityManager(entities, false);
|
||||
let removed = 0;
|
||||
for (const item of entities) {
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
const entity = Reference.unwrapReference(item);
|
||||
if (this.#items.delete(entity)) {
|
||||
this.incrementCount(-1);
|
||||
delete this[this.#items.size]; // remove last item
|
||||
this.propagate(entity, 'remove');
|
||||
removed++;
|
||||
this.#dirty = true;
|
||||
}
|
||||
if (this.property.orphanRemoval && em) {
|
||||
em.getUnitOfWork().scheduleOrphanRemoval(entity);
|
||||
}
|
||||
}
|
||||
if (this.property.kind === ReferenceKind.ONE_TO_MANY && !this.property.orphanRemoval && em) {
|
||||
em.persist(entities);
|
||||
}
|
||||
if (removed > 0) {
|
||||
Object.assign(this, [...this.#items]); // reassign array access
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
/** Checks whether the collection contains the given item. */
|
||||
contains(item, check = true) {
|
||||
if (check) {
|
||||
this.checkInitialized();
|
||||
}
|
||||
const entity = Reference.unwrapReference(item);
|
||||
return this.#items.has(entity);
|
||||
}
|
||||
/** Returns the number of items in the collection. Throws if the collection is not initialized. */
|
||||
count() {
|
||||
this.checkInitialized();
|
||||
return this.#items.size;
|
||||
}
|
||||
/** Returns true if the collection has no items. Throws if the collection is not initialized. */
|
||||
isEmpty() {
|
||||
this.checkInitialized();
|
||||
return this.count() === 0;
|
||||
}
|
||||
/** Returns whether this collection should be included in serialization based on its populated state. */
|
||||
shouldPopulate(populated) {
|
||||
if (!this.isInitialized(true)) {
|
||||
return false;
|
||||
}
|
||||
if (this.#populated != null) {
|
||||
return this.#populated;
|
||||
}
|
||||
return !!populated;
|
||||
}
|
||||
/** Marks the collection as populated or not for serialization purposes. */
|
||||
populated(populated = true) {
|
||||
this.#populated = populated;
|
||||
}
|
||||
/** Initializes the collection by loading its items from the database. */
|
||||
async init(options = {}) {
|
||||
if (this.#dirty) {
|
||||
const items = [...this.#items];
|
||||
this.#dirty = false;
|
||||
await this.init(options);
|
||||
items.forEach(i => this.add(i));
|
||||
return this;
|
||||
}
|
||||
const em = this.getEntityManager();
|
||||
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
||||
if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
|
||||
const order = [...this.#items]; // copy order of references
|
||||
const orderBy = QueryHelper.mergeOrderBy(
|
||||
options.orderBy,
|
||||
this.property.orderBy,
|
||||
this.property.targetMeta?.orderBy,
|
||||
);
|
||||
const customOrder = orderBy.length > 0;
|
||||
const pivotTable = this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable();
|
||||
const loader = await em.getDataLoader(pivotTable ? 'm:n' : '1:m');
|
||||
const items = await loader.load([this, { ...options, orderBy }]);
|
||||
if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
this.#initialized = true;
|
||||
this.#dirty = false;
|
||||
if (!customOrder) {
|
||||
this.reorderItems(items, order);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
this.#items.clear();
|
||||
let i = 0;
|
||||
for (const item of items) {
|
||||
this.#items.add(item);
|
||||
this[i++] = item;
|
||||
}
|
||||
this.#initialized = true;
|
||||
this.#dirty = false;
|
||||
return this;
|
||||
}
|
||||
const populate = Array.isArray(options.populate)
|
||||
? options.populate.map(f => (f === '*' ? f : `${this.property.name}.${f}`))
|
||||
: [`${this.property.name}${options.ref ? ':ref' : ''}`];
|
||||
const schema = this.property.targetMeta.schema === '*' ? helper(this.owner).__schema : undefined;
|
||||
await em.populate(this.owner, populate, {
|
||||
refresh: true,
|
||||
...options,
|
||||
connectionType: options.connectionType,
|
||||
schema,
|
||||
where: { [this.property.name]: options.where },
|
||||
orderBy: { [this.property.name]: options.orderBy },
|
||||
});
|
||||
return this;
|
||||
}
|
||||
getEntityManager(items = [], required = true) {
|
||||
const wrapped = helper(this.owner);
|
||||
let em = wrapped.__em;
|
||||
if (!em) {
|
||||
for (const i of items) {
|
||||
if (i && helper(i).__em) {
|
||||
em = helper(i).__em;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!em && required) {
|
||||
throw ValidationError.entityNotManaged(this.owner);
|
||||
}
|
||||
return em;
|
||||
}
|
||||
createCondition(cond = {}) {
|
||||
if (this.property.kind === ReferenceKind.ONE_TO_MANY) {
|
||||
cond[this.property.mappedBy] = helper(this.owner).getPrimaryKey();
|
||||
} else {
|
||||
// MANY_TO_MANY
|
||||
this.createManyToManyCondition(cond);
|
||||
}
|
||||
return cond;
|
||||
}
|
||||
createManyToManyCondition(cond) {
|
||||
const dict = cond;
|
||||
if (this.property.owner || this.property.pivotTable) {
|
||||
// we know there is at least one item as it was checked in load method
|
||||
const pk = this.property.targetMeta.primaryKeys[0];
|
||||
dict[pk] = { $in: [] };
|
||||
this.#items.forEach(item => dict[pk].$in.push(helper(item).getPrimaryKey()));
|
||||
} else {
|
||||
dict[this.property.mappedBy] = helper(this.owner).getPrimaryKey();
|
||||
}
|
||||
}
|
||||
createLoadCountCondition(cond) {
|
||||
const wrapped = helper(this.owner);
|
||||
const val = wrapped.__meta.compositePK ? { $in: wrapped.__primaryKeys } : wrapped.getPrimaryKey();
|
||||
const dict = cond;
|
||||
if (this.property.kind === ReferenceKind.ONE_TO_MANY) {
|
||||
dict[this.property.mappedBy] = val;
|
||||
} else {
|
||||
const key = this.property.owner ? this.property.inversedBy : this.property.mappedBy;
|
||||
dict[key] = val;
|
||||
}
|
||||
return cond;
|
||||
}
|
||||
checkInitialized() {
|
||||
if (!this.isInitialized()) {
|
||||
throw new Error(
|
||||
`Collection<${this.property.type}> of entity ${helper(this.owner).__meta.name}[${helper(this.owner).getSerializedPrimaryKey()}] not initialized`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* re-orders items after searching with `$in` operator
|
||||
*/
|
||||
reorderItems(items, order) {
|
||||
if (this.property.kind === ReferenceKind.MANY_TO_MANY && this.property.owner) {
|
||||
items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
|
||||
}
|
||||
}
|
||||
cancelOrphanRemoval(items) {
|
||||
const em = this.getEntityManager(items, false);
|
||||
if (!em) {
|
||||
return;
|
||||
}
|
||||
for (const item of items) {
|
||||
em.getUnitOfWork().cancelOrphanRemoval(item);
|
||||
}
|
||||
}
|
||||
validateModification(items) {
|
||||
if (this.#readonly) {
|
||||
throw ValidationError.cannotModifyReadonlyCollection(this.owner, this.property);
|
||||
}
|
||||
const check = item => {
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
if (!Utils.isEntity(item)) {
|
||||
throw ValidationError.notEntity(this.owner, this.property, item);
|
||||
}
|
||||
// currently we allow persisting to inverse sides only in SQL drivers
|
||||
if (this.property.pivotTable || !this.property.mappedBy) {
|
||||
return false;
|
||||
}
|
||||
if (helper(item).__initialized) {
|
||||
return false;
|
||||
}
|
||||
return !item[this.property.mappedBy] && this.property.kind === ReferenceKind.MANY_TO_MANY;
|
||||
};
|
||||
// throw if we are modifying inverse side of M:N collection when owning side is initialized (would be ignored when persisting)
|
||||
if (items.some(item => check(item))) {
|
||||
throw ValidationError.cannotModifyInverseCollection(this.owner, this.property);
|
||||
}
|
||||
}
|
||||
/** Converts all items in the collection to plain DTO objects. */
|
||||
toArray() {
|
||||
if (this.#items.size === 0) {
|
||||
return [];
|
||||
}
|
||||
return this.map(item => wrap(item).toJSON());
|
||||
}
|
||||
/** Returns the primary key values (or a specific field) of all items in the collection. */
|
||||
getIdentifiers(field) {
|
||||
const items = this.getItems();
|
||||
const targetMeta = this.property.targetMeta;
|
||||
if (items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
field ??= targetMeta.compositePK
|
||||
? targetMeta.primaryKeys
|
||||
: (targetMeta.serializedPrimaryKey ?? targetMeta.primaryKeys[0]);
|
||||
const cb = (i, f) => {
|
||||
if (Utils.isEntity(i[f], true)) {
|
||||
return wrap(i[f], true).getPrimaryKey();
|
||||
}
|
||||
return i[f];
|
||||
};
|
||||
return items.map(i => {
|
||||
if (Array.isArray(field)) {
|
||||
return field.map(f => cb(i, f));
|
||||
}
|
||||
return cb(i, field);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
addWithoutPropagation(entity) {
|
||||
if (!this.contains(entity, false)) {
|
||||
this.incrementCount(1);
|
||||
this[this.#items.size] = entity;
|
||||
this.#items.add(entity);
|
||||
this.#dirty = true;
|
||||
}
|
||||
}
|
||||
/** Replaces all items in the collection with the given items. */
|
||||
set(items) {
|
||||
if (!this.#initialized) {
|
||||
this.#initialized = true;
|
||||
this.#snapshot = undefined;
|
||||
}
|
||||
if (this.compare(Utils.asArray(items).map(item => Reference.unwrapReference(item)))) {
|
||||
return;
|
||||
}
|
||||
this.remove(this.#items);
|
||||
this.add(items);
|
||||
}
|
||||
compare(items) {
|
||||
if (items.length !== this.#items.size) {
|
||||
return false;
|
||||
}
|
||||
let idx = 0;
|
||||
for (const item of this.#items) {
|
||||
if (item !== items[idx++]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
hydrate(items, forcePropagate, partial) {
|
||||
for (let i = 0; i < this.#items.size; i++) {
|
||||
delete this[i];
|
||||
}
|
||||
this.#initialized = true;
|
||||
this.#partial = !!partial;
|
||||
this.#items.clear();
|
||||
this.#count = 0;
|
||||
this.add(items);
|
||||
this.takeSnapshot(forcePropagate);
|
||||
}
|
||||
/**
|
||||
* Remove all items from the collection. Note that removing items from collection does not necessarily imply deleting the target entity,
|
||||
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
||||
* 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`,
|
||||
* which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
|
||||
*/
|
||||
removeAll() {
|
||||
if (!this.#initialized) {
|
||||
this.#initialized = true;
|
||||
this.#snapshot = undefined;
|
||||
}
|
||||
this.remove(this.#items);
|
||||
this.#dirty = true;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
removeWithoutPropagation(entity) {
|
||||
if (!this.#items.delete(entity)) {
|
||||
return;
|
||||
}
|
||||
this.incrementCount(-1);
|
||||
delete this[this.#items.size];
|
||||
Object.assign(this, [...this.#items]);
|
||||
this.#dirty = true;
|
||||
}
|
||||
/**
|
||||
* Extracts a slice of the collection items starting at position start to end (exclusive) of the collection.
|
||||
* If end is null it returns all elements from start to the end of the collection.
|
||||
*/
|
||||
slice(start = 0, end) {
|
||||
this.checkInitialized();
|
||||
let index = 0;
|
||||
end ??= this.#items.size;
|
||||
const items = [];
|
||||
for (const item of this.#items) {
|
||||
if (index === end) {
|
||||
break;
|
||||
}
|
||||
if (index >= start && index < end) {
|
||||
items.push(item);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
/**
|
||||
* Tests for the existence of an element that satisfies the given predicate.
|
||||
*/
|
||||
exists(cb) {
|
||||
this.checkInitialized();
|
||||
for (const item of this.#items) {
|
||||
if (cb(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the first element of this collection that satisfies the predicate.
|
||||
*/
|
||||
find(cb) {
|
||||
this.checkInitialized();
|
||||
let index = 0;
|
||||
for (const item of this.#items) {
|
||||
if (cb(item, index++)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Extracts a subset of the collection items.
|
||||
*/
|
||||
filter(cb) {
|
||||
this.checkInitialized();
|
||||
const items = [];
|
||||
let index = 0;
|
||||
for (const item of this.#items) {
|
||||
if (cb(item, index++)) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
/**
|
||||
* Maps the collection items based on your provided mapper function.
|
||||
*/
|
||||
map(mapper) {
|
||||
this.checkInitialized();
|
||||
const items = [];
|
||||
let index = 0;
|
||||
for (const item of this.#items) {
|
||||
items.push(mapper(item, index++));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
/**
|
||||
* Maps the collection items based on your provided mapper function to a single object.
|
||||
*/
|
||||
reduce(cb, initial = {}) {
|
||||
this.checkInitialized();
|
||||
let index = 0;
|
||||
for (const item of this.#items) {
|
||||
initial = cb(initial, item, index++);
|
||||
}
|
||||
return initial;
|
||||
}
|
||||
/**
|
||||
* Maps the collection items to a dictionary, indexed by the key you specify.
|
||||
* If there are more items with the same key, only the first one will be present.
|
||||
*/
|
||||
indexBy(key, valueKey) {
|
||||
return this.reduce((obj, item) => {
|
||||
obj[item[key]] ??= valueKey ? item[valueKey] : item;
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
/** Returns whether the collection has been initialized. Pass `fully = true` to also check that all items are initialized. */
|
||||
isInitialized(fully = false) {
|
||||
if (!this.#initialized || !fully) {
|
||||
return this.#initialized;
|
||||
}
|
||||
for (const item of this.#items) {
|
||||
if (!helper(item).__initialized) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
isDirty() {
|
||||
return this.#dirty;
|
||||
}
|
||||
/** Returns whether the collection was partially loaded (propagation is disabled for partial collections). */
|
||||
isPartial() {
|
||||
return this.#partial;
|
||||
}
|
||||
setDirty(dirty = true) {
|
||||
this.#dirty = dirty;
|
||||
}
|
||||
get length() {
|
||||
return this.count();
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
for (const item of this.getItems()) {
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
takeSnapshot(forcePropagate) {
|
||||
this.#snapshot = [...this.#items];
|
||||
this.#dirty = false;
|
||||
if (this.property.owner || forcePropagate) {
|
||||
this.#items.forEach(item => {
|
||||
this.propagate(item, 'takeSnapshot');
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getSnapshot() {
|
||||
return this.#snapshot;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get property() {
|
||||
// cannot be typed to `EntityProperty<O, T>` as it causes issues in assignability of `Loaded` type
|
||||
if (!this.#property) {
|
||||
const meta = wrap(this.owner, true).__meta;
|
||||
/* v8 ignore next */
|
||||
if (!meta) {
|
||||
throw MetadataError.fromUnknownEntity(
|
||||
this.owner.constructor.name,
|
||||
'Collection.property getter, maybe you just forgot to initialize the ORM?',
|
||||
);
|
||||
}
|
||||
this.#property = meta.relations.find(prop => this.owner[prop.name] === this);
|
||||
}
|
||||
return this.#property;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
set property(prop) {
|
||||
// cannot be typed to `EntityProperty<O, T>` as it causes issues in assignability of `Loaded` type
|
||||
this.#property = prop;
|
||||
}
|
||||
propagate(item, method) {
|
||||
if (this.property.owner && this.property.inversedBy) {
|
||||
this.propagateToInverseSide(item, method);
|
||||
} else if (!this.property.owner && this.property.mappedBy) {
|
||||
this.propagateToOwningSide(item, method);
|
||||
}
|
||||
}
|
||||
propagateToInverseSide(item, method) {
|
||||
const collection = item[this.property.inversedBy];
|
||||
if (this.shouldPropagateToCollection(collection, method)) {
|
||||
method = method === 'takeSnapshot' ? method : method + 'WithoutPropagation';
|
||||
collection[method](this.owner);
|
||||
}
|
||||
}
|
||||
propagateToOwningSide(item, method) {
|
||||
const mappedBy = this.property.mappedBy;
|
||||
const collection = item[mappedBy];
|
||||
if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
if (this.shouldPropagateToCollection(collection, method)) {
|
||||
collection[method](this.owner);
|
||||
}
|
||||
} else if (this.property.kind === ReferenceKind.ONE_TO_MANY && method !== 'takeSnapshot') {
|
||||
const prop2 = this.property.targetMeta.properties[mappedBy];
|
||||
const owner = prop2.mapToPk ? helper(this.owner).getPrimaryKey() : this.owner;
|
||||
const value = method === 'add' ? owner : null;
|
||||
if (this.property.orphanRemoval && method === 'remove') {
|
||||
// cache the PK before we propagate, as its value might be needed when flushing
|
||||
helper(item).__pk = helper(item).getPrimaryKey();
|
||||
}
|
||||
if (!prop2.nullable && prop2.deleteRule !== 'cascade' && method === 'remove') {
|
||||
if (!this.property.orphanRemoval) {
|
||||
throw ValidationError.cannotRemoveFromCollectionWithoutOrphanRemoval(this.owner, this.property);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// skip if already propagated
|
||||
if (Reference.unwrapReference(item[mappedBy]) !== value) {
|
||||
item[mappedBy] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
shouldPropagateToCollection(collection, method) {
|
||||
if (!collection) {
|
||||
return false;
|
||||
}
|
||||
switch (method) {
|
||||
case 'add':
|
||||
return !collection.contains(this.owner, false);
|
||||
case 'remove':
|
||||
return collection.isInitialized() && collection.contains(this.owner, false);
|
||||
case 'takeSnapshot':
|
||||
return collection.isDirty();
|
||||
}
|
||||
}
|
||||
incrementCount(value) {
|
||||
if (typeof this.#count === 'number' && this.#initialized) {
|
||||
this.#count += value;
|
||||
}
|
||||
}
|
||||
/** @ignore */
|
||||
[Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
|
||||
const object = { ...this };
|
||||
delete object.owner;
|
||||
object.initialized = this.#initialized;
|
||||
object.dirty = this.#dirty;
|
||||
const ret = inspect(object, { depth });
|
||||
const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
|
||||
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
||||
}
|
||||
}
|
||||
Object.defineProperties(Collection.prototype, {
|
||||
$: {
|
||||
get() {
|
||||
return this;
|
||||
},
|
||||
},
|
||||
get: {
|
||||
get() {
|
||||
return () => this;
|
||||
},
|
||||
},
|
||||
__collection: { value: true, enumerable: false, writable: false },
|
||||
});
|
||||
97
node_modules/@mikro-orm/core/entity/EntityAssigner.d.ts
generated
vendored
Normal file
97
node_modules/@mikro-orm/core/entity/EntityAssigner.d.ts
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type { EntityData, EntityDTO, EntityProperty, FromEntityType, IsSubset, MergeSelected } from '../typings.js';
|
||||
/** Handles assigning data to entities, resolving relations, and propagating changes. */
|
||||
export declare class EntityAssigner {
|
||||
/** Assigns the given data to the entity, resolving relations and handling custom types. */
|
||||
static assign<
|
||||
Entity extends object,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
|
||||
| EntityData<Naked, Convert>
|
||||
| Partial<EntityDTO<Naked>>,
|
||||
>(
|
||||
entity: Entity,
|
||||
data: Data & IsSubset<EntityData<Naked, Convert>, Data>,
|
||||
options?: AssignOptions<Convert>,
|
||||
): MergeSelected<Entity, Naked, keyof Data & string>;
|
||||
private static assignProperty;
|
||||
/**
|
||||
* auto-wire 1:1 inverse side with owner as in no-sql drivers it can't be joined
|
||||
* also makes sure the link is bidirectional when creating new entities from nested structures
|
||||
* @internal
|
||||
*/
|
||||
static autoWireOneToOne<T extends object, O extends object>(prop: EntityProperty<O, T>, entity: O): void;
|
||||
private static validateEM;
|
||||
private static assignReference;
|
||||
private static assignCollection;
|
||||
private static assignEmbeddable;
|
||||
private static createCollectionItem;
|
||||
}
|
||||
export declare const assign: typeof EntityAssigner.assign;
|
||||
/** Options controlling how data is assigned to an entity via `assign()`. */
|
||||
export interface AssignOptions<Convert extends boolean> {
|
||||
/**
|
||||
* Allows disabling processing of nested relations. When disabled, an object payload in place of a relation always
|
||||
* results in an `INSERT` query. To assign a value of the relation, use the foreign key instead of an object.
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
updateNestedEntities?: boolean;
|
||||
/**
|
||||
* When assigning to a relation property with object payload and `updateNestedEntities` enabled (default), you can
|
||||
* control how a payload without a primary key is handled. By default, it is considered as a new object, resulting
|
||||
* in an `INSERT` query. Use `updateByPrimaryKey: false` to allow assigning the data on an existing relation instead.
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
updateByPrimaryKey?: boolean;
|
||||
/**
|
||||
* When you have some properties in the payload that are not represented by an entity property mapping, you can skip
|
||||
* such unknown properties via `onlyProperties: true`. Defaults to `false`.
|
||||
*/
|
||||
onlyProperties?: boolean;
|
||||
/**
|
||||
* With `onlyOwnProperties` enabled, inverse sides of to-many relations are skipped, and payloads of other relations are converted
|
||||
* to foreign keys. Defaults to `false`.
|
||||
*/
|
||||
onlyOwnProperties?: boolean;
|
||||
/**
|
||||
* With `ignoreUndefined` enabled, `undefined` properties passed in the payload are skipped. Defaults to `false`.
|
||||
*/
|
||||
ignoreUndefined?: boolean;
|
||||
/**
|
||||
* `assign` excepts runtime values for properties using custom types. To be able to assign raw database values, you
|
||||
* can enable the `convertCustomTypes` option. Defaults to `false`.
|
||||
*/
|
||||
convertCustomTypes?: Convert;
|
||||
/**
|
||||
* When assigning to a JSON property, the value is replaced. Use `mergeObjectProperties: true` to enable deep merging
|
||||
* of the payload with the existing value. Defaults to `false`.
|
||||
*/
|
||||
mergeObjectProperties?: boolean;
|
||||
/**
|
||||
* When assigning to an embedded property, the values are deeply merged with the existing data.
|
||||
* Use `mergeEmbeddedProperties: false` to replace them instead. Defaults to `true`.
|
||||
*/
|
||||
mergeEmbeddedProperties?: boolean;
|
||||
/**
|
||||
* When assigning to a relation property, if the value is a POJO and `updateByPrimaryKey` is enabled, we check if
|
||||
* the target exists in the identity map based on its primary key and call `assign` on it recursively. If there is
|
||||
* no primary key provided, or the entity is not present in the context, such an entity is considered as new
|
||||
* (resulting in `INSERT` query), created via `em.create()`. You can use `merge: true` to use `em.merge()` instead,
|
||||
* which means there won't be any query used for persisting the relation. Defaults to `false`.
|
||||
*/
|
||||
merge?: boolean;
|
||||
/**
|
||||
* When assigning to a to-many relation properties (`Collection`) with `updateNestedEntities` and `updateByPrimaryKey`
|
||||
* enabled (default), you can use this option to override the relation schema. This is used only when trying to find
|
||||
* the entity reference in the current context. If it is not found, we create the relation entity using the target
|
||||
* entity schema. The value is automatically inferred from the target entity.
|
||||
*/
|
||||
schema?: string;
|
||||
/**
|
||||
* When using the static `assign()` helper, you can pass the EntityManager instance explicitly via the `em` option.
|
||||
* This is only needed when you try to assign a relation property. The value is automatically inferred from the target
|
||||
* entity when it is managed, or when you use `em.assign()` instead.
|
||||
*/
|
||||
em?: EntityManager;
|
||||
}
|
||||
251
node_modules/@mikro-orm/core/entity/EntityAssigner.js
generated
vendored
Normal file
251
node_modules/@mikro-orm/core/entity/EntityAssigner.js
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
import { Collection } from './Collection.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { ReferenceKind, SCALAR_TYPES } from '../enums.js';
|
||||
import { validateProperty } from './validators.js';
|
||||
import { helper, wrap } from './wrap.js';
|
||||
import { EntityHelper } from './EntityHelper.js';
|
||||
import { ValidationError } from '../errors.js';
|
||||
/** Handles assigning data to entities, resolving relations, and propagating changes. */
|
||||
export class EntityAssigner {
|
||||
/** Assigns the given data to the entity, resolving relations and handling custom types. */
|
||||
static assign(entity, data, options = {}) {
|
||||
let opts = options;
|
||||
if (opts.visited?.has(entity)) {
|
||||
return entity;
|
||||
}
|
||||
EntityHelper.ensurePropagation(entity);
|
||||
opts.visited ??= new Set();
|
||||
opts.visited.add(entity);
|
||||
const wrapped = helper(entity);
|
||||
opts = {
|
||||
...wrapped.__config.get('assign'),
|
||||
schema: wrapped.__schema,
|
||||
...opts, // allow overriding the defaults
|
||||
};
|
||||
const meta = wrapped.__meta;
|
||||
const props = meta.properties;
|
||||
Object.keys(data).forEach(prop => {
|
||||
return EntityAssigner.assignProperty(entity, prop, props, data, {
|
||||
...opts,
|
||||
em: opts.em || wrapped.__em,
|
||||
platform: wrapped.__platform,
|
||||
});
|
||||
});
|
||||
return entity;
|
||||
}
|
||||
static assignProperty(entity, propName, props, data, options) {
|
||||
let value = data[propName];
|
||||
const onlyProperties = options.onlyProperties && !(propName in props);
|
||||
const ignoreUndefined = options.ignoreUndefined === true && value === undefined;
|
||||
if (onlyProperties || ignoreUndefined) {
|
||||
return;
|
||||
}
|
||||
const prop = { ...props[propName], name: propName };
|
||||
if (prop && options.onlyOwnProperties) {
|
||||
if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
||||
return;
|
||||
}
|
||||
if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
||||
if (!prop.owner) {
|
||||
return;
|
||||
} else if (value?.map) {
|
||||
value = value.map(v => Utils.extractPK(v, prop.targetMeta));
|
||||
}
|
||||
}
|
||||
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
||||
value = Utils.extractPK(value, prop.targetMeta);
|
||||
}
|
||||
}
|
||||
if (propName in props && !prop.nullable && value == null) {
|
||||
throw new Error(
|
||||
`You must pass a non-${value} value to the property ${propName} of entity ${entity.constructor.name}.`,
|
||||
);
|
||||
}
|
||||
// create collection instance if its missing so old items can be deleted with orphan removal
|
||||
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop?.kind) && entity[prop.name] == null) {
|
||||
entity[prop.name] = Collection.create(entity, prop.name, undefined, helper(entity).isInitialized());
|
||||
}
|
||||
if (prop && Utils.isCollection(entity[prop.name])) {
|
||||
return EntityAssigner.assignCollection(entity, entity[prop.name], value, prop, options.em, options);
|
||||
}
|
||||
const customType = prop?.customType;
|
||||
if (options.convertCustomTypes && customType && prop.kind === ReferenceKind.SCALAR && !Utils.isEntity(data)) {
|
||||
value = customType.convertToJSValue(value, options.platform);
|
||||
}
|
||||
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop?.kind) && value != null) {
|
||||
if (
|
||||
options.updateNestedEntities &&
|
||||
Object.hasOwn(entity, propName) &&
|
||||
Utils.isEntity(entity[propName], true) &&
|
||||
Utils.isPlainObject(value)
|
||||
) {
|
||||
const unwrappedEntity = Reference.unwrapReference(entity[propName]);
|
||||
const wrapped = helper(unwrappedEntity);
|
||||
if (options.updateByPrimaryKey) {
|
||||
const pk = Utils.extractPK(value, prop.targetMeta);
|
||||
if (pk) {
|
||||
const ref = options.em.getReference(prop.targetMeta.class, pk, options);
|
||||
// if the PK differs, we want to change the target entity, not update it
|
||||
const wrappedChild = helper(ref);
|
||||
const sameTarget = wrappedChild.getSerializedPrimaryKey() === wrapped.getSerializedPrimaryKey();
|
||||
if (wrappedChild.__managed && wrappedChild.isInitialized() && sameTarget) {
|
||||
return EntityAssigner.assign(ref, value, options);
|
||||
}
|
||||
}
|
||||
return EntityAssigner.assignReference(entity, value, prop, options.em, options);
|
||||
}
|
||||
if (wrapped.__managed && wrap(unwrappedEntity).isInitialized()) {
|
||||
return EntityAssigner.assign(unwrappedEntity, value, options);
|
||||
}
|
||||
}
|
||||
return EntityAssigner.assignReference(entity, value, prop, options.em, options);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && (prop.setter || !prop.getter)) {
|
||||
validateProperty(prop, value, entity);
|
||||
return (entity[prop.name] = value);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.EMBEDDED && EntityAssigner.validateEM(options.em)) {
|
||||
return EntityAssigner.assignEmbeddable(entity, value, prop, options.em, options);
|
||||
}
|
||||
if (options.mergeObjectProperties && Utils.isPlainObject(entity[propName]) && Utils.isPlainObject(value)) {
|
||||
entity[propName] ??= {};
|
||||
entity[propName] = Utils.merge({}, entity[propName], value);
|
||||
} else if (!prop || prop.setter || !prop.getter) {
|
||||
entity[propName] = value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* auto-wire 1:1 inverse side with owner as in no-sql drivers it can't be joined
|
||||
* also makes sure the link is bidirectional when creating new entities from nested structures
|
||||
* @internal
|
||||
*/
|
||||
static autoWireOneToOne(prop, entity) {
|
||||
const ref = entity[prop.name];
|
||||
if (prop.kind !== ReferenceKind.ONE_TO_ONE || !Utils.isEntity(ref)) {
|
||||
return;
|
||||
}
|
||||
const meta2 = helper(ref).__meta;
|
||||
const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
|
||||
/* v8 ignore next */
|
||||
if (prop2 && !ref[prop2.name]) {
|
||||
if (Reference.isReference(ref)) {
|
||||
ref.unwrap()[prop2.name] = Reference.wrapReference(entity, prop2);
|
||||
} else {
|
||||
ref[prop2.name] = Reference.wrapReference(entity, prop2);
|
||||
}
|
||||
}
|
||||
}
|
||||
static validateEM(em) {
|
||||
if (!em) {
|
||||
throw new Error(
|
||||
`To use assign() on not managed entities, explicitly provide EM instance: wrap(entity).assign(data, { em: orm.em })`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static assignReference(entity, value, prop, em, options) {
|
||||
if (Utils.isEntity(value, true)) {
|
||||
entity[prop.name] = Reference.wrapReference(value, prop);
|
||||
} else if (Utils.isPrimaryKey(value, true) && EntityAssigner.validateEM(em)) {
|
||||
entity[prop.name] = prop.mapToPk
|
||||
? value
|
||||
: Reference.wrapReference(em.getReference(prop.targetMeta.class, value, options), prop);
|
||||
} else if (Utils.isPlainObject(value) && options.merge && EntityAssigner.validateEM(em)) {
|
||||
entity[prop.name] = Reference.wrapReference(em.merge(prop.targetMeta.class, value, options), prop);
|
||||
} else if (Utils.isPlainObject(value) && EntityAssigner.validateEM(em)) {
|
||||
entity[prop.name] = Reference.wrapReference(em.create(prop.targetMeta.class, value, options), prop);
|
||||
} else {
|
||||
const name = entity.constructor.name;
|
||||
throw new Error(
|
||||
`Invalid reference value provided for '${name}.${prop.name}' in ${name}.assign(): ${JSON.stringify(value)}`,
|
||||
);
|
||||
}
|
||||
EntityAssigner.autoWireOneToOne(prop, entity);
|
||||
}
|
||||
static assignCollection(entity, collection, value, prop, em, options) {
|
||||
const invalid = [];
|
||||
const items = Utils.asArray(value).map((item, idx) => {
|
||||
// try to propagate missing owning side reference to the payload first
|
||||
const prop2 = prop.targetMeta?.properties[prop.mappedBy];
|
||||
if (Utils.isPlainObject(item) && prop2 && item[prop2.name] == null) {
|
||||
item = { ...item, [prop2.name]: Reference.wrapReference(entity, prop2) };
|
||||
}
|
||||
if (options.updateNestedEntities && options.updateByPrimaryKey && Utils.isPlainObject(item)) {
|
||||
const pk = Utils.extractPK(item, prop.targetMeta);
|
||||
if (pk && EntityAssigner.validateEM(em)) {
|
||||
const ref = em.getUnitOfWork().getById(prop.targetMeta.class, pk, options.schema);
|
||||
if (ref) {
|
||||
return EntityAssigner.assign(ref, item, options);
|
||||
}
|
||||
}
|
||||
return this.createCollectionItem(item, em, prop, invalid, options);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (
|
||||
options.updateNestedEntities &&
|
||||
!options.updateByPrimaryKey &&
|
||||
collection[idx] &&
|
||||
helper(collection[idx])?.isInitialized()
|
||||
) {
|
||||
return EntityAssigner.assign(collection[idx], item, options);
|
||||
}
|
||||
return this.createCollectionItem(item, em, prop, invalid, options);
|
||||
});
|
||||
if (invalid.length > 0) {
|
||||
const name = entity.constructor.name;
|
||||
throw ValidationError.invalidCollectionValues(name, prop.name, invalid);
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
collection.set(items);
|
||||
} else {
|
||||
// append to the collection in case of assigning a single value instead of array
|
||||
collection.add(items);
|
||||
}
|
||||
}
|
||||
static assignEmbeddable(entity, value, prop, em, options) {
|
||||
const propName = prop.embedded ? prop.embedded[1] : prop.name;
|
||||
if (value == null) {
|
||||
entity[propName] = value;
|
||||
return;
|
||||
}
|
||||
// if the value is not an array, we just push, otherwise we replace the array
|
||||
if (prop.array && (Array.isArray(value) || entity[propName] == null)) {
|
||||
entity[propName] = [];
|
||||
}
|
||||
if (prop.array) {
|
||||
return Utils.asArray(value).forEach(item => {
|
||||
const tmp = {};
|
||||
this.assignEmbeddable(tmp, item, { ...prop, array: false }, em, options);
|
||||
entity[propName].push(...Object.values(tmp));
|
||||
});
|
||||
}
|
||||
const create = () =>
|
||||
EntityAssigner.validateEM(em) &&
|
||||
em.getEntityFactory().createEmbeddable(prop.targetMeta.class, value, {
|
||||
convertCustomTypes: options.convertCustomTypes,
|
||||
newEntity: options.mergeEmbeddedProperties ? !('propName' in entity) : true,
|
||||
});
|
||||
entity[propName] = options.mergeEmbeddedProperties ? entity[propName] || create() : create();
|
||||
Object.keys(value).forEach(key => {
|
||||
EntityAssigner.assignProperty(entity[propName], key, prop.embeddedProps, value, options);
|
||||
});
|
||||
}
|
||||
static createCollectionItem(item, em, prop, invalid, options) {
|
||||
if (Utils.isEntity(item)) {
|
||||
return item;
|
||||
}
|
||||
if (Utils.isPrimaryKey(item) && EntityAssigner.validateEM(em)) {
|
||||
return em.getReference(prop.targetMeta.class, item, options);
|
||||
}
|
||||
if (Utils.isPlainObject(item) && options.merge && EntityAssigner.validateEM(em)) {
|
||||
return em.merge(prop.targetMeta.class, item, options);
|
||||
}
|
||||
if (Utils.isPlainObject(item) && EntityAssigner.validateEM(em)) {
|
||||
return em.create(prop.targetMeta.class, item, options);
|
||||
}
|
||||
invalid.push(item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
export const assign = EntityAssigner.assign;
|
||||
75
node_modules/@mikro-orm/core/entity/EntityFactory.d.ts
generated
vendored
Normal file
75
node_modules/@mikro-orm/core/entity/EntityFactory.d.ts
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
import type { EntityData, EntityMetadata, EntityName, New, Primary } from '../typings.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type { EntityComparator } from '../utils/EntityComparator.js';
|
||||
/** @internal Options for creating and merging entities via the EntityFactory. */
|
||||
export interface FactoryOptions {
|
||||
/** Whether the entity should be marked as initialized. */
|
||||
initialized?: boolean;
|
||||
/** Whether the entity is being newly created (uses constructor). */
|
||||
newEntity?: boolean;
|
||||
/**
|
||||
* Property `onCreate` hooks are normally executed during `flush` operation.
|
||||
* With this option, they will be processed early inside `em.create()` method.
|
||||
*/
|
||||
processOnCreateHooksEarly?: boolean;
|
||||
/** Whether to merge the entity into the identity map. */
|
||||
merge?: boolean;
|
||||
/** Whether to refresh an already loaded entity with new data. */
|
||||
refresh?: boolean;
|
||||
/** Whether to convert custom types during hydration. */
|
||||
convertCustomTypes?: boolean;
|
||||
/** Whether to recompute the entity snapshot after creation. */
|
||||
recomputeSnapshot?: boolean;
|
||||
/** Schema from FindOptions, overrides default schema. */
|
||||
schema?: string;
|
||||
/** Parent entity schema for nested entity creation. */
|
||||
parentSchema?: string;
|
||||
/** Whether to normalize accessors to the correct property names (normally handled via result mapper). */
|
||||
normalizeAccessors?: boolean;
|
||||
/**
|
||||
* Property name to use for identity map lookup instead of the primary key.
|
||||
* This is useful for creating references by unique non-PK properties.
|
||||
*/
|
||||
key?: string;
|
||||
}
|
||||
/** @internal Factory responsible for creating, merging, and hydrating entity instances. */
|
||||
export declare class EntityFactory {
|
||||
#private;
|
||||
constructor(em: EntityManager);
|
||||
/** Creates a new entity instance or returns an existing one from the identity map, hydrating it with the provided data. */
|
||||
create<T extends object, P extends string = string>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityData<T>,
|
||||
options?: FactoryOptions,
|
||||
): New<T, P>;
|
||||
/** Merges new data into an existing entity, preserving user-modified properties. */
|
||||
mergeData<T extends object>(meta: EntityMetadata<T>, entity: T, data: EntityData<T>, options?: FactoryOptions): void;
|
||||
/** Creates or retrieves an uninitialized entity reference by its primary key or alternate key. */
|
||||
createReference<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
id: Primary<T> | Primary<T>[] | Record<string, Primary<T>>,
|
||||
options?: Pick<FactoryOptions, 'merge' | 'convertCustomTypes' | 'schema' | 'key'>,
|
||||
): T;
|
||||
/** Creates an embeddable entity instance from the provided data. */
|
||||
createEmbeddable<T extends object>(
|
||||
entityName: EntityName<T>,
|
||||
data: EntityData<T>,
|
||||
options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>,
|
||||
): T;
|
||||
/** Returns the EntityComparator instance used for diffing entities. */
|
||||
getComparator(): EntityComparator;
|
||||
private createEntity;
|
||||
private assignDefaultValues;
|
||||
private hydrate;
|
||||
private findEntity;
|
||||
private processDiscriminatorColumn;
|
||||
/**
|
||||
* denormalize PK to value required by driver (e.g. ObjectId)
|
||||
*/
|
||||
private denormalizePrimaryKey;
|
||||
/**
|
||||
* returns parameters for entity constructor, creating references from plain ids
|
||||
*/
|
||||
private extractConstructorParams;
|
||||
private get unitOfWork();
|
||||
}
|
||||
458
node_modules/@mikro-orm/core/entity/EntityFactory.js
generated
vendored
Normal file
458
node_modules/@mikro-orm/core/entity/EntityFactory.js
generated
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { QueryHelper } from '../utils/QueryHelper.js';
|
||||
import { EventType, ReferenceKind } from '../enums.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { helper } from './wrap.js';
|
||||
import { EntityHelper } from './EntityHelper.js';
|
||||
import { JsonType } from '../types/JsonType.js';
|
||||
import { isRaw } from '../utils/RawQueryFragment.js';
|
||||
/** @internal Factory responsible for creating, merging, and hydrating entity instances. */
|
||||
export class EntityFactory {
|
||||
#driver;
|
||||
#platform;
|
||||
#config;
|
||||
#metadata;
|
||||
#hydrator;
|
||||
#eventManager;
|
||||
#comparator;
|
||||
#em;
|
||||
constructor(em) {
|
||||
this.#em = em;
|
||||
this.#driver = this.#em.getDriver();
|
||||
this.#platform = this.#driver.getPlatform();
|
||||
this.#config = this.#em.config;
|
||||
this.#metadata = this.#em.getMetadata();
|
||||
this.#hydrator = this.#config.getHydrator(this.#metadata);
|
||||
this.#eventManager = this.#em.getEventManager();
|
||||
this.#comparator = this.#em.getComparator();
|
||||
}
|
||||
/** Creates a new entity instance or returns an existing one from the identity map, hydrating it with the provided data. */
|
||||
create(entityName, data, options = {}) {
|
||||
data = Reference.unwrapReference(data);
|
||||
options.initialized ??= true;
|
||||
if (data.__entity) {
|
||||
return data;
|
||||
}
|
||||
const meta = this.#metadata.get(entityName);
|
||||
if (meta.virtual) {
|
||||
data = { ...data };
|
||||
const entity = this.createEntity(data, meta, options);
|
||||
this.hydrate(entity, meta, data, options);
|
||||
return entity;
|
||||
}
|
||||
if (meta.serializedPrimaryKey) {
|
||||
this.denormalizePrimaryKey(meta, data);
|
||||
}
|
||||
const meta2 = this.processDiscriminatorColumn(meta, data);
|
||||
const exists = this.findEntity(data, meta2, options);
|
||||
let wrapped = exists && helper(exists);
|
||||
if (wrapped && !options.refresh) {
|
||||
wrapped.__processing = true;
|
||||
Utils.dropUndefinedProperties(data);
|
||||
this.mergeData(meta2, exists, data, options);
|
||||
wrapped.__processing = false;
|
||||
if (wrapped.isInitialized()) {
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
data = { ...data };
|
||||
const entity = exists ?? this.createEntity(data, meta2, options);
|
||||
wrapped = helper(entity);
|
||||
wrapped.__processing = true;
|
||||
wrapped.__initialized = options.initialized;
|
||||
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
||||
const tmp = { ...data };
|
||||
meta.constructorParams?.forEach(prop => delete tmp[prop]);
|
||||
this.hydrate(entity, meta2, tmp, options);
|
||||
// since we now process only a copy of the `data` via hydrator, but later we register the state with the full snapshot,
|
||||
// we need to go through all props with custom types that have `ensureComparable: true` and ensure they are comparable
|
||||
// even if they are not part of constructor parameters (as this is otherwise normalized during hydration, here only in `tmp`)
|
||||
if (options.convertCustomTypes) {
|
||||
for (const prop of meta.props) {
|
||||
if (prop.customType?.ensureComparable(meta, prop) && data[prop.name]) {
|
||||
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
||||
Utils.isPlainObject(data[prop.name])
|
||||
) {
|
||||
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
||||
}
|
||||
if (prop.customType instanceof JsonType && this.#platform.convertsJsonAutomatically()) {
|
||||
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.#platform, {
|
||||
key: prop.name,
|
||||
mode: 'hydration',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.hydrate(entity, meta2, data, options);
|
||||
}
|
||||
if (exists && meta.root.inheritanceType && !(entity instanceof meta2.class)) {
|
||||
Object.setPrototypeOf(entity, meta2.prototype);
|
||||
}
|
||||
if (options.merge && wrapped.hasPrimaryKey()) {
|
||||
this.unitOfWork.register(entity, data, {
|
||||
// Always refresh to ensure the payload is in correct shape for joined strategy. When loading nested relations,
|
||||
// they will be created early without `Type.ensureComparable` being properly handled, resulting in extra updates.
|
||||
refresh: options.initialized,
|
||||
newEntity: options.newEntity,
|
||||
loaded: options.initialized,
|
||||
});
|
||||
if (options.recomputeSnapshot) {
|
||||
wrapped.__originalEntityData = this.#comparator.prepareEntity(entity);
|
||||
}
|
||||
}
|
||||
if (this.#eventManager.hasListeners(EventType.onInit, meta2)) {
|
||||
this.#eventManager.dispatchEvent(EventType.onInit, { entity, meta: meta2, em: this.#em });
|
||||
}
|
||||
wrapped.__processing = false;
|
||||
return entity;
|
||||
}
|
||||
/** Merges new data into an existing entity, preserving user-modified properties. */
|
||||
mergeData(meta, entity, data, options = {}) {
|
||||
// merge unchanged properties automatically
|
||||
data = QueryHelper.processParams(data);
|
||||
const existsData = this.#comparator.prepareEntity(entity);
|
||||
const originalEntityData = helper(entity).__originalEntityData ?? {};
|
||||
const diff = this.#comparator.diffEntities(meta.class, originalEntityData, existsData);
|
||||
// version properties are not part of entity snapshots
|
||||
if (
|
||||
meta.versionProperty &&
|
||||
data[meta.versionProperty] &&
|
||||
data[meta.versionProperty] !== originalEntityData[meta.versionProperty]
|
||||
) {
|
||||
diff[meta.versionProperty] = data[meta.versionProperty];
|
||||
}
|
||||
const diff2 = this.#comparator.diffEntities(meta.class, existsData, data, { includeInverseSides: true });
|
||||
// do not override values changed by user
|
||||
Utils.keys(diff).forEach(key => delete diff2[key]);
|
||||
Utils.keys(diff2)
|
||||
.filter(key => {
|
||||
// ignore null values if there is already present non-null value
|
||||
if (existsData[key] != null) {
|
||||
return diff2[key] == null;
|
||||
}
|
||||
return diff2[key] === undefined;
|
||||
})
|
||||
.forEach(key => delete diff2[key]);
|
||||
// but always add collection properties and formulas if they are part of the `data`
|
||||
Utils.keys(data)
|
||||
.filter(
|
||||
key =>
|
||||
meta.properties[key]?.formula ||
|
||||
[ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(meta.properties[key]?.kind),
|
||||
)
|
||||
.forEach(key => (diff2[key] = data[key]));
|
||||
// rehydrated with the new values, skip those changed by user
|
||||
// use full hydration if the entity is already initialized, even if the caller used `initialized: false`
|
||||
// (e.g. from createReference), otherwise scalar properties in diff2 won't be applied
|
||||
const initialized = options.initialized || helper(entity).__initialized;
|
||||
this.hydrate(entity, meta, diff2, initialized ? { ...options, initialized } : options);
|
||||
// we need to update the entity data only with keys that were not present before
|
||||
const nullVal = this.#config.get('forceUndefined') ? undefined : null;
|
||||
Utils.keys(diff2).forEach(key => {
|
||||
const prop = meta.properties[key];
|
||||
if (
|
||||
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
||||
Utils.isPlainObject(data[prop.name])
|
||||
) {
|
||||
// oxfmt-ignore
|
||||
diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
|
||||
}
|
||||
if (
|
||||
!options.convertCustomTypes &&
|
||||
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) &&
|
||||
prop.customType?.ensureComparable(meta, prop) &&
|
||||
diff2[key] != null
|
||||
) {
|
||||
const converted = prop.customType.convertToJSValue(diff2[key], this.#platform, { force: true });
|
||||
diff2[key] = prop.customType.convertToDatabaseValue(converted, this.#platform, { fromQuery: true });
|
||||
}
|
||||
originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
|
||||
helper(entity).__loadedProperties.add(key);
|
||||
});
|
||||
// in case of joined loading strategy, we need to cascade the merging to possibly loaded relations manually
|
||||
meta.relations.forEach(prop => {
|
||||
if (
|
||||
[ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind) &&
|
||||
Array.isArray(data[prop.name])
|
||||
) {
|
||||
// instead of trying to match the collection items (which could easily fail if the collection was loaded with different ordering),
|
||||
// we just create the entity from scratch, which will automatically pick the right one from the identity map and call `mergeData` on it
|
||||
data[prop.name]
|
||||
.filter(child => Utils.isPlainObject(child)) // objects with prototype can be PKs (e.g. `ObjectId`)
|
||||
.forEach(child => this.create(prop.targetMeta.class, child, options)); // we can ignore the value, we just care about the `mergeData` call
|
||||
return;
|
||||
}
|
||||
if (
|
||||
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
||||
Utils.isPlainObject(data[prop.name]) &&
|
||||
entity[prop.name] &&
|
||||
helper(entity[prop.name]).__initialized
|
||||
) {
|
||||
this.create(prop.targetMeta.class, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
|
||||
}
|
||||
});
|
||||
this.unitOfWork.normalizeEntityData(meta, originalEntityData);
|
||||
}
|
||||
/** Creates or retrieves an uninitialized entity reference by its primary key or alternate key. */
|
||||
createReference(entityName, id, options = {}) {
|
||||
options.convertCustomTypes ??= true;
|
||||
const meta = this.#metadata.get(entityName);
|
||||
const schema = this.#driver.getSchemaName(meta, options);
|
||||
// Handle alternate key lookup
|
||||
if (options.key) {
|
||||
const value = '' + (Array.isArray(id) ? id[0] : Utils.isPlainObject(id) ? id[options.key] : id);
|
||||
const exists = this.unitOfWork.getByKey(entityName, options.key, value, schema, options.convertCustomTypes);
|
||||
if (exists) {
|
||||
return exists;
|
||||
}
|
||||
// Create entity stub - storeByKey will set the alternate key property and store in identity map
|
||||
const entity = this.create(entityName, {}, { ...options, initialized: false });
|
||||
this.unitOfWork.storeByKey(entity, options.key, value, schema, options.convertCustomTypes);
|
||||
return entity;
|
||||
}
|
||||
if (meta.simplePK) {
|
||||
const exists = this.unitOfWork.getById(entityName, id, schema);
|
||||
if (exists) {
|
||||
return exists;
|
||||
}
|
||||
const data = Utils.isPlainObject(id) ? id : { [meta.primaryKeys[0]]: Array.isArray(id) ? id[0] : id };
|
||||
return this.create(entityName, data, { ...options, initialized: false });
|
||||
}
|
||||
if (Array.isArray(id)) {
|
||||
id = Utils.getPrimaryKeyCondFromArray(id, meta);
|
||||
}
|
||||
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.#platform);
|
||||
const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
|
||||
if (exists) {
|
||||
return exists;
|
||||
}
|
||||
if (Utils.isPrimaryKey(id)) {
|
||||
id = { [meta.primaryKeys[0]]: id };
|
||||
}
|
||||
return this.create(entityName, id, { ...options, initialized: false });
|
||||
}
|
||||
/** Creates an embeddable entity instance from the provided data. */
|
||||
createEmbeddable(entityName, data, options = {}) {
|
||||
data = { ...data };
|
||||
const meta = this.#metadata.get(entityName);
|
||||
const meta2 = this.processDiscriminatorColumn(meta, data);
|
||||
return this.createEntity(data, meta2, options);
|
||||
}
|
||||
/** Returns the EntityComparator instance used for diffing entities. */
|
||||
getComparator() {
|
||||
return this.#comparator;
|
||||
}
|
||||
createEntity(data, meta, options) {
|
||||
const schema = this.#driver.getSchemaName(meta, options);
|
||||
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
||||
if (meta.polymorphs) {
|
||||
throw new Error(`Cannot create entity ${meta.className}, class prototype is unknown`);
|
||||
}
|
||||
const params = this.extractConstructorParams(meta, data, options);
|
||||
const Entity = meta.class;
|
||||
// creates new instance via constructor as this is the new entity
|
||||
const entity = new Entity(...params);
|
||||
// creating managed entity instance when `forceEntityConstructor` is enabled,
|
||||
// we need to wipe all the values as they would cause update queries on next flush
|
||||
if (!options.newEntity && (meta.forceConstructor || this.#config.get('forceEntityConstructor'))) {
|
||||
meta.props
|
||||
.filter(prop => prop.persist !== false && !prop.primary && data[prop.name] === undefined)
|
||||
.forEach(prop => delete entity[prop.name]);
|
||||
}
|
||||
if (meta.virtual) {
|
||||
return entity;
|
||||
}
|
||||
helper(entity).__schema = schema;
|
||||
if (options.initialized) {
|
||||
EntityHelper.ensurePropagation(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
// creates new entity instance, bypassing constructor call as its already persisted entity
|
||||
const entity = Object.create(meta.class.prototype);
|
||||
helper(entity).__managed = true;
|
||||
helper(entity).__processing = !meta.embeddable && !meta.virtual;
|
||||
helper(entity).__schema = schema;
|
||||
if (options.merge && !options.newEntity) {
|
||||
this.#hydrator.hydrateReference(
|
||||
entity,
|
||||
meta,
|
||||
data,
|
||||
this,
|
||||
options.convertCustomTypes,
|
||||
options.schema,
|
||||
options.parentSchema,
|
||||
);
|
||||
this.unitOfWork.register(entity);
|
||||
}
|
||||
if (options.initialized) {
|
||||
EntityHelper.ensurePropagation(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
assignDefaultValues(entity, meta) {
|
||||
for (const prop of meta.props) {
|
||||
if (prop.embedded || [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
||||
continue;
|
||||
}
|
||||
if (prop.onCreate) {
|
||||
entity[prop.name] ??= prop.onCreate(entity, this.#em);
|
||||
} else if (prop.default != null && !isRaw(prop.default) && entity[prop.name] === undefined) {
|
||||
entity[prop.name] = prop.default;
|
||||
}
|
||||
if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
|
||||
const items = prop.array ? entity[prop.name] : [entity[prop.name]];
|
||||
for (const item of items) {
|
||||
this.assignDefaultValues(item, prop.targetMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hydrate(entity, meta, data, options) {
|
||||
if (options.initialized) {
|
||||
this.#hydrator.hydrate(
|
||||
entity,
|
||||
meta,
|
||||
data,
|
||||
this,
|
||||
'full',
|
||||
options.newEntity,
|
||||
options.convertCustomTypes,
|
||||
options.schema,
|
||||
this.#driver.getSchemaName(meta, options),
|
||||
options.normalizeAccessors,
|
||||
);
|
||||
} else {
|
||||
this.#hydrator.hydrateReference(
|
||||
entity,
|
||||
meta,
|
||||
data,
|
||||
this,
|
||||
options.convertCustomTypes,
|
||||
options.schema,
|
||||
this.#driver.getSchemaName(meta, options),
|
||||
options.normalizeAccessors,
|
||||
);
|
||||
}
|
||||
Utils.keys(data).forEach(key => {
|
||||
helper(entity)?.__loadedProperties.add(key);
|
||||
helper(entity)?.__serializationContext.fields?.add(key);
|
||||
});
|
||||
const processOnCreateHooksEarly =
|
||||
options.processOnCreateHooksEarly ?? this.#config.get('processOnCreateHooksEarly');
|
||||
if (options.newEntity && processOnCreateHooksEarly) {
|
||||
this.assignDefaultValues(entity, meta);
|
||||
}
|
||||
}
|
||||
findEntity(data, meta, options) {
|
||||
const schema = this.#driver.getSchemaName(meta, options);
|
||||
if (meta.simplePK) {
|
||||
return this.unitOfWork.getById(meta.class, data[meta.primaryKeys[0]], schema);
|
||||
}
|
||||
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
||||
return undefined;
|
||||
}
|
||||
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.#platform, options.convertCustomTypes);
|
||||
return this.unitOfWork.getById(meta.class, pks, schema);
|
||||
}
|
||||
processDiscriminatorColumn(meta, data) {
|
||||
// Handle STI discriminator (persisted column)
|
||||
if (meta.root.inheritanceType === 'sti') {
|
||||
const prop = meta.properties[meta.root.discriminatorColumn];
|
||||
const value = data[prop.name];
|
||||
const type = meta.root.discriminatorMap[value];
|
||||
meta = type ? this.#metadata.get(type) : meta;
|
||||
return meta;
|
||||
}
|
||||
// Handle TPT discriminator (computed at query time)
|
||||
if (meta.root.inheritanceType === 'tpt' && meta.root.discriminatorMap) {
|
||||
const value = data[meta.root.tptDiscriminatorColumn];
|
||||
if (value) {
|
||||
const type = meta.root.discriminatorMap[value];
|
||||
meta = type ? this.#metadata.get(type) : meta;
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
/**
|
||||
* denormalize PK to value required by driver (e.g. ObjectId)
|
||||
*/
|
||||
denormalizePrimaryKey(meta, data) {
|
||||
const pk = meta.getPrimaryProp();
|
||||
const spk = meta.properties[meta.serializedPrimaryKey];
|
||||
if (!spk?.serializedPrimaryKey) {
|
||||
return;
|
||||
}
|
||||
if (pk.type === 'ObjectId' && (data[pk.name] != null || data[spk.name] != null)) {
|
||||
data[pk.name] = this.#platform.denormalizePrimaryKey(data[spk.name] || data[pk.name]);
|
||||
delete data[spk.name];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* returns parameters for entity constructor, creating references from plain ids
|
||||
*/
|
||||
extractConstructorParams(meta, data, options) {
|
||||
if (!meta.constructorParams) {
|
||||
return [data];
|
||||
}
|
||||
return meta.constructorParams.map(k => {
|
||||
const prop = meta.properties[k];
|
||||
const value = data[k];
|
||||
if (prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && value) {
|
||||
const pk = Reference.unwrapReference(value);
|
||||
const entity = this.unitOfWork.getById(prop.targetMeta.class, pk, options.schema, true);
|
||||
if (entity) {
|
||||
return entity;
|
||||
}
|
||||
if (Utils.isEntity(value)) {
|
||||
return value;
|
||||
}
|
||||
const nakedPk = Utils.extractPK(value, prop.targetMeta, true);
|
||||
if (Utils.isObject(value) && !nakedPk) {
|
||||
return this.create(prop.targetMeta.class, value, options);
|
||||
}
|
||||
const { newEntity, initialized, ...rest } = options;
|
||||
const target = this.createReference(prop.targetMeta.class, nakedPk, rest);
|
||||
return Reference.wrapReference(target, prop);
|
||||
}
|
||||
if (prop?.kind === ReferenceKind.EMBEDDED && value) {
|
||||
/* v8 ignore next */
|
||||
if (Utils.isEntity(value)) {
|
||||
return value;
|
||||
}
|
||||
return this.createEmbeddable(prop.targetMeta.class, value, options);
|
||||
}
|
||||
if (!prop) {
|
||||
const tmp = { ...data };
|
||||
for (const prop of meta.props) {
|
||||
if (!options.convertCustomTypes || !prop.customType || tmp[prop.name] == null) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
||||
Utils.isPlainObject(tmp[prop.name]) &&
|
||||
!Utils.extractPK(tmp[prop.name], prop.targetMeta, true)
|
||||
) {
|
||||
tmp[prop.name] = Reference.wrapReference(this.create(prop.targetMeta.class, tmp[prop.name], options), prop);
|
||||
} else if (prop.kind === ReferenceKind.SCALAR) {
|
||||
tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this.#platform);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
if (options.convertCustomTypes && prop.customType && value != null) {
|
||||
return prop.customType.convertToJSValue(value, this.#platform);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
get unitOfWork() {
|
||||
return this.#em.getUnitOfWork(false);
|
||||
}
|
||||
}
|
||||
41
node_modules/@mikro-orm/core/entity/EntityHelper.d.ts
generated
vendored
Normal file
41
node_modules/@mikro-orm/core/entity/EntityHelper.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import { type EntityMetadata, type EntityProperty, type IHydrator } from '../typings.js';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export declare class EntityHelper {
|
||||
static decorate<T extends object>(meta: EntityMetadata<T>, em: EntityManager): void;
|
||||
/**
|
||||
* As a performance optimization, we create entity state methods lazily. We first add
|
||||
* the `null` value to the prototype to reserve space in memory. Then we define a setter on the
|
||||
* prototype that will be executed exactly once per entity instance. There we redefine the given
|
||||
* property on the entity instance, so shadowing the prototype setter.
|
||||
*/
|
||||
private static defineBaseProperties;
|
||||
/**
|
||||
* Defines getter and setter for every owning side of m:1 and 1:1 relation. This is then used for propagation of
|
||||
* changes to the inverse side of bi-directional relations. Rest of the properties are also defined this way to
|
||||
* achieve dirtiness, which is then used for fast checks whether we need to auto-flush because of managed entities.
|
||||
*
|
||||
* First defines a setter on the prototype, once called, actual get/set handlers are registered on the instance rather
|
||||
* than on its prototype. Thanks to this we still have those properties enumerable (e.g. part of `Object.keys(entity)`).
|
||||
*/
|
||||
private static defineProperties;
|
||||
static defineCustomInspect<T extends object>(meta: EntityMetadata<T>): void;
|
||||
static defineReferenceProperty<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
prop: EntityProperty<T>,
|
||||
ref: T,
|
||||
hydrator: IHydrator,
|
||||
): void;
|
||||
static propagate<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
entity: T,
|
||||
owner: T,
|
||||
prop: EntityProperty<T>,
|
||||
value?: T[keyof T & string],
|
||||
old?: T,
|
||||
): void;
|
||||
private static propagateOneToOne;
|
||||
static ensurePropagation<T extends object>(entity: T): void;
|
||||
}
|
||||
311
node_modules/@mikro-orm/core/entity/EntityHelper.js
generated
vendored
Normal file
311
node_modules/@mikro-orm/core/entity/EntityHelper.js
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
import {
|
||||
EagerProps,
|
||||
EntityName,
|
||||
EntityRepositoryType,
|
||||
HiddenProps,
|
||||
OptionalProps,
|
||||
PrimaryKeyProp,
|
||||
} from '../typings.js';
|
||||
import { EntityTransformer } from '../serialization/EntityTransformer.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { WrappedEntity } from './WrappedEntity.js';
|
||||
import { ReferenceKind } from '../enums.js';
|
||||
import { helper } from './wrap.js';
|
||||
import { inspect } from '../logging/inspect.js';
|
||||
import { getEnv } from '../utils/env-vars.js';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class EntityHelper {
|
||||
static decorate(meta, em) {
|
||||
const fork = em.fork(); // use fork so we can access `EntityFactory`
|
||||
const serializedPrimaryKey = meta.props.find(p => p.serializedPrimaryKey);
|
||||
if (serializedPrimaryKey) {
|
||||
Object.defineProperty(meta.prototype, serializedPrimaryKey.name, {
|
||||
get() {
|
||||
return this._id ? em.getPlatform().normalizePrimaryKey(this._id) : null;
|
||||
},
|
||||
set(id) {
|
||||
this._id = id ? em.getPlatform().denormalizePrimaryKey(id) : null;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
EntityHelper.defineBaseProperties(meta, meta.prototype, fork);
|
||||
EntityHelper.defineCustomInspect(meta);
|
||||
if (em.config.get('propagationOnPrototype') && !meta.embeddable && !meta.virtual) {
|
||||
EntityHelper.defineProperties(meta, fork);
|
||||
}
|
||||
const prototype = meta.prototype;
|
||||
if (!prototype.toJSON) {
|
||||
// toJSON can be overridden
|
||||
Object.defineProperty(prototype, 'toJSON', {
|
||||
value: function (...args) {
|
||||
// Guard against being called on the prototype itself (e.g. by serializers
|
||||
// walking the object graph and calling toJSON on prototype objects)
|
||||
if (this === prototype) {
|
||||
return {};
|
||||
}
|
||||
return EntityTransformer.toObject(this, ...args);
|
||||
},
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* As a performance optimization, we create entity state methods lazily. We first add
|
||||
* the `null` value to the prototype to reserve space in memory. Then we define a setter on the
|
||||
* prototype that will be executed exactly once per entity instance. There we redefine the given
|
||||
* property on the entity instance, so shadowing the prototype setter.
|
||||
*/
|
||||
static defineBaseProperties(meta, prototype, em) {
|
||||
// oxfmt-ignore
|
||||
const helperParams = meta.embeddable || meta.virtual ? [] : [em.getComparator().getPkGetter(meta), em.getComparator().getPkSerializer(meta), em.getComparator().getPkGetterConverted(meta)];
|
||||
Object.defineProperties(prototype, {
|
||||
__entity: { value: !meta.embeddable, configurable: true },
|
||||
__meta: { value: meta, configurable: true },
|
||||
__config: { value: em.config, configurable: true },
|
||||
__platform: { value: em.getPlatform(), configurable: true },
|
||||
__factory: { value: em.getEntityFactory(), configurable: true },
|
||||
__helper: {
|
||||
get() {
|
||||
Object.defineProperty(this, '__helper', {
|
||||
value: new WrappedEntity(this, em.getHydrator(), ...helperParams),
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
return this.__helper;
|
||||
},
|
||||
configurable: true, // otherwise jest fails when trying to compare entities ¯\_(ツ)_/¯
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Defines getter and setter for every owning side of m:1 and 1:1 relation. This is then used for propagation of
|
||||
* changes to the inverse side of bi-directional relations. Rest of the properties are also defined this way to
|
||||
* achieve dirtiness, which is then used for fast checks whether we need to auto-flush because of managed entities.
|
||||
*
|
||||
* First defines a setter on the prototype, once called, actual get/set handlers are registered on the instance rather
|
||||
* than on its prototype. Thanks to this we still have those properties enumerable (e.g. part of `Object.keys(entity)`).
|
||||
*/
|
||||
static defineProperties(meta, em) {
|
||||
Object.values(meta.properties).forEach(prop => {
|
||||
const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
|
||||
// oxfmt-ignore
|
||||
const isReference = [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
|
||||
if (isReference) {
|
||||
Object.defineProperty(meta.prototype, prop.name, {
|
||||
set(val) {
|
||||
EntityHelper.defineReferenceProperty(meta, prop, this, em.getHydrator());
|
||||
this[prop.name] = val;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.embedded || isCollection) {
|
||||
return;
|
||||
}
|
||||
Object.defineProperty(meta.prototype, prop.name, {
|
||||
set(val) {
|
||||
Object.defineProperty(this, prop.name, {
|
||||
get() {
|
||||
return this.__helper?.__data[prop.name];
|
||||
},
|
||||
set(val) {
|
||||
this.__helper.__data[prop.name] = val;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
this.__helper.__data[prop.name] = val;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
static defineCustomInspect(meta) {
|
||||
// @ts-ignore
|
||||
meta.prototype[Symbol.for('nodejs.util.inspect.custom')] ??= function (depth = 2) {
|
||||
const object = {};
|
||||
const keys = new Set(Utils.keys(this));
|
||||
for (const prop of meta.props) {
|
||||
if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
|
||||
object[prop.name] = this[prop.name];
|
||||
}
|
||||
}
|
||||
for (const key of keys) {
|
||||
if (!meta.properties[key]) {
|
||||
object[key] = this[key];
|
||||
}
|
||||
}
|
||||
// ensure we dont have internal symbols in the POJO
|
||||
[OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps, EntityName].forEach(
|
||||
sym => delete object[sym],
|
||||
);
|
||||
meta.props.filter(prop => object[prop.name] === undefined).forEach(prop => delete object[prop.name]);
|
||||
const ret = inspect(object, { depth });
|
||||
let name = this.constructor.name;
|
||||
const showEM = ['true', 't', '1'].includes(getEnv('MIKRO_ORM_LOG_EM_ID')?.toLowerCase() ?? '');
|
||||
if (showEM) {
|
||||
if (helper(this).__em) {
|
||||
name += ` [managed by ${helper(this).__em.id}]`;
|
||||
} else {
|
||||
name += ` [not managed]`;
|
||||
}
|
||||
}
|
||||
// distinguish not initialized entities
|
||||
if (!helper(this).__initialized) {
|
||||
name = `(${name})`;
|
||||
}
|
||||
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
||||
};
|
||||
}
|
||||
static defineReferenceProperty(meta, prop, ref, hydrator) {
|
||||
const wrapped = helper(ref);
|
||||
Object.defineProperty(ref, prop.name, {
|
||||
get() {
|
||||
return helper(ref).__data[prop.name];
|
||||
},
|
||||
set(val) {
|
||||
const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
|
||||
const old = Reference.unwrapReference(wrapped.__data[prop.name]);
|
||||
// oxfmt-ignore
|
||||
if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
|
||||
old[prop.inversedBy].removeWithoutPropagation(this);
|
||||
}
|
||||
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
||||
// when propagation from inside hydration, we set the FK to the entity data immediately
|
||||
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
||||
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(
|
||||
wrapped.__data[prop.name],
|
||||
prop.targetMeta,
|
||||
true,
|
||||
);
|
||||
}
|
||||
EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
static propagate(meta, entity, owner, prop, value, old) {
|
||||
// For polymorphic relations, get bidirectional relations from the actual entity's metadata
|
||||
let bidirectionalRelations;
|
||||
if (prop.polymorphic && prop.polymorphTargets?.length) {
|
||||
// For polymorphic relations, we need to get the bidirectional relations from the actual value's metadata
|
||||
if (!value) {
|
||||
return; // No value means no propagation needed
|
||||
}
|
||||
bidirectionalRelations = helper(value).__meta.bidirectionalRelations;
|
||||
} else {
|
||||
bidirectionalRelations = prop.targetMeta.bidirectionalRelations;
|
||||
}
|
||||
for (const prop2 of bidirectionalRelations) {
|
||||
if ((prop2.inversedBy || prop2.mappedBy) !== prop.name) {
|
||||
continue;
|
||||
}
|
||||
// oxfmt-ignore
|
||||
if (prop2.targetMeta.abstract ? prop2.targetMeta.root.class !== meta.root.class : prop2.targetMeta.class !== meta.class) {
|
||||
continue;
|
||||
}
|
||||
const inverse = value?.[prop2.name];
|
||||
if (prop.ref && owner[prop.name]) {
|
||||
// eslint-disable-next-line dot-notation
|
||||
owner[prop.name]['property'] = prop;
|
||||
}
|
||||
if (Utils.isCollection(inverse) && inverse.isPartial()) {
|
||||
continue;
|
||||
}
|
||||
if (prop.kind === ReferenceKind.MANY_TO_ONE && Utils.isCollection(inverse) && inverse.isInitialized()) {
|
||||
inverse.addWithoutPropagation(owner);
|
||||
helper(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
||||
if (
|
||||
(value != null && Reference.unwrapReference(inverse) !== owner) ||
|
||||
(value == null && entity?.[prop2.name] != null)
|
||||
) {
|
||||
if (entity && (!prop.owner || helper(entity).__initialized)) {
|
||||
EntityHelper.propagateOneToOne(entity, owner, prop, prop2, value, old);
|
||||
}
|
||||
if (old && prop.orphanRemoval) {
|
||||
helper(old).__em?.getUnitOfWork().scheduleOrphanRemoval(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static propagateOneToOne(entity, owner, prop, prop2, value, old) {
|
||||
helper(entity).__pk = helper(entity).getPrimaryKey();
|
||||
// the inverse side will be changed on the `value` too, so we need to clean-up and schedule orphan removal there too
|
||||
if (
|
||||
!prop.primary &&
|
||||
!prop2.mapToPk &&
|
||||
value?.[prop2.name] != null &&
|
||||
Reference.unwrapReference(value[prop2.name]) !== entity
|
||||
) {
|
||||
const other = Reference.unwrapReference(value[prop2.name]);
|
||||
delete helper(other).__data[prop.name];
|
||||
if (prop2.orphanRemoval) {
|
||||
helper(other).__em?.getUnitOfWork().scheduleOrphanRemoval(other);
|
||||
}
|
||||
}
|
||||
// Skip setting the inverse side to null if it's a primary key - the entity will be removed via orphan removal
|
||||
// Setting a primary key to null would corrupt the entity and cause validation errors
|
||||
if (value == null && prop.orphanRemoval && prop2.primary) {
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
entity[prop2.name] = value;
|
||||
} else if (prop2.mapToPk) {
|
||||
entity[prop2.name] = helper(owner).getPrimaryKey();
|
||||
} else {
|
||||
entity[prop2.name] = Reference.wrapReference(owner, prop);
|
||||
}
|
||||
if (old?.[prop2.name] != null) {
|
||||
delete helper(old).__data[prop2.name];
|
||||
old[prop2.name] = null;
|
||||
}
|
||||
}
|
||||
static ensurePropagation(entity) {
|
||||
if (entity.__gettersDefined) {
|
||||
return;
|
||||
}
|
||||
const wrapped = helper(entity);
|
||||
const meta = wrapped.__meta;
|
||||
const platform = wrapped.__platform;
|
||||
const serializedPrimaryKey = meta.props.find(p => p.serializedPrimaryKey);
|
||||
const values = [];
|
||||
if (serializedPrimaryKey) {
|
||||
const pk = meta.getPrimaryProps()[0];
|
||||
const val = entity[serializedPrimaryKey.name];
|
||||
delete entity[serializedPrimaryKey.name];
|
||||
Object.defineProperty(entity, serializedPrimaryKey.name, {
|
||||
get() {
|
||||
return this[pk.name] ? platform.normalizePrimaryKey(this[pk.name]) : null;
|
||||
},
|
||||
set(id) {
|
||||
this[pk.name] = id ? platform.denormalizePrimaryKey(id) : null;
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
if (entity[pk.name] == null && val != null) {
|
||||
values.push(serializedPrimaryKey.name, val);
|
||||
}
|
||||
}
|
||||
for (const prop of meta.trackingProps) {
|
||||
if (entity[prop.name] !== undefined) {
|
||||
values.push(prop.name, entity[prop.name]);
|
||||
}
|
||||
delete entity[prop.name];
|
||||
}
|
||||
Object.defineProperties(entity, meta.definedProperties);
|
||||
for (let i = 0; i < values.length; i += 2) {
|
||||
entity[values[i]] = values[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
10
node_modules/@mikro-orm/core/entity/EntityIdentifier.d.ts
generated
vendored
Normal file
10
node_modules/@mikro-orm/core/entity/EntityIdentifier.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { IPrimaryKey } from '../typings.js';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export declare class EntityIdentifier {
|
||||
private value?;
|
||||
constructor(value?: IPrimaryKey | undefined);
|
||||
setValue(value: IPrimaryKey): void;
|
||||
getValue<T extends IPrimaryKey = IPrimaryKey>(): T;
|
||||
}
|
||||
15
node_modules/@mikro-orm/core/entity/EntityIdentifier.js
generated
vendored
Normal file
15
node_modules/@mikro-orm/core/entity/EntityIdentifier.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class EntityIdentifier {
|
||||
value;
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
}
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
}
|
||||
getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
112
node_modules/@mikro-orm/core/entity/EntityLoader.d.ts
generated
vendored
Normal file
112
node_modules/@mikro-orm/core/entity/EntityLoader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
import type {
|
||||
AnyEntity,
|
||||
AutoPath,
|
||||
ConnectionType,
|
||||
EntityName,
|
||||
EntityProperty,
|
||||
FilterQuery,
|
||||
PopulateOptions,
|
||||
} from '../typings.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
|
||||
import type { FilterOptions } from '../drivers/IDatabaseDriver.js';
|
||||
import type { LoggingOptions } from '../logging/Logger.js';
|
||||
/** Options for controlling how relations are loaded by the EntityLoader. */
|
||||
export interface EntityLoaderOptions<
|
||||
Entity,
|
||||
Fields extends string = PopulatePath.ALL,
|
||||
Excludes extends string = never,
|
||||
> {
|
||||
/** Select specific fields to load (partial loading). */
|
||||
fields?: readonly AutoPath<Entity, Fields, `${PopulatePath.ALL}`>[];
|
||||
/** Fields to exclude from loading. */
|
||||
exclude?: readonly AutoPath<Entity, Excludes>[];
|
||||
/** Additional filtering conditions applied to populated relations. */
|
||||
where?: FilterQuery<Entity>;
|
||||
/** Controls how `where` conditions are applied to populated relations. */
|
||||
populateWhere?: PopulateHint | `${PopulateHint}`;
|
||||
/** Ordering for populated relations. */
|
||||
orderBy?: QueryOrderMap<Entity> | QueryOrderMap<Entity>[];
|
||||
/** Whether to reload already loaded entities. */
|
||||
refresh?: boolean;
|
||||
/** Whether to validate the populate hint against the entity metadata. */
|
||||
validate?: boolean;
|
||||
/** Whether to look up eager-loaded relationships automatically. */
|
||||
lookup?: boolean;
|
||||
/** Whether to convert custom types during hydration. */
|
||||
convertCustomTypes?: boolean;
|
||||
/** Whether to skip loading lazy scalar properties. */
|
||||
ignoreLazyScalarProperties?: boolean;
|
||||
/** Filter options to apply when loading relations. */
|
||||
filters?: FilterOptions;
|
||||
/** Loading strategy to use (select-in, joined, or balanced). */
|
||||
strategy?: LoadStrategy | `${LoadStrategy}`;
|
||||
/** Lock mode for the query (pessimistic locking). */
|
||||
lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
|
||||
/** Database schema override. */
|
||||
schema?: string;
|
||||
/** Connection type (read or write replica). */
|
||||
connectionType?: ConnectionType;
|
||||
/** Logging options for the query. */
|
||||
logging?: LoggingOptions;
|
||||
}
|
||||
/** Responsible for batch-loading entity relations using either select-in or joined loading strategies. */
|
||||
export declare class EntityLoader {
|
||||
#private;
|
||||
constructor(em: EntityManager);
|
||||
/**
|
||||
* Loads specified relations in batch.
|
||||
* This will execute one query for each relation, that will populate it on all the specified entities.
|
||||
*/
|
||||
populate<Entity extends object, Fields extends string = PopulatePath.ALL>(
|
||||
entityName: EntityName<Entity>,
|
||||
entities: Entity[],
|
||||
populate: PopulateOptions<Entity>[] | boolean,
|
||||
options: EntityLoaderOptions<Entity, Fields>,
|
||||
): Promise<void>;
|
||||
/** Normalizes populate hints into a structured array of PopulateOptions, expanding dot paths and eager relations. */
|
||||
normalizePopulate<Entity>(
|
||||
entityName: EntityName<Entity>,
|
||||
populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean,
|
||||
strategy?: LoadStrategy,
|
||||
lookup?: boolean,
|
||||
exclude?: string[],
|
||||
): PopulateOptions<Entity>[];
|
||||
private setSerializationContext;
|
||||
/**
|
||||
* Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
|
||||
* partial loading hints (`fields`) that are used to infer the `populate` hint if missing.
|
||||
*/
|
||||
private mergeNestedPopulate;
|
||||
/**
|
||||
* preload everything in one call (this will update already existing references in IM)
|
||||
*/
|
||||
private populateMany;
|
||||
private populateScalar;
|
||||
private populatePolymorphic;
|
||||
private initializeCollections;
|
||||
private initializeOneToMany;
|
||||
private initializeManyToMany;
|
||||
private findChildren;
|
||||
private mergePrimaryCondition;
|
||||
private populateField;
|
||||
/** @internal */
|
||||
findChildrenFromPivotTable<Entity extends object>(
|
||||
filtered: Entity[],
|
||||
prop: EntityProperty<Entity>,
|
||||
options: Required<EntityLoaderOptions<Entity>>,
|
||||
orderBy?: QueryOrderMap<Entity>[],
|
||||
populate?: PopulateOptions<Entity>,
|
||||
pivotJoin?: boolean,
|
||||
): Promise<AnyEntity[][]>;
|
||||
private extractChildCondition;
|
||||
private buildFields;
|
||||
private getChildReferences;
|
||||
private filterCollections;
|
||||
private isPropertyLoaded;
|
||||
private filterReferences;
|
||||
private filterByReferences;
|
||||
private lookupAllRelationships;
|
||||
private getRelationName;
|
||||
private lookupEagerLoadedRelationships;
|
||||
}
|
||||
787
node_modules/@mikro-orm/core/entity/EntityLoader.js
generated
vendored
Normal file
787
node_modules/@mikro-orm/core/entity/EntityLoader.js
generated
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
import { QueryHelper } from '../utils/QueryHelper.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { ValidationError } from '../errors.js';
|
||||
import { LoadStrategy, PopulatePath, ReferenceKind } from '../enums.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { helper } from './wrap.js';
|
||||
import { expandDotPaths } from './utils.js';
|
||||
import { Raw } from '../utils/RawQueryFragment.js';
|
||||
/** Responsible for batch-loading entity relations using either select-in or joined loading strategies. */
|
||||
export class EntityLoader {
|
||||
#metadata;
|
||||
#driver;
|
||||
#em;
|
||||
constructor(em) {
|
||||
this.#em = em;
|
||||
this.#metadata = this.#em.getMetadata();
|
||||
this.#driver = this.#em.getDriver();
|
||||
}
|
||||
/**
|
||||
* Loads specified relations in batch.
|
||||
* This will execute one query for each relation, that will populate it on all the specified entities.
|
||||
*/
|
||||
async populate(entityName, entities, populate, options) {
|
||||
if (entities.length === 0 || Utils.isEmpty(populate)) {
|
||||
return this.setSerializationContext(entities, populate, options);
|
||||
}
|
||||
const meta = this.#metadata.find(entityName);
|
||||
if (entities.some(e => !e.__helper)) {
|
||||
const entity = entities.find(e => !Utils.isEntity(e));
|
||||
throw ValidationError.notDiscoveredEntity(entity, meta, 'populate');
|
||||
}
|
||||
const references = entities.filter(e => !helper(e).isInitialized());
|
||||
const visited = (options.visited ??= new Set());
|
||||
options.where ??= {};
|
||||
options.orderBy ??= {};
|
||||
options.lookup ??= true;
|
||||
options.validate ??= true;
|
||||
options.refresh ??= false;
|
||||
options.convertCustomTypes ??= true;
|
||||
if (references.length > 0) {
|
||||
await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
|
||||
}
|
||||
populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup, options.exclude);
|
||||
const invalid = populate.find(({ field }) => !this.#em.canPopulate(entityName, field));
|
||||
/* v8 ignore next */
|
||||
if (options.validate && invalid) {
|
||||
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
||||
}
|
||||
this.setSerializationContext(entities, populate, options);
|
||||
for (const entity of entities) {
|
||||
visited.add(entity);
|
||||
}
|
||||
for (const pop of populate) {
|
||||
await this.populateField(entityName, entities, pop, options);
|
||||
}
|
||||
for (const entity of entities) {
|
||||
visited.delete(entity);
|
||||
}
|
||||
}
|
||||
/** Normalizes populate hints into a structured array of PopulateOptions, expanding dot paths and eager relations. */
|
||||
normalizePopulate(entityName, populate, strategy, lookup = true, exclude) {
|
||||
const meta = this.#metadata.find(entityName);
|
||||
let normalized = Utils.asArray(populate).map(field => {
|
||||
// oxfmt-ignore
|
||||
return typeof field === 'boolean' || field.field === PopulatePath.ALL ? { all: !!field, field: meta.primaryKeys[0] } : field;
|
||||
});
|
||||
if (normalized.some(p => p.all)) {
|
||||
normalized = this.lookupAllRelationships(entityName);
|
||||
}
|
||||
// convert nested `field` with dot syntax to PopulateOptions with `children` array
|
||||
expandDotPaths(meta, normalized, true);
|
||||
if (lookup && populate !== false) {
|
||||
normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy, '', [], exclude);
|
||||
// convert nested `field` with dot syntax produced by eager relations
|
||||
expandDotPaths(meta, normalized, true);
|
||||
}
|
||||
// merge same fields
|
||||
return this.mergeNestedPopulate(normalized);
|
||||
}
|
||||
setSerializationContext(entities, populate, options) {
|
||||
for (const entity of entities) {
|
||||
helper(entity).setSerializationContext({
|
||||
populate,
|
||||
fields: options.fields,
|
||||
exclude: options.exclude,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
|
||||
* partial loading hints (`fields`) that are used to infer the `populate` hint if missing.
|
||||
*/
|
||||
mergeNestedPopulate(populate) {
|
||||
const tmp = populate.reduce((ret, item) => {
|
||||
/* v8 ignore next */
|
||||
if (item.field === PopulatePath.ALL) {
|
||||
return ret;
|
||||
}
|
||||
if (!ret[item.field]) {
|
||||
ret[item.field] = item;
|
||||
return ret;
|
||||
}
|
||||
if (!ret[item.field].children && item.children) {
|
||||
ret[item.field].children = item.children;
|
||||
} else if (ret[item.field].children && item.children) {
|
||||
ret[item.field].children.push(...item.children);
|
||||
}
|
||||
return ret;
|
||||
}, {});
|
||||
return Object.values(tmp).map(item => {
|
||||
if (item.children) {
|
||||
item.children = this.mergeNestedPopulate(item.children);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* preload everything in one call (this will update already existing references in IM)
|
||||
*/
|
||||
async populateMany(entityName, entities, populate, options) {
|
||||
const [field, ref] = populate.field.split(':', 2);
|
||||
const meta = this.#metadata.find(entityName);
|
||||
const prop = meta.properties[field];
|
||||
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && !this.#driver.getPlatform().usesPivotTable()) {
|
||||
const filtered = entities.filter(e => !e[prop.name]?.isInitialized());
|
||||
if (filtered.length > 0) {
|
||||
await this.populateScalar(meta, filtered, { ...options, fields: [prop.name] });
|
||||
}
|
||||
}
|
||||
if (prop.kind === ReferenceKind.SCALAR && prop.lazy) {
|
||||
const filtered = entities.filter(
|
||||
e => options.refresh || (prop.ref ? !e[prop.name]?.isInitialized() : e[prop.name] === undefined),
|
||||
);
|
||||
if (options.ignoreLazyScalarProperties || filtered.length === 0) {
|
||||
return entities;
|
||||
}
|
||||
await this.populateScalar(meta, filtered, { ...options, fields: [prop.name] });
|
||||
return entities;
|
||||
}
|
||||
if (prop.kind === ReferenceKind.EMBEDDED) {
|
||||
return [];
|
||||
}
|
||||
const filtered = this.filterCollections(entities, field, options, ref);
|
||||
const innerOrderBy = Utils.asArray(options.orderBy)
|
||||
.filter(
|
||||
orderBy =>
|
||||
(Array.isArray(orderBy[prop.name]) && orderBy[prop.name].length > 0) || Utils.isObject(orderBy[prop.name]),
|
||||
)
|
||||
.flatMap(orderBy => orderBy[prop.name]);
|
||||
const where = await this.extractChildCondition(options, prop);
|
||||
if (prop.kind === ReferenceKind.MANY_TO_MANY && this.#driver.getPlatform().usesPivotTable()) {
|
||||
const pivotOrderBy = QueryHelper.mergeOrderBy(innerOrderBy, prop.orderBy, prop.targetMeta?.orderBy);
|
||||
const res = await this.findChildrenFromPivotTable(filtered, prop, options, pivotOrderBy, populate, !!ref);
|
||||
return Utils.flatten(res);
|
||||
}
|
||||
if (prop.polymorphic && prop.polymorphTargets) {
|
||||
return this.populatePolymorphic(entities, prop, options, !!ref);
|
||||
}
|
||||
const { items, partial } = await this.findChildren(
|
||||
options.filtered ?? entities,
|
||||
prop,
|
||||
populate,
|
||||
{
|
||||
...options,
|
||||
where,
|
||||
orderBy: innerOrderBy,
|
||||
},
|
||||
!!(ref || prop.mapToPk),
|
||||
);
|
||||
const customOrder = innerOrderBy.length > 0 || !!prop.orderBy || !!prop.targetMeta?.orderBy;
|
||||
this.initializeCollections(filtered, prop, field, items, customOrder, partial);
|
||||
return items;
|
||||
}
|
||||
async populateScalar(meta, filtered, options) {
|
||||
const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
||||
const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta, true)));
|
||||
const where = this.mergePrimaryCondition(ids, pk, options, meta, this.#metadata, this.#driver.getPlatform());
|
||||
const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
|
||||
await this.#em.find(meta.class, where, {
|
||||
filters,
|
||||
convertCustomTypes,
|
||||
lockMode,
|
||||
strategy,
|
||||
populateWhere,
|
||||
connectionType,
|
||||
logging,
|
||||
fields: fields,
|
||||
populate: [],
|
||||
});
|
||||
}
|
||||
async populatePolymorphic(entities, prop, options, ref) {
|
||||
const ownerMeta = this.#metadata.get(entities[0].constructor);
|
||||
// Separate entities: those with loaded refs vs those needing FK load
|
||||
const toPopulate = [];
|
||||
const needsFkLoad = [];
|
||||
for (const entity of entities) {
|
||||
const refValue = entity[prop.name];
|
||||
if (refValue && helper(refValue).hasPrimaryKey()) {
|
||||
if (
|
||||
(ref && !options.refresh) || // :ref hint - already have reference
|
||||
(!ref && helper(refValue).__initialized && !options.refresh) // already loaded
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
toPopulate.push(entity);
|
||||
} else if (refValue == null && !helper(entity).__loadedProperties.has(prop.name)) {
|
||||
// FK columns weren't loaded (partial loading) — need to re-fetch them.
|
||||
// If the property IS in __loadedProperties, the FK was loaded and is genuinely null.
|
||||
needsFkLoad.push(entity);
|
||||
}
|
||||
}
|
||||
// Load FK columns using populateScalar pattern
|
||||
if (needsFkLoad.length > 0) {
|
||||
await this.populateScalar(ownerMeta, needsFkLoad, {
|
||||
...options,
|
||||
fields: [...ownerMeta.primaryKeys, prop.name],
|
||||
});
|
||||
// After loading FKs, add to toPopulate if not using :ref hint
|
||||
if (!ref) {
|
||||
for (const entity of needsFkLoad) {
|
||||
const refValue = entity[prop.name];
|
||||
if (refValue && helper(refValue).hasPrimaryKey()) {
|
||||
toPopulate.push(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toPopulate.length === 0) {
|
||||
return [];
|
||||
}
|
||||
// Group references by target class for batch loading
|
||||
const groups = new Map();
|
||||
for (const entity of toPopulate) {
|
||||
const refValue = Reference.unwrapReference(entity[prop.name]);
|
||||
const discriminator = QueryHelper.findDiscriminatorValue(prop.discriminatorMap, helper(refValue).__meta.class);
|
||||
const group = groups.get(discriminator) ?? [];
|
||||
group.push(refValue);
|
||||
groups.set(discriminator, group);
|
||||
}
|
||||
// Load each group concurrently - identity map handles merging with existing references
|
||||
const allItems = [];
|
||||
await Promise.all(
|
||||
[...groups].map(async ([discriminator, children]) => {
|
||||
const targetMeta = this.#metadata.find(prop.discriminatorMap[discriminator]);
|
||||
await this.populateScalar(targetMeta, children, options);
|
||||
allItems.push(...children);
|
||||
}),
|
||||
);
|
||||
return allItems;
|
||||
}
|
||||
initializeCollections(filtered, prop, field, children, customOrder, partial) {
|
||||
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
||||
this.initializeOneToMany(filtered, children, prop, field, partial);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.#driver.getPlatform().usesPivotTable()) {
|
||||
this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
|
||||
}
|
||||
}
|
||||
initializeOneToMany(filtered, children, prop, field, partial) {
|
||||
const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
|
||||
const map = {};
|
||||
for (const entity of filtered) {
|
||||
const key = helper(entity).getSerializedPrimaryKey();
|
||||
map[key] = [];
|
||||
}
|
||||
for (const child of children) {
|
||||
const pk = child.__helper.__data[prop.mappedBy] ?? child[prop.mappedBy];
|
||||
if (pk) {
|
||||
const key = helper(mapToPk ? this.#em.getReference(prop.targetMeta.class, pk) : pk).getSerializedPrimaryKey();
|
||||
map[key]?.push(child);
|
||||
}
|
||||
}
|
||||
for (const entity of filtered) {
|
||||
const key = helper(entity).getSerializedPrimaryKey();
|
||||
entity[field].hydrate(map[key], undefined, partial);
|
||||
}
|
||||
}
|
||||
initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
|
||||
if (prop.mappedBy) {
|
||||
for (const entity of filtered) {
|
||||
const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
|
||||
entity[field].hydrate(items, true, partial);
|
||||
}
|
||||
} else {
|
||||
// owning side of M:N without pivot table needs to be reordered
|
||||
for (const entity of filtered) {
|
||||
const order = !customOrder ? [...entity[prop.name].getItems(false)] : []; // copy order of references
|
||||
const items = children.filter(child => entity[prop.name].contains(child, false));
|
||||
if (!customOrder) {
|
||||
items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
|
||||
}
|
||||
entity[field].hydrate(items, true, partial);
|
||||
}
|
||||
}
|
||||
}
|
||||
async findChildren(entities, prop, populate, options, ref) {
|
||||
const children = Utils.unique(this.getChildReferences(entities, prop, options, ref));
|
||||
const meta = prop.targetMeta;
|
||||
// When targetKey is set, use it for FK lookup instead of the PK
|
||||
let fk = prop.targetKey ?? Utils.getPrimaryKeyHash(meta.primaryKeys);
|
||||
let schema = options.schema;
|
||||
const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
|
||||
let polymorphicOwnerProp;
|
||||
if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
|
||||
const ownerProp = meta.properties[prop.mappedBy];
|
||||
if (ownerProp.polymorphic && ownerProp.fieldNames.length >= 2) {
|
||||
const idColumns = ownerProp.fieldNames.slice(1);
|
||||
fk = idColumns.length === 1 ? idColumns[0] : idColumns;
|
||||
polymorphicOwnerProp = ownerProp;
|
||||
} else {
|
||||
fk = ownerProp.name;
|
||||
}
|
||||
}
|
||||
if (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !ref) {
|
||||
children.length = 0;
|
||||
fk = meta.properties[prop.mappedBy].name;
|
||||
children.push(...this.filterByReferences(entities, prop.name, options.refresh));
|
||||
}
|
||||
if (children.length === 0) {
|
||||
return { items: [], partial };
|
||||
}
|
||||
if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
|
||||
schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
|
||||
}
|
||||
const ids = Utils.unique(children.map(e => (prop.targetKey ? e[prop.targetKey] : e.__helper.getPrimaryKey())));
|
||||
let where;
|
||||
if (polymorphicOwnerProp && Array.isArray(fk)) {
|
||||
const conditions = ids.map(id => {
|
||||
const pkValues = Object.values(id);
|
||||
return Object.fromEntries(fk.map((col, idx) => [col, pkValues[idx]]));
|
||||
});
|
||||
where = conditions.length === 1 ? conditions[0] : { $or: conditions };
|
||||
} else {
|
||||
where = this.mergePrimaryCondition(ids, fk, options, meta, this.#metadata, this.#driver.getPlatform());
|
||||
}
|
||||
if (polymorphicOwnerProp) {
|
||||
const parentMeta = this.#metadata.find(entities[0].constructor);
|
||||
const discriminatorValue =
|
||||
QueryHelper.findDiscriminatorValue(polymorphicOwnerProp.discriminatorMap, parentMeta.class) ??
|
||||
parentMeta.tableName;
|
||||
const discriminatorColumn = polymorphicOwnerProp.fieldNames[0];
|
||||
where = { $and: [where, { [discriminatorColumn]: discriminatorValue }] };
|
||||
}
|
||||
const fields = this.buildFields(options.fields, prop, ref);
|
||||
/* eslint-disable prefer-const */
|
||||
let {
|
||||
refresh,
|
||||
filters,
|
||||
convertCustomTypes,
|
||||
lockMode,
|
||||
strategy,
|
||||
populateWhere = 'infer',
|
||||
connectionType,
|
||||
logging,
|
||||
} = options;
|
||||
/* eslint-enable prefer-const */
|
||||
if (typeof populateWhere === 'object') {
|
||||
populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
|
||||
}
|
||||
if (!Utils.isEmpty(prop.where) || Raw.hasObjectFragments(prop.where)) {
|
||||
where = { $and: [where, prop.where] };
|
||||
}
|
||||
const orderBy = QueryHelper.mergeOrderBy(options.orderBy, prop.orderBy);
|
||||
const items = await this.#em.find(meta.class, where, {
|
||||
filters,
|
||||
convertCustomTypes,
|
||||
lockMode,
|
||||
populateWhere,
|
||||
logging,
|
||||
orderBy,
|
||||
populate: populate.children ?? populate.all ?? [],
|
||||
exclude: Array.isArray(options.exclude)
|
||||
? Utils.extractChildElements(options.exclude, prop.name)
|
||||
: options.exclude,
|
||||
strategy,
|
||||
fields,
|
||||
schema,
|
||||
connectionType,
|
||||
// @ts-ignore not a public option, will be propagated to the populate call
|
||||
refresh: refresh && !children.every(item => options.visited.has(item)),
|
||||
// @ts-ignore not a public option, will be propagated to the populate call
|
||||
visited: options.visited,
|
||||
});
|
||||
// For targetKey relations, wire up loaded entities to parent references
|
||||
// This is needed because the references were created under alternate key,
|
||||
// but loaded entities are stored under PK, so they don't automatically merge
|
||||
if (prop.targetKey && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
|
||||
const itemsByKey = new Map();
|
||||
for (const item of items) {
|
||||
itemsByKey.set('' + item[prop.targetKey], item);
|
||||
}
|
||||
for (const entity of entities) {
|
||||
const ref = entity[prop.name];
|
||||
/* v8 ignore next */
|
||||
if (!ref) {
|
||||
continue;
|
||||
}
|
||||
// oxfmt-ignore
|
||||
const keyValue = '' + (Reference.isReference(ref) ? ref.unwrap()[prop.targetKey] : ref[prop.targetKey]);
|
||||
const loadedItem = itemsByKey.get(keyValue);
|
||||
if (loadedItem) {
|
||||
entity[prop.name] = Reference.isReference(ref) ? Reference.create(loadedItem) : loadedItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
|
||||
const nullVal = this.#em.config.get('forceUndefined') ? undefined : null;
|
||||
const itemsMap = new Set();
|
||||
const childrenMap = new Set();
|
||||
// Use targetKey value if set, otherwise use serialized PK
|
||||
const getKey = e => (prop.targetKey ? '' + e[prop.targetKey] : helper(e).getSerializedPrimaryKey());
|
||||
for (const item of items) {
|
||||
/* v8 ignore next */
|
||||
itemsMap.add(getKey(item));
|
||||
}
|
||||
for (const child of children) {
|
||||
childrenMap.add(getKey(child));
|
||||
}
|
||||
for (const entity of entities) {
|
||||
const ref = entity[prop.name] ?? {};
|
||||
const key = helper(ref) ? getKey(ref) : undefined;
|
||||
if (key && childrenMap.has(key) && !itemsMap.has(key)) {
|
||||
entity[prop.name] = nullVal;
|
||||
helper(entity).__originalEntityData[prop.name] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const item of items) {
|
||||
if (ref && !helper(item).__onLoadFired) {
|
||||
helper(item).__initialized = false;
|
||||
this.#em.getUnitOfWork().unmarkAsLoaded(item);
|
||||
}
|
||||
}
|
||||
return { items, partial };
|
||||
}
|
||||
mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
|
||||
const cond1 = QueryHelper.processWhere({
|
||||
where: { [pk]: { $in: ids } },
|
||||
entityName: meta.class,
|
||||
metadata,
|
||||
platform,
|
||||
convertCustomTypes: !options.convertCustomTypes,
|
||||
});
|
||||
const where = { ...options.where };
|
||||
Utils.dropUndefinedProperties(where);
|
||||
return where[pk] ? { $and: [cond1, where] } : { ...cond1, ...where };
|
||||
}
|
||||
async populateField(entityName, entities, populate, options) {
|
||||
const field = populate.field.split(':')[0];
|
||||
const prop = this.#metadata.find(entityName).properties[field];
|
||||
if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
|
||||
return;
|
||||
}
|
||||
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
||||
const populated = await this.populateMany(entityName, entities, populate, options);
|
||||
if (!populate.children && !populate.all) {
|
||||
return;
|
||||
}
|
||||
const children = [];
|
||||
for (const entity of entities) {
|
||||
const ref = entity[field];
|
||||
if (Utils.isEntity(ref)) {
|
||||
children.push(ref);
|
||||
} else if (Reference.isReference(ref)) {
|
||||
children.push(ref.unwrap());
|
||||
} else if (Utils.isCollection(ref)) {
|
||||
children.push(...ref.getItems());
|
||||
} else if (ref && prop.kind === ReferenceKind.EMBEDDED) {
|
||||
children.push(...Utils.asArray(ref));
|
||||
}
|
||||
}
|
||||
if (populated.length === 0 && !populate.children) {
|
||||
return;
|
||||
}
|
||||
const fields = this.buildFields(options.fields, prop);
|
||||
const innerOrderBy = Utils.asArray(options.orderBy)
|
||||
.filter(orderBy => Utils.isObject(orderBy[prop.name]))
|
||||
.map(orderBy => orderBy[prop.name]);
|
||||
const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging, schema } = options;
|
||||
// oxfmt-ignore
|
||||
const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
||||
const visited = options.visited;
|
||||
for (const entity of entities) {
|
||||
visited.delete(entity);
|
||||
}
|
||||
const unique = Utils.unique(children);
|
||||
const filtered = unique.filter(e => !visited.has(e));
|
||||
for (const entity of entities) {
|
||||
visited.add(entity);
|
||||
}
|
||||
if (!prop.targetMeta) {
|
||||
return;
|
||||
}
|
||||
const populateChildren = async (targetMeta, items) => {
|
||||
await this.populate(targetMeta.class, items, populate.children ?? populate.all, {
|
||||
where: await this.extractChildCondition(options, prop, false),
|
||||
orderBy: innerOrderBy,
|
||||
fields,
|
||||
exclude,
|
||||
validate: false,
|
||||
lookup: false,
|
||||
filters,
|
||||
ignoreLazyScalarProperties,
|
||||
populateWhere,
|
||||
connectionType,
|
||||
logging,
|
||||
schema,
|
||||
// @ts-ignore not a public option, will be propagated to the populate call
|
||||
refresh: refresh && !filtered.every(item => options.visited.has(item)),
|
||||
// @ts-ignore not a public option, will be propagated to the populate call
|
||||
visited: options.visited,
|
||||
// @ts-ignore not a public option
|
||||
filtered,
|
||||
});
|
||||
};
|
||||
if (prop.polymorphic && prop.polymorphTargets) {
|
||||
await Promise.all(
|
||||
prop.polymorphTargets.map(async targetMeta => {
|
||||
const targetChildren = unique.filter(child => helper(child).__meta.className === targetMeta.className);
|
||||
if (targetChildren.length > 0) {
|
||||
await populateChildren(targetMeta, targetChildren);
|
||||
}
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
await populateChildren(prop.targetMeta, unique);
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
|
||||
const ids = filtered.map(e => e.__helper.__primaryKeys);
|
||||
const refresh = options.refresh;
|
||||
let where = await this.extractChildCondition(options, prop, true);
|
||||
const fields = this.buildFields(options.fields, prop);
|
||||
// oxfmt-ignore
|
||||
const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
||||
const populateFilter = options.populateFilter?.[prop.name];
|
||||
const options2 = { ...options, fields, exclude, populateFilter };
|
||||
['limit', 'offset', 'first', 'last', 'before', 'after', 'overfetch'].forEach(prop => delete options2[prop]);
|
||||
options2.populate = populate?.children ?? [];
|
||||
if (!Utils.isEmpty(prop.where)) {
|
||||
where = { $and: [where, prop.where] };
|
||||
}
|
||||
const map = await this.#driver.loadFromPivotTable(
|
||||
prop,
|
||||
ids,
|
||||
where,
|
||||
orderBy,
|
||||
this.#em.getTransactionContext(),
|
||||
options2,
|
||||
pivotJoin,
|
||||
);
|
||||
const children = [];
|
||||
for (let i = 0; i < filtered.length; i++) {
|
||||
const entity = filtered[i];
|
||||
const items = map[Utils.getPrimaryKeyHash(ids[i])].map(item => {
|
||||
if (pivotJoin) {
|
||||
return this.#em.getReference(prop.targetMeta.class, item, {
|
||||
convertCustomTypes: true,
|
||||
schema: options.schema ?? this.#em.config.get('schema'),
|
||||
});
|
||||
}
|
||||
const entity = this.#em.getEntityFactory().create(prop.targetMeta.class, item, {
|
||||
refresh,
|
||||
merge: true,
|
||||
convertCustomTypes: true,
|
||||
schema: options.schema ?? this.#em.config.get('schema'),
|
||||
});
|
||||
return this.#em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
|
||||
});
|
||||
entity[prop.name].hydrate(items, true);
|
||||
children.push(items);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
async extractChildCondition(options, prop, filters = false) {
|
||||
const where = options.where;
|
||||
const subCond = Utils.isPlainObject(where[prop.name]) ? where[prop.name] : {};
|
||||
const meta2 = prop.targetMeta;
|
||||
const pk = Utils.getPrimaryKeyHash(meta2.primaryKeys);
|
||||
['$and', '$or'].forEach(op => {
|
||||
if (where[op]) {
|
||||
const child = where[op]
|
||||
.map(cond => cond[prop.name])
|
||||
.filter(
|
||||
sub =>
|
||||
sub != null &&
|
||||
!(Utils.isPlainObject(sub) && Utils.getObjectQueryKeys(sub).every(key => Utils.isOperator(key, false))),
|
||||
)
|
||||
.map(cond => {
|
||||
if (Utils.isPrimaryKey(cond)) {
|
||||
return { [pk]: cond };
|
||||
}
|
||||
return cond;
|
||||
});
|
||||
if (child.length > 0) {
|
||||
subCond[op] = child;
|
||||
}
|
||||
}
|
||||
});
|
||||
const operators = Object.keys(subCond).filter(key => Utils.isOperator(key, false));
|
||||
if (operators.length > 0) {
|
||||
operators.forEach(op => {
|
||||
subCond[pk] ??= {};
|
||||
subCond[pk][op] = subCond[op];
|
||||
delete subCond[op];
|
||||
});
|
||||
}
|
||||
if (filters) {
|
||||
return this.#em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
|
||||
}
|
||||
return subCond;
|
||||
}
|
||||
buildFields(fields = [], prop, ref) {
|
||||
if (ref) {
|
||||
fields = prop.targetMeta.primaryKeys.map(targetPkName => `${prop.name}.${targetPkName}`);
|
||||
}
|
||||
const ret = fields.reduce((ret, f) => {
|
||||
if (Utils.isPlainObject(f)) {
|
||||
Utils.keys(f)
|
||||
.filter(ff => ff === prop.name)
|
||||
.forEach(ff => ret.push(...f[ff]));
|
||||
} else if (f.toString().includes('.')) {
|
||||
const parts = f.toString().split('.');
|
||||
const propName = parts.shift();
|
||||
const childPropName = parts.join('.');
|
||||
/* v8 ignore next */
|
||||
if (propName === prop.name) {
|
||||
ret.push(childPropName);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}, []);
|
||||
// we need to automatically select the FKs too, e.g. for 1:m relations to be able to wire them with the items
|
||||
if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
const owner = prop.targetMeta.properties[prop.mappedBy];
|
||||
// when the owning FK is lazy, we need to explicitly select it even without user-provided fields,
|
||||
// otherwise the driver will exclude it and we won't be able to map children to their parent collections
|
||||
if (owner && !ret.includes(owner.name) && (ret.length > 0 || owner.lazy)) {
|
||||
ret.push(owner.name);
|
||||
}
|
||||
}
|
||||
if (ret.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
getChildReferences(entities, prop, options, ref) {
|
||||
const filtered = this.filterCollections(entities, prop.name, options, ref);
|
||||
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
||||
return filtered.map(e => e[prop.name].owner);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
|
||||
return filtered.reduce((a, b) => {
|
||||
a.push(...b[prop.name].getItems());
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
if (prop.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
// inverse side
|
||||
return filtered;
|
||||
}
|
||||
// MANY_TO_ONE or ONE_TO_ONE
|
||||
return this.filterReferences(entities, prop.name, options, ref);
|
||||
}
|
||||
filterCollections(entities, field, options, ref) {
|
||||
if (options.refresh) {
|
||||
return entities.filter(e => e[field]);
|
||||
}
|
||||
return entities.filter(e => Utils.isCollection(e[field]) && !e[field].isInitialized(!ref));
|
||||
}
|
||||
isPropertyLoaded(entity, field) {
|
||||
if (!entity || field === '*') {
|
||||
return true;
|
||||
}
|
||||
const wrapped = helper(entity);
|
||||
if (!field.includes('.')) {
|
||||
return wrapped.__loadedProperties.has(field);
|
||||
}
|
||||
const [f, ...r] = field.split('.');
|
||||
/* v8 ignore next */
|
||||
if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
|
||||
return false;
|
||||
}
|
||||
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(wrapped.__meta.properties[f].kind)) {
|
||||
return entity[f].getItems(false).every(item => this.isPropertyLoaded(item, r.join('.')));
|
||||
}
|
||||
return this.isPropertyLoaded(entity[f], r.join('.'));
|
||||
}
|
||||
filterReferences(entities, field, options, ref) {
|
||||
if (ref) {
|
||||
return [];
|
||||
}
|
||||
const children = entities.filter(e => Utils.isEntity(e[field], true));
|
||||
if (options.refresh) {
|
||||
return children.map(e => Reference.unwrapReference(e[field]));
|
||||
}
|
||||
if (options.fields) {
|
||||
return children
|
||||
.map(e => Reference.unwrapReference(e[field]))
|
||||
.filter(target => {
|
||||
const wrapped = helper(target);
|
||||
const childFields = options.fields
|
||||
.filter(f => f.startsWith(`${field}.`))
|
||||
.map(f => f.substring(field.length + 1));
|
||||
return !wrapped.__initialized || !childFields.every(cf => this.isPropertyLoaded(target, cf));
|
||||
});
|
||||
}
|
||||
return children.filter(e => !e[field].__helper.__initialized).map(e => Reference.unwrapReference(e[field]));
|
||||
}
|
||||
filterByReferences(entities, field, refresh) {
|
||||
/* v8 ignore next */
|
||||
if (refresh) {
|
||||
return entities;
|
||||
}
|
||||
return entities.filter(e => e[field] !== null && !e[field]?.__helper?.__initialized);
|
||||
}
|
||||
lookupAllRelationships(entityName) {
|
||||
const ret = [];
|
||||
const meta = this.#metadata.find(entityName);
|
||||
meta.relations.forEach(prop => {
|
||||
ret.push({
|
||||
field: this.getRelationName(meta, prop),
|
||||
// force select-in strategy when populating all relations as otherwise we could cause infinite loops when self-referencing
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
// no need to look up populate children recursively as we just pass `all: true` here
|
||||
all: true,
|
||||
});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
getRelationName(meta, prop) {
|
||||
if (!prop.embedded) {
|
||||
return prop.name;
|
||||
}
|
||||
return `${this.getRelationName(meta, meta.properties[prop.embedded[0]])}.${prop.embedded[1]}`;
|
||||
}
|
||||
lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = [], exclude) {
|
||||
const meta = this.#metadata.find(entityName);
|
||||
if (!meta && !prefix) {
|
||||
return populate;
|
||||
}
|
||||
if (!meta || visited.includes(meta)) {
|
||||
return [];
|
||||
}
|
||||
visited.push(meta);
|
||||
const ret = prefix === '' ? [...populate] : [];
|
||||
meta.relations
|
||||
.filter(prop => {
|
||||
const field = this.getRelationName(meta, prop);
|
||||
const prefixed = prefix ? `${prefix}.${field}` : field;
|
||||
const isExcluded = exclude?.includes(prefixed);
|
||||
const eager = prop.eager && !populate.some(p => p.field === `${prop.name}:ref`);
|
||||
const populated = populate.some(p => p.field === prop.name);
|
||||
const disabled = populate.some(p => p.field === prop.name && p.all === false);
|
||||
return !disabled && !isExcluded && (eager || populated);
|
||||
})
|
||||
.forEach(prop => {
|
||||
const field = this.getRelationName(meta, prop);
|
||||
const prefixed = prefix ? `${prefix}.${field}` : field;
|
||||
const nestedPopulate = populate
|
||||
.filter(p => p.field === prop.name)
|
||||
.flatMap(p => p.children)
|
||||
.filter(Boolean);
|
||||
const nested = this.lookupEagerLoadedRelationships(
|
||||
prop.targetMeta.class,
|
||||
nestedPopulate,
|
||||
strategy,
|
||||
prefixed,
|
||||
visited.slice(),
|
||||
exclude,
|
||||
);
|
||||
if (nested.length > 0) {
|
||||
ret.push(...nested);
|
||||
} else {
|
||||
const selfReferencing =
|
||||
[meta.tableName, ...visited.map(m => m.tableName)].includes(prop.targetMeta.tableName) && prop.eager;
|
||||
ret.push({
|
||||
field: prefixed,
|
||||
// enforce select-in strategy for self-referencing relations
|
||||
strategy: selfReferencing ? LoadStrategy.SELECT_IN : (strategy ?? prop.strategy),
|
||||
});
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
324
node_modules/@mikro-orm/core/entity/EntityRepository.d.ts
generated
vendored
Normal file
324
node_modules/@mikro-orm/core/entity/EntityRepository.d.ts
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
import type { PopulatePath } from '../enums.js';
|
||||
import type { CreateOptions, EntityManager, MergeOptions } from '../EntityManager.js';
|
||||
import type { AssignOptions } from './EntityAssigner.js';
|
||||
import type {
|
||||
EntityData,
|
||||
EntityName,
|
||||
Primary,
|
||||
Loaded,
|
||||
FilterQuery,
|
||||
EntityDictionary,
|
||||
AutoPath,
|
||||
RequiredEntityData,
|
||||
Ref,
|
||||
EntityType,
|
||||
EntityDTO,
|
||||
MergeSelected,
|
||||
FromEntityType,
|
||||
IsSubset,
|
||||
MergeLoaded,
|
||||
ArrayElement,
|
||||
} from '../typings.js';
|
||||
import type {
|
||||
CountOptions,
|
||||
DeleteOptions,
|
||||
FindAllOptions,
|
||||
FindByCursorOptions,
|
||||
FindOneOptions,
|
||||
FindOneOrFailOptions,
|
||||
FindOptions,
|
||||
GetReferenceOptions,
|
||||
NativeInsertUpdateOptions,
|
||||
StreamOptions,
|
||||
UpdateOptions,
|
||||
UpsertManyOptions,
|
||||
UpsertOptions,
|
||||
} from '../drivers/IDatabaseDriver.js';
|
||||
import type { EntityLoaderOptions } from './EntityLoader.js';
|
||||
import type { Cursor } from '../utils/Cursor.js';
|
||||
/** Repository class providing a type-safe API for querying and persisting a specific entity type. */
|
||||
export declare class EntityRepository<Entity extends object> {
|
||||
protected readonly em: EntityManager;
|
||||
protected readonly entityName: EntityName<Entity>;
|
||||
constructor(em: EntityManager, entityName: EntityName<Entity>);
|
||||
/**
|
||||
* Finds first entity matching your `where` query.
|
||||
*/
|
||||
findOne<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
where: FilterQuery<Entity>,
|
||||
options?: FindOneOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
||||
/**
|
||||
* Finds first entity matching your `where` query. If nothing is found, it will throw an error.
|
||||
* You can override the factory for creating this method via `options.failHandler` locally
|
||||
* or via `Configuration.findOneOrFailHandler` globally.
|
||||
*/
|
||||
findOneOrFail<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
where: FilterQuery<Entity>,
|
||||
options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>>;
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance. The method accepts either `entityName` together with the entity `data`, or just entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
upsert<Fields extends string = any>(
|
||||
entityOrData?: EntityData<Entity> | Entity,
|
||||
options?: UpsertOptions<Entity, Fields>,
|
||||
): Promise<Entity>;
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const authors = await em.getRepository(Author).upsertMany([{ email: 'foo@bar.com', age: 33 }, ...]);
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com'), (666, 'lol@lol.lol') on conflict ("email") do update set "age" = excluded."age"
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.getRepository(Author).upsertMany([
|
||||
* { email: 'foo@bar.com', age: 33 },
|
||||
* { email: 'lol@lol.lol', age: 666 },
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
upsertMany<Fields extends string = any>(
|
||||
entitiesOrData?: EntityData<Entity>[] | Entity[],
|
||||
options?: UpsertManyOptions<Entity, Fields>,
|
||||
): Promise<Entity[]>;
|
||||
/**
|
||||
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
||||
*/
|
||||
find<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
where: FilterQuery<Entity>,
|
||||
options?: FindOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
||||
/**
|
||||
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as tuple
|
||||
* where first element is the array of entities, and the second is the count.
|
||||
*/
|
||||
findAndCount<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
where: FilterQuery<Entity>,
|
||||
options?: FindOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<[Loaded<Entity, Hint, Fields, Excludes>[], number]>;
|
||||
/**
|
||||
* @inheritDoc EntityManager.findByCursor
|
||||
*/
|
||||
findByCursor<
|
||||
Hint extends string = never,
|
||||
Fields extends string = '*',
|
||||
Excludes extends string = never,
|
||||
IncludeCount extends boolean = true,
|
||||
>(
|
||||
options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>,
|
||||
): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
||||
/**
|
||||
* Finds all entities of given type. You can pass additional options via the `options` parameter.
|
||||
*/
|
||||
findAll<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
options?: FindAllOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
||||
/**
|
||||
* @inheritDoc EntityManager.stream
|
||||
*/
|
||||
stream<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
options?: StreamOptions<Entity, Hint, Fields, Excludes>,
|
||||
): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
|
||||
/**
|
||||
* @inheritDoc EntityManager.insert
|
||||
*/
|
||||
insert(
|
||||
data: Entity | RequiredEntityData<Entity>,
|
||||
options?: NativeInsertUpdateOptions<Entity>,
|
||||
): Promise<Primary<Entity>>;
|
||||
/**
|
||||
* @inheritDoc EntityManager.insert
|
||||
*/
|
||||
insertMany(
|
||||
data: Entity[] | RequiredEntityData<Entity>[],
|
||||
options?: NativeInsertUpdateOptions<Entity>,
|
||||
): Promise<Primary<Entity>[]>;
|
||||
/**
|
||||
* Fires native update query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
nativeUpdate(where: FilterQuery<Entity>, data: EntityData<Entity>, options?: UpdateOptions<Entity>): Promise<number>;
|
||||
/**
|
||||
* Fires native delete query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
nativeDelete(where: FilterQuery<Entity>, options?: DeleteOptions<Entity>): Promise<number>;
|
||||
/**
|
||||
* Maps raw database result to an entity and merges it to this EntityManager.
|
||||
*/
|
||||
map(
|
||||
result: EntityDictionary<Entity>,
|
||||
options?: {
|
||||
schema?: string;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
||||
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
||||
*/
|
||||
getReference<K extends string & keyof Entity>(
|
||||
id: Entity[K],
|
||||
options: Omit<GetReferenceOptions, 'key' | 'wrapped'> & {
|
||||
key: K;
|
||||
wrapped: true;
|
||||
},
|
||||
): Ref<Entity>;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
||||
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
||||
*/
|
||||
getReference<K extends string & keyof Entity>(
|
||||
id: Entity[K],
|
||||
options: Omit<GetReferenceOptions, 'key'> & {
|
||||
key: K;
|
||||
wrapped?: false;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference(
|
||||
id: Primary<Entity>,
|
||||
options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
||||
wrapped: true;
|
||||
},
|
||||
): Ref<Entity>;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference(id: Primary<Entity> | Primary<Entity>[]): Entity;
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference(
|
||||
id: Primary<Entity>,
|
||||
options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
||||
wrapped: false;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Checks whether given property can be populated on the entity.
|
||||
*/
|
||||
canPopulate(property: string): boolean;
|
||||
/**
|
||||
* Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
|
||||
*/
|
||||
populate<
|
||||
Ent extends Entity | Entity[],
|
||||
Hint extends string = never,
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Fields extends string = never,
|
||||
Excludes extends string = never,
|
||||
>(
|
||||
entities: Ent,
|
||||
populate: AutoPath<Naked, Hint, PopulatePath.ALL>[] | false,
|
||||
options?: EntityLoaderOptions<Naked, Fields, Excludes>,
|
||||
): Promise<
|
||||
Ent extends object[]
|
||||
? MergeLoaded<ArrayElement<Ent>, Naked, Hint, Fields, Excludes>[]
|
||||
: MergeLoaded<Ent, Naked, Hint, Fields, Excludes>
|
||||
>;
|
||||
/**
|
||||
* Creates new instance of given entity and populates it with given data.
|
||||
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
||||
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
||||
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
||||
* the whole `data` parameter will be passed. This means we can also define `constructor(data: Partial<T>)` and
|
||||
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
||||
*
|
||||
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
||||
* symbol to omit some properties from this check without making them optional. Alternatively, use `partial: true`
|
||||
* in the options to disable the strict checks for required properties. This option has no effect on runtime.
|
||||
*
|
||||
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
||||
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
||||
*/
|
||||
create<
|
||||
Convert extends boolean = false,
|
||||
Data extends RequiredEntityData<Entity, never, Convert> = RequiredEntityData<Entity, never, Convert>,
|
||||
>(data: Data & IsSubset<RequiredEntityData<Entity, never, Convert>, Data>, options?: CreateOptions<Convert>): Entity;
|
||||
/**
|
||||
* Creates new instance of given entity and populates it with given data.
|
||||
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
||||
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
||||
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
||||
* the whole `data` parameter will be pass. This means we can also define `constructor(data: Partial<T>)` and
|
||||
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
||||
*
|
||||
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
||||
* symbol to omit some properties from this check without making them optional. Alternatively, use `partial: true`
|
||||
* in the options to disable the strict checks for required properties. This option has no effect on runtime.
|
||||
*
|
||||
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
||||
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
||||
*/
|
||||
create<Convert extends boolean = false, Data extends EntityData<Entity, Convert> = EntityData<Entity, Convert>>(
|
||||
data: Data & IsSubset<EntityData<Entity, Convert>, Data>,
|
||||
options: CreateOptions<Convert> & {
|
||||
partial: true;
|
||||
},
|
||||
): Entity;
|
||||
/**
|
||||
* Shortcut for `wrap(entity).assign(data, { em })`
|
||||
*/
|
||||
assign<
|
||||
Ent extends EntityType<Entity>,
|
||||
Naked extends FromEntityType<Ent> = FromEntityType<Ent>,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
|
||||
| EntityData<Naked, Convert>
|
||||
| Partial<EntityDTO<Naked>>,
|
||||
>(
|
||||
entity: Ent | Partial<Ent>,
|
||||
data: Data & IsSubset<EntityData<Naked, Convert>, Data>,
|
||||
options?: AssignOptions<Convert>,
|
||||
): MergeSelected<Ent, Naked, keyof Data & string>;
|
||||
/**
|
||||
* Merges given entity to this EntityManager so it becomes managed. You can force refreshing of existing entities
|
||||
* via second parameter. By default it will return already loaded entities without modifying them.
|
||||
*/
|
||||
merge(data: Entity | EntityData<Entity>, options?: MergeOptions): Entity;
|
||||
/**
|
||||
* Returns total number of entities matching your `where` query.
|
||||
*/
|
||||
count<Hint extends string = never>(
|
||||
where?: FilterQuery<Entity>,
|
||||
options?: CountOptions<Entity, Hint>,
|
||||
): Promise<number>;
|
||||
/** Returns the entity class name associated with this repository. */
|
||||
getEntityName(): string;
|
||||
/**
|
||||
* Returns the underlying EntityManager instance
|
||||
*/
|
||||
getEntityManager(): EntityManager;
|
||||
protected validateRepositoryType(entities: Entity[] | Entity, method: string): void;
|
||||
}
|
||||
218
node_modules/@mikro-orm/core/entity/EntityRepository.js
generated
vendored
Normal file
218
node_modules/@mikro-orm/core/entity/EntityRepository.js
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
import { ValidationError } from '../errors.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
/** Repository class providing a type-safe API for querying and persisting a specific entity type. */
|
||||
export class EntityRepository {
|
||||
em;
|
||||
entityName;
|
||||
constructor(em, entityName) {
|
||||
this.em = em;
|
||||
this.entityName = entityName;
|
||||
}
|
||||
/**
|
||||
* Finds first entity matching your `where` query.
|
||||
*/
|
||||
async findOne(where, options) {
|
||||
return this.getEntityManager().findOne(this.entityName, where, options);
|
||||
}
|
||||
/**
|
||||
* Finds first entity matching your `where` query. If nothing is found, it will throw an error.
|
||||
* You can override the factory for creating this method via `options.failHandler` locally
|
||||
* or via `Configuration.findOneOrFailHandler` globally.
|
||||
*/
|
||||
async findOneOrFail(where, options) {
|
||||
return this.getEntityManager().findOneOrFail(this.entityName, where, options);
|
||||
}
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance. The method accepts either `entityName` together with the entity `data`, or just entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
async upsert(entityOrData, options) {
|
||||
return this.getEntityManager().upsert(this.entityName, entityOrData, options);
|
||||
}
|
||||
/**
|
||||
* Creates or updates the entity, based on whether it is already present in the database.
|
||||
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
|
||||
* entity instance.
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
|
||||
* const authors = await em.getRepository(Author).upsertMany([{ email: 'foo@bar.com', age: 33 }, ...]);
|
||||
* ```
|
||||
*
|
||||
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
|
||||
*
|
||||
* ```ts
|
||||
* // insert into "author" ("age", "email") values (33, 'foo@bar.com'), (666, 'lol@lol.lol') on conflict ("email") do update set "age" = excluded."age"
|
||||
* // select "id" from "author" where "email" = 'foo@bar.com'
|
||||
* const author = await em.getRepository(Author).upsertMany([
|
||||
* { email: 'foo@bar.com', age: 33 },
|
||||
* { email: 'lol@lol.lol', age: 666 },
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
|
||||
*
|
||||
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
|
||||
*/
|
||||
async upsertMany(entitiesOrData, options) {
|
||||
return this.getEntityManager().upsertMany(this.entityName, entitiesOrData, options);
|
||||
}
|
||||
/**
|
||||
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
||||
*/
|
||||
async find(where, options) {
|
||||
return this.getEntityManager().find(this.entityName, where, options);
|
||||
}
|
||||
/**
|
||||
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as tuple
|
||||
* where first element is the array of entities, and the second is the count.
|
||||
*/
|
||||
async findAndCount(where, options) {
|
||||
return this.getEntityManager().findAndCount(this.entityName, where, options);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc EntityManager.findByCursor
|
||||
*/
|
||||
async findByCursor(options) {
|
||||
return this.getEntityManager().findByCursor(this.entityName, options);
|
||||
}
|
||||
/**
|
||||
* Finds all entities of given type. You can pass additional options via the `options` parameter.
|
||||
*/
|
||||
async findAll(options) {
|
||||
return this.getEntityManager().findAll(this.entityName, options);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc EntityManager.stream
|
||||
*/
|
||||
async *stream(options) {
|
||||
yield* this.getEntityManager().stream(this.entityName, options);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc EntityManager.insert
|
||||
*/
|
||||
async insert(data, options) {
|
||||
return this.getEntityManager().insert(this.entityName, data, options);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc EntityManager.insert
|
||||
*/
|
||||
async insertMany(data, options) {
|
||||
return this.getEntityManager().insertMany(this.entityName, data, options);
|
||||
}
|
||||
/**
|
||||
* Fires native update query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
async nativeUpdate(where, data, options) {
|
||||
return this.getEntityManager().nativeUpdate(this.entityName, where, data, options);
|
||||
}
|
||||
/**
|
||||
* Fires native delete query. Calling this has no side effects on the context (identity map).
|
||||
*/
|
||||
async nativeDelete(where, options) {
|
||||
return this.getEntityManager().nativeDelete(this.entityName, where, options);
|
||||
}
|
||||
/**
|
||||
* Maps raw database result to an entity and merges it to this EntityManager.
|
||||
*/
|
||||
map(result, options) {
|
||||
return this.getEntityManager().map(this.entityName, result, options);
|
||||
}
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
||||
*/
|
||||
getReference(id, options) {
|
||||
return this.getEntityManager().getReference(this.entityName, id, options);
|
||||
}
|
||||
/**
|
||||
* Checks whether given property can be populated on the entity.
|
||||
*/
|
||||
canPopulate(property) {
|
||||
return this.getEntityManager().canPopulate(this.entityName, property);
|
||||
}
|
||||
/**
|
||||
* Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
|
||||
*/
|
||||
async populate(entities, populate, options) {
|
||||
this.validateRepositoryType(entities, 'populate');
|
||||
// @ts-ignore hard to type
|
||||
return this.getEntityManager().populate(entities, populate, options);
|
||||
}
|
||||
/**
|
||||
* Creates new instance of given entity and populates it with given data.
|
||||
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
||||
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
||||
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
||||
* the whole `data` parameter will be passed. This means we can also define `constructor(data: Partial<T>)` and
|
||||
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
||||
*
|
||||
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
||||
* symbol to omit some properties from this check without making them optional. Alternatively, use `partial: true`
|
||||
* in the options to disable the strict checks for required properties. This option has no effect on runtime.
|
||||
*
|
||||
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
||||
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
||||
*/
|
||||
create(data, options) {
|
||||
return this.getEntityManager().create(this.entityName, data, options);
|
||||
}
|
||||
/**
|
||||
* Shortcut for `wrap(entity).assign(data, { em })`
|
||||
*/
|
||||
assign(entity, data, options) {
|
||||
this.validateRepositoryType(entity, 'assign');
|
||||
return this.getEntityManager().assign(entity, data, options);
|
||||
}
|
||||
/**
|
||||
* Merges given entity to this EntityManager so it becomes managed. You can force refreshing of existing entities
|
||||
* via second parameter. By default it will return already loaded entities without modifying them.
|
||||
*/
|
||||
merge(data, options) {
|
||||
return this.getEntityManager().merge(this.entityName, data, options);
|
||||
}
|
||||
/**
|
||||
* Returns total number of entities matching your `where` query.
|
||||
*/
|
||||
async count(where = {}, options = {}) {
|
||||
return this.getEntityManager().count(this.entityName, where, options);
|
||||
}
|
||||
/** Returns the entity class name associated with this repository. */
|
||||
getEntityName() {
|
||||
return Utils.className(this.entityName);
|
||||
}
|
||||
/**
|
||||
* Returns the underlying EntityManager instance
|
||||
*/
|
||||
getEntityManager() {
|
||||
return this.em;
|
||||
}
|
||||
validateRepositoryType(entities, method) {
|
||||
entities = Utils.asArray(entities);
|
||||
if (entities.length === 0) {
|
||||
return;
|
||||
}
|
||||
const entityName = entities[0].constructor.name;
|
||||
const repoType = Utils.className(this.entityName);
|
||||
if (entityName && repoType !== entityName) {
|
||||
throw ValidationError.fromWrongRepositoryType(entityName, repoType, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
node_modules/@mikro-orm/core/entity/PolymorphicRef.d.ts
generated
vendored
Normal file
12
node_modules/@mikro-orm/core/entity/PolymorphicRef.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Wrapper class for polymorphic relation reference data.
|
||||
* Holds the discriminator value (type identifier) and the primary key value(s).
|
||||
* Used internally to track polymorphic FK values before hydration.
|
||||
*/
|
||||
export declare class PolymorphicRef {
|
||||
readonly discriminator: string;
|
||||
id: unknown;
|
||||
constructor(discriminator: string, id: unknown);
|
||||
/** Returns `[discriminator, ...idValues]` tuple suitable for column-level expansion. */
|
||||
toTuple(): unknown[];
|
||||
}
|
||||
18
node_modules/@mikro-orm/core/entity/PolymorphicRef.js
generated
vendored
Normal file
18
node_modules/@mikro-orm/core/entity/PolymorphicRef.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
/**
|
||||
* Wrapper class for polymorphic relation reference data.
|
||||
* Holds the discriminator value (type identifier) and the primary key value(s).
|
||||
* Used internally to track polymorphic FK values before hydration.
|
||||
*/
|
||||
export class PolymorphicRef {
|
||||
discriminator;
|
||||
id;
|
||||
constructor(discriminator, id) {
|
||||
this.discriminator = discriminator;
|
||||
this.id = id;
|
||||
}
|
||||
/** Returns `[discriminator, ...idValues]` tuple suitable for column-level expansion. */
|
||||
toTuple() {
|
||||
return [this.discriminator, ...Utils.asArray(this.id)];
|
||||
}
|
||||
}
|
||||
148
node_modules/@mikro-orm/core/entity/Reference.d.ts
generated
vendored
Normal file
148
node_modules/@mikro-orm/core/entity/Reference.d.ts
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
import type {
|
||||
AddEager,
|
||||
AddOptional,
|
||||
Dictionary,
|
||||
EntityClass,
|
||||
EntityKey,
|
||||
EntityProperty,
|
||||
Loaded,
|
||||
LoadedReference,
|
||||
Primary,
|
||||
Ref,
|
||||
} from '../typings.js';
|
||||
import type { FindOneOptions, FindOneOrFailOptions } from '../drivers/IDatabaseDriver.js';
|
||||
/** Wrapper around an entity that provides lazy loading capabilities and identity-preserving reference semantics. */
|
||||
export declare class Reference<T extends object> {
|
||||
private entity;
|
||||
private property?;
|
||||
constructor(entity: T);
|
||||
/** Creates a Reference wrapper for the given entity, preserving identity if one already exists. */
|
||||
static create<T extends object>(entity: T | Ref<T>): Ref<T>;
|
||||
/** Creates a Reference wrapper for an entity identified by its primary key, wrapped in a Ref. */
|
||||
static createFromPK<T extends object>(
|
||||
entityType: EntityClass<T>,
|
||||
pk: Primary<T>,
|
||||
options?: {
|
||||
schema?: string;
|
||||
},
|
||||
): Ref<T>;
|
||||
/** Creates an uninitialized entity reference by primary key without wrapping it in a Reference. */
|
||||
static createNakedFromPK<T extends object>(
|
||||
entityType: EntityClass<T>,
|
||||
pk: Primary<T>,
|
||||
options?: {
|
||||
schema?: string;
|
||||
},
|
||||
): T;
|
||||
/**
|
||||
* Checks whether the argument is instance of `Reference` wrapper.
|
||||
*/
|
||||
static isReference<T extends object>(data: any): data is Reference<T>;
|
||||
/**
|
||||
* Wraps the entity in a `Reference` wrapper if the property is defined as `ref`.
|
||||
*/
|
||||
static wrapReference<T extends object, O extends object>(
|
||||
entity: T | Reference<T>,
|
||||
prop: EntityProperty<O, T>,
|
||||
): Reference<T> | T;
|
||||
/**
|
||||
* Returns wrapped entity.
|
||||
*/
|
||||
static unwrapReference<T extends object>(ref: T | Reference<T> | ScalarReference<T> | Ref<T>): T;
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded). Returns the entity.
|
||||
* If the entity is not found in the database (e.g. it was deleted in the meantime, or currently active filters disallow loading of it)
|
||||
* the method returns `null`. Use `loadOrFail()` if you want an error to be thrown in such a case.
|
||||
*/
|
||||
load<TT extends T, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
options?: LoadReferenceOptions<TT, P, F, E>,
|
||||
): Promise<Loaded<TT, P, F, E> | null>;
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
||||
*/
|
||||
loadOrFail<TT extends T, P extends string = never, F extends string = '*', E extends string = never>(
|
||||
options?: LoadReferenceOrFailOptions<TT, P, F, E>,
|
||||
): Promise<Loaded<TT, P, F, E>>;
|
||||
private set;
|
||||
/** Returns the underlying entity without checking initialization state. */
|
||||
unwrap(): T;
|
||||
/** Returns the underlying entity, throwing an error if the reference is not initialized. */
|
||||
getEntity(): T;
|
||||
/** Returns the value of a property on the underlying entity. Throws if the reference is not initialized. */
|
||||
getProperty<K extends keyof T>(prop: K): T[K];
|
||||
/** Loads the entity if needed, then returns the value of the specified property. */
|
||||
loadProperty<TT extends T, P extends string = never, K extends keyof TT = keyof TT>(
|
||||
prop: K,
|
||||
options?: LoadReferenceOrFailOptions<TT, P>,
|
||||
): Promise<Loaded<TT, P>[K]>;
|
||||
/** Returns whether the underlying entity has been fully loaded from the database. */
|
||||
isInitialized(): boolean;
|
||||
/** Marks the underlying entity as populated or not for serialization purposes. */
|
||||
populated(populated?: boolean): void;
|
||||
/** Serializes the underlying entity to a plain JSON object. */
|
||||
toJSON(...args: any[]): Dictionary;
|
||||
}
|
||||
/** Wrapper for lazy scalar properties that provides on-demand loading from the database. */
|
||||
export declare class ScalarReference<Value> {
|
||||
#private;
|
||||
private value?;
|
||||
private entity?;
|
||||
constructor(value?: Value | undefined, initialized?: boolean);
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns either the whole entity, or the requested property.
|
||||
*/
|
||||
load(options?: Omit<LoadReferenceOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value | undefined>;
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
||||
*/
|
||||
loadOrFail(options?: Omit<LoadReferenceOrFailOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value>;
|
||||
/** Sets the scalar value and marks the reference as initialized. */
|
||||
set(value: Value): void;
|
||||
/** Binds this scalar reference to a specific entity and property for lazy loading support. */
|
||||
bind<Entity extends object>(entity: Entity, property: EntityKey<Entity>): void;
|
||||
/** Returns the current scalar value, or undefined if not yet loaded. */
|
||||
unwrap(): Value | undefined;
|
||||
/** Returns whether the scalar value has been loaded. */
|
||||
isInitialized(): boolean;
|
||||
}
|
||||
/** Options for `Reference.load()` to control how the referenced entity is loaded. */
|
||||
export interface LoadReferenceOptions<
|
||||
T extends object,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends FindOneOptions<T, P, F, E> {
|
||||
/** Whether to use the dataloader for batching reference loads. */
|
||||
dataloader?: boolean;
|
||||
}
|
||||
/** Options for `Reference.loadOrFail()` which throws when the entity is not found. */
|
||||
export interface LoadReferenceOrFailOptions<
|
||||
T extends object,
|
||||
P extends string = never,
|
||||
F extends string = '*',
|
||||
E extends string = never,
|
||||
> extends FindOneOrFailOptions<T, P, F, E> {
|
||||
/** Whether to use the dataloader for batching reference loads. */
|
||||
dataloader?: boolean;
|
||||
}
|
||||
/**
|
||||
* shortcut for `wrap(entity).toReference()`
|
||||
*/
|
||||
export declare function ref<I extends unknown | Ref<unknown> | undefined | null, T extends I & {}>(
|
||||
entity: I,
|
||||
): (Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>) | AddOptional<typeof entity>;
|
||||
/**
|
||||
* shortcut for `Reference.createFromPK(entityType, pk)`
|
||||
*/
|
||||
export declare function ref<I extends unknown | undefined | null, T, PKV extends Primary<T> = Primary<T>>(
|
||||
entityType: EntityClass<T>,
|
||||
pk: I,
|
||||
): Ref<T> | AddOptional<typeof pk>;
|
||||
/**
|
||||
* shortcut for `Reference.createNakedFromPK(entityType, pk)`
|
||||
*/
|
||||
export declare function rel<T, PK extends Primary<T>>(entityType: EntityClass<T>, pk: T | PK): T;
|
||||
export { Reference as Ref };
|
||||
312
node_modules/@mikro-orm/core/entity/Reference.js
generated
vendored
Normal file
312
node_modules/@mikro-orm/core/entity/Reference.js
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
import { DataloaderType } from '../enums.js';
|
||||
import { helper, wrap } from './wrap.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { QueryHelper } from '../utils/QueryHelper.js';
|
||||
import { NotFoundError } from '../errors.js';
|
||||
import { inspect } from '../logging/inspect.js';
|
||||
/** Wrapper around an entity that provides lazy loading capabilities and identity-preserving reference semantics. */
|
||||
export class Reference {
|
||||
entity;
|
||||
property;
|
||||
constructor(entity) {
|
||||
this.entity = entity;
|
||||
this.set(entity);
|
||||
const meta = helper(this.entity).__meta;
|
||||
meta.primaryKeys.forEach(primaryKey => {
|
||||
Object.defineProperty(this, primaryKey, {
|
||||
get() {
|
||||
return this.entity[primaryKey];
|
||||
},
|
||||
});
|
||||
});
|
||||
if (meta.serializedPrimaryKey && meta.primaryKeys[0] !== meta.serializedPrimaryKey) {
|
||||
Object.defineProperty(this, meta.serializedPrimaryKey, {
|
||||
get() {
|
||||
return helper(this.entity).getSerializedPrimaryKey();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
/** Creates a Reference wrapper for the given entity, preserving identity if one already exists. */
|
||||
static create(entity) {
|
||||
const unwrapped = Reference.unwrapReference(entity);
|
||||
const ref = helper(entity).toReference();
|
||||
if (unwrapped !== ref.unwrap()) {
|
||||
ref.set(unwrapped);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
/** Creates a Reference wrapper for an entity identified by its primary key, wrapped in a Ref. */
|
||||
static createFromPK(entityType, pk, options) {
|
||||
const ref = this.createNakedFromPK(entityType, pk, options);
|
||||
return helper(ref)?.toReference() ?? ref;
|
||||
}
|
||||
/** Creates an uninitialized entity reference by primary key without wrapping it in a Reference. */
|
||||
static createNakedFromPK(entityType, pk, options) {
|
||||
const factory = entityType.prototype.__factory;
|
||||
if (!factory) {
|
||||
// this can happen only if `ref()` is used as a property initializer, and the value is important only for the
|
||||
// inference of defaults, so it's fine to return it directly without wrapping with `Reference` class
|
||||
return pk;
|
||||
}
|
||||
const entity = factory.createReference(entityType, pk, {
|
||||
merge: false,
|
||||
convertCustomTypes: false,
|
||||
...options,
|
||||
});
|
||||
const wrapped = helper(entity);
|
||||
wrapped.__meta.primaryKeys.forEach(key => wrapped.__loadedProperties.add(key));
|
||||
wrapped.__originalEntityData = factory.getComparator().prepareEntity(entity);
|
||||
return entity;
|
||||
}
|
||||
/**
|
||||
* Checks whether the argument is instance of `Reference` wrapper.
|
||||
*/
|
||||
static isReference(data) {
|
||||
return data && !!data.__reference;
|
||||
}
|
||||
/**
|
||||
* Wraps the entity in a `Reference` wrapper if the property is defined as `ref`.
|
||||
*/
|
||||
static wrapReference(entity, prop) {
|
||||
if (entity && prop.ref && !Reference.isReference(entity)) {
|
||||
const ref = Reference.create(entity);
|
||||
ref.property = prop;
|
||||
return ref;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
/**
|
||||
* Returns wrapped entity.
|
||||
*/
|
||||
static unwrapReference(ref) {
|
||||
return Reference.isReference(ref) ? ref.unwrap() : ref;
|
||||
}
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded). Returns the entity.
|
||||
* If the entity is not found in the database (e.g. it was deleted in the meantime, or currently active filters disallow loading of it)
|
||||
* the method returns `null`. Use `loadOrFail()` if you want an error to be thrown in such a case.
|
||||
*/
|
||||
async load(options = {}) {
|
||||
const wrapped = helper(this.entity);
|
||||
if (!wrapped.__em) {
|
||||
return this.entity;
|
||||
}
|
||||
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property?.filters, options.filters) };
|
||||
if (this.isInitialized() && !options.refresh && options.populate) {
|
||||
await wrapped.__em.populate(this.entity, options.populate, options);
|
||||
}
|
||||
if (!this.isInitialized() || options.refresh) {
|
||||
if (
|
||||
options.dataloader ??
|
||||
[DataloaderType.ALL, DataloaderType.REFERENCE].includes(wrapped.__em.config.getDataloaderType())
|
||||
) {
|
||||
const dataLoader = await wrapped.__em.getDataLoader('ref');
|
||||
return dataLoader.load([this, options]);
|
||||
}
|
||||
return wrapped.init(options);
|
||||
}
|
||||
return this.entity;
|
||||
}
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
||||
*/
|
||||
async loadOrFail(options = {}) {
|
||||
const ret = await this.load(options);
|
||||
if (!ret) {
|
||||
const wrapped = helper(this.entity);
|
||||
options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
|
||||
const entityName = this.entity.constructor.name;
|
||||
const where = wrapped.getPrimaryKey();
|
||||
throw options.failHandler(entityName, where);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
set(entity) {
|
||||
this.entity = Reference.unwrapReference(entity);
|
||||
delete helper(this.entity).__reference;
|
||||
}
|
||||
/** Returns the underlying entity without checking initialization state. */
|
||||
unwrap() {
|
||||
return this.entity;
|
||||
}
|
||||
/** Returns the underlying entity, throwing an error if the reference is not initialized. */
|
||||
getEntity() {
|
||||
if (!this.isInitialized()) {
|
||||
throw new Error(
|
||||
`Reference<${helper(this.entity).__meta.name}> ${helper(this.entity).getPrimaryKey()} not initialized`,
|
||||
);
|
||||
}
|
||||
return this.entity;
|
||||
}
|
||||
/** Returns the value of a property on the underlying entity. Throws if the reference is not initialized. */
|
||||
getProperty(prop) {
|
||||
return this.getEntity()[prop];
|
||||
}
|
||||
/** Loads the entity if needed, then returns the value of the specified property. */
|
||||
async loadProperty(prop, options) {
|
||||
await this.loadOrFail(options);
|
||||
return this.getEntity()[prop];
|
||||
}
|
||||
/** Returns whether the underlying entity has been fully loaded from the database. */
|
||||
isInitialized() {
|
||||
return helper(this.entity).__initialized;
|
||||
}
|
||||
/** Marks the underlying entity as populated or not for serialization purposes. */
|
||||
populated(populated) {
|
||||
helper(this.entity).populated(populated);
|
||||
}
|
||||
/** Serializes the underlying entity to a plain JSON object. */
|
||||
toJSON(...args) {
|
||||
return wrap(this.entity).toJSON(...args);
|
||||
}
|
||||
/** @ignore */
|
||||
[Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
|
||||
const object = { ...this };
|
||||
const hidden = ['meta', 'property'];
|
||||
hidden.forEach(k => delete object[k]);
|
||||
const ret = inspect(object, { depth });
|
||||
const wrapped = helper(this.entity);
|
||||
const meta = wrapped.__meta;
|
||||
/* v8 ignore next */
|
||||
const pk = wrapped.hasPrimaryKey() ? '<' + wrapped.getSerializedPrimaryKey() + '>' : '';
|
||||
const name = `Ref<${meta.className}${pk}>`;
|
||||
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
||||
}
|
||||
}
|
||||
/** Wrapper for lazy scalar properties that provides on-demand loading from the database. */
|
||||
export class ScalarReference {
|
||||
value;
|
||||
entity;
|
||||
#property;
|
||||
#initialized;
|
||||
constructor(value, initialized = value != null) {
|
||||
this.value = value;
|
||||
this.#initialized = initialized;
|
||||
}
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns either the whole entity, or the requested property.
|
||||
*/
|
||||
async load(options) {
|
||||
const opts = typeof options === 'object' ? options : { prop: options };
|
||||
if (!this.#initialized || opts.refresh) {
|
||||
if (this.entity == null || this.#property == null) {
|
||||
throw new Error('Cannot load scalar reference that is not bound to an entity property.');
|
||||
}
|
||||
await helper(this.entity).populate([this.#property], opts);
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
/**
|
||||
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
||||
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
||||
*/
|
||||
async loadOrFail(options = {}) {
|
||||
const ret = await this.load(options);
|
||||
if (ret == null) {
|
||||
const wrapped = helper(this.entity);
|
||||
options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
|
||||
const entityName = this.entity.constructor.name;
|
||||
throw NotFoundError.failedToLoadProperty(entityName, this.#property, wrapped.getPrimaryKey());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/** Sets the scalar value and marks the reference as initialized. */
|
||||
set(value) {
|
||||
this.value = value;
|
||||
this.#initialized = true;
|
||||
}
|
||||
/** Binds this scalar reference to a specific entity and property for lazy loading support. */
|
||||
bind(entity, property) {
|
||||
this.entity = entity;
|
||||
this.#property = property;
|
||||
Object.defineProperty(this, 'entity', { enumerable: false, value: entity });
|
||||
}
|
||||
/** Returns the current scalar value, or undefined if not yet loaded. */
|
||||
unwrap() {
|
||||
return this.value;
|
||||
}
|
||||
/** Returns whether the scalar value has been loaded. */
|
||||
isInitialized() {
|
||||
return this.#initialized;
|
||||
}
|
||||
/** @ignore */
|
||||
/* v8 ignore next */
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
return this.#initialized ? `Ref<${inspect(this.value)}>` : `Ref<?>`;
|
||||
}
|
||||
}
|
||||
Object.defineProperties(Reference.prototype, {
|
||||
__reference: { value: true, enumerable: false },
|
||||
__meta: {
|
||||
get() {
|
||||
return this.entity.__meta;
|
||||
},
|
||||
},
|
||||
__platform: {
|
||||
get() {
|
||||
return this.entity.__platform;
|
||||
},
|
||||
},
|
||||
__helper: {
|
||||
get() {
|
||||
return this.entity.__helper;
|
||||
},
|
||||
},
|
||||
$: {
|
||||
get() {
|
||||
return this.entity;
|
||||
},
|
||||
},
|
||||
get: {
|
||||
get() {
|
||||
return () => this.entity;
|
||||
},
|
||||
},
|
||||
});
|
||||
Object.defineProperties(ScalarReference.prototype, {
|
||||
__scalarReference: { value: true, enumerable: false },
|
||||
$: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
},
|
||||
get: {
|
||||
get() {
|
||||
return () => this.value;
|
||||
},
|
||||
},
|
||||
});
|
||||
/**
|
||||
* shortcut for `wrap(entity).toReference()`
|
||||
*/
|
||||
export function ref(entityOrType, pk) {
|
||||
if (entityOrType == null) {
|
||||
return entityOrType;
|
||||
}
|
||||
if (Utils.isEntity(entityOrType, true)) {
|
||||
return helper(entityOrType).toReference();
|
||||
}
|
||||
if (Utils.isEntity(pk, true)) {
|
||||
return helper(pk).toReference();
|
||||
}
|
||||
if (arguments.length === 1) {
|
||||
return new ScalarReference(entityOrType, true);
|
||||
}
|
||||
if (pk == null) {
|
||||
return pk;
|
||||
}
|
||||
return Reference.createFromPK(entityOrType, pk);
|
||||
}
|
||||
/**
|
||||
* shortcut for `Reference.createNakedFromPK(entityType, pk)`
|
||||
*/
|
||||
export function rel(entityType, pk) {
|
||||
if (pk == null || Utils.isEntity(pk)) {
|
||||
return pk;
|
||||
}
|
||||
return Reference.createNakedFromPK(entityType, pk);
|
||||
}
|
||||
export { Reference as Ref };
|
||||
129
node_modules/@mikro-orm/core/entity/WrappedEntity.d.ts
generated
vendored
Normal file
129
node_modules/@mikro-orm/core/entity/WrappedEntity.d.ts
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
import type { PopulatePath } from '../enums.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type {
|
||||
Dictionary,
|
||||
EntityData,
|
||||
EntityDictionary,
|
||||
EntityMetadata,
|
||||
IHydrator,
|
||||
EntityKey,
|
||||
PopulateOptions,
|
||||
Primary,
|
||||
AutoPath,
|
||||
Ref,
|
||||
AddEager,
|
||||
LoadedReference,
|
||||
EntityDTO,
|
||||
Loaded,
|
||||
SerializeDTO,
|
||||
FromEntityType,
|
||||
IsSubset,
|
||||
MergeSelected,
|
||||
} from '../typings.js';
|
||||
import { Reference } from './Reference.js';
|
||||
import { type AssignOptions } from './EntityAssigner.js';
|
||||
import type { EntityLoaderOptions } from './EntityLoader.js';
|
||||
import type { EntityIdentifier } from './EntityIdentifier.js';
|
||||
import type { SerializationContext } from '../serialization/SerializationContext.js';
|
||||
import { type SerializeOptions } from '../serialization/EntitySerializer.js';
|
||||
import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
import type { Configuration } from '../utils/Configuration.js';
|
||||
/** @internal Wrapper attached to every managed entity, holding ORM state such as initialization flags, identity map references, and change tracking snapshots. */
|
||||
export declare class WrappedEntity<Entity extends object> {
|
||||
__initialized: boolean;
|
||||
__populated?: boolean;
|
||||
__managed?: boolean;
|
||||
__onLoadFired?: boolean;
|
||||
__schema?: string;
|
||||
__em?: EntityManager;
|
||||
__loadedProperties: Set<string>;
|
||||
__data: Dictionary;
|
||||
__processing: boolean;
|
||||
__serializationContext: {
|
||||
root?: SerializationContext<Entity>;
|
||||
populate?: PopulateOptions<Entity>[];
|
||||
fields?: Set<string>;
|
||||
exclude?: readonly string[];
|
||||
};
|
||||
/** stores last known primary key, as its current state might be broken due to propagation/orphan removal, but we need to know the PK to be able t remove the entity */
|
||||
__pk?: Primary<Entity>;
|
||||
/** holds the reference wrapper instance (if created), so we can maintain the identity on reference wrappers too */
|
||||
__reference?: Reference<Entity>;
|
||||
/** holds last entity data snapshot, so we can compute changes when persisting managed entities */
|
||||
__originalEntityData?: EntityData<Entity>;
|
||||
/** holds wrapped primary key, so we can compute change set without eager commit */
|
||||
__identifier?: EntityIdentifier;
|
||||
private readonly entity;
|
||||
private readonly hydrator;
|
||||
private readonly pkGetter?;
|
||||
private readonly pkSerializer?;
|
||||
private readonly pkGetterConverted?;
|
||||
constructor(
|
||||
entity: Entity,
|
||||
hydrator: IHydrator,
|
||||
pkGetter?: (e: Entity) => Primary<Entity>,
|
||||
pkSerializer?: (e: Entity) => string,
|
||||
pkGetterConverted?: (e: Entity) => Primary<Entity>,
|
||||
);
|
||||
/** Returns whether the entity has been fully loaded from the database. */
|
||||
isInitialized(): boolean;
|
||||
/** Returns whether the entity is managed by an EntityManager (tracked in the identity map). */
|
||||
isManaged(): boolean;
|
||||
/** Marks the entity as populated or not for serialization purposes. */
|
||||
populated(populated?: boolean | undefined): void;
|
||||
/** Sets the serialization context with populate hints, field selections, and exclusions. */
|
||||
setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(
|
||||
options: LoadHint<Entity, Hint, Fields, Exclude>,
|
||||
): void;
|
||||
/** Returns a Reference wrapper for this entity, creating one if it does not already exist. */
|
||||
toReference(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
|
||||
/** Converts the entity to a plain object representation, optionally excluding specified fields. */
|
||||
toObject<Ignored extends EntityKey<Entity> = never>(ignoreFields?: Ignored[]): Omit<EntityDTO<Entity>, Ignored>;
|
||||
/** Serializes the entity with control over which relations and fields to include or exclude. */
|
||||
serialize<Hint extends string = never, Exclude extends string = never>(
|
||||
options?: SerializeOptions<Entity, Hint, Exclude>,
|
||||
): SerializeDTO<Entity, Hint, Exclude>;
|
||||
/** Converts the entity to a plain object, including all properties regardless of serialization rules. */
|
||||
toPOJO(): EntityDTO<Entity>;
|
||||
/** Serializes the entity using its `toJSON` method (supports `JSON.stringify`). */
|
||||
toJSON(...args: any[]): EntityDictionary<Entity>;
|
||||
/** Assigns the given data to this entity, updating its properties and relations. */
|
||||
assign<
|
||||
Naked extends FromEntityType<Entity> = FromEntityType<Entity>,
|
||||
Convert extends boolean = false,
|
||||
Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> =
|
||||
| EntityData<Naked, Convert>
|
||||
| Partial<EntityDTO<Naked>>,
|
||||
>(
|
||||
data: Data & IsSubset<EntityData<Naked>, Data>,
|
||||
options?: AssignOptions<Convert>,
|
||||
): MergeSelected<Entity, Naked, keyof Data & string>;
|
||||
/** Initializes (refreshes) the entity by reloading it from the database. Returns null if not found. */
|
||||
init<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(
|
||||
options?: FindOneOptions<Entity, Hint, Fields, Excludes>,
|
||||
): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
|
||||
/** Loads the specified relations on this entity. */
|
||||
populate<Hint extends string = never, Fields extends string = never>(
|
||||
populate: AutoPath<Entity, Hint, PopulatePath.ALL>[] | false,
|
||||
options?: EntityLoaderOptions<Entity, Fields>,
|
||||
): Promise<Loaded<Entity, Hint>>;
|
||||
/** Returns whether this entity has a primary key value set. */
|
||||
hasPrimaryKey(): boolean;
|
||||
/** Returns the primary key value, optionally converting custom types to their database representation. */
|
||||
getPrimaryKey(convertCustomTypes?: boolean): Primary<Entity> | null;
|
||||
/** Returns all primary key values as an array. Used internally for composite key handling. */
|
||||
getPrimaryKeys(convertCustomTypes?: boolean): Primary<Entity>[] | null;
|
||||
/** Returns the database schema this entity belongs to. */
|
||||
getSchema(): string | undefined;
|
||||
/** Sets the database schema for this entity. */
|
||||
setSchema(schema?: string): void;
|
||||
/** Sets the primary key value on the entity. */
|
||||
setPrimaryKey(id: Primary<Entity> | null): void;
|
||||
/** Returns the primary key serialized as a string suitable for identity map lookups. */
|
||||
getSerializedPrimaryKey(): string;
|
||||
get __meta(): EntityMetadata<Entity>;
|
||||
get __platform(): Platform;
|
||||
get __config(): Configuration;
|
||||
get __primaryKeys(): Primary<Entity>[];
|
||||
}
|
||||
180
node_modules/@mikro-orm/core/entity/WrappedEntity.js
generated
vendored
Normal file
180
node_modules/@mikro-orm/core/entity/WrappedEntity.js
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
import { Reference } from './Reference.js';
|
||||
import { EntityTransformer } from '../serialization/EntityTransformer.js';
|
||||
import { EntityAssigner } from './EntityAssigner.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { ValidationError } from '../errors.js';
|
||||
import { helper } from './wrap.js';
|
||||
import { EntitySerializer } from '../serialization/EntitySerializer.js';
|
||||
import { expandDotPaths } from './utils.js';
|
||||
/** @internal Wrapper attached to every managed entity, holding ORM state such as initialization flags, identity map references, and change tracking snapshots. */
|
||||
export class WrappedEntity {
|
||||
constructor(entity, hydrator, pkGetter, pkSerializer, pkGetterConverted) {
|
||||
this.entity = entity;
|
||||
this.hydrator = hydrator;
|
||||
this.pkGetter = pkGetter;
|
||||
this.pkSerializer = pkSerializer;
|
||||
this.pkGetterConverted = pkGetterConverted;
|
||||
this.__initialized = true;
|
||||
this.__serializationContext = {};
|
||||
this.__loadedProperties = new Set();
|
||||
this.__data = {};
|
||||
this.__processing = false;
|
||||
}
|
||||
/** Returns whether the entity has been fully loaded from the database. */
|
||||
isInitialized() {
|
||||
return this.__initialized;
|
||||
}
|
||||
/** Returns whether the entity is managed by an EntityManager (tracked in the identity map). */
|
||||
isManaged() {
|
||||
return !!this.__managed;
|
||||
}
|
||||
/** Marks the entity as populated or not for serialization purposes. */
|
||||
populated(populated = true) {
|
||||
this.__populated = populated;
|
||||
}
|
||||
/** Sets the serialization context with populate hints, field selections, and exclusions. */
|
||||
setSerializationContext(options) {
|
||||
const exclude = options.exclude ?? [];
|
||||
const context = this.__serializationContext;
|
||||
const populate = expandDotPaths(this.__meta, options.populate);
|
||||
context.populate = context.populate ? context.populate.concat(populate) : populate;
|
||||
context.exclude = context.exclude ? context.exclude.concat(exclude) : exclude;
|
||||
if (context.fields && options.fields) {
|
||||
options.fields.forEach(f => context.fields.add(f));
|
||||
} else if (options.fields) {
|
||||
context.fields = new Set(options.fields);
|
||||
} else {
|
||||
context.fields = new Set(['*']);
|
||||
}
|
||||
}
|
||||
/** Returns a Reference wrapper for this entity, creating one if it does not already exist. */
|
||||
toReference() {
|
||||
this.__reference ??= new Reference(this.entity);
|
||||
return this.__reference;
|
||||
}
|
||||
/** Converts the entity to a plain object representation, optionally excluding specified fields. */
|
||||
toObject(ignoreFields) {
|
||||
return EntityTransformer.toObject(this.entity, ignoreFields);
|
||||
}
|
||||
/** Serializes the entity with control over which relations and fields to include or exclude. */
|
||||
serialize(options) {
|
||||
return EntitySerializer.serialize(this.entity, options);
|
||||
}
|
||||
/** Converts the entity to a plain object, including all properties regardless of serialization rules. */
|
||||
toPOJO() {
|
||||
return EntityTransformer.toObject(this.entity, [], true);
|
||||
}
|
||||
/** Serializes the entity using its `toJSON` method (supports `JSON.stringify`). */
|
||||
toJSON(...args) {
|
||||
// toJSON methods is added to the prototype during discovery to support automatic serialization via JSON.stringify()
|
||||
return this.entity.toJSON(...args);
|
||||
}
|
||||
/** Assigns the given data to this entity, updating its properties and relations. */
|
||||
assign(data, options) {
|
||||
if ('assign' in this.entity) {
|
||||
return this.entity.assign(data, options);
|
||||
}
|
||||
return EntityAssigner.assign(this.entity, data, options);
|
||||
}
|
||||
/** Initializes (refreshes) the entity by reloading it from the database. Returns null if not found. */
|
||||
async init(options) {
|
||||
if (!this.__em) {
|
||||
throw ValidationError.entityNotManaged(this.entity);
|
||||
}
|
||||
return this.__em.findOne(this.entity.constructor, this.entity, {
|
||||
...options,
|
||||
refresh: true,
|
||||
schema: this.__schema,
|
||||
});
|
||||
}
|
||||
/** Loads the specified relations on this entity. */
|
||||
async populate(populate, options = {}) {
|
||||
if (!this.__em) {
|
||||
throw ValidationError.entityNotManaged(this.entity);
|
||||
}
|
||||
// @ts-ignore hard to type
|
||||
await this.__em.populate(this.entity, populate, options);
|
||||
return this.entity;
|
||||
}
|
||||
/** Returns whether this entity has a primary key value set. */
|
||||
hasPrimaryKey() {
|
||||
const pk = this.getPrimaryKey();
|
||||
return pk != null;
|
||||
}
|
||||
/** Returns the primary key value, optionally converting custom types to their database representation. */
|
||||
getPrimaryKey(convertCustomTypes = false) {
|
||||
const prop = this.__meta.getPrimaryProps()[0];
|
||||
if (!prop) {
|
||||
return null;
|
||||
}
|
||||
if (this.__pk != null && this.__meta.compositePK) {
|
||||
return Utils.getCompositeKeyValue(
|
||||
this.__pk,
|
||||
this.__meta,
|
||||
convertCustomTypes ? 'convertToDatabaseValue' : false,
|
||||
this.__platform,
|
||||
);
|
||||
}
|
||||
if (convertCustomTypes && this.__pk != null && prop.customType) {
|
||||
return prop.customType.convertToDatabaseValue(this.__pk, this.__platform);
|
||||
}
|
||||
if (convertCustomTypes) {
|
||||
return this.__pk ?? this.pkGetterConverted(this.entity);
|
||||
}
|
||||
return this.__pk ?? this.pkGetter(this.entity);
|
||||
}
|
||||
/** Returns all primary key values as an array. Used internally for composite key handling. */
|
||||
// TODO: currently used only in `Driver.syncCollection` — candidate for removal
|
||||
getPrimaryKeys(convertCustomTypes = false) {
|
||||
const pk = this.getPrimaryKey(convertCustomTypes);
|
||||
if (pk == null) {
|
||||
return null;
|
||||
}
|
||||
if (this.__meta.compositePK) {
|
||||
return this.__meta.primaryKeys.reduce((ret, pk) => {
|
||||
const child = this.entity[pk];
|
||||
if (Utils.isEntity(child, true)) {
|
||||
const childPk = helper(child).getPrimaryKeys(convertCustomTypes);
|
||||
ret.push(...childPk);
|
||||
} else {
|
||||
ret.push(child);
|
||||
}
|
||||
return ret;
|
||||
}, []);
|
||||
}
|
||||
return [pk];
|
||||
}
|
||||
/** Returns the database schema this entity belongs to. */
|
||||
getSchema() {
|
||||
return this.__schema;
|
||||
}
|
||||
/** Sets the database schema for this entity. */
|
||||
setSchema(schema) {
|
||||
this.__schema = schema;
|
||||
}
|
||||
/** Sets the primary key value on the entity. */
|
||||
setPrimaryKey(id) {
|
||||
this.entity[this.__meta.primaryKeys[0]] = id;
|
||||
this.__pk = id;
|
||||
}
|
||||
/** Returns the primary key serialized as a string suitable for identity map lookups. */
|
||||
getSerializedPrimaryKey() {
|
||||
return this.pkSerializer(this.entity);
|
||||
}
|
||||
get __meta() {
|
||||
return this.entity.__meta;
|
||||
}
|
||||
get __platform() {
|
||||
return this.entity.__platform;
|
||||
}
|
||||
get __config() {
|
||||
return this.__em?.config ?? this.entity.__config;
|
||||
}
|
||||
get __primaryKeys() {
|
||||
return Utils.getPrimaryKeyValues(this.entity, this.__meta);
|
||||
}
|
||||
/** @ignore */
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
return `[WrappedEntity<${this.__meta.className}>]`;
|
||||
}
|
||||
}
|
||||
1372
node_modules/@mikro-orm/core/entity/defineEntity.d.ts
generated
vendored
Normal file
1372
node_modules/@mikro-orm/core/entity/defineEntity.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
547
node_modules/@mikro-orm/core/entity/defineEntity.js
generated
vendored
Normal file
547
node_modules/@mikro-orm/core/entity/defineEntity.js
generated
vendored
Normal file
@@ -0,0 +1,547 @@
|
||||
import { types } from '../types/index.js';
|
||||
import { EntitySchema } from '../metadata/EntitySchema.js';
|
||||
// Parameter-level sync assertion lives in tests/defineEntity.test.ts to avoid
|
||||
// instantiating the full builder class in production builds (~680 instantiations).
|
||||
/** @internal */
|
||||
export class UniversalPropertyOptionsBuilder {
|
||||
'~options';
|
||||
'~type';
|
||||
constructor(options) {
|
||||
this['~options'] = options;
|
||||
}
|
||||
assignOptions(options) {
|
||||
return new UniversalPropertyOptionsBuilder({ ...this['~options'], ...options });
|
||||
}
|
||||
$type() {
|
||||
return this.assignOptions({});
|
||||
}
|
||||
/**
|
||||
* Alias for `fieldName`.
|
||||
*/
|
||||
name(name) {
|
||||
return this.assignOptions({ name });
|
||||
}
|
||||
/**
|
||||
* Specify database column name for this property.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/naming-strategy
|
||||
*/
|
||||
fieldName(fieldName) {
|
||||
return this.assignOptions({ fieldName });
|
||||
}
|
||||
/**
|
||||
* Specify database column names for this property.
|
||||
* Same as `fieldName` but for composite FKs.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/naming-strategy
|
||||
*/
|
||||
fieldNames(...fieldNames) {
|
||||
return this.assignOptions({ fieldNames });
|
||||
}
|
||||
/**
|
||||
* Specify an exact database column type for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. This option is only for simple properties represented by a single column. (SQL only)
|
||||
*/
|
||||
columnType(columnType) {
|
||||
return this.assignOptions({ columnType });
|
||||
}
|
||||
/**
|
||||
* Specify an exact database column type for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. This option is suitable for composite keys, where one property is represented by multiple columns. (SQL only)
|
||||
*/
|
||||
columnTypes(...columnTypes) {
|
||||
return this.assignOptions({ columnTypes });
|
||||
}
|
||||
/**
|
||||
* Explicitly specify the runtime type.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/metadata-providers
|
||||
* @see https://mikro-orm.io/docs/custom-types
|
||||
*/
|
||||
type(type) {
|
||||
return this.assignOptions({ type });
|
||||
}
|
||||
/**
|
||||
* Runtime type of the property. This is the JS type that your property is mapped to, e.g. `string` or `number`, and is normally inferred automatically via `reflect-metadata`.
|
||||
* In some cases, the inference won't work, and you might need to specify the `runtimeType` explicitly - the most common one is when you use a union type with null like `foo: number | null`.
|
||||
*/
|
||||
runtimeType(runtimeType) {
|
||||
return this.assignOptions({ runtimeType });
|
||||
}
|
||||
/**
|
||||
* Set length of database column, used for datetime/timestamp/varchar column types for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
||||
*/
|
||||
length(length) {
|
||||
return this.assignOptions({ length });
|
||||
}
|
||||
/**
|
||||
* Set precision of database column to represent the number of significant digits. (SQL only)
|
||||
*/
|
||||
precision(precision) {
|
||||
return this.assignOptions({ precision });
|
||||
}
|
||||
/**
|
||||
* Set scale of database column to represents the number of digits after the decimal point. (SQL only)
|
||||
*/
|
||||
scale(scale) {
|
||||
return this.assignOptions({ scale });
|
||||
}
|
||||
autoincrement(autoincrement = true) {
|
||||
return this.assignOptions({ autoincrement });
|
||||
}
|
||||
/**
|
||||
* Add the property to the `returning` statement.
|
||||
*/
|
||||
returning(returning = true) {
|
||||
return this.assignOptions({ returning });
|
||||
}
|
||||
/**
|
||||
* Automatically set the property value when entity gets created, executed during flush operation.
|
||||
*/
|
||||
onCreate(onCreate) {
|
||||
return this.assignOptions({ onCreate });
|
||||
}
|
||||
/**
|
||||
* Automatically update the property value every time entity gets updated, executed during flush operation.
|
||||
*/
|
||||
onUpdate(onUpdate) {
|
||||
return this.assignOptions({ onUpdate });
|
||||
}
|
||||
/**
|
||||
* Specify default column value for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}.
|
||||
* This is a runtime value, assignable to the entity property. (SQL only)
|
||||
*/
|
||||
default(defaultValue) {
|
||||
return this.assignOptions({ default: defaultValue });
|
||||
}
|
||||
/**
|
||||
* Specify SQL functions for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
||||
* Since v4 you should use defaultRaw for SQL functions. e.g. now()
|
||||
*/
|
||||
defaultRaw(defaultRaw) {
|
||||
return this.assignOptions({ defaultRaw });
|
||||
}
|
||||
/**
|
||||
* Allow controlling `filters` option. This will be overridden with `em.fork` or `FindOptions` if provided.
|
||||
*/
|
||||
filters(filters) {
|
||||
return this.assignOptions({ filters });
|
||||
}
|
||||
/**
|
||||
* Set to map some SQL snippet for the entity.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/defining-entities#formulas Formulas
|
||||
*/
|
||||
formula(formula) {
|
||||
return this.assignOptions({ formula });
|
||||
}
|
||||
/**
|
||||
* For generated columns. This will be appended to the column type after the `generated always` clause.
|
||||
*/
|
||||
generated(generated) {
|
||||
return this.assignOptions({ generated });
|
||||
}
|
||||
/**
|
||||
* Set column as nullable for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}.
|
||||
*/
|
||||
nullable() {
|
||||
return this.assignOptions({ nullable: true });
|
||||
}
|
||||
/**
|
||||
* Set column as unsigned for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
||||
*/
|
||||
unsigned(unsigned = true) {
|
||||
return this.assignOptions({ unsigned });
|
||||
}
|
||||
persist(persist = true) {
|
||||
return this.assignOptions({ persist });
|
||||
}
|
||||
/**
|
||||
* Set false to disable hydration of this property. Useful for persisted getters.
|
||||
*/
|
||||
hydrate(hydrate = true) {
|
||||
return this.assignOptions({ hydrate });
|
||||
}
|
||||
/**
|
||||
* Enable `ScalarReference` wrapper for lazy values. Use this in combination with `lazy: true` to have a type-safe accessor object in place of the value.
|
||||
*/
|
||||
ref() {
|
||||
return this.assignOptions({ ref: true });
|
||||
}
|
||||
/**
|
||||
* Set to true to omit the property when {@link https://mikro-orm.io/docs/serializing Serializing}.
|
||||
*/
|
||||
hidden() {
|
||||
return this.assignOptions({ hidden: true });
|
||||
}
|
||||
/**
|
||||
* Set to true to enable {@link https://mikro-orm.io/docs/transactions#optimistic-locking Optimistic Locking} via version field. (SQL only)
|
||||
*/
|
||||
version() {
|
||||
return this.assignOptions({ version: true });
|
||||
}
|
||||
/**
|
||||
* Set to true to enable {@link https://mikro-orm.io/docs/transactions#optimistic-locking Optimistic Locking} via concurrency fields.
|
||||
*/
|
||||
concurrencyCheck(concurrencyCheck = true) {
|
||||
return this.assignOptions({ concurrencyCheck });
|
||||
}
|
||||
/**
|
||||
* Explicitly specify index on a property.
|
||||
*/
|
||||
index(index = true) {
|
||||
return this.assignOptions({ index });
|
||||
}
|
||||
/**
|
||||
* Set column as unique for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
||||
*/
|
||||
unique(unique = true) {
|
||||
return this.assignOptions({ unique });
|
||||
}
|
||||
/**
|
||||
* Specify column with check constraints. (Postgres driver only)
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/defining-entities#check-constraints
|
||||
*/
|
||||
check(check) {
|
||||
return this.assignOptions({ check });
|
||||
}
|
||||
/**
|
||||
* Set to omit the property from the select clause for lazy loading.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/defining-entities#lazy-scalar-properties
|
||||
*/
|
||||
lazy() {
|
||||
return this.assignOptions({ lazy: true });
|
||||
}
|
||||
/**
|
||||
* Set true to define entity's unique primary key identifier.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/decorators#primarykey
|
||||
*/
|
||||
primary() {
|
||||
return this.assignOptions({ primary: true });
|
||||
}
|
||||
/**
|
||||
* Set true to define the properties as setter. (virtual)
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* @Property({ setter: true })
|
||||
* set address(value: string) {
|
||||
* this._address = value.toLocaleLowerCase();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
setter(setter = true) {
|
||||
return this.assignOptions({ setter });
|
||||
}
|
||||
/**
|
||||
* Set true to define the properties as getter. (virtual)
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* @Property({ getter: true })
|
||||
* get fullName() {
|
||||
* return this.firstName + this.lastName;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
getter(getter = true) {
|
||||
return this.assignOptions({ getter });
|
||||
}
|
||||
/**
|
||||
* When defining a property over a method (not a getter, a regular function), you can use this option to point
|
||||
* to the method name.
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* @Property({ getter: true })
|
||||
* getFullName() {
|
||||
* return this.firstName + this.lastName;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
getterName(getterName) {
|
||||
return this.assignOptions({ getterName });
|
||||
}
|
||||
/**
|
||||
* Set to define serialized primary key for MongoDB. (virtual)
|
||||
* Alias for `@SerializedPrimaryKey()` decorator.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/decorators#serializedprimarykey
|
||||
*/
|
||||
serializedPrimaryKey(serializedPrimaryKey = true) {
|
||||
return this.assignOptions({ serializedPrimaryKey });
|
||||
}
|
||||
/**
|
||||
* Set to use serialize property. Allow to specify a callback that will be used when serializing a property.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/serializing#property-serializers
|
||||
*/
|
||||
serializer(serializer) {
|
||||
return this.assignOptions({ serializer });
|
||||
}
|
||||
/**
|
||||
* Specify name of key for the serialized value.
|
||||
*/
|
||||
serializedName(serializedName) {
|
||||
return this.assignOptions({ serializedName });
|
||||
}
|
||||
/**
|
||||
* Specify serialization groups for `serialize()` calls. If a property does not specify any group, it will be included,
|
||||
* otherwise only properties with a matching group are included.
|
||||
*/
|
||||
groups(...groups) {
|
||||
return this.assignOptions({ groups });
|
||||
}
|
||||
/**
|
||||
* Specify a custom order based on the values. (SQL only)
|
||||
*/
|
||||
customOrder(...customOrder) {
|
||||
return this.assignOptions({ customOrder });
|
||||
}
|
||||
/**
|
||||
* Specify comment of column for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
|
||||
*/
|
||||
comment(comment) {
|
||||
return this.assignOptions({ comment });
|
||||
}
|
||||
/** mysql only */
|
||||
extra(extra) {
|
||||
return this.assignOptions({ extra });
|
||||
}
|
||||
/**
|
||||
* Set to avoid a perpetual diff from the {@link https://mikro-orm.io/docs/schema-generator Schema Generator} when columns are generated.
|
||||
*
|
||||
* @see https://mikro-orm.io/docs/defining-entities#sql-generated-columns
|
||||
*/
|
||||
ignoreSchemaChanges(...ignoreSchemaChanges) {
|
||||
return this.assignOptions({ ignoreSchemaChanges });
|
||||
}
|
||||
array() {
|
||||
return this.assignOptions({ array: true });
|
||||
}
|
||||
/** for postgres, by default it uses text column with check constraint */
|
||||
nativeEnumName(nativeEnumName) {
|
||||
return this.assignOptions({ nativeEnumName });
|
||||
}
|
||||
prefix(prefix) {
|
||||
return this.assignOptions({ prefix });
|
||||
}
|
||||
prefixMode(prefixMode) {
|
||||
return this.assignOptions({ prefixMode });
|
||||
}
|
||||
object(object = true) {
|
||||
return this.assignOptions({ object });
|
||||
}
|
||||
/** Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see {@doclink cascading}). */
|
||||
cascade(...cascade) {
|
||||
return this.assignOptions({ cascade });
|
||||
}
|
||||
/** Always load the relationship. Discouraged for use with to-many relations for performance reasons. */
|
||||
eager(eager = true) {
|
||||
return this.assignOptions({ eager });
|
||||
}
|
||||
/** Override the default loading strategy for this property. This option has precedence over the global `loadStrategy`, but can be overridden by `FindOptions.strategy`. */
|
||||
strategy(strategy) {
|
||||
return this.assignOptions({ strategy });
|
||||
}
|
||||
/** Set this side as owning. Owning side is where the foreign key is defined. This option is not required if you use `inversedBy` or `mappedBy` to distinguish owning and inverse side. */
|
||||
owner() {
|
||||
return this.assignOptions({ owner: true });
|
||||
}
|
||||
/** For polymorphic relations. Specifies the property name that stores the entity type discriminator. Defaults to the property name. */
|
||||
discriminator(discriminator) {
|
||||
return this.assignOptions({ discriminator });
|
||||
}
|
||||
/** For polymorphic relations. Custom mapping of discriminator values to entity class names. */
|
||||
discriminatorMap(discriminatorMap) {
|
||||
return this.assignOptions({ discriminatorMap });
|
||||
}
|
||||
/** Point to the inverse side property name. */
|
||||
inversedBy(inversedBy) {
|
||||
return this.assignOptions({ inversedBy });
|
||||
}
|
||||
/** Point to the owning side property name. */
|
||||
mappedBy(mappedBy) {
|
||||
return this.assignOptions({ mappedBy });
|
||||
}
|
||||
/** Condition for {@doclink collections#declarative-partial-loading | Declarative partial loading}. */
|
||||
where(...where) {
|
||||
return this.assignOptions({ where });
|
||||
}
|
||||
/** Set default ordering. */
|
||||
orderBy(...orderBy) {
|
||||
return this.assignOptions({ orderBy });
|
||||
}
|
||||
/** Force stable insertion order of items in the collection (see {@doclink collections | Collections}). */
|
||||
fixedOrder(fixedOrder = true) {
|
||||
return this.assignOptions({ fixedOrder });
|
||||
}
|
||||
/** Override default order column name (`id`) for fixed ordering. */
|
||||
fixedOrderColumn(fixedOrderColumn) {
|
||||
return this.assignOptions({ fixedOrderColumn });
|
||||
}
|
||||
/** Override default name for pivot table (see {@doclink naming-strategy | Naming Strategy}). */
|
||||
pivotTable(pivotTable) {
|
||||
return this.assignOptions({ pivotTable });
|
||||
}
|
||||
/** Set pivot entity for this relation (see {@doclink collections#custom-pivot-table-entity | Custom pivot table entity}). */
|
||||
pivotEntity(pivotEntity) {
|
||||
return this.assignOptions({ pivotEntity });
|
||||
}
|
||||
/** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
|
||||
joinColumn(joinColumn) {
|
||||
return this.assignOptions({ joinColumn });
|
||||
}
|
||||
/** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is suitable for composite keys, where one property is represented by multiple columns. */
|
||||
joinColumns(...joinColumns) {
|
||||
return this.assignOptions({ joinColumns });
|
||||
}
|
||||
/** Override the default database column name on the inverse side (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
|
||||
inverseJoinColumn(inverseJoinColumn) {
|
||||
return this.assignOptions({ inverseJoinColumn });
|
||||
}
|
||||
/** Override the default database column name on the inverse side (see {@doclink naming-strategy | Naming Strategy}). This option is suitable for composite keys, where one property is represented by multiple columns. */
|
||||
inverseJoinColumns(...inverseJoinColumns) {
|
||||
return this.assignOptions({ inverseJoinColumns });
|
||||
}
|
||||
/** Override the default database column name on the target entity (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
|
||||
referenceColumnName(referenceColumnName) {
|
||||
return this.assignOptions({ referenceColumnName });
|
||||
}
|
||||
/** Override the default database column name on the target entity (see {@doclink naming-strategy | Naming Strategy}). This option is suitable for composite keys, where one property is represented by multiple columns. */
|
||||
referencedColumnNames(...referencedColumnNames) {
|
||||
return this.assignOptions({ referencedColumnNames });
|
||||
}
|
||||
/** Specify the property name on the target entity that this FK references instead of the primary key. */
|
||||
targetKey(targetKey) {
|
||||
return this.assignOptions({ targetKey });
|
||||
}
|
||||
/** What to do when the target entity gets deleted. */
|
||||
deleteRule(deleteRule) {
|
||||
return this.assignOptions({ deleteRule });
|
||||
}
|
||||
/** What to do when the reference to the target entity gets updated. */
|
||||
updateRule(updateRule) {
|
||||
return this.assignOptions({ updateRule });
|
||||
}
|
||||
/** Map this relation to the primary key value instead of an entity. */
|
||||
mapToPk() {
|
||||
return this.assignOptions({ mapToPk: true });
|
||||
}
|
||||
/** Set the constraint type. Immediate constraints are checked for each statement, while deferred ones are only checked at the end of the transaction. Only for postgres unique constraints. */
|
||||
deferMode(deferMode) {
|
||||
return this.assignOptions({ deferMode });
|
||||
}
|
||||
/** When a part of a composite column is shared in other properties, use this option to specify what columns are considered as owned by this property. This is useful when your composite property is nullable, but parts of it are not. */
|
||||
ownColumns(...ownColumns) {
|
||||
return this.assignOptions({ ownColumns });
|
||||
}
|
||||
/** Enable/disable foreign key constraint creation on this relation */
|
||||
createForeignKeyConstraint(createForeignKeyConstraint = true) {
|
||||
return this.assignOptions({ createForeignKeyConstraint });
|
||||
}
|
||||
/** Set a custom foreign key constraint name, overriding NamingStrategy.indexName(). */
|
||||
foreignKeyName(foreignKeyName) {
|
||||
return this.assignOptions({ foreignKeyName });
|
||||
}
|
||||
/** Remove the entity when it gets disconnected from the relationship (see {@doclink cascading | Cascading}). */
|
||||
orphanRemoval(orphanRemoval = true) {
|
||||
return this.assignOptions({ orphanRemoval });
|
||||
}
|
||||
accessor(accessor = true) {
|
||||
return this.assignOptions({ accessor });
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export class OneToManyOptionsBuilderOnlyMappedBy extends UniversalPropertyOptionsBuilder {
|
||||
/** Point to the owning side property name. */
|
||||
mappedBy(mappedBy) {
|
||||
return new UniversalPropertyOptionsBuilder({ ...this['~options'], mappedBy });
|
||||
}
|
||||
}
|
||||
function createPropertyBuilders(options) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(options).map(([key, value]) => [key, () => new UniversalPropertyOptionsBuilder({ type: value })]),
|
||||
);
|
||||
}
|
||||
const propertyBuilders = {
|
||||
...createPropertyBuilders(types),
|
||||
bigint: mode => new UniversalPropertyOptionsBuilder({ type: new types.bigint(mode) }),
|
||||
array: (toJsValue = i => i, toDbValue = i => i) =>
|
||||
new UniversalPropertyOptionsBuilder({ type: new types.array(toJsValue, toDbValue) }),
|
||||
decimal: mode => new UniversalPropertyOptionsBuilder({ type: new types.decimal(mode) }),
|
||||
json: () => new UniversalPropertyOptionsBuilder({ type: types.json }),
|
||||
formula: formula => new UniversalPropertyOptionsBuilder({ formula }),
|
||||
datetime: length => new UniversalPropertyOptionsBuilder({ type: types.datetime, length }),
|
||||
time: length => new UniversalPropertyOptionsBuilder({ type: types.time, length }),
|
||||
type: type => new UniversalPropertyOptionsBuilder({ type }),
|
||||
enum: items =>
|
||||
new UniversalPropertyOptionsBuilder({
|
||||
enum: true,
|
||||
items,
|
||||
}),
|
||||
embedded: target =>
|
||||
new UniversalPropertyOptionsBuilder({
|
||||
entity: () => target,
|
||||
kind: 'embedded',
|
||||
}),
|
||||
manyToMany: target =>
|
||||
new UniversalPropertyOptionsBuilder({
|
||||
entity: () => target,
|
||||
kind: 'm:n',
|
||||
}),
|
||||
manyToOne: target =>
|
||||
new UniversalPropertyOptionsBuilder({
|
||||
entity: () => target,
|
||||
kind: 'm:1',
|
||||
}),
|
||||
oneToMany: target =>
|
||||
new OneToManyOptionsBuilderOnlyMappedBy({
|
||||
entity: () => target,
|
||||
kind: '1:m',
|
||||
}),
|
||||
oneToOne: target =>
|
||||
new UniversalPropertyOptionsBuilder({
|
||||
entity: () => target,
|
||||
kind: '1:1',
|
||||
}),
|
||||
};
|
||||
function getBuilderOptions(builder) {
|
||||
return '~options' in builder ? builder['~options'] : builder;
|
||||
}
|
||||
export function defineEntity(meta) {
|
||||
const { properties: propertiesOrGetter, ...options } = meta;
|
||||
const propertyOptions =
|
||||
typeof propertiesOrGetter === 'function' ? propertiesOrGetter(propertyBuilders) : propertiesOrGetter;
|
||||
const properties = {};
|
||||
const values = new Map();
|
||||
for (const [key, builder] of Object.entries(propertyOptions)) {
|
||||
if (typeof builder === 'function') {
|
||||
Object.defineProperty(properties, key, {
|
||||
get: () => {
|
||||
let value = values.get(key);
|
||||
if (value === undefined) {
|
||||
value = getBuilderOptions(builder());
|
||||
values.set(key, value);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
set: value => {
|
||||
values.set(key, value);
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
} else {
|
||||
Object.defineProperty(properties, key, {
|
||||
value: getBuilderOptions(builder),
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return new EntitySchema({ properties, ...options });
|
||||
}
|
||||
defineEntity.properties = propertyBuilders;
|
||||
/** Shorthand alias for `defineEntity.properties` - the property builders for use in `defineEntity()`. */
|
||||
export { propertyBuilders as p };
|
||||
15
node_modules/@mikro-orm/core/entity/index.d.ts
generated
vendored
Normal file
15
node_modules/@mikro-orm/core/entity/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export * from './EntityRepository.js';
|
||||
export * from './EntityIdentifier.js';
|
||||
export * from './PolymorphicRef.js';
|
||||
export * from './EntityAssigner.js';
|
||||
export * from './EntityHelper.js';
|
||||
export * from './EntityFactory.js';
|
||||
export * from './Collection.js';
|
||||
export * from './EntityLoader.js';
|
||||
export * from './Reference.js';
|
||||
export * from './BaseEntity.js';
|
||||
export * from './WrappedEntity.js';
|
||||
export * from './validators.js';
|
||||
export * from './wrap.js';
|
||||
export * from './defineEntity.js';
|
||||
export * from './utils.js';
|
||||
15
node_modules/@mikro-orm/core/entity/index.js
generated
vendored
Normal file
15
node_modules/@mikro-orm/core/entity/index.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export * from './EntityRepository.js';
|
||||
export * from './EntityIdentifier.js';
|
||||
export * from './PolymorphicRef.js';
|
||||
export * from './EntityAssigner.js';
|
||||
export * from './EntityHelper.js';
|
||||
export * from './EntityFactory.js';
|
||||
export * from './Collection.js';
|
||||
export * from './EntityLoader.js';
|
||||
export * from './Reference.js';
|
||||
export * from './BaseEntity.js';
|
||||
export * from './WrappedEntity.js';
|
||||
export * from './validators.js';
|
||||
export * from './wrap.js';
|
||||
export * from './defineEntity.js';
|
||||
export * from './utils.js';
|
||||
27
node_modules/@mikro-orm/core/entity/utils.d.ts
generated
vendored
Normal file
27
node_modules/@mikro-orm/core/entity/utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { EntityMetadata, PopulateHintOptions, PopulateOptions } from '../typings.js';
|
||||
import { LoadStrategy, ReferenceKind } from '../enums.js';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export declare function expandDotPaths<Entity>(
|
||||
meta: EntityMetadata<Entity>,
|
||||
populate?: readonly (string | PopulateOptions<Entity>)[],
|
||||
normalized?: boolean,
|
||||
): PopulateOptions<Entity>[];
|
||||
/**
|
||||
* Returns the loading strategy based on the provided hint.
|
||||
* If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
|
||||
* @internal
|
||||
*/
|
||||
export declare function getLoadingStrategy(
|
||||
strategy: LoadStrategy | `${LoadStrategy}`,
|
||||
kind: ReferenceKind,
|
||||
): LoadStrategy.SELECT_IN | LoadStrategy.JOINED;
|
||||
/**
|
||||
* Applies per-relation overrides from `populateHints` to the normalized populate tree.
|
||||
* @internal
|
||||
*/
|
||||
export declare function applyPopulateHints<Entity>(
|
||||
populate: PopulateOptions<Entity>[],
|
||||
hints: Record<string, PopulateHintOptions>,
|
||||
): void;
|
||||
102
node_modules/@mikro-orm/core/entity/utils.js
generated
vendored
Normal file
102
node_modules/@mikro-orm/core/entity/utils.js
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
import { LoadStrategy, PopulatePath, ReferenceKind } from '../enums.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
/**
|
||||
* Expands `books.perex` like populate to use `children` array instead of the dot syntax
|
||||
*/
|
||||
function expandNestedPopulate(parentProp, parts, strategy, all) {
|
||||
const meta = parentProp.targetMeta;
|
||||
const field = parts.shift();
|
||||
const prop = meta.properties[field];
|
||||
const ret = { field, strategy, all };
|
||||
if (parts.length > 0) {
|
||||
ret.children = [expandNestedPopulate(prop, parts, strategy)];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function expandDotPaths(meta, populate, normalized = false) {
|
||||
const ret = normalized
|
||||
? populate
|
||||
: Utils.asArray(populate).map(field => {
|
||||
if (typeof field === 'string') {
|
||||
return { field };
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return typeof field === 'boolean' || field.field === PopulatePath.ALL
|
||||
? { all: !!field, field: meta.primaryKeys[0] }
|
||||
: field;
|
||||
});
|
||||
for (const p of ret) {
|
||||
if (!p.field.includes('.')) {
|
||||
continue;
|
||||
}
|
||||
const [f, ...parts] = p.field.split('.');
|
||||
p.field = f;
|
||||
p.children ??= [];
|
||||
const prop = meta.properties[p.field];
|
||||
if (parts[0] === PopulatePath.ALL) {
|
||||
prop.targetMeta.props
|
||||
.filter(prop => prop.lazy || prop.kind !== ReferenceKind.SCALAR)
|
||||
.forEach(prop => p.children.push({ field: prop.name, strategy: p.strategy }));
|
||||
} else if (prop.kind === ReferenceKind.EMBEDDED) {
|
||||
const embeddedProp = Object.values(prop.embeddedProps).find(c => c.embedded[1] === parts[0]);
|
||||
ret.push({
|
||||
...p,
|
||||
field: embeddedProp.name,
|
||||
children: parts.length > 1 ? [expandNestedPopulate(embeddedProp, parts.slice(1), p.strategy, p.all)] : [],
|
||||
});
|
||||
p.children.push(expandNestedPopulate(prop, parts, p.strategy, p.all));
|
||||
} else {
|
||||
p.children.push(expandNestedPopulate(prop, parts, p.strategy, p.all));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Returns the loading strategy based on the provided hint.
|
||||
* If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
|
||||
* @internal
|
||||
*/
|
||||
export function getLoadingStrategy(strategy, kind) {
|
||||
if (strategy === LoadStrategy.BALANCED) {
|
||||
return [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(kind)
|
||||
? LoadStrategy.JOINED
|
||||
: LoadStrategy.SELECT_IN;
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
function findPopulateEntry(populate, parts) {
|
||||
let current = populate;
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const entry = current.find(p => p.field.split(':')[0] === parts[i]);
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
if (i === parts.length - 1) {
|
||||
return entry;
|
||||
}
|
||||
current = entry.children ?? [];
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Applies per-relation overrides from `populateHints` to the normalized populate tree.
|
||||
* @internal
|
||||
*/
|
||||
export function applyPopulateHints(populate, hints) {
|
||||
for (const [path, hint] of Object.entries(hints)) {
|
||||
const entry = findPopulateEntry(populate, path.split('.'));
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
if (hint.strategy != null) {
|
||||
entry.strategy = hint.strategy;
|
||||
}
|
||||
if (hint.joinType != null) {
|
||||
entry.joinType = hint.joinType;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
node_modules/@mikro-orm/core/entity/validators.d.ts
generated
vendored
Normal file
11
node_modules/@mikro-orm/core/entity/validators.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { EntityData, EntityMetadata, EntityProperty, FilterQuery } from '../typings.js';
|
||||
/** @internal */
|
||||
export declare function validateProperty<T extends object>(prop: EntityProperty, givenValue: any, entity: T): void;
|
||||
/** @internal */
|
||||
export declare function validateEntity<T extends object>(entity: T, meta: EntityMetadata<T>): void;
|
||||
/** @internal */
|
||||
export declare function validateParams(params: any, type?: string, field?: string): void;
|
||||
/** @internal */
|
||||
export declare function validatePrimaryKey<T>(entity: EntityData<T>, meta: EntityMetadata<T>): void;
|
||||
/** @internal */
|
||||
export declare function validateEmptyWhere<T>(where: FilterQuery<T>): void;
|
||||
66
node_modules/@mikro-orm/core/entity/validators.js
generated
vendored
Normal file
66
node_modules/@mikro-orm/core/entity/validators.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { ValidationError } from '../errors.js';
|
||||
import { isRaw, Raw } from '../utils/RawQueryFragment.js';
|
||||
import { SCALAR_TYPES } from '../enums.js';
|
||||
/** @internal */
|
||||
export function validateProperty(prop, givenValue, entity) {
|
||||
if (givenValue == null || isRaw(givenValue)) {
|
||||
return;
|
||||
}
|
||||
const expectedType = prop.runtimeType;
|
||||
const propName = prop.embedded ? prop.name.replace(/~/g, '.') : prop.name;
|
||||
const givenType = Utils.getObjectType(givenValue);
|
||||
if (prop.enum && prop.items) {
|
||||
/* v8 ignore next */
|
||||
if (!prop.items.some(it => it === givenValue)) {
|
||||
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
||||
}
|
||||
} else {
|
||||
if (givenType !== expectedType && SCALAR_TYPES.has(expectedType)) {
|
||||
throw ValidationError.fromWrongPropertyType(entity, propName, expectedType, givenType, givenValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getValue(o, prop) {
|
||||
if (prop.embedded && prop.embedded[0] in o) {
|
||||
return o[prop.embedded[0]]?.[prop.embedded[1]];
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (prop.ref) {
|
||||
return o[prop.name]?.unwrap();
|
||||
}
|
||||
return o[prop.name];
|
||||
}
|
||||
/** @internal */
|
||||
export function validateEntity(entity, meta) {
|
||||
for (const prop of meta.validateProps) {
|
||||
validateProperty(prop, getValue(entity, prop), entity);
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export function validateParams(params, type = 'search condition', field) {
|
||||
if (Utils.isPrimaryKey(params) || Utils.isEntity(params)) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(params)) {
|
||||
return params.forEach(item => validateParams(item, type, field));
|
||||
}
|
||||
if (Utils.isPlainObject(params)) {
|
||||
Object.keys(params).forEach(k => validateParams(params[k], type, k));
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export function validatePrimaryKey(entity, meta) {
|
||||
const pkExists =
|
||||
meta.primaryKeys.every(pk => entity[pk] != null) ||
|
||||
(meta.serializedPrimaryKey && entity[meta.serializedPrimaryKey] != null);
|
||||
if (!entity || !pkExists) {
|
||||
throw ValidationError.fromMergeWithoutPK(meta);
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export function validateEmptyWhere(where) {
|
||||
if (Utils.isEmpty(where) && !Raw.hasObjectFragments(where)) {
|
||||
throw new Error(`You cannot call 'EntityManager.findOne()' with empty 'where' parameter`);
|
||||
}
|
||||
}
|
||||
15
node_modules/@mikro-orm/core/entity/wrap.d.ts
generated
vendored
Normal file
15
node_modules/@mikro-orm/core/entity/wrap.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { IWrappedEntity, IWrappedEntityInternal } from '../typings.js';
|
||||
/**
|
||||
* returns WrappedEntity instance associated with this entity. This includes all the internal properties like `__meta` or `__em`.
|
||||
*/
|
||||
export declare function wrap<T extends object>(entity: T, preferHelper: true): IWrappedEntityInternal<T>;
|
||||
/**
|
||||
* wraps entity type with WrappedEntity internal properties and helpers like init/isInitialized/populated/toJSON
|
||||
*/
|
||||
export declare function wrap<T extends object>(entity: T, preferHelper?: false): IWrappedEntity<T>;
|
||||
/**
|
||||
* wraps entity type with WrappedEntity internal properties and helpers like init/isInitialized/populated/toJSON
|
||||
* use `preferHelper = true` to have access to the internal `__` properties like `__meta` or `__em`
|
||||
* @internal
|
||||
*/
|
||||
export declare function helper<T extends object>(entity: T): IWrappedEntityInternal<T>;
|
||||
21
node_modules/@mikro-orm/core/entity/wrap.js
generated
vendored
Normal file
21
node_modules/@mikro-orm/core/entity/wrap.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* wraps entity type with WrappedEntity internal properties and helpers like init/isInitialized/populated/toJSON
|
||||
* use `preferHelper = true` to have access to the internal `__` properties like `__meta` or `__em`
|
||||
*/
|
||||
export function wrap(entity, preferHelper = false) {
|
||||
if (!entity) {
|
||||
return entity;
|
||||
}
|
||||
if (entity.__baseEntity && !preferHelper) {
|
||||
return entity;
|
||||
}
|
||||
return entity.__helper ?? entity;
|
||||
}
|
||||
/**
|
||||
* wraps entity type with WrappedEntity internal properties and helpers like init/isInitialized/populated/toJSON
|
||||
* use `preferHelper = true` to have access to the internal `__` properties like `__meta` or `__em`
|
||||
* @internal
|
||||
*/
|
||||
export function helper(entity) {
|
||||
return entity.__helper;
|
||||
}
|
||||
326
node_modules/@mikro-orm/core/enums.d.ts
generated
vendored
Normal file
326
node_modules/@mikro-orm/core/enums.d.ts
generated
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
import type { EntityKey, ExpandProperty } from './typings.js';
|
||||
import type { Transaction } from './connections/Connection.js';
|
||||
import type { LogContext } from './logging/Logger.js';
|
||||
/** Controls when the `EntityManager` flushes pending changes to the database. */
|
||||
export declare enum FlushMode {
|
||||
/** The `EntityManager` delays the flush until the current Transaction is committed. */
|
||||
COMMIT = 'commit',
|
||||
/** This is the default mode, and it flushes the `EntityManager` only if necessary. */
|
||||
AUTO = 'auto',
|
||||
/** Flushes the `EntityManager` before every query. */
|
||||
ALWAYS = 'always',
|
||||
}
|
||||
/** Controls how populate hints are resolved when using `FindOptions.populateWhere`. */
|
||||
export declare enum PopulateHint {
|
||||
/** Infer population hints from the `where` condition. */
|
||||
INFER = 'infer',
|
||||
/** Apply population hints to all relations. */
|
||||
ALL = 'all',
|
||||
}
|
||||
/** Special tokens used as populate path values in `FindOptions.populate`. */
|
||||
export declare enum PopulatePath {
|
||||
/** Infer which relations to populate based on fields accessed in the `where` or `orderBy` clause. */
|
||||
INFER = '$infer',
|
||||
/** Populate all relations. */
|
||||
ALL = '*',
|
||||
}
|
||||
/** Logical grouping operators for combining query conditions. */
|
||||
export declare enum GroupOperator {
|
||||
/** Logical AND — all conditions must match. */
|
||||
$and = 'and',
|
||||
/** Logical OR — at least one condition must match. */
|
||||
$or = 'or',
|
||||
}
|
||||
/** Comparison and filtering operators used in query conditions. */
|
||||
export declare enum QueryOperator {
|
||||
/** Equal. */
|
||||
$eq = '=',
|
||||
/** Included in the given list. */
|
||||
$in = 'in',
|
||||
/** Not included in the given list. */
|
||||
$nin = 'not in',
|
||||
/** Greater than. */
|
||||
$gt = '>',
|
||||
/** Greater than or equal to. */
|
||||
$gte = '>=',
|
||||
/** Less than. */
|
||||
$lt = '<',
|
||||
/** Less than or equal to. */
|
||||
$lte = '<=',
|
||||
/** Not equal. */
|
||||
$ne = '!=',
|
||||
/** Negation wrapper. */
|
||||
$not = 'not',
|
||||
/** SQL LIKE pattern matching. */
|
||||
$like = 'like',
|
||||
/** Regular expression matching. */
|
||||
$re = 'regexp',
|
||||
/** Full-text search. */
|
||||
$fulltext = 'fulltext',
|
||||
/** Checks that the value is not null (i.e., exists). */
|
||||
$exists = 'not null',
|
||||
/** Case-insensitive LIKE (PostgreSQL only). */
|
||||
$ilike = 'ilike', // postgres only
|
||||
/** Array overlap operator (PostgreSQL only). */
|
||||
$overlap = '&&', // postgres only
|
||||
/** Array/JSON contains operator (PostgreSQL only). */
|
||||
$contains = '@>', // postgres only
|
||||
/** Array/JSON contained-by operator (PostgreSQL only). */
|
||||
$contained = '<@', // postgres only
|
||||
/** No element in the collection matches (SQL only). */
|
||||
$none = 'none', // collection operators, sql only
|
||||
/** At least one element in the collection matches (SQL only). */
|
||||
$some = 'some', // collection operators, sql only
|
||||
/** Every element in the collection matches (SQL only). */
|
||||
$every = 'every', // collection operators, sql only
|
||||
/** Matches collections by their size (SQL only). */
|
||||
$size = 'size', // collection operators, sql only
|
||||
/** JSON object has the given key (PostgreSQL only). */
|
||||
$hasKey = '?', // postgres only, json
|
||||
/** JSON object has all of the given keys (PostgreSQL only). */
|
||||
$hasKeys = '?&', // postgres only, json
|
||||
/** JSON object has at least one of the given keys (PostgreSQL only). */
|
||||
$hasSomeKeys = '?|', // postgres only, json
|
||||
/** Matches an element inside a JSON array (SQL only). */
|
||||
$elemMatch = 'elemMatch',
|
||||
}
|
||||
export declare const ARRAY_OPERATORS: string[];
|
||||
export declare const JSON_KEY_OPERATORS: string[];
|
||||
/** Sort direction for query results. Both upper- and lower-case variants are accepted. */
|
||||
export declare enum QueryOrder {
|
||||
/** Ascending order. */
|
||||
ASC = 'ASC',
|
||||
/** Ascending order with nulls sorted last. */
|
||||
ASC_NULLS_LAST = 'ASC NULLS LAST',
|
||||
/** Ascending order with nulls sorted first. */
|
||||
ASC_NULLS_FIRST = 'ASC NULLS FIRST',
|
||||
/** Descending order. */
|
||||
DESC = 'DESC',
|
||||
/** Descending order with nulls sorted last. */
|
||||
DESC_NULLS_LAST = 'DESC NULLS LAST',
|
||||
/** Descending order with nulls sorted first. */
|
||||
DESC_NULLS_FIRST = 'DESC NULLS FIRST',
|
||||
/** Ascending order (lower-case variant). */
|
||||
asc = 'asc',
|
||||
/** Ascending order with nulls sorted last (lower-case variant). */
|
||||
asc_nulls_last = 'asc nulls last',
|
||||
/** Ascending order with nulls sorted first (lower-case variant). */
|
||||
asc_nulls_first = 'asc nulls first',
|
||||
/** Descending order (lower-case variant). */
|
||||
desc = 'desc',
|
||||
/** Descending order with nulls sorted last (lower-case variant). */
|
||||
desc_nulls_last = 'desc nulls last',
|
||||
/** Descending order with nulls sorted first (lower-case variant). */
|
||||
desc_nulls_first = 'desc nulls first',
|
||||
}
|
||||
/** Numeric sort direction, compatible with MongoDB-style ordering. */
|
||||
export declare enum QueryOrderNumeric {
|
||||
/** Ascending order. */
|
||||
ASC = 1,
|
||||
/** Descending order. */
|
||||
DESC = -1,
|
||||
}
|
||||
export type QueryOrderKeysFlat = QueryOrder | QueryOrderNumeric | `${QueryOrder}`;
|
||||
export type QueryOrderKeys<T> = QueryOrderKeysFlat | QueryOrderMap<T>;
|
||||
export type QueryOrderMap<T> = {
|
||||
[K in EntityKey<T>]?: QueryOrderKeys<ExpandProperty<T[K]>>;
|
||||
};
|
||||
export interface FlatQueryOrderMap {
|
||||
[x: string]: QueryOrderKeysFlat;
|
||||
}
|
||||
/** Flags that modify query builder behavior. */
|
||||
export declare enum QueryFlag {
|
||||
/** Add a DISTINCT clause to the SELECT statement. */
|
||||
DISTINCT = 'DISTINCT',
|
||||
/** Enable result pagination via a sub-query for the primary keys. */
|
||||
PAGINATE = 'PAGINATE',
|
||||
/** Disable the automatic pagination sub-query. */
|
||||
DISABLE_PAGINATE = 'DISABLE_PAGINATE',
|
||||
/** Wrap UPDATE statements in a sub-query. */
|
||||
UPDATE_SUB_QUERY = 'UPDATE_SUB_QUERY',
|
||||
/** Wrap DELETE statements in a sub-query. */
|
||||
DELETE_SUB_QUERY = 'DELETE_SUB_QUERY',
|
||||
/** Convert values through custom type mappings when reading results. */
|
||||
CONVERT_CUSTOM_TYPES = 'CONVERT_CUSTOM_TYPES',
|
||||
/** Include lazy formula properties in the SELECT clause. */
|
||||
INCLUDE_LAZY_FORMULAS = 'INCLUDE_LAZY_FORMULAS',
|
||||
/** Automatically join the owning side of one-to-one relations. */
|
||||
AUTO_JOIN_ONE_TO_ONE_OWNER = 'AUTO_JOIN_ONE_TO_ONE_OWNER',
|
||||
/** Infer the populate hint from the query fields. */
|
||||
INFER_POPULATE = 'INFER_POPULATE',
|
||||
/** Prevent nested conditions from being promoted to INNER JOINs. */
|
||||
DISABLE_NESTED_INNER_JOIN = 'DISABLE_NESTED_INNER_JOIN',
|
||||
/** Enable IDENTITY_INSERT for explicit PK values (MSSQL only). */
|
||||
IDENTITY_INSERT = 'IDENTITY_INSERT', // mssql only
|
||||
/** Use an OUTPUT...INTO temp table for returning rows (MSSQL only). */
|
||||
OUTPUT_TABLE = 'OUTPUT_TABLE',
|
||||
}
|
||||
export declare const SCALAR_TYPES: Set<string>;
|
||||
/** Describes the kind of relationship a property represents. */
|
||||
export declare enum ReferenceKind {
|
||||
/** A plain scalar property (not a relation). */
|
||||
SCALAR = 'scalar',
|
||||
/** A one-to-one relation. */
|
||||
ONE_TO_ONE = '1:1',
|
||||
/** A one-to-many relation (inverse side of a many-to-one). */
|
||||
ONE_TO_MANY = '1:m',
|
||||
/** A many-to-one relation (owning side). */
|
||||
MANY_TO_ONE = 'm:1',
|
||||
/** A many-to-many relation. */
|
||||
MANY_TO_MANY = 'm:n',
|
||||
/** An embedded entity (inline object stored within the parent). */
|
||||
EMBEDDED = 'embedded',
|
||||
}
|
||||
/** Cascade operations that propagate from a parent entity to its relations. */
|
||||
export declare enum Cascade {
|
||||
/** Cascade persist — new related entities are automatically persisted. */
|
||||
PERSIST = 'persist',
|
||||
/** Cascade merge — detached related entities are merged into the identity map. */
|
||||
MERGE = 'merge',
|
||||
/** Cascade remove — removing the parent also removes related entities. */
|
||||
REMOVE = 'remove',
|
||||
/** Enable all cascade operations (persist, merge, remove). */
|
||||
ALL = 'all',
|
||||
/** @internal */
|
||||
SCHEDULE_ORPHAN_REMOVAL = 'schedule_orphan_removal',
|
||||
/** @internal */
|
||||
CANCEL_ORPHAN_REMOVAL = 'cancel_orphan_removal',
|
||||
}
|
||||
/** Strategy used to load related entities when populating. */
|
||||
export declare enum LoadStrategy {
|
||||
/** Load relations with a separate SELECT ... WHERE pk IN (...) query. */
|
||||
SELECT_IN = 'select-in',
|
||||
/** Load relations via SQL JOINs in a single query. */
|
||||
JOINED = 'joined',
|
||||
/** Use joined strategy for to-one relations and select-in for to-many. */
|
||||
BALANCED = 'balanced',
|
||||
}
|
||||
/** Controls which relation types use the dataloader for batched loading. */
|
||||
export declare enum DataloaderType {
|
||||
/** Dataloader is disabled. */
|
||||
NONE = 0,
|
||||
/** Use the dataloader for Reference (to-one) relations only. */
|
||||
REFERENCE = 1,
|
||||
/** Use the dataloader for Collection (to-many) relations only. */
|
||||
COLLECTION = 2,
|
||||
/** Use the dataloader for both Reference and Collection relations. */
|
||||
ALL = 3,
|
||||
}
|
||||
/** Locking strategy for concurrency control. */
|
||||
export declare enum LockMode {
|
||||
/** No locking. */
|
||||
NONE = 0,
|
||||
/** Optimistic locking via a version column. */
|
||||
OPTIMISTIC = 1,
|
||||
/** Pessimistic shared lock (FOR SHARE). */
|
||||
PESSIMISTIC_READ = 2,
|
||||
/** Pessimistic exclusive lock (FOR UPDATE). */
|
||||
PESSIMISTIC_WRITE = 3,
|
||||
/** Pessimistic exclusive lock that skips already-locked rows (FOR UPDATE SKIP LOCKED). */
|
||||
PESSIMISTIC_PARTIAL_WRITE = 4,
|
||||
/** Pessimistic exclusive lock that fails immediately if the row is locked (FOR UPDATE NOWAIT). */
|
||||
PESSIMISTIC_WRITE_OR_FAIL = 5,
|
||||
/** Pessimistic shared lock that skips already-locked rows (FOR SHARE SKIP LOCKED). */
|
||||
PESSIMISTIC_PARTIAL_READ = 6,
|
||||
/** Pessimistic shared lock that fails immediately if the row is locked (FOR SHARE NOWAIT). */
|
||||
PESSIMISTIC_READ_OR_FAIL = 7,
|
||||
}
|
||||
/** Transaction isolation levels as defined by the SQL standard (plus vendor extensions). */
|
||||
export declare enum IsolationLevel {
|
||||
/** Allows dirty reads, non-repeatable reads, and phantom reads. */
|
||||
READ_UNCOMMITTED = 'read uncommitted',
|
||||
/** Prevents dirty reads; non-repeatable and phantom reads are still possible. */
|
||||
READ_COMMITTED = 'read committed',
|
||||
/** Snapshot isolation — each transaction sees a consistent snapshot of the database (MSSQL). */
|
||||
SNAPSHOT = 'snapshot',
|
||||
/** Prevents dirty and non-repeatable reads; phantom reads are still possible. */
|
||||
REPEATABLE_READ = 'repeatable read',
|
||||
/** Full isolation — transactions are executed as if they were run sequentially. */
|
||||
SERIALIZABLE = 'serializable',
|
||||
}
|
||||
/** Lifecycle and transaction events emitted by the ORM. */
|
||||
export declare enum EventType {
|
||||
/** Fired when an entity instance is created (via constructor or `em.create`). */
|
||||
onInit = 'onInit',
|
||||
/** Fired after an entity is loaded from the database. */
|
||||
onLoad = 'onLoad',
|
||||
/** Fired before a new entity is inserted into the database. */
|
||||
beforeCreate = 'beforeCreate',
|
||||
/** Fired after a new entity has been inserted into the database. */
|
||||
afterCreate = 'afterCreate',
|
||||
/** Fired before an existing entity is updated in the database. */
|
||||
beforeUpdate = 'beforeUpdate',
|
||||
/** Fired after an existing entity has been updated in the database. */
|
||||
afterUpdate = 'afterUpdate',
|
||||
/** Fired before an upsert operation. */
|
||||
beforeUpsert = 'beforeUpsert',
|
||||
/** Fired after an upsert operation. */
|
||||
afterUpsert = 'afterUpsert',
|
||||
/** Fired before an entity is deleted from the database. */
|
||||
beforeDelete = 'beforeDelete',
|
||||
/** Fired after an entity has been deleted from the database. */
|
||||
afterDelete = 'afterDelete',
|
||||
/** Fired at the very beginning of `em.flush()`, before change detection. */
|
||||
beforeFlush = 'beforeFlush',
|
||||
/** Fired during `em.flush()` after change detection but before database writes. */
|
||||
onFlush = 'onFlush',
|
||||
/** Fired after `em.flush()` has completed all database writes. */
|
||||
afterFlush = 'afterFlush',
|
||||
/** Fired before a new database transaction is started. */
|
||||
beforeTransactionStart = 'beforeTransactionStart',
|
||||
/** Fired after a new database transaction has been started. */
|
||||
afterTransactionStart = 'afterTransactionStart',
|
||||
/** Fired before a database transaction is committed. */
|
||||
beforeTransactionCommit = 'beforeTransactionCommit',
|
||||
/** Fired after a database transaction has been committed. */
|
||||
afterTransactionCommit = 'afterTransactionCommit',
|
||||
/** Fired before a database transaction is rolled back. */
|
||||
beforeTransactionRollback = 'beforeTransactionRollback',
|
||||
/** Fired after a database transaction has been rolled back. */
|
||||
afterTransactionRollback = 'afterTransactionRollback',
|
||||
}
|
||||
export declare const EventTypeMap: Record<EventType, number>;
|
||||
export type TransactionEventType =
|
||||
| EventType.beforeTransactionStart
|
||||
| EventType.afterTransactionStart
|
||||
| EventType.beforeTransactionCommit
|
||||
| EventType.afterTransactionCommit
|
||||
| EventType.beforeTransactionRollback
|
||||
| EventType.afterTransactionRollback;
|
||||
/** Controls how a transactional operation interacts with an existing transaction. */
|
||||
export declare enum TransactionPropagation {
|
||||
/** Join the current transaction or create a new one if none exists. */
|
||||
REQUIRED = 'required',
|
||||
/** Always create a new transaction, suspending the current one if it exists. */
|
||||
REQUIRES_NEW = 'requires_new',
|
||||
/** Create a nested savepoint within the current transaction, or a new transaction if none exists. */
|
||||
NESTED = 'nested',
|
||||
/** Execute non-transactionally, suspending the current transaction if one exists. */
|
||||
NOT_SUPPORTED = 'not_supported',
|
||||
/** Join the current transaction if one exists, otherwise execute non-transactionally. */
|
||||
SUPPORTS = 'supports',
|
||||
/** Join the current transaction; throw if no transaction is active. */
|
||||
MANDATORY = 'mandatory',
|
||||
/** Execute non-transactionally; throw if a transaction is active. */
|
||||
NEVER = 'never',
|
||||
}
|
||||
export interface TransactionOptions {
|
||||
ctx?: Transaction;
|
||||
propagation?: TransactionPropagation | `${TransactionPropagation}`;
|
||||
isolationLevel?: IsolationLevel | `${IsolationLevel}`;
|
||||
readOnly?: boolean;
|
||||
clear?: boolean;
|
||||
flushMode?: FlushMode | `${FlushMode}`;
|
||||
ignoreNestedTransactions?: boolean;
|
||||
loggerContext?: LogContext;
|
||||
}
|
||||
export declare abstract class PlainObject {}
|
||||
/** Constraint deferral mode for database constraints (e.g., foreign keys, unique). */
|
||||
export declare enum DeferMode {
|
||||
/** The constraint is checked immediately by default, but can be deferred within a transaction. */
|
||||
INITIALLY_IMMEDIATE = 'immediate',
|
||||
/** The constraint is deferred until the transaction is committed. */
|
||||
INITIALLY_DEFERRED = 'deferred',
|
||||
}
|
||||
/** With `absolute` the prefix is set at the root of the entity (regardless of the nesting level) */
|
||||
export type EmbeddedPrefixMode = 'absolute' | 'relative';
|
||||
325
node_modules/@mikro-orm/core/enums.js
generated
vendored
Normal file
325
node_modules/@mikro-orm/core/enums.js
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/** Controls when the `EntityManager` flushes pending changes to the database. */
|
||||
export var FlushMode;
|
||||
(function (FlushMode) {
|
||||
/** The `EntityManager` delays the flush until the current Transaction is committed. */
|
||||
FlushMode['COMMIT'] = 'commit';
|
||||
/** This is the default mode, and it flushes the `EntityManager` only if necessary. */
|
||||
FlushMode['AUTO'] = 'auto';
|
||||
/** Flushes the `EntityManager` before every query. */
|
||||
FlushMode['ALWAYS'] = 'always';
|
||||
})(FlushMode || (FlushMode = {}));
|
||||
/** Controls how populate hints are resolved when using `FindOptions.populateWhere`. */
|
||||
export var PopulateHint;
|
||||
(function (PopulateHint) {
|
||||
/** Infer population hints from the `where` condition. */
|
||||
PopulateHint['INFER'] = 'infer';
|
||||
/** Apply population hints to all relations. */
|
||||
PopulateHint['ALL'] = 'all';
|
||||
})(PopulateHint || (PopulateHint = {}));
|
||||
/** Special tokens used as populate path values in `FindOptions.populate`. */
|
||||
export var PopulatePath;
|
||||
(function (PopulatePath) {
|
||||
/** Infer which relations to populate based on fields accessed in the `where` or `orderBy` clause. */
|
||||
PopulatePath['INFER'] = '$infer';
|
||||
/** Populate all relations. */
|
||||
PopulatePath['ALL'] = '*';
|
||||
})(PopulatePath || (PopulatePath = {}));
|
||||
/** Logical grouping operators for combining query conditions. */
|
||||
export var GroupOperator;
|
||||
(function (GroupOperator) {
|
||||
/** Logical AND — all conditions must match. */
|
||||
GroupOperator['$and'] = 'and';
|
||||
/** Logical OR — at least one condition must match. */
|
||||
GroupOperator['$or'] = 'or';
|
||||
})(GroupOperator || (GroupOperator = {}));
|
||||
/** Comparison and filtering operators used in query conditions. */
|
||||
export var QueryOperator;
|
||||
(function (QueryOperator) {
|
||||
/** Equal. */
|
||||
QueryOperator['$eq'] = '=';
|
||||
/** Included in the given list. */
|
||||
QueryOperator['$in'] = 'in';
|
||||
/** Not included in the given list. */
|
||||
QueryOperator['$nin'] = 'not in';
|
||||
/** Greater than. */
|
||||
QueryOperator['$gt'] = '>';
|
||||
/** Greater than or equal to. */
|
||||
QueryOperator['$gte'] = '>=';
|
||||
/** Less than. */
|
||||
QueryOperator['$lt'] = '<';
|
||||
/** Less than or equal to. */
|
||||
QueryOperator['$lte'] = '<=';
|
||||
/** Not equal. */
|
||||
QueryOperator['$ne'] = '!=';
|
||||
/** Negation wrapper. */
|
||||
QueryOperator['$not'] = 'not';
|
||||
/** SQL LIKE pattern matching. */
|
||||
QueryOperator['$like'] = 'like';
|
||||
/** Regular expression matching. */
|
||||
QueryOperator['$re'] = 'regexp';
|
||||
/** Full-text search. */
|
||||
QueryOperator['$fulltext'] = 'fulltext';
|
||||
/** Checks that the value is not null (i.e., exists). */
|
||||
QueryOperator['$exists'] = 'not null';
|
||||
/** Case-insensitive LIKE (PostgreSQL only). */
|
||||
QueryOperator['$ilike'] = 'ilike';
|
||||
/** Array overlap operator (PostgreSQL only). */
|
||||
QueryOperator['$overlap'] = '&&';
|
||||
/** Array/JSON contains operator (PostgreSQL only). */
|
||||
QueryOperator['$contains'] = '@>';
|
||||
/** Array/JSON contained-by operator (PostgreSQL only). */
|
||||
QueryOperator['$contained'] = '<@';
|
||||
/** No element in the collection matches (SQL only). */
|
||||
QueryOperator['$none'] = 'none';
|
||||
/** At least one element in the collection matches (SQL only). */
|
||||
QueryOperator['$some'] = 'some';
|
||||
/** Every element in the collection matches (SQL only). */
|
||||
QueryOperator['$every'] = 'every';
|
||||
/** Matches collections by their size (SQL only). */
|
||||
QueryOperator['$size'] = 'size';
|
||||
/** JSON object has the given key (PostgreSQL only). */
|
||||
QueryOperator['$hasKey'] = '?';
|
||||
/** JSON object has all of the given keys (PostgreSQL only). */
|
||||
QueryOperator['$hasKeys'] = '?&';
|
||||
/** JSON object has at least one of the given keys (PostgreSQL only). */
|
||||
QueryOperator['$hasSomeKeys'] = '?|';
|
||||
/** Matches an element inside a JSON array (SQL only). */
|
||||
QueryOperator['$elemMatch'] = 'elemMatch';
|
||||
})(QueryOperator || (QueryOperator = {}));
|
||||
export const ARRAY_OPERATORS = ['$eq', '$gt', '$gte', '$lt', '$lte', '$ne', '$overlap', '$contains', '$contained'];
|
||||
export const JSON_KEY_OPERATORS = ['$hasKey', '$hasKeys', '$hasSomeKeys'];
|
||||
/** Sort direction for query results. Both upper- and lower-case variants are accepted. */
|
||||
export var QueryOrder;
|
||||
(function (QueryOrder) {
|
||||
/** Ascending order. */
|
||||
QueryOrder['ASC'] = 'ASC';
|
||||
/** Ascending order with nulls sorted last. */
|
||||
QueryOrder['ASC_NULLS_LAST'] = 'ASC NULLS LAST';
|
||||
/** Ascending order with nulls sorted first. */
|
||||
QueryOrder['ASC_NULLS_FIRST'] = 'ASC NULLS FIRST';
|
||||
/** Descending order. */
|
||||
QueryOrder['DESC'] = 'DESC';
|
||||
/** Descending order with nulls sorted last. */
|
||||
QueryOrder['DESC_NULLS_LAST'] = 'DESC NULLS LAST';
|
||||
/** Descending order with nulls sorted first. */
|
||||
QueryOrder['DESC_NULLS_FIRST'] = 'DESC NULLS FIRST';
|
||||
/** Ascending order (lower-case variant). */
|
||||
QueryOrder['asc'] = 'asc';
|
||||
/** Ascending order with nulls sorted last (lower-case variant). */
|
||||
QueryOrder['asc_nulls_last'] = 'asc nulls last';
|
||||
/** Ascending order with nulls sorted first (lower-case variant). */
|
||||
QueryOrder['asc_nulls_first'] = 'asc nulls first';
|
||||
/** Descending order (lower-case variant). */
|
||||
QueryOrder['desc'] = 'desc';
|
||||
/** Descending order with nulls sorted last (lower-case variant). */
|
||||
QueryOrder['desc_nulls_last'] = 'desc nulls last';
|
||||
/** Descending order with nulls sorted first (lower-case variant). */
|
||||
QueryOrder['desc_nulls_first'] = 'desc nulls first';
|
||||
})(QueryOrder || (QueryOrder = {}));
|
||||
/** Numeric sort direction, compatible with MongoDB-style ordering. */
|
||||
export var QueryOrderNumeric;
|
||||
(function (QueryOrderNumeric) {
|
||||
/** Ascending order. */
|
||||
QueryOrderNumeric[(QueryOrderNumeric['ASC'] = 1)] = 'ASC';
|
||||
/** Descending order. */
|
||||
QueryOrderNumeric[(QueryOrderNumeric['DESC'] = -1)] = 'DESC';
|
||||
})(QueryOrderNumeric || (QueryOrderNumeric = {}));
|
||||
/** Flags that modify query builder behavior. */
|
||||
export var QueryFlag;
|
||||
(function (QueryFlag) {
|
||||
/** Add a DISTINCT clause to the SELECT statement. */
|
||||
QueryFlag['DISTINCT'] = 'DISTINCT';
|
||||
/** Enable result pagination via a sub-query for the primary keys. */
|
||||
QueryFlag['PAGINATE'] = 'PAGINATE';
|
||||
/** Disable the automatic pagination sub-query. */
|
||||
QueryFlag['DISABLE_PAGINATE'] = 'DISABLE_PAGINATE';
|
||||
/** Wrap UPDATE statements in a sub-query. */
|
||||
QueryFlag['UPDATE_SUB_QUERY'] = 'UPDATE_SUB_QUERY';
|
||||
/** Wrap DELETE statements in a sub-query. */
|
||||
QueryFlag['DELETE_SUB_QUERY'] = 'DELETE_SUB_QUERY';
|
||||
/** Convert values through custom type mappings when reading results. */
|
||||
QueryFlag['CONVERT_CUSTOM_TYPES'] = 'CONVERT_CUSTOM_TYPES';
|
||||
/** Include lazy formula properties in the SELECT clause. */
|
||||
QueryFlag['INCLUDE_LAZY_FORMULAS'] = 'INCLUDE_LAZY_FORMULAS';
|
||||
/** Automatically join the owning side of one-to-one relations. */
|
||||
QueryFlag['AUTO_JOIN_ONE_TO_ONE_OWNER'] = 'AUTO_JOIN_ONE_TO_ONE_OWNER';
|
||||
/** Infer the populate hint from the query fields. */
|
||||
QueryFlag['INFER_POPULATE'] = 'INFER_POPULATE';
|
||||
/** Prevent nested conditions from being promoted to INNER JOINs. */
|
||||
QueryFlag['DISABLE_NESTED_INNER_JOIN'] = 'DISABLE_NESTED_INNER_JOIN';
|
||||
/** Enable IDENTITY_INSERT for explicit PK values (MSSQL only). */
|
||||
QueryFlag['IDENTITY_INSERT'] = 'IDENTITY_INSERT';
|
||||
/** Use an OUTPUT...INTO temp table for returning rows (MSSQL only). */
|
||||
QueryFlag['OUTPUT_TABLE'] = 'OUTPUT_TABLE';
|
||||
})(QueryFlag || (QueryFlag = {}));
|
||||
export const SCALAR_TYPES = new Set([
|
||||
'string',
|
||||
'number',
|
||||
'boolean',
|
||||
'bigint',
|
||||
'Uint8Array',
|
||||
'Date',
|
||||
'Buffer',
|
||||
'RegExp',
|
||||
]);
|
||||
/** Describes the kind of relationship a property represents. */
|
||||
export var ReferenceKind;
|
||||
(function (ReferenceKind) {
|
||||
/** A plain scalar property (not a relation). */
|
||||
ReferenceKind['SCALAR'] = 'scalar';
|
||||
/** A one-to-one relation. */
|
||||
ReferenceKind['ONE_TO_ONE'] = '1:1';
|
||||
/** A one-to-many relation (inverse side of a many-to-one). */
|
||||
ReferenceKind['ONE_TO_MANY'] = '1:m';
|
||||
/** A many-to-one relation (owning side). */
|
||||
ReferenceKind['MANY_TO_ONE'] = 'm:1';
|
||||
/** A many-to-many relation. */
|
||||
ReferenceKind['MANY_TO_MANY'] = 'm:n';
|
||||
/** An embedded entity (inline object stored within the parent). */
|
||||
ReferenceKind['EMBEDDED'] = 'embedded';
|
||||
})(ReferenceKind || (ReferenceKind = {}));
|
||||
/** Cascade operations that propagate from a parent entity to its relations. */
|
||||
export var Cascade;
|
||||
(function (Cascade) {
|
||||
/** Cascade persist — new related entities are automatically persisted. */
|
||||
Cascade['PERSIST'] = 'persist';
|
||||
/** Cascade merge — detached related entities are merged into the identity map. */
|
||||
Cascade['MERGE'] = 'merge';
|
||||
/** Cascade remove — removing the parent also removes related entities. */
|
||||
Cascade['REMOVE'] = 'remove';
|
||||
/** Enable all cascade operations (persist, merge, remove). */
|
||||
Cascade['ALL'] = 'all';
|
||||
/** @internal */
|
||||
Cascade['SCHEDULE_ORPHAN_REMOVAL'] = 'schedule_orphan_removal';
|
||||
/** @internal */
|
||||
Cascade['CANCEL_ORPHAN_REMOVAL'] = 'cancel_orphan_removal';
|
||||
})(Cascade || (Cascade = {}));
|
||||
/** Strategy used to load related entities when populating. */
|
||||
export var LoadStrategy;
|
||||
(function (LoadStrategy) {
|
||||
/** Load relations with a separate SELECT ... WHERE pk IN (...) query. */
|
||||
LoadStrategy['SELECT_IN'] = 'select-in';
|
||||
/** Load relations via SQL JOINs in a single query. */
|
||||
LoadStrategy['JOINED'] = 'joined';
|
||||
/** Use joined strategy for to-one relations and select-in for to-many. */
|
||||
LoadStrategy['BALANCED'] = 'balanced';
|
||||
})(LoadStrategy || (LoadStrategy = {}));
|
||||
/** Controls which relation types use the dataloader for batched loading. */
|
||||
export var DataloaderType;
|
||||
(function (DataloaderType) {
|
||||
/** Dataloader is disabled. */
|
||||
DataloaderType[(DataloaderType['NONE'] = 0)] = 'NONE';
|
||||
/** Use the dataloader for Reference (to-one) relations only. */
|
||||
DataloaderType[(DataloaderType['REFERENCE'] = 1)] = 'REFERENCE';
|
||||
/** Use the dataloader for Collection (to-many) relations only. */
|
||||
DataloaderType[(DataloaderType['COLLECTION'] = 2)] = 'COLLECTION';
|
||||
/** Use the dataloader for both Reference and Collection relations. */
|
||||
DataloaderType[(DataloaderType['ALL'] = 3)] = 'ALL';
|
||||
})(DataloaderType || (DataloaderType = {}));
|
||||
/** Locking strategy for concurrency control. */
|
||||
export var LockMode;
|
||||
(function (LockMode) {
|
||||
/** No locking. */
|
||||
LockMode[(LockMode['NONE'] = 0)] = 'NONE';
|
||||
/** Optimistic locking via a version column. */
|
||||
LockMode[(LockMode['OPTIMISTIC'] = 1)] = 'OPTIMISTIC';
|
||||
/** Pessimistic shared lock (FOR SHARE). */
|
||||
LockMode[(LockMode['PESSIMISTIC_READ'] = 2)] = 'PESSIMISTIC_READ';
|
||||
/** Pessimistic exclusive lock (FOR UPDATE). */
|
||||
LockMode[(LockMode['PESSIMISTIC_WRITE'] = 3)] = 'PESSIMISTIC_WRITE';
|
||||
/** Pessimistic exclusive lock that skips already-locked rows (FOR UPDATE SKIP LOCKED). */
|
||||
LockMode[(LockMode['PESSIMISTIC_PARTIAL_WRITE'] = 4)] = 'PESSIMISTIC_PARTIAL_WRITE';
|
||||
/** Pessimistic exclusive lock that fails immediately if the row is locked (FOR UPDATE NOWAIT). */
|
||||
LockMode[(LockMode['PESSIMISTIC_WRITE_OR_FAIL'] = 5)] = 'PESSIMISTIC_WRITE_OR_FAIL';
|
||||
/** Pessimistic shared lock that skips already-locked rows (FOR SHARE SKIP LOCKED). */
|
||||
LockMode[(LockMode['PESSIMISTIC_PARTIAL_READ'] = 6)] = 'PESSIMISTIC_PARTIAL_READ';
|
||||
/** Pessimistic shared lock that fails immediately if the row is locked (FOR SHARE NOWAIT). */
|
||||
LockMode[(LockMode['PESSIMISTIC_READ_OR_FAIL'] = 7)] = 'PESSIMISTIC_READ_OR_FAIL';
|
||||
})(LockMode || (LockMode = {}));
|
||||
/** Transaction isolation levels as defined by the SQL standard (plus vendor extensions). */
|
||||
export var IsolationLevel;
|
||||
(function (IsolationLevel) {
|
||||
/** Allows dirty reads, non-repeatable reads, and phantom reads. */
|
||||
IsolationLevel['READ_UNCOMMITTED'] = 'read uncommitted';
|
||||
/** Prevents dirty reads; non-repeatable and phantom reads are still possible. */
|
||||
IsolationLevel['READ_COMMITTED'] = 'read committed';
|
||||
/** Snapshot isolation — each transaction sees a consistent snapshot of the database (MSSQL). */
|
||||
IsolationLevel['SNAPSHOT'] = 'snapshot';
|
||||
/** Prevents dirty and non-repeatable reads; phantom reads are still possible. */
|
||||
IsolationLevel['REPEATABLE_READ'] = 'repeatable read';
|
||||
/** Full isolation — transactions are executed as if they were run sequentially. */
|
||||
IsolationLevel['SERIALIZABLE'] = 'serializable';
|
||||
})(IsolationLevel || (IsolationLevel = {}));
|
||||
/** Lifecycle and transaction events emitted by the ORM. */
|
||||
export var EventType;
|
||||
(function (EventType) {
|
||||
/** Fired when an entity instance is created (via constructor or `em.create`). */
|
||||
EventType['onInit'] = 'onInit';
|
||||
/** Fired after an entity is loaded from the database. */
|
||||
EventType['onLoad'] = 'onLoad';
|
||||
/** Fired before a new entity is inserted into the database. */
|
||||
EventType['beforeCreate'] = 'beforeCreate';
|
||||
/** Fired after a new entity has been inserted into the database. */
|
||||
EventType['afterCreate'] = 'afterCreate';
|
||||
/** Fired before an existing entity is updated in the database. */
|
||||
EventType['beforeUpdate'] = 'beforeUpdate';
|
||||
/** Fired after an existing entity has been updated in the database. */
|
||||
EventType['afterUpdate'] = 'afterUpdate';
|
||||
/** Fired before an upsert operation. */
|
||||
EventType['beforeUpsert'] = 'beforeUpsert';
|
||||
/** Fired after an upsert operation. */
|
||||
EventType['afterUpsert'] = 'afterUpsert';
|
||||
/** Fired before an entity is deleted from the database. */
|
||||
EventType['beforeDelete'] = 'beforeDelete';
|
||||
/** Fired after an entity has been deleted from the database. */
|
||||
EventType['afterDelete'] = 'afterDelete';
|
||||
/** Fired at the very beginning of `em.flush()`, before change detection. */
|
||||
EventType['beforeFlush'] = 'beforeFlush';
|
||||
/** Fired during `em.flush()` after change detection but before database writes. */
|
||||
EventType['onFlush'] = 'onFlush';
|
||||
/** Fired after `em.flush()` has completed all database writes. */
|
||||
EventType['afterFlush'] = 'afterFlush';
|
||||
/** Fired before a new database transaction is started. */
|
||||
EventType['beforeTransactionStart'] = 'beforeTransactionStart';
|
||||
/** Fired after a new database transaction has been started. */
|
||||
EventType['afterTransactionStart'] = 'afterTransactionStart';
|
||||
/** Fired before a database transaction is committed. */
|
||||
EventType['beforeTransactionCommit'] = 'beforeTransactionCommit';
|
||||
/** Fired after a database transaction has been committed. */
|
||||
EventType['afterTransactionCommit'] = 'afterTransactionCommit';
|
||||
/** Fired before a database transaction is rolled back. */
|
||||
EventType['beforeTransactionRollback'] = 'beforeTransactionRollback';
|
||||
/** Fired after a database transaction has been rolled back. */
|
||||
EventType['afterTransactionRollback'] = 'afterTransactionRollback';
|
||||
})(EventType || (EventType = {}));
|
||||
export const EventTypeMap = Object.keys(EventType).reduce((a, b, i) => {
|
||||
a[b] = i;
|
||||
return a;
|
||||
}, {});
|
||||
/** Controls how a transactional operation interacts with an existing transaction. */
|
||||
export var TransactionPropagation;
|
||||
(function (TransactionPropagation) {
|
||||
/** Join the current transaction or create a new one if none exists. */
|
||||
TransactionPropagation['REQUIRED'] = 'required';
|
||||
/** Always create a new transaction, suspending the current one if it exists. */
|
||||
TransactionPropagation['REQUIRES_NEW'] = 'requires_new';
|
||||
/** Create a nested savepoint within the current transaction, or a new transaction if none exists. */
|
||||
TransactionPropagation['NESTED'] = 'nested';
|
||||
/** Execute non-transactionally, suspending the current transaction if one exists. */
|
||||
TransactionPropagation['NOT_SUPPORTED'] = 'not_supported';
|
||||
/** Join the current transaction if one exists, otherwise execute non-transactionally. */
|
||||
TransactionPropagation['SUPPORTS'] = 'supports';
|
||||
/** Join the current transaction; throw if no transaction is active. */
|
||||
TransactionPropagation['MANDATORY'] = 'mandatory';
|
||||
/** Execute non-transactionally; throw if a transaction is active. */
|
||||
TransactionPropagation['NEVER'] = 'never';
|
||||
})(TransactionPropagation || (TransactionPropagation = {}));
|
||||
export class PlainObject {}
|
||||
/** Constraint deferral mode for database constraints (e.g., foreign keys, unique). */
|
||||
export var DeferMode;
|
||||
(function (DeferMode) {
|
||||
/** The constraint is checked immediately by default, but can be deferred within a transaction. */
|
||||
DeferMode['INITIALLY_IMMEDIATE'] = 'immediate';
|
||||
/** The constraint is deferred until the transaction is committed. */
|
||||
DeferMode['INITIALLY_DEFERRED'] = 'deferred';
|
||||
})(DeferMode || (DeferMode = {}));
|
||||
132
node_modules/@mikro-orm/core/errors.d.ts
generated
vendored
Normal file
132
node_modules/@mikro-orm/core/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
import type {
|
||||
AnyEntity,
|
||||
Constructor,
|
||||
Dictionary,
|
||||
EntityMetadata,
|
||||
EntityName,
|
||||
EntityProperty,
|
||||
IPrimaryKey,
|
||||
} from './typings.js';
|
||||
/** Base error class for ORM validation errors such as invalid entity state or incorrect usage. */
|
||||
export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Error {
|
||||
readonly entity?: T | undefined;
|
||||
constructor(message: string, entity?: T | undefined);
|
||||
/**
|
||||
* Gets instance of entity that caused this error.
|
||||
*/
|
||||
getEntity(): AnyEntity | undefined;
|
||||
static fromWrongPropertyType(
|
||||
entity: AnyEntity,
|
||||
property: string,
|
||||
expectedType: string,
|
||||
givenType: string,
|
||||
givenValue: string,
|
||||
): ValidationError;
|
||||
static fromWrongRepositoryType(entityName: string, repoType: string, method: string): ValidationError;
|
||||
static fromMergeWithoutPK(meta: EntityMetadata): ValidationError;
|
||||
static transactionRequired(): ValidationError;
|
||||
static entityNotManaged(entity: AnyEntity): ValidationError;
|
||||
static notEntity(owner: AnyEntity, prop: EntityProperty, data: any): ValidationError;
|
||||
static notDiscoveredEntity(data: any, meta?: EntityMetadata, action?: string): ValidationError;
|
||||
static invalidPropertyName(entityName: EntityName, invalid: string): ValidationError;
|
||||
static invalidCollectionValues(entityName: string, propName: string, invalid: unknown): ValidationError;
|
||||
static invalidEnumArrayItems(entityName: string, invalid: unknown): ValidationError;
|
||||
static invalidType(type: Constructor<any>, value: any, mode: string): ValidationError;
|
||||
static propertyRequired(entity: AnyEntity, property: EntityProperty): ValidationError;
|
||||
static cannotModifyInverseCollection(owner: AnyEntity, property: EntityProperty): ValidationError;
|
||||
static cannotModifyReadonlyCollection(owner: AnyEntity, property: EntityProperty): ValidationError;
|
||||
static cannotRemoveFromCollectionWithoutOrphanRemoval(owner: AnyEntity, property: EntityProperty): ValidationError;
|
||||
static invalidCompositeIdentifier(meta: EntityMetadata): ValidationError;
|
||||
static cannotCommit(): ValidationError;
|
||||
static cannotUseGlobalContext(): ValidationError;
|
||||
static cannotUseOperatorsInsideEmbeddables(
|
||||
entityName: EntityName,
|
||||
propName: string,
|
||||
payload: unknown,
|
||||
): ValidationError;
|
||||
static cannotUseGroupOperatorsInsideScalars(
|
||||
entityName: EntityName,
|
||||
propName: string,
|
||||
payload: unknown,
|
||||
): ValidationError;
|
||||
static invalidEmbeddableQuery(entityName: EntityName, propName: string, embeddableType: string): ValidationError;
|
||||
static invalidQueryCondition(cond: unknown): ValidationError;
|
||||
}
|
||||
/** Error thrown when cursor-based pagination encounters missing or invalid cursor values. */
|
||||
export declare class CursorError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
||||
static entityNotPopulated(entity: AnyEntity, prop: string): ValidationError;
|
||||
static missingValue(entityName: string, prop: string): ValidationError;
|
||||
}
|
||||
/** Error thrown when an optimistic lock conflict is detected during entity persistence. */
|
||||
export declare class OptimisticLockError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
||||
static notVersioned(meta: EntityMetadata): OptimisticLockError;
|
||||
static lockFailed(entityOrName: AnyEntity | string): OptimisticLockError;
|
||||
static lockFailedVersionMismatch(
|
||||
entity: AnyEntity,
|
||||
expectedLockVersion: number | Date,
|
||||
actualLockVersion: number | Date,
|
||||
): OptimisticLockError;
|
||||
}
|
||||
/** Error thrown when entity metadata is invalid, incomplete, or inconsistent. */
|
||||
export declare class MetadataError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
||||
static fromMissingPrimaryKey(meta: EntityMetadata): MetadataError;
|
||||
static fromWrongReference(
|
||||
meta: EntityMetadata,
|
||||
prop: EntityProperty,
|
||||
key: 'inversedBy' | 'mappedBy',
|
||||
owner?: EntityProperty,
|
||||
): MetadataError;
|
||||
static fromWrongForeignKey(meta: EntityMetadata, prop: EntityProperty, key: string): MetadataError;
|
||||
static fromWrongTypeDefinition(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
||||
static fromWrongOwnership(meta: EntityMetadata, prop: EntityProperty, key: 'inversedBy' | 'mappedBy'): MetadataError;
|
||||
static fromWrongReferenceKind(meta: EntityMetadata, owner: EntityProperty, prop: EntityProperty): MetadataError;
|
||||
static fromInversideSidePrimary(meta: EntityMetadata, owner: EntityProperty, prop: EntityProperty): MetadataError;
|
||||
static unknownIndexProperty(meta: EntityMetadata, prop: string, type: string): MetadataError;
|
||||
static multipleVersionFields(meta: EntityMetadata, fields: string[]): MetadataError;
|
||||
static invalidVersionFieldType(meta: EntityMetadata): MetadataError;
|
||||
static fromUnknownEntity(entityName: string, source: string): MetadataError;
|
||||
static noEntityDiscovered(): MetadataError;
|
||||
static onlyAbstractEntitiesDiscovered(): MetadataError;
|
||||
static duplicateEntityDiscovered(paths: string[]): MetadataError;
|
||||
static duplicateFieldName(entityName: EntityName, names: [string, string][]): MetadataError;
|
||||
static multipleDecorators(entityName: string, propertyName: string): MetadataError;
|
||||
static missingMetadata(entity: string): MetadataError;
|
||||
static invalidPrimaryKey(meta: EntityMetadata, prop: EntityProperty, requiredName: string): MetadataError;
|
||||
static invalidManyToManyWithPivotEntity(
|
||||
meta1: EntityMetadata,
|
||||
prop1: EntityProperty,
|
||||
meta2: EntityMetadata,
|
||||
prop2: EntityProperty,
|
||||
): MetadataError;
|
||||
static targetIsAbstract(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
||||
static nonPersistentCompositeProp(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
||||
static propertyTargetsEntityType(meta: EntityMetadata, prop: EntityProperty, target: EntityMetadata): MetadataError;
|
||||
static fromMissingOption(meta: EntityMetadata, prop: EntityProperty, option: string): MetadataError;
|
||||
static targetKeyOnManyToMany(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
||||
static targetKeyNotUnique(meta: EntityMetadata, prop: EntityProperty, target?: EntityMetadata): MetadataError;
|
||||
static targetKeyNotFound(meta: EntityMetadata, prop: EntityProperty, target?: EntityMetadata): MetadataError;
|
||||
static incompatiblePolymorphicTargets(
|
||||
meta: EntityMetadata,
|
||||
prop: EntityProperty,
|
||||
target1: EntityMetadata,
|
||||
target2: EntityMetadata,
|
||||
reason: string,
|
||||
): MetadataError;
|
||||
static dangerousPropertyName(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
||||
static viewEntityWithoutExpression(meta: EntityMetadata): MetadataError;
|
||||
static mixedInheritanceStrategies(root: EntityMetadata, child: EntityMetadata): MetadataError;
|
||||
static tptNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
||||
private static fromMessage;
|
||||
}
|
||||
/** Error thrown when an entity lookup fails to find the expected result. */
|
||||
export declare class NotFoundError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
||||
static findOneFailed(name: string, where: Dictionary | IPrimaryKey): NotFoundError;
|
||||
static findExactlyOneFailed(name: string, where: Dictionary | IPrimaryKey): NotFoundError;
|
||||
static failedToLoadProperty(name: string, propName: string, where: unknown): NotFoundError;
|
||||
}
|
||||
/** Error thrown when a transaction propagation requirement is not satisfied. */
|
||||
export declare class TransactionStateError extends ValidationError {
|
||||
static requiredTransactionNotFound(propagation: string): TransactionStateError;
|
||||
static transactionNotAllowed(propagation: string): TransactionStateError;
|
||||
static invalidPropagation(propagation: string): TransactionStateError;
|
||||
}
|
||||
371
node_modules/@mikro-orm/core/errors.js
generated
vendored
Normal file
371
node_modules/@mikro-orm/core/errors.js
generated
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
import { inspect } from './logging/inspect.js';
|
||||
import { Utils } from './utils/Utils.js';
|
||||
/** Base error class for ORM validation errors such as invalid entity state or incorrect usage. */
|
||||
export class ValidationError extends Error {
|
||||
entity;
|
||||
constructor(message, entity) {
|
||||
super(message);
|
||||
this.entity = entity;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
}
|
||||
/**
|
||||
* Gets instance of entity that caused this error.
|
||||
*/
|
||||
getEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
static fromWrongPropertyType(entity, property, expectedType, givenType, givenValue) {
|
||||
const entityName = entity.constructor.name;
|
||||
const msg = `Trying to set ${entityName}.${property} of type '${expectedType}' to ${inspect(givenValue)} of type '${givenType}'`;
|
||||
return new ValidationError(msg);
|
||||
}
|
||||
static fromWrongRepositoryType(entityName, repoType, method) {
|
||||
const msg = `Trying to use EntityRepository.${method}() with '${entityName}' entity while the repository is of type '${repoType}'`;
|
||||
return new ValidationError(msg);
|
||||
}
|
||||
static fromMergeWithoutPK(meta) {
|
||||
return new ValidationError(`You cannot merge entity '${meta.className}' without identifier!`);
|
||||
}
|
||||
static transactionRequired() {
|
||||
return new ValidationError('An open transaction is required for this operation');
|
||||
}
|
||||
static entityNotManaged(entity) {
|
||||
return new ValidationError(
|
||||
`Entity ${entity.constructor.name} is not managed. An entity is managed if its fetched from the database or registered as new through EntityManager.persist()`,
|
||||
);
|
||||
}
|
||||
static notEntity(owner, prop, data) {
|
||||
const type = /\[object (\w+)]/.exec(Object.prototype.toString.call(data))[1].toLowerCase();
|
||||
return new ValidationError(
|
||||
`Entity of type ${prop.type} expected for property ${owner.constructor.name}.${prop.name}, ${inspect(data)} of type ${type} given. If you are using Object.assign(entity, data), use em.assign(entity, data) instead.`,
|
||||
);
|
||||
}
|
||||
static notDiscoveredEntity(data, meta, action = 'persist') {
|
||||
/* v8 ignore next */
|
||||
const type = meta?.className ?? /\[object (\w+)]/.exec(Object.prototype.toString.call(data))[1].toLowerCase();
|
||||
let err = `Trying to ${action} not discovered entity of type ${type}.`;
|
||||
if (meta) {
|
||||
err += ` Entity with this name was discovered, but not the prototype you are passing to the ORM. If using EntitySchema, be sure to point to the implementation via \`class\`.`;
|
||||
}
|
||||
return new ValidationError(err);
|
||||
}
|
||||
static invalidPropertyName(entityName, invalid) {
|
||||
return new ValidationError(`Entity '${Utils.className(entityName)}' does not have property '${invalid}'`);
|
||||
}
|
||||
static invalidCollectionValues(entityName, propName, invalid) {
|
||||
return new ValidationError(
|
||||
`Invalid collection values provided for '${entityName}.${propName}' in ${entityName}.assign(): ${inspect(invalid)}`,
|
||||
);
|
||||
}
|
||||
static invalidEnumArrayItems(entityName, invalid) {
|
||||
return new ValidationError(`Invalid enum array items provided in ${entityName}: ${inspect(invalid)}`);
|
||||
}
|
||||
static invalidType(type, value, mode) {
|
||||
const valueType = /\[object (\w+)]/.exec(Object.prototype.toString.call(value))[1].toLowerCase();
|
||||
if (value instanceof Date) {
|
||||
value = value.toISOString();
|
||||
}
|
||||
return new ValidationError(
|
||||
`Could not convert ${mode} value '${value}' of type '${valueType}' to type ${type.name}`,
|
||||
);
|
||||
}
|
||||
static propertyRequired(entity, property) {
|
||||
const entityName = entity.__meta.className;
|
||||
return new ValidationError(
|
||||
`Value for ${entityName}.${property.name} is required, '${entity[property.name]}' found\nentity: ${inspect(entity)}`,
|
||||
entity,
|
||||
);
|
||||
}
|
||||
static cannotModifyInverseCollection(owner, property) {
|
||||
const inverseCollection = `${owner.constructor.name}.${property.name}`;
|
||||
const ownerCollection = `${property.type}.${property.mappedBy}`;
|
||||
const error =
|
||||
`You cannot modify inverse side of M:N collection ${inverseCollection} when the owning side is not initialized. ` +
|
||||
`Consider working with the owning side instead (${ownerCollection}).`;
|
||||
return new ValidationError(error, owner);
|
||||
}
|
||||
static cannotModifyReadonlyCollection(owner, property) {
|
||||
return new ValidationError(
|
||||
`You cannot modify collection ${owner.constructor.name}.${property.name} as it is marked as readonly.`,
|
||||
owner,
|
||||
);
|
||||
}
|
||||
static cannotRemoveFromCollectionWithoutOrphanRemoval(owner, property) {
|
||||
const options = [
|
||||
' - add `orphanRemoval: true` to the collection options',
|
||||
" - add `deleteRule: 'cascade'` to the owning side options",
|
||||
' - add `nullable: true` to the owning side options',
|
||||
].join('\n');
|
||||
return new ValidationError(
|
||||
`Removing items from collection ${owner.constructor.name}.${property.name} without \`orphanRemoval: true\` would break non-null constraint on the owning side. You have several options: \n${options}`,
|
||||
owner,
|
||||
);
|
||||
}
|
||||
static invalidCompositeIdentifier(meta) {
|
||||
return new ValidationError(`Composite key required for entity ${meta.className}.`);
|
||||
}
|
||||
static cannotCommit() {
|
||||
return new ValidationError('You cannot call em.flush() from inside lifecycle hook handlers');
|
||||
}
|
||||
static cannotUseGlobalContext() {
|
||||
return new ValidationError(
|
||||
"Using global EntityManager instance methods for context specific actions is disallowed. If you need to work with the global instance's identity map, use `allowGlobalContext` configuration option or `fork()` instead.",
|
||||
);
|
||||
}
|
||||
static cannotUseOperatorsInsideEmbeddables(entityName, propName, payload) {
|
||||
return new ValidationError(
|
||||
`Using operators inside embeddables is not allowed, move the operator above. (property: ${Utils.className(entityName)}.${propName}, payload: ${inspect(payload)})`,
|
||||
);
|
||||
}
|
||||
static cannotUseGroupOperatorsInsideScalars(entityName, propName, payload) {
|
||||
return new ValidationError(
|
||||
`Using group operators ($and/$or) inside scalar properties is not allowed, move the operator above. (property: ${Utils.className(entityName)}.${propName}, payload: ${inspect(payload)})`,
|
||||
);
|
||||
}
|
||||
static invalidEmbeddableQuery(entityName, propName, embeddableType) {
|
||||
return new ValidationError(
|
||||
`Invalid query for entity '${Utils.className(entityName)}', property '${propName}' does not exist in embeddable '${embeddableType}'`,
|
||||
);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
static invalidQueryCondition(cond) {
|
||||
return new ValidationError(`Invalid query condition: ${inspect(cond, { depth: 5 })}`);
|
||||
}
|
||||
}
|
||||
/** Error thrown when cursor-based pagination encounters missing or invalid cursor values. */
|
||||
export class CursorError extends ValidationError {
|
||||
static entityNotPopulated(entity, prop) {
|
||||
return new CursorError(`Cannot create cursor, value for '${entity.constructor.name}.${prop}' is missing.`);
|
||||
}
|
||||
static missingValue(entityName, prop) {
|
||||
return new CursorError(`Invalid cursor condition, value for '${entityName}.${prop}' is missing.`);
|
||||
}
|
||||
}
|
||||
/** Error thrown when an optimistic lock conflict is detected during entity persistence. */
|
||||
export class OptimisticLockError extends ValidationError {
|
||||
static notVersioned(meta) {
|
||||
return new OptimisticLockError(`Cannot obtain optimistic lock on unversioned entity ${meta.className}`);
|
||||
}
|
||||
static lockFailed(entityOrName) {
|
||||
const name = typeof entityOrName === 'string' ? entityOrName : entityOrName.constructor.name;
|
||||
const entity = typeof entityOrName === 'string' ? undefined : entityOrName;
|
||||
return new OptimisticLockError(`The optimistic lock on entity ${name} failed`, entity);
|
||||
}
|
||||
static lockFailedVersionMismatch(entity, expectedLockVersion, actualLockVersion) {
|
||||
expectedLockVersion = expectedLockVersion instanceof Date ? expectedLockVersion.getTime() : expectedLockVersion;
|
||||
actualLockVersion = actualLockVersion instanceof Date ? actualLockVersion.getTime() : actualLockVersion;
|
||||
return new OptimisticLockError(
|
||||
`The optimistic lock failed, version ${expectedLockVersion} was expected, but is actually ${actualLockVersion}`,
|
||||
entity,
|
||||
);
|
||||
}
|
||||
}
|
||||
/** Error thrown when entity metadata is invalid, incomplete, or inconsistent. */
|
||||
export class MetadataError extends ValidationError {
|
||||
static fromMissingPrimaryKey(meta) {
|
||||
return new MetadataError(`${meta.className} entity is missing @PrimaryKey()`);
|
||||
}
|
||||
static fromWrongReference(meta, prop, key, owner) {
|
||||
if (owner) {
|
||||
return MetadataError.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`has wrong '${key}' reference type: ${owner.type} instead of ${meta.className}`,
|
||||
);
|
||||
}
|
||||
return MetadataError.fromMessage(meta, prop, `has unknown '${key}' reference: ${prop.type}.${prop[key]}`);
|
||||
}
|
||||
static fromWrongForeignKey(meta, prop, key) {
|
||||
return MetadataError.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`requires explicit '${key}' option, since the 'joinColumns' are not matching the length.`,
|
||||
);
|
||||
}
|
||||
static fromWrongTypeDefinition(meta, prop) {
|
||||
if (!prop.type) {
|
||||
return MetadataError.fromMessage(meta, prop, `is missing type definition`);
|
||||
}
|
||||
return MetadataError.fromMessage(meta, prop, `has unknown type: ${prop.type}`);
|
||||
}
|
||||
static fromWrongOwnership(meta, prop, key) {
|
||||
const type = key === 'inversedBy' ? 'owning' : 'inverse';
|
||||
const other = key === 'inversedBy' ? 'mappedBy' : 'inversedBy';
|
||||
return new MetadataError(
|
||||
`Both ${meta.className}.${prop.name} and ${prop.type}.${prop[key]} are defined as ${type} sides, use '${other}' on one of them`,
|
||||
);
|
||||
}
|
||||
static fromWrongReferenceKind(meta, owner, prop) {
|
||||
return new MetadataError(
|
||||
`${meta.className}.${prop.name} is of type ${prop.kind} which is incompatible with its owning side ${prop.type}.${owner.name} of type ${owner.kind}`,
|
||||
);
|
||||
}
|
||||
static fromInversideSidePrimary(meta, owner, prop) {
|
||||
return new MetadataError(
|
||||
`${meta.className}.${prop.name} cannot be primary key as it is defined as inverse side. Maybe you should swap the use of 'inversedBy' and 'mappedBy'.`,
|
||||
);
|
||||
}
|
||||
static unknownIndexProperty(meta, prop, type) {
|
||||
return new MetadataError(
|
||||
`Entity ${meta.className} has wrong ${type} definition: '${prop}' does not exist. You need to use property name, not column name.`,
|
||||
);
|
||||
}
|
||||
static multipleVersionFields(meta, fields) {
|
||||
return new MetadataError(
|
||||
`Entity ${meta.className} has multiple version properties defined: '${fields.join("', '")}'. Only one version property is allowed per entity.`,
|
||||
);
|
||||
}
|
||||
static invalidVersionFieldType(meta) {
|
||||
const prop = meta.properties[meta.versionProperty];
|
||||
return new MetadataError(
|
||||
`Version property ${meta.className}.${prop.name} has unsupported type '${prop.type}'. Only 'number' and 'Date' are allowed.`,
|
||||
);
|
||||
}
|
||||
static fromUnknownEntity(entityName, source) {
|
||||
return new MetadataError(
|
||||
`Entity '${entityName}' was not discovered, please make sure to provide it in 'entities' array when initializing the ORM (used in ${source})`,
|
||||
);
|
||||
}
|
||||
static noEntityDiscovered() {
|
||||
return new MetadataError('No entities were discovered');
|
||||
}
|
||||
static onlyAbstractEntitiesDiscovered() {
|
||||
return new MetadataError(
|
||||
'Only abstract entities were discovered, maybe you forgot to use @Entity() decorator? This can also happen when you have multiple `@mikro-orm/core` packages installed side by side.',
|
||||
);
|
||||
}
|
||||
static duplicateEntityDiscovered(paths) {
|
||||
return new MetadataError(`Duplicate table names are not allowed: ${paths.join(', ')}`);
|
||||
}
|
||||
static duplicateFieldName(entityName, names) {
|
||||
return new MetadataError(
|
||||
`Duplicate fieldNames are not allowed: ${names.map(n => `${Utils.className(entityName)}.${n[0]} (fieldName: '${n[1]}')`).join(', ')}`,
|
||||
);
|
||||
}
|
||||
static multipleDecorators(entityName, propertyName) {
|
||||
return new MetadataError(`Multiple property decorators used on '${entityName}.${propertyName}' property`);
|
||||
}
|
||||
static missingMetadata(entity) {
|
||||
return new MetadataError(`Metadata for entity ${entity} not found`);
|
||||
}
|
||||
static invalidPrimaryKey(meta, prop, requiredName) {
|
||||
return this.fromMessage(meta, prop, `has wrong field name, '${requiredName}' is required in current driver`);
|
||||
}
|
||||
static invalidManyToManyWithPivotEntity(meta1, prop1, meta2, prop2) {
|
||||
const p1 = `${meta1.className}.${prop1.name}`;
|
||||
const p2 = `${meta2.className}.${prop2.name}`;
|
||||
return new MetadataError(
|
||||
`${p1} and ${p2} use the same 'pivotEntity', but don't form a bidirectional relation. Specify 'inversedBy' or 'mappedBy' to link them.`,
|
||||
);
|
||||
}
|
||||
static targetIsAbstract(meta, prop) {
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`targets abstract entity ${prop.type}. Maybe you forgot to put @Entity() decorator on the ${prop.type} class?`,
|
||||
);
|
||||
}
|
||||
static nonPersistentCompositeProp(meta, prop) {
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`is non-persistent relation which targets composite primary key. This is not supported and will cause issues, 'persist: false' should be added to the properties representing single columns instead.`,
|
||||
);
|
||||
}
|
||||
static propertyTargetsEntityType(meta, prop, target) {
|
||||
/* v8 ignore next */
|
||||
const suggestion = target.embeddable ? 'Embedded' : 'ManyToOne';
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`is defined as scalar @Property(), but its type is a discovered entity ${target.className}. Maybe you want to use @${suggestion}() decorator instead?`,
|
||||
);
|
||||
}
|
||||
static fromMissingOption(meta, prop, option) {
|
||||
return this.fromMessage(meta, prop, `is missing '${option}' option`);
|
||||
}
|
||||
static targetKeyOnManyToMany(meta, prop) {
|
||||
return this.fromMessage(meta, prop, `uses 'targetKey' option which is not supported for ManyToMany relations`);
|
||||
}
|
||||
static targetKeyNotUnique(meta, prop, target) {
|
||||
const targetName = target?.className ?? prop.type;
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`has 'targetKey' set to '${prop.targetKey}', but ${targetName}.${prop.targetKey} is not marked as unique`,
|
||||
);
|
||||
}
|
||||
static targetKeyNotFound(meta, prop, target) {
|
||||
const targetName = target?.className ?? prop.type;
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`has 'targetKey' set to '${prop.targetKey}', but ${targetName}.${prop.targetKey} does not exist`,
|
||||
);
|
||||
}
|
||||
static incompatiblePolymorphicTargets(meta, prop, target1, target2, reason) {
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`has incompatible polymorphic targets ${target1.className} and ${target2.className}: ${reason}`,
|
||||
);
|
||||
}
|
||||
static dangerousPropertyName(meta, prop) {
|
||||
return this.fromMessage(
|
||||
meta,
|
||||
prop,
|
||||
`uses a dangerous property name '${prop.name}' which could lead to prototype pollution. Please use a different property name.`,
|
||||
);
|
||||
}
|
||||
static viewEntityWithoutExpression(meta) {
|
||||
return new MetadataError(
|
||||
`View entity ${meta.className} is missing 'expression'. View entities must have an expression defining the SQL query.`,
|
||||
);
|
||||
}
|
||||
static mixedInheritanceStrategies(root, child) {
|
||||
return new MetadataError(
|
||||
`Entity ${child.className} cannot mix STI (Single Table Inheritance) and TPT (Table-Per-Type) inheritance. Root entity ${root.className} uses STI (discriminatorColumn) but also has inheritance: 'tpt'. Choose one inheritance strategy per hierarchy.`,
|
||||
);
|
||||
}
|
||||
static tptNotSupportedByDriver(meta) {
|
||||
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.`,
|
||||
);
|
||||
}
|
||||
static fromMessage(meta, prop, message) {
|
||||
return new MetadataError(`${meta.className}.${prop.name} ${message}`);
|
||||
}
|
||||
}
|
||||
/** Error thrown when an entity lookup fails to find the expected result. */
|
||||
export class NotFoundError extends ValidationError {
|
||||
static findOneFailed(name, where) {
|
||||
return new NotFoundError(`${name} not found (${inspect(where)})`);
|
||||
}
|
||||
static findExactlyOneFailed(name, where) {
|
||||
return new NotFoundError(
|
||||
`Wrong number of ${name} entities found for query ${inspect(where)}, expected exactly one`,
|
||||
);
|
||||
}
|
||||
static failedToLoadProperty(name, propName, where) {
|
||||
const whereString = typeof where === 'object' ? inspect(where) : where;
|
||||
return new NotFoundError(`${name} (${whereString}) failed to load property '${propName}'`);
|
||||
}
|
||||
}
|
||||
/** Error thrown when a transaction propagation requirement is not satisfied. */
|
||||
export class TransactionStateError extends ValidationError {
|
||||
static requiredTransactionNotFound(propagation) {
|
||||
return new TransactionStateError(
|
||||
`No existing transaction found for transaction marked with propagation "${propagation}"`,
|
||||
);
|
||||
}
|
||||
static transactionNotAllowed(propagation) {
|
||||
return new TransactionStateError(
|
||||
`Existing transaction found for transaction marked with propagation "${propagation}"`,
|
||||
);
|
||||
}
|
||||
static invalidPropagation(propagation) {
|
||||
return new TransactionStateError(`Unsupported transaction propagation type: ${propagation}`);
|
||||
}
|
||||
}
|
||||
32
node_modules/@mikro-orm/core/events/EventManager.d.ts
generated
vendored
Normal file
32
node_modules/@mikro-orm/core/events/EventManager.d.ts
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { EntityMetadata } from '../typings.js';
|
||||
import type { EventArgs, EventSubscriber, FlushEventArgs, TransactionEventArgs } from './EventSubscriber.js';
|
||||
import { EventType, type TransactionEventType } from '../enums.js';
|
||||
/** Manages event subscribers and dispatches entity/flush/transaction lifecycle events. */
|
||||
export declare class EventManager {
|
||||
#private;
|
||||
constructor(subscribers: Iterable<EventSubscriber>);
|
||||
/** Registers an event subscriber and indexes its subscribed entities and event types. */
|
||||
registerSubscriber(subscriber: EventSubscriber): void;
|
||||
/** Returns the set of all registered event subscribers. */
|
||||
getSubscribers(): Set<EventSubscriber>;
|
||||
dispatchEvent<T extends object>(
|
||||
event: TransactionEventType,
|
||||
args: TransactionEventArgs,
|
||||
meta?: EntityMetadata<T>,
|
||||
): unknown;
|
||||
dispatchEvent<T extends object>(
|
||||
event: EventType.onInit,
|
||||
args: Partial<EventArgs<T>>,
|
||||
meta?: EntityMetadata<T>,
|
||||
): unknown;
|
||||
dispatchEvent<T extends object>(
|
||||
event: EventType,
|
||||
args: Partial<EventArgs<T> | FlushEventArgs>,
|
||||
meta?: EntityMetadata<T>,
|
||||
): Promise<unknown>;
|
||||
/** Checks whether there are any listeners (hooks or subscribers) for the given event type and entity. */
|
||||
hasListeners<T>(event: EventType, meta: EntityMetadata<T>): boolean;
|
||||
/** Creates a new EventManager with the same set of subscribers. */
|
||||
clone(): EventManager;
|
||||
private getSubscribedEntities;
|
||||
}
|
||||
91
node_modules/@mikro-orm/core/events/EventManager.js
generated
vendored
Normal file
91
node_modules/@mikro-orm/core/events/EventManager.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { EventType, EventTypeMap } from '../enums.js';
|
||||
/** Manages event subscribers and dispatches entity/flush/transaction lifecycle events. */
|
||||
export class EventManager {
|
||||
#listeners = {};
|
||||
#entities = new Map();
|
||||
#cache = new Map();
|
||||
#subscribers = new Set();
|
||||
constructor(subscribers) {
|
||||
for (const subscriber of subscribers) {
|
||||
this.registerSubscriber(subscriber);
|
||||
}
|
||||
}
|
||||
/** Registers an event subscriber and indexes its subscribed entities and event types. */
|
||||
registerSubscriber(subscriber) {
|
||||
if (this.#subscribers.has(subscriber)) {
|
||||
return;
|
||||
}
|
||||
this.#subscribers.add(subscriber);
|
||||
this.#entities.set(subscriber, this.getSubscribedEntities(subscriber));
|
||||
this.#cache.clear();
|
||||
Utils.keys(EventType)
|
||||
.filter(event => event in subscriber)
|
||||
.forEach(event => {
|
||||
this.#listeners[event] ??= new Set();
|
||||
this.#listeners[event].add(subscriber);
|
||||
});
|
||||
}
|
||||
/** Returns the set of all registered event subscribers. */
|
||||
getSubscribers() {
|
||||
return this.#subscribers;
|
||||
}
|
||||
dispatchEvent(event, args, meta) {
|
||||
const listeners = [];
|
||||
const entity = args.entity;
|
||||
// execute lifecycle hooks first
|
||||
meta ??= entity?.__meta;
|
||||
const hooks = meta?.hooks[event] || [];
|
||||
listeners.push(
|
||||
...hooks.map(hook => {
|
||||
const prototypeHook = meta?.prototype[hook];
|
||||
const handler = typeof hook === 'function' ? hook : (entity[hook] ?? prototypeHook);
|
||||
return handler.bind(entity);
|
||||
}),
|
||||
);
|
||||
for (const listener of this.#listeners[event] ?? new Set()) {
|
||||
const entities = this.#entities.get(listener);
|
||||
if (entities.size === 0 || !entity || entities.has(entity.constructor.name)) {
|
||||
listeners.push(listener[event].bind(listener));
|
||||
}
|
||||
}
|
||||
if (event === EventType.onInit) {
|
||||
for (const listener of listeners) {
|
||||
void listener(args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return Utils.runSerial(listeners, listener => listener(args));
|
||||
}
|
||||
/** Checks whether there are any listeners (hooks or subscribers) for the given event type and entity. */
|
||||
hasListeners(event, meta) {
|
||||
const cacheKey = meta._id + EventTypeMap[event];
|
||||
if (this.#cache.has(cacheKey)) {
|
||||
return this.#cache.get(cacheKey);
|
||||
}
|
||||
const hasHooks = meta.hooks[event]?.length;
|
||||
if (hasHooks) {
|
||||
this.#cache.set(cacheKey, true);
|
||||
return true;
|
||||
}
|
||||
for (const listener of this.#listeners[event] ?? new Set()) {
|
||||
const entities = this.#entities.get(listener);
|
||||
if (entities.size === 0 || entities.has(meta.className)) {
|
||||
this.#cache.set(cacheKey, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this.#cache.set(cacheKey, false);
|
||||
return false;
|
||||
}
|
||||
/** Creates a new EventManager with the same set of subscribers. */
|
||||
clone() {
|
||||
return new EventManager(this.#subscribers);
|
||||
}
|
||||
getSubscribedEntities(listener) {
|
||||
if (!listener.getSubscribedEntities) {
|
||||
return new Set();
|
||||
}
|
||||
return new Set(listener.getSubscribedEntities().map(name => Utils.className(name)));
|
||||
}
|
||||
}
|
||||
46
node_modules/@mikro-orm/core/events/EventSubscriber.d.ts
generated
vendored
Normal file
46
node_modules/@mikro-orm/core/events/EventSubscriber.d.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { EntityName, EntityMetadata } from '../typings.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type { UnitOfWork } from '../unit-of-work/UnitOfWork.js';
|
||||
import type { ChangeSet } from '../unit-of-work/ChangeSet.js';
|
||||
import type { Transaction } from '../connections/Connection.js';
|
||||
/** Arguments passed to entity lifecycle event hooks. */
|
||||
export interface EventArgs<T> {
|
||||
entity: T;
|
||||
em: EntityManager;
|
||||
meta: EntityMetadata<T>;
|
||||
changeSet?: ChangeSet<T & {}>;
|
||||
}
|
||||
/** Arguments passed to flush lifecycle event hooks (beforeFlush, onFlush, afterFlush). */
|
||||
export interface FlushEventArgs extends Omit<EventArgs<any>, 'entity' | 'changeSet' | 'meta'> {
|
||||
uow: UnitOfWork;
|
||||
}
|
||||
/** Arguments passed to transaction lifecycle event hooks (start, commit, rollback). */
|
||||
export interface TransactionEventArgs extends Omit<EventArgs<any>, 'entity' | 'meta' | 'changeSet'> {
|
||||
transaction?: Transaction & {
|
||||
savepointName?: string;
|
||||
};
|
||||
uow?: UnitOfWork;
|
||||
}
|
||||
/** Interface for subscribing to entity and transaction lifecycle events. */
|
||||
export interface EventSubscriber<T = any> {
|
||||
getSubscribedEntities?(): EntityName<T>[];
|
||||
onInit?(args: EventArgs<T>): void;
|
||||
onLoad?(args: EventArgs<T>): void | Promise<void>;
|
||||
beforeCreate?(args: EventArgs<T>): void | Promise<void>;
|
||||
afterCreate?(args: EventArgs<T>): void | Promise<void>;
|
||||
beforeUpdate?(args: EventArgs<T>): void | Promise<void>;
|
||||
afterUpdate?(args: EventArgs<T>): void | Promise<void>;
|
||||
beforeUpsert?(args: EventArgs<T>): void | Promise<void>;
|
||||
afterUpsert?(args: EventArgs<T>): void | Promise<void>;
|
||||
beforeDelete?(args: EventArgs<T>): void | Promise<void>;
|
||||
afterDelete?(args: EventArgs<T>): void | Promise<void>;
|
||||
beforeFlush?(args: FlushEventArgs): void | Promise<void>;
|
||||
onFlush?(args: FlushEventArgs): void | Promise<void>;
|
||||
afterFlush?(args: FlushEventArgs): void | Promise<void>;
|
||||
beforeTransactionStart?(args: TransactionEventArgs): void | Promise<void>;
|
||||
afterTransactionStart?(args: TransactionEventArgs): void | Promise<void>;
|
||||
beforeTransactionCommit?(args: TransactionEventArgs): void | Promise<void>;
|
||||
afterTransactionCommit?(args: TransactionEventArgs): void | Promise<void>;
|
||||
beforeTransactionRollback?(args: TransactionEventArgs): void | Promise<void>;
|
||||
afterTransactionRollback?(args: TransactionEventArgs): void | Promise<void>;
|
||||
}
|
||||
1
node_modules/@mikro-orm/core/events/EventSubscriber.js
generated
vendored
Normal file
1
node_modules/@mikro-orm/core/events/EventSubscriber.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
22
node_modules/@mikro-orm/core/events/TransactionEventBroadcaster.d.ts
generated
vendored
Normal file
22
node_modules/@mikro-orm/core/events/TransactionEventBroadcaster.d.ts
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { Transaction } from '../connections/Connection.js';
|
||||
import type { EntityManager } from '../EntityManager.js';
|
||||
import type { TransactionEventType } from '../enums.js';
|
||||
/** Broadcasts transaction lifecycle events (start, commit, rollback) through the EventManager. */
|
||||
export declare class TransactionEventBroadcaster {
|
||||
private readonly em;
|
||||
readonly context?:
|
||||
| {
|
||||
topLevelTransaction?: boolean;
|
||||
}
|
||||
| undefined;
|
||||
constructor(
|
||||
em: EntityManager,
|
||||
context?:
|
||||
| {
|
||||
topLevelTransaction?: boolean;
|
||||
}
|
||||
| undefined,
|
||||
);
|
||||
/** Dispatches a transaction lifecycle event to the EventManager. */
|
||||
dispatchEvent(event: TransactionEventType, transaction?: Transaction): Promise<void>;
|
||||
}
|
||||
17
node_modules/@mikro-orm/core/events/TransactionEventBroadcaster.js
generated
vendored
Normal file
17
node_modules/@mikro-orm/core/events/TransactionEventBroadcaster.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/** Broadcasts transaction lifecycle events (start, commit, rollback) through the EventManager. */
|
||||
export class TransactionEventBroadcaster {
|
||||
em;
|
||||
context;
|
||||
constructor(em, context) {
|
||||
this.em = em;
|
||||
this.context = context;
|
||||
}
|
||||
/** Dispatches a transaction lifecycle event to the EventManager. */
|
||||
async dispatchEvent(event, transaction) {
|
||||
await this.em.getEventManager().dispatchEvent(event, {
|
||||
em: this.em,
|
||||
uow: this.em.getUnitOfWork(false),
|
||||
transaction,
|
||||
});
|
||||
}
|
||||
}
|
||||
3
node_modules/@mikro-orm/core/events/index.d.ts
generated
vendored
Normal file
3
node_modules/@mikro-orm/core/events/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export type * from './EventSubscriber.js';
|
||||
export * from './EventManager.js';
|
||||
export * from './TransactionEventBroadcaster.js';
|
||||
2
node_modules/@mikro-orm/core/events/index.js
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/events/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './EventManager.js';
|
||||
export * from './TransactionEventBroadcaster.js';
|
||||
87
node_modules/@mikro-orm/core/exceptions.d.ts
generated
vendored
Normal file
87
node_modules/@mikro-orm/core/exceptions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Base class for all errors detected in the driver.
|
||||
*/
|
||||
export declare class DriverException extends Error {
|
||||
code?: string;
|
||||
errno?: number;
|
||||
sqlState?: string;
|
||||
sqlMessage?: string;
|
||||
errmsg?: string;
|
||||
constructor(previous: Error);
|
||||
}
|
||||
/**
|
||||
* Base class for all connection related errors detected in the driver.
|
||||
*/
|
||||
export declare class ConnectionException extends DriverException {}
|
||||
/**
|
||||
* Base class for all server related errors detected in the driver.
|
||||
*/
|
||||
export declare class ServerException extends DriverException {}
|
||||
/**
|
||||
* Base class for all constraint violation related errors detected in the driver.
|
||||
*/
|
||||
export declare class ConstraintViolationException extends ServerException {}
|
||||
/**
|
||||
* Base class for all already existing database object related errors detected in the driver.
|
||||
*
|
||||
* A database object is considered any asset that can be created in a database
|
||||
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
|
||||
* functions, stored procedures etc.
|
||||
*/
|
||||
export declare class DatabaseObjectExistsException extends ServerException {}
|
||||
/**
|
||||
* Base class for all unknown database object related errors detected in the driver.
|
||||
*
|
||||
* A database object is considered any asset that can be created in a database
|
||||
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
|
||||
* functions, stored procedures etc.
|
||||
*/
|
||||
export declare class DatabaseObjectNotFoundException extends ServerException {}
|
||||
/**
|
||||
* Exception for a deadlock error of a transaction detected in the driver.
|
||||
*/
|
||||
export declare class DeadlockException extends ServerException {}
|
||||
/**
|
||||
* Exception for a foreign key constraint violation detected in the driver.
|
||||
*/
|
||||
export declare class ForeignKeyConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for a check constraint violation detected in the driver.
|
||||
*/
|
||||
export declare class CheckConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for an invalid specified field name in a statement detected in the driver.
|
||||
*/
|
||||
export declare class InvalidFieldNameException extends ServerException {}
|
||||
/**
|
||||
* Exception for a lock wait timeout error of a transaction detected in the driver.
|
||||
*/
|
||||
export declare class LockWaitTimeoutException extends ServerException {}
|
||||
/**
|
||||
* Exception for a non-unique/ambiguous specified field name in a statement detected in the driver.
|
||||
*/
|
||||
export declare class NonUniqueFieldNameException extends ServerException {}
|
||||
/**
|
||||
* Exception for a NOT NULL constraint violation detected in the driver.
|
||||
*/
|
||||
export declare class NotNullConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for a write operation attempt on a read-only database element detected in the driver.
|
||||
*/
|
||||
export declare class ReadOnlyException extends ServerException {}
|
||||
/**
|
||||
* Exception for a syntax error in a statement detected in the driver.
|
||||
*/
|
||||
export declare class SyntaxErrorException extends ServerException {}
|
||||
/**
|
||||
* Exception for an already existing table referenced in a statement detected in the driver.
|
||||
*/
|
||||
export declare class TableExistsException extends DatabaseObjectExistsException {}
|
||||
/**
|
||||
* Exception for an unknown table referenced in a statement detected in the driver.
|
||||
*/
|
||||
export declare class TableNotFoundException extends DatabaseObjectNotFoundException {}
|
||||
/**
|
||||
* Exception for a unique constraint violation detected in the driver.
|
||||
*/
|
||||
export declare class UniqueConstraintViolationException extends ConstraintViolationException {}
|
||||
100
node_modules/@mikro-orm/core/exceptions.js
generated
vendored
Normal file
100
node_modules/@mikro-orm/core/exceptions.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Base class for all errors detected in the driver.
|
||||
*/
|
||||
export class DriverException extends Error {
|
||||
code;
|
||||
errno;
|
||||
sqlState;
|
||||
sqlMessage;
|
||||
errmsg;
|
||||
constructor(previous) {
|
||||
super(previous.message);
|
||||
Object.getOwnPropertyNames(previous).forEach(k => (this[k] = previous[k]));
|
||||
this.name = this.constructor.name;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
if (previous.stack) {
|
||||
this.stack +=
|
||||
'\n\n' +
|
||||
previous.stack
|
||||
.split('\n')
|
||||
.filter(l => l.trim().startsWith('at '))
|
||||
.join('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Base class for all connection related errors detected in the driver.
|
||||
*/
|
||||
export class ConnectionException extends DriverException {}
|
||||
/**
|
||||
* Base class for all server related errors detected in the driver.
|
||||
*/
|
||||
export class ServerException extends DriverException {}
|
||||
/**
|
||||
* Base class for all constraint violation related errors detected in the driver.
|
||||
*/
|
||||
export class ConstraintViolationException extends ServerException {}
|
||||
/**
|
||||
* Base class for all already existing database object related errors detected in the driver.
|
||||
*
|
||||
* A database object is considered any asset that can be created in a database
|
||||
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
|
||||
* functions, stored procedures etc.
|
||||
*/
|
||||
export class DatabaseObjectExistsException extends ServerException {}
|
||||
/**
|
||||
* Base class for all unknown database object related errors detected in the driver.
|
||||
*
|
||||
* A database object is considered any asset that can be created in a database
|
||||
* such as schemas, tables, views, sequences, triggers, constraints, indexes,
|
||||
* functions, stored procedures etc.
|
||||
*/
|
||||
export class DatabaseObjectNotFoundException extends ServerException {}
|
||||
/**
|
||||
* Exception for a deadlock error of a transaction detected in the driver.
|
||||
*/
|
||||
export class DeadlockException extends ServerException {}
|
||||
/**
|
||||
* Exception for a foreign key constraint violation detected in the driver.
|
||||
*/
|
||||
export class ForeignKeyConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for a check constraint violation detected in the driver.
|
||||
*/
|
||||
export class CheckConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for an invalid specified field name in a statement detected in the driver.
|
||||
*/
|
||||
export class InvalidFieldNameException extends ServerException {}
|
||||
/**
|
||||
* Exception for a lock wait timeout error of a transaction detected in the driver.
|
||||
*/
|
||||
export class LockWaitTimeoutException extends ServerException {}
|
||||
/**
|
||||
* Exception for a non-unique/ambiguous specified field name in a statement detected in the driver.
|
||||
*/
|
||||
export class NonUniqueFieldNameException extends ServerException {}
|
||||
/**
|
||||
* Exception for a NOT NULL constraint violation detected in the driver.
|
||||
*/
|
||||
export class NotNullConstraintViolationException extends ConstraintViolationException {}
|
||||
/**
|
||||
* Exception for a write operation attempt on a read-only database element detected in the driver.
|
||||
*/
|
||||
export class ReadOnlyException extends ServerException {}
|
||||
/**
|
||||
* Exception for a syntax error in a statement detected in the driver.
|
||||
*/
|
||||
export class SyntaxErrorException extends ServerException {}
|
||||
/**
|
||||
* Exception for an already existing table referenced in a statement detected in the driver.
|
||||
*/
|
||||
export class TableExistsException extends DatabaseObjectExistsException {}
|
||||
/**
|
||||
* Exception for an unknown table referenced in a statement detected in the driver.
|
||||
*/
|
||||
export class TableNotFoundException extends DatabaseObjectNotFoundException {}
|
||||
/**
|
||||
* Exception for a unique constraint violation detected in the driver.
|
||||
*/
|
||||
export class UniqueConstraintViolationException extends ConstraintViolationException {}
|
||||
50
node_modules/@mikro-orm/core/hydration/Hydrator.d.ts
generated
vendored
Normal file
50
node_modules/@mikro-orm/core/hydration/Hydrator.d.ts
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { EntityData, EntityMetadata, EntityProperty, IHydrator } from '../typings.js';
|
||||
import type { EntityFactory } from '../entity/EntityFactory.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
||||
import type { Configuration } from '../utils/Configuration.js';
|
||||
/** Abstract base class for hydrating entity instances from raw database data. */
|
||||
export declare abstract class Hydrator implements IHydrator {
|
||||
protected readonly metadata: MetadataStorage;
|
||||
protected readonly platform: Platform;
|
||||
protected readonly config: Configuration;
|
||||
protected running: boolean;
|
||||
constructor(metadata: MetadataStorage, platform: Platform, config: Configuration);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrate<T extends object>(
|
||||
entity: T,
|
||||
meta: EntityMetadata<T>,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
type: 'full' | 'reference',
|
||||
newEntity?: boolean,
|
||||
convertCustomTypes?: boolean,
|
||||
schema?: string,
|
||||
parentSchema?: string,
|
||||
): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrateReference<T extends object>(
|
||||
entity: T,
|
||||
meta: EntityMetadata<T>,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
convertCustomTypes?: boolean,
|
||||
schema?: string,
|
||||
parentSchema?: string,
|
||||
): void;
|
||||
/** Returns whether the hydrator is currently in the middle of hydrating an entity. */
|
||||
isRunning(): boolean;
|
||||
protected getProperties<T extends object>(meta: EntityMetadata<T>, type: 'full' | 'reference'): EntityProperty<T>[];
|
||||
protected hydrateProperty<T extends object>(
|
||||
entity: T,
|
||||
prop: EntityProperty<T>,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
newEntity?: boolean,
|
||||
convertCustomTypes?: boolean,
|
||||
): void;
|
||||
}
|
||||
49
node_modules/@mikro-orm/core/hydration/Hydrator.js
generated
vendored
Normal file
49
node_modules/@mikro-orm/core/hydration/Hydrator.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/** Abstract base class for hydrating entity instances from raw database data. */
|
||||
/* v8 ignore next */
|
||||
export class Hydrator {
|
||||
metadata;
|
||||
platform;
|
||||
config;
|
||||
running = false;
|
||||
constructor(metadata, platform, config) {
|
||||
this.metadata = metadata;
|
||||
this.platform = platform;
|
||||
this.config = config;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrate(entity, meta, data, factory, type, newEntity = false, convertCustomTypes = false, schema, parentSchema) {
|
||||
// the running state is used to consider propagation as hydration, saving the values directly to the entity data,
|
||||
// but we don't want that for new entities, their propagation should result in entity updates when flushing
|
||||
this.running = !newEntity;
|
||||
const props = this.getProperties(meta, type);
|
||||
for (const prop of props) {
|
||||
this.hydrateProperty(entity, prop, data, factory, newEntity, convertCustomTypes);
|
||||
}
|
||||
this.running = false;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrateReference(entity, meta, data, factory, convertCustomTypes, schema, parentSchema) {
|
||||
this.running = true;
|
||||
meta.primaryKeys.forEach(pk => {
|
||||
this.hydrateProperty(entity, meta.properties[pk], data, factory, false, convertCustomTypes);
|
||||
});
|
||||
this.running = false;
|
||||
}
|
||||
/** Returns whether the hydrator is currently in the middle of hydrating an entity. */
|
||||
isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
getProperties(meta, type) {
|
||||
if (type === 'reference') {
|
||||
return meta.primaryKeys.map(pk => meta.properties[pk]);
|
||||
}
|
||||
return meta.hydrateProps;
|
||||
}
|
||||
hydrateProperty(entity, prop, data, factory, newEntity, convertCustomTypes) {
|
||||
entity[prop.name] = data[prop.name];
|
||||
}
|
||||
}
|
||||
57
node_modules/@mikro-orm/core/hydration/ObjectHydrator.d.ts
generated
vendored
Normal file
57
node_modules/@mikro-orm/core/hydration/ObjectHydrator.d.ts
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { EntityData, EntityMetadata } from '../typings.js';
|
||||
import { Hydrator } from './Hydrator.js';
|
||||
import type { EntityFactory } from '../entity/EntityFactory.js';
|
||||
type EntityHydrator<T extends object> = (
|
||||
entity: T,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
newEntity: boolean,
|
||||
convertCustomTypes: boolean,
|
||||
schema?: string,
|
||||
parentSchema?: string,
|
||||
normalizeAccessors?: boolean,
|
||||
) => void;
|
||||
/** @internal JIT-compiled hydrator that converts raw database rows into entity instances with optimized generated code. */
|
||||
export declare class ObjectHydrator extends Hydrator {
|
||||
#private;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrate<T extends object>(
|
||||
entity: T,
|
||||
meta: EntityMetadata<T>,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
type: 'full' | 'reference',
|
||||
newEntity?: boolean,
|
||||
convertCustomTypes?: boolean,
|
||||
schema?: string,
|
||||
parentSchema?: string,
|
||||
normalizeAccessors?: boolean,
|
||||
): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrateReference<T extends object>(
|
||||
entity: T,
|
||||
meta: EntityMetadata<T>,
|
||||
data: EntityData<T>,
|
||||
factory: EntityFactory,
|
||||
convertCustomTypes?: boolean,
|
||||
schema?: string,
|
||||
parentSchema?: string,
|
||||
normalizeAccessors?: boolean,
|
||||
): void;
|
||||
/**
|
||||
* @internal Highly performance-sensitive method.
|
||||
*/
|
||||
getEntityHydrator<T extends object>(
|
||||
meta: EntityMetadata<T>,
|
||||
type: 'full' | 'reference',
|
||||
normalizeAccessors?: boolean,
|
||||
): EntityHydrator<T>;
|
||||
private createCollectionItemMapper;
|
||||
private wrap;
|
||||
private safeKey;
|
||||
}
|
||||
export {};
|
||||
499
node_modules/@mikro-orm/core/hydration/ObjectHydrator.js
generated
vendored
Normal file
499
node_modules/@mikro-orm/core/hydration/ObjectHydrator.js
generated
vendored
Normal file
@@ -0,0 +1,499 @@
|
||||
import { Hydrator } from './Hydrator.js';
|
||||
import { Collection } from '../entity/Collection.js';
|
||||
import { Reference, ScalarReference } from '../entity/Reference.js';
|
||||
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
||||
import { parseJsonSafe, Utils } from '../utils/Utils.js';
|
||||
import { ReferenceKind } from '../enums.js';
|
||||
import { Raw } from '../utils/RawQueryFragment.js';
|
||||
import { ValidationError } from '../errors.js';
|
||||
/** @internal JIT-compiled hydrator that converts raw database rows into entity instances with optimized generated code. */
|
||||
export class ObjectHydrator extends Hydrator {
|
||||
#hydrators = {
|
||||
'full~true': new Map(),
|
||||
'full~false': new Map(),
|
||||
'reference~true': new Map(),
|
||||
'reference~false': new Map(),
|
||||
};
|
||||
#tmpIndex = 0;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrate(
|
||||
entity,
|
||||
meta,
|
||||
data,
|
||||
factory,
|
||||
type,
|
||||
newEntity = false,
|
||||
convertCustomTypes = false,
|
||||
schema,
|
||||
parentSchema,
|
||||
normalizeAccessors,
|
||||
) {
|
||||
const hydrate = this.getEntityHydrator(meta, type, normalizeAccessors);
|
||||
const running = this.running;
|
||||
// the running state is used to consider propagation as hydration, saving the values directly to the entity data,
|
||||
// but we don't want that for new entities, their propagation should result in entity updates when flushing
|
||||
this.running = !newEntity;
|
||||
Utils.callCompiledFunction(
|
||||
hydrate,
|
||||
entity,
|
||||
data,
|
||||
factory,
|
||||
newEntity,
|
||||
convertCustomTypes,
|
||||
schema,
|
||||
parentSchema,
|
||||
normalizeAccessors,
|
||||
);
|
||||
this.running = running;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
hydrateReference(entity, meta, data, factory, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
|
||||
const hydrate = this.getEntityHydrator(meta, 'reference', normalizeAccessors);
|
||||
const running = this.running;
|
||||
this.running = true;
|
||||
Utils.callCompiledFunction(
|
||||
hydrate,
|
||||
entity,
|
||||
data,
|
||||
factory,
|
||||
false,
|
||||
convertCustomTypes,
|
||||
schema,
|
||||
parentSchema,
|
||||
normalizeAccessors,
|
||||
);
|
||||
this.running = running;
|
||||
}
|
||||
/**
|
||||
* @internal Highly performance-sensitive method.
|
||||
*/
|
||||
getEntityHydrator(meta, type, normalizeAccessors = false) {
|
||||
const key = `${type}~${normalizeAccessors}`;
|
||||
const exists = this.#hydrators[key].get(meta.class);
|
||||
if (exists) {
|
||||
return exists;
|
||||
}
|
||||
const lines = [];
|
||||
const context = new Map();
|
||||
const props = this.getProperties(meta, type);
|
||||
context.set('isPrimaryKey', Utils.isPrimaryKey);
|
||||
context.set('Collection', Collection);
|
||||
context.set('Reference', Reference);
|
||||
context.set('PolymorphicRef', PolymorphicRef);
|
||||
context.set('ValidationError', ValidationError);
|
||||
const registerCustomType = (prop, convertorKey, method, context) => {
|
||||
context.set(`${method}_${convertorKey}`, val => {
|
||||
/* v8 ignore next */
|
||||
if (Raw.isKnownFragment(val)) {
|
||||
return val;
|
||||
}
|
||||
return prop.customType[method](val, this.platform, { mode: 'serialization' });
|
||||
});
|
||||
return convertorKey;
|
||||
};
|
||||
const hydrateScalar = (prop, path, dataKey) => {
|
||||
const entityKey = path.map(k => this.wrap(k)).join('');
|
||||
const tz = this.platform.getTimezone();
|
||||
const convertorKey = path
|
||||
.filter(k => !/\[idx_\d+]/.exec(k))
|
||||
.map(k => this.safeKey(k))
|
||||
.join('_');
|
||||
const ret = [];
|
||||
const idx = this.#tmpIndex++;
|
||||
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
||||
if (prop.getter && !prop.setter && prop.persist === false) {
|
||||
return [];
|
||||
}
|
||||
if (prop.ref) {
|
||||
context.set('ScalarReference', ScalarReference);
|
||||
ret.push(` const oldValue_${idx} = entity${entityKey};`);
|
||||
}
|
||||
ret.push(` if (data${dataKey} === null) {`);
|
||||
if (prop.ref) {
|
||||
ret.push(` entity${entityKey} = new ScalarReference();`);
|
||||
ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
|
||||
ret.push(` entity${entityKey}.set(${nullVal});`);
|
||||
} else {
|
||||
ret.push(` entity${entityKey} = ${nullVal};`);
|
||||
}
|
||||
ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
|
||||
if (prop.customType) {
|
||||
registerCustomType(prop, convertorKey, 'convertToJSValue', context);
|
||||
registerCustomType(prop, convertorKey, 'convertToDatabaseValue', context);
|
||||
ret.push(
|
||||
` if (convertCustomTypes) {`,
|
||||
` const value = convertToJSValue_${convertorKey}(data${dataKey});`,
|
||||
);
|
||||
if (prop.customType.ensureComparable(meta, prop)) {
|
||||
ret.push(` data${dataKey} = convertToDatabaseValue_${convertorKey}(value);`);
|
||||
}
|
||||
ret.push(
|
||||
` entity${entityKey} = value;`,
|
||||
` } else {`,
|
||||
` entity${entityKey} = data${dataKey};`,
|
||||
` }`,
|
||||
);
|
||||
} else if (prop.runtimeType === 'boolean') {
|
||||
ret.push(` entity${entityKey} = !!data${dataKey};`);
|
||||
} else if (prop.runtimeType === 'Date' && !this.platform.isNumericProperty(prop)) {
|
||||
ret.push(` if (data${dataKey} instanceof Date) {`);
|
||||
ret.push(` entity${entityKey} = data${dataKey};`);
|
||||
if (!tz || tz === 'local') {
|
||||
ret.push(` } else {`);
|
||||
ret.push(` entity${entityKey} = new Date(data${dataKey});`);
|
||||
} else {
|
||||
ret.push(
|
||||
` } else if (typeof data${dataKey} === 'number' || data${dataKey}.includes('+') || data${dataKey}.lastIndexOf('-') > 10 || data${dataKey}.endsWith('Z')) {`,
|
||||
);
|
||||
ret.push(` entity${entityKey} = new Date(data${dataKey});`);
|
||||
ret.push(` } else {`);
|
||||
ret.push(` entity${entityKey} = new Date(data${dataKey} + '${tz}');`);
|
||||
}
|
||||
ret.push(` }`);
|
||||
} else {
|
||||
ret.push(` entity${entityKey} = data${dataKey};`);
|
||||
}
|
||||
if (prop.ref) {
|
||||
ret.push(` const value = entity${entityKey};`);
|
||||
ret.push(` entity${entityKey} = oldValue_${idx} ?? new ScalarReference(value);`);
|
||||
ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
|
||||
ret.push(` entity${entityKey}.set(value);`);
|
||||
}
|
||||
ret.push(` }`);
|
||||
if (prop.ref) {
|
||||
ret.push(` if (!entity${entityKey}) {`);
|
||||
ret.push(` entity${entityKey} = new ScalarReference();`);
|
||||
ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
|
||||
ret.push(` }`);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
const hydrateToOne = (prop, dataKey, entityKey) => {
|
||||
const ret = [];
|
||||
const method = type === 'reference' ? 'createReference' : 'create';
|
||||
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
||||
ret.push(` if (data${dataKey} === null) {\n entity${entityKey} = ${nullVal};`);
|
||||
ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
|
||||
// For polymorphic: instanceof check; for regular: isPrimaryKey() check
|
||||
const pkCheck = prop.polymorphic
|
||||
? `data${dataKey} instanceof PolymorphicRef`
|
||||
: `isPrimaryKey(data${dataKey}, true)`;
|
||||
ret.push(` if (${pkCheck}) {`);
|
||||
// When targetKey is set, pass the key option to createReference so it uses the alternate key
|
||||
const keyOption = prop.targetKey ? `, key: '${prop.targetKey}'` : '';
|
||||
if (prop.polymorphic) {
|
||||
// For polymorphic: target class from discriminator map, PK from data.id
|
||||
const discriminatorMapKey = this.safeKey(`discriminatorMap_${prop.name}_${this.#tmpIndex++}`);
|
||||
context.set(discriminatorMapKey, prop.discriminatorMap);
|
||||
ret.push(` const targetClass = ${discriminatorMapKey}[data${dataKey}.discriminator];`);
|
||||
ret.push(
|
||||
` if (!targetClass) throw new ValidationError(\`Unknown discriminator value '\${data${dataKey}.discriminator}' for polymorphic relation '${prop.name}'. Valid values: \${Object.keys(${discriminatorMapKey}).join(', ')}\`);`,
|
||||
);
|
||||
if (prop.ref) {
|
||||
ret.push(
|
||||
` entity${entityKey} = Reference.create(factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`,
|
||||
);
|
||||
} else {
|
||||
ret.push(
|
||||
` entity${entityKey} = factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// For regular: fixed target class, PK is the data itself
|
||||
const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
|
||||
context.set(targetKey, prop.targetMeta.class);
|
||||
if (prop.ref) {
|
||||
ret.push(
|
||||
` entity${entityKey} = Reference.create(factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`,
|
||||
);
|
||||
} else {
|
||||
ret.push(
|
||||
` entity${entityKey} = factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`,
|
||||
);
|
||||
}
|
||||
}
|
||||
ret.push(` } else if (data${dataKey} && typeof data${dataKey} === 'object') {`);
|
||||
// For full entity hydration, polymorphic needs to determine target class from entity itself
|
||||
let hydrateTargetExpr;
|
||||
if (prop.polymorphic) {
|
||||
hydrateTargetExpr = `data${dataKey}.constructor`;
|
||||
} else {
|
||||
const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
|
||||
context.set(targetKey, prop.targetMeta.class);
|
||||
hydrateTargetExpr = targetKey;
|
||||
}
|
||||
if (prop.ref) {
|
||||
ret.push(
|
||||
` entity${entityKey} = Reference.create(factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema }));`,
|
||||
);
|
||||
} else {
|
||||
ret.push(
|
||||
` entity${entityKey} = factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema });`,
|
||||
);
|
||||
}
|
||||
ret.push(` }`);
|
||||
ret.push(` }`);
|
||||
if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
||||
const meta2 = this.metadata.get(prop.targetMeta.class);
|
||||
const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
|
||||
if (prop2 && !prop2.mapToPk) {
|
||||
ret.push(` if (data${dataKey} && entity${entityKey} && !entity${entityKey}.${this.safeKey(prop2.name)}) {`);
|
||||
ret.push(
|
||||
` entity${entityKey}.${prop.ref ? 'unwrap().' : ''}${this.safeKey(prop2.name)} = ${prop2.ref ? 'Reference.create(entity)' : 'entity'};`,
|
||||
);
|
||||
ret.push(` }`);
|
||||
}
|
||||
}
|
||||
if (prop.customType?.ensureComparable(meta, prop)) {
|
||||
registerCustomType(prop, this.safeKey(prop.name), 'convertToDatabaseValue', context);
|
||||
ret.push(` if (data${dataKey} != null && typeof data${dataKey} !== 'object' && convertCustomTypes) {`);
|
||||
ret.push(
|
||||
` data${dataKey} = convertToDatabaseValue_${this.safeKey(prop.name)}(entity${entityKey}.__helper.getPrimaryKey());`,
|
||||
);
|
||||
ret.push(` }`);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
const hydrateToMany = (prop, dataKey, entityKey) => {
|
||||
const ret = [];
|
||||
ret.push(...this.createCollectionItemMapper(prop, context));
|
||||
ret.push(` if (data${dataKey} && !Array.isArray(data${dataKey}) && typeof data${dataKey} === 'object') {`);
|
||||
ret.push(` data${dataKey} = [data${dataKey}];`);
|
||||
ret.push(` }`);
|
||||
ret.push(` if (Array.isArray(data${dataKey})) {`);
|
||||
ret.push(
|
||||
` const items = data${dataKey}.map(value => createCollectionItem_${this.safeKey(prop.name)}(value, entity));`,
|
||||
);
|
||||
ret.push(` const coll = Collection.create(entity, '${prop.name}', items, newEntity);`);
|
||||
ret.push(` if (newEntity) {`);
|
||||
ret.push(` coll.setDirty();`);
|
||||
ret.push(` } else {`);
|
||||
ret.push(` coll.takeSnapshot(true);`);
|
||||
ret.push(` }`);
|
||||
ret.push(` } else if (!entity${entityKey} && data${dataKey} instanceof Collection) {`);
|
||||
ret.push(` entity${entityKey} = data${dataKey};`);
|
||||
if (!this.platform.usesPivotTable() && prop.owner && prop.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
ret.push(` } else if (!entity${entityKey} && Array.isArray(data${dataKey})) {`);
|
||||
const items = this.platform.usesPivotTable() || !prop.owner ? 'undefined' : '[]';
|
||||
ret.push(
|
||||
` const coll = Collection.create(entity, '${prop.name}', ${items}, !!data${dataKey} || newEntity);`,
|
||||
);
|
||||
ret.push(` coll.setDirty(false);`);
|
||||
}
|
||||
ret.push(` } else if (!entity${entityKey}) {`);
|
||||
ret.push(` const coll = Collection.create(entity, '${prop.name}', undefined, newEntity);`);
|
||||
ret.push(` coll.setDirty(false);`);
|
||||
ret.push(` }`);
|
||||
return ret;
|
||||
};
|
||||
const registerEmbeddedPrototype = (prop, path) => {
|
||||
const convertorKey = path
|
||||
.filter(k => !/\[idx_\d+]/.exec(k))
|
||||
.map(k => this.safeKey(k))
|
||||
.join('_');
|
||||
if (prop.targetMeta?.polymorphs) {
|
||||
prop.targetMeta.polymorphs.forEach(meta => {
|
||||
context.set(`prototype_${convertorKey}_${meta.className}`, meta.prototype);
|
||||
});
|
||||
} else {
|
||||
context.set(`prototype_${convertorKey}`, prop.embeddable.prototype);
|
||||
}
|
||||
};
|
||||
const parseObjectEmbeddable = (prop, dataKey, ret) => {
|
||||
if (!this.platform.convertsJsonAutomatically() && (prop.object || prop.array)) {
|
||||
context.set('parseJsonSafe', parseJsonSafe);
|
||||
ret.push(
|
||||
` if (typeof data${dataKey} === 'string') {`,
|
||||
` data${dataKey} = parseJsonSafe(data${dataKey});`,
|
||||
` }`,
|
||||
);
|
||||
}
|
||||
};
|
||||
const createCond = (prop, dataKey, cond) => {
|
||||
const conds = [];
|
||||
if (prop.object) {
|
||||
conds.push(`data${dataKey} ${cond ?? '!= null'}`);
|
||||
} else {
|
||||
const notNull = cond ?? (prop.nullable ? '!= null' : '!== undefined');
|
||||
meta.props
|
||||
.filter(p => p.embedded?.[0] === prop.name)
|
||||
.forEach(p => {
|
||||
if (p.kind === ReferenceKind.EMBEDDED && !p.object && !p.array) {
|
||||
conds.push(...createCond(p, dataKey + this.wrap(p.embedded[1]), cond));
|
||||
return;
|
||||
}
|
||||
conds.push(`data${this.wrap(p.name)} ${notNull}`);
|
||||
});
|
||||
}
|
||||
return conds;
|
||||
};
|
||||
const hydrateEmbedded = (prop, path, dataKey) => {
|
||||
const entityKey = path.map(k => this.wrap(k)).join('');
|
||||
const ret = [];
|
||||
registerEmbeddedPrototype(prop, path);
|
||||
parseObjectEmbeddable(prop, dataKey, ret);
|
||||
ret.push(` if (${createCond(prop, dataKey).join(' || ')}) {`);
|
||||
if (prop.object) {
|
||||
ret.push(` const embeddedData = data${dataKey};`);
|
||||
} else {
|
||||
ret.push(` const embeddedData = {`);
|
||||
for (const childProp of Object.values(prop.embeddedProps)) {
|
||||
const key = /^\w+$/.exec(childProp.embedded[1]) ? childProp.embedded[1] : `'${childProp.embedded[1]}'`;
|
||||
ret.push(` ${key}: data${this.wrap(childProp.name)},`);
|
||||
}
|
||||
ret.push(` };`);
|
||||
}
|
||||
if (prop.targetMeta?.polymorphs) {
|
||||
prop.targetMeta.polymorphs.forEach(childMeta => {
|
||||
const childProp = prop.embeddedProps[prop.targetMeta.discriminatorColumn];
|
||||
const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
||||
context.set(childMeta.className, childMeta.class);
|
||||
// weak comparison as we can have numbers that might have been converted to strings due to being object keys
|
||||
ret.push(` if (data${childDataKey} == '${childMeta.discriminatorValue}') {`);
|
||||
ret.push(` if (entity${entityKey} == null) {`);
|
||||
ret.push(
|
||||
` entity${entityKey} = factory.createEmbeddable(${childMeta.className}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`,
|
||||
);
|
||||
ret.push(` }`);
|
||||
meta.props
|
||||
.filter(p => p.embedded?.[0] === prop.name)
|
||||
.forEach(childProp => {
|
||||
const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
||||
const prop2 = childMeta.properties[childProp.embedded[1]];
|
||||
const prop3 = {
|
||||
...prop2,
|
||||
name: childProp.name,
|
||||
embedded: childProp.embedded,
|
||||
embeddedProps: childProp.embeddedProps,
|
||||
};
|
||||
ret.push(
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
|
||||
...hydrateProperty(prop3, childProp.object, [...path, childProp.embedded[1]], childDataKey).map(
|
||||
l => ' ' + l,
|
||||
),
|
||||
);
|
||||
});
|
||||
ret.push(` }`);
|
||||
});
|
||||
} else {
|
||||
const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
|
||||
context.set(targetKey, prop.targetMeta.class);
|
||||
ret.push(` if (entity${entityKey} == null) {`);
|
||||
ret.push(
|
||||
` entity${entityKey} = factory.createEmbeddable(${targetKey}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`,
|
||||
);
|
||||
ret.push(` }`);
|
||||
meta.props
|
||||
.filter(p => p.embedded?.[0] === prop.name)
|
||||
.forEach(childProp => {
|
||||
const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
||||
ret.push(
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
|
||||
...hydrateProperty(childProp, prop.object, [...path, childProp.embedded[1]], childDataKey).map(
|
||||
l => ' ' + l,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
/* v8 ignore next */
|
||||
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
||||
if (prop.object) {
|
||||
ret.push(` } else if (data${dataKey} === null) {`);
|
||||
} else {
|
||||
ret.push(` } else if (${createCond(prop, dataKey, '=== null').join(' && ')}) {`);
|
||||
}
|
||||
ret.push(` entity${entityKey} = ${nullVal};`);
|
||||
ret.push(` }`);
|
||||
return ret;
|
||||
};
|
||||
const hydrateEmbeddedArray = (prop, path, dataKey) => {
|
||||
const entityKey = path.map(k => this.wrap(k)).join('');
|
||||
const ret = [];
|
||||
const idx = this.#tmpIndex++;
|
||||
registerEmbeddedPrototype(prop, path);
|
||||
parseObjectEmbeddable(prop, dataKey, ret);
|
||||
ret.push(` if (Array.isArray(data${dataKey})) {`);
|
||||
ret.push(` entity${entityKey} = [];`);
|
||||
ret.push(` data${dataKey}.forEach((_, idx_${idx}) => {`);
|
||||
ret.push(...hydrateEmbedded(prop, [...path, `[idx_${idx}]`], `${dataKey}[idx_${idx}]`).map(l => ' ' + l));
|
||||
ret.push(` });`);
|
||||
ret.push(` }`);
|
||||
return ret;
|
||||
};
|
||||
const hydrateProperty = (prop, object = prop.object, path = [prop.name], dataKey) => {
|
||||
const entityKey = path.map(k => this.wrap(k)).join('');
|
||||
dataKey =
|
||||
dataKey ?? (object ? entityKey : this.wrap(normalizeAccessors ? (prop.accessor ?? prop.name) : prop.name));
|
||||
const ret = [];
|
||||
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.mapToPk) {
|
||||
ret.push(...hydrateToOne(prop, dataKey, entityKey));
|
||||
} else if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
|
||||
ret.push(...hydrateToMany(prop, dataKey, entityKey));
|
||||
} else if (prop.kind === ReferenceKind.EMBEDDED) {
|
||||
if (prop.array) {
|
||||
ret.push(...hydrateEmbeddedArray(prop, path, dataKey));
|
||||
} else {
|
||||
ret.push(...hydrateEmbedded(prop, path, dataKey));
|
||||
if (!prop.object) {
|
||||
ret.push(...hydrateEmbedded({ ...prop, object: true }, path, dataKey));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ReferenceKind.SCALAR
|
||||
ret.push(...hydrateScalar(prop, path, dataKey));
|
||||
}
|
||||
if (this.config.get('forceUndefined')) {
|
||||
ret.push(` if (data${dataKey} === null) entity${entityKey} = undefined;`);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
for (const prop of props) {
|
||||
lines.push(...hydrateProperty(prop));
|
||||
}
|
||||
const code =
|
||||
`// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n` +
|
||||
`return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n` +
|
||||
`${lines.join('\n')}\n}`;
|
||||
const fnKey = `hydrator-${meta.uniqueName}-${type}-${normalizeAccessors}`;
|
||||
const hydrator = Utils.createFunction(context, code, this.config.get('compiledFunctions'), fnKey);
|
||||
this.#hydrators[key].set(meta.class, hydrator);
|
||||
return hydrator;
|
||||
}
|
||||
createCollectionItemMapper(prop, context) {
|
||||
const meta = this.metadata.get(prop.targetMeta.class);
|
||||
const lines = [];
|
||||
lines.push(` const createCollectionItem_${this.safeKey(prop.name)} = (value, entity) => {`);
|
||||
const prop2 = prop.targetMeta.properties[prop.mappedBy];
|
||||
if (prop.kind === ReferenceKind.ONE_TO_MANY && prop2.primary) {
|
||||
lines.push(` if (typeof value === 'object' && value?.['${prop2.name}'] == null) {`);
|
||||
lines.push(
|
||||
` value = { ...value, ['${prop2.name}']: Reference.wrapReference(entity, { ref: ${prop2.ref} }) };`,
|
||||
);
|
||||
lines.push(` }`);
|
||||
}
|
||||
const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
|
||||
context.set(targetKey, prop.targetMeta.class);
|
||||
lines.push(
|
||||
` if (isPrimaryKey(value, ${meta.compositePK})) return factory.createReference(${targetKey}, value, { convertCustomTypes, schema, normalizeAccessors, merge: true });`,
|
||||
);
|
||||
lines.push(` if (value && value.__entity) return value;`);
|
||||
lines.push(
|
||||
` return factory.create(${targetKey}, value, { newEntity, convertCustomTypes, schema, normalizeAccessors, merge: true });`,
|
||||
);
|
||||
lines.push(` }`);
|
||||
return lines;
|
||||
}
|
||||
wrap(key) {
|
||||
if (/^\[.*]$/.exec(key)) {
|
||||
return key;
|
||||
}
|
||||
return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
|
||||
}
|
||||
safeKey(key) {
|
||||
return key.replace(/\W/g, '_');
|
||||
}
|
||||
}
|
||||
2
node_modules/@mikro-orm/core/hydration/index.d.ts
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/hydration/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './Hydrator.js';
|
||||
export * from './ObjectHydrator.js';
|
||||
2
node_modules/@mikro-orm/core/hydration/index.js
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/hydration/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './Hydrator.js';
|
||||
export * from './ObjectHydrator.js';
|
||||
139
node_modules/@mikro-orm/core/index.d.ts
generated
vendored
Normal file
139
node_modules/@mikro-orm/core/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
* @module core
|
||||
*/
|
||||
export {
|
||||
EntityMetadata,
|
||||
PrimaryKeyProp,
|
||||
EntityRepositoryType,
|
||||
OptionalProps,
|
||||
EagerProps,
|
||||
HiddenProps,
|
||||
Config,
|
||||
EntityName,
|
||||
} from './typings.js';
|
||||
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';
|
||||
export * from './enums.js';
|
||||
export * from './errors.js';
|
||||
export * from './exceptions.js';
|
||||
export * from './MikroORM.js';
|
||||
export * from './entity/index.js';
|
||||
export * from './serialization/index.js';
|
||||
export * from './events/index.js';
|
||||
export * from './EntityManager.js';
|
||||
export * from './unit-of-work/index.js';
|
||||
export * from './utils/index.js';
|
||||
export * from './logging/index.js';
|
||||
export * from './hydration/index.js';
|
||||
export * from './drivers/index.js';
|
||||
export * from './connections/index.js';
|
||||
export * from './platforms/index.js';
|
||||
export * from './types/index.js';
|
||||
export * from './naming-strategy/index.js';
|
||||
export * from './metadata/index.js';
|
||||
export * from './cache/index.js';
|
||||
33
node_modules/@mikro-orm/core/index.js
generated
vendored
Normal file
33
node_modules/@mikro-orm/core/index.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
* @module core
|
||||
*/
|
||||
export {
|
||||
EntityMetadata,
|
||||
PrimaryKeyProp,
|
||||
EntityRepositoryType,
|
||||
OptionalProps,
|
||||
EagerProps,
|
||||
HiddenProps,
|
||||
Config,
|
||||
EntityName,
|
||||
} from './typings.js';
|
||||
export * from './enums.js';
|
||||
export * from './errors.js';
|
||||
export * from './exceptions.js';
|
||||
export * from './MikroORM.js';
|
||||
export * from './entity/index.js';
|
||||
export * from './serialization/index.js';
|
||||
export * from './events/index.js';
|
||||
export * from './EntityManager.js';
|
||||
export * from './unit-of-work/index.js';
|
||||
export * from './utils/index.js';
|
||||
export * from './logging/index.js';
|
||||
export * from './hydration/index.js';
|
||||
export * from './drivers/index.js';
|
||||
export * from './connections/index.js';
|
||||
export * from './platforms/index.js';
|
||||
export * from './types/index.js';
|
||||
export * from './naming-strategy/index.js';
|
||||
export * from './metadata/index.js';
|
||||
export * from './cache/index.js';
|
||||
38
node_modules/@mikro-orm/core/logging/DefaultLogger.d.ts
generated
vendored
Normal file
38
node_modules/@mikro-orm/core/logging/DefaultLogger.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { Logger, LoggerNamespace, LogContext, LoggerOptions } from './Logger.js';
|
||||
/** Default logger implementation with colored output, query formatting, and namespace-based filtering. */
|
||||
export declare class DefaultLogger implements Logger {
|
||||
private readonly options;
|
||||
debugMode: boolean | LoggerNamespace[];
|
||||
readonly writer: (message: string) => void;
|
||||
private readonly usesReplicas?;
|
||||
private readonly highlighter?;
|
||||
constructor(options: LoggerOptions);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
log(namespace: LoggerNamespace, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
error(namespace: LoggerNamespace, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
warn(namespace: LoggerNamespace, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setDebugMode(debugMode: boolean | LoggerNamespace[]): void;
|
||||
/** Checks whether logging is enabled for the given namespace, considering context overrides. */
|
||||
isEnabled(namespace: LoggerNamespace, context?: LogContext): boolean;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
logQuery(
|
||||
context: {
|
||||
query: string;
|
||||
} & LogContext,
|
||||
): void;
|
||||
/** Factory method for creating a new DefaultLogger instance. */
|
||||
static create(this: void, options: LoggerOptions): DefaultLogger;
|
||||
}
|
||||
98
node_modules/@mikro-orm/core/logging/DefaultLogger.js
generated
vendored
Normal file
98
node_modules/@mikro-orm/core/logging/DefaultLogger.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
import { colors } from './colors.js';
|
||||
/** Default logger implementation with colored output, query formatting, and namespace-based filtering. */
|
||||
export class DefaultLogger {
|
||||
options;
|
||||
debugMode;
|
||||
writer;
|
||||
usesReplicas;
|
||||
highlighter;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
this.debugMode = this.options.debugMode ?? false;
|
||||
this.writer = this.options.writer;
|
||||
this.usesReplicas = this.options.usesReplicas;
|
||||
this.highlighter = this.options.highlighter;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
log(namespace, message, context) {
|
||||
if (!this.isEnabled(namespace, context)) {
|
||||
return;
|
||||
}
|
||||
// clean up the whitespace
|
||||
message = message.replace(/\n/g, '').replace(/ +/g, ' ').trim();
|
||||
// use red for error levels
|
||||
if (context?.level === 'error') {
|
||||
message = colors.red(message);
|
||||
}
|
||||
// use yellow for warning levels
|
||||
if (context?.level === 'warning') {
|
||||
message = colors.yellow(message);
|
||||
}
|
||||
const label = context?.label ? colors.cyan(`(${context.label}) `) : '';
|
||||
this.writer(colors.grey(`[${namespace}] `) + label + message);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
error(namespace, message, context) {
|
||||
this.log(namespace, message, { ...context, level: 'error' });
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
warn(namespace, message, context) {
|
||||
this.log(namespace, message, { ...context, level: 'warning' });
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setDebugMode(debugMode) {
|
||||
this.debugMode = debugMode;
|
||||
}
|
||||
/** Checks whether logging is enabled for the given namespace, considering context overrides. */
|
||||
isEnabled(namespace, context) {
|
||||
if (context?.enabled !== undefined) {
|
||||
return context.enabled;
|
||||
}
|
||||
const debugMode = context?.debugMode ?? this.debugMode;
|
||||
if (namespace === 'deprecated') {
|
||||
const { ignoreDeprecations = false } = this.options;
|
||||
return Array.isArray(ignoreDeprecations)
|
||||
? /* v8 ignore next */
|
||||
!ignoreDeprecations.includes(context?.label ?? '')
|
||||
: !ignoreDeprecations;
|
||||
}
|
||||
return !!debugMode && (!Array.isArray(debugMode) || debugMode.includes(namespace));
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
logQuery(context) {
|
||||
const namespace = context.namespace ?? 'query';
|
||||
if (!this.isEnabled(namespace, context)) {
|
||||
return;
|
||||
}
|
||||
/* v8 ignore next */
|
||||
let msg = this.highlighter?.highlight(context.query) ?? context.query;
|
||||
if (context.took != null) {
|
||||
const meta = [`took ${context.took} ms`];
|
||||
if (context.results != null) {
|
||||
meta.push(`${context.results} result${context.results === 0 || context.results > 1 ? 's' : ''}`);
|
||||
}
|
||||
if (context.affected != null) {
|
||||
meta.push(`${context.affected} row${context.affected === 0 || context.affected > 1 ? 's' : ''} affected`);
|
||||
}
|
||||
msg += colors.grey(` [${meta.join(', ')}]`);
|
||||
}
|
||||
if (this.usesReplicas && context.connection) {
|
||||
msg += colors.cyan(` (via ${context.connection.type} connection '${context.connection.name}')`);
|
||||
}
|
||||
return this.log(namespace, msg, context);
|
||||
}
|
||||
/** Factory method for creating a new DefaultLogger instance. */
|
||||
static create(options) {
|
||||
return new DefaultLogger(options);
|
||||
}
|
||||
}
|
||||
63
node_modules/@mikro-orm/core/logging/Logger.d.ts
generated
vendored
Normal file
63
node_modules/@mikro-orm/core/logging/Logger.d.ts
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { AnyString, Dictionary, Highlighter } from '../typings.js';
|
||||
/** Interface for ORM logging, supporting namespaced log levels and query logging. */
|
||||
export interface Logger {
|
||||
/**
|
||||
* Logs a message inside given namespace.
|
||||
*/
|
||||
log(namespace: LoggerNamespace | AnyString, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* Logs error message inside given namespace.
|
||||
*/
|
||||
error(namespace: LoggerNamespace | AnyString, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* Logs warning message inside given namespace.
|
||||
*/
|
||||
warn(namespace: LoggerNamespace | AnyString, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* Logs a message inside given namespace.
|
||||
*/
|
||||
logQuery(context: LogContext): void;
|
||||
/**
|
||||
* Sets active namespaces. Pass `true` to enable all logging.
|
||||
*/
|
||||
setDebugMode(debugMode: boolean | LoggerNamespace[]): void;
|
||||
/** Checks whether logging is enabled for the given namespace. */
|
||||
isEnabled(namespace: LoggerNamespace, context?: LogContext): boolean;
|
||||
}
|
||||
/** Available logging namespaces that can be individually enabled or disabled. */
|
||||
export type LoggerNamespace = 'query' | 'query-params' | 'schema' | 'discovery' | 'info' | 'deprecated' | 'slow-query';
|
||||
/** Contextual metadata passed alongside log messages, including query details and timing. */
|
||||
export interface LogContext extends Dictionary {
|
||||
query?: string;
|
||||
label?: string;
|
||||
namespace?: LoggerNamespace;
|
||||
params?: readonly unknown[];
|
||||
took?: number;
|
||||
results?: number;
|
||||
affected?: number;
|
||||
level?: 'info' | 'warning' | 'error';
|
||||
enabled?: boolean;
|
||||
debugMode?: LoggerNamespace[];
|
||||
connection?: {
|
||||
type?: string;
|
||||
name?: string;
|
||||
};
|
||||
}
|
||||
/** Options for constructing a Logger instance. */
|
||||
export interface LoggerOptions {
|
||||
writer: (message: string) => void;
|
||||
debugMode?: boolean | LoggerNamespace[];
|
||||
ignoreDeprecations?: boolean | string[];
|
||||
highlighter?: Highlighter;
|
||||
usesReplicas?: boolean;
|
||||
}
|
||||
/**
|
||||
* Logger options to modify format output and overrides, including a label and additional properties that can be accessed by custom loggers.
|
||||
*
|
||||
* Differs from {@apilink LoggerOptions} in terms of how they are used; this type is primarily a public type meant to be used within methods like `em.find()`.
|
||||
*
|
||||
* @example
|
||||
* await em.findOne(User, 1, { logger: { label: 'user middleware' } };
|
||||
* // [query] (user middleware) select * from user where id = 1;
|
||||
*/
|
||||
export type LoggingOptions = Pick<LogContext, 'label' | 'enabled' | 'debugMode'>;
|
||||
1
node_modules/@mikro-orm/core/logging/Logger.js
generated
vendored
Normal file
1
node_modules/@mikro-orm/core/logging/Logger.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
20
node_modules/@mikro-orm/core/logging/SimpleLogger.d.ts
generated
vendored
Normal file
20
node_modules/@mikro-orm/core/logging/SimpleLogger.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { LogContext, LoggerNamespace, LoggerOptions } from './Logger.js';
|
||||
import { DefaultLogger } from './DefaultLogger.js';
|
||||
/**
|
||||
* A basic logger that provides fully formatted output without color
|
||||
*/
|
||||
export declare class SimpleLogger extends DefaultLogger {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
log(namespace: LoggerNamespace, message: string, context?: LogContext): void;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
logQuery(
|
||||
context: {
|
||||
query: string;
|
||||
} & LogContext,
|
||||
): void;
|
||||
static create(this: void, options: LoggerOptions): SimpleLogger;
|
||||
}
|
||||
30
node_modules/@mikro-orm/core/logging/SimpleLogger.js
generated
vendored
Normal file
30
node_modules/@mikro-orm/core/logging/SimpleLogger.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { DefaultLogger } from './DefaultLogger.js';
|
||||
/**
|
||||
* A basic logger that provides fully formatted output without color
|
||||
*/
|
||||
export class SimpleLogger extends DefaultLogger {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
log(namespace, message, context) {
|
||||
if (!this.isEnabled(namespace, context)) {
|
||||
return;
|
||||
}
|
||||
// clean up the whitespace
|
||||
message = message.replace(/\n/g, '').replace(/ +/g, ' ').trim();
|
||||
const label = context?.label ? `(${context.label}) ` : '';
|
||||
this.writer(`[${namespace}] ${label}${message}`);
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
logQuery(context) {
|
||||
if (!this.isEnabled('query', context)) {
|
||||
return;
|
||||
}
|
||||
return this.log('query', context.query, context);
|
||||
}
|
||||
static create(options) {
|
||||
return new SimpleLogger(options);
|
||||
}
|
||||
}
|
||||
9
node_modules/@mikro-orm/core/logging/colors.d.ts
generated
vendored
Normal file
9
node_modules/@mikro-orm/core/logging/colors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/** @internal */
|
||||
export declare const colors: {
|
||||
red: (text: string) => string;
|
||||
green: (text: string) => string;
|
||||
yellow: (text: string) => string;
|
||||
grey: (text: string) => string;
|
||||
cyan: (text: string) => string;
|
||||
enabled: () => boolean;
|
||||
};
|
||||
15
node_modules/@mikro-orm/core/logging/colors.js
generated
vendored
Normal file
15
node_modules/@mikro-orm/core/logging/colors.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { getEnv } from '../utils/env-vars.js';
|
||||
const bool = k => ['true', 't', '1'].includes(getEnv(k)?.toLowerCase() ?? '');
|
||||
const boolIfDefined = k => (getEnv(k) != null ? bool(k) : true);
|
||||
const enabled = () =>
|
||||
!bool('NO_COLOR') && !bool('MIKRO_ORM_NO_COLOR') && boolIfDefined('FORCE_COLOR') && boolIfDefined('MIKRO_ORM_COLORS');
|
||||
const wrap = fn => text => (enabled() ? fn(text) : text);
|
||||
/** @internal */
|
||||
export const colors = {
|
||||
red: wrap(text => `\x1B[31m${text}\x1B[39m`),
|
||||
green: wrap(text => `\x1B[32m${text}\x1B[39m`),
|
||||
yellow: wrap(text => `\x1B[33m${text}\x1B[39m`),
|
||||
grey: wrap(text => `\x1B[90m${text}\x1B[39m`),
|
||||
cyan: wrap(text => `\x1B[36m${text}\x1B[39m`),
|
||||
enabled,
|
||||
};
|
||||
5
node_modules/@mikro-orm/core/logging/index.d.ts
generated
vendored
Normal file
5
node_modules/@mikro-orm/core/logging/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './colors.js';
|
||||
export type * from './Logger.js';
|
||||
export * from './DefaultLogger.js';
|
||||
export * from './SimpleLogger.js';
|
||||
export * from './inspect.js';
|
||||
4
node_modules/@mikro-orm/core/logging/index.js
generated
vendored
Normal file
4
node_modules/@mikro-orm/core/logging/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './colors.js';
|
||||
export * from './DefaultLogger.js';
|
||||
export * from './SimpleLogger.js';
|
||||
export * from './inspect.js';
|
||||
2
node_modules/@mikro-orm/core/logging/inspect.d.ts
generated
vendored
Normal file
2
node_modules/@mikro-orm/core/logging/inspect.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @internal */
|
||||
export declare function inspect(value: unknown, options?: Record<string, any>): string;
|
||||
11
node_modules/@mikro-orm/core/logging/inspect.js
generated
vendored
Normal file
11
node_modules/@mikro-orm/core/logging/inspect.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
let nodeInspect;
|
||||
/** @internal */
|
||||
export function inspect(value, options) {
|
||||
nodeInspect ??= globalThis.process?.getBuiltinModule?.('node:util').inspect;
|
||||
/* v8 ignore else */
|
||||
if (nodeInspect) {
|
||||
return nodeInspect(value, options);
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
225
node_modules/@mikro-orm/core/metadata/EntitySchema.d.ts
generated
vendored
Normal file
225
node_modules/@mikro-orm/core/metadata/EntitySchema.d.ts
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
import {
|
||||
EntityMetadata,
|
||||
type AnyEntity,
|
||||
type EntityKey,
|
||||
type Constructor,
|
||||
type DeepPartial,
|
||||
type EntityName,
|
||||
type EntityProperty,
|
||||
type CleanKeys,
|
||||
type ExpandProperty,
|
||||
type IsNever,
|
||||
type EntityCtor,
|
||||
} from '../typings.js';
|
||||
import { type EventType, ReferenceKind } from '../enums.js';
|
||||
import type { EventArgs } from '../events/EventSubscriber.js';
|
||||
import { Type } from '../types/Type.js';
|
||||
import type {
|
||||
PropertyOptions,
|
||||
ManyToOneOptions,
|
||||
OneToOneOptions,
|
||||
OneToManyOptions,
|
||||
ManyToManyOptions,
|
||||
EmbeddedOptions,
|
||||
EnumOptions,
|
||||
PrimaryKeyOptions,
|
||||
SerializedPrimaryKeyOptions,
|
||||
IndexOptions,
|
||||
UniqueOptions,
|
||||
} from './types.js';
|
||||
type TypeType =
|
||||
| string
|
||||
| NumberConstructor
|
||||
| StringConstructor
|
||||
| BooleanConstructor
|
||||
| DateConstructor
|
||||
| ArrayConstructor
|
||||
| Constructor<Type<any>>
|
||||
| Type<any>;
|
||||
type TypeDef<Target> =
|
||||
| {
|
||||
type: TypeType;
|
||||
}
|
||||
| {
|
||||
entity: () => EntityName<Target> | EntityName[];
|
||||
};
|
||||
type EmbeddedTypeDef<Target> =
|
||||
| {
|
||||
type: TypeType;
|
||||
}
|
||||
| {
|
||||
entity: () => EntityName<Target> | EntityName[];
|
||||
};
|
||||
/** Union type representing all possible property definition shapes in an EntitySchema. */
|
||||
export type EntitySchemaProperty<Target, Owner> =
|
||||
| ({
|
||||
kind: ReferenceKind.MANY_TO_ONE | 'm:1';
|
||||
} & TypeDef<Target> &
|
||||
ManyToOneOptions<Owner, Target>)
|
||||
| ({
|
||||
kind: ReferenceKind.ONE_TO_ONE | '1:1';
|
||||
} & TypeDef<Target> &
|
||||
OneToOneOptions<Owner, Target>)
|
||||
| ({
|
||||
kind: ReferenceKind.ONE_TO_MANY | '1:m';
|
||||
} & TypeDef<Target> &
|
||||
OneToManyOptions<Owner, Target>)
|
||||
| ({
|
||||
kind: ReferenceKind.MANY_TO_MANY | 'm:n';
|
||||
} & TypeDef<Target> &
|
||||
ManyToManyOptions<Owner, Target>)
|
||||
| ({
|
||||
kind: ReferenceKind.EMBEDDED | 'embedded';
|
||||
} & EmbeddedTypeDef<Target> &
|
||||
EmbeddedOptions<Owner, Target> &
|
||||
PropertyOptions<Owner>)
|
||||
| ({
|
||||
enum: true;
|
||||
} & EnumOptions<Owner>)
|
||||
| (TypeDef<Target> & PropertyOptions<Owner>);
|
||||
type OmitBaseProps<Entity, Base> = IsNever<Base> extends true ? Entity : Omit<Entity, keyof Base>;
|
||||
/** Configuration object for defining an entity via EntitySchema. */
|
||||
export type EntitySchemaMetadata<Entity, Base = never, Class extends EntityCtor = EntityCtor<Entity>> = Omit<
|
||||
Partial<EntityMetadata<Entity>>,
|
||||
'name' | 'properties' | 'extends'
|
||||
> &
|
||||
(
|
||||
| {
|
||||
name: string;
|
||||
}
|
||||
| {
|
||||
class: Class;
|
||||
name?: string;
|
||||
}
|
||||
) & {
|
||||
extends?: EntityName<Base>;
|
||||
} & {
|
||||
properties?: {
|
||||
[Key in keyof OmitBaseProps<Entity, Base> as CleanKeys<OmitBaseProps<Entity, Base>, Key>]-?: EntitySchemaProperty<
|
||||
ExpandProperty<NonNullable<Entity[Key]>>,
|
||||
Entity
|
||||
>;
|
||||
};
|
||||
} & {
|
||||
inheritance?: 'tpt';
|
||||
};
|
||||
/** Class-less entity definition that provides a programmatic API for defining entities without decorators. */
|
||||
export declare class EntitySchema<Entity = any, Base = never, Class extends EntityCtor = EntityCtor<Entity>> {
|
||||
/**
|
||||
* When schema links the entity class via `class` option, this registry allows the lookup from opposite side,
|
||||
* so we can use the class in `entities` option just like the EntitySchema instance.
|
||||
*/
|
||||
static REGISTRY: Map<AnyEntity, EntitySchema>;
|
||||
/** @internal Type-level marker for fast entity type inference */
|
||||
readonly '~entity': Entity;
|
||||
private readonly _meta;
|
||||
private internal;
|
||||
private initialized;
|
||||
constructor(meta: EntitySchemaMetadata<Entity, Base, Class>);
|
||||
/**
|
||||
* Checks if the given value is an EntitySchema instance, using duck-typing
|
||||
* as a fallback when `instanceof` fails due to CJS/ESM dual-package hazard
|
||||
* (e.g. when using `tsx` or `@swc-node/register` with `"type": "commonjs"` projects).
|
||||
*/
|
||||
static is(item: unknown): item is EntitySchema;
|
||||
/** Creates an EntitySchema from existing EntityMetadata (used internally). */
|
||||
static fromMetadata<T = AnyEntity, U = never>(
|
||||
meta: EntityMetadata<T> | DeepPartial<EntityMetadata<T>>,
|
||||
): EntitySchema<T, U>;
|
||||
/** Adds a scalar property to the entity schema. */
|
||||
addProperty(
|
||||
name: EntityKey<Entity>,
|
||||
type?: TypeType,
|
||||
options?: PropertyOptions<Entity> | EntityProperty<Entity>,
|
||||
): void;
|
||||
/** Adds an enum property to the entity schema. */
|
||||
addEnum(name: EntityKey<Entity>, type?: TypeType, options?: EnumOptions<Entity>): void;
|
||||
/** Adds a version property for optimistic locking. */
|
||||
addVersion(name: EntityKey<Entity>, type: TypeType, options?: PropertyOptions<Entity>): void;
|
||||
/** Adds a primary key property to the entity schema. */
|
||||
addPrimaryKey(name: EntityKey<Entity>, type: TypeType, options?: PrimaryKeyOptions<Entity>): void;
|
||||
/** Adds a serialized primary key property (e.g. for MongoDB ObjectId). */
|
||||
addSerializedPrimaryKey(name: EntityKey<Entity>, type: TypeType, options?: SerializedPrimaryKeyOptions<Entity>): void;
|
||||
/** Adds an embedded property to the entity schema. */
|
||||
addEmbedded<Target = AnyEntity>(name: EntityKey<Entity>, options: EmbeddedOptions<Entity, Target>): void;
|
||||
/** Adds a many-to-one relation to the entity schema. */
|
||||
addManyToOne<Target = AnyEntity>(
|
||||
name: EntityKey<Entity>,
|
||||
type: TypeType,
|
||||
options: ManyToOneOptions<Entity, Target>,
|
||||
): void;
|
||||
/** Adds a many-to-many relation to the entity schema. */
|
||||
addManyToMany<Target = AnyEntity>(
|
||||
name: EntityKey<Entity>,
|
||||
type: TypeType,
|
||||
options: ManyToManyOptions<Entity, Target>,
|
||||
): void;
|
||||
/** Adds a one-to-many relation to the entity schema. */
|
||||
addOneToMany<Target = AnyEntity>(
|
||||
name: EntityKey<Entity>,
|
||||
type: TypeType,
|
||||
options: OneToManyOptions<Entity, Target>,
|
||||
): void;
|
||||
/** Adds a one-to-one relation to the entity schema. */
|
||||
addOneToOne<Target = AnyEntity>(
|
||||
name: EntityKey<Entity>,
|
||||
type: TypeType,
|
||||
options: OneToOneOptions<Entity, Target>,
|
||||
): void;
|
||||
/** Adds an index definition to the entity schema. */
|
||||
addIndex<Key extends string>(options: IndexOptions<Entity, Key>): void;
|
||||
/** Adds a unique constraint definition to the entity schema. */
|
||||
addUnique<Key extends string>(options: UniqueOptions<Entity, Key>): void;
|
||||
/** Sets a custom repository class for this entity. */
|
||||
setCustomRepository(repository: () => Constructor): void;
|
||||
/** Sets the base entity that this schema extends. */
|
||||
setExtends(base: EntityName): void;
|
||||
/** Sets or replaces the entity class associated with this schema. */
|
||||
setClass(cls: Class): void;
|
||||
/** Returns the underlying EntityMetadata. */
|
||||
get meta(): EntityMetadata<Entity, Class>;
|
||||
/** Returns the entity class name. */
|
||||
get name(): string | EntityName<Entity>;
|
||||
/** Returns the database table name. */
|
||||
get tableName(): string;
|
||||
get class(): Class;
|
||||
get properties(): Record<string, any>;
|
||||
new(...params: ConstructorParameters<Class>): Entity;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
init(): this;
|
||||
/**
|
||||
* Check if this entity is part of a TPT hierarchy by walking up the extends chain.
|
||||
* This handles mid-level abstract entities (e.g., Animal -> Mammal -> Dog where Mammal is abstract).
|
||||
*/
|
||||
private isPartOfTPTHierarchy;
|
||||
private initProperties;
|
||||
private initPrimaryKeys;
|
||||
private normalizeType;
|
||||
private createProperty;
|
||||
private rename;
|
||||
private renameCompositeOptions;
|
||||
/**
|
||||
* Adds a lifecycle hook handler to the entity schema.
|
||||
* This method allows registering hooks after the entity is defined,
|
||||
* which can be useful for avoiding circular type references.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* export const Article = defineEntity({
|
||||
* name: 'Article',
|
||||
* properties: { ... },
|
||||
* });
|
||||
*
|
||||
* Article.addHook('beforeCreate', async args => {
|
||||
* args.entity.slug = args.entity.title.toLowerCase();
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
addHook<T extends Entity = Entity>(
|
||||
event: EventType | `${EventType}`,
|
||||
handler: (args: EventArgs<T>) => void | Promise<void>,
|
||||
): this;
|
||||
}
|
||||
export {};
|
||||
405
node_modules/@mikro-orm/core/metadata/EntitySchema.js
generated
vendored
Normal file
405
node_modules/@mikro-orm/core/metadata/EntitySchema.js
generated
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
import { EntityMetadata } from '../typings.js';
|
||||
import { BaseEntity } from '../entity/BaseEntity.js';
|
||||
import { Cascade, ReferenceKind } from '../enums.js';
|
||||
import { Type } from '../types/Type.js';
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { EnumArrayType } from '../types/EnumArrayType.js';
|
||||
/** Class-less entity definition that provides a programmatic API for defining entities without decorators. */
|
||||
export class EntitySchema {
|
||||
/**
|
||||
* When schema links the entity class via `class` option, this registry allows the lookup from opposite side,
|
||||
* so we can use the class in `entities` option just like the EntitySchema instance.
|
||||
*/
|
||||
static REGISTRY = new Map();
|
||||
_meta;
|
||||
internal = false;
|
||||
initialized = false;
|
||||
constructor(meta) {
|
||||
meta.name = meta.class ? meta.class.name : meta.name;
|
||||
if (meta.name) {
|
||||
meta.abstract ??= false;
|
||||
}
|
||||
this._meta = new EntityMetadata({
|
||||
className: meta.name,
|
||||
...meta,
|
||||
});
|
||||
this._meta.root ??= this._meta;
|
||||
if (meta.class && !meta.internal) {
|
||||
EntitySchema.REGISTRY.set(meta.class, this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if the given value is an EntitySchema instance, using duck-typing
|
||||
* as a fallback when `instanceof` fails due to CJS/ESM dual-package hazard
|
||||
* (e.g. when using `tsx` or `@swc-node/register` with `"type": "commonjs"` projects).
|
||||
*/
|
||||
static is(item) {
|
||||
if (item instanceof EntitySchema) {
|
||||
return true;
|
||||
}
|
||||
return item != null && typeof item === 'object' && item.constructor?.name === 'EntitySchema' && 'meta' in item;
|
||||
}
|
||||
/** Creates an EntitySchema from existing EntityMetadata (used internally). */
|
||||
static fromMetadata(meta) {
|
||||
const schema = new EntitySchema({ ...meta, internal: true });
|
||||
schema.internal = true;
|
||||
return schema;
|
||||
}
|
||||
/** Adds a scalar property to the entity schema. */
|
||||
addProperty(name, type, options = {}) {
|
||||
this.renameCompositeOptions(name, options);
|
||||
const prop = {
|
||||
name,
|
||||
kind: ReferenceKind.SCALAR,
|
||||
...options,
|
||||
...this.normalizeType(options, type),
|
||||
};
|
||||
if (type && Type.isMappedType(type.prototype)) {
|
||||
prop.type = type;
|
||||
}
|
||||
if (typeof prop.formula === 'string') {
|
||||
const formula = prop.formula;
|
||||
prop.formula = () => formula;
|
||||
}
|
||||
if (prop.formula) {
|
||||
prop.persist ??= false;
|
||||
}
|
||||
this._meta.properties[name] = prop;
|
||||
}
|
||||
/** Adds an enum property to the entity schema. */
|
||||
addEnum(name, type, options = {}) {
|
||||
if (options.items instanceof Function) {
|
||||
options.items = Utils.extractEnumValues(options.items());
|
||||
}
|
||||
// enum arrays are simple numeric/string arrays, the constraint is enforced in the custom type only
|
||||
if (options.array && !options.type) {
|
||||
options.type = new EnumArrayType(`${this._meta.className}.${name}`, options.items);
|
||||
options.enum = false;
|
||||
}
|
||||
const prop = { enum: true, ...options };
|
||||
if (prop.array) {
|
||||
prop.enum = false;
|
||||
}
|
||||
// force string labels on native enums
|
||||
if (prop.nativeEnumName && Array.isArray(prop.items)) {
|
||||
prop.items = prop.items.map(val => '' + val);
|
||||
}
|
||||
this.addProperty(name, this.internal ? type : type || 'enum', prop);
|
||||
}
|
||||
/** Adds a version property for optimistic locking. */
|
||||
addVersion(name, type, options = {}) {
|
||||
this.addProperty(name, type, { version: true, ...options });
|
||||
}
|
||||
/** Adds a primary key property to the entity schema. */
|
||||
addPrimaryKey(name, type, options = {}) {
|
||||
this.addProperty(name, type, { primary: true, ...options });
|
||||
}
|
||||
/** Adds a serialized primary key property (e.g. for MongoDB ObjectId). */
|
||||
addSerializedPrimaryKey(name, type, options = {}) {
|
||||
this._meta.serializedPrimaryKey = name;
|
||||
this.addProperty(name, type, { serializedPrimaryKey: true, ...options });
|
||||
}
|
||||
/** Adds an embedded property to the entity schema. */
|
||||
addEmbedded(name, options) {
|
||||
this.renameCompositeOptions(name, options);
|
||||
Utils.defaultValue(options, 'prefix', true);
|
||||
if (options.array) {
|
||||
options.object = true; // force object mode for arrays
|
||||
}
|
||||
this._meta.properties[name] = {
|
||||
name,
|
||||
kind: ReferenceKind.EMBEDDED,
|
||||
...this.normalizeType(options),
|
||||
...options,
|
||||
};
|
||||
}
|
||||
/** Adds a many-to-one relation to the entity schema. */
|
||||
addManyToOne(name, type, options) {
|
||||
const prop = this.createProperty(ReferenceKind.MANY_TO_ONE, options);
|
||||
prop.owner = true;
|
||||
if (prop.joinColumns && !prop.fieldNames) {
|
||||
prop.fieldNames = prop.joinColumns;
|
||||
}
|
||||
if (prop.fieldNames && !prop.joinColumns) {
|
||||
prop.joinColumns = prop.fieldNames;
|
||||
}
|
||||
// By default, the foreign key constraint is created on the relation
|
||||
Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
|
||||
this.addProperty(name, type, prop);
|
||||
}
|
||||
/** Adds a many-to-many relation to the entity schema. */
|
||||
addManyToMany(name, type, options) {
|
||||
options.fixedOrder = options.fixedOrder || !!options.fixedOrderColumn;
|
||||
if (!options.owner && !options.mappedBy) {
|
||||
options.owner = true;
|
||||
}
|
||||
if (options.owner) {
|
||||
Utils.renameKey(options, 'mappedBy', 'inversedBy');
|
||||
// By default, the foreign key constraint is created on the relation
|
||||
Utils.defaultValue(options, 'createForeignKeyConstraint', true);
|
||||
}
|
||||
const prop = this.createProperty(ReferenceKind.MANY_TO_MANY, options);
|
||||
this.addProperty(name, type, prop);
|
||||
}
|
||||
/** Adds a one-to-many relation to the entity schema. */
|
||||
addOneToMany(name, type, options) {
|
||||
const prop = this.createProperty(ReferenceKind.ONE_TO_MANY, options);
|
||||
this.addProperty(name, type, prop);
|
||||
}
|
||||
/** Adds a one-to-one relation to the entity schema. */
|
||||
addOneToOne(name, type, options) {
|
||||
const prop = this.createProperty(ReferenceKind.ONE_TO_ONE, options);
|
||||
Utils.defaultValue(prop, 'owner', !!prop.inversedBy || !prop.mappedBy);
|
||||
Utils.defaultValue(prop, 'unique', prop.owner);
|
||||
if (prop.owner) {
|
||||
if (options.mappedBy) {
|
||||
Utils.renameKey(prop, 'mappedBy', 'inversedBy');
|
||||
}
|
||||
// By default, the foreign key constraint is created on the relation
|
||||
Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
|
||||
}
|
||||
if (prop.joinColumns && !prop.fieldNames) {
|
||||
prop.fieldNames = prop.joinColumns;
|
||||
}
|
||||
if (prop.fieldNames && !prop.joinColumns) {
|
||||
prop.joinColumns = prop.fieldNames;
|
||||
}
|
||||
this.addProperty(name, type, prop);
|
||||
}
|
||||
/** Adds an index definition to the entity schema. */
|
||||
addIndex(options) {
|
||||
this._meta.indexes.push(options);
|
||||
}
|
||||
/** Adds a unique constraint definition to the entity schema. */
|
||||
addUnique(options) {
|
||||
this._meta.uniques.push(options);
|
||||
}
|
||||
/** Sets a custom repository class for this entity. */
|
||||
setCustomRepository(repository) {
|
||||
this._meta.repository = repository;
|
||||
}
|
||||
/** Sets the base entity that this schema extends. */
|
||||
setExtends(base) {
|
||||
this._meta.extends = base;
|
||||
}
|
||||
/** Sets or replaces the entity class associated with this schema. */
|
||||
setClass(cls) {
|
||||
const oldClass = this._meta.class;
|
||||
const sameClass = this._meta.class === cls;
|
||||
this._meta.class = cls;
|
||||
this._meta.prototype = cls.prototype;
|
||||
this._meta.className = this._meta.name ?? cls.name;
|
||||
if (!sameClass || !this._meta.constructorParams) {
|
||||
this._meta.constructorParams = Utils.getConstructorParams(cls);
|
||||
}
|
||||
if (!this.internal) {
|
||||
// Remove old class from registry if it's being replaced with a different class
|
||||
if (oldClass && oldClass !== cls && EntitySchema.REGISTRY.get(oldClass) === this) {
|
||||
EntitySchema.REGISTRY.delete(oldClass);
|
||||
}
|
||||
EntitySchema.REGISTRY.set(cls, this);
|
||||
}
|
||||
const base = Object.getPrototypeOf(cls);
|
||||
// Only set extends if the parent is NOT the auto-generated class for this same entity.
|
||||
// When the user extends the auto-generated class (from defineEntity without a class option)
|
||||
// and registers their custom class via setClass, we don't want to discover the
|
||||
// auto-generated class as a separate parent entity.
|
||||
if (base !== BaseEntity && base.name !== this._meta.className) {
|
||||
this._meta.extends ??= base.name ? base : undefined;
|
||||
}
|
||||
}
|
||||
/** Returns the underlying EntityMetadata. */
|
||||
get meta() {
|
||||
return this._meta;
|
||||
}
|
||||
/** Returns the entity class name. */
|
||||
get name() {
|
||||
return this._meta.className;
|
||||
}
|
||||
/** Returns the database table name. */
|
||||
get tableName() {
|
||||
return this._meta.tableName;
|
||||
}
|
||||
get class() {
|
||||
return this._meta.class;
|
||||
}
|
||||
get properties() {
|
||||
return this._meta.properties;
|
||||
}
|
||||
new(...params) {
|
||||
return new this._meta.class(...params);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
init() {
|
||||
if (this.initialized) {
|
||||
return this;
|
||||
}
|
||||
this.setClass(this._meta.class);
|
||||
// Abstract TPT entities keep their name because they have their own table
|
||||
const isTPT = this._meta.inheritance === 'tpt' || this.isPartOfTPTHierarchy();
|
||||
if (this._meta.abstract && !this._meta.discriminatorColumn && !isTPT) {
|
||||
delete this._meta.name;
|
||||
}
|
||||
const tableName = this._meta.collection ?? this._meta.tableName;
|
||||
if (tableName?.includes('.') && !this._meta.schema) {
|
||||
this._meta.schema = tableName.substring(0, tableName.indexOf('.'));
|
||||
this._meta.tableName = tableName.substring(tableName.indexOf('.') + 1);
|
||||
}
|
||||
this.initProperties();
|
||||
this.initPrimaryKeys();
|
||||
this._meta.props = Object.values(this._meta.properties);
|
||||
this._meta.relations = this._meta.props.filter(
|
||||
prop =>
|
||||
typeof prop.kind !== 'undefined' && prop.kind !== ReferenceKind.SCALAR && prop.kind !== ReferenceKind.EMBEDDED,
|
||||
);
|
||||
this.initialized = true;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Check if this entity is part of a TPT hierarchy by walking up the extends chain.
|
||||
* This handles mid-level abstract entities (e.g., Animal -> Mammal -> Dog where Mammal is abstract).
|
||||
*/
|
||||
isPartOfTPTHierarchy() {
|
||||
let parent = this._meta.extends;
|
||||
while (parent) {
|
||||
const parentSchema = EntitySchema.is(parent) ? parent : EntitySchema.REGISTRY.get(parent);
|
||||
if (!parentSchema) {
|
||||
break;
|
||||
}
|
||||
if (parentSchema._meta.inheritance === 'tpt') {
|
||||
return true;
|
||||
}
|
||||
parent = parentSchema._meta.extends;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
initProperties() {
|
||||
Utils.entries(this._meta.properties).forEach(([name, options]) => {
|
||||
if (Type.isMappedType(options.type)) {
|
||||
options.type ??= options.type.constructor.name;
|
||||
}
|
||||
switch (options.kind) {
|
||||
case ReferenceKind.ONE_TO_ONE:
|
||||
this.addOneToOne(name, options.type, options);
|
||||
break;
|
||||
case ReferenceKind.ONE_TO_MANY:
|
||||
this.addOneToMany(name, options.type, options);
|
||||
break;
|
||||
case ReferenceKind.MANY_TO_ONE:
|
||||
this.addManyToOne(name, options.type, options);
|
||||
break;
|
||||
case ReferenceKind.MANY_TO_MANY:
|
||||
this.addManyToMany(name, options.type, options);
|
||||
break;
|
||||
case ReferenceKind.EMBEDDED:
|
||||
this.addEmbedded(name, options);
|
||||
break;
|
||||
default:
|
||||
if (options.enum) {
|
||||
this.addEnum(name, options.type, options);
|
||||
} else if (options.primary) {
|
||||
this.addPrimaryKey(name, options.type, options);
|
||||
} else if (options.serializedPrimaryKey) {
|
||||
this.addSerializedPrimaryKey(name, options.type, options);
|
||||
} else if (options.version) {
|
||||
this.addVersion(name, options.type, options);
|
||||
} else {
|
||||
this.addProperty(name, options.type, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
initPrimaryKeys() {
|
||||
const pks = Object.values(this._meta.properties).filter(prop => prop.primary);
|
||||
if (pks.length > 0) {
|
||||
this._meta.primaryKeys = pks.map(prop => prop.name);
|
||||
this._meta.compositePK = pks.length > 1;
|
||||
this._meta.simplePK = !this._meta.compositePK && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType;
|
||||
}
|
||||
if (pks.length === 1 && ['number', 'bigint'].includes(pks[0].type)) {
|
||||
pks[0].autoincrement ??= true;
|
||||
}
|
||||
const serializedPrimaryKey = Object.values(this._meta.properties).find(prop => prop.serializedPrimaryKey);
|
||||
if (serializedPrimaryKey) {
|
||||
this._meta.serializedPrimaryKey = serializedPrimaryKey.name;
|
||||
}
|
||||
}
|
||||
normalizeType(options, type) {
|
||||
if ('entity' in options) {
|
||||
/* v8 ignore next */
|
||||
if (typeof options.entity === 'string') {
|
||||
throw new Error(
|
||||
`Relation target needs to be an entity class or EntitySchema instance, string '${options.entity}' given instead for ${this._meta.className}.${options.name}.`,
|
||||
);
|
||||
} else if (options.entity) {
|
||||
const tmp = options.entity();
|
||||
type = options.type = Array.isArray(tmp)
|
||||
? tmp
|
||||
.map(t => Utils.className(t))
|
||||
.sort()
|
||||
.join(' | ')
|
||||
: Utils.className(tmp);
|
||||
const target = EntitySchema.is(tmp) ? tmp.meta.class : tmp;
|
||||
return { type, target };
|
||||
}
|
||||
}
|
||||
if (type instanceof Function) {
|
||||
type = type.name;
|
||||
}
|
||||
if (['String', 'Number', 'Boolean', 'Array'].includes(type)) {
|
||||
type = type.toLowerCase();
|
||||
}
|
||||
return { type };
|
||||
}
|
||||
createProperty(kind, options) {
|
||||
return {
|
||||
kind,
|
||||
cascade: [Cascade.PERSIST],
|
||||
...options,
|
||||
};
|
||||
}
|
||||
rename(data, from, to) {
|
||||
if (from in data && !(to in data)) {
|
||||
// @ts-ignore
|
||||
data[to] = [data[from]];
|
||||
// @ts-ignore
|
||||
delete data[from];
|
||||
}
|
||||
}
|
||||
renameCompositeOptions(name, options = {}) {
|
||||
if (name !== options.name && !options.fieldNames) {
|
||||
Utils.renameKey(options, 'name', 'fieldName');
|
||||
} else if (options.name && (options.fieldNames?.length ?? 0) > 1) {
|
||||
delete options.name;
|
||||
}
|
||||
this.rename(options, 'fieldName', 'fieldNames');
|
||||
this.rename(options, 'joinColumn', 'joinColumns');
|
||||
this.rename(options, 'inverseJoinColumn', 'inverseJoinColumns');
|
||||
this.rename(options, 'referenceColumnName', 'referencedColumnNames');
|
||||
this.rename(options, 'columnType', 'columnTypes');
|
||||
}
|
||||
/**
|
||||
* Adds a lifecycle hook handler to the entity schema.
|
||||
* This method allows registering hooks after the entity is defined,
|
||||
* which can be useful for avoiding circular type references.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* export const Article = defineEntity({
|
||||
* name: 'Article',
|
||||
* properties: { ... },
|
||||
* });
|
||||
*
|
||||
* Article.addHook('beforeCreate', async args => {
|
||||
* args.entity.slug = args.entity.title.toLowerCase();
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
addHook(event, handler) {
|
||||
this._meta.hooks[event] ??= [];
|
||||
this._meta.hooks[event].push(handler);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
122
node_modules/@mikro-orm/core/metadata/MetadataDiscovery.d.ts
generated
vendored
Normal file
122
node_modules/@mikro-orm/core/metadata/MetadataDiscovery.d.ts
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
import { type EntityClass, EntityMetadata, type EntityName } from '../typings.js';
|
||||
import type { Configuration } from '../utils/Configuration.js';
|
||||
import { MetadataStorage } from './MetadataStorage.js';
|
||||
import { EntitySchema } from './EntitySchema.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
/** Discovers, validates, and processes entity metadata from configured sources. */
|
||||
export declare class MetadataDiscovery {
|
||||
#private;
|
||||
constructor(metadata: MetadataStorage, platform: Platform, config: Configuration);
|
||||
/** Discovers all entities asynchronously and returns the populated MetadataStorage. */
|
||||
discover(preferTs?: boolean): Promise<MetadataStorage>;
|
||||
/** Discovers all entities synchronously and returns the populated MetadataStorage. */
|
||||
discoverSync(): MetadataStorage;
|
||||
private mapDiscoveredEntities;
|
||||
private initAccessors;
|
||||
/** Processes discovered entities: initializes relations, embeddables, indexes, and inheritance. */
|
||||
processDiscoveredEntities(discovered: EntityMetadata[]): EntityMetadata[];
|
||||
private findEntities;
|
||||
private discoverMissingTargets;
|
||||
private tryDiscoverTargets;
|
||||
discoverReferences<T>(refs: Iterable<EntityClass<T> | EntitySchema<T>>, validate?: boolean): EntityMetadata<T>[];
|
||||
reset<T>(entityName: EntityName<T>): void;
|
||||
private getSchema;
|
||||
private getRootEntity;
|
||||
private discoverEntity;
|
||||
private initNullability;
|
||||
private applyNamingStrategy;
|
||||
private initOwnColumns;
|
||||
private initFieldName;
|
||||
private initManyToOneFieldName;
|
||||
private initManyToManyFieldName;
|
||||
private initManyToManyFields;
|
||||
private isExplicitTableName;
|
||||
private initManyToOneFields;
|
||||
private initOneToManyFields;
|
||||
private processEntity;
|
||||
private findReferencingProperties;
|
||||
private initFactoryField;
|
||||
private ensureCorrectFKOrderInPivotEntity;
|
||||
private definePivotTableEntity;
|
||||
/**
|
||||
* Create a scalar property for a pivot table column.
|
||||
*/
|
||||
private createPivotScalarProperty;
|
||||
/**
|
||||
* Get column types for an entity's primary keys, initializing them if needed.
|
||||
*/
|
||||
private getPrimaryKeyColumnTypes;
|
||||
/**
|
||||
* Add missing FK columns for a polymorphic entity to an existing pivot table.
|
||||
*/
|
||||
private addPolymorphicPivotColumns;
|
||||
/**
|
||||
* Define properties for a polymorphic pivot table.
|
||||
*/
|
||||
private definePolymorphicPivotProperties;
|
||||
/**
|
||||
* Create a virtual M:1 relation from pivot to a polymorphic owner entity.
|
||||
* This enables single-query join loading for inverse-side polymorphic M:N.
|
||||
*/
|
||||
private definePolymorphicOwnerRelation;
|
||||
private defineFixedOrderProperty;
|
||||
private definePivotProperty;
|
||||
private autoWireBidirectionalProperties;
|
||||
private defineBaseEntityProperties;
|
||||
private initPolyEmbeddables;
|
||||
private initPolymorphicRelation;
|
||||
private initEmbeddables;
|
||||
private initSingleTableInheritance;
|
||||
/**
|
||||
* First pass of TPT initialization: sets up hierarchy relationships
|
||||
* (inheritanceType, tptParent, tptChildren) before properties have fieldNames.
|
||||
*/
|
||||
private initTPTRelationships;
|
||||
/**
|
||||
* Second pass of TPT initialization: re-resolves metadata references after fieldNames
|
||||
* are set, syncs to registry metadata, and sets up discriminators.
|
||||
*/
|
||||
private finalizeTPTInheritance;
|
||||
/**
|
||||
* Initialize TPT discriminator map and virtual discriminator property.
|
||||
* Unlike STI where the discriminator is a persisted column, TPT discriminator is computed
|
||||
* at query time using CASE WHEN expressions based on which child table has data.
|
||||
*/
|
||||
private initTPTDiscriminator;
|
||||
/**
|
||||
* Recursively collect all TPT descendants (children, grandchildren, etc.)
|
||||
*/
|
||||
private collectAllTPTDescendants;
|
||||
/**
|
||||
* Computes ownProps for TPT entities - only properties defined in THIS entity,
|
||||
* not inherited from parent. Also creates synthetic join properties for parent/child relationships.
|
||||
*
|
||||
* Called multiple times during discovery as metadata is progressively built.
|
||||
* Each pass overwrites earlier results to reflect the final state of properties.
|
||||
*/
|
||||
private computeTPTOwnProps;
|
||||
/** Returns the depth of a TPT entity in its hierarchy (0 for root). */
|
||||
private getTPTDepth;
|
||||
/**
|
||||
* Find the direct TPT parent entity for the given entity.
|
||||
*/
|
||||
private getTPTParent;
|
||||
private createDiscriminatorProperty;
|
||||
private initAutoincrement;
|
||||
private createSchemaTable;
|
||||
private initCheckConstraints;
|
||||
private initGeneratedColumn;
|
||||
private getDefaultVersionValue;
|
||||
private inferDefaultValue;
|
||||
private initDefaultValue;
|
||||
private inferTypeFromDefault;
|
||||
private initVersionProperty;
|
||||
private initCustomType;
|
||||
private initRelation;
|
||||
private initColumnType;
|
||||
private getMappedType;
|
||||
private getPrefix;
|
||||
private initUnsigned;
|
||||
private initIndexes;
|
||||
private shouldForceConstructorUsage;
|
||||
}
|
||||
1973
node_modules/@mikro-orm/core/metadata/MetadataDiscovery.js
generated
vendored
Normal file
1973
node_modules/@mikro-orm/core/metadata/MetadataDiscovery.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
33
node_modules/@mikro-orm/core/metadata/MetadataProvider.d.ts
generated
vendored
Normal file
33
node_modules/@mikro-orm/core/metadata/MetadataProvider.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { EntityMetadata } from '../typings.js';
|
||||
import type { Logger } from '../logging/Logger.js';
|
||||
import type { SyncCacheAdapter } from '../cache/CacheAdapter.js';
|
||||
import type { Platform } from '../platforms/Platform.js';
|
||||
export interface IConfiguration {
|
||||
get(key: string, defaultValue?: any): any;
|
||||
getLogger(): Logger;
|
||||
getMetadataCacheAdapter(): SyncCacheAdapter;
|
||||
getPlatform(): Platform;
|
||||
}
|
||||
/** Base metadata provider that resolves entity type information and manages metadata caching. */
|
||||
export declare class MetadataProvider {
|
||||
protected readonly config: IConfiguration;
|
||||
constructor(config: IConfiguration);
|
||||
/** Resolves entity references and type information for all properties in the given metadata. */
|
||||
loadEntityMetadata(meta: EntityMetadata): void;
|
||||
/** Merges cached metadata into the given entity metadata, preserving function expressions. */
|
||||
loadFromCache(meta: EntityMetadata, cache: EntityMetadata): void;
|
||||
/** Whether this provider class uses metadata caching by default. */
|
||||
static useCache(): boolean;
|
||||
/** Whether metadata caching is enabled for this instance. */
|
||||
useCache(): boolean;
|
||||
saveToCache(meta: EntityMetadata): void;
|
||||
/** Attempts to load metadata from cache, returning undefined if not available. */
|
||||
getCachedMetadata<T>(
|
||||
meta: Pick<EntityMetadata<T>, 'className' | 'path' | 'root'>,
|
||||
root: EntityMetadata<T>,
|
||||
): EntityMetadata<T> | undefined;
|
||||
/** Combines individual metadata cache entries into a single file. */
|
||||
combineCache(): void;
|
||||
/** Returns the cache key for the given entity metadata. */
|
||||
getCacheKey(meta: Pick<EntityMetadata, 'className' | 'path'>): string;
|
||||
}
|
||||
95
node_modules/@mikro-orm/core/metadata/MetadataProvider.js
generated
vendored
Normal file
95
node_modules/@mikro-orm/core/metadata/MetadataProvider.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Utils } from '../utils/Utils.js';
|
||||
import { EntitySchema } from './EntitySchema.js';
|
||||
/** Base metadata provider that resolves entity type information and manages metadata caching. */
|
||||
export class MetadataProvider {
|
||||
config;
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
/** Resolves entity references and type information for all properties in the given metadata. */
|
||||
loadEntityMetadata(meta) {
|
||||
for (const prop of meta.props) {
|
||||
/* v8 ignore next */
|
||||
if (typeof prop.entity === 'string') {
|
||||
prop.type = prop.entity;
|
||||
} else if (prop.entity) {
|
||||
const tmp = prop.entity();
|
||||
prop.type = Array.isArray(tmp)
|
||||
? tmp
|
||||
.map(t => Utils.className(t))
|
||||
.sort()
|
||||
.join(' | ')
|
||||
: Utils.className(tmp);
|
||||
prop.target = EntitySchema.is(tmp) ? tmp.meta.class : tmp;
|
||||
} else if (!prop.type && !((prop.enum || prop.array) && (prop.items?.length ?? 0) > 0)) {
|
||||
throw new Error(`Please provide either 'type' or 'entity' attribute in ${meta.className}.${prop.name}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Merges cached metadata into the given entity metadata, preserving function expressions. */
|
||||
loadFromCache(meta, cache) {
|
||||
Object.values(cache.properties).forEach(prop => {
|
||||
const metaProp = meta.properties[prop.name];
|
||||
/* v8 ignore next */
|
||||
if (metaProp?.enum && Array.isArray(metaProp.items)) {
|
||||
delete prop.items;
|
||||
}
|
||||
});
|
||||
// Preserve function expressions from indexes/uniques — they can't survive JSON cache serialization
|
||||
const expressionMap = new Map();
|
||||
for (const arr of [meta.indexes, meta.uniques]) {
|
||||
for (const idx of arr ?? []) {
|
||||
if (typeof idx.expression === 'function' && idx.name) {
|
||||
expressionMap.set(idx.name, idx.expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.mergeConfig(meta, cache);
|
||||
// Restore function expressions that were lost during JSON serialization
|
||||
if (expressionMap.size > 0) {
|
||||
for (const arr of [meta.indexes, meta.uniques]) {
|
||||
for (const idx of arr ?? []) {
|
||||
const fn = idx.name && expressionMap.get(idx.name);
|
||||
if (fn && typeof idx.expression !== 'function') {
|
||||
idx.expression = fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Whether this provider class uses metadata caching by default. */
|
||||
static useCache() {
|
||||
return false;
|
||||
}
|
||||
/** Whether metadata caching is enabled for this instance. */
|
||||
useCache() {
|
||||
return this.config.get('metadataCache').enabled ?? MetadataProvider.useCache();
|
||||
}
|
||||
saveToCache(meta) {
|
||||
//
|
||||
}
|
||||
/** Attempts to load metadata from cache, returning undefined if not available. */
|
||||
getCachedMetadata(meta, root) {
|
||||
if (!this.useCache()) {
|
||||
return undefined;
|
||||
}
|
||||
const cache = meta.path && this.config.getMetadataCacheAdapter().get(this.getCacheKey(meta));
|
||||
if (cache) {
|
||||
this.loadFromCache(meta, cache);
|
||||
meta.root = root;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
/** Combines individual metadata cache entries into a single file. */
|
||||
combineCache() {
|
||||
const path = this.config.getMetadataCacheAdapter().combine?.();
|
||||
// override the path in the options, so we can log it from the CLI in `cache:generate` command
|
||||
if (path) {
|
||||
this.config.get('metadataCache').combined = path;
|
||||
}
|
||||
}
|
||||
/** Returns the cache key for the given entity metadata. */
|
||||
getCacheKey(meta) {
|
||||
return meta.className;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user