-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Describe the bug
iModel transformer is not handling Federation Guid update.
Federation Guid is used to map elements between source and target iModels. When Federation Guid is updated and process change is executed, transformer:
- Leaves element with old
Federation Guidin target - Adds new element with new
Federation Guid
To Reproduce
it.only("should handle federation guid update", async () => {
// Arrange
const sourceSubjectId = Subject.insert(
sourceDb,
IModel.rootSubjectId,
"S1"
);
// Create physical model
const physicalModel1Id = PhysicalModel.insert(
sourceDb,
sourceSubjectId,
"PM1"
);
const categoryId1 = SpatialCategory.insert(
sourceDb,
IModel.dictionaryId,
"C1",
{}
);
// Create element with null code value to make sure that code value is not used to map elements between source and target
const oldGuid = Guid.createValue();
const code = new Code({ scope: "0x1", spec: "0x1", value: undefined });
const element: PhysicalElementProps = {
classFullName: PhysicalObject.classFullName,
model: physicalModel1Id,
category: categoryId1,
code,
userLabel: "PhysicalElement1",
federationGuid: oldGuid,
};
var physicalElemId= sourceDb.elements.insertElement(element);
await pushChanges(sourceDb, "Initial changes");
// === Transformation 1: Run `process all` transformation ===
let transformer = new IModelTransformer(sourceDb, targetDb);
await transformer.process();
transformer.updateSynchronizationVersion({
initializeReverseSyncVersion: true,
});
await pushChanges(targetDb, "Transformation 1: Process All");
// Assert
expect(
IModelTestUtils.count(targetDb, PhysicalElement.classFullName)
).to.be.equal(1);
targetDb.elements.getElement(oldGuid); // throws if element not found
// === Transformation 2: `process changes` transformation to insert excluded parent model ===
// Update physical element's federation guid in source
const updatedElementProps = sourceDb.elements.getElementProps(physicalElemId);
const newGuid = Guid.createValue();
updatedElementProps.federationGuid = newGuid;
sourceDb.elements.updateElement(updatedElementProps);
await pushChanges(sourceDb, "Updated federation guid");
transformer = new IModelTransformer(sourceDb, targetDb, {argsForProcessChanges: {}});
await transformer.process();
await pushChanges(
targetDb,
"Transformation 2: inserted previously excluded model"
);
// Assert
expect(
IModelTestUtils.count(targetDb, PhysicalElement.classFullName)
).to.be.equal(1);
expect(targetDb.elements.getElement(newGuid)).to.not.be.undefined; // throws if element not found
expect(targetDb.elements.tryGetElement(oldGuid)).to.be.undefined;
});Expected behavior
Target should have only one element with new Federation Guid. Element with old Federation Guid should not exist.
Additional context
This issue was discovered while investigating https://github.com/iTwin/itwinjs-backlog/issues/1762
PR: #279
In the issue, element that re-used Instance ID was marked as updated. Which showed up as update of all properties such as class and Federation Guid.
Not sure if there are any other use - cases where it would make sense to update Federation Guid, but since it is supported by iTwinjs API, transformer should also handle it without corrupting target iModel (duplicating elements).
Versions used:
- @itwin/imodel-transformer 1.2.1-dev.1
- iTwin.js Version 4.11.1