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 { CountByOptions, 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, EntityKey, EntityMetadata, EntityName, FilterDef, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MergeLoaded, MergeSelected, ObjectQuery, PopulateOptions, Primary, Ref, RequiredEntityData, RoutineArgs, RoutineReturn, UnboxArray, IndexFilterQuery, WithUsingOptions } from './typings.js';
import type { Routine } from './metadata/Routine.js';
import { FlushMode, LockMode, PopulatePath, type TransactionOptions } from './enums.js';
import type { MetadataStorage } from './metadata/MetadataStorage.js';
import type { AbortQueryOptions, InflightQueryAbortStrategy, 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 */
    protected signal?: AbortSignal;
    /** @internal */
    protected inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
    /**
     * @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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, where: [Using] extends [never] ? FilterQuery<NoInfer<Entity>> : IndexFilterQuery<NoInfer<Entity>, Using>, options?: FindOptions<Entity, Hint, Fields, Excludes> & {
        using?: Using | Using[];
    }): 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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, options?: WithUsingOptions<StreamOptions<NoInfer<Entity>, Hint, Fields, Excludes>, NoInfer<Entity>, Using>): 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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, options?: WithUsingOptions<FindAllOptions<NoInfer<Entity>, Hint, Fields, Excludes>, NoInfer<Entity>, Using>): 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 = never, 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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, where: [Using] extends [never] ? FilterQuery<NoInfer<Entity>> : IndexFilterQuery<NoInfer<Entity>, Using>, options?: FindOptions<Entity, Hint, Fields, Excludes> & {
        using?: Using | Using[];
    }): 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 = never, Excludes extends string = never, IncludeCount extends boolean = true, Using extends string = never>(entityName: EntityName<Entity>, options: WithUsingOptions<FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>, Entity, Using>): 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 = never, 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 = never, 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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, where: [Using] extends [never] ? FilterQuery<NoInfer<Entity>> : IndexFilterQuery<NoInfer<Entity>, Using>, options?: FindOneOptions<Entity, Hint, Fields, Excludes> & {
        using?: Using | Using[];
    }): 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 = never, Excludes extends string = never, Using extends string = never>(entityName: EntityName<Entity>, where: [Using] extends [never] ? FilterQuery<NoInfer<Entity>> : IndexFilterQuery<NoInfer<Entity>, Using>, options?: FindOneOrFailOptions<Entity, Hint, Fields, Excludes> & {
        using?: Using | Using[];
    }): 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>>;
    /**
     * Clones rows matching the condition at the database level via INSERT...SELECT.
     * Automatically excludes auto-increment PKs, generated columns, and resets version properties.
     * Returns the cloned entity, registered in the identity map.
     *
     * @example
     * ```ts
     * // Clone by entity class + where + overrides
     * const cloned = await em.clone(Author, { id: 1 }, { email: 'new@email.com' });
     *
     * // Pure clone (all non-PK fields copied)
     * const cloned = await em.clone(Author, { id: 1 });
     *
     * // Clone a loaded entity
     * const author = await em.findOneOrFail(Author, 1);
     * const cloned = await em.clone(author, { email: 'new@email.com' });
     * ```
     */
    clone<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, whereOrOverrides?: FilterQuery<NoInfer<Entity>> | EntityData<Entity>, overridesOrOptions?: EntityData<Entity> | NativeInsertUpdateOptions<Entity>, options?: NativeInsertUpdateOptions<Entity>): Promise<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>;
    /**
     * Invokes a stored procedure or function declared via the {@link Routine} class. Arg and return
     * types are inferred from the literal config; use {@link Routine.create} to refine when needed.
     *
     * Procedures emitting result sets (MySQL `SELECT`s, PG/Oracle refcursor OUT params) return
     * `Dictionary[][]`; MSSQL multi-result procs aren't exposed here, use `em.getConnection().execute()`.
     *
     * Mongo throws. SQLite bridges `bodyJs` functions via better-sqlite3 UDFs (procedures and
     * function-without-bodyJs throw); libSQL throws unconditionally. Oracle calls run on their own
     * pool connection with `autoCommit: true`, so wrapping in `em.transactional(...)` throws.
     *
     * @example
     * ```ts
     * const hash = await em.callRoutine(HashUser, { name: 'jon', salt: 'pepper' });
     *
     * const hashRef = new ScalarReference<string>();
     * await em.callRoutine(AddRecord, { p_name: 'jon', p_age: 30, p_hash: hashRef });
     *
     * const TwoCursors = Routine.create<Record<string, never>, unknown[][]>({ ... });
     * const [users, books] = await em.transactional(em => em.callRoutine(TwoCursors, {}));
     * ```
     */
    callRoutine<R extends Routine>(routine: R, args: RoutineArgs<R>): Promise<RoutineReturn<R>>;
    /**
     * 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;
        mapped?: boolean;
    }): 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>;
    /**
     * Counts entities grouped by one or more properties. Returns a dictionary keyed by the grouped
     * field value(s), with counts as values. For composite `groupBy`, keys are joined with `~~~`.
     *
     * SQL drivers issue a single `GROUP BY` query; MongoDB uses an aggregation pipeline.
     *
     * @example
     * ```ts
     * // Count books per author
     * const counts = await em.countBy(Book, 'author');
     * // { '1': 2, '2': 1, '3': 3 }
     *
     * // Count with a filter
     * const counts = await em.countBy(Book, 'author', { where: { active: true } });
     *
     * // Composite groupBy — keys joined with ~~~
     * const counts = await em.countBy(Order, ['status', 'country']);
     * // { 'pending~~~US': 5, 'shipped~~~DE': 3 }
     * ```
     */
    countBy<Entity extends object>(entityName: EntityName<Entity>, groupBy: EntityKey<Entity> | readonly EntityKey<Entity>[], options?: CountByOptions<Entity>): Promise<Dictionary<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;
    /**
     * Returns the cancellation defaults configured on this EntityManager (via `em.fork({ signal })`
     * or inherited from a transactional fork). Returns `undefined` when no signal is set.
     *
     * @internal — exposed for subclass drivers and `UnitOfWork`; not part of the public API.
     */
    protected getAbortOptions(): AbortQueryOptions | 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 validateIndexUsage;
    private validateWhereKeysForIndex;
    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>[]>;
    /** Force SELECT_IN strategy on populate entries with `limit`, since JOINED cannot do per-parent limiting. */
    private forceSelectInForLimitedPopulate;
    /**
     * 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 = never, 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> | CountByOptions<any>) & AbortQueryOptions): 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' | 'count'): 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;
    /**
     * Default `AbortSignal` applied to every operation on this fork (queries and UoW flushes).
     * Per-call options.signal still takes precedence.
     */
    signal?: AbortSignal;
    /** Default cancellation strategy paired with {@link signal}. */
    inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
}
