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;
}
