@itwin/core-backend
Version:
iTwin.js backend components
371 lines • 19.7 kB
TypeScript
/** @packageDocumentation
* @module iModels
*/
import { DbResult, Id64Arg, Id64Array, Id64Set, Id64String } from "@itwin/core-bentley";
import { EcefLocationProps, ElementAspectProps, ElementProps, FilePropertyProps, ModelProps, RelationshipProps, SaveChangesArgs } from "@itwin/core-common";
import { Range3dProps } from "@itwin/core-geometry";
import type { CloudSqlite } from "./CloudSqlite";
import type { ImplicitWriteEnforcement } from "./IModelHost";
import type { ChangeElementModelProps, ChangeElementParentProps, IModelDb, InsertElementOptions, UpdateModelOptions } from "./IModelDb";
import type { SettingsContainer } from "./workspace/Settings";
/** Options for bulk deleting elements from an iModelDb.
* @beta
*/
export interface BulkDeleteElementsArgs {
/**
* Skips pre-deletion **NO ACTION** foreign key constraint validation checks, which may improve performance for large deletions.
* This will improve performance, but if the user supplies elements which have FK constraint violations, it will result in the delete failing and an eventual rollback.
*/
skipFKConstraintValidations?: boolean;
}
/**
* Result of a bulk element delete operation.
* @beta
*/
export interface BulkDeleteElementsResult {
/**
* Overall status of the bulk delete operation.
* - `Success`: All elements were deleted successfully. `failedIds` will be empty.
* - `PartialSuccess`: Some elements were deleted, but others failed. `failedIds` contains the ids that could not be deleted.
* - `DeletionFailed`: The delete operation failed entirely (e.g. due to an FK constraint violation). `failedIds` contains the ids that could not be deleted.
*/
status: BulkDeleteElementsStatus;
/**
* The raw SQLite result code from the underlying SQL DELETE statement.
* `DbResult.BE_SQLITE_OK` on success; a non-OK code indicates a database-level error such as a constraint violation.
*/
sqlDeleteStatus: DbResult;
/**
* The set of element ids that could not be deleted.
* Empty when `status` is `Success`. Non-empty when `status` is `PartialSuccess` or `DeletionFailed`.
*/
failedIds: Id64Set;
}
/**
* Status of a bulk element delete operation, mirroring the C++ `BulkDeleteStatus` enum.
* @beta
*/
export declare enum BulkDeleteElementsStatus {
/** All supplied elements were deleted successfully. */
Success = 0,
/** Some elements were deleted but others could not be, typically due to foreign key constraints on the elements not being deleted. */
PartialSuccess = 1,
/** No elements were deleted. This occurs when the SQL DELETE statement itself fails, e.g. due to a FK constraint violation that prevents the entire batch from being processed. */
DeletionFailed = 2
}
/**
* Represents an explicit editing transaction for an iModel.
*
* An explicit EditTxn lets callers define a deliberate unit of work by choosing when editing
* starts (`start`) and how it ends (`end()` / `end("save")` or `end("abandon")`). This avoids mixing
* unrelated edits into one implicit unit of work and makes save/rollback boundaries explicit.
*
* Explicit EditTxn instances must be active before mutating operations are performed, regardless of enforcement level.
* In other words, explicit transaction behavior is independent of `implicitWriteEnforcement`.
*
* @see [EditTxn transaction model and migration guidance]($docs/learning/backend/EditTxn.md)
*
* *During indirect changes (commit processing):* Use callback args (`indirectEditTxn`) in callbacks like
* [[Relationship.onRootChangedArg]] and [[Relationship.onDeletedDependencyArg]] that fire during indirect processing.
*
* @beta
*/
export declare class EditTxn {
/** Controls how writes through the implicit transaction are handled.
*
* This does not relax activation requirements for explicit transactions: explicit EditTxn writes
* must always come from the active EditTxn.
*
* - `allow`: allow implicit writes for backwards compatibility, even while an explicit EditTxn is active.
* - `log`: allow implicit writes but log `implicit-txn-write-disallowed` errors.
* - `throw`: reject implicit writes with `implicit-txn-write-disallowed`.
*
* This is initialized from [[IModelHostOptions.implicitWriteEnforcement]] during [[IModelHost.startup]].
*
* Defaults to `allow` for backwards compatibility.
* @beta
*/
static implicitWriteEnforcement: ImplicitWriteEnforcement;
/** The iModel this EditTxn may modify. */
readonly iModel: IModelDb;
/** Default description passed to [[saveChanges]] when saving this transaction. */
description: string;
/** True if this transaction currently owns the iModel write surface. */
get isActive(): boolean;
constructor(iModel: IModelDb, description: string);
verifyWriteable(): void;
/** Start this EditTxn, making it the active transaction for the iModel.
* @throws EditTxnError if this EditTxn is already active, another EditTxn is already active, or if unsaved changes are present.
*/
start(): void;
/** End this EditTxn, either by saving or abandoning the changes.
* @param mode Whether to "save" or "abandon" the changes. Defaults to "save".
* @param args Save changes arguments when saving.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if saving changes fails.
*/
end(): void;
end(mode: "save" | "abandon", args?: string | SaveChangesArgs): void;
/** Invoked when the owning iModel is closing.
* The base implementation commits unsaved changes. Subclasses may override to customize how
* their changes are handled before the iModel closes.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if saving on close fails.
*/
onClose(): void;
/** Abandon database changes while keeping this EditTxn active.
* @throws EditTxnError if this EditTxn is not active.
*/
abandonChanges(): void;
/** Save changes with additional arguments.
* @param args Save changes arguments.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if the iModel is readonly, if indirect changes are active, or if the native save fails.
*/
saveChanges(args?: string | SaveChangesArgs): void;
/** Insert a new element into the iModel.
* @param elProps The properties of the new element.
* @returns The newly inserted element's Id.
* @throws EditTxnError if this EditTxn is not active.
* @throws [[ITwinError]] if insertion fails.
*/
insertElement(elProps: ElementProps, options?: InsertElementOptions): Id64String;
/** Update an existing element in the iModel.
* @param elProps The properties to update.
* @throws EditTxnError if this EditTxn is not active.
* @throws [[ITwinError]] if update fails.
*/
updateElement<T extends ElementProps>(elProps: Partial<T>): void;
/** Delete elements from the iModel.
* @param ids The Ids of the elements to delete.
* @throws EditTxnError if this EditTxn is not active.
* @throws [[ITwinError]] if deletion fails.
*/
deleteElement(ids: Id64Arg): void;
/** Change the parent of an element within its model.
*
* The new parent must be in the same model as the element. Cross-model reparenting is not allowed;
* use [[changeElementModel]] only to move root elements between models.
* Only the target element is reparented — its children and their model membership are unaffected.
*
* **Blocked cases** (will throw):
* - The new parent is in a different model than the element.
* - Element has a `ParentElement`-scoped code (code uniqueness is tied to the parent; use delete+insert instead).
*
* **Allowed cases**:
* - Element has a `Repository`-scoped code (unique across entire iModel — unaffected by the parent change).
* - Element has a `RelatedElement`-scoped code (scope element is independent of the parent).
* - Element has a `Model`-scoped code (the model does not change, so the code remains valid).
* - Element has no meaningful code (empty code).
*
* Channel verification is performed on the element's model.
* Lock enforcement: requires an exclusive lock on the element, and a shared lock on the new parent.
* @param props The reparent parameters: element id and new parent id.
* @throws EditTxnError if this EditTxn is not active.
* @throws [[ITwinError]] if the operation fails.
* @beta
*/
changeElementParent(props: ChangeElementParentProps): void;
/** Change the model of a root element, making it a root element in the new model.
*
* The element must not have a parent.
* The element's entire subtree moves with it: BIS requires a parent and all of its children to reside
* in the same model, so every descendant of the element is relocated into the target model as well.
* The parent-child hierarchy is preserved. The whole subtree is validated before anything is moved, so
* a rejected change leaves the iModel untouched.
*
* **Blocked cases** (will throw):
* - Element has a parent (only root elements can be moved between models).
* - Any element in the subtree has a `Model`-scoped code (code uniqueness is tied to the source model; use delete+insert instead).
* - The moved (root) element has a `ParentElement`-scoped code (use delete+insert instead). A descendant's `ParentElement`-scoped code is allowed, because its parent moves with it.
*
* **Allowed cases** (for any element in the subtree):
* - A `Repository`-scoped code (unique across entire iModel — unaffected by the model change).
* - A `RelatedElement`-scoped code (scope element is independent of the model).
* - No meaningful code (empty code).
*
* The source and target models must be of the same class (classFullName must match exactly).
* Channel verification is performed on both the source and target models.
* Lock enforcement: requires an exclusive lock on every element in the moved subtree, and a shared lock on the target model.
* @param props The model change parameters: element id and target model id.
* @throws EditTxnError if this EditTxn is not active.
* @throws [[ITwinError]] if the operation fails.
* @beta
*/
changeElementModel(props: ChangeElementModelProps): void;
/** Collect an element together with all of its descendants by walking the `ElementOwnsChildElements`
* hierarchy depth-first. Used to invalidate the cached props of every element affected by a subtree move.
*/
private collectSubtreeIds;
/**
* Delete multiple elements from the iModel.
* @param ids The ids of the elements to delete. All ids must be well-formed and valid [[Id64String]]s.
* @param deleteOptions Options for the delete operation.
* @returns A result object containing information about the deletion operation success and the element ids that failed to delete (if any).
* @throws [[ITwinError]] if any of the supplied ids are not well-formed/valid [[Id64String]]s.
* @beta
*/
deleteElements(ids: Id64Array, deleteOptions?: BulkDeleteElementsArgs): BulkDeleteElementsResult;
/** Insert a new aspect into the iModel.
* @param aspectProps The properties of the new aspect.
* @returns The newly inserted aspect Id.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if insertion fails.
*/
insertAspect(aspectProps: ElementAspectProps): Id64String;
/** Update an existing aspect in the iModel.
* @param aspectProps The properties of the aspect to update.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if update fails.
*/
updateAspect(aspectProps: ElementAspectProps): void;
/** Delete one or more aspects from the iModel.
* @param aspectInstanceIds The Ids of the aspects to delete.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if deletion fails.
*/
deleteAspect(aspectInstanceIds: Id64Arg): void;
/** Delete definition elements from the iModel when they are not referenced.
* @param definitionElementIds The Ids of the definition elements to attempt to delete.
* @returns The set of definition elements that were still in use and therefore not deleted.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if usage queries fail.
*/
deleteDefinitionElements(definitionElementIds: Id64Array): Id64Set;
/** Insert a new model into the iModel.
* @param props The data for the new model.
* @returns The newly inserted model's Id.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if insertion fails.
*/
insertModel(props: ModelProps): Id64String;
/** Update an existing model in the iModel.
* @param props the properties of the model to change
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if update fails.
*/
updateModel(props: UpdateModelOptions): void;
/** Update the geometry guid of a model.
* @param modelId The Id of the model to update.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if the update fails.
*/
updateGeometryGuid(modelId: Id64String): void;
/** Delete models from the iModel.
* @param ids The Ids of the models to delete.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if deletion fails.
*/
deleteModel(ids: Id64Arg): void;
/** Insert a new relationship into the iModel.
* @param props The properties of the new relationship.
* @returns The Id of the newly inserted relationship.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if the class is invalid for link-table insertion.
*/
insertRelationship(props: RelationshipProps): Id64String;
/** Update an existing relationship in the iModel.
* @param props the properties of the relationship to update.
* @throws EditTxnError if this EditTxn is not active.
*/
updateRelationship(props: RelationshipProps): void;
/** Delete a relationship from the iModel.
* @param props The properties of the relationship to delete.
* @throws EditTxnError if this EditTxn is not active.
*/
deleteRelationship(props: RelationshipProps): void;
/** Delete multiple relationships from the iModel.
* @param props The properties of the relationships to delete.
* @throws EditTxnError if this EditTxn is not active.
*/
deleteRelationships(props: ReadonlyArray<RelationshipProps>): void;
/** Save a file property to the iModel.
* @param prop The file property to save.
* @param strValue String value.
* @param blobVal Blob value.
* @throws EditTxnError if this EditTxn is not active.
*/
saveFileProperty(prop: FilePropertyProps, strValue: string | undefined, blobVal?: Uint8Array): void;
/** Delete a file property from the iModel.
* @param prop The file property to delete.
* @throws EditTxnError if this EditTxn is not active.
*/
deleteFileProperty(prop: FilePropertyProps): void;
/** Update the project extents of the iModel.
* @param newExtents The new project extents.
* @throws EditTxnError if this EditTxn is not active.
* @throws IModelError if extents are invalid.
*/
updateProjectExtents(newExtents: Range3dProps): void;
/** Update the ECEF location of the iModel.
* @param ecef The new ECEF location.
* @throws EditTxnError if this EditTxn is not active.
*/
updateEcefLocation(ecef: EcefLocationProps): void;
/** Update the iModel props in the database from the current in-memory state.
* @throws EditTxnError if this EditTxn is not active.
*/
updateIModelProps(): void;
private static readonly _settingPropNamespace;
private static readonly _viewStoreProperty;
/** Save a `SettingDictionary` in this iModel.
* @param name The name for the SettingDictionary. If a dictionary by that name already exists, its value is replaced.
* @param dict The SettingDictionary object to stringify and save.
* @throws EditTxnError if this EditTxn is not active.
* @beta
*/
saveSettingDictionary(name: string, dict: SettingsContainer): void;
/** Delete a SettingDictionary from this iModel.
* @param name The name of the dictionary to delete.
* @throws EditTxnError if this EditTxn is not active.
* @beta
*/
deleteSettingDictionary(name: string): void;
/** Save a default ViewStore container reference in this iModel.
* @param arg The cloud container properties for the ViewStore.
* @throws EditTxnError if this EditTxn is not active.
* @beta
*/
saveDefaultViewStore(arg: CloudSqlite.ContainerProps): void;
}
/** Execute a callback within an explicit editing transaction. A new [[EditTxn]] is created, started,
* and passed to `fn`. If `fn` returns normally (or its returned Promise resolves), the transaction
* is committed. If `fn` throws (or its returned Promise rejects), the transaction is abandoned —
* none of the changes made during the callback are saved — and the error is re-thrown.
*
* This is the recommended way to perform a scoped unit of work on an iModel. It ensures that
* edits are committed atomically on success and rolled back on failure, without the caller needing
* to manage `start` / `end` manually.
*
* @param iModel The iModel to edit.
* @param fn A callback that receives the active [[EditTxn]] and performs edits.
* @returns The value returned by `fn`.
* @throws EditTxnError if the transaction cannot be started (e.g. unsaved changes or another EditTxn is active).
* @throws Re-throws any error thrown by `fn` after abandoning the transaction.
* @beta
*/
export declare function withEditTxn<T>(iModel: IModelDb, fn: (txn: EditTxn) => T): T;
/** Execute a callback within an explicit editing transaction, supplying commit arguments.
* @param iModel The iModel to edit.
* @param saveArgs Description or structured arguments passed to [[EditTxn.saveChanges]] on save.
* @param fn A callback that receives the active [[EditTxn]] and performs edits.
* @returns The value returned by `fn`.
* @beta
*/
export declare function withEditTxn<T>(iModel: IModelDb, saveArgs: string | SaveChangesArgs, fn: (txn: EditTxn) => T): T;
/** Execute an async callback within an explicit editing transaction.
* @param iModel The iModel to edit.
* @param fn An async callback that receives the active [[EditTxn]] and performs edits.
* @returns A Promise that resolves to the value returned by `fn`.
* @beta
*/
export declare function withEditTxn<T>(iModel: IModelDb, fn: (txn: EditTxn) => Promise<T>): Promise<T>;
/** Execute an async callback within an explicit editing transaction, supplying commit arguments.
* @param iModel The iModel to edit.
* @param saveArgs Description or structured arguments passed to [[EditTxn.saveChanges]] on save.
* @param fn An async callback that receives the active [[EditTxn]] and performs edits.
* @returns A Promise that resolves to the value returned by `fn`.
* @beta
*/
export declare function withEditTxn<T>(iModel: IModelDb, saveArgs: string | SaveChangesArgs, fn: (txn: EditTxn) => Promise<T>): Promise<T>;
//# sourceMappingURL=EditTxn.d.ts.map