import type { AnyEntity, AutoPath, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateHintOptions, PopulateOptions } from '../typings.js';
import type { EntityManager } from '../EntityManager.js';
import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
import type { InflightQueryAbortStrategy } from '../connections/Connection.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 = never, 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;
    /** Per-relation populate overrides (limit, offset, orderBy). */
    populateHints?: Record<string, PopulateHintOptions>;
    /** AbortSignal forwarded to populated relation queries. */
    signal?: AbortSignal;
    /** Cancellation strategy paired with {@link signal}. */
    inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
}
/** 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 = never>(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;
}
