Skip to content

Allow element to change its parent or model or both#9303

Open
khanaffan wants to merge 23 commits into
masterfrom
affank/move-el
Open

Allow element to change its parent or model or both#9303
khanaffan wants to merge 23 commits into
masterfrom
affank/move-el

Conversation

@khanaffan
Copy link
Copy Markdown
Contributor

@khanaffan khanaffan commented May 14, 2026

imodel-native: iTwin/imodel-native#1428

Add changeElementParent and changeElementModel methods to @itwin/core-backend

Adds new @beta APIs for moving elements between models and/or parents without deleting and re-inserting them. The native implementation automatically handles moving element subtrees (assemblies) — all descendants are moved along with the parent element.

Changes

  • EditTxn.changeElementParent — changes the parent of an element. If the new parent is in a different model, the element's model changes as well. When called on an element with children, all descendants are automatically moved as well (handled by the native implementation). Enforces model type matching, channel verification, and lock checks.
  • EditTxn.changeElementModel — changes the model of an element, making it a root element (no parent) in the new model. When called on an element with children, all descendants are automatically moved as well (handled by the native implementation). Enforces model type matching, channel verification, and lock checks.
  • IModelDb.Elements.changeElementParent — deprecated convenience wrapper that delegates to the implicit transaction. Use EditTxn.changeElementParent instead within an explicit EditTxn scope.
  • IModelDb.Elements.changeElementModel — deprecated convenience wrapper that delegates to the implicit transaction. Use EditTxn.changeElementModel instead within an explicit EditTxn scope.
  • ChangeElementParentProps / ChangeElementModelProps — interfaces specifying move parameters (element id, target parent/model).

Code scope restrictions

Blocked scopes (will throw):

  • Model-scoped code — code uniqueness is tied to the source model; moving across models would break uniqueness guarantees.
  • ParentElement-scoped code — code scope is invalidated by reparenting; the scope reference becomes stale.

Allowed scopes (move proceeds):

  • Repository-scoped code — unique across the entire iModel, unaffected by model or parent changes.
  • RelatedElement-scoped code — scope element is independent of the parent/model hierarchy.
  • Empty codes — no scope to conflict.

For elements with blocked code scopes, use delete+insert instead of move.

Validation

  • Targeted verification: Added comprehensive unit tests (ChangeElementParentModel.test.ts) covering single-element moves, subtree moves (assemblies), model type mismatch, circular dependency rejection, self-parenting rejection, blocked code scopes (Model-scoped, ParentElement-scoped), allowed code scopes (Repository-scoped, RelatedElement-scoped, empty), and channel verification.
  • Known baseline issues: None.

@khanaffan khanaffan changed the title Affank/move el Add support for move element May 14, 2026
@khanaffan khanaffan marked this pull request as ready for review May 15, 2026 15:07
@khanaffan khanaffan requested review from a team as code owners May 15, 2026 15:07
@aruniverse aruniverse requested a review from Copilot May 15, 2026 15:09

This comment was marked as outdated.

khanaffan and others added 7 commits May 15, 2026 11:18
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@kabentley
Copy link
Copy Markdown
Collaborator

Didn't we already deal with this in a past PR? I distinctly remember telling whomever was working on it then to NOT call this "move" - that is the term we use for geometric location. It will confuse everyone!

At the time, i remember discussing why "move tree" is a bad idea. What brings this up again?

@aruniverse
Copy link
Copy Markdown
Member

Didn't we already deal with this in a past PR?

#8833

…changeElementModel

- Added `EditTxn.changeElementParent` and `EditTxn.changeElementModel` methods for changing the parent and model of leaf elements, respectively.
- Implemented `IModelDb.Elements.changeElementParent` and `IModelDb.Elements.changeElementModel` for recursively moving elements and their subtrees.
- Removed the deprecated `EditTxn.moveElement` and related tests.
- Updated documentation to reflect the new methods and their usage.
@khanaffan khanaffan requested a review from RohitPtnkr1996 as a code owner May 21, 2026 20:18
@khanaffan khanaffan changed the title Add support for move element Allow element to change its parent or model or both May 21, 2026
Comment thread core/backend/src/IModelDb.ts Outdated
const sourceModel = iModel.models.getModel(sourceModelId);
const targetModel = iModel.models.getModel(targetModelId);
if (sourceModel.classFullName !== targetModel.classFullName)
ITwinError.throwError({ message: `cannot move element from model of type '${sourceModel.classFullName}' to model of type '${targetModel.classFullName}'`, iTwinErrorId: { scope: "imodel", key: "invalid-arguments" } });
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make a new ITwinError interface for this so callers can know what errors to expect.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the recursive version of this function from IModelDb.

Comment thread core/backend/src/IModelDb.ts Outdated
* @throws [[ITwinError]] if the operation fails (e.g., model type mismatch, code scope conflict).
* @beta
*/
public changeElementParent(props: ChangeElementParentProps): void {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be on EditTxn, not here. It should not commit a transaction

Copy link
Copy Markdown
Collaborator

@kabentley kabentley May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly, I don't understand why there should be 2 methods (single element vs. element+children). Why is that necessary? But you definitely should not have an API that commits its changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the recursive version of this function from IModelDb.

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 26, 2026

This pull request is now in conflicts. Could you fix it @khanaffan? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

@khanaffan
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Co-authored-by: khanaffan <29756942+khanaffan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 3, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts resolved in commit eee59c2. The two conflicts were:

  1. core/backend/src/IModelDb.ts — combined the _verifyChannel import from our branch with the SchemaView import added in master.
  2. docs/changehistory/NextVersion.md — merged both branches' content, preserving our @itwin/core-backend section alongside master's new @itwin/map-layers-formats (Azure Maps) section.

…hods to change parent and model of leaf elements without deletion. Updated documentation for clarity on usage and constraints.
Comment thread core/backend/src/IModelDb.ts Dismissed
Comment thread core/backend/src/test/standalone/ElementUpdateHandler.test.ts Fixed
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Jun 4, 2026

This pull request is now in conflicts. Could you fix it @khanaffan? 🙏
To fixup this pull request, you can check out it locally. See documentation: https://help.github.com/articles/checking-out-pull-requests-locally/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants