import type { AnyEntity, EntityData, EntityMetadata, EntityName, EntityProperty, FilterQuery, Primary } from '../typings.js'; import { Collection } from '../entity/Collection.js'; import { Reference } from '../entity/Reference.js'; import { ChangeSet, ChangeSetType } from './ChangeSet.js'; import { ChangeSetPersister } from './ChangeSetPersister.js'; import type { EntityManager } from '../EntityManager.js'; import { IdentityMap } from './IdentityMap.js'; import type { LockOptions } from '../drivers/IDatabaseDriver.js'; /** Implements the Unit of Work pattern: tracks entity changes, computes change sets, and flushes them to the database. */ export declare class UnitOfWork { #private; constructor(em: EntityManager); /** Merges an entity into the identity map, taking a snapshot of its current state. */ merge(entity: T, visited?: Set): void; /** * Entity data can wary in its shape, e.g. we might get a deep relation graph with joined strategy, but for diffing, * we need to normalize the shape, so relation values are only raw FKs. This method handles that. * @internal */ normalizeEntityData(meta: EntityMetadata, data: EntityData): void; /** * @internal */ register(entity: T, data?: EntityData, options?: RegisterOptions): T; /** * @internal */ dispatchOnLoadEvent(): Promise; /** * @internal */ unmarkAsLoaded(entity: AnyEntity): void; /** * Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`. */ getById(entityName: EntityName, id: Primary | Primary[], schema?: string, convertCustomTypes?: boolean): T | undefined; /** * Returns entity from the identity map by an alternate key (non-PK property). * @param convertCustomTypes - If true, the value is in database format and will be converted to JS format for lookup. * If false (default), the value is assumed to be in JS format already. */ getByKey(entityName: EntityName, key: string, value: unknown, schema?: string, convertCustomTypes?: boolean): T | undefined; /** * Stores an entity in the identity map under an alternate key (non-PK property). * Also sets the property value on the entity. * @param convertCustomTypes - If true, the value is in database format and will be converted to JS format. * If false (default), the value is assumed to be in JS format already. */ storeByKey(entity: T, key: string, value: unknown, schema?: string, convertCustomTypes?: boolean): void; /** Attempts to extract a primary key from the where condition and look up the entity in the identity map. */ tryGetById(entityName: EntityName, where: FilterQuery, schema?: string, strict?: boolean): T | null; /** * Returns map of all managed entities. */ getIdentityMap(): IdentityMap; /** * Returns stored snapshot of entity state that is used for change set computation. */ getOriginalEntityData(entity: T): EntityData | undefined; /** Returns the set of entities scheduled for persistence. */ getPersistStack(): Set; /** Returns the set of entities scheduled for removal. */ getRemoveStack(): Set; /** Returns all computed change sets for the current flush. */ getChangeSets(): ChangeSet[]; /** Returns all M:N collections that need synchronization. */ getCollectionUpdates(): Collection[]; /** Returns extra updates needed for relations that could not be resolved in the initial pass. */ getExtraUpdates(): Set<[ AnyEntity, string | string[], AnyEntity | AnyEntity[] | Reference | Collection, ChangeSet | undefined, ChangeSetType ]>; /** Checks whether an auto-flush is needed before querying the given entity type. */ shouldAutoFlush(meta: EntityMetadata): boolean; /** Clears the queue of entity types that triggered auto-flush detection. */ clearActionsQueue(): void; /** Computes and registers a change set for the given entity. */ computeChangeSet(entity: T, type?: ChangeSetType): void; /** Recomputes and merges the change set for an already-tracked entity. */ recomputeSingleChangeSet(entity: T): void; /** Marks an entity for persistence, cascading to related entities. */ persist(entity: T, visited?: Set, options?: { checkRemoveStack?: boolean; cascade?: boolean; }): void; /** Marks an entity for removal, cascading to related entities. */ remove(entity: T, visited?: Set, options?: { cascade?: boolean; }): void; /** Flushes all pending changes to the database within a transaction. */ commit(): Promise; private doCommit; lock(entity: T, options: LockOptions): Promise; clear(): void; unsetIdentity(entity: AnyEntity): void; computeChangeSets(): void; scheduleExtraUpdate(changeSet: ChangeSet, props: EntityProperty[]): void; scheduleOrphanRemoval(entity?: AnyEntity, visited?: Set): void; cancelOrphanRemoval(entity: AnyEntity, visited?: Set): void; getOrphanRemoveStack(): Set; getChangeSetPersister(): ChangeSetPersister; private findNewEntities; /** * For TPT inheritance, creates separate changesets for each table in the hierarchy. * Uses the same entity instance for all changesets - only the metadata and payload differ. */ private createTPTChangeSets; /** * Returns `true` when the change set should be skipped as it will be empty after the extra update. */ private checkUniqueProps; private expandUniqueProps; private initIdentifier; private processReference; private processToOneReference; private processToManyReference; private runHooks; private postCommitCleanup; private cascade; private cascadeReference; private isCollectionSelfReferenced; private shouldCascade; private lockPessimistic; private lockOptimistic; private fixMissingReference; private persistToDatabase; private commitCreateChangeSets; private findExtraUpdates; private findEarlyUpdates; private commitUpdateChangeSets; private commitDeleteChangeSets; private commitExtraUpdates; private commitCollectionUpdates; private filterCollectionUpdates; /** * Orders change sets so FK constrains are maintained, ensures stable order (needed for node < 11) */ private getChangeSetGroups; private getCommitOrder; private resetTransaction; /** * Takes snapshots of all processed collections */ private takeCollectionSnapshots; } export interface RegisterOptions { refresh?: boolean; newEntity?: boolean; loaded?: boolean; }