@itwin/core-backend 5.13.0-dev.8 → 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.
Files changed (235) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/lib/cjs/Category.d.ts +4 -4
  3. package/lib/cjs/Category.js.map +1 -1
  4. package/lib/cjs/ChangesetECAdaptor.d.ts +5 -0
  5. package/lib/cjs/ChangesetECAdaptor.d.ts.map +1 -1
  6. package/lib/cjs/ChangesetECAdaptor.js +13 -3
  7. package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
  8. package/lib/cjs/CodeSpecs.d.ts +3 -3
  9. package/lib/cjs/CodeSpecs.js.map +1 -1
  10. package/lib/cjs/DisplayStyle.d.ts +2 -2
  11. package/lib/cjs/DisplayStyle.js.map +1 -1
  12. package/lib/cjs/EditTxn.d.ts.map +1 -1
  13. package/lib/cjs/EditTxn.js +1 -0
  14. package/lib/cjs/EditTxn.js.map +1 -1
  15. package/lib/cjs/Element.d.ts +48 -12
  16. package/lib/cjs/Element.d.ts.map +1 -1
  17. package/lib/cjs/Element.js +120 -24
  18. package/lib/cjs/Element.js.map +1 -1
  19. package/lib/cjs/IModelDb.d.ts +30 -15
  20. package/lib/cjs/IModelDb.d.ts.map +1 -1
  21. package/lib/cjs/IModelDb.js +51 -15
  22. package/lib/cjs/IModelDb.js.map +1 -1
  23. package/lib/cjs/Model.d.ts +5 -5
  24. package/lib/cjs/Model.d.ts.map +1 -1
  25. package/lib/cjs/Model.js.map +1 -1
  26. package/lib/cjs/PropertyStore.js +1 -1
  27. package/lib/cjs/PropertyStore.js.map +1 -1
  28. package/lib/cjs/SchemaSync.d.ts +37 -9
  29. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  30. package/lib/cjs/SchemaSync.js +125 -6
  31. package/lib/cjs/SchemaSync.js.map +1 -1
  32. package/lib/cjs/SynchronousChannel.d.ts +62 -0
  33. package/lib/cjs/SynchronousChannel.d.ts.map +1 -0
  34. package/lib/cjs/SynchronousChannel.js +11 -0
  35. package/lib/cjs/SynchronousChannel.js.map +1 -0
  36. package/lib/cjs/Texture.d.ts +1 -1
  37. package/lib/cjs/Texture.js.map +1 -1
  38. package/lib/cjs/TxnManager.d.ts +44 -4
  39. package/lib/cjs/TxnManager.d.ts.map +1 -1
  40. package/lib/cjs/TxnManager.js +72 -14
  41. package/lib/cjs/TxnManager.js.map +1 -1
  42. package/lib/cjs/ViewDefinition.d.ts +6 -6
  43. package/lib/cjs/ViewDefinition.d.ts.map +1 -1
  44. package/lib/cjs/ViewDefinition.js.map +1 -1
  45. package/lib/cjs/annotations/LeaderGeometry.d.ts +22 -7
  46. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  47. package/lib/cjs/annotations/LeaderGeometry.js +104 -36
  48. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  49. package/lib/cjs/annotations/TextAnnotationElement.d.ts +1 -1
  50. package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
  51. package/lib/cjs/annotations/TextAnnotationElement.js +25 -10
  52. package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
  53. package/lib/cjs/core-backend.d.ts +1 -0
  54. package/lib/cjs/core-backend.d.ts.map +1 -1
  55. package/lib/cjs/core-backend.js +1 -0
  56. package/lib/cjs/core-backend.js.map +1 -1
  57. package/lib/cjs/internal/IntegrityCheck.d.ts +22 -0
  58. package/lib/cjs/internal/IntegrityCheck.d.ts.map +1 -1
  59. package/lib/cjs/internal/IntegrityCheck.js +13 -0
  60. package/lib/cjs/internal/IntegrityCheck.js.map +1 -1
  61. package/lib/cjs/internal/NoReservations.d.ts +6 -0
  62. package/lib/cjs/internal/NoReservations.d.ts.map +1 -0
  63. package/lib/cjs/internal/NoReservations.js +21 -0
  64. package/lib/cjs/internal/NoReservations.js.map +1 -0
  65. package/lib/cjs/internal/SchemaSyncReservations.d.ts +4 -0
  66. package/lib/cjs/internal/SchemaSyncReservations.d.ts.map +1 -0
  67. package/lib/cjs/internal/SchemaSyncReservations.js +118 -0
  68. package/lib/cjs/internal/SchemaSyncReservations.js.map +1 -0
  69. package/lib/cjs/internal/Symbols.d.ts +1 -0
  70. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  71. package/lib/cjs/internal/Symbols.js +2 -1
  72. package/lib/cjs/internal/Symbols.js.map +1 -1
  73. package/lib/esm/Category.d.ts +4 -4
  74. package/lib/esm/Category.js.map +1 -1
  75. package/lib/esm/ChangesetECAdaptor.d.ts +5 -0
  76. package/lib/esm/ChangesetECAdaptor.d.ts.map +1 -1
  77. package/lib/esm/ChangesetECAdaptor.js +13 -3
  78. package/lib/esm/ChangesetECAdaptor.js.map +1 -1
  79. package/lib/esm/CodeSpecs.d.ts +3 -3
  80. package/lib/esm/CodeSpecs.js.map +1 -1
  81. package/lib/esm/DisplayStyle.d.ts +2 -2
  82. package/lib/esm/DisplayStyle.js.map +1 -1
  83. package/lib/esm/EditTxn.d.ts.map +1 -1
  84. package/lib/esm/EditTxn.js +1 -0
  85. package/lib/esm/EditTxn.js.map +1 -1
  86. package/lib/esm/Element.d.ts +48 -12
  87. package/lib/esm/Element.d.ts.map +1 -1
  88. package/lib/esm/Element.js +121 -25
  89. package/lib/esm/Element.js.map +1 -1
  90. package/lib/esm/IModelDb.d.ts +30 -15
  91. package/lib/esm/IModelDb.d.ts.map +1 -1
  92. package/lib/esm/IModelDb.js +52 -16
  93. package/lib/esm/IModelDb.js.map +1 -1
  94. package/lib/esm/Model.d.ts +5 -5
  95. package/lib/esm/Model.d.ts.map +1 -1
  96. package/lib/esm/Model.js.map +1 -1
  97. package/lib/esm/PropertyStore.js +1 -1
  98. package/lib/esm/PropertyStore.js.map +1 -1
  99. package/lib/esm/SchemaSync.d.ts +37 -9
  100. package/lib/esm/SchemaSync.d.ts.map +1 -1
  101. package/lib/esm/SchemaSync.js +127 -8
  102. package/lib/esm/SchemaSync.js.map +1 -1
  103. package/lib/esm/SynchronousChannel.d.ts +62 -0
  104. package/lib/esm/SynchronousChannel.d.ts.map +1 -0
  105. package/lib/esm/SynchronousChannel.js +9 -0
  106. package/lib/esm/SynchronousChannel.js.map +1 -0
  107. package/lib/esm/Texture.d.ts +1 -1
  108. package/lib/esm/Texture.js.map +1 -1
  109. package/lib/esm/TxnManager.d.ts +44 -4
  110. package/lib/esm/TxnManager.d.ts.map +1 -1
  111. package/lib/esm/TxnManager.js +72 -14
  112. package/lib/esm/TxnManager.js.map +1 -1
  113. package/lib/esm/ViewDefinition.d.ts +6 -6
  114. package/lib/esm/ViewDefinition.d.ts.map +1 -1
  115. package/lib/esm/ViewDefinition.js.map +1 -1
  116. package/lib/esm/annotations/LeaderGeometry.d.ts +22 -7
  117. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  118. package/lib/esm/annotations/LeaderGeometry.js +104 -36
  119. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  120. package/lib/esm/annotations/TextAnnotationElement.d.ts +1 -1
  121. package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
  122. package/lib/esm/annotations/TextAnnotationElement.js +25 -10
  123. package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
  124. package/lib/esm/core-backend.d.ts +1 -0
  125. package/lib/esm/core-backend.d.ts.map +1 -1
  126. package/lib/esm/core-backend.js +1 -0
  127. package/lib/esm/core-backend.js.map +1 -1
  128. package/lib/esm/internal/IntegrityCheck.d.ts +22 -0
  129. package/lib/esm/internal/IntegrityCheck.d.ts.map +1 -1
  130. package/lib/esm/internal/IntegrityCheck.js +13 -0
  131. package/lib/esm/internal/IntegrityCheck.js.map +1 -1
  132. package/lib/esm/internal/NoReservations.d.ts +6 -0
  133. package/lib/esm/internal/NoReservations.d.ts.map +1 -0
  134. package/lib/esm/internal/NoReservations.js +18 -0
  135. package/lib/esm/internal/NoReservations.js.map +1 -0
  136. package/lib/esm/internal/SchemaSyncReservations.d.ts +4 -0
  137. package/lib/esm/internal/SchemaSyncReservations.d.ts.map +1 -0
  138. package/lib/esm/internal/SchemaSyncReservations.js +115 -0
  139. package/lib/esm/internal/SchemaSyncReservations.js.map +1 -0
  140. package/lib/esm/internal/Symbols.d.ts +1 -0
  141. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  142. package/lib/esm/internal/Symbols.js +1 -0
  143. package/lib/esm/internal/Symbols.js.map +1 -1
  144. package/lib/esm/test/IModelTestUtils.d.ts +1 -1
  145. package/lib/esm/test/IModelTestUtils.d.ts.map +1 -1
  146. package/lib/esm/test/IModelTestUtils.js +8 -3
  147. package/lib/esm/test/IModelTestUtils.js.map +1 -1
  148. package/lib/esm/test/annotations/LeaderGeometry.test.js +178 -2
  149. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  150. package/lib/esm/test/annotations/TextAnnotation.test.js +48 -18
  151. package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
  152. package/lib/esm/test/ecdb/ECSqlStatement.test.js +177 -0
  153. package/lib/esm/test/ecdb/ECSqlStatement.test.js.map +1 -1
  154. package/lib/esm/test/ecdb/QueryReaders.test.js +2 -16
  155. package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
  156. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js +2 -2
  157. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js.map +1 -1
  158. package/lib/esm/test/element/ElementRoundTrip.test.js +80 -2
  159. package/lib/esm/test/element/ElementRoundTrip.test.js.map +1 -1
  160. package/lib/esm/test/imodel/IModelECSql.test.d.ts +2 -0
  161. package/lib/esm/test/imodel/IModelECSql.test.d.ts.map +1 -0
  162. package/lib/esm/test/imodel/IModelECSql.test.js +367 -0
  163. package/lib/esm/test/imodel/IModelECSql.test.js.map +1 -0
  164. package/lib/esm/test/imodel/IModelElements.test.d.ts +2 -0
  165. package/lib/esm/test/imodel/IModelElements.test.d.ts.map +1 -0
  166. package/lib/esm/test/imodel/IModelElements.test.js +969 -0
  167. package/lib/esm/test/imodel/IModelElements.test.js.map +1 -0
  168. package/lib/esm/test/imodel/IModelGeolocation.test.d.ts +2 -0
  169. package/lib/esm/test/imodel/IModelGeolocation.test.d.ts.map +1 -0
  170. package/lib/esm/test/imodel/IModelGeolocation.test.js +539 -0
  171. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -0
  172. package/lib/esm/test/imodel/IModelLifecycle.test.d.ts +2 -0
  173. package/lib/esm/test/imodel/IModelLifecycle.test.d.ts.map +1 -0
  174. package/lib/esm/test/imodel/IModelLifecycle.test.js +499 -0
  175. package/lib/esm/test/imodel/IModelLifecycle.test.js.map +1 -0
  176. package/lib/esm/test/imodel/IModelMetadata.test.d.ts +2 -0
  177. package/lib/esm/test/imodel/IModelMetadata.test.d.ts.map +1 -0
  178. package/lib/esm/test/imodel/IModelMetadata.test.js +274 -0
  179. package/lib/esm/test/imodel/IModelMetadata.test.js.map +1 -0
  180. package/lib/esm/test/imodel/IModelModels.test.d.ts +2 -0
  181. package/lib/esm/test/imodel/IModelModels.test.d.ts.map +1 -0
  182. package/lib/esm/test/imodel/IModelModels.test.js +357 -0
  183. package/lib/esm/test/imodel/IModelModels.test.js.map +1 -0
  184. package/lib/esm/test/imodel/IModelRelationships.test.d.ts +2 -0
  185. package/lib/esm/test/imodel/IModelRelationships.test.d.ts.map +1 -0
  186. package/lib/esm/test/imodel/IModelRelationships.test.js +407 -0
  187. package/lib/esm/test/imodel/IModelRelationships.test.js.map +1 -0
  188. package/lib/esm/test/imodel/IModelTestFixtures.d.ts +53 -0
  189. package/lib/esm/test/imodel/IModelTestFixtures.d.ts.map +1 -0
  190. package/lib/esm/test/imodel/IModelTestFixtures.js +107 -0
  191. package/lib/esm/test/imodel/IModelTestFixtures.js.map +1 -0
  192. package/lib/esm/test/imodel/IModelViews.test.d.ts +2 -0
  193. package/lib/esm/test/imodel/IModelViews.test.d.ts.map +1 -0
  194. package/lib/esm/test/imodel/IModelViews.test.js +199 -0
  195. package/lib/esm/test/imodel/IModelViews.test.js.map +1 -0
  196. package/lib/esm/test/index.d.ts +0 -1
  197. package/lib/esm/test/index.d.ts.map +1 -1
  198. package/lib/esm/test/index.js +0 -1
  199. package/lib/esm/test/index.js.map +1 -1
  200. package/lib/esm/test/standalone/ChangesetReader.test.js +8 -26
  201. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  202. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts +2 -0
  203. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts.map +1 -0
  204. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js +263 -0
  205. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js.map +1 -0
  206. package/lib/esm/test/standalone/GeometryStream.test.js +1 -3
  207. package/lib/esm/test/standalone/GeometryStream.test.js.map +1 -1
  208. package/lib/esm/test/standalone/IModelWrite.test.d.ts.map +1 -1
  209. package/lib/esm/test/standalone/IModelWrite.test.js +78 -1
  210. package/lib/esm/test/standalone/IModelWrite.test.js.map +1 -1
  211. package/lib/esm/test/standalone/IntegrityCheck.test.js +29 -10
  212. package/lib/esm/test/standalone/IntegrityCheck.test.js.map +1 -1
  213. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +23 -0
  214. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -1
  215. package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts +2 -0
  216. package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts.map +1 -0
  217. package/lib/esm/test/standalone/SchemaSyncDb.test.js +221 -0
  218. package/lib/esm/test/standalone/SchemaSyncDb.test.js.map +1 -0
  219. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts +2 -0
  220. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts.map +1 -0
  221. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js +459 -0
  222. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js.map +1 -0
  223. package/lib/esm/test/standalone/SnapshotDb.test.js +1 -0
  224. package/lib/esm/test/standalone/SnapshotDb.test.js.map +1 -1
  225. package/lib/esm/test/standalone/TxnManager.test.js +108 -8
  226. package/lib/esm/test/standalone/TxnManager.test.js.map +1 -1
  227. package/package.json +13 -16
  228. package/lib/esm/test/RevisionUtility.d.ts +0 -33
  229. package/lib/esm/test/RevisionUtility.d.ts.map +0 -1
  230. package/lib/esm/test/RevisionUtility.js +0 -52
  231. package/lib/esm/test/RevisionUtility.js.map +0 -1
  232. package/lib/esm/test/imodel/IModel.test.d.ts +0 -2
  233. package/lib/esm/test/imodel/IModel.test.d.ts.map +0 -1
  234. package/lib/esm/test/imodel/IModel.test.js +0 -3277
  235. package/lib/esm/test/imodel/IModel.test.js.map +0 -1
@@ -0,0 +1,407 @@
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 { Id64 } from "@itwin/core-bentley";
7
+ import { Code, ColorByName, ColorDef, IModel, IModelError, QueryBinder, RelatedElement, SubCategoryAppearance, } from "@itwin/core-common";
8
+ import { EntityClass } from "@itwin/ecschema-metadata";
9
+ import { EditTxn, withEditTxn } from "../../EditTxn";
10
+ import { ElementDrivesElement, ElementGroupsMembers, IModelJsFs, PhysicalModel, PhysicalObject, SnapshotDb, SpatialCategory, StandaloneDb, } from "../../core-backend";
11
+ import { IModelTestUtils } from "../IModelTestUtils";
12
+ import { TestUtils } from "../TestUtils";
13
+ import { createIModelFromSeed, importTestBim } from "./IModelTestFixtures";
14
+ function createElemProps(_imodel, modId, catId, className) {
15
+ const elementProps = {
16
+ classFullName: className,
17
+ model: modId,
18
+ category: catId,
19
+ code: Code.createEmpty(),
20
+ };
21
+ return elementProps;
22
+ }
23
+ function insertElement(imodel, mId, cId, cName, propName, txn) {
24
+ const elementProps = createElemProps(imodel, mId, cId, cName);
25
+ const geomElement = imodel.elements.createElement(elementProps);
26
+ geomElement.name = propName; // Add a custom property to the element
27
+ const id = txn.insertElement(geomElement.toJSON());
28
+ assert.isTrue(Id64.isValidId64(id), "insert failed");
29
+ return id;
30
+ }
31
+ function validateADrivesBRowCount(imodel, expectedRows) {
32
+ const reader = IModelTestUtils.executeQuery(imodel, `select * from trs.ADrivesB`);
33
+ assert.strictEqual(reader.length, expectedRows, `Expected ${expectedRows} rows in trs.ADrivesB table`);
34
+ }
35
+ function validateNavProp(imodel, expectedNavPropValue) {
36
+ const reader = IModelTestUtils.executeQuery(imodel, `select NavPropChildB from trs.ChildA`);
37
+ assert.strictEqual(reader.length, 1);
38
+ assert.deepEqual(reader[0].navPropChildB, expectedNavPropValue, `Expected NavPropChildB to be "${expectedNavPropValue}"`);
39
+ }
40
+ describe("iModel relationships", () => {
41
+ before(async () => {
42
+ await TestUtils.startBackend();
43
+ IModelTestUtils.registerTestBimSchema();
44
+ });
45
+ describe("with a writable seed iModel", () => {
46
+ let imodel;
47
+ beforeEach(async () => {
48
+ imodel = await importTestBim(createIModelFromSeed("relationships.bim", "test.bim"));
49
+ });
50
+ afterEach(() => {
51
+ if (imodel !== undefined && imodel.isOpen)
52
+ imodel.close();
53
+ });
54
+ it("should create model with custom relationship to modeled element", async () => {
55
+ const testImodel = imodel;
56
+ const txn = new EditTxn(testImodel, "custom relationship to modeled element");
57
+ assert.doesNotThrow(() => testImodel.schemaContext.getSchemaItemSync("TestBim:TestModelModelsElement", EntityClass), "TestModelModelsElement is expected to be defined in TestBim.ecschema.xml");
58
+ txn.start();
59
+ const newPartition1 = IModelTestUtils.createAndInsertPhysicalPartition(txn, Code.createEmpty());
60
+ const relClassName1 = "TestBim:TestModelModelsElement";
61
+ const modeledElementRef = new RelatedElement({ id: newPartition1, relClassName: relClassName1 });
62
+ const newModelId1 = IModelTestUtils.createAndInsertPhysicalModel(txn, modeledElementRef);
63
+ assert.isTrue(Id64.isValidId64(newModelId1));
64
+ const [, newModelId2] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(txn, Code.createEmpty());
65
+ txn.end();
66
+ const newModel2 = testImodel.models.getModel(newModelId2);
67
+ const relClassName2 = newModel2.modeledElement.relClassName;
68
+ const model1 = testImodel.models.getModel(newModelId1);
69
+ const model2 = testImodel.models.getModel(newModelId2);
70
+ const foundRelClassName1 = model1.modeledElement.relClassName;
71
+ const foundRelClassName2 = model2.modeledElement.relClassName;
72
+ assert.equal(foundRelClassName1, relClassName1);
73
+ assert.equal(foundRelClassName2, relClassName2);
74
+ });
75
+ });
76
+ it("should create link table relationship instances", () => {
77
+ const snapshotFile2 = IModelTestUtils.prepareOutputFile("IModel", "CreateLinkTable.bim");
78
+ const testImodel = StandaloneDb.createEmpty(snapshotFile2, { rootSubject: { name: "test1" }, enableTransactions: true });
79
+ const txn = new EditTxn(testImodel, "link table relationship instances");
80
+ txn.start();
81
+ // Create a new physical model
82
+ const newModelId = PhysicalModel.insert(txn, IModel.rootSubjectId, "TestModel");
83
+ // create a SpatialCategory
84
+ const spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "MySpatialCategory", new SubCategoryAppearance({ color: ColorByName.darkRed }));
85
+ // Create a couple of physical elements.
86
+ const elementProps = {
87
+ classFullName: PhysicalObject.classFullName,
88
+ model: newModelId,
89
+ category: spatialCategoryId,
90
+ code: Code.createEmpty(),
91
+ };
92
+ const id0 = txn.insertElement(elementProps);
93
+ const id1 = txn.insertElement(elementProps);
94
+ const id2 = txn.insertElement(elementProps);
95
+ const geometricModel = testImodel.models.getModel(newModelId);
96
+ assert.throws(() => geometricModel.queryExtents()); // no geometry
97
+ // Create grouping relationships from 0 to 1 and from 0 to 2
98
+ const r1 = ElementGroupsMembers.create(testImodel, id0, id1, 1);
99
+ r1.id = txn.insertRelationship(r1.toJSON());
100
+ const r2 = ElementGroupsMembers.create(testImodel, id0, id2);
101
+ r2.id = txn.insertRelationship(r2.toJSON());
102
+ // Look up by id
103
+ const g1 = ElementGroupsMembers.getInstance(testImodel, r1.id);
104
+ const g2 = ElementGroupsMembers.getInstance(testImodel, r2.id);
105
+ assert.deepEqual(g1.id, r1.id);
106
+ assert.equal(g1.classFullName, ElementGroupsMembers.classFullName);
107
+ assert.equal(g1.memberPriority, 1, "g1.memberPriority");
108
+ assert.deepEqual(g2.id, r2.id);
109
+ assert.equal(g2.classFullName, ElementGroupsMembers.classFullName);
110
+ assert.equal(g2.memberPriority, 0, "g2.memberPriority"); // The memberPriority parameter defaults to 0 in ElementGroupsMembers.create
111
+ // Look up by source and target
112
+ const g1byst = ElementGroupsMembers.getInstance(testImodel, { sourceId: r1.sourceId, targetId: r1.targetId });
113
+ assert.deepEqual(g1byst, g1);
114
+ // Update relationship instance property
115
+ r1.asAny.memberPriority = 2;
116
+ txn.updateRelationship(r1.toJSON());
117
+ const g11 = ElementGroupsMembers.getInstance(testImodel, r1.id);
118
+ assert.equal(g11.memberPriority, 2, "g11.memberPriority");
119
+ txn.saveChanges("step 1");
120
+ // Delete relationship instance property
121
+ txn.deleteRelationship(g11.toJSON());
122
+ txn.saveChanges("step 2");
123
+ assert.throws(() => ElementGroupsMembers.getInstance(testImodel, r1.id), IModelError);
124
+ const d0 = txn.insertElement(elementProps);
125
+ const d1 = txn.insertElement(elementProps);
126
+ const ede1 = ElementDrivesElement.create(testImodel, d0, d1, 0);
127
+ ede1.id = txn.insertRelationship(ede1.toJSON());
128
+ txn.saveChanges("step 3");
129
+ txn.deleteRelationship(ede1.toJSON());
130
+ txn.end("save", "step 4");
131
+ testImodel.close();
132
+ });
133
+ it("should throw \"constraint failed (BE_SQLITE_CONSTRAINT_UNIQUE)\" when inserting a relationship instance with the same prop twice", () => {
134
+ const imodelPath = IModelTestUtils.prepareOutputFile("IModel", "insertDuplicateInstance.bim");
135
+ const imodel = SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: "insertDuplicateInstance" } });
136
+ const txn = new EditTxn(imodel, "insert duplicate relationship instance");
137
+ txn.start();
138
+ // Create a new physical model
139
+ const newModelId = PhysicalModel.insert(txn, IModel.rootSubjectId, "TestModel");
140
+ // create a SpatialCategory
141
+ const spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "MySpatialCategory", new SubCategoryAppearance({ color: ColorByName.darkRed }));
142
+ // Create a couple of physical elements.
143
+ const elementProps = {
144
+ classFullName: PhysicalObject.classFullName,
145
+ model: newModelId,
146
+ category: spatialCategoryId,
147
+ code: Code.createEmpty(),
148
+ };
149
+ const id0 = txn.insertElement(elementProps);
150
+ const id1 = txn.insertElement(elementProps);
151
+ const props = {
152
+ classFullName: "BisCore:ElementGroupsMembers",
153
+ sourceId: id0,
154
+ targetId: id1,
155
+ memberPriority: 1,
156
+ };
157
+ txn.insertRelationship(props);
158
+ expect(() => txn.insertRelationship(props)).to.throw(`Failed to insert relationship [${imodelPath}]: rc=2067, constraint failed (BE_SQLITE_CONSTRAINT_UNIQUE)`);
159
+ txn.end("abandon");
160
+ imodel.close();
161
+ });
162
+ it("Validate invalid relationship classes being inserted/updated", async () => {
163
+ const imodelPath = IModelTestUtils.prepareOutputFile("IModel", "invalidRelationshipClass.bim");
164
+ if (IModelJsFs.existsSync(imodelPath))
165
+ IModelJsFs.unlinkSync(imodelPath);
166
+ const testImodel = SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: "invalidRelationshipClass" } });
167
+ await testImodel.importSchemaStrings([
168
+ `<?xml version="1.0" encoding="UTF-8"?>
169
+ <ECSchema schemaName="TestRelationSchema" alias="trs" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
170
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
171
+ <ECEntityClass typeName="TestElement">
172
+ <BaseClass>bis:PhysicalElement</BaseClass>
173
+ <ECProperty propertyName="Name" typeName="string" />
174
+ </ECEntityClass>
175
+
176
+ <ECEntityClass typeName="ChildA" >
177
+ <BaseClass>TestElement</BaseClass>
178
+ <ECNavigationProperty propertyName="NavPropChildB" relationshipName="ADrivesB" direction="Forward" readOnly="True">
179
+ </ECNavigationProperty>
180
+ </ECEntityClass>
181
+
182
+ <ECEntityClass typeName="ChildB" >
183
+ <BaseClass>TestElement</BaseClass>
184
+ </ECEntityClass>
185
+
186
+ <ECRelationshipClass typeName="ADrivesB" strengthDirection="Backward" strength="referencing" modifier="Sealed">
187
+ <Source multiplicity="(0..*)" polymorphic="true" roleLabel="drives">
188
+ <Class class="ChildA"/>
189
+ </Source>
190
+ <Target multiplicity="(0..1)" polymorphic="true" roleLabel="is driven by">
191
+ <Class class="ChildB"/>
192
+ </Target>
193
+ </ECRelationshipClass>
194
+
195
+ <ECEntityClass typeName="ChildC">
196
+ <BaseClass>TestElement</BaseClass>
197
+ </ECEntityClass>
198
+
199
+ <ECEntityClass typeName="ChildD">
200
+ <BaseClass>TestElement</BaseClass>
201
+ </ECEntityClass>
202
+
203
+ <ECRelationshipClass typeName="CIsRelatedToD" strength="referencing" modifier="Sealed">
204
+ <BaseClass>bis:ElementRefersToElements</BaseClass>
205
+ <Source multiplicity="(0..*)" roleLabel="IsRelatedTo" polymorphic="true">
206
+ <Class class="ChildC"/>
207
+ </Source>
208
+ <Target multiplicity="(0..*)" roleLabel="IsRelatedTo (Reversed)" polymorphic="true">
209
+ <Class class="ChildD"/>
210
+ </Target>
211
+ </ECRelationshipClass>
212
+ </ECSchema>`
213
+ ]);
214
+ // Enable ECSQL write validation and verify it's set
215
+ const pragmaRows = IModelTestUtils.executeQuery(testImodel, `PRAGMA validate_ecsql_writes=true`);
216
+ assert.exists(pragmaRows);
217
+ assert.strictEqual(pragmaRows[0].validate_ecsql_writes, true);
218
+ // Ensure ADrivesB table is empty before test
219
+ validateADrivesBRowCount(testImodel, 0);
220
+ // Create a physical model and spatial category if needed
221
+ const setupTxn = new EditTxn(testImodel, "setup invalid relationship class test");
222
+ setupTxn.start();
223
+ const [, newModelId] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(setupTxn, Code.createEmpty(), true);
224
+ const spatialCategoryId = SpatialCategory.queryCategoryIdByName(testImodel, IModel.dictionaryId, "MySpatialCategory")
225
+ ?? SpatialCategory.insert(setupTxn, IModel.dictionaryId, "MySpatialCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
226
+ const idB = insertElement(testImodel, newModelId, spatialCategoryId, "TestRelationSchema:ChildB", "ChildBElement", setupTxn);
227
+ setupTxn.end();
228
+ assert.isTrue(Id64.isValidId64(idB), "Insert ChildBElement failed");
229
+ // Prepare base props for ChildA
230
+ const elementProps = createElemProps(testImodel, newModelId, spatialCategoryId, "TestRelationSchema:ChildA");
231
+ // Test various relationship class names for navigation property
232
+ const testCases = [
233
+ { name: "trs:ADrivesB", shouldSucceed: true, expectedRows: 1 },
234
+ { name: "trs.FakeClass", shouldSucceed: true, expectedRows: 0 },
235
+ { name: "trs:ChildA", shouldSucceed: false, expectedRows: 0 },
236
+ { name: "trs:ChildB", shouldSucceed: false, expectedRows: 0 },
237
+ { name: "trs:CIsRelatedToD", shouldSucceed: false, expectedRows: 0 },
238
+ ];
239
+ for (const { name, shouldSucceed, expectedRows } of testCases) {
240
+ const txn = new EditTxn(testImodel, `invalid relationship class ${name}`);
241
+ txn.start();
242
+ try {
243
+ const elemRef = new RelatedElement({ id: idB, relClassName: name });
244
+ elementProps.navPropChildB = elemRef;
245
+ elementProps.name = "ChildAElement";
246
+ const geomElement = testImodel.elements.createElement(elementProps);
247
+ let idA;
248
+ try {
249
+ idA = txn.insertElement(geomElement.toJSON());
250
+ if (shouldSucceed)
251
+ assert.isTrue(Id64.isValidId64(idA), `Insert should have succeeded for ${name}.`);
252
+ else
253
+ assert.fail(`Insert should have failed for ${name}.`);
254
+ }
255
+ catch (err) {
256
+ if (shouldSucceed)
257
+ assert.fail(`Insert should have succeeded for ${name}. Error: ${err.message}`);
258
+ // If should not succeed, error is expected
259
+ }
260
+ // Validate row count in ADrivesB table
261
+ validateADrivesBRowCount(testImodel, expectedRows);
262
+ // If insert succeeded, test update and delete scenarios
263
+ if (expectedRows === 1 && idA !== undefined) {
264
+ validateNavProp(testImodel, { id: idB, relClassName: "TestRelationSchema.ADrivesB" });
265
+ const editElem = testImodel.elements.getElement(idA);
266
+ editElem.navPropChildB = new RelatedElement({ id: idB, relClassName: "trs.FakeClass" });
267
+ editElem.name = "ChildAElementUpdated";
268
+ txn.updateElement(editElem);
269
+ validateADrivesBRowCount(testImodel, 1);
270
+ validateNavProp(testImodel, { id: idB, relClassName: "TestRelationSchema.ADrivesB" });
271
+ const editedElem = testImodel.elements.getElement(idA);
272
+ assert.equal(editedElem.name, "ChildAElementUpdated", `Expected name to be "ChildAElementUpdated" after update, but got "${editedElem.name}"`);
273
+ assert.strictEqual(editedElem.navPropChildB.relClassName, "TestRelationSchema.ADrivesB", `Expected navPropChildB to be "TestRelationSchema.ADrivesB" after update, but got "${editedElem.navPropChildB}"`);
274
+ // Set the nav prop value to null
275
+ editElem.name = "ChildAElementNulled";
276
+ editElem.navPropChildB = null;
277
+ txn.updateElement(editElem);
278
+ validateADrivesBRowCount(testImodel, 0);
279
+ const nulledElem = testImodel.elements.getElement(idA);
280
+ assert.equal(nulledElem.name, "ChildAElementNulled", `Expected name to be "ChildAElementNulled" after nulling, but got "${nulledElem.name}"`);
281
+ assert.isUndefined(nulledElem.navPropChildB, `Expected navPropChildB to be undefined after nulling, but got "${nulledElem.navPropChildB}"`);
282
+ if (shouldSucceed) {
283
+ txn.deleteElement(idA);
284
+ assert.isUndefined(testImodel.elements.tryGetElement(idA), `Expected element with id ${idA} to be deleted, but it still exists.`);
285
+ }
286
+ }
287
+ }
288
+ finally {
289
+ txn.end("abandon");
290
+ }
291
+ }
292
+ testImodel.close();
293
+ });
294
+ describe("Delete relationship instances", () => {
295
+ let testImodel;
296
+ const relationshipClasses = [
297
+ "BisCore:ElementGroupsMembers",
298
+ "BisCore:ElementDrivesElement",
299
+ "BisCore:ElementRefersToDocuments"
300
+ ];
301
+ afterEach(() => {
302
+ if (testImodel !== undefined) {
303
+ const iModelPath = testImodel.pathName;
304
+ if (testImodel.isOpen)
305
+ testImodel.close();
306
+ IModelJsFs.unlinkSync(iModelPath);
307
+ }
308
+ });
309
+ function setupRelationships(numOfRelationships, multipleClasses = false) {
310
+ testImodel = SnapshotDb.createEmpty(IModelTestUtils.prepareOutputFile("IModel", "DeleteRelationshipInstances.bim"), { rootSubject: { name: "DeleteRelationshipInstances" } });
311
+ assert.isTrue(testImodel.isOpen);
312
+ const txn = new EditTxn(testImodel, "setup delete relationships");
313
+ txn.start();
314
+ const [, newModelId] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(txn, Code.createEmpty(), true);
315
+ let spatialCategoryId = SpatialCategory.queryCategoryIdByName(testImodel, IModel.dictionaryId, "MySpatialCategory");
316
+ if (!spatialCategoryId) {
317
+ spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, "MySpatialCategory", new SubCategoryAppearance());
318
+ }
319
+ const relationships = [];
320
+ for (let i = 0; i < numOfRelationships; ++i) {
321
+ const sourceProps = createElemProps(testImodel, newModelId, spatialCategoryId, "Generic:PhysicalObject");
322
+ const sourceId = txn.insertElement(sourceProps);
323
+ const targetProps = createElemProps(testImodel, newModelId, spatialCategoryId, "Generic:PhysicalObject");
324
+ const targetId = txn.insertElement(targetProps);
325
+ let relationshipClass = "BisCore:ElementGroupsMembers";
326
+ if (multipleClasses)
327
+ relationshipClass = relationshipClasses[i % relationshipClasses.length];
328
+ const relationshipProps = {
329
+ classFullName: relationshipClass,
330
+ sourceId,
331
+ targetId,
332
+ };
333
+ relationshipProps.id = txn.insertRelationship(relationshipProps);
334
+ relationships.push(relationshipProps);
335
+ }
336
+ txn.end();
337
+ return relationships;
338
+ }
339
+ async function getRelationshipCount(iModel, relationshipClass) {
340
+ const reader = iModel.createQueryReader(`SELECT COUNT(*) AS [count] FROM ${relationshipClass}`);
341
+ await reader.step();
342
+ return reader.current.count;
343
+ }
344
+ it("deleteInstances with an empty array", async () => {
345
+ const relationships = setupRelationships(10);
346
+ assert.equal(relationships.length, await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers"));
347
+ withEditTxn(testImodel, (txn) => {
348
+ txn.deleteRelationships([]);
349
+ });
350
+ assert.equal(relationships.length, await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers"));
351
+ });
352
+ it("deleteInstances with a single relationship instance", async () => {
353
+ const relationships = setupRelationships(10);
354
+ assert.equal(relationships.length, await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers"), "Should delete exactly one relationship");
355
+ // Delete just one relationship using deleteInstances method
356
+ withEditTxn(testImodel, (txn) => {
357
+ txn.deleteRelationships([relationships[0]]);
358
+ });
359
+ const remainingCount = await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers");
360
+ assert.equal(remainingCount, relationships.length - 1, "Should delete exactly one relationship");
361
+ });
362
+ it("deleteInstances with different relationship classes", async () => {
363
+ const relationships = setupRelationships(500, true);
364
+ // Verify relationships were created across different classes
365
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers") >= Math.floor(relationships.length / 3));
366
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementDrivesElement") >= Math.floor(relationships.length / 3));
367
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementRefersToDocuments") >= Math.floor(relationships.length / 3));
368
+ // Test deleteInstances with mixed relationship classes
369
+ withEditTxn(testImodel, (txn) => {
370
+ txn.deleteRelationships(relationships);
371
+ });
372
+ // Verify all relationships were deleted regardless of their class
373
+ assert.equal(0, await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers"), "All ElementGroupsMembers relationships should be deleted");
374
+ assert.equal(0, await getRelationshipCount(testImodel, "BisCore.ElementDrivesElement"), "All ElementDrivesElement relationships should be deleted");
375
+ assert.equal(0, await getRelationshipCount(testImodel, "BisCore.ElementRefersToDocuments"), "All ElementRefersToDocuments relationships should be deleted");
376
+ });
377
+ it("deleteInstances for subset including duplicate entries", async () => {
378
+ const relationships = setupRelationships(1000, true);
379
+ // Verify relationships exist before deletion
380
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementGroupsMembers") >= Math.floor(relationships.length / 3));
381
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementDrivesElement") >= Math.floor(relationships.length / 3));
382
+ assert.isTrue(await getRelationshipCount(testImodel, "BisCore.ElementRefersToDocuments") >= Math.floor(relationships.length / 3));
383
+ // Select a deterministic, unique subset (every 4th relationship => 250 unique entries)
384
+ // so the test is stable and reproducible.
385
+ const relationshipsToDelete = [];
386
+ for (let i = 0; i < relationships.length; i += 4) {
387
+ relationshipsToDelete.push(relationships[i]);
388
+ }
389
+ assert.equal(relationshipsToDelete.length, 250);
390
+ // Intentionally pass one relationship twice in the same call. deleteRelationships must
391
+ // tolerate duplicate IDs in a single batch (deleting an already-deleted relationship is a no-op),
392
+ // which exercises the batch/native boundary that the previous with-replacement sampling covered.
393
+ const duplicated = relationshipsToDelete[0];
394
+ relationshipsToDelete.push(duplicated);
395
+ withEditTxn(testImodel, (txn) => {
396
+ txn.deleteRelationships(relationshipsToDelete);
397
+ });
398
+ // Verify all relationships were deleted (dedupe so the duplicated entry is only checked once)
399
+ const uniqueDeleted = relationshipsToDelete.filter((rel, index) => relationshipsToDelete.indexOf(rel) === index);
400
+ for (const relClass of uniqueDeleted) {
401
+ const reader = testImodel.createQueryReader(`SELECT ECInstanceId FROM ${relClass.classFullName} WHERE SourceECInstanceId=? AND TargetECInstanceId=?`, new QueryBinder().bindId(1, relClass.sourceId).bindId(2, relClass.targetId));
402
+ assert.isFalse(await reader.step(), `Relationship ${relClass.id} should be deleted`); // No row should be returned
403
+ }
404
+ });
405
+ });
406
+ });
407
+ //# sourceMappingURL=IModelRelationships.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IModelRelationships.test.js","sourceRoot":"","sources":["../../../../src/test/imodel/IModelRelationships.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { assert, expect } from \"chai\";\r\nimport { Id64, Id64String } from \"@itwin/core-bentley\";\r\nimport {\r\n Code, ColorByName, ColorDef, GeometricElementProps, IModel, IModelError, QueryBinder, RelatedElement, RelationshipProps, SubCategoryAppearance,\r\n} from \"@itwin/core-common\";\r\nimport { EntityClass } from \"@itwin/ecschema-metadata\";\r\nimport { EditTxn, withEditTxn } from \"../../EditTxn\";\r\nimport {\r\n ElementDrivesElement, ElementGroupsMembers, ElementGroupsMembersProps, GeometricModel, IModelDb, IModelJsFs, PhysicalModel,\r\n PhysicalObject, SnapshotDb, SpatialCategory, StandaloneDb,\r\n} from \"../../core-backend\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\nimport { TestUtils } from \"../TestUtils\";\r\nimport { createIModelFromSeed, importTestBim } from \"./IModelTestFixtures\";\r\n\r\n\r\nfunction createElemProps(_imodel: IModelDb, modId: Id64String, catId: Id64String, className: string): GeometricElementProps {\r\n const elementProps: GeometricElementProps = {\r\n classFullName: className,\r\n model: modId,\r\n category: catId,\r\n code: Code.createEmpty(),\r\n };\r\n return elementProps;\r\n}\r\n\r\nfunction insertElement(imodel: IModelDb, mId: Id64String, cId: Id64String, cName: string, propName: string, txn: EditTxn): Id64String {\r\n const elementProps = createElemProps(imodel, mId, cId, cName);\r\n const geomElement = imodel.elements.createElement(elementProps);\r\n (geomElement as any).name = propName; // Add a custom property to the element\r\n const id = txn.insertElement(geomElement.toJSON());\r\n assert.isTrue(Id64.isValidId64(id), \"insert failed\");\r\n return id;\r\n}\r\n\r\nfunction validateADrivesBRowCount(imodel: IModelDb, expectedRows: number): void {\r\n const reader = IModelTestUtils.executeQuery(imodel, `select * from trs.ADrivesB`);\r\n assert.strictEqual(reader.length, expectedRows, `Expected ${expectedRows} rows in trs.ADrivesB table`);\r\n}\r\n\r\nfunction validateNavProp(imodel: IModelDb, expectedNavPropValue: any): void {\r\n const reader = IModelTestUtils.executeQuery(imodel, `select NavPropChildB from trs.ChildA`);\r\n assert.strictEqual(reader.length, 1);\r\n assert.deepEqual(reader[0].navPropChildB, expectedNavPropValue, `Expected NavPropChildB to be \"${expectedNavPropValue}\"`);\r\n}\r\n\r\ndescribe(\"iModel relationships\", () => {\r\n before(async () => {\r\n await TestUtils.startBackend();\r\n IModelTestUtils.registerTestBimSchema();\r\n });\r\n\r\n describe(\"with a writable seed iModel\", () => {\r\n let imodel: SnapshotDb;\r\n\r\n beforeEach(async () => {\r\n imodel = await importTestBim(createIModelFromSeed(\"relationships.bim\", \"test.bim\"));\r\n });\r\n\r\n afterEach(() => {\r\n if (imodel !== undefined && imodel.isOpen)\r\n imodel.close();\r\n });\r\n\r\n it(\"should create model with custom relationship to modeled element\", async () => {\r\n const testImodel = imodel;\r\n const txn = new EditTxn(testImodel, \"custom relationship to modeled element\");\r\n\r\n assert.doesNotThrow(() => testImodel.schemaContext.getSchemaItemSync(\"TestBim:TestModelModelsElement\", EntityClass), \"TestModelModelsElement is expected to be defined in TestBim.ecschema.xml\");\r\n\r\n txn.start();\r\n const newPartition1 = IModelTestUtils.createAndInsertPhysicalPartition(txn, Code.createEmpty());\r\n const relClassName1 = \"TestBim:TestModelModelsElement\";\r\n const modeledElementRef = new RelatedElement({ id: newPartition1, relClassName: relClassName1 });\r\n const newModelId1 = IModelTestUtils.createAndInsertPhysicalModel(txn, modeledElementRef);\r\n assert.isTrue(Id64.isValidId64(newModelId1));\r\n const [, newModelId2] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(txn, Code.createEmpty());\r\n txn.end();\r\n const newModel2 = testImodel.models.getModel(newModelId2);\r\n const relClassName2 = newModel2.modeledElement.relClassName;\r\n\r\n const model1 = testImodel.models.getModel(newModelId1);\r\n const model2 = testImodel.models.getModel(newModelId2);\r\n\r\n const foundRelClassName1 = model1.modeledElement.relClassName;\r\n const foundRelClassName2 = model2.modeledElement.relClassName;\r\n\r\n assert.equal(foundRelClassName1, relClassName1);\r\n assert.equal(foundRelClassName2, relClassName2);\r\n });\r\n });\r\n\r\n it(\"should create link table relationship instances\", () => {\r\n const snapshotFile2: string = IModelTestUtils.prepareOutputFile(\"IModel\", \"CreateLinkTable.bim\");\r\n const testImodel = StandaloneDb.createEmpty(snapshotFile2, { rootSubject: { name: \"test1\" }, enableTransactions: true });\r\n const txn = new EditTxn(testImodel, \"link table relationship instances\");\r\n txn.start();\r\n // Create a new physical model\r\n const newModelId = PhysicalModel.insert(txn, IModel.rootSubjectId, \"TestModel\");\r\n\r\n // create a SpatialCategory\r\n const spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, \"MySpatialCategory\", new SubCategoryAppearance({ color: ColorByName.darkRed }));\r\n\r\n // Create a couple of physical elements.\r\n const elementProps: GeometricElementProps = {\r\n classFullName: PhysicalObject.classFullName,\r\n model: newModelId,\r\n category: spatialCategoryId,\r\n code: Code.createEmpty(),\r\n };\r\n\r\n const id0 = txn.insertElement(elementProps);\r\n const id1 = txn.insertElement(elementProps);\r\n const id2 = txn.insertElement(elementProps);\r\n\r\n const geometricModel = testImodel.models.getModel<GeometricModel>(newModelId);\r\n assert.throws(() => geometricModel.queryExtents()); // no geometry\r\n\r\n // Create grouping relationships from 0 to 1 and from 0 to 2\r\n const r1 = ElementGroupsMembers.create(testImodel, id0, id1, 1);\r\n r1.id = txn.insertRelationship(r1.toJSON());\r\n const r2 = ElementGroupsMembers.create(testImodel, id0, id2);\r\n r2.id = txn.insertRelationship(r2.toJSON());\r\n\r\n // Look up by id\r\n const g1 = ElementGroupsMembers.getInstance<ElementGroupsMembers>(testImodel, r1.id);\r\n const g2 = ElementGroupsMembers.getInstance<ElementGroupsMembers>(testImodel, r2.id);\r\n\r\n assert.deepEqual(g1.id, r1.id);\r\n assert.equal(g1.classFullName, ElementGroupsMembers.classFullName);\r\n assert.equal(g1.memberPriority, 1, \"g1.memberPriority\");\r\n assert.deepEqual(g2.id, r2.id);\r\n assert.equal(g2.classFullName, ElementGroupsMembers.classFullName);\r\n assert.equal(g2.memberPriority, 0, \"g2.memberPriority\"); // The memberPriority parameter defaults to 0 in ElementGroupsMembers.create\r\n\r\n // Look up by source and target\r\n const g1byst = ElementGroupsMembers.getInstance<ElementGroupsMembers>(testImodel, { sourceId: r1.sourceId, targetId: r1.targetId });\r\n assert.deepEqual(g1byst, g1);\r\n\r\n // Update relationship instance property\r\n r1.asAny.memberPriority = 2;\r\n txn.updateRelationship(r1.toJSON());\r\n\r\n const g11 = ElementGroupsMembers.getInstance<ElementGroupsMembers>(testImodel, r1.id);\r\n assert.equal(g11.memberPriority, 2, \"g11.memberPriority\");\r\n txn.saveChanges(\"step 1\");\r\n\r\n // Delete relationship instance property\r\n txn.deleteRelationship(g11.toJSON());\r\n txn.saveChanges(\"step 2\");\r\n assert.throws(() => ElementGroupsMembers.getInstance(testImodel, r1.id), IModelError);\r\n\r\n const d0 = txn.insertElement(elementProps);\r\n const d1 = txn.insertElement(elementProps);\r\n const ede1 = ElementDrivesElement.create(testImodel, d0, d1, 0);\r\n ede1.id = txn.insertRelationship(ede1.toJSON());\r\n txn.saveChanges(\"step 3\");\r\n\r\n txn.deleteRelationship(ede1.toJSON());\r\n txn.end(\"save\", \"step 4\");\r\n testImodel.close();\r\n });\r\n\r\n it(\"should throw \\\"constraint failed (BE_SQLITE_CONSTRAINT_UNIQUE)\\\" when inserting a relationship instance with the same prop twice\", () => {\r\n const imodelPath = IModelTestUtils.prepareOutputFile(\"IModel\", \"insertDuplicateInstance.bim\");\r\n const imodel = SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: \"insertDuplicateInstance\" } });\r\n const txn = new EditTxn(imodel, \"insert duplicate relationship instance\");\r\n txn.start();\r\n // Create a new physical model\r\n const newModelId = PhysicalModel.insert(txn, IModel.rootSubjectId, \"TestModel\");\r\n\r\n // create a SpatialCategory\r\n const spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, \"MySpatialCategory\", new SubCategoryAppearance({ color: ColorByName.darkRed }));\r\n\r\n // Create a couple of physical elements.\r\n const elementProps: GeometricElementProps = {\r\n classFullName: PhysicalObject.classFullName,\r\n model: newModelId,\r\n category: spatialCategoryId,\r\n code: Code.createEmpty(),\r\n };\r\n\r\n const id0 = txn.insertElement(elementProps);\r\n const id1 = txn.insertElement(elementProps);\r\n\r\n const props: ElementGroupsMembersProps = {\r\n classFullName: \"BisCore:ElementGroupsMembers\",\r\n sourceId: id0,\r\n targetId: id1,\r\n memberPriority: 1,\r\n };\r\n\r\n txn.insertRelationship(props);\r\n expect(() => txn.insertRelationship(props)).to.throw(`Failed to insert relationship [${imodelPath}]: rc=2067, constraint failed (BE_SQLITE_CONSTRAINT_UNIQUE)`);\r\n\r\n txn.end(\"abandon\");\r\n imodel.close();\r\n });\r\n\r\n it(\"Validate invalid relationship classes being inserted/updated\", async () => {\r\n const imodelPath = IModelTestUtils.prepareOutputFile(\"IModel\", \"invalidRelationshipClass.bim\");\r\n\r\n if (IModelJsFs.existsSync(imodelPath))\r\n IModelJsFs.unlinkSync(imodelPath);\r\n\r\n const testImodel = SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: \"invalidRelationshipClass\" } });\r\n\r\n await testImodel.importSchemaStrings([\r\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n <ECSchema schemaName=\"TestRelationSchema\" alias=\"trs\" version=\"01.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.1\">\r\n <ECSchemaReference name=\"BisCore\" version=\"01.00\" alias=\"bis\"/>\r\n <ECEntityClass typeName=\"TestElement\">\r\n <BaseClass>bis:PhysicalElement</BaseClass>\r\n <ECProperty propertyName=\"Name\" typeName=\"string\" />\r\n </ECEntityClass>\r\n\r\n <ECEntityClass typeName=\"ChildA\" >\r\n <BaseClass>TestElement</BaseClass>\r\n <ECNavigationProperty propertyName=\"NavPropChildB\" relationshipName=\"ADrivesB\" direction=\"Forward\" readOnly=\"True\">\r\n </ECNavigationProperty>\r\n </ECEntityClass>\r\n\r\n <ECEntityClass typeName=\"ChildB\" >\r\n <BaseClass>TestElement</BaseClass>\r\n </ECEntityClass>\r\n\r\n <ECRelationshipClass typeName=\"ADrivesB\" strengthDirection=\"Backward\" strength=\"referencing\" modifier=\"Sealed\">\r\n <Source multiplicity=\"(0..*)\" polymorphic=\"true\" roleLabel=\"drives\">\r\n <Class class=\"ChildA\"/>\r\n </Source>\r\n <Target multiplicity=\"(0..1)\" polymorphic=\"true\" roleLabel=\"is driven by\">\r\n <Class class=\"ChildB\"/>\r\n </Target>\r\n </ECRelationshipClass>\r\n\r\n <ECEntityClass typeName=\"ChildC\">\r\n <BaseClass>TestElement</BaseClass>\r\n </ECEntityClass>\r\n\r\n <ECEntityClass typeName=\"ChildD\">\r\n <BaseClass>TestElement</BaseClass>\r\n </ECEntityClass>\r\n\r\n <ECRelationshipClass typeName=\"CIsRelatedToD\" strength=\"referencing\" modifier=\"Sealed\">\r\n <BaseClass>bis:ElementRefersToElements</BaseClass>\r\n <Source multiplicity=\"(0..*)\" roleLabel=\"IsRelatedTo\" polymorphic=\"true\">\r\n <Class class=\"ChildC\"/>\r\n </Source>\r\n <Target multiplicity=\"(0..*)\" roleLabel=\"IsRelatedTo (Reversed)\" polymorphic=\"true\">\r\n <Class class=\"ChildD\"/>\r\n </Target>\r\n </ECRelationshipClass>\r\n </ECSchema>`]);\r\n\r\n // Enable ECSQL write validation and verify it's set\r\n const pragmaRows = IModelTestUtils.executeQuery(testImodel, `PRAGMA validate_ecsql_writes=true`);\r\n assert.exists(pragmaRows);\r\n assert.strictEqual(pragmaRows[0].validate_ecsql_writes, true);\r\n\r\n // Ensure ADrivesB table is empty before test\r\n validateADrivesBRowCount(testImodel, 0);\r\n\r\n // Create a physical model and spatial category if needed\r\n const setupTxn = new EditTxn(testImodel, \"setup invalid relationship class test\");\r\n setupTxn.start();\r\n const [, newModelId] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(setupTxn, Code.createEmpty(), true);\r\n const spatialCategoryId = SpatialCategory.queryCategoryIdByName(testImodel, IModel.dictionaryId, \"MySpatialCategory\")\r\n ?? SpatialCategory.insert(setupTxn,\r\n IModel.dictionaryId,\r\n \"MySpatialCategory\",\r\n new SubCategoryAppearance({ color: ColorDef.fromString(\"rgb(255,0,0)\").toJSON() })\r\n );\r\n const idB = insertElement(testImodel, newModelId, spatialCategoryId, \"TestRelationSchema:ChildB\", \"ChildBElement\", setupTxn);\r\n setupTxn.end();\r\n assert.isTrue(Id64.isValidId64(idB), \"Insert ChildBElement failed\");\r\n\r\n // Prepare base props for ChildA\r\n const elementProps = createElemProps(testImodel, newModelId, spatialCategoryId, \"TestRelationSchema:ChildA\");\r\n\r\n // Test various relationship class names for navigation property\r\n const testCases = [\r\n { name: \"trs:ADrivesB\", shouldSucceed: true, expectedRows: 1 },\r\n { name: \"trs.FakeClass\", shouldSucceed: true, expectedRows: 0 },\r\n { name: \"trs:ChildA\", shouldSucceed: false, expectedRows: 0 },\r\n { name: \"trs:ChildB\", shouldSucceed: false, expectedRows: 0 },\r\n { name: \"trs:CIsRelatedToD\", shouldSucceed: false, expectedRows: 0 },\r\n ];\r\n\r\n for (const { name, shouldSucceed, expectedRows } of testCases) {\r\n const txn = new EditTxn(testImodel, `invalid relationship class ${name}`);\r\n txn.start();\r\n try {\r\n const elemRef = new RelatedElement({ id: idB, relClassName: name });\r\n (elementProps as any).navPropChildB = elemRef;\r\n (elementProps as any).name = \"ChildAElement\";\r\n const geomElement = testImodel.elements.createElement(elementProps);\r\n\r\n let idA: Id64String | undefined;\r\n try {\r\n idA = txn.insertElement(geomElement.toJSON());\r\n if (shouldSucceed)\r\n assert.isTrue(Id64.isValidId64(idA), `Insert should have succeeded for ${name}.`);\r\n else\r\n assert.fail(`Insert should have failed for ${name}.`);\r\n } catch (err: any) {\r\n if (shouldSucceed)\r\n assert.fail(`Insert should have succeeded for ${name}. Error: ${err.message}`);\r\n\r\n // If should not succeed, error is expected\r\n }\r\n\r\n // Validate row count in ADrivesB table\r\n validateADrivesBRowCount(testImodel, expectedRows);\r\n\r\n // If insert succeeded, test update and delete scenarios\r\n if (expectedRows === 1 && idA !== undefined) {\r\n validateNavProp(testImodel, { id: idB, relClassName: \"TestRelationSchema.ADrivesB\" });\r\n\r\n const editElem: any = testImodel.elements.getElement(idA);\r\n editElem.navPropChildB = new RelatedElement({ id: idB, relClassName: \"trs.FakeClass\" });\r\n editElem.name = \"ChildAElementUpdated\";\r\n txn.updateElement(editElem);\r\n\r\n validateADrivesBRowCount(testImodel, 1);\r\n validateNavProp(testImodel, { id: idB, relClassName: \"TestRelationSchema.ADrivesB\" });\r\n\r\n const editedElem: any = testImodel.elements.getElement(idA);\r\n assert.equal(editedElem.name, \"ChildAElementUpdated\", `Expected name to be \"ChildAElementUpdated\" after update, but got \"${editedElem.name}\"`);\r\n assert.strictEqual(editedElem.navPropChildB.relClassName, \"TestRelationSchema.ADrivesB\", `Expected navPropChildB to be \"TestRelationSchema.ADrivesB\" after update, but got \"${editedElem.navPropChildB}\"`);\r\n\r\n // Set the nav prop value to null\r\n editElem.name = \"ChildAElementNulled\";\r\n editElem.navPropChildB = null;\r\n txn.updateElement(editElem);\r\n\r\n validateADrivesBRowCount(testImodel, 0);\r\n const nulledElem: any = testImodel.elements.getElement(idA);\r\n assert.equal(nulledElem.name, \"ChildAElementNulled\", `Expected name to be \"ChildAElementNulled\" after nulling, but got \"${nulledElem.name}\"`);\r\n assert.isUndefined(nulledElem.navPropChildB, `Expected navPropChildB to be undefined after nulling, but got \"${nulledElem.navPropChildB}\"`);\r\n\r\n if (shouldSucceed) {\r\n txn.deleteElement(idA);\r\n assert.isUndefined(testImodel.elements.tryGetElement(idA), `Expected element with id ${idA} to be deleted, but it still exists.`);\r\n }\r\n }\r\n } finally {\r\n txn.end(\"abandon\");\r\n }\r\n }\r\n testImodel.close();\r\n });\r\n\r\n describe(\"Delete relationship instances\", () => {\r\n let testImodel: SnapshotDb;\r\n const relationshipClasses = [\r\n \"BisCore:ElementGroupsMembers\",\r\n \"BisCore:ElementDrivesElement\",\r\n \"BisCore:ElementRefersToDocuments\"\r\n ];\r\n\r\n afterEach(() => {\r\n if (testImodel !== undefined) {\r\n const iModelPath = testImodel.pathName;\r\n if (testImodel.isOpen)\r\n testImodel.close();\r\n IModelJsFs.unlinkSync(iModelPath);\r\n }\r\n });\r\n\r\n function setupRelationships(numOfRelationships: number, multipleClasses: boolean = false): RelationshipProps[] {\r\n testImodel = SnapshotDb.createEmpty(IModelTestUtils.prepareOutputFile(\"IModel\", \"DeleteRelationshipInstances.bim\"), { rootSubject: { name: \"DeleteRelationshipInstances\" } });\r\n assert.isTrue(testImodel.isOpen);\r\n\r\n const txn = new EditTxn(testImodel, \"setup delete relationships\");\r\n txn.start();\r\n const [, newModelId] = IModelTestUtils.createAndInsertPhysicalPartitionAndModel(txn, Code.createEmpty(), true);\r\n let spatialCategoryId = SpatialCategory.queryCategoryIdByName(testImodel, IModel.dictionaryId, \"MySpatialCategory\");\r\n if (!spatialCategoryId) {\r\n spatialCategoryId = SpatialCategory.insert(txn, IModel.dictionaryId, \"MySpatialCategory\", new SubCategoryAppearance());\r\n }\r\n\r\n const relationships: RelationshipProps[] = [];\r\n for (let i = 0; i < numOfRelationships; ++i) {\r\n const sourceProps = createElemProps(testImodel, newModelId, spatialCategoryId, \"Generic:PhysicalObject\");\r\n const sourceId = txn.insertElement(sourceProps);\r\n\r\n const targetProps = createElemProps(testImodel, newModelId, spatialCategoryId, \"Generic:PhysicalObject\");\r\n const targetId = txn.insertElement(targetProps);\r\n\r\n let relationshipClass = \"BisCore:ElementGroupsMembers\";\r\n if (multipleClasses)\r\n relationshipClass = relationshipClasses[i % relationshipClasses.length];\r\n\r\n const relationshipProps: RelationshipProps = {\r\n classFullName: relationshipClass,\r\n sourceId,\r\n targetId,\r\n };\r\n\r\n relationshipProps.id = txn.insertRelationship(relationshipProps);\r\n relationships.push(relationshipProps);\r\n }\r\n txn.end();\r\n return relationships;\r\n }\r\n\r\n async function getRelationshipCount(iModel: IModelDb, relationshipClass: string): Promise<number> {\r\n const reader = iModel.createQueryReader(`SELECT COUNT(*) AS [count] FROM ${relationshipClass}`);\r\n await reader.step();\r\n return reader.current.count;\r\n }\r\n\r\n it(\"deleteInstances with an empty array\", async () => {\r\n const relationships = setupRelationships(10);\r\n assert.equal(relationships.length, await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\"));\r\n\r\n withEditTxn(testImodel, (txn) => {\r\n txn.deleteRelationships([]);\r\n });\r\n\r\n assert.equal(relationships.length, await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\"));\r\n });\r\n\r\n it(\"deleteInstances with a single relationship instance\", async () => {\r\n const relationships = setupRelationships(10);\r\n assert.equal(relationships.length, await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\"), \"Should delete exactly one relationship\");\r\n\r\n // Delete just one relationship using deleteInstances method\r\n withEditTxn(testImodel, (txn) => {\r\n txn.deleteRelationships([relationships[0]]);\r\n });\r\n\r\n const remainingCount = await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\");\r\n assert.equal(remainingCount, relationships.length - 1, \"Should delete exactly one relationship\");\r\n });\r\n\r\n it(\"deleteInstances with different relationship classes\", async () => {\r\n const relationships = setupRelationships(500, true);\r\n\r\n // Verify relationships were created across different classes\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\") >= Math.floor(relationships.length / 3));\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementDrivesElement\") >= Math.floor(relationships.length / 3));\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementRefersToDocuments\") >= Math.floor(relationships.length / 3));\r\n\r\n // Test deleteInstances with mixed relationship classes\r\n withEditTxn(testImodel, (txn) => {\r\n txn.deleteRelationships(relationships);\r\n });\r\n\r\n // Verify all relationships were deleted regardless of their class\r\n assert.equal(0, await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\"), \"All ElementGroupsMembers relationships should be deleted\");\r\n assert.equal(0, await getRelationshipCount(testImodel, \"BisCore.ElementDrivesElement\"), \"All ElementDrivesElement relationships should be deleted\");\r\n assert.equal(0, await getRelationshipCount(testImodel, \"BisCore.ElementRefersToDocuments\"), \"All ElementRefersToDocuments relationships should be deleted\");\r\n });\r\n\r\n it(\"deleteInstances for subset including duplicate entries\", async () => {\r\n const relationships = setupRelationships(1000, true);\r\n\r\n // Verify relationships exist before deletion\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementGroupsMembers\") >= Math.floor(relationships.length / 3));\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementDrivesElement\") >= Math.floor(relationships.length / 3));\r\n assert.isTrue(await getRelationshipCount(testImodel, \"BisCore.ElementRefersToDocuments\") >= Math.floor(relationships.length / 3));\r\n\r\n // Select a deterministic, unique subset (every 4th relationship => 250 unique entries)\r\n // so the test is stable and reproducible.\r\n const relationshipsToDelete: RelationshipProps[] = [];\r\n for (let i = 0; i < relationships.length; i += 4) {\r\n relationshipsToDelete.push(relationships[i]);\r\n }\r\n assert.equal(relationshipsToDelete.length, 250);\r\n\r\n // Intentionally pass one relationship twice in the same call. deleteRelationships must\r\n // tolerate duplicate IDs in a single batch (deleting an already-deleted relationship is a no-op),\r\n // which exercises the batch/native boundary that the previous with-replacement sampling covered.\r\n const duplicated = relationshipsToDelete[0];\r\n relationshipsToDelete.push(duplicated);\r\n\r\n withEditTxn(testImodel, (txn) => {\r\n txn.deleteRelationships(relationshipsToDelete);\r\n });\r\n\r\n // Verify all relationships were deleted (dedupe so the duplicated entry is only checked once)\r\n const uniqueDeleted = relationshipsToDelete.filter((rel, index) => relationshipsToDelete.indexOf(rel) === index);\r\n for (const relClass of uniqueDeleted) {\r\n const reader = testImodel.createQueryReader(`SELECT ECInstanceId FROM ${relClass.classFullName} WHERE SourceECInstanceId=? AND TargetECInstanceId=?`, new QueryBinder().bindId(1, relClass.sourceId).bindId(2, relClass.targetId));\r\n assert.isFalse(await reader.step(), `Relationship ${relClass.id} should be deleted`); // No row should be returned\r\n }\r\n });\r\n });\r\n});\r\n"]}
@@ -0,0 +1,53 @@
1
+ import { DbResult, IModelStatus } from "@itwin/core-bentley";
2
+ import { IModelError } from "@itwin/core-common";
3
+ import { Entity, IModelDb, SnapshotDb } from "../../core-backend";
4
+ /**
5
+ * Awaits `promise` and returns the {@link IModelError} it rejected with, or `undefined` if it resolved.
6
+ *
7
+ * A rejection that is not an {@link IModelError} is rethrown rather than swallowed, so an unexpected
8
+ * failure surfaces with its original message and stack trace instead of being misreported as
9
+ * "no error was thrown". This means `undefined` unambiguously means the promise resolved.
10
+ */
11
+ export declare function getIModelError<T>(promise: Promise<T>): Promise<IModelError | undefined>;
12
+ /** Asserts that `error` is an {@link IModelError} carrying the expected error number. */
13
+ export declare function expectIModelError(expectedErrorNumber: IModelStatus | DbResult, error: IModelError | undefined): void;
14
+ /** Roundtrip an entity through a JSON string and back to a new entity, asserting the serialization is stable. */
15
+ export declare function roundtripThroughJson(entity1: Entity): Entity;
16
+ /**
17
+ * Create a fresh writable snapshot copied from a seed asset. This is the single creation path for
18
+ * mutating tests (hybrid isolation) so state never leaks between tests. Compose with
19
+ * {@link importTestBim} when the test also needs the `TestBim` schema.
20
+ */
21
+ export declare function createIModelFromSeed(targetFileName: string, seedAssetName: string): SnapshotDb;
22
+ /**
23
+ * Import the `TestBim` schema into `imodel` and return it, so this can wrap a creation call:
24
+ * `await importTestBim(createIModelFromSeed(target, seed))`.
25
+ */
26
+ export declare function importTestBim<T extends SnapshotDb>(imodel: T): Promise<T>;
27
+ /**
28
+ * Create a fresh writable copy from a seed asset, close it, and reopen it read-only.
29
+ *
30
+ * This is the canonical way to build a shared, per-file read-only fixture under the hybrid
31
+ * isolation policy: the read-only handle can be shared safely across tests in a file because
32
+ * nothing can mutate it, while each mutating test still gets its own writable copy elsewhere.
33
+ * When `importTestBim` is set, the `TestBim` schema is imported into the writable copy before
34
+ * it is reopened read-only.
35
+ */
36
+ export declare function openReadonlySeedCopy(targetFileName: string, seedAssetName: string, opts?: {
37
+ importTestBim?: boolean;
38
+ }): Promise<SnapshotDb>;
39
+ /** Close each provided database that is still open. Guards against `undefined` and already-closed handles. */
40
+ export declare function closeIfOpen(...dbs: Array<IModelDb | undefined>): void;
41
+ /**
42
+ * Create a tracker for the writable iModels a test file opens, so they are all closed during teardown.
43
+ *
44
+ * This is the mechanism that enforces the hybrid isolation policy for mutating tests: each test wraps
45
+ * its freshly-created writable copy in `trackMutableIModel(...)`, and the file's `afterEach`/`after`
46
+ * calls `closeTrackedIModels()` to close and forget them. `closeTrackedIModels` is idempotent, so it is
47
+ * safe to call from both hooks.
48
+ */
49
+ export declare function createMutableIModelTracker(): {
50
+ trackMutableIModel: <T extends IModelDb>(imodel: T) => T;
51
+ closeTrackedIModels: () => void;
52
+ };
53
+ //# sourceMappingURL=IModelTestFixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IModelTestFixtures.d.ts","sourceRoot":"","sources":["../../../../src/test/imodel/IModelTestFixtures.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAe,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIlE;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAS7F;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,mBAAmB,EAAE,YAAY,GAAG,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,IAAI,CAIpH;AAED,iHAAiH;AACjH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO5D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,UAAU,CAI9F;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAI/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAOjJ;AAED,8GAA8G;AAC9G,wBAAgB,WAAW,CAAC,GAAG,GAAG,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,IAAI,CAKrE;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,IAAI;IAC5C,kBAAkB,EAAE,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IACzD,mBAAmB,EAAE,MAAM,IAAI,CAAC;CACjC,CAWA"}