UNPKG

@itwin/core-backend

Version:
545 lines • 26.2 kB
/** @packageDocumentation * @module iModels */ import { BeEvent, DbConflictResolution, DbResult, Id64String, IModelStatus } from "@itwin/core-bentley"; import { ChangesetIndexAndId, EntityIdAndClassIdIterable, ModelGeometryChangesProps, ModelIdAndGeometryGuid } from "@itwin/core-common"; import { BriefcaseDb, SaveChangesArgs, StandaloneDb } from "./IModelDb"; import { RelationshipProps } from "./Relationship"; import { DbRebaseChangesetConflictArgs, RebaseChangesetConflictArgs } from "./internal/ChangesetConflictArgs"; /** A string that identifies a Txn. * @public @preview */ export type TxnIdString = string; /** An error generated during dependency validation. * @see [[TxnManager.validationErrors]]. * @public @preview */ export interface ValidationError { /** If true, txn is aborted. */ fatal: boolean; /** The type of error. */ errorType: string; /** Optional description of what went wrong. */ message?: string; } /** Describes a set of [[Element]]s or [[Model]]s that changed as part of a transaction. * @see [[TxnManager.onElementsChanged]] and [[TxnManager.onModelsChanged]]. * @public @preview */ export interface TxnChangedEntities { /** The entities that were inserted by the transaction. */ readonly inserts: EntityIdAndClassIdIterable; /** The entities that were deleted by the transaction. */ readonly deletes: EntityIdAndClassIdIterable; /** The entities that were modified by the transaction, including any [[Element]]s for which one of their [[ElementAspect]]s was changed. */ readonly updates: EntityIdAndClassIdIterable; } /** Arguments supplied to [[TxnManager.queryLocalChanges]]. * @beta */ export interface QueryLocalChangesArgs { /** If supplied and non-empty, restricts the results to include only EC instances belonging to the specified classes or subclasses thereof. */ readonly includedClasses?: string[]; /** If `true`, include changes that have not yet been saved. */ readonly includeUnsavedChanges?: boolean; } /** Represents a change (insertion, deletion, or modification) to a single EC instance made in a local [[BriefcaseDb]]. * @see [[TxnManager.queryLocalChanges]] to iterate all of the changed instances. * @beta */ export interface ChangeInstanceKey { /** ECInstanceId of the instance. */ id: Id64String; /** Fully-qualified class name of the instance. */ classFullName: string; /** The type of change. */ changeType: "inserted" | "updated" | "deleted"; } /** Strictly for tests. @internal */ export declare function setMaxEntitiesPerEvent(max: number): number; /** * @alpha * Transaction types */ export type TxnType = "Data" | "ECSchema" | "Ddl"; /** * @alpha * Transaction modes */ export type TxnMode = "direct" | "indirect"; /** * @alpha * Represents the properties of a transaction within the transaction manager. * * @property id - The unique identifier for the transaction. * @property sessionId - The identifier of the session to which the transaction belongs. * @property nextId - (Optional) The identifier of the next transaction in the sequence. * @property prevId - (Optional) The identifier of the previous transaction in the sequence. * @property props - The arguments or properties associated with the save changes operation. * @property type - The type of transaction, which can be "Data", "ECSchema", or "Ddl". * @property reversed - Indicates whether the transaction has been reversed. * @property grouped - Indicates whether the transaction is grouped with others. * @property timestamp - The timestamp when the transaction was created. */ export interface TxnProps { id: TxnIdString; sessionId: number; nextId?: TxnIdString; prevId?: TxnIdString; props: SaveChangesArgs; type: TxnType; reversed: boolean; grouped: boolean; timestamp: string; } /** * Manages the process of merging and rebasing local changes (transactions) in a [[BriefcaseDb]] or [[StandaloneDb]]. * * The `RebaseManager` coordinates the rebase of local transactions when pulling and merging changes from other sources, * such as remote repositories or other users. It provides mechanisms to handle transaction conflicts, register custom conflict * handlers, and manage the rebase workflow. This includes resuming rebases, invoking user-defined handlers for conflict resolution, * and tracking the current merge/rebase state. * * Key responsibilities: * - Orchestrates the rebase of local transactions after a pull/merge operation. * - Allows registration and removal of custom conflict handlers to resolve changeset conflicts during rebase. * - Provides methods to check the current merge/rebase state. * - Raises events before and after each transaction is rebased. * - Ensures changes are saved or aborted appropriately based on the outcome of the rebase process. * * @alpha */ export declare class RebaseManager { private _iModel; private _conflictHandlers?; private _customHandler?; private _aborting; constructor(_iModel: BriefcaseDb | StandaloneDb); /** * Resumes the rebase process for the current iModel, applying any pending local changes * on top of the latest pulled changes from the remote source. * * This method performs the following steps: * 1. Begins the rebase process using the native database. * 2. Iterates through each transaction that needs to be rebased: * - Retrieves transaction properties. * - Raises events before and after rebasing each transaction. * - Optionally reinstates local changes based on the rebase handler. * - Optionally recomputes transaction data using the rebase handler. * - Updates the transaction in the native database. * 3. Ends the rebase process and saves changes if the database is not read-only. * 4. Drops any restore point associated with the pull-merge operation. * * If an error occurs during the process, the rebase is aborted and the error is rethrown. * * @throws {Error} If a transaction cannot be found or if any step in the rebase process fails. */ resume(): Promise<void>; /** * Determines whether the current transaction can be aborted. * * This method checks if a transaction is currently in progress and if a specific restore point, * identified by `BriefcaseManager.PULL_MERGE_RESTORE_POINT_NAME`, exists in the briefcase manager. * * @returns {boolean} Returns `true` if a transaction is in progress and the required restore point exists; otherwise, returns `false`. */ canAbort(): boolean; /** * Aborts the current transaction by restoring the iModel to a predefined restore point. This method will * automatically discard any unsaved changes before performing the restore. * * If a restore point is available (as determined by `canAbort()`), this method restores the iModel * to the state saved at the restore point named by `BriefcaseManager.PULL_MERGE_RESTORE_POINT_NAME`. * If no restore point is available, an error is thrown. * * @returns A promise that resolves when the restore operation is complete. * @throws {Error} If there is no restore point to abort to. */ abort(): Promise<void>; /** * Sets the handler to be invoked for rebase operations. * * @param handler - The {@link RebaseHandler} to handle rebase events. */ setCustomHandler(handler: RebaseHandler): void; /** * Determines whether a transaction is currently in progress. * * @returns {boolean} Returns `true` if there is an active transaction stage, otherwise `false`. */ inProgress(): boolean; /** * Indicates whether the current transaction manager is in the process of aborting a transaction. * * @returns `true` if the transaction manager is currently aborting; otherwise, `false`. */ get isAborting(): boolean; /** * Indicates whether the current transaction manager is in the "Rebasing" stage. * * This property checks the internal native database's merge stage to determine if a rebase operation is in progress. * * @returns `true` if the transaction manager is currently rebasing; otherwise, `false`. */ get isRebasing(): boolean; /** * Indicates whether the current iModel is in the process of merging changes from a pull operation. * * @returns `true` if the iModel is currently merging changes; otherwise, `false`. */ get isMerging(): boolean; /** * Attempts to resolve a changeset conflict by invoking registered conflict handlers in sequence. * * Iterates through the linked list of conflict handlers, passing the provided conflict arguments to each handler. * If a handler returns a defined resolution, logs the resolution and returns it immediately. * If no handler resolves the conflict, returns `undefined`. * * @param args - The arguments describing the changeset conflict to resolve. * @returns The conflict resolution provided by a handler, or `undefined` if no handler resolves the conflict. */ onConflict(args: RebaseChangesetConflictArgs): DbConflictResolution | undefined; /** * Registers a new conflict handler for rebase changeset conflicts. * * @param args - An object containing: * - `id`: A unique identifier for the conflict handler. * - `handler`: A function that handles rebase changeset conflicts and returns a `DbConflictResolution` or `undefined`. * @throws IModelError if a conflict handler with the same `id` already exists. * * @remarks * Conflict handlers are used during changeset rebase operations to resolve conflicts. * Each handler must have a unique `id`. Attempting to register a handler with a duplicate `id` will result in an error. */ addConflictHandler(args: { id: string; handler: (args: RebaseChangesetConflictArgs) => DbConflictResolution | undefined; }): void; /** * Removes a conflict handler from the internal linked list by its identifier. * * @param id - The unique identifier of the conflict handler to remove. * * If the handler with the specified `id` exists in the list, it will be removed. * If no handler with the given `id` is found, the method does nothing. */ removeConflictHandler(id: string): void; } /** Manages local changes to a [[BriefcaseDb]] or [[StandaloneDb]] via [Txns]($docs/learning/InteractiveEditing.md) * @public @preview */ export declare class TxnManager { private _iModel; /** @internal */ private _isDisposed; /** @internal */ private _withIndirectChangeRefCounter; /** @internal */ get isDisposed(): boolean; /** @internal */ readonly rebaser: RebaseManager; /** @internal */ constructor(_iModel: BriefcaseDb | StandaloneDb); /** Array of errors from dependency propagation */ readonly validationErrors: ValidationError[]; private get _nativeDb(); private _getElementClass; private _getRelationshipClass; /** If a -watch file exists for this iModel, update its timestamp so watching processes can be * notified that we've modified the briefcase. * @internal Used by IModelDb on push/pull. */ touchWatchFile(): void; /** @internal */ protected _onBeforeOutputsHandled(elClassName: string, elId: Id64String): void; /** @internal */ protected _onAllInputsHandled(elClassName: string, elId: Id64String): void; /** @internal */ protected _onRootChanged(props: RelationshipProps): void; /** @internal */ protected _onDeletedDependency(props: RelationshipProps): void; /** @internal */ protected _onBeginValidate(): void; /** called from native code after validation of a Txn, either from saveChanges or apply changeset. * @internal */ protected _onEndValidate(): void; /** @internal */ protected _onGeometryChanged(modelProps: ModelGeometryChangesProps[]): void; /** @internal */ protected _onGeometryGuidsChanged(changes: ModelIdAndGeometryGuid[]): void; /** @internal */ protected _onCommit(): void; /** @internal */ protected _onCommitted(): void; /** @internal */ protected _onReplayExternalTxns(): void; /** @internal */ protected _onReplayedExternalTxns(): void; /** @internal */ protected _onChangesApplied(): void; /** @internal */ protected _onBeforeUndoRedo(isUndo: boolean): void; /** @internal */ protected _onAfterUndoRedo(isUndo: boolean): void; /** @internal */ _onChangesPushed(changeset: ChangesetIndexAndId): void; /** @internal */ _onChangesPulled(changeset: ChangesetIndexAndId): void; private _onRebaseLocalTxnConflict; /** * @alpha * Retrieves the txn properties for a given txn ID. * * @param id - The unique identifier of the transaction. * @returns The properties of the transaction if found; otherwise, `undefined`. */ getTxnProps(id: TxnIdString): TxnProps | undefined; /** * @alpha * Iterates over all transactions in the sequence, yielding each transaction's properties. * * @yields {TxnProps} The properties of each transaction in the sequence. */ queryTxns(): Generator<TxnProps>; /** * @alpha * Retrieves the properties of the last saved txn via `IModelDb.saveChanges()`, if available. * * @returns The properties of the last saved txn, or `undefined` if none exist. */ getLastSavedTxnProps(): TxnProps | undefined; /** Dependency handlers may call method this to report a validation error. * @param error The error. If error.fatal === true, the transaction will cancel rather than commit. */ reportError(error: ValidationError): void; /** Determine whether any fatal validation errors have occurred during dependency propagation. */ get hasFatalError(): boolean; /** @internal */ readonly onEndValidation: BeEvent<() => void>; /** Called after validation completes from [[IModelDb.saveChanges]]. * The argument to the event holds the list of elements that were inserted, updated, and deleted. * @note If there are many changed elements in a single Txn, the notifications are sent in batches so this event *may be called multiple times* per Txn. */ readonly onElementsChanged: BeEvent<(changes: TxnChangedEntities) => void>; /** Called after validation completes from [[IModelDb.saveChanges]]. * The argument to the event holds the list of models that were inserted, updated, and deleted. * @note If there are many changed models in a single Txn, the notifications are sent in batches so this event *may be called multiple times* per Txn. */ readonly onModelsChanged: BeEvent<(changes: TxnChangedEntities) => void>; /** Event raised after the geometry within one or more [[GeometricModel]]s is modified by applying a changeset or validation of a transaction. * A model's geometry can change as a result of: * - Insertion or deletion of a geometric element within the model; or * - Modification of an existing element's geometric properties; or * - An explicit request to flag it as changed via [[IModelDb.Models.updateModel]]. */ readonly onModelGeometryChanged: BeEvent<(changes: ReadonlyArray<ModelIdAndGeometryGuid>) => void>; readonly onGeometryChanged: BeEvent<(models: ModelGeometryChangesProps[]) => void>; /** Event raised before a commit operation is performed. Initiated by a call to [[IModelDb.saveChanges]], unless there are no changes to save. */ readonly onCommit: BeEvent<() => void>; /** Event raised after a commit operation has been performed. Initiated by a call to [[IModelDb.saveChanges]], even if there were no changes to save. */ readonly onCommitted: BeEvent<() => void>; /** Event raised after a ChangeSet has been applied to this briefcase */ readonly onChangesApplied: BeEvent<() => void>; /** Event raised before an undo/redo operation is performed. */ readonly onBeforeUndoRedo: BeEvent<(isUndo: boolean) => void>; /** Event raised after an undo/redo operation has been performed. * @param _action The action that was performed. */ readonly onAfterUndoRedo: BeEvent<(isUndo: boolean) => void>; /** Event raised for a read-only briefcase that was opened with the `watchForChanges` flag enabled when changes made by another connection are applied to the briefcase. * @see [[onReplayedExternalTxns]] for the event raised after all such changes have been applied. */ readonly onReplayExternalTxns: BeEvent<() => void>; /** Event raised for a read-only briefcase that was opened with the `watchForChanges` flag enabled when changes made by another connection are applied to the briefcase. * @see [[onReplayExternalTxns]] for the event raised before the changes are applied. */ readonly onReplayedExternalTxns: BeEvent<() => void>; /** * @alpha * Event raised when a rebase transaction begins. */ readonly onRebaseTxnBegin: BeEvent<(txn: TxnProps) => void>; /** * @alpha * Event raised when a rebase transaction ends. */ readonly onRebaseTxnEnd: BeEvent<(txn: TxnProps) => void>; /** * @alpha * Event raised when a rebase begins. */ readonly onRebaseBegin: BeEvent<(txns: TxnIdString[]) => void>; /** * @alpha * Event raised when a rebase ends. */ readonly onRebaseEnd: BeEvent<() => void>; /** Event raised after changes are pulled from iModelHub. * @see [[BriefcaseDb.pullChanges]]. */ readonly onChangesPulled: BeEvent<(parentChangeset: ChangesetIndexAndId) => void>; /** Event raised after changes are pushed to iModelHub. * @see [[BriefcaseDb.pushChanges]]. */ readonly onChangesPushed: BeEvent<(parentChangeset: ChangesetIndexAndId) => void>; /** * if handler is set and it does not return undefined then default handler will not be called * @internal * */ appCustomConflictHandler?: (args: DbRebaseChangesetConflictArgs) => DbConflictResolution | undefined; /** * Restart the current TxnManager session. This causes all Txns in the current session to no longer be undoable (as if the file was closed * and reopened.) * @note This can be quite disconcerting to the user expecting to be able to undo previously made changes. It should only be used * under extreme circumstances where damage to the file or session could happen if the currently committed are reversed. Use sparingly and with care. * Probably a good idea to alert the user it happened. */ restartSession(): void; /** Determine whether current txn is propagating indirect changes or not. */ get isIndirectChanges(): boolean; /** Determine if there are currently any reversible (undoable) changes from this editing session. */ get isUndoPossible(): boolean; /** Determine if there are currently any reinstatable (redoable) changes */ get isRedoPossible(): boolean; /** Get the description of the operation that would be reversed by calling reverseTxns(1). * This is useful for showing the operation that would be undone, for example in a menu. */ getUndoString(): string; /** Get a description of the operation that would be reinstated by calling reinstateTxn. * This is useful for showing the operation that would be redone, in a pull-down menu for example. */ getRedoString(): string; /** Begin a new multi-Txn operation. This can be used to cause a series of Txns that would normally * be considered separate actions for undo to be grouped into a single undoable operation. This means that when reverseTxns(1) is called, * the entire group of changes are undone together. Multi-Txn operations can be nested and until the outermost operation is closed * all changes constitute a single operation. * @note This method must always be paired with a call to endMultiTxnAction. */ beginMultiTxnOperation(): DbResult; /** End a multi-Txn operation */ endMultiTxnOperation(): DbResult; /** Return the depth of the multi-Txn stack. Generally for diagnostic use only. */ getMultiTxnOperationDepth(): number; /** Reverse (undo) the most recent operation(s) to this IModelDb. * @param numOperations the number of operations to reverse. If this is greater than 1, the entire set of operations will * be reinstated together when/if ReinstateTxn is called. * @note If there are any outstanding uncommitted changes, they are reversed. * @note The term "operation" is used rather than Txn, since multiple Txns can be grouped together via [[beginMultiTxnOperation]]. So, * even if numOperations is 1, multiple Txns may be reversed if they were grouped together when they were made. * @note If numOperations is too large only the operations are reversible are reversed. */ reverseTxns(numOperations: number): IModelStatus; /** Reverse the most recent operation. */ reverseSingleTxn(): IModelStatus; /** Reverse all changes back to the beginning of the session. */ reverseAll(): IModelStatus; /** Reverse all changes back to a previously saved TxnId. * @param txnId a TxnId obtained from a previous call to GetCurrentTxnId. * @returns Success if the transactions were reversed, error status otherwise. * @see [[getCurrentTxnId]] [[cancelTo]] */ reverseTo(txnId: TxnIdString): IModelStatus; /** Reverse and then cancel (make non-reinstatable) all changes back to a previous TxnId. * @param txnId a TxnId obtained from a previous call to [[getCurrentTxnId]] * @returns Success if the transactions were reversed and cleared, error status otherwise. */ cancelTo(txnId: TxnIdString): IModelStatus; /** Reinstate the most recently reversed transaction. Since at any time multiple transactions can be reversed, it * may take multiple calls to this method to reinstate all reversed operations. * @returns Success if a reversed transaction was reinstated, error status otherwise. * @note If there are any outstanding uncommitted changes, they are canceled before the Txn is reinstated. */ reinstateTxn(): IModelStatus; /** Get the Id of the first transaction, if any. */ queryFirstTxnId(): TxnIdString; /** Get the successor of the specified TxnId */ queryNextTxnId(txnId: TxnIdString): TxnIdString; /** Get the predecessor of the specified TxnId */ queryPreviousTxnId(txnId: TxnIdString): TxnIdString; /** Get the Id of the current (tip) transaction. */ getCurrentTxnId(): TxnIdString; /** * @alpha * Get the Id of the current session. */ getCurrentSessionId(): number; /** Get the description that was supplied when the specified transaction was saved. */ getTxnDescription(txnId: TxnIdString): string; /** Test if a TxnId is valid */ isTxnIdValid(txnId: TxnIdString): boolean; /** Query if there are any pending Txns in this IModelDb that are waiting to be pushed. * @see [[IModelDb.pushChanges]] */ get hasPendingTxns(): boolean; /** * Query if there are any changes in memory that have yet to be saved to the IModelDb. * @see [[IModelDb.saveChanges]] */ get hasUnsavedChanges(): boolean; /** * @alpha * Query if there are any pending schema changes in this IModelDb. */ get hasPendingSchemaChanges(): boolean; /** * Query if there are changes in memory that have not been saved to the iModelDb or if there are Txns that are waiting to be pushed. * @see [[IModelDb.saveChanges]] * @see [[IModelDb.pushChanges]] */ get hasLocalChanges(): boolean; /** Destroy the record of all local changes that have yet to be saved and/or pushed. * This permanently eradicates your changes - use with caution! * Typically, callers will want to subsequently use [[LockControl.releaseAllLocks]]. * After calling this function, [[hasLocalChanges]], [[hasPendingTxns]], and [[hasUnsavedChanges]] will all be `false`. */ deleteAllTxns(): void; /** Obtain a list of the EC instances that have been changed locally by the [[BriefcaseDb]] associated with this `TxnManager` and have not yet been pushed to the iModel. * @beta */ queryLocalChanges(args?: QueryLocalChangesArgs): Iterable<ChangeInstanceKey>; /** Query the number of bytes of memory currently allocated by SQLite to keep track of * changes to the iModel, for debugging/diagnostic purposes, as reported by [sqlite3session_memory_used](https://www.sqlite.org/session/sqlite3session_memory_used.html). */ getChangeTrackingMemoryUsed(): number; /** * @alpha * Get the current transaction mode. * @returns The current transaction mode, either "direct" or "indirect". */ getMode(): TxnMode; /** * @alpha * Execute a series of changes in an indirect transaction. * @param callback The function containing the changes to make. */ withIndirectTxnMode(callback: () => void): void; /** * @alpha * Execute a series of changes in an indirect transaction. * @param callback The function containing the changes to make. */ withIndirectTxnModeAsync(callback: () => Promise<void>): Promise<void>; } /** * Interface for handling rebase operations on transactions. * @alpha */ export interface RebaseHandler { /** * Determine whether a transaction should be reinstated during a rebase operation. * @param txn The transaction to check. * * @alpha */ shouldReinstate(txn: TxnProps): boolean; /** * Recompute the changes for a given transaction. * @param txn The transaction to recompute. * * @alpha */ recompute(txn: TxnProps): Promise<void>; } //# sourceMappingURL=TxnManager.d.ts.map