@itwin/core-backend 5.13.0-dev.9 → 5.14.0-dev.1
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/CHANGELOG.md +33 -1
- package/lib/cjs/Category.d.ts +4 -4
- package/lib/cjs/Category.js.map +1 -1
- package/lib/cjs/ChangesetECAdaptor.d.ts +5 -0
- package/lib/cjs/ChangesetECAdaptor.d.ts.map +1 -1
- package/lib/cjs/ChangesetECAdaptor.js +13 -3
- package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
- package/lib/cjs/CodeSpecs.d.ts +3 -3
- package/lib/cjs/CodeSpecs.js.map +1 -1
- package/lib/cjs/DisplayStyle.d.ts +2 -2
- package/lib/cjs/DisplayStyle.js.map +1 -1
- package/lib/cjs/EditTxn.d.ts.map +1 -1
- package/lib/cjs/EditTxn.js +1 -0
- package/lib/cjs/EditTxn.js.map +1 -1
- package/lib/cjs/Element.d.ts +48 -12
- package/lib/cjs/Element.d.ts.map +1 -1
- package/lib/cjs/Element.js +120 -24
- package/lib/cjs/Element.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +30 -15
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +51 -15
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/Model.d.ts +5 -5
- package/lib/cjs/Model.d.ts.map +1 -1
- package/lib/cjs/Model.js.map +1 -1
- package/lib/cjs/PropertyStore.js +1 -1
- package/lib/cjs/PropertyStore.js.map +1 -1
- package/lib/cjs/SchemaSync.d.ts +37 -9
- package/lib/cjs/SchemaSync.d.ts.map +1 -1
- package/lib/cjs/SchemaSync.js +125 -6
- package/lib/cjs/SchemaSync.js.map +1 -1
- package/lib/cjs/SynchronousChannel.d.ts +62 -0
- package/lib/cjs/SynchronousChannel.d.ts.map +1 -0
- package/lib/cjs/SynchronousChannel.js +11 -0
- package/lib/cjs/SynchronousChannel.js.map +1 -0
- package/lib/cjs/Texture.d.ts +1 -1
- package/lib/cjs/Texture.js.map +1 -1
- package/lib/cjs/TxnManager.d.ts +44 -4
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +72 -14
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/ViewDefinition.d.ts +6 -6
- package/lib/cjs/ViewDefinition.d.ts.map +1 -1
- package/lib/cjs/ViewDefinition.js.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.d.ts +22 -7
- package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.js +104 -36
- package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.d.ts +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.js +25 -10
- package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/cjs/core-backend.d.ts +1 -0
- package/lib/cjs/core-backend.d.ts.map +1 -1
- package/lib/cjs/core-backend.js +1 -0
- package/lib/cjs/core-backend.js.map +1 -1
- package/lib/cjs/internal/IntegrityCheck.d.ts +22 -0
- package/lib/cjs/internal/IntegrityCheck.d.ts.map +1 -1
- package/lib/cjs/internal/IntegrityCheck.js +13 -0
- package/lib/cjs/internal/IntegrityCheck.js.map +1 -1
- package/lib/cjs/internal/NoReservations.d.ts +6 -0
- package/lib/cjs/internal/NoReservations.d.ts.map +1 -0
- package/lib/cjs/internal/NoReservations.js +21 -0
- package/lib/cjs/internal/NoReservations.js.map +1 -0
- package/lib/cjs/internal/SchemaSyncReservations.d.ts +4 -0
- package/lib/cjs/internal/SchemaSyncReservations.d.ts.map +1 -0
- package/lib/cjs/internal/SchemaSyncReservations.js +118 -0
- package/lib/cjs/internal/SchemaSyncReservations.js.map +1 -0
- package/lib/cjs/internal/Symbols.d.ts +1 -0
- package/lib/cjs/internal/Symbols.d.ts.map +1 -1
- package/lib/cjs/internal/Symbols.js +2 -1
- package/lib/cjs/internal/Symbols.js.map +1 -1
- package/lib/esm/Category.d.ts +4 -4
- package/lib/esm/Category.js.map +1 -1
- package/lib/esm/ChangesetECAdaptor.d.ts +5 -0
- package/lib/esm/ChangesetECAdaptor.d.ts.map +1 -1
- package/lib/esm/ChangesetECAdaptor.js +13 -3
- package/lib/esm/ChangesetECAdaptor.js.map +1 -1
- package/lib/esm/CodeSpecs.d.ts +3 -3
- package/lib/esm/CodeSpecs.js.map +1 -1
- package/lib/esm/DisplayStyle.d.ts +2 -2
- package/lib/esm/DisplayStyle.js.map +1 -1
- package/lib/esm/EditTxn.d.ts.map +1 -1
- package/lib/esm/EditTxn.js +1 -0
- package/lib/esm/EditTxn.js.map +1 -1
- package/lib/esm/Element.d.ts +48 -12
- package/lib/esm/Element.d.ts.map +1 -1
- package/lib/esm/Element.js +121 -25
- package/lib/esm/Element.js.map +1 -1
- package/lib/esm/IModelDb.d.ts +30 -15
- package/lib/esm/IModelDb.d.ts.map +1 -1
- package/lib/esm/IModelDb.js +52 -16
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/Model.d.ts +5 -5
- package/lib/esm/Model.d.ts.map +1 -1
- package/lib/esm/Model.js.map +1 -1
- package/lib/esm/PropertyStore.js +1 -1
- package/lib/esm/PropertyStore.js.map +1 -1
- package/lib/esm/SchemaSync.d.ts +37 -9
- package/lib/esm/SchemaSync.d.ts.map +1 -1
- package/lib/esm/SchemaSync.js +127 -8
- package/lib/esm/SchemaSync.js.map +1 -1
- package/lib/esm/SynchronousChannel.d.ts +62 -0
- package/lib/esm/SynchronousChannel.d.ts.map +1 -0
- package/lib/esm/SynchronousChannel.js +9 -0
- package/lib/esm/SynchronousChannel.js.map +1 -0
- package/lib/esm/Texture.d.ts +1 -1
- package/lib/esm/Texture.js.map +1 -1
- package/lib/esm/TxnManager.d.ts +44 -4
- package/lib/esm/TxnManager.d.ts.map +1 -1
- package/lib/esm/TxnManager.js +72 -14
- package/lib/esm/TxnManager.js.map +1 -1
- package/lib/esm/ViewDefinition.d.ts +6 -6
- package/lib/esm/ViewDefinition.d.ts.map +1 -1
- package/lib/esm/ViewDefinition.js.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.d.ts +22 -7
- package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.js +104 -36
- package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.d.ts +1 -1
- package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.js +25 -10
- package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/esm/core-backend.d.ts +1 -0
- package/lib/esm/core-backend.d.ts.map +1 -1
- package/lib/esm/core-backend.js +1 -0
- package/lib/esm/core-backend.js.map +1 -1
- package/lib/esm/internal/IntegrityCheck.d.ts +22 -0
- package/lib/esm/internal/IntegrityCheck.d.ts.map +1 -1
- package/lib/esm/internal/IntegrityCheck.js +13 -0
- package/lib/esm/internal/IntegrityCheck.js.map +1 -1
- package/lib/esm/internal/NoReservations.d.ts +6 -0
- package/lib/esm/internal/NoReservations.d.ts.map +1 -0
- package/lib/esm/internal/NoReservations.js +18 -0
- package/lib/esm/internal/NoReservations.js.map +1 -0
- package/lib/esm/internal/SchemaSyncReservations.d.ts +4 -0
- package/lib/esm/internal/SchemaSyncReservations.d.ts.map +1 -0
- package/lib/esm/internal/SchemaSyncReservations.js +115 -0
- package/lib/esm/internal/SchemaSyncReservations.js.map +1 -0
- package/lib/esm/internal/Symbols.d.ts +1 -0
- package/lib/esm/internal/Symbols.d.ts.map +1 -1
- package/lib/esm/internal/Symbols.js +1 -0
- package/lib/esm/internal/Symbols.js.map +1 -1
- package/lib/esm/test/IModelTestUtils.d.ts +1 -1
- package/lib/esm/test/IModelTestUtils.d.ts.map +1 -1
- package/lib/esm/test/IModelTestUtils.js +8 -3
- package/lib/esm/test/IModelTestUtils.js.map +1 -1
- package/lib/esm/test/annotations/LeaderGeometry.test.js +178 -2
- package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
- package/lib/esm/test/annotations/TextAnnotation.test.js +48 -18
- package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
- package/lib/esm/test/ecdb/ECSqlStatement.test.js +177 -0
- package/lib/esm/test/ecdb/ECSqlStatement.test.js.map +1 -1
- package/lib/esm/test/ecdb/QueryReaders.test.js +2 -16
- package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
- package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js +2 -2
- package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js.map +1 -1
- package/lib/esm/test/element/ElementRoundTrip.test.js +80 -2
- package/lib/esm/test/element/ElementRoundTrip.test.js.map +1 -1
- package/lib/esm/test/imodel/IModelECSql.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelECSql.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelECSql.test.js +367 -0
- package/lib/esm/test/imodel/IModelECSql.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelElements.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelElements.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelElements.test.js +969 -0
- package/lib/esm/test/imodel/IModelElements.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelGeolocation.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelGeolocation.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelGeolocation.test.js +539 -0
- package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelLifecycle.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelLifecycle.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelLifecycle.test.js +499 -0
- package/lib/esm/test/imodel/IModelLifecycle.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelMetadata.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelMetadata.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelMetadata.test.js +274 -0
- package/lib/esm/test/imodel/IModelMetadata.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelModels.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelModels.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelModels.test.js +357 -0
- package/lib/esm/test/imodel/IModelModels.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelRelationships.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelRelationships.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelRelationships.test.js +407 -0
- package/lib/esm/test/imodel/IModelRelationships.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelTestFixtures.d.ts +53 -0
- package/lib/esm/test/imodel/IModelTestFixtures.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelTestFixtures.js +107 -0
- package/lib/esm/test/imodel/IModelTestFixtures.js.map +1 -0
- package/lib/esm/test/imodel/IModelViews.test.d.ts +2 -0
- package/lib/esm/test/imodel/IModelViews.test.d.ts.map +1 -0
- package/lib/esm/test/imodel/IModelViews.test.js +199 -0
- package/lib/esm/test/imodel/IModelViews.test.js.map +1 -0
- package/lib/esm/test/index.d.ts +0 -1
- package/lib/esm/test/index.d.ts.map +1 -1
- package/lib/esm/test/index.js +0 -1
- package/lib/esm/test/index.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +8 -26
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts +2 -0
- package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts.map +1 -0
- package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js +263 -0
- package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js.map +1 -0
- package/lib/esm/test/standalone/GeometryStream.test.js +1 -3
- package/lib/esm/test/standalone/GeometryStream.test.js.map +1 -1
- package/lib/esm/test/standalone/IModelWrite.test.d.ts.map +1 -1
- package/lib/esm/test/standalone/IModelWrite.test.js +78 -1
- package/lib/esm/test/standalone/IModelWrite.test.js.map +1 -1
- package/lib/esm/test/standalone/IntegrityCheck.test.js +29 -10
- package/lib/esm/test/standalone/IntegrityCheck.test.js.map +1 -1
- package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +23 -0
- package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -1
- package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts +2 -0
- package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts.map +1 -0
- package/lib/esm/test/standalone/SchemaSyncDb.test.js +221 -0
- package/lib/esm/test/standalone/SchemaSyncDb.test.js.map +1 -0
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts +2 -0
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts.map +1 -0
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js +459 -0
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js.map +1 -0
- package/lib/esm/test/standalone/SnapshotDb.test.js +1 -0
- package/lib/esm/test/standalone/SnapshotDb.test.js.map +1 -1
- package/lib/esm/test/standalone/TxnManager.test.js +108 -8
- package/lib/esm/test/standalone/TxnManager.test.js.map +1 -1
- package/package.json +14 -17
- package/lib/esm/test/RevisionUtility.d.ts +0 -33
- package/lib/esm/test/RevisionUtility.d.ts.map +0 -1
- package/lib/esm/test/RevisionUtility.js +0 -52
- package/lib/esm/test/RevisionUtility.js.map +0 -1
- package/lib/esm/test/imodel/IModel.test.d.ts +0 -2
- package/lib/esm/test/imodel/IModel.test.d.ts.map +0 -1
- package/lib/esm/test/imodel/IModel.test.js +0 -3277
- package/lib/esm/test/imodel/IModel.test.js.map +0 -1
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { assert, expect } from "chai";
|
|
6
|
+
import { Guid, Id64, IModelStatus } from "@itwin/core-bentley";
|
|
7
|
+
import { EditTxn, withEditTxn } from "../../EditTxn";
|
|
8
|
+
import { Code, CodeScopeSpec, ColorDef, GeometryParams, GeometryStreamBuilder, ImageSourceFormat, IModel, IModelError, Rank, SubCategoryAppearance, TextureMapping, TextureMapUnits, } from "@itwin/core-common";
|
|
9
|
+
import { LineString3d, Loop, Matrix4d, Point3d, PolyfaceBuilder, StrokeOptions, YawPitchRollAngles, } from "@itwin/core-geometry";
|
|
10
|
+
import { Category, DefinitionContainer, DefinitionGroup, DefinitionModel, DefinitionPartition, DictionaryModel, Element, ElementOwnsChildElements, GenericGraphicalType2d, GeometricElement3d, GeometricModel, IModelDb, InformationPartitionElement, InformationRecordElement, LinkPartition, PhysicalElement, PhysicalModel, PhysicalObject, RenderMaterialElement, SnapshotDb, SpatialCategory, StandaloneDb, SubCategory, Subject, Texture, } from "../../core-backend";
|
|
11
|
+
import { IModelTestUtils } from "../IModelTestUtils";
|
|
12
|
+
import { TestUtils } from "../TestUtils";
|
|
13
|
+
import { samplePngTexture } from "../imageData";
|
|
14
|
+
import { EntityClass } from "@itwin/ecschema-metadata";
|
|
15
|
+
import { closeIfOpen, createIModelFromSeed, createMutableIModelTracker, importTestBim, openReadonlySeedCopy, roundtripThroughJson } from "./IModelTestFixtures";
|
|
16
|
+
describe("iModel elements", () => {
|
|
17
|
+
let testBimReadonly;
|
|
18
|
+
let compatibilityReadonly;
|
|
19
|
+
const { trackMutableIModel, closeTrackedIModels } = createMutableIModelTracker();
|
|
20
|
+
before(async () => {
|
|
21
|
+
await TestUtils.startBackend();
|
|
22
|
+
IModelTestUtils.registerTestBimSchema();
|
|
23
|
+
testBimReadonly = await openReadonlySeedCopy("elements-test.bim", "test.bim", { importTestBim: true });
|
|
24
|
+
compatibilityReadonly = await openReadonlySeedCopy("elements-CompatibilityTestSeed.bim", "CompatibilityTestSeed.bim");
|
|
25
|
+
});
|
|
26
|
+
after(() => {
|
|
27
|
+
closeIfOpen(testBimReadonly, compatibilityReadonly);
|
|
28
|
+
closeTrackedIModels();
|
|
29
|
+
});
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
closeTrackedIModels();
|
|
32
|
+
});
|
|
33
|
+
it("should be able to get properties of an iModel", () => {
|
|
34
|
+
const imodel1 = testBimReadonly;
|
|
35
|
+
expect(imodel1.name).equals("TBD"); // That's the name of the root subject!
|
|
36
|
+
const extents = imodel1.projectExtents;
|
|
37
|
+
assert(!extents.isNull);
|
|
38
|
+
// make sure we can construct a new element even if we haven't loaded its metadata (will be loaded in ctor)
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
40
|
+
assert.isUndefined(imodel1.classMetaDataRegistry.find("biscore:lightlocation"));
|
|
41
|
+
const e1 = imodel1.constructEntity({ category: "0x11", classFullName: "BisCore:LightLocation", model: "0x01", code: Code.createEmpty() });
|
|
42
|
+
assert.isDefined(e1);
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
44
|
+
assert.isDefined(imodel1.classMetaDataRegistry.find("biscore:lightlocation")); // should have been loaded in ctor
|
|
45
|
+
});
|
|
46
|
+
it("should load a known element by Id from an existing iModel", () => {
|
|
47
|
+
const imodel1 = testBimReadonly;
|
|
48
|
+
const imodel2 = trackMutableIModel(createIModelFromSeed("elements-load-known-CompatibilityTestSeed.bim", "CompatibilityTestSeed.bim"));
|
|
49
|
+
assert.exists(imodel1.elements);
|
|
50
|
+
const code1 = new Code({ spec: "0x10", scope: "0x11", value: "RF1.dgn" });
|
|
51
|
+
const el = imodel1.elements.getElement(code1);
|
|
52
|
+
assert.exists(el);
|
|
53
|
+
const el2ById = imodel1.elements.getElement("0x34");
|
|
54
|
+
assert.exists(el2ById);
|
|
55
|
+
const badCode = new Code({ spec: "0x10", scope: "0x11", value: "RF1_does_not_exist.dgn" });
|
|
56
|
+
try {
|
|
57
|
+
imodel1.elements.getElement(badCode); // throws Error
|
|
58
|
+
assert.fail(); // this line should be skipped
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
assert.instanceOf(error, Error);
|
|
62
|
+
assert.instanceOf(error, IModelError);
|
|
63
|
+
assert.equal(error.errorNumber, IModelStatus.NotFound);
|
|
64
|
+
}
|
|
65
|
+
const element1 = imodel1.elements.tryGetElement(code1);
|
|
66
|
+
const element2 = imodel1.elements.tryGetElement("0x34");
|
|
67
|
+
const element3 = imodel1.elements.tryGetElement(badCode);
|
|
68
|
+
assert.isDefined(element1);
|
|
69
|
+
assert.isDefined(element2);
|
|
70
|
+
assert.isUndefined(element3);
|
|
71
|
+
const elementProps1 = imodel1.elements.tryGetElementProps(code1);
|
|
72
|
+
const elementProps2 = imodel1.elements.tryGetElementProps("0x34");
|
|
73
|
+
const elementProps3 = imodel1.elements.tryGetElementProps(badCode);
|
|
74
|
+
assert.isDefined(elementProps1);
|
|
75
|
+
assert.isDefined(elementProps2);
|
|
76
|
+
assert.isUndefined(elementProps3);
|
|
77
|
+
const model1 = imodel1.models.tryGetModel(IModel.dictionaryId);
|
|
78
|
+
const modelProps1 = imodel1.models.tryGetModelProps(IModel.dictionaryId);
|
|
79
|
+
const subModel1 = imodel1.models.tryGetSubModel(IModel.dictionaryId);
|
|
80
|
+
assert.isDefined(model1);
|
|
81
|
+
assert.isDefined(modelProps1);
|
|
82
|
+
assert.isDefined(subModel1);
|
|
83
|
+
const badModel1 = imodel1.models.tryGetModel(Id64.fromUint32Pair(999, 999));
|
|
84
|
+
const badModelProps1 = imodel1.models.tryGetModelProps(Id64.fromUint32Pair(999, 999));
|
|
85
|
+
const badSubModel1 = imodel1.models.tryGetSubModel(IModel.rootSubjectId);
|
|
86
|
+
const badSubModel2 = imodel1.models.tryGetSubModel(badCode);
|
|
87
|
+
assert.isUndefined(badModel1);
|
|
88
|
+
assert.isUndefined(badModelProps1);
|
|
89
|
+
assert.isUndefined(badSubModel1);
|
|
90
|
+
assert.isUndefined(badSubModel2);
|
|
91
|
+
const subCat = imodel1.elements.getElement("0x2e");
|
|
92
|
+
assert.isTrue(subCat instanceof SubCategory);
|
|
93
|
+
if (subCat instanceof SubCategory) {
|
|
94
|
+
assert.isTrue(subCat.appearance.color.tbgr === 16777215);
|
|
95
|
+
assert.isTrue(subCat.appearance.weight === 2);
|
|
96
|
+
assert.equal(Id64.getLocalId(subCat.id), 46);
|
|
97
|
+
assert.equal(Id64.getBriefcaseId(subCat.id), 0);
|
|
98
|
+
assert.equal(Id64.getLocalId(subCat.code.spec), 30);
|
|
99
|
+
assert.equal(Id64.getBriefcaseId(subCat.code.spec), 0);
|
|
100
|
+
assert.isTrue(subCat.code.scope === "0x2d");
|
|
101
|
+
assert.isTrue(subCat.code.value === "A-Z013-G-Legn");
|
|
102
|
+
roundtripThroughJson(subCat);
|
|
103
|
+
}
|
|
104
|
+
/// Get the parent Category of the subcategory.
|
|
105
|
+
const cat = imodel1.elements.getElement(subCat.getCategoryId());
|
|
106
|
+
assert.isTrue(cat instanceof Category);
|
|
107
|
+
if (cat instanceof Category) {
|
|
108
|
+
assert.equal(Id64.getLocalId(cat.id), 45);
|
|
109
|
+
assert.equal(Id64.getBriefcaseId(cat.id), 0);
|
|
110
|
+
assert.isTrue(cat.description === "Legends, symbols keys");
|
|
111
|
+
assert.equal(Id64.getLocalId(cat.code.spec), 22);
|
|
112
|
+
assert.equal(Id64.getBriefcaseId(cat.code.spec), 0);
|
|
113
|
+
assert.isTrue(cat.code.value === "A-Z013-G-Legn");
|
|
114
|
+
roundtripThroughJson(cat);
|
|
115
|
+
}
|
|
116
|
+
const phys = imodel1.elements.getElement("0x38");
|
|
117
|
+
assert.isTrue(phys instanceof GeometricElement3d);
|
|
118
|
+
const locateMsg = phys.getToolTipMessage();
|
|
119
|
+
assert.isDefined(locateMsg);
|
|
120
|
+
const a2 = imodel2.elements.getElement("0x1d");
|
|
121
|
+
assert.exists(a2);
|
|
122
|
+
expect(a2.federationGuid).equal("18eb4650-b074-414f-b961-d9cfaa6c8746");
|
|
123
|
+
const el3 = imodel2.elements.getElement(a2.federationGuid);
|
|
124
|
+
assert.exists(el3);
|
|
125
|
+
assert.notEqual(a2, el3);
|
|
126
|
+
assert.equal(a2.id, el3.id);
|
|
127
|
+
roundtripThroughJson(el3);
|
|
128
|
+
const txn = new EditTxn(imodel2, "code scope mutation test");
|
|
129
|
+
txn.start();
|
|
130
|
+
const newEl = el3.toJSON();
|
|
131
|
+
newEl.federationGuid = undefined;
|
|
132
|
+
newEl.code = { scope: "bad scope", spec: "0x10", value: "new code" };
|
|
133
|
+
expect(() => txn.insertElement(newEl)).throws("invalid code scope").to.have.property("metadata");
|
|
134
|
+
newEl.code.scope = "0x34322"; // valid id, but element doesn't exist
|
|
135
|
+
expect(() => txn.insertElement(newEl)).throws("invalid code scope").to.have.property("metadata");
|
|
136
|
+
newEl.code.scope = el3.federationGuid;
|
|
137
|
+
const newId = txn.insertElement(newEl); // code scope from FederationGuid should get converted to ElementId
|
|
138
|
+
const a4 = imodel2.elements.getElementProps(newId);
|
|
139
|
+
expect(a4.code.scope).equal(el3.id);
|
|
140
|
+
a4.code.scope = "0x13343";
|
|
141
|
+
expect(() => txn.updateElement(a4)).throws("invalid code scope").to.have.property("metadata");
|
|
142
|
+
a4.code.scope = "0x1";
|
|
143
|
+
txn.updateElement(a4); // should change the code scope to new element
|
|
144
|
+
let a5 = imodel2.elements.getElementProps(newId);
|
|
145
|
+
expect(a5.code.scope).equal("0x1");
|
|
146
|
+
// only pass minimum, but expect model and classFullName to be added.
|
|
147
|
+
const newProps = { id: a4.id, code: a4.code, classFullName: undefined, model: undefined };
|
|
148
|
+
newProps.code.scope = el3.federationGuid; // should convert FederationGuid to ElementId
|
|
149
|
+
txn.updateElement(newProps);
|
|
150
|
+
expect(newProps.classFullName).eq(a4.classFullName);
|
|
151
|
+
expect(newProps.model).eq(a4.model);
|
|
152
|
+
a5 = imodel2.elements.getElementProps(newId);
|
|
153
|
+
expect(a5.code.scope).equal(el3.id);
|
|
154
|
+
txn.end();
|
|
155
|
+
});
|
|
156
|
+
it("should optionally detect class mismatches", () => {
|
|
157
|
+
const imodel1 = testBimReadonly;
|
|
158
|
+
// tryGetElement
|
|
159
|
+
const subjectUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId);
|
|
160
|
+
assert.isDefined(subjectUnvalidated);
|
|
161
|
+
const subjectValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, Subject);
|
|
162
|
+
assert.isDefined(subjectValidated);
|
|
163
|
+
const physicalElementUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId);
|
|
164
|
+
assert.isDefined(physicalElementUnvalidated); // wrong type, but class to validate was not passed
|
|
165
|
+
const physicalElementValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, PhysicalElement); // abstract class
|
|
166
|
+
assert.isUndefined(physicalElementValidated); // wrong type
|
|
167
|
+
const physicalObjectUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId);
|
|
168
|
+
assert.isDefined(physicalObjectUnvalidated); // wrong type, but class to validate was not passed
|
|
169
|
+
const physicalObjectValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, PhysicalObject); // concrete class
|
|
170
|
+
assert.isUndefined(physicalObjectValidated); // wrong type
|
|
171
|
+
// tryGetModel
|
|
172
|
+
const dictionaryUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId);
|
|
173
|
+
assert.isDefined(dictionaryUnvalidated);
|
|
174
|
+
const dictionaryValidated = imodel1.models.tryGetModel(IModel.dictionaryId, DictionaryModel);
|
|
175
|
+
assert.isDefined(dictionaryValidated);
|
|
176
|
+
const geometricModelUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId);
|
|
177
|
+
assert.isDefined(geometricModelUnvalidated); // wrong type, but class to validate was not passed
|
|
178
|
+
const geometricModelValidated = imodel1.models.tryGetModel(IModel.dictionaryId, GeometricModel); // abstract class
|
|
179
|
+
assert.isUndefined(geometricModelValidated); // wrong type
|
|
180
|
+
const physicalModelUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId);
|
|
181
|
+
assert.isDefined(physicalModelUnvalidated); // wrong type, but class to validate was not passed
|
|
182
|
+
const physicalModelValidated = imodel1.models.tryGetModel(IModel.dictionaryId, PhysicalModel); // concrete class
|
|
183
|
+
assert.isUndefined(physicalModelValidated); // wrong type
|
|
184
|
+
// tryGetSubModel
|
|
185
|
+
const dictionarySubUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId);
|
|
186
|
+
assert.isDefined(dictionarySubUnvalidated);
|
|
187
|
+
const dictionarySubValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, DictionaryModel);
|
|
188
|
+
assert.isDefined(dictionarySubValidated);
|
|
189
|
+
const geometricSubModelUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId);
|
|
190
|
+
assert.isDefined(geometricSubModelUnvalidated); // wrong type, but class to validate was not passed
|
|
191
|
+
const geometricSubModelValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, GeometricModel); // abstract class
|
|
192
|
+
assert.isUndefined(geometricSubModelValidated); // wrong type
|
|
193
|
+
const physicalSubModelUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId);
|
|
194
|
+
assert.isDefined(physicalSubModelUnvalidated); // wrong type, but class to validate was not passed
|
|
195
|
+
const physicalSubModelValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, PhysicalModel); // concrete class
|
|
196
|
+
assert.isUndefined(physicalSubModelValidated); // wrong type
|
|
197
|
+
});
|
|
198
|
+
it("should create elements", () => {
|
|
199
|
+
const imodel2 = trackMutableIModel(createIModelFromSeed("elements-create-CompatibilityTestSeed.bim", "CompatibilityTestSeed.bim"));
|
|
200
|
+
const seedElement = imodel2.elements.getElement("0x1d");
|
|
201
|
+
assert.exists(seedElement);
|
|
202
|
+
assert.isTrue(seedElement.federationGuid === "18eb4650-b074-414f-b961-d9cfaa6c8746");
|
|
203
|
+
withEditTxn(imodel2, (txn) => {
|
|
204
|
+
for (let i = 0; i < 25; i++) {
|
|
205
|
+
const elementProps = {
|
|
206
|
+
classFullName: "Generic:PhysicalObject",
|
|
207
|
+
model: seedElement.model,
|
|
208
|
+
category: seedElement.category,
|
|
209
|
+
code: Code.createEmpty(),
|
|
210
|
+
federationGuid: Guid.createValue(),
|
|
211
|
+
userLabel: `UserLabel-${i}`,
|
|
212
|
+
};
|
|
213
|
+
const element = imodel2.elements.createElement(elementProps);
|
|
214
|
+
element.setUserProperties("performanceTest", { s: `String-${i}`, n: i });
|
|
215
|
+
const elementId = txn.insertElement(element.toJSON());
|
|
216
|
+
assert.isTrue(Id64.isValidId64(elementId));
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
it("should insert a RenderMaterial", () => {
|
|
221
|
+
const imodel2 = trackMutableIModel(createIModelFromSeed("elements-render-material-CompatibilityTestSeed.bim", "CompatibilityTestSeed.bim"));
|
|
222
|
+
const model = imodel2.models.getModel(IModel.dictionaryId);
|
|
223
|
+
expect(model).not.to.be.undefined;
|
|
224
|
+
const testMaterialName = "test material name";
|
|
225
|
+
const testPaletteName = "test palette name";
|
|
226
|
+
const testDescription = "test description";
|
|
227
|
+
const color = [0.3, 0.7, 0.8];
|
|
228
|
+
const specularColor = [0.1, 1, 0];
|
|
229
|
+
const finish = 0.4;
|
|
230
|
+
const transmit = 0.1;
|
|
231
|
+
const diffuse = 0.24;
|
|
232
|
+
const specular = 0.9;
|
|
233
|
+
const reflect = 0.3;
|
|
234
|
+
const reflectColor = [1, 0, 0.5];
|
|
235
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
236
|
+
const textureMapProps = {
|
|
237
|
+
pattern_angle: 3.0,
|
|
238
|
+
pattern_u_flip: false,
|
|
239
|
+
pattern_flip: false,
|
|
240
|
+
pattern_scale: [1.0, 1.0],
|
|
241
|
+
pattern_offset: [0.0, 0.0],
|
|
242
|
+
pattern_scalemode: TextureMapUnits.Inches,
|
|
243
|
+
pattern_mapping: TextureMapping.Mode.Planar,
|
|
244
|
+
pattern_weight: 0.5,
|
|
245
|
+
TextureId: "test_textureid",
|
|
246
|
+
};
|
|
247
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
248
|
+
const renderMaterialParams = {
|
|
249
|
+
paletteName: testPaletteName,
|
|
250
|
+
description: testDescription,
|
|
251
|
+
color,
|
|
252
|
+
specularColor,
|
|
253
|
+
finish,
|
|
254
|
+
transmit,
|
|
255
|
+
diffuse,
|
|
256
|
+
specular,
|
|
257
|
+
reflect,
|
|
258
|
+
reflectColor,
|
|
259
|
+
patternMap: textureMapProps,
|
|
260
|
+
};
|
|
261
|
+
const renderMaterialId = withEditTxn(imodel2, (txn) => RenderMaterialElement.insert(txn, IModel.dictionaryId, testMaterialName, renderMaterialParams));
|
|
262
|
+
const renderMaterial = imodel2.elements.getElement(renderMaterialId);
|
|
263
|
+
assert((renderMaterial instanceof RenderMaterialElement) === true, "did not retrieve an instance of RenderMaterial");
|
|
264
|
+
expect(renderMaterial.paletteName).to.equal(testPaletteName);
|
|
265
|
+
expect(renderMaterial.description).to.equal(testDescription);
|
|
266
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasBaseColor).to.equal(true);
|
|
267
|
+
expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.color)).to.equal(JSON.stringify(color));
|
|
268
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasSpecularColor).to.equal(true);
|
|
269
|
+
expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.specular_color)).to.equal(JSON.stringify(specularColor));
|
|
270
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasFinish).to.equal(true);
|
|
271
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.finish).to.equal(finish);
|
|
272
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasTransmit).to.equal(true);
|
|
273
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.transmit).to.equal(transmit);
|
|
274
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasDiffuse).to.equal(true);
|
|
275
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.diffuse).to.equal(diffuse);
|
|
276
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasSpecular).to.equal(true);
|
|
277
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.specular).to.equal(specular);
|
|
278
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasReflect).to.equal(true);
|
|
279
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.reflect).to.equal(reflect);
|
|
280
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasReflectColor).to.equal(true);
|
|
281
|
+
expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.reflect_color)).to.equal(JSON.stringify(reflectColor));
|
|
282
|
+
expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.Map).not.to.be.undefined;
|
|
283
|
+
const patternMap = renderMaterial.jsonProperties.materialAssets.renderMaterial.Map.Pattern;
|
|
284
|
+
expect(patternMap).not.to.be.undefined;
|
|
285
|
+
expect(patternMap.pattern_angle).to.equal(textureMapProps.pattern_angle);
|
|
286
|
+
expect(patternMap.pattern_u_flip).to.equal(textureMapProps.pattern_u_flip);
|
|
287
|
+
expect(patternMap.pattern_flip).to.equal(textureMapProps.pattern_flip);
|
|
288
|
+
expect(JSON.stringify(patternMap.pattern_scale)).to.equal(JSON.stringify(textureMapProps.pattern_scale));
|
|
289
|
+
expect(JSON.stringify(patternMap.pattern_offset)).to.equal(JSON.stringify(textureMapProps.pattern_offset));
|
|
290
|
+
expect(patternMap.pattern_scalemode).to.equal(textureMapProps.pattern_scalemode);
|
|
291
|
+
expect(patternMap.pattern_mapping).to.equal(textureMapProps.pattern_mapping);
|
|
292
|
+
expect(patternMap.pattern_weight).to.equal(textureMapProps.pattern_weight);
|
|
293
|
+
expect(patternMap.TextureId).to.equal(textureMapProps.TextureId);
|
|
294
|
+
});
|
|
295
|
+
it("attempt to apply material to new element in imodel5", () => {
|
|
296
|
+
const imodel5 = trackMutableIModel(createIModelFromSeed("elements-mirukuru.ibim", "mirukuru.ibim"));
|
|
297
|
+
const testTextureName = "fake texture name";
|
|
298
|
+
const testTextureFormat = ImageSourceFormat.Png;
|
|
299
|
+
const testTextureDescription = "empty description";
|
|
300
|
+
const txn = new EditTxn(imodel5, "apply material to new element");
|
|
301
|
+
txn.start();
|
|
302
|
+
const texId = Texture.insertTexture(txn, IModel.dictionaryId, testTextureName, testTextureFormat, samplePngTexture.base64, testTextureDescription);
|
|
303
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
304
|
+
const matId = RenderMaterialElement.insert(txn, IModel.dictionaryId, "test material name", {
|
|
305
|
+
paletteName: "TestPaletteName",
|
|
306
|
+
patternMap: {
|
|
307
|
+
TextureId: texId,
|
|
308
|
+
pattern_offset: [0, 0],
|
|
309
|
+
pattern_scale: [1, 1],
|
|
310
|
+
pattern_scalemode: TextureMapUnits.Relative,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
314
|
+
/** Create a simple flat mesh with 4 points (2x2) */
|
|
315
|
+
const width = imodel5.projectExtents.xLength() * 0.2;
|
|
316
|
+
const height = imodel5.projectExtents.yLength() * 0.2;
|
|
317
|
+
let shape;
|
|
318
|
+
const doPolyface = true;
|
|
319
|
+
if (doPolyface) {
|
|
320
|
+
const options = StrokeOptions.createForFacets();
|
|
321
|
+
options.shouldTriangulate = false;
|
|
322
|
+
const builder = PolyfaceBuilder.create(options);
|
|
323
|
+
const quad = [
|
|
324
|
+
Point3d.create(0.0, 0.0, 0.0),
|
|
325
|
+
Point3d.create(width, 0.0, 0.0),
|
|
326
|
+
Point3d.create(width, height, 0.0),
|
|
327
|
+
Point3d.create(0.0, height, 0.0),
|
|
328
|
+
];
|
|
329
|
+
builder.addQuadFacet(quad);
|
|
330
|
+
shape = builder.claimPolyface();
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
shape = Loop.create(LineString3d.create([
|
|
334
|
+
Point3d.create(0, 0, 0),
|
|
335
|
+
Point3d.create(width, 0, 0),
|
|
336
|
+
Point3d.create(width, height, 0),
|
|
337
|
+
Point3d.create(0, height, 0),
|
|
338
|
+
Point3d.create(0, 0, 0),
|
|
339
|
+
]));
|
|
340
|
+
}
|
|
341
|
+
const modelId = PhysicalModel.insert(txn, IModelDb.rootSubjectId, "test_render_material_model_name");
|
|
342
|
+
const categoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "GeoJSON Feature", { color: ColorDef.white.toJSON() });
|
|
343
|
+
/** generate a geometry stream containing the polyface */
|
|
344
|
+
const gsBuilder = new GeometryStreamBuilder();
|
|
345
|
+
const params = new GeometryParams(categoryId);
|
|
346
|
+
params.materialId = matId;
|
|
347
|
+
gsBuilder.appendGeometryParamsChange(params);
|
|
348
|
+
gsBuilder.appendGeometry(shape);
|
|
349
|
+
const geometry = gsBuilder.geometryStream;
|
|
350
|
+
// geometry[0].material = { materialId: matId };
|
|
351
|
+
const props = {
|
|
352
|
+
classFullName: "Generic:PhysicalObject",
|
|
353
|
+
placement: { origin: imodel5.projectExtents.center, angles: new YawPitchRollAngles() },
|
|
354
|
+
model: modelId,
|
|
355
|
+
code: Code.createEmpty(),
|
|
356
|
+
category: categoryId,
|
|
357
|
+
geom: geometry,
|
|
358
|
+
};
|
|
359
|
+
txn.insertElement(props);
|
|
360
|
+
txn.end();
|
|
361
|
+
});
|
|
362
|
+
it("should have a valid root subject element", () => {
|
|
363
|
+
const imodel1 = testBimReadonly;
|
|
364
|
+
const rootSubject = imodel1.elements.getRootSubject();
|
|
365
|
+
assert.exists(rootSubject);
|
|
366
|
+
assert.isTrue(rootSubject instanceof Subject);
|
|
367
|
+
assert.isAtLeast(rootSubject.code.value.length, 1);
|
|
368
|
+
assert.isFalse(imodel1.elements.hasSubModel(IModel.rootSubjectId));
|
|
369
|
+
try {
|
|
370
|
+
imodel1.models.getSubModel(rootSubject.id); // throws error
|
|
371
|
+
assert.fail(); // this line should be skipped
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
assert.isTrue(error instanceof Error);
|
|
375
|
+
assert.isTrue(error instanceof IModelError);
|
|
376
|
+
assert.equal(error.errorNumber, IModelStatus.NotFound);
|
|
377
|
+
}
|
|
378
|
+
const childIds = imodel1.elements.queryChildren(rootSubject.id);
|
|
379
|
+
assert.isAtLeast(childIds.length, 1);
|
|
380
|
+
for (const childId of childIds) {
|
|
381
|
+
const childElement = imodel1.elements.getElement(childId);
|
|
382
|
+
assert.exists(childElement);
|
|
383
|
+
assert.isTrue(childElement instanceof Element);
|
|
384
|
+
roundtripThroughJson(childElement);
|
|
385
|
+
assert.equal(rootSubject.id, childElement.parent.id);
|
|
386
|
+
const childLocalId = Id64.getLocalId(childId);
|
|
387
|
+
const childBcId = Id64.getBriefcaseId(childId);
|
|
388
|
+
if (childElement instanceof InformationPartitionElement) {
|
|
389
|
+
assert.isTrue(imodel1.elements.hasSubModel(childElement.id));
|
|
390
|
+
const childSubModel = imodel1.models.getSubModel(childElement.id);
|
|
391
|
+
assert.exists(childSubModel, "InformationPartitionElements should have a subModel");
|
|
392
|
+
if (childLocalId === 16 && childBcId === 0) {
|
|
393
|
+
assert.isTrue(childElement instanceof DefinitionPartition, "ChildId 0x00000010 should be a DefinitionPartition");
|
|
394
|
+
assert.isTrue(childElement.code.value === "BisCore.DictionaryModel", "Definition Partition should have code value of BisCore.DictionaryModel");
|
|
395
|
+
}
|
|
396
|
+
else if (childLocalId === 14 && childBcId === 0) {
|
|
397
|
+
assert.isTrue(childElement instanceof LinkPartition);
|
|
398
|
+
assert.isTrue(childElement.code.value === "BisCore.RealityDataSources");
|
|
399
|
+
}
|
|
400
|
+
else if (childLocalId === 17 && childBcId === 0) {
|
|
401
|
+
assert.isTrue(childElement instanceof LinkPartition, "ChildId 0x000000011 should be a LinkPartition");
|
|
402
|
+
assert.isTrue(childElement.code.value === "Repository Links");
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
else if (childElement instanceof Subject) {
|
|
406
|
+
assert.isFalse(imodel1.elements.hasSubModel(childElement.id));
|
|
407
|
+
if (childLocalId === 19 && childBcId === 0) {
|
|
408
|
+
assert.isTrue(childElement instanceof Subject);
|
|
409
|
+
assert.isTrue(childElement.code.value === "DgnV8:mf3, A", "Subject should have code value of DgnV8:mf3, A");
|
|
410
|
+
assert.isTrue(childElement.jsonProperties.Subject.Job.DgnV8.V8File === "mf3.dgn", "Subject should have jsonProperty Subject.Job.DgnV.V8File");
|
|
411
|
+
assert.isTrue(childElement.jsonProperties.Subject.Job.DgnV8.V8RootModel === "A", "Subject should have jsonProperty Subject.Job.DgnV.V8RootModel");
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
it("should insert and update auto-handled properties", () => {
|
|
417
|
+
const imodel4 = trackMutableIModel(createIModelFromSeed("elements-auto-handled-array.bim", "GetSetAutoHandledArrayProperties.bim"));
|
|
418
|
+
const testElem = imodel4.elements.getElement("0x14");
|
|
419
|
+
assert.isDefined(testElem);
|
|
420
|
+
assert.equal(testElem.classFullName, "DgnPlatformTest:TestElementWithNoHandler");
|
|
421
|
+
assert.isUndefined(testElem.asAny.integerProperty1);
|
|
422
|
+
const newTestElem = roundtripThroughJson(testElem);
|
|
423
|
+
assert.equal(newTestElem.classFullName, testElem.classFullName);
|
|
424
|
+
newTestElem.asAny.integerProperty1 = 999;
|
|
425
|
+
assert.isTrue(testElem.asAny.arrayOfPoint3d[0].isAlmostEqual(newTestElem.asAny.arrayOfPoint3d[0]));
|
|
426
|
+
const loc1 = { street: "Elm Street", city: { name: "Downingtown", state: "PA" } };
|
|
427
|
+
const loc2 = { street: "Oak Street", city: { name: "Downingtown", state: "PA" } };
|
|
428
|
+
const loc3 = { street: "Chestnut Street", city: { name: "Philadelphia", state: "PA" } };
|
|
429
|
+
const arrayOfStructs = [loc2, loc3];
|
|
430
|
+
newTestElem.asAny.location = loc1;
|
|
431
|
+
newTestElem.asAny.arrayOfStructs = arrayOfStructs;
|
|
432
|
+
newTestElem.asAny.dtUtc = new Date("2015-03-25");
|
|
433
|
+
newTestElem.asAny.p3d = new Point3d(1, 2, 3);
|
|
434
|
+
const txn = new EditTxn(imodel4, "insert and update auto-handled properties");
|
|
435
|
+
txn.start();
|
|
436
|
+
const newTestElemId = txn.insertElement(newTestElem.toJSON());
|
|
437
|
+
assert.isTrue(Id64.isValidId64(newTestElemId), "insert worked");
|
|
438
|
+
const newTestElemFetched = imodel4.elements.getElement(newTestElemId);
|
|
439
|
+
assert.isDefined(newTestElemFetched);
|
|
440
|
+
assert.isTrue(newTestElemFetched.id === newTestElemId);
|
|
441
|
+
assert.equal(newTestElemFetched.classFullName, newTestElem.classFullName);
|
|
442
|
+
assert.isDefined(newTestElemFetched.asAny.integerProperty1);
|
|
443
|
+
assert.equal(newTestElemFetched.asAny.integerProperty1, newTestElem.asAny.integerProperty1);
|
|
444
|
+
assert.isTrue(newTestElemFetched.asAny.arrayOfPoint3d[0].isAlmostEqual(newTestElem.asAny.arrayOfPoint3d[0]));
|
|
445
|
+
assert.deepEqual(newTestElemFetched.asAny.location, loc1);
|
|
446
|
+
assert.deepEqual(newTestElem.asAny.arrayOfStructs, arrayOfStructs);
|
|
447
|
+
// TODO: getElement must convert date ISO string to Date object assert.deepEqual(newTestElemFetched.dtUtc, newTestElem.dtUtc);
|
|
448
|
+
assert.deepEqual(newTestElemFetched.asAny.dtUtc, newTestElem.asAny.dtUtc.toJSON());
|
|
449
|
+
assert.isTrue(newTestElemFetched.asAny.p3d.isAlmostEqual(newTestElem.asAny.p3d));
|
|
450
|
+
// ----------- updates ----------------
|
|
451
|
+
const wasp3d = newTestElemFetched.asAny.p3d;
|
|
452
|
+
const editElem = newTestElemFetched;
|
|
453
|
+
editElem.asAny.location = loc2;
|
|
454
|
+
try {
|
|
455
|
+
txn.updateElement(editElem.toJSON());
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
assert.fail("Element.update failed");
|
|
459
|
+
}
|
|
460
|
+
const afterUpdateElemFetched = imodel4.elements.getElement(editElem.id);
|
|
461
|
+
assert.deepEqual(afterUpdateElemFetched.asAny.location, loc2, " location property should be the new one");
|
|
462
|
+
assert.deepEqual(afterUpdateElemFetched.asAny.id, editElem.id, " the id should not have changed.");
|
|
463
|
+
assert.deepEqual(afterUpdateElemFetched.asAny.p3d, wasp3d, " p3d property should not have changed");
|
|
464
|
+
// Make array shorter
|
|
465
|
+
assert.equal(afterUpdateElemFetched.asAny.arrayOfInt.length, 300);
|
|
466
|
+
afterUpdateElemFetched.asAny.arrayOfInt = [99, 3];
|
|
467
|
+
txn.updateElement(afterUpdateElemFetched.toJSON());
|
|
468
|
+
const afterShortenArray = imodel4.elements.getElement(afterUpdateElemFetched.id);
|
|
469
|
+
assert.equal(afterShortenArray.asAny.arrayOfInt.length, 2);
|
|
470
|
+
assert.deepEqual(afterShortenArray.asAny.arrayOfInt, [99, 3]);
|
|
471
|
+
// Make array longer
|
|
472
|
+
afterShortenArray.asAny.arrayOfInt = [1, 2, 3];
|
|
473
|
+
txn.updateElement(afterShortenArray.toJSON());
|
|
474
|
+
const afterLengthenArray = imodel4.elements.getElement(afterShortenArray.id);
|
|
475
|
+
assert.equal(afterLengthenArray.asAny.arrayOfInt.length, 3);
|
|
476
|
+
assert.deepEqual(afterLengthenArray.asAny.arrayOfInt, [1, 2, 3]);
|
|
477
|
+
// ------------ delete -----------------
|
|
478
|
+
const elid = afterUpdateElemFetched.id;
|
|
479
|
+
txn.deleteElement(elid);
|
|
480
|
+
assert.throws(() => imodel4.elements.getElement(elid), IModelError);
|
|
481
|
+
txn.end();
|
|
482
|
+
});
|
|
483
|
+
it("should handle parent and child deletion properly", () => {
|
|
484
|
+
const imodel4 = trackMutableIModel(createIModelFromSeed("elements-parent-child-array.bim", "GetSetAutoHandledArrayProperties.bim"));
|
|
485
|
+
const txn = new EditTxn(imodel4, "handle parent and child deletion");
|
|
486
|
+
txn.start();
|
|
487
|
+
const categoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "MyTestCategory", new SubCategoryAppearance());
|
|
488
|
+
const category = imodel4.elements.getElement(categoryId);
|
|
489
|
+
const subCategory = imodel4.elements.getElement(category.myDefaultSubCategoryId());
|
|
490
|
+
expect(() => txn.deleteElement(categoryId)).throws("error deleting element").to.have.property("metadata");
|
|
491
|
+
assert.exists(imodel4.elements.getElement(categoryId), "Category deletes should be blocked in native code");
|
|
492
|
+
assert.exists(imodel4.elements.getElement(subCategory.id), "Children should not be deleted if parent delete is blocked");
|
|
493
|
+
const modelId = PhysicalModel.insert(txn, IModel.rootSubjectId, "MyTestPhysicalModel");
|
|
494
|
+
const elementProps = {
|
|
495
|
+
classFullName: PhysicalObject.classFullName,
|
|
496
|
+
model: modelId,
|
|
497
|
+
category: categoryId,
|
|
498
|
+
code: Code.createEmpty(),
|
|
499
|
+
};
|
|
500
|
+
const parentId = txn.insertElement(elementProps);
|
|
501
|
+
elementProps.parent = new ElementOwnsChildElements(parentId);
|
|
502
|
+
const childId1 = txn.insertElement(elementProps);
|
|
503
|
+
const childId2 = txn.insertElement(elementProps);
|
|
504
|
+
assert.exists(imodel4.elements.getElement(parentId));
|
|
505
|
+
assert.exists(imodel4.elements.getElement(childId1));
|
|
506
|
+
assert.exists(imodel4.elements.getElement(childId2));
|
|
507
|
+
txn.deleteElement(parentId);
|
|
508
|
+
assert.throws(() => imodel4.elements.getElement(parentId), IModelError);
|
|
509
|
+
assert.throws(() => imodel4.elements.getElement(childId1), IModelError);
|
|
510
|
+
assert.throws(() => imodel4.elements.getElement(childId2), IModelError);
|
|
511
|
+
txn.end();
|
|
512
|
+
});
|
|
513
|
+
it("snapping", async () => {
|
|
514
|
+
const imodel2 = compatibilityReadonly;
|
|
515
|
+
const worldToView = Matrix4d.createIdentity();
|
|
516
|
+
const response = await imodel2.requestSnap("0x222", { testPoint: { x: 1, y: 2, z: 3 }, closePoint: { x: 1, y: 2, z: 3 }, id: "0x111", worldToView: worldToView.toJSON() });
|
|
517
|
+
assert.isDefined(response.status);
|
|
518
|
+
});
|
|
519
|
+
describe("DefinitionSet.rank", () => {
|
|
520
|
+
function setRank(iModelDb, id, className, rank) {
|
|
521
|
+
withEditTxn(iModelDb, (txn) => txn.updateElement({ id, classFullName: className, rank }));
|
|
522
|
+
}
|
|
523
|
+
function createRankTestDb(fileName, subjectName) {
|
|
524
|
+
const iModelFileName = IModelTestUtils.prepareOutputFile("IModel", fileName);
|
|
525
|
+
return trackMutableIModel(StandaloneDb.createEmpty(iModelFileName, { rootSubject: { name: subjectName } }));
|
|
526
|
+
}
|
|
527
|
+
it("should insert, update, read and serialize rank", () => {
|
|
528
|
+
const iModelDb = createRankTestDb("DefinitionSetRank.bim", "DefinitionSetRank");
|
|
529
|
+
const containerId = withEditTxn(iModelDb, (txn) => DefinitionContainer.insert(txn, IModel.dictionaryId, Code.createEmpty()));
|
|
530
|
+
const groupId = withEditTxn(iModelDb, (txn) => DefinitionGroup.create(iModelDb, IModel.dictionaryId, Code.createEmpty()).insert(txn));
|
|
531
|
+
// Freshly inserted DefinitionSets have no rank persisted.
|
|
532
|
+
assert.isUndefined(iModelDb.elements.getElementProps(containerId).rank);
|
|
533
|
+
assert.isUndefined(iModelDb.elements.getElement(containerId).rank);
|
|
534
|
+
setRank(iModelDb, containerId, DefinitionContainer.classFullName, Rank.Application);
|
|
535
|
+
setRank(iModelDb, groupId, DefinitionGroup.classFullName, Rank.Domain);
|
|
536
|
+
const containerProps = iModelDb.elements.getElementProps(containerId);
|
|
537
|
+
assert.equal(containerProps.rank, Rank.Application);
|
|
538
|
+
const container = iModelDb.elements.getElement(containerId);
|
|
539
|
+
assert.equal(container.rank, Rank.Application);
|
|
540
|
+
assert.equal(container.toJSON().rank, Rank.Application);
|
|
541
|
+
const group = iModelDb.elements.getElement(groupId);
|
|
542
|
+
assert.equal(group.rank, Rank.Domain);
|
|
543
|
+
assert.equal(group.toJSON().rank, Rank.Domain);
|
|
544
|
+
});
|
|
545
|
+
it("should serialize/deserialize DefinitionSet.rank via DefinitionSet.serialize/deserialize", () => {
|
|
546
|
+
const iModelDb = createRankTestDb("DefinitionSetRankSerialize.bim", "DefinitionSetRankSerialize");
|
|
547
|
+
const props = {
|
|
548
|
+
classFullName: DefinitionContainer.classFullName,
|
|
549
|
+
model: IModel.dictionaryId,
|
|
550
|
+
code: Code.createEmpty(),
|
|
551
|
+
rank: Rank.User,
|
|
552
|
+
};
|
|
553
|
+
const row = DefinitionContainer.serialize(props, iModelDb);
|
|
554
|
+
assert.equal(row.rank, Rank.User);
|
|
555
|
+
const propsWithoutRank = {
|
|
556
|
+
classFullName: DefinitionContainer.classFullName,
|
|
557
|
+
model: IModel.dictionaryId,
|
|
558
|
+
code: Code.createEmpty(),
|
|
559
|
+
};
|
|
560
|
+
const rowWithoutRank = DefinitionContainer.serialize(propsWithoutRank, iModelDb);
|
|
561
|
+
assert.isUndefined(rowWithoutRank.rank);
|
|
562
|
+
});
|
|
563
|
+
it("should insert a DefinitionContainer with rank property", () => {
|
|
564
|
+
const iModelDb = createRankTestDb("DefinitionContainerRank.bim", "DefinitionContainerRank");
|
|
565
|
+
const containerId = withEditTxn(iModelDb, (txn) => {
|
|
566
|
+
const containerProps = {
|
|
567
|
+
classFullName: DefinitionContainer.classFullName,
|
|
568
|
+
model: IModel.dictionaryId,
|
|
569
|
+
code: Code.createEmpty(),
|
|
570
|
+
rank: Rank.Application,
|
|
571
|
+
};
|
|
572
|
+
return txn.insertElement(containerProps);
|
|
573
|
+
});
|
|
574
|
+
const inserted = iModelDb.elements.getElementProps(containerId);
|
|
575
|
+
assert.equal(inserted.rank, Rank.Application);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
it("should set EC properties of various types", async () => {
|
|
579
|
+
const testImodel = trackMutableIModel(await importTestBim(createIModelFromSeed("elements-ec-properties.bim", "test.bim")));
|
|
580
|
+
assert.doesNotThrow(() => testImodel.schemaContext.getSchemaItemSync("TestBim:TestPhysicalObject", EntityClass), "TestPhysicalObject is expected to be defined in TestBim.ecschema.xml");
|
|
581
|
+
const txn = new EditTxn(testImodel, "set EC properties of various types");
|
|
582
|
+
txn.start();
|
|
583
|
+
// Create a new physical model
|
|
584
|
+
const [, newModelId] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(txn, Code.createEmpty(), true);
|
|
585
|
+
// Find or create a SpatialCategory
|
|
586
|
+
let spatialCategoryId = SpatialCategory.queryCategoryIdByName(testImodel, IModel.dictionaryId, "MySpatialCategory");
|
|
587
|
+
if (undefined === spatialCategoryId) {
|
|
588
|
+
spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "MySpatialCategory", new SubCategoryAppearance());
|
|
589
|
+
}
|
|
590
|
+
const trelClassName = "TestBim:TestPhysicalObjectRelatedToTestPhysicalObject";
|
|
591
|
+
let id1;
|
|
592
|
+
let id2;
|
|
593
|
+
if (true) {
|
|
594
|
+
// Create a couple of TestPhysicalObjects
|
|
595
|
+
const elementProps = {
|
|
596
|
+
classFullName: "TestBim:TestPhysicalObject",
|
|
597
|
+
model: newModelId,
|
|
598
|
+
category: spatialCategoryId,
|
|
599
|
+
code: Code.createEmpty(),
|
|
600
|
+
};
|
|
601
|
+
id1 = txn.insertElement(testImodel.elements.createElement(elementProps).toJSON());
|
|
602
|
+
assert.isTrue(Id64.isValidId64(id1));
|
|
603
|
+
// The second one should point to the first.
|
|
604
|
+
elementProps.id = Id64.invalid;
|
|
605
|
+
elementProps.relatedElement = { id: id1, relClassName: trelClassName };
|
|
606
|
+
elementProps.parent = { id: id1, relClassName: trelClassName };
|
|
607
|
+
elementProps.longProp = 4294967295; // make sure that we can save values in the range 0 ... UINT_MAX
|
|
608
|
+
id2 = txn.insertElement(testImodel.elements.createElement(elementProps).toJSON());
|
|
609
|
+
assert.isTrue(Id64.isValidId64(id2));
|
|
610
|
+
}
|
|
611
|
+
if (true) {
|
|
612
|
+
// Test that el2 points to el1
|
|
613
|
+
const el2 = testImodel.elements.getElement(id2);
|
|
614
|
+
assert.equal(el2.classFullName, "TestBim:TestPhysicalObject");
|
|
615
|
+
assert.isTrue("relatedElement" in el2);
|
|
616
|
+
assert.isTrue("id" in el2.asAny.relatedElement);
|
|
617
|
+
assert.deepEqual(el2.asAny.relatedElement.id, id1);
|
|
618
|
+
assert.equal(el2.asAny.longProp, 4294967295);
|
|
619
|
+
// Even though I didn't set it, the platform knows the relationship class and reports it.
|
|
620
|
+
assert.isTrue("relClassName" in el2.asAny.relatedElement);
|
|
621
|
+
assert.equal(el2.asAny.relatedElement.relClassName.replace(".", ":"), trelClassName);
|
|
622
|
+
}
|
|
623
|
+
if (true) {
|
|
624
|
+
// Change el2 to point to itself.
|
|
625
|
+
const el2Modified = testImodel.elements.getElement(id2);
|
|
626
|
+
el2Modified.asAny.relatedElement = { id: id2, relClassName: trelClassName };
|
|
627
|
+
txn.updateElement(el2Modified.toJSON());
|
|
628
|
+
// Test that el2 points to itself.
|
|
629
|
+
const el2after = testImodel.elements.getElement(id2);
|
|
630
|
+
assert.deepEqual(el2after.asAny.relatedElement.id, id2);
|
|
631
|
+
assert.equal(el2after.asAny.relatedElement.relClassName.replace(".", ":"), trelClassName);
|
|
632
|
+
}
|
|
633
|
+
if (true) {
|
|
634
|
+
// Test that we can null out the navigation property
|
|
635
|
+
const el2Modified = testImodel.elements.getElement(id2);
|
|
636
|
+
el2Modified.asAny.relatedElement = null;
|
|
637
|
+
txn.updateElement(el2Modified.toJSON());
|
|
638
|
+
// Test that el2 has no relatedElement property value
|
|
639
|
+
const el2after = testImodel.elements.getElement(id2);
|
|
640
|
+
assert.isUndefined(el2after.asAny.relatedElement);
|
|
641
|
+
}
|
|
642
|
+
txn.end();
|
|
643
|
+
});
|
|
644
|
+
it("should update Element code", () => {
|
|
645
|
+
const imodel4 = trackMutableIModel(createIModelFromSeed("elements-update-code-array.bim", "GetSetAutoHandledArrayProperties.bim"));
|
|
646
|
+
const txn = new EditTxn(imodel4, "update element code");
|
|
647
|
+
txn.start();
|
|
648
|
+
const elementId = txn.insertElement({
|
|
649
|
+
classFullName: "DgnPlatformTest:TestInformationRecord",
|
|
650
|
+
model: IModel.repositoryModelId,
|
|
651
|
+
code: Code.createEmpty(),
|
|
652
|
+
});
|
|
653
|
+
let element = imodel4.elements.getElement(elementId, InformationRecordElement);
|
|
654
|
+
assert.isTrue(Code.isValid(element.code));
|
|
655
|
+
assert.isTrue(Code.isEmpty(element.code));
|
|
656
|
+
const codeSpecId = imodel4.codeSpecs.insert(txn, "TestCodeSpec", CodeScopeSpec.Type.Model);
|
|
657
|
+
const codeValue = `${element.className}-1`;
|
|
658
|
+
element.code = new Code({ spec: codeSpecId, scope: IModel.repositoryModelId, value: codeValue });
|
|
659
|
+
element.update(txn);
|
|
660
|
+
txn.end();
|
|
661
|
+
element = imodel4.elements.getElement(elementId, InformationRecordElement);
|
|
662
|
+
assert.isTrue(Code.isValid(element.code));
|
|
663
|
+
assert.isFalse(Code.isEmpty(element.code));
|
|
664
|
+
assert.equal(element.code.value, codeValue);
|
|
665
|
+
});
|
|
666
|
+
it("should update UserLabel", async () => {
|
|
667
|
+
const imodel1 = trackMutableIModel(await importTestBim(createIModelFromSeed("elements-update-user-label.bim", "test.bim")));
|
|
668
|
+
const txn = new EditTxn(imodel1, "update user label");
|
|
669
|
+
txn.start();
|
|
670
|
+
// type coercion reminder!
|
|
671
|
+
const s = "";
|
|
672
|
+
assert.isTrue(s === "");
|
|
673
|
+
assert.isFalse(s ? true : false);
|
|
674
|
+
// insert element with an undefined UserLabel
|
|
675
|
+
const elementProps = {
|
|
676
|
+
classFullName: SpatialCategory.classFullName,
|
|
677
|
+
model: IModel.dictionaryId,
|
|
678
|
+
code: SpatialCategory.createCode(imodel1, IModel.dictionaryId, "TestCategoryForClearUserLabel"),
|
|
679
|
+
};
|
|
680
|
+
const elementId = txn.insertElement(elementProps);
|
|
681
|
+
let element = imodel1.elements.getElement(elementId);
|
|
682
|
+
assert.isUndefined(element.userLabel);
|
|
683
|
+
// update element with a defined userLabel
|
|
684
|
+
element.userLabel = "UserLabel";
|
|
685
|
+
element.update(txn);
|
|
686
|
+
element = imodel1.elements.getElement(elementId);
|
|
687
|
+
assert.equal(element.userLabel, "UserLabel");
|
|
688
|
+
// make sure userLabel is not updated when not part of the specified ElementProps
|
|
689
|
+
txn.updateElement({
|
|
690
|
+
id: element.id,
|
|
691
|
+
classFullName: element.classFullName,
|
|
692
|
+
model: element.model,
|
|
693
|
+
code: element.code,
|
|
694
|
+
});
|
|
695
|
+
element = imodel1.elements.getElement(elementId);
|
|
696
|
+
assert.equal(element.userLabel, "UserLabel"); // NOTE: userLabel is not modified when userLabel is not part of the input ElementProps
|
|
697
|
+
const elProps = imodel1.elements.getElementProps({ id: elementId, onlyBaseProperties: true });
|
|
698
|
+
expect(elProps.userLabel).equal(element.userLabel);
|
|
699
|
+
expect(elProps.classFullName).equal(SpatialCategory.classFullName);
|
|
700
|
+
expect(elProps.model).equal(element.model);
|
|
701
|
+
expect(elProps.code.value).equal(element.code.value);
|
|
702
|
+
expect(elProps.code.scope).equal(element.code.scope);
|
|
703
|
+
expect(elProps.code.spec).equal(element.code.spec);
|
|
704
|
+
expect(elProps.federationGuid).equal(element.federationGuid);
|
|
705
|
+
expect(elProps.isPrivate).to.be.oneOf([false, undefined]);
|
|
706
|
+
expect(elProps.isInstanceOfEntity).undefined;
|
|
707
|
+
// remove userlabel by setting it to the blank string
|
|
708
|
+
element.userLabel = "";
|
|
709
|
+
element.update(txn);
|
|
710
|
+
txn.end();
|
|
711
|
+
element = imodel1.elements.getElement(elementId);
|
|
712
|
+
assert.isUndefined(element.userLabel); // NOTE: userLabel is cleared when the empty string is specified
|
|
713
|
+
});
|
|
714
|
+
it("should update FederationGuid", async () => {
|
|
715
|
+
const imodel1 = trackMutableIModel(await importTestBim(createIModelFromSeed("elements-update-federation-guid.bim", "test.bim")));
|
|
716
|
+
const txn = new EditTxn(imodel1, "update federation guid");
|
|
717
|
+
txn.start();
|
|
718
|
+
// insert element with an undefined FederationGuid
|
|
719
|
+
const elementProps = {
|
|
720
|
+
classFullName: SpatialCategory.classFullName,
|
|
721
|
+
model: IModel.dictionaryId,
|
|
722
|
+
federationGuid: Guid.empty,
|
|
723
|
+
code: SpatialCategory.createCode(imodel1, IModel.dictionaryId, "TestCategoryForClearFederationGuid"),
|
|
724
|
+
};
|
|
725
|
+
const elementId = txn.insertElement(elementProps);
|
|
726
|
+
let element = imodel1.elements.getElement(elementId);
|
|
727
|
+
assert.isUndefined(element.federationGuid);
|
|
728
|
+
assert.isFalse(element.isPrivate);
|
|
729
|
+
// update element with a defined FederationGuid
|
|
730
|
+
const federationGuid = Guid.createValue();
|
|
731
|
+
element.federationGuid = federationGuid;
|
|
732
|
+
element.isPrivate = true;
|
|
733
|
+
element.update(txn);
|
|
734
|
+
element = imodel1.elements.getElement(elementId);
|
|
735
|
+
assert.equal(element.federationGuid, federationGuid);
|
|
736
|
+
assert.isTrue(element.isPrivate);
|
|
737
|
+
// make sure FederationGuid is not updated when not part of the specified ElementProps
|
|
738
|
+
txn.updateElement({
|
|
739
|
+
id: element.id,
|
|
740
|
+
classFullName: element.classFullName,
|
|
741
|
+
model: element.model,
|
|
742
|
+
code: element.code,
|
|
743
|
+
});
|
|
744
|
+
element = imodel1.elements.getElement(elementId);
|
|
745
|
+
assert.equal(element.federationGuid, federationGuid);
|
|
746
|
+
assert.isTrue(element.isPrivate);
|
|
747
|
+
// remove federationGuid by setting it to undefined in ElementProps
|
|
748
|
+
const elProps = element.toJSON();
|
|
749
|
+
elProps.federationGuid = undefined;
|
|
750
|
+
txn.updateElement(elProps);
|
|
751
|
+
element = imodel1.elements.getElement(elementId);
|
|
752
|
+
assert.isUndefined(element.federationGuid);
|
|
753
|
+
// ensure that update doesn't change federationGuid from an element immediately after insert (toJSON should remove undefined value)
|
|
754
|
+
const subject5 = Subject.create(imodel1, IModel.rootSubjectId, "Subject5");
|
|
755
|
+
const s5Id = subject5.insert(txn);
|
|
756
|
+
const s5pre = imodel1.elements.getElement(s5Id);
|
|
757
|
+
subject5.description = "new descr";
|
|
758
|
+
subject5.update(txn);
|
|
759
|
+
txn.end();
|
|
760
|
+
const s5post = imodel1.elements.getElement(s5Id);
|
|
761
|
+
expect(s5pre.federationGuid).equal(s5post.federationGuid);
|
|
762
|
+
expect(s5post.description).equal(subject5.description);
|
|
763
|
+
});
|
|
764
|
+
it("should support partial update", async () => {
|
|
765
|
+
const imodel1 = trackMutableIModel(await importTestBim(createIModelFromSeed("elements-partial-update.bim", "test.bim")));
|
|
766
|
+
const txn = new EditTxn(imodel1, "partial element update");
|
|
767
|
+
txn.start();
|
|
768
|
+
// Insert Subject elements - initializing Description and UserLabel to similar values
|
|
769
|
+
let subject1 = Subject.create(imodel1, IModel.rootSubjectId, "Subject1", "Description1");
|
|
770
|
+
let subject2 = Subject.create(imodel1, IModel.rootSubjectId, "Subject2", "Description2");
|
|
771
|
+
let subject3 = Subject.create(imodel1, IModel.rootSubjectId, "Subject3", "");
|
|
772
|
+
let subject4 = Subject.create(imodel1, IModel.rootSubjectId, "Subject4");
|
|
773
|
+
subject1.userLabel = "UserLabel1";
|
|
774
|
+
subject2.userLabel = "UserLabel2";
|
|
775
|
+
subject3.userLabel = "";
|
|
776
|
+
subject4.userLabel = undefined;
|
|
777
|
+
const federationGuid1 = Guid.createValue();
|
|
778
|
+
const federationGuid2 = Guid.createValue();
|
|
779
|
+
subject1.federationGuid = federationGuid1;
|
|
780
|
+
subject2.federationGuid = federationGuid2;
|
|
781
|
+
subject3.federationGuid = "";
|
|
782
|
+
subject4.federationGuid = Guid.empty;
|
|
783
|
+
const subjectId1 = subject1.insert(txn);
|
|
784
|
+
const subjectId2 = subject2.insert(txn);
|
|
785
|
+
const subjectId3 = subject3.insert(txn);
|
|
786
|
+
const subjectId4 = subject4.insert(txn);
|
|
787
|
+
subject1 = imodel1.elements.getElement(subjectId1, Subject);
|
|
788
|
+
subject2 = imodel1.elements.getElement(subjectId2, Subject);
|
|
789
|
+
subject3 = imodel1.elements.getElement(subjectId3, Subject);
|
|
790
|
+
subject4 = imodel1.elements.getElement(subjectId4, Subject);
|
|
791
|
+
// Subject.Description is an auto-handled property
|
|
792
|
+
assert.equal(subject1.description, "Description1");
|
|
793
|
+
assert.equal(subject2.description, "Description2");
|
|
794
|
+
assert.equal(subject3.description, ""); // NOTE: different behavior between auto-handled and custom-handled
|
|
795
|
+
assert.isUndefined(subject4.description);
|
|
796
|
+
// Test toJSON
|
|
797
|
+
assert.equal(subject1.toJSON().description, "Description1");
|
|
798
|
+
assert.equal(subject2.toJSON().description, "Description2");
|
|
799
|
+
assert.equal(subject3.toJSON().description, "");
|
|
800
|
+
assert.isUndefined(subject4.toJSON().description);
|
|
801
|
+
// Element.UserLabel is a custom-handled property
|
|
802
|
+
assert.equal(subject1.userLabel, "UserLabel1");
|
|
803
|
+
assert.equal(subject2.userLabel, "UserLabel2");
|
|
804
|
+
assert.isUndefined(subject3.userLabel); // NOTE: different behavior between auto-handled and custom-handled
|
|
805
|
+
assert.isUndefined(subject4.userLabel);
|
|
806
|
+
// Element.FederationGuid is a custom-handled property
|
|
807
|
+
assert.equal(subject1.federationGuid, federationGuid1);
|
|
808
|
+
assert.equal(subject2.federationGuid, federationGuid2);
|
|
809
|
+
assert.isUndefined(subject4.federationGuid);
|
|
810
|
+
// test partial update of Description (auto-handled)
|
|
811
|
+
txn.updateElement({ id: subject1.id, description: "Description1-Updated" });
|
|
812
|
+
subject1 = imodel1.elements.getElement(subjectId1, Subject);
|
|
813
|
+
assert.equal(subject1.description, "Description1-Updated"); // should have been updated
|
|
814
|
+
assert.isDefined(subject1.model);
|
|
815
|
+
assert.isDefined(subject1.parent);
|
|
816
|
+
assert.equal(subject1.code.value, "Subject1"); // should not have changed
|
|
817
|
+
assert.equal(subject1.userLabel, "UserLabel1"); // should not have changed
|
|
818
|
+
assert.equal(subject1.federationGuid, federationGuid1); // should not have changed
|
|
819
|
+
// test partial update of UserLabel (custom-handled)
|
|
820
|
+
txn.updateElement({ id: subject2.id, userLabel: "UserLabel2-Updated" });
|
|
821
|
+
subject2 = imodel1.elements.getElement(subjectId2, Subject);
|
|
822
|
+
assert.isDefined(subject2.model);
|
|
823
|
+
assert.isDefined(subject2.parent);
|
|
824
|
+
assert.equal(subject2.userLabel, "UserLabel2-Updated"); // should have been updated
|
|
825
|
+
assert.equal(subject2.code.value, "Subject2"); // should not have changed
|
|
826
|
+
assert.equal(subject2.description, "Description2"); // should not have changed
|
|
827
|
+
assert.equal(subject2.federationGuid, federationGuid2); // should not have changed
|
|
828
|
+
// Update Subject elements - setting Description and UserLabel to similar values
|
|
829
|
+
subject1.description = undefined;
|
|
830
|
+
subject2.description = "";
|
|
831
|
+
subject3.description = "Description3";
|
|
832
|
+
subject4.description = "Description4";
|
|
833
|
+
subject2.userLabel = "";
|
|
834
|
+
subject3.userLabel = "UserLabel3";
|
|
835
|
+
subject4.userLabel = "UserLabel4";
|
|
836
|
+
subject1.update(txn);
|
|
837
|
+
subject2.update(txn);
|
|
838
|
+
subject3.update(txn);
|
|
839
|
+
subject4.update(txn);
|
|
840
|
+
subject1 = imodel1.elements.getElement(subjectId1, Subject);
|
|
841
|
+
subject2 = imodel1.elements.getElement(subjectId2, Subject);
|
|
842
|
+
subject3 = imodel1.elements.getElement(subjectId3, Subject);
|
|
843
|
+
subject4 = imodel1.elements.getElement(subjectId4, Subject);
|
|
844
|
+
// Subject.Description is an auto-handled property
|
|
845
|
+
assert.isUndefined(subject1.description);
|
|
846
|
+
assert.equal(subject2.description, ""); // NOTE: different behavior between auto-handled and custom-handled
|
|
847
|
+
assert.equal(subject3.description, "Description3");
|
|
848
|
+
assert.equal(subject4.description, "Description4");
|
|
849
|
+
// Element.UserLabel is a custom-handled property
|
|
850
|
+
assert.isUndefined(subject2.userLabel); // NOTE: different behavior between auto-handled and custom-handled
|
|
851
|
+
assert.equal(subject3.userLabel, "UserLabel3");
|
|
852
|
+
assert.equal(subject4.userLabel, "UserLabel4");
|
|
853
|
+
// test partial update of Description to undefined
|
|
854
|
+
const s3Fed = subject3.federationGuid;
|
|
855
|
+
txn.updateElement({ id: subject3.id, description: undefined });
|
|
856
|
+
subject3 = imodel1.elements.getElement(subjectId3, Subject);
|
|
857
|
+
assert.isUndefined(subject3.description); // should have been updated
|
|
858
|
+
assert.isDefined(subject3.model);
|
|
859
|
+
assert.isDefined(subject3.parent);
|
|
860
|
+
assert.equal(subject3.code.value, "Subject3"); // should not have changed
|
|
861
|
+
assert.equal(subject3.userLabel, "UserLabel3"); // should not have changed
|
|
862
|
+
assert.equal(subject3.federationGuid, s3Fed); // should not have changed
|
|
863
|
+
// test partial update of UserLabel to undefined
|
|
864
|
+
txn.updateElement({ id: subject4.id, userLabel: undefined });
|
|
865
|
+
txn.end();
|
|
866
|
+
subject4 = imodel1.elements.getElement(subjectId4, Subject);
|
|
867
|
+
assert.isDefined(subject4.model);
|
|
868
|
+
assert.isDefined(subject4.parent);
|
|
869
|
+
// assert.isUndefined(subject4.userLabel); // should have been updated - WIP WIP WIP
|
|
870
|
+
assert.equal(subject4.code.value, "Subject4"); // should not have changed
|
|
871
|
+
assert.equal(subject4.description, "Description4"); // should not have changed
|
|
872
|
+
assert.isUndefined(subject4.federationGuid); // should not have changed
|
|
873
|
+
});
|
|
874
|
+
it('should allow untrimmed codes when using "exact" codeValueBehavior', () => {
|
|
875
|
+
const imodelPath = IModelTestUtils.prepareOutputFile("IModel", "codeValueBehavior.bim");
|
|
876
|
+
const imodel = trackMutableIModel(SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: "codeValueBehaviors" } }));
|
|
877
|
+
const txn = new EditTxn(imodel, "codeValueBehavior");
|
|
878
|
+
txn.start();
|
|
879
|
+
const getNumberedCodeValAndProps = (n) => {
|
|
880
|
+
const trimmedCodeVal = `CodeValue${n}`;
|
|
881
|
+
const untrimmedCodeVal = `${trimmedCodeVal}\xa0`;
|
|
882
|
+
const spec = imodel.codeSpecs.getByName(SpatialCategory.getCodeSpecName()).id;
|
|
883
|
+
const props = {
|
|
884
|
+
// the [[Code]] class still (as it always has) trims unicode space, so avoid it
|
|
885
|
+
code: { spec, scope: IModelDb.dictionaryId, value: untrimmedCodeVal },
|
|
886
|
+
model: IModelDb.dictionaryId,
|
|
887
|
+
classFullName: SpatialCategory.classFullName,
|
|
888
|
+
};
|
|
889
|
+
return { trimmedCodeVal, untrimmedCodeVal, props };
|
|
890
|
+
};
|
|
891
|
+
expect(imodel.codeValueBehavior).to.equal("trim-unicode-whitespace");
|
|
892
|
+
const code1 = getNumberedCodeValAndProps(1);
|
|
893
|
+
const categ1Id = txn.insertElement(code1.props);
|
|
894
|
+
const categ1 = imodel.elements.getElementProps({ id: categ1Id });
|
|
895
|
+
expect(categ1.code.value).to.equal(code1.trimmedCodeVal);
|
|
896
|
+
imodel.codeValueBehavior = "exact";
|
|
897
|
+
const code2 = getNumberedCodeValAndProps(2);
|
|
898
|
+
const categ2Id = txn.insertElement(code2.props);
|
|
899
|
+
const categ2 = imodel.elements.getElementProps({ id: categ2Id });
|
|
900
|
+
expect(categ2.code.value).to.equal(code2.untrimmedCodeVal);
|
|
901
|
+
imodel.codeValueBehavior = "trim-unicode-whitespace";
|
|
902
|
+
const code3 = getNumberedCodeValAndProps(3);
|
|
903
|
+
const categ3Id = txn.insertElement(code3.props);
|
|
904
|
+
const categ3 = imodel.elements.getElement({ id: categ3Id });
|
|
905
|
+
expect(categ3.code.value).to.equal(code3.trimmedCodeVal);
|
|
906
|
+
txn.end();
|
|
907
|
+
imodel.close();
|
|
908
|
+
});
|
|
909
|
+
it("should throw iTwinErrors on element CRUD operation fails", async () => {
|
|
910
|
+
const imodel1 = trackMutableIModel(await importTestBim(createIModelFromSeed("elements-crud-errors.bim", "test.bim")));
|
|
911
|
+
const txn = new EditTxn(imodel1, "element CRUD failure cases");
|
|
912
|
+
txn.start();
|
|
913
|
+
const code = Code.createEmpty();
|
|
914
|
+
code.value = "foo";
|
|
915
|
+
const props = {
|
|
916
|
+
classFullName: GenericGraphicalType2d.classFullName,
|
|
917
|
+
model: IModel.dictionaryId,
|
|
918
|
+
code,
|
|
919
|
+
};
|
|
920
|
+
txn.insertElement(props);
|
|
921
|
+
expect(() => txn.insertElement(props)).throws("Error inserting element [duplicate code]").to.have.property("iTwinErrorId");
|
|
922
|
+
const updateProps = {
|
|
923
|
+
id: Id64.fromString("0x111111"),
|
|
924
|
+
classFullName: GenericGraphicalType2d.classFullName,
|
|
925
|
+
model: IModel.dictionaryId,
|
|
926
|
+
code,
|
|
927
|
+
};
|
|
928
|
+
expect(() => txn.updateElement(updateProps)).throws(`Error updating element [missing id], id: ${updateProps.id}`).to.have.property("iTwinErrorId");
|
|
929
|
+
expect(() => txn.deleteElement(updateProps.id)).throws(`Error deleting element [missing id], id: ${updateProps.id}`).to.have.property("iTwinErrorId");
|
|
930
|
+
expect(() => txn.insertModel({ classFullName: DefinitionModel.classFullName, modeledElement: { id: "0x10000000bad" } })).throws("Error inserting model [error=10004], class=BisCore:DefinitionModel").to.have.property("iTwinErrorId");
|
|
931
|
+
expect(() => txn.updateModel({
|
|
932
|
+
id: Id64.fromString("0x111111"),
|
|
933
|
+
modeledElement: { id: Id64.fromString("0x111111") },
|
|
934
|
+
classFullName: ""
|
|
935
|
+
})).throws(`Error updating model [missing id], id: ${Id64.fromString("0x111111")}`).to.have.property("iTwinErrorId");
|
|
936
|
+
expect(() => txn.deleteModel(Id64.fromString("0x111111"))).throws(`Error deleting model [missing id], id: ${Id64.fromString("0x111111")}`).to.have.property("iTwinErrorId");
|
|
937
|
+
txn.end("abandon");
|
|
938
|
+
});
|
|
939
|
+
it("should update codeValues that are switched between elements", async () => {
|
|
940
|
+
const dbFileName = IModelTestUtils.prepareOutputFile("IModel", "change-codeValues.bim");
|
|
941
|
+
const imodelDb = trackMutableIModel(SnapshotDb.createEmpty(dbFileName, {
|
|
942
|
+
rootSubject: { name: "change-codeValues" },
|
|
943
|
+
}));
|
|
944
|
+
let categoryA = SpatialCategory.create(imodelDb, IModel.dictionaryId, "A");
|
|
945
|
+
let categoryB = SpatialCategory.create(imodelDb, IModel.dictionaryId, "B");
|
|
946
|
+
categoryA.userLabel = "A";
|
|
947
|
+
categoryB.userLabel = "B";
|
|
948
|
+
const txn = new EditTxn(imodelDb, "change codeValues");
|
|
949
|
+
txn.start();
|
|
950
|
+
categoryA.insert(txn);
|
|
951
|
+
categoryB.insert(txn);
|
|
952
|
+
txn.saveChanges();
|
|
953
|
+
categoryA = imodelDb.elements.getElement(SpatialCategory.createCode(imodelDb, IModel.dictionaryId, "A"));
|
|
954
|
+
categoryB = imodelDb.elements.getElement(SpatialCategory.createCode(imodelDb, IModel.dictionaryId, "B"));
|
|
955
|
+
categoryA.code.value = "temp";
|
|
956
|
+
categoryA.update(txn);
|
|
957
|
+
categoryB.code.value = "A";
|
|
958
|
+
categoryB.update(txn);
|
|
959
|
+
categoryA.code.value = "B";
|
|
960
|
+
categoryA.update(txn);
|
|
961
|
+
txn.end();
|
|
962
|
+
categoryA = imodelDb.elements.getElement(SpatialCategory.createCode(imodelDb, IModel.dictionaryId, "A"));
|
|
963
|
+
categoryB = imodelDb.elements.getElement(SpatialCategory.createCode(imodelDb, IModel.dictionaryId, "B"));
|
|
964
|
+
expect(categoryA.userLabel).to.equal("B", `categoryA.userLabel mismatch in ${imodelDb.name}`);
|
|
965
|
+
expect(categoryB.userLabel).to.equal("A", `categoryB.userLabel mismatch in ${imodelDb.name}`);
|
|
966
|
+
imodelDb.close();
|
|
967
|
+
});
|
|
968
|
+
});
|
|
969
|
+
//# sourceMappingURL=IModelElements.test.js.map
|