@itwin/core-backend 5.14.0-dev.20 → 5.14.0-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/ChangesetReader.d.ts +1 -1
- package/lib/cjs/ChangesetReader.js +2 -2
- package/lib/cjs/ChangesetReader.js.map +1 -1
- package/lib/cjs/ChangesetReaderTypes.d.ts +4 -1
- package/lib/cjs/ChangesetReaderTypes.d.ts.map +1 -1
- package/lib/cjs/ChangesetReaderTypes.js +3 -0
- package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
- package/lib/cjs/Element.d.ts.map +1 -1
- package/lib/cjs/Element.js +6 -3
- package/lib/cjs/Element.js.map +1 -1
- package/lib/esm/ChangesetReader.d.ts +1 -1
- package/lib/esm/ChangesetReader.js +2 -2
- package/lib/esm/ChangesetReader.js.map +1 -1
- package/lib/esm/ChangesetReaderTypes.d.ts +4 -1
- package/lib/esm/ChangesetReaderTypes.d.ts.map +1 -1
- package/lib/esm/ChangesetReaderTypes.js +3 -0
- package/lib/esm/ChangesetReaderTypes.js.map +1 -1
- package/lib/esm/Element.d.ts.map +1 -1
- package/lib/esm/Element.js +6 -3
- package/lib/esm/Element.js.map +1 -1
- package/lib/esm/test/ecdb/ConcurrentQuery.test.js +19 -2
- package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
- package/lib/esm/test/imodel/IModelElements.test.js +5 -0
- package/lib/esm/test/imodel/IModelElements.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +111 -2
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/package.json +13 -13
|
@@ -54,12 +54,12 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
54
54
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
55
55
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
56
56
|
*--------------------------------------------------------------------------------------------*/
|
|
57
|
-
import { DbResult, Id64 } from "@itwin/core-bentley";
|
|
57
|
+
import { DbResult, Guid, Id64 } from "@itwin/core-bentley";
|
|
58
58
|
import { Code, ColorDef, IModel, SubCategoryAppearance } from "@itwin/core-common";
|
|
59
59
|
import { Arc3d, IModelJson, Point3d } from "@itwin/core-geometry";
|
|
60
60
|
import { assert, expect } from "chai";
|
|
61
61
|
import { DrawingCategory } from "../../Category";
|
|
62
|
-
import { _nativeDb, BriefcaseDb, ChannelControl } from "../../core-backend";
|
|
62
|
+
import { _nativeDb, BriefcaseDb, ChannelControl, DrawingGraphic, ElementGroupsMembers, ElementOwnsChildElements, ExternalSourceAspect } from "../../core-backend";
|
|
63
63
|
import { HubMock } from "../../internal/HubMock";
|
|
64
64
|
import { ChangesetReader } from "../../ChangesetReader";
|
|
65
65
|
import * as path from "node:path";
|
|
@@ -3736,6 +3736,115 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3736
3736
|
}
|
|
3737
3737
|
});
|
|
3738
3738
|
});
|
|
3739
|
+
describe("ChangesetReader: PropertyFilter.InstanceKeyAndIdentifiers", () => {
|
|
3740
|
+
let iModel;
|
|
3741
|
+
let txn;
|
|
3742
|
+
let modelId;
|
|
3743
|
+
let categoryId;
|
|
3744
|
+
before(async () => {
|
|
3745
|
+
HubMock.startup("ChangesetReaderIdentifiersTest", KnownTestLocations.outputDir);
|
|
3746
|
+
const accessToken = "super manager token";
|
|
3747
|
+
const iModelId = await HubMock.createNewIModel({ iTwinId: HubMock.iTwinId, iModelName: "identifiersTest", description: "InstanceKeyAndIdentifiers", accessToken });
|
|
3748
|
+
iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId: HubMock.iTwinId, iModelId, accessToken });
|
|
3749
|
+
iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
3750
|
+
txn = startTestTxn(iModel, "InstanceKeyAndIdentifiers setup");
|
|
3751
|
+
await iModel.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
3752
|
+
const codeProps = Code.createEmpty();
|
|
3753
|
+
codeProps.value = "DrawingModel";
|
|
3754
|
+
[, modelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
|
|
3755
|
+
categoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "Category", new SubCategoryAppearance());
|
|
3756
|
+
txn.saveChanges("setup");
|
|
3757
|
+
await iModel.locks.acquireLocks({ shared: modelId });
|
|
3758
|
+
});
|
|
3759
|
+
after(() => {
|
|
3760
|
+
txn.end();
|
|
3761
|
+
iModel?.close();
|
|
3762
|
+
HubMock.shutdown();
|
|
3763
|
+
});
|
|
3764
|
+
const insertGraphic = (props) => {
|
|
3765
|
+
const elementProps = { classFullName: DrawingGraphic.classFullName, model: modelId, category: categoryId, code: Code.createEmpty(), ...props };
|
|
3766
|
+
return txn.insertElement(elementProps);
|
|
3767
|
+
};
|
|
3768
|
+
const lastTxnId = () => iModel.txns.getLastSavedTxnProps().id;
|
|
3769
|
+
// An aspect or relationship can have the same id as an element or model, so also match the table.
|
|
3770
|
+
const readIdentifiers = (txnId, instanceId, table) => readTxn(iModel, txnId, PropertyFilter.InstanceKeyAndIdentifiers, { classIdsToClassNames: true })
|
|
3771
|
+
.filter((i) => i.ECInstanceId === instanceId && i.$meta.tables.includes(table));
|
|
3772
|
+
it("reads a reparent after the element is deleted, without querying the iModel", () => {
|
|
3773
|
+
// iTwin/itwinjs-core#9738: the reparent records Parent.Id but not Parent.RelECClassId, which cannot be read back once the element is deleted.
|
|
3774
|
+
const [parentA, parentB] = [insertGraphic(), insertGraphic()];
|
|
3775
|
+
const childId = insertGraphic({ parent: new ElementOwnsChildElements(parentA) });
|
|
3776
|
+
txn.saveChanges("insert child");
|
|
3777
|
+
txn.updateElement({ ...iModel.elements.getElementProps(childId), parent: new ElementOwnsChildElements(parentB) });
|
|
3778
|
+
txn.saveChanges("reparent child");
|
|
3779
|
+
const reparentTxnId = lastTxnId();
|
|
3780
|
+
txn.deleteElement(childId);
|
|
3781
|
+
txn.saveChanges("delete child");
|
|
3782
|
+
const reparented = readIdentifiers(reparentTxnId, childId, "bis_Element");
|
|
3783
|
+
expect(reparented.map((i) => i.$meta.stage).sort()).to.deep.equal(["New", "Old"]);
|
|
3784
|
+
for (const instance of reparented)
|
|
3785
|
+
expect(Object.keys(instance).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId"]);
|
|
3786
|
+
});
|
|
3787
|
+
it("returns the owning Element of an aspect, plus ExternalSourceAspect identifiers when it is deleted", () => {
|
|
3788
|
+
const [ownerId, scopeId] = [insertGraphic(), insertGraphic()];
|
|
3789
|
+
const aspectId = txn.insertAspect({
|
|
3790
|
+
classFullName: ExternalSourceAspect.classFullName,
|
|
3791
|
+
element: { id: ownerId },
|
|
3792
|
+
scope: { id: scopeId },
|
|
3793
|
+
identifier: "source-id",
|
|
3794
|
+
kind: "Element",
|
|
3795
|
+
version: "1",
|
|
3796
|
+
});
|
|
3797
|
+
txn.saveChanges("insert aspect");
|
|
3798
|
+
const insertTxnId = lastTxnId();
|
|
3799
|
+
const versionUpdate = { ...iModel.elements.getAspect(aspectId).toJSON(), version: "2" };
|
|
3800
|
+
txn.updateAspect(versionUpdate);
|
|
3801
|
+
txn.saveChanges("update aspect version");
|
|
3802
|
+
const updateTxnId = lastTxnId();
|
|
3803
|
+
txn.deleteAspect(aspectId);
|
|
3804
|
+
txn.saveChanges("delete aspect");
|
|
3805
|
+
const deleteTxnId = lastTxnId();
|
|
3806
|
+
// Scope, Kind, and Identifier are returned only for deleted rows.
|
|
3807
|
+
const inserted = readIdentifiers(insertTxnId, aspectId, "bis_ElementMultiAspect");
|
|
3808
|
+
expect(inserted).to.have.lengthOf(1);
|
|
3809
|
+
expect(Object.keys(inserted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "Element"]);
|
|
3810
|
+
expect(inserted[0].Element).to.deep.equal({ Id: ownerId });
|
|
3811
|
+
// Version is not an identifier, and the update did not record Element.
|
|
3812
|
+
const updated = readIdentifiers(updateTxnId, aspectId, "bis_ElementMultiAspect");
|
|
3813
|
+
expect(updated).to.have.lengthOf(2);
|
|
3814
|
+
for (const instance of updated)
|
|
3815
|
+
expect(Object.keys(instance).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId"]);
|
|
3816
|
+
const deleted = readIdentifiers(deleteTxnId, aspectId, "bis_ElementMultiAspect");
|
|
3817
|
+
expect(deleted).to.have.lengthOf(1);
|
|
3818
|
+
expect(deleted[0].$meta.op).to.equal("Deleted");
|
|
3819
|
+
expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "Element", "Identifier", "Kind", "Scope"]);
|
|
3820
|
+
expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.ExternalSourceAspect", Element: { Id: ownerId }, Scope: { Id: scopeId }, Kind: "Element", Identifier: "source-id" });
|
|
3821
|
+
});
|
|
3822
|
+
it("returns FederationGuid for a deleted element", () => {
|
|
3823
|
+
const federationGuid = Guid.createValue();
|
|
3824
|
+
const elementId = insertGraphic({ federationGuid });
|
|
3825
|
+
txn.saveChanges("insert element");
|
|
3826
|
+
txn.deleteElement(elementId);
|
|
3827
|
+
txn.saveChanges("delete element");
|
|
3828
|
+
const deleted = readIdentifiers(lastTxnId(), elementId, "bis_Element");
|
|
3829
|
+
expect(deleted).to.have.lengthOf(1);
|
|
3830
|
+
expect(deleted[0].$meta.op).to.equal("Deleted");
|
|
3831
|
+
expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "FederationGuid"]);
|
|
3832
|
+
expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.DrawingGraphic", FederationGuid: federationGuid });
|
|
3833
|
+
});
|
|
3834
|
+
it("returns source and target ids for a deleted link-table relationship", () => {
|
|
3835
|
+
const [sourceId, targetId] = [insertGraphic(), insertGraphic()];
|
|
3836
|
+
const props = { classFullName: ElementGroupsMembers.classFullName, sourceId, targetId, memberPriority: 1 };
|
|
3837
|
+
const relationshipId = txn.insertRelationship(props);
|
|
3838
|
+
txn.saveChanges("insert relationship");
|
|
3839
|
+
txn.deleteRelationship({ ...props, id: relationshipId });
|
|
3840
|
+
txn.saveChanges("delete relationship");
|
|
3841
|
+
const deleted = readIdentifiers(lastTxnId(), relationshipId, "bis_ElementRefersToElements");
|
|
3842
|
+
expect(deleted).to.have.lengthOf(1);
|
|
3843
|
+
expect(deleted[0].$meta.op).to.equal("Deleted");
|
|
3844
|
+
expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "SourceECInstanceId", "TargetECInstanceId"]);
|
|
3845
|
+
expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.ElementGroupsMembers", SourceECInstanceId: sourceId, TargetECInstanceId: targetId });
|
|
3846
|
+
});
|
|
3847
|
+
});
|
|
3739
3848
|
describe("ChangesetReader: overflow table graceful recovery when ExclusiveRootClassId is NULL", () => {
|
|
3740
3849
|
let rwIModel;
|
|
3741
3850
|
let rwIModelId;
|