@itwin/core-backend 5.9.0-dev.8 → 5.9.0

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 (604) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/lib/cjs/BackendHubAccess.d.ts +38 -0
  3. package/lib/cjs/BackendHubAccess.d.ts.map +1 -1
  4. package/lib/cjs/BackendHubAccess.js.map +1 -1
  5. package/lib/cjs/BackendLoggerCategory.js.map +1 -1
  6. package/lib/cjs/BisCoreSchema.js.map +1 -1
  7. package/lib/cjs/BlobContainerService.js.map +1 -1
  8. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  9. package/lib/cjs/BriefcaseManager.js +6 -3
  10. package/lib/cjs/BriefcaseManager.js.map +1 -1
  11. package/lib/cjs/CatalogDb.js.map +1 -1
  12. package/lib/cjs/Category.d.ts +4 -4
  13. package/lib/cjs/Category.js.map +1 -1
  14. package/lib/cjs/ChangeSummaryManager.js +2 -2
  15. package/lib/cjs/ChangeSummaryManager.js.map +1 -1
  16. package/lib/cjs/ChangedElementsDb.js.map +1 -1
  17. package/lib/cjs/ChangesetECAdaptor.d.ts +9 -1
  18. package/lib/cjs/ChangesetECAdaptor.d.ts.map +1 -1
  19. package/lib/cjs/ChangesetECAdaptor.js +255 -249
  20. package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
  21. package/lib/cjs/ChangesetReader.d.ts +186 -0
  22. package/lib/cjs/ChangesetReader.d.ts.map +1 -0
  23. package/lib/cjs/ChangesetReader.js +372 -0
  24. package/lib/cjs/ChangesetReader.js.map +1 -0
  25. package/lib/cjs/ChangesetReaderTypes.d.ts +120 -0
  26. package/lib/cjs/ChangesetReaderTypes.d.ts.map +1 -0
  27. package/lib/cjs/ChangesetReaderTypes.js +23 -0
  28. package/lib/cjs/ChangesetReaderTypes.js.map +1 -0
  29. package/lib/cjs/ChannelControl.js.map +1 -1
  30. package/lib/cjs/CheckpointManager.js.map +1 -1
  31. package/lib/cjs/ClassRegistry.js +5 -5
  32. package/lib/cjs/ClassRegistry.js.map +1 -1
  33. package/lib/cjs/CloudSqlite.d.ts +1 -1
  34. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  35. package/lib/cjs/CloudSqlite.js +68 -13
  36. package/lib/cjs/CloudSqlite.js.map +1 -1
  37. package/lib/cjs/CodeService.js.map +1 -1
  38. package/lib/cjs/CodeSpecs.d.ts +3 -3
  39. package/lib/cjs/CodeSpecs.js.map +1 -1
  40. package/lib/cjs/ConcurrentQuery.js.map +1 -1
  41. package/lib/cjs/CustomViewState3dCreator.js.map +1 -1
  42. package/lib/cjs/DevTools.js.map +1 -1
  43. package/lib/cjs/DisplayStyle.d.ts +2 -2
  44. package/lib/cjs/DisplayStyle.js.map +1 -1
  45. package/lib/cjs/ECDb.js.map +1 -1
  46. package/lib/cjs/ECSchemaXmlContext.js.map +1 -1
  47. package/lib/cjs/ECSqlRowExecutor.js.map +1 -1
  48. package/lib/cjs/ECSqlStatement.d.ts.map +1 -1
  49. package/lib/cjs/ECSqlStatement.js.map +1 -1
  50. package/lib/cjs/ECSqlSyncReader.js.map +1 -1
  51. package/lib/cjs/EditTxn.d.ts +55 -1
  52. package/lib/cjs/EditTxn.d.ts.map +1 -1
  53. package/lib/cjs/EditTxn.js +43 -1
  54. package/lib/cjs/EditTxn.js.map +1 -1
  55. package/lib/cjs/Element.d.ts +79 -10
  56. package/lib/cjs/Element.d.ts.map +1 -1
  57. package/lib/cjs/Element.js +38 -2
  58. package/lib/cjs/Element.js.map +1 -1
  59. package/lib/cjs/ElementAspect.d.ts +1 -1
  60. package/lib/cjs/ElementAspect.js.map +1 -1
  61. package/lib/cjs/ElementGraphics.js.map +1 -1
  62. package/lib/cjs/ElementTreeWalker.d.ts +5 -5
  63. package/lib/cjs/ElementTreeWalker.js.map +1 -1
  64. package/lib/cjs/Entity.js.map +1 -1
  65. package/lib/cjs/EntityReferences.js.map +1 -1
  66. package/lib/cjs/ExportGraphics.js.map +1 -1
  67. package/lib/cjs/ExternalSource.d.ts +2 -2
  68. package/lib/cjs/ExternalSource.d.ts.map +1 -1
  69. package/lib/cjs/ExternalSource.js.map +1 -1
  70. package/lib/cjs/FontFile.js.map +1 -1
  71. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  72. package/lib/cjs/GeographicCRSServices.d.ts +15 -0
  73. package/lib/cjs/GeographicCRSServices.d.ts.map +1 -1
  74. package/lib/cjs/GeographicCRSServices.js +13 -4
  75. package/lib/cjs/GeographicCRSServices.js.map +1 -1
  76. package/lib/cjs/GeometrySummary.js +47 -47
  77. package/lib/cjs/GeometrySummary.js.map +1 -1
  78. package/lib/cjs/IModelDb.d.ts +31 -23
  79. package/lib/cjs/IModelDb.d.ts.map +1 -1
  80. package/lib/cjs/IModelDb.js +53 -34
  81. package/lib/cjs/IModelDb.js.map +1 -1
  82. package/lib/cjs/IModelDbFonts.js.map +1 -1
  83. package/lib/cjs/IModelElementCloneContext.js.map +1 -1
  84. package/lib/cjs/IModelHost.js.map +1 -1
  85. package/lib/cjs/IModelIncrementalSchemaLocater.js.map +1 -1
  86. package/lib/cjs/IModelJsFs.js.map +1 -1
  87. package/lib/cjs/ImageSourceConversion.js.map +1 -1
  88. package/lib/cjs/IpcHost.d.ts.map +1 -1
  89. package/lib/cjs/IpcHost.js +33 -13
  90. package/lib/cjs/IpcHost.js.map +1 -1
  91. package/lib/cjs/LineStyle.d.ts +6 -6
  92. package/lib/cjs/LineStyle.js.map +1 -1
  93. package/lib/cjs/LocalHub.js +1 -1
  94. package/lib/cjs/LocalHub.js.map +1 -1
  95. package/lib/cjs/LocalhostIpcHost.js.map +1 -1
  96. package/lib/cjs/LockControl.d.ts +85 -1
  97. package/lib/cjs/LockControl.d.ts.map +1 -1
  98. package/lib/cjs/LockControl.js.map +1 -1
  99. package/lib/cjs/Material.d.ts +1 -1
  100. package/lib/cjs/Material.js.map +1 -1
  101. package/lib/cjs/Model.d.ts +40 -6
  102. package/lib/cjs/Model.d.ts.map +1 -1
  103. package/lib/cjs/Model.js +24 -0
  104. package/lib/cjs/Model.js.map +1 -1
  105. package/lib/cjs/NativeAppStorage.js.map +1 -1
  106. package/lib/cjs/NativeHost.js.map +1 -1
  107. package/lib/cjs/NavigationRelationship.js.map +1 -1
  108. package/lib/cjs/PartialChangeUnifier.d.ts +77 -0
  109. package/lib/cjs/PartialChangeUnifier.d.ts.map +1 -0
  110. package/lib/cjs/PartialChangeUnifier.js +234 -0
  111. package/lib/cjs/PartialChangeUnifier.js.map +1 -0
  112. package/lib/cjs/PromiseMemoizer.js.map +1 -1
  113. package/lib/cjs/PropertyStore.js.map +1 -1
  114. package/lib/cjs/Relationship.d.ts +10 -10
  115. package/lib/cjs/Relationship.js +6 -6
  116. package/lib/cjs/Relationship.js.map +1 -1
  117. package/lib/cjs/RpcBackend.js.map +1 -1
  118. package/lib/cjs/SQLiteDb.js.map +1 -1
  119. package/lib/cjs/Schema.js.map +1 -1
  120. package/lib/cjs/SchemaSync.js.map +1 -1
  121. package/lib/cjs/SchemaUtils.js.map +1 -1
  122. package/lib/cjs/SheetIndex.d.ts +4 -4
  123. package/lib/cjs/SheetIndex.d.ts.map +1 -1
  124. package/lib/cjs/SheetIndex.js.map +1 -1
  125. package/lib/cjs/SqliteChangesetReader.d.ts.map +1 -1
  126. package/lib/cjs/SqliteChangesetReader.js +1 -1
  127. package/lib/cjs/SqliteChangesetReader.js.map +1 -1
  128. package/lib/cjs/SqliteStatement.js.map +1 -1
  129. package/lib/cjs/StashManager.js.map +1 -1
  130. package/lib/cjs/Texture.d.ts +1 -1
  131. package/lib/cjs/Texture.js.map +1 -1
  132. package/lib/cjs/TileStorage.js.map +1 -1
  133. package/lib/cjs/TxnManager.d.ts +114 -4
  134. package/lib/cjs/TxnManager.d.ts.map +1 -1
  135. package/lib/cjs/TxnManager.js +196 -8
  136. package/lib/cjs/TxnManager.js.map +1 -1
  137. package/lib/cjs/ViewDefinition.d.ts +25 -13
  138. package/lib/cjs/ViewDefinition.d.ts.map +1 -1
  139. package/lib/cjs/ViewDefinition.js +77 -25
  140. package/lib/cjs/ViewDefinition.js.map +1 -1
  141. package/lib/cjs/ViewStateHydrator.js.map +1 -1
  142. package/lib/cjs/ViewStore.d.ts.map +1 -1
  143. package/lib/cjs/ViewStore.js +63 -21
  144. package/lib/cjs/ViewStore.js.map +1 -1
  145. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +1 -1
  146. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  147. package/lib/cjs/annotations/FrameGeometry.js.map +1 -1
  148. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  149. package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
  150. package/lib/cjs/annotations/TextAnnotationGeometry.js.map +1 -1
  151. package/lib/cjs/annotations/TextBlockGeometry.js.map +1 -1
  152. package/lib/cjs/annotations/TextBlockLayout.js.map +1 -1
  153. package/lib/cjs/assets/IModelChange.02.00.00.ecschema.xml +90 -90
  154. package/lib/cjs/assets/Settings/Schemas/Base.Schema.json +32 -32
  155. package/lib/cjs/assets/Settings/Schemas/Gcs.schema.json +27 -27
  156. package/lib/cjs/assets/Settings/Schemas/Workspace.Schema.json +94 -94
  157. package/lib/cjs/assets/Settings/backend.setting.json5 +21 -21
  158. package/lib/cjs/core-backend.d.ts +3 -0
  159. package/lib/cjs/core-backend.d.ts.map +1 -1
  160. package/lib/cjs/core-backend.js +3 -0
  161. package/lib/cjs/core-backend.js.map +1 -1
  162. package/lib/cjs/domains/FunctionalElements.d.ts +1 -1
  163. package/lib/cjs/domains/FunctionalElements.d.ts.map +1 -1
  164. package/lib/cjs/domains/FunctionalElements.js.map +1 -1
  165. package/lib/cjs/domains/FunctionalSchema.js.map +1 -1
  166. package/lib/cjs/domains/GenericElements.d.ts +2 -2
  167. package/lib/cjs/domains/GenericElements.d.ts.map +1 -1
  168. package/lib/cjs/domains/GenericElements.js.map +1 -1
  169. package/lib/cjs/domains/GenericSchema.js.map +1 -1
  170. package/lib/cjs/internal/ChangesetConflictArgs.js.map +1 -1
  171. package/lib/cjs/internal/ChannelAdmin.d.ts +2 -2
  172. package/lib/cjs/internal/ChannelAdmin.d.ts.map +1 -1
  173. package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
  174. package/lib/cjs/internal/ElementLRUCache.js.map +1 -1
  175. package/lib/cjs/internal/FontFileImpl.js.map +1 -1
  176. package/lib/cjs/internal/HubMock.d.ts +2 -0
  177. package/lib/cjs/internal/HubMock.d.ts.map +1 -1
  178. package/lib/cjs/internal/HubMock.js +7 -0
  179. package/lib/cjs/internal/HubMock.js.map +1 -1
  180. package/lib/cjs/internal/IModelDbFontsImpl.js.map +1 -1
  181. package/lib/cjs/internal/IntegrityCheck.d.ts +10 -10
  182. package/lib/cjs/internal/IntegrityCheck.js +22 -22
  183. package/lib/cjs/internal/IntegrityCheck.js.map +1 -1
  184. package/lib/cjs/internal/NativePlatform.js.map +1 -1
  185. package/lib/cjs/internal/NoLocks.d.ts.map +1 -1
  186. package/lib/cjs/internal/NoLocks.js +6 -0
  187. package/lib/cjs/internal/NoLocks.js.map +1 -1
  188. package/lib/cjs/internal/OnlineStatus.js.map +1 -1
  189. package/lib/cjs/internal/ServerBasedLocks.d.ts +12 -0
  190. package/lib/cjs/internal/ServerBasedLocks.d.ts.map +1 -1
  191. package/lib/cjs/internal/ServerBasedLocks.js +285 -4
  192. package/lib/cjs/internal/ServerBasedLocks.js.map +1 -1
  193. package/lib/cjs/internal/Symbols.js.map +1 -1
  194. package/lib/cjs/internal/annotations/fields.js.map +1 -1
  195. package/lib/cjs/internal/cross-package.js.map +1 -1
  196. package/lib/cjs/internal/workspace/SettingsEditorImpl.js.map +1 -1
  197. package/lib/cjs/internal/workspace/SettingsImpl.js.map +1 -1
  198. package/lib/cjs/internal/workspace/SettingsSchemasImpl.js.map +1 -1
  199. package/lib/cjs/internal/workspace/WorkspaceImpl.js.map +1 -1
  200. package/lib/cjs/internal/workspace/WorkspaceSqliteDb.js.map +1 -1
  201. package/lib/cjs/rpc/multipart.js.map +1 -1
  202. package/lib/cjs/rpc/tracing.js.map +1 -1
  203. package/lib/cjs/rpc/web/logging.js.map +1 -1
  204. package/lib/cjs/rpc/web/request.js.map +1 -1
  205. package/lib/cjs/rpc/web/response.js.map +1 -1
  206. package/lib/cjs/rpc-impl/DevToolsRpcImpl.js.map +1 -1
  207. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  208. package/lib/cjs/rpc-impl/IModelTileRpcImpl.js.map +1 -1
  209. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
  210. package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
  211. package/lib/cjs/workspace/Settings.d.ts +6 -4
  212. package/lib/cjs/workspace/Settings.d.ts.map +1 -1
  213. package/lib/cjs/workspace/Settings.js.map +1 -1
  214. package/lib/cjs/workspace/SettingsDb.js.map +1 -1
  215. package/lib/cjs/workspace/SettingsEditor.js.map +1 -1
  216. package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
  217. package/lib/cjs/workspace/Workspace.js.map +1 -1
  218. package/lib/cjs/workspace/WorkspaceEditor.js.map +1 -1
  219. package/lib/esm/BackendHubAccess.d.ts +38 -0
  220. package/lib/esm/BackendHubAccess.d.ts.map +1 -1
  221. package/lib/esm/BackendHubAccess.js.map +1 -1
  222. package/lib/esm/BackendLoggerCategory.js.map +1 -1
  223. package/lib/esm/BisCoreSchema.js.map +1 -1
  224. package/lib/esm/BlobContainerService.js.map +1 -1
  225. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  226. package/lib/esm/BriefcaseManager.js +6 -3
  227. package/lib/esm/BriefcaseManager.js.map +1 -1
  228. package/lib/esm/CatalogDb.js.map +1 -1
  229. package/lib/esm/Category.d.ts +4 -4
  230. package/lib/esm/Category.js.map +1 -1
  231. package/lib/esm/ChangeSummaryManager.js +2 -2
  232. package/lib/esm/ChangeSummaryManager.js.map +1 -1
  233. package/lib/esm/ChangedElementsDb.js.map +1 -1
  234. package/lib/esm/ChangesetECAdaptor.d.ts +9 -1
  235. package/lib/esm/ChangesetECAdaptor.d.ts.map +1 -1
  236. package/lib/esm/ChangesetECAdaptor.js +255 -249
  237. package/lib/esm/ChangesetECAdaptor.js.map +1 -1
  238. package/lib/esm/ChangesetReader.d.ts +186 -0
  239. package/lib/esm/ChangesetReader.d.ts.map +1 -0
  240. package/lib/esm/ChangesetReader.js +368 -0
  241. package/lib/esm/ChangesetReader.js.map +1 -0
  242. package/lib/esm/ChangesetReaderTypes.d.ts +120 -0
  243. package/lib/esm/ChangesetReaderTypes.d.ts.map +1 -0
  244. package/lib/esm/ChangesetReaderTypes.js +20 -0
  245. package/lib/esm/ChangesetReaderTypes.js.map +1 -0
  246. package/lib/esm/ChannelControl.js.map +1 -1
  247. package/lib/esm/CheckpointManager.js.map +1 -1
  248. package/lib/esm/ClassRegistry.js +5 -5
  249. package/lib/esm/ClassRegistry.js.map +1 -1
  250. package/lib/esm/CloudSqlite.d.ts +1 -1
  251. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  252. package/lib/esm/CloudSqlite.js +69 -14
  253. package/lib/esm/CloudSqlite.js.map +1 -1
  254. package/lib/esm/CodeService.js.map +1 -1
  255. package/lib/esm/CodeSpecs.d.ts +3 -3
  256. package/lib/esm/CodeSpecs.js.map +1 -1
  257. package/lib/esm/ConcurrentQuery.js.map +1 -1
  258. package/lib/esm/CustomViewState3dCreator.js.map +1 -1
  259. package/lib/esm/DevTools.js.map +1 -1
  260. package/lib/esm/DisplayStyle.d.ts +2 -2
  261. package/lib/esm/DisplayStyle.js.map +1 -1
  262. package/lib/esm/ECDb.js.map +1 -1
  263. package/lib/esm/ECSchemaXmlContext.js.map +1 -1
  264. package/lib/esm/ECSqlRowExecutor.js.map +1 -1
  265. package/lib/esm/ECSqlStatement.d.ts.map +1 -1
  266. package/lib/esm/ECSqlStatement.js.map +1 -1
  267. package/lib/esm/ECSqlSyncReader.js.map +1 -1
  268. package/lib/esm/EditTxn.d.ts +55 -1
  269. package/lib/esm/EditTxn.d.ts.map +1 -1
  270. package/lib/esm/EditTxn.js +43 -1
  271. package/lib/esm/EditTxn.js.map +1 -1
  272. package/lib/esm/Element.d.ts +79 -10
  273. package/lib/esm/Element.d.ts.map +1 -1
  274. package/lib/esm/Element.js +38 -2
  275. package/lib/esm/Element.js.map +1 -1
  276. package/lib/esm/ElementAspect.d.ts +1 -1
  277. package/lib/esm/ElementAspect.js.map +1 -1
  278. package/lib/esm/ElementGraphics.js.map +1 -1
  279. package/lib/esm/ElementTreeWalker.d.ts +5 -5
  280. package/lib/esm/ElementTreeWalker.js.map +1 -1
  281. package/lib/esm/Entity.js.map +1 -1
  282. package/lib/esm/EntityReferences.js.map +1 -1
  283. package/lib/esm/ExportGraphics.js.map +1 -1
  284. package/lib/esm/ExternalSource.d.ts +2 -2
  285. package/lib/esm/ExternalSource.d.ts.map +1 -1
  286. package/lib/esm/ExternalSource.js.map +1 -1
  287. package/lib/esm/FontFile.js.map +1 -1
  288. package/lib/esm/GeoCoordConfig.js.map +1 -1
  289. package/lib/esm/GeographicCRSServices.d.ts +15 -0
  290. package/lib/esm/GeographicCRSServices.d.ts.map +1 -1
  291. package/lib/esm/GeographicCRSServices.js +12 -4
  292. package/lib/esm/GeographicCRSServices.js.map +1 -1
  293. package/lib/esm/GeometrySummary.js +47 -47
  294. package/lib/esm/GeometrySummary.js.map +1 -1
  295. package/lib/esm/IModelDb.d.ts +31 -23
  296. package/lib/esm/IModelDb.d.ts.map +1 -1
  297. package/lib/esm/IModelDb.js +54 -35
  298. package/lib/esm/IModelDb.js.map +1 -1
  299. package/lib/esm/IModelDbFonts.js.map +1 -1
  300. package/lib/esm/IModelElementCloneContext.js.map +1 -1
  301. package/lib/esm/IModelHost.js.map +1 -1
  302. package/lib/esm/IModelIncrementalSchemaLocater.js.map +1 -1
  303. package/lib/esm/IModelJsFs.js.map +1 -1
  304. package/lib/esm/ImageSourceConversion.js.map +1 -1
  305. package/lib/esm/IpcHost.d.ts.map +1 -1
  306. package/lib/esm/IpcHost.js +33 -13
  307. package/lib/esm/IpcHost.js.map +1 -1
  308. package/lib/esm/LineStyle.d.ts +6 -6
  309. package/lib/esm/LineStyle.js.map +1 -1
  310. package/lib/esm/LocalHub.js +1 -1
  311. package/lib/esm/LocalHub.js.map +1 -1
  312. package/lib/esm/LocalhostIpcHost.js.map +1 -1
  313. package/lib/esm/LockControl.d.ts +85 -1
  314. package/lib/esm/LockControl.d.ts.map +1 -1
  315. package/lib/esm/LockControl.js.map +1 -1
  316. package/lib/esm/Material.d.ts +1 -1
  317. package/lib/esm/Material.js.map +1 -1
  318. package/lib/esm/Model.d.ts +40 -6
  319. package/lib/esm/Model.d.ts.map +1 -1
  320. package/lib/esm/Model.js +24 -0
  321. package/lib/esm/Model.js.map +1 -1
  322. package/lib/esm/NativeAppStorage.js.map +1 -1
  323. package/lib/esm/NativeHost.js.map +1 -1
  324. package/lib/esm/NavigationRelationship.js.map +1 -1
  325. package/lib/esm/PartialChangeUnifier.d.ts +77 -0
  326. package/lib/esm/PartialChangeUnifier.d.ts.map +1 -0
  327. package/lib/esm/PartialChangeUnifier.js +230 -0
  328. package/lib/esm/PartialChangeUnifier.js.map +1 -0
  329. package/lib/esm/PromiseMemoizer.js.map +1 -1
  330. package/lib/esm/PropertyStore.js.map +1 -1
  331. package/lib/esm/Relationship.d.ts +10 -10
  332. package/lib/esm/Relationship.js +6 -6
  333. package/lib/esm/Relationship.js.map +1 -1
  334. package/lib/esm/RpcBackend.js.map +1 -1
  335. package/lib/esm/SQLiteDb.js.map +1 -1
  336. package/lib/esm/Schema.js.map +1 -1
  337. package/lib/esm/SchemaSync.js.map +1 -1
  338. package/lib/esm/SchemaUtils.js.map +1 -1
  339. package/lib/esm/SheetIndex.d.ts +4 -4
  340. package/lib/esm/SheetIndex.d.ts.map +1 -1
  341. package/lib/esm/SheetIndex.js.map +1 -1
  342. package/lib/esm/SqliteChangesetReader.d.ts.map +1 -1
  343. package/lib/esm/SqliteChangesetReader.js +1 -1
  344. package/lib/esm/SqliteChangesetReader.js.map +1 -1
  345. package/lib/esm/SqliteStatement.js.map +1 -1
  346. package/lib/esm/StashManager.js.map +1 -1
  347. package/lib/esm/Texture.d.ts +1 -1
  348. package/lib/esm/Texture.js.map +1 -1
  349. package/lib/esm/TileStorage.js.map +1 -1
  350. package/lib/esm/TxnManager.d.ts +114 -4
  351. package/lib/esm/TxnManager.d.ts.map +1 -1
  352. package/lib/esm/TxnManager.js +196 -8
  353. package/lib/esm/TxnManager.js.map +1 -1
  354. package/lib/esm/ViewDefinition.d.ts +25 -13
  355. package/lib/esm/ViewDefinition.d.ts.map +1 -1
  356. package/lib/esm/ViewDefinition.js +78 -26
  357. package/lib/esm/ViewDefinition.js.map +1 -1
  358. package/lib/esm/ViewStateHydrator.js.map +1 -1
  359. package/lib/esm/ViewStore.d.ts.map +1 -1
  360. package/lib/esm/ViewStore.js +64 -22
  361. package/lib/esm/ViewStore.js.map +1 -1
  362. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +1 -1
  363. package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  364. package/lib/esm/annotations/FrameGeometry.js.map +1 -1
  365. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  366. package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
  367. package/lib/esm/annotations/TextAnnotationGeometry.js.map +1 -1
  368. package/lib/esm/annotations/TextBlockGeometry.js.map +1 -1
  369. package/lib/esm/annotations/TextBlockLayout.js.map +1 -1
  370. package/lib/esm/core-backend.d.ts +3 -0
  371. package/lib/esm/core-backend.d.ts.map +1 -1
  372. package/lib/esm/core-backend.js +3 -0
  373. package/lib/esm/core-backend.js.map +1 -1
  374. package/lib/esm/domains/FunctionalElements.d.ts +1 -1
  375. package/lib/esm/domains/FunctionalElements.d.ts.map +1 -1
  376. package/lib/esm/domains/FunctionalElements.js.map +1 -1
  377. package/lib/esm/domains/FunctionalSchema.js.map +1 -1
  378. package/lib/esm/domains/GenericElements.d.ts +2 -2
  379. package/lib/esm/domains/GenericElements.d.ts.map +1 -1
  380. package/lib/esm/domains/GenericElements.js.map +1 -1
  381. package/lib/esm/domains/GenericSchema.js.map +1 -1
  382. package/lib/esm/internal/ChangesetConflictArgs.js.map +1 -1
  383. package/lib/esm/internal/ChannelAdmin.d.ts +2 -2
  384. package/lib/esm/internal/ChannelAdmin.d.ts.map +1 -1
  385. package/lib/esm/internal/ChannelAdmin.js.map +1 -1
  386. package/lib/esm/internal/ElementLRUCache.js.map +1 -1
  387. package/lib/esm/internal/FontFileImpl.js.map +1 -1
  388. package/lib/esm/internal/HubMock.d.ts +2 -0
  389. package/lib/esm/internal/HubMock.d.ts.map +1 -1
  390. package/lib/esm/internal/HubMock.js +7 -0
  391. package/lib/esm/internal/HubMock.js.map +1 -1
  392. package/lib/esm/internal/IModelDbFontsImpl.js.map +1 -1
  393. package/lib/esm/internal/IntegrityCheck.d.ts +10 -10
  394. package/lib/esm/internal/IntegrityCheck.js +22 -22
  395. package/lib/esm/internal/IntegrityCheck.js.map +1 -1
  396. package/lib/esm/internal/NativePlatform.js.map +1 -1
  397. package/lib/esm/internal/NoLocks.d.ts.map +1 -1
  398. package/lib/esm/internal/NoLocks.js +6 -0
  399. package/lib/esm/internal/NoLocks.js.map +1 -1
  400. package/lib/esm/internal/OnlineStatus.js.map +1 -1
  401. package/lib/esm/internal/ServerBasedLocks.d.ts +12 -0
  402. package/lib/esm/internal/ServerBasedLocks.d.ts.map +1 -1
  403. package/lib/esm/internal/ServerBasedLocks.js +286 -5
  404. package/lib/esm/internal/ServerBasedLocks.js.map +1 -1
  405. package/lib/esm/internal/Symbols.js.map +1 -1
  406. package/lib/esm/internal/annotations/fields.js.map +1 -1
  407. package/lib/esm/internal/cross-package.js.map +1 -1
  408. package/lib/esm/internal/workspace/SettingsEditorImpl.js.map +1 -1
  409. package/lib/esm/internal/workspace/SettingsImpl.js.map +1 -1
  410. package/lib/esm/internal/workspace/SettingsSchemasImpl.js.map +1 -1
  411. package/lib/esm/internal/workspace/WorkspaceImpl.js.map +1 -1
  412. package/lib/esm/internal/workspace/WorkspaceSqliteDb.js.map +1 -1
  413. package/lib/esm/rpc/multipart.js.map +1 -1
  414. package/lib/esm/rpc/tracing.js.map +1 -1
  415. package/lib/esm/rpc/web/logging.js.map +1 -1
  416. package/lib/esm/rpc/web/request.js.map +1 -1
  417. package/lib/esm/rpc/web/response.js.map +1 -1
  418. package/lib/esm/rpc-impl/DevToolsRpcImpl.js.map +1 -1
  419. package/lib/esm/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  420. package/lib/esm/rpc-impl/IModelTileRpcImpl.js.map +1 -1
  421. package/lib/esm/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
  422. package/lib/esm/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
  423. package/lib/esm/test/AdvancedEqual.js.map +1 -1
  424. package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
  425. package/lib/esm/test/AttachDb.test.js +11 -11
  426. package/lib/esm/test/AttachDb.test.js.map +1 -1
  427. package/lib/esm/test/ElementDrivesElement.test.d.ts.map +1 -1
  428. package/lib/esm/test/ElementDrivesElement.test.js +23 -23
  429. package/lib/esm/test/ElementDrivesElement.test.js.map +1 -1
  430. package/lib/esm/test/ElementLRUCache.test.js.map +1 -1
  431. package/lib/esm/test/GeometryTestUtil.js.map +1 -1
  432. package/lib/esm/test/IModelHost.test.js.map +1 -1
  433. package/lib/esm/test/IModelTestUtils.d.ts +1 -0
  434. package/lib/esm/test/IModelTestUtils.d.ts.map +1 -1
  435. package/lib/esm/test/IModelTestUtils.js +5 -0
  436. package/lib/esm/test/IModelTestUtils.js.map +1 -1
  437. package/lib/esm/test/ImageSourceConversion.test.js.map +1 -1
  438. package/lib/esm/test/IpcHost.test.js +112 -0
  439. package/lib/esm/test/IpcHost.test.js.map +1 -1
  440. package/lib/esm/test/KnownTestLocations.js.map +1 -1
  441. package/lib/esm/test/PrintElementTree.js.map +1 -1
  442. package/lib/esm/test/PropertyDb.test.js.map +1 -1
  443. package/lib/esm/test/RevisionUtility.js.map +1 -1
  444. package/lib/esm/test/SchemaUtils.test.js +25 -25
  445. package/lib/esm/test/SchemaUtils.test.js.map +1 -1
  446. package/lib/esm/test/SequentialLogMatcher.js.map +1 -1
  447. package/lib/esm/test/SquashSchemaAndDataChanges.test.js +129 -129
  448. package/lib/esm/test/SquashSchemaAndDataChanges.test.js.map +1 -1
  449. package/lib/esm/test/TestChangeSetUtility.js.map +1 -1
  450. package/lib/esm/test/TestEditTxn.js.map +1 -1
  451. package/lib/esm/test/TestUtils.js.map +1 -1
  452. package/lib/esm/test/annotations/Fields.test.js +53 -53
  453. package/lib/esm/test/annotations/Fields.test.js.map +1 -1
  454. package/lib/esm/test/annotations/FrameGeometry.test.js.map +1 -1
  455. package/lib/esm/test/annotations/LeaderGeometry.test.js +0 -1
  456. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  457. package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
  458. package/lib/esm/test/annotations/TextBlock.test.js.map +1 -1
  459. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/old.config.js.map +1 -1
  460. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
  461. package/lib/esm/test/categories/Category.test.js.map +1 -1
  462. package/lib/esm/test/codespec/CodeSpec.test.js.map +1 -1
  463. package/lib/esm/test/ecdb/CTE.test.js +88 -88
  464. package/lib/esm/test/ecdb/CTE.test.js.map +1 -1
  465. package/lib/esm/test/ecdb/ConcurrentQuery.test.js +19 -19
  466. package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
  467. package/lib/esm/test/ecdb/ConcurrentQueryLoad.test.js +15 -15
  468. package/lib/esm/test/ecdb/ConcurrentQueryLoad.test.js.map +1 -1
  469. package/lib/esm/test/ecdb/ECDb.test.js +72 -72
  470. package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
  471. package/lib/esm/test/ecdb/ECDbTestHelper.js.map +1 -1
  472. package/lib/esm/test/ecdb/ECSchemaXmlContext.test.js.map +1 -1
  473. package/lib/esm/test/ecdb/ECSqlAst.test.js +65 -65
  474. package/lib/esm/test/ecdb/ECSqlAst.test.js.map +1 -1
  475. package/lib/esm/test/ecdb/ECSqlQuery.test.js +4 -4
  476. package/lib/esm/test/ecdb/ECSqlQuery.test.js.map +1 -1
  477. package/lib/esm/test/ecdb/ECSqlStatement.test.js +332 -332
  478. package/lib/esm/test/ecdb/ECSqlStatement.test.js.map +1 -1
  479. package/lib/esm/test/ecdb/ECSqlSyncReader.test.js.map +1 -1
  480. package/lib/esm/test/ecdb/QueryReaders.test.js +31 -31
  481. package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
  482. package/lib/esm/test/ecdb/SqliteStatement.test.js.map +1 -1
  483. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.js.map +1 -1
  484. package/lib/esm/test/ecsql/src/ECSqlTestGenerator.js +21 -21
  485. package/lib/esm/test/ecsql/src/ECSqlTestGenerator.js.map +1 -1
  486. package/lib/esm/test/ecsql/src/ECSqlTestParser.js.map +1 -1
  487. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js.map +1 -1
  488. package/lib/esm/test/element/DeleteDefinitionElements.test.js +819 -26
  489. package/lib/esm/test/element/DeleteDefinitionElements.test.js.map +1 -1
  490. package/lib/esm/test/element/ElementAspect.test.js +22 -22
  491. package/lib/esm/test/element/ElementAspect.test.js.map +1 -1
  492. package/lib/esm/test/element/ElementDependencyGraph.test.js.map +1 -1
  493. package/lib/esm/test/element/ElementRoundTrip.test.js +283 -142
  494. package/lib/esm/test/element/ElementRoundTrip.test.js.map +1 -1
  495. package/lib/esm/test/element/ExcludedElements.test.js.map +1 -1
  496. package/lib/esm/test/element/ExternalSource.test.js.map +1 -1
  497. package/lib/esm/test/element/NullStructArray.test.js +13 -13
  498. package/lib/esm/test/element/NullStructArray.test.js.map +1 -1
  499. package/lib/esm/test/element/ProjectInformationRecord.test.js.map +1 -1
  500. package/lib/esm/test/element/SheetInformationAspect.test.js.map +1 -1
  501. package/lib/esm/test/element/UrlLink.test.js.map +1 -1
  502. package/lib/esm/test/font/FontFile.test.js.map +1 -1
  503. package/lib/esm/test/font/IModelDbFonts.test.js.map +1 -1
  504. package/lib/esm/test/hubaccess/ApplyChangeset.test.js +32 -32
  505. package/lib/esm/test/hubaccess/ApplyChangeset.test.js.map +1 -1
  506. package/lib/esm/test/hubaccess/BriefcaseManager.test.js.map +1 -1
  507. package/lib/esm/test/hubaccess/CheckpointManager.test.js.map +1 -1
  508. package/lib/esm/test/hubaccess/Rebase.test.js +57 -57
  509. package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -1
  510. package/lib/esm/test/hubaccess/SemanticRebase.test.js +145 -145
  511. package/lib/esm/test/hubaccess/SemanticRebase.test.js.map +1 -1
  512. package/lib/esm/test/imageData.js.map +1 -1
  513. package/lib/esm/test/imodel/Code.test.js.map +1 -1
  514. package/lib/esm/test/imodel/ElementTreeWalker.test.js.map +1 -1
  515. package/lib/esm/test/imodel/GetTextureImage.test.js.map +1 -1
  516. package/lib/esm/test/imodel/IModel.test.js +45 -45
  517. package/lib/esm/test/imodel/IModel.test.js.map +1 -1
  518. package/lib/esm/test/imodel/ProjectExtents.test.js.map +1 -1
  519. package/lib/esm/test/imodel/SchemaXmlImport.test.js +77 -13
  520. package/lib/esm/test/imodel/SchemaXmlImport.test.js.map +1 -1
  521. package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
  522. package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
  523. package/lib/esm/test/incrementalSchemaLocater/TestContext.js.map +1 -1
  524. package/lib/esm/test/index.js.map +1 -1
  525. package/lib/esm/test/misc/DevTools.test.js.map +1 -1
  526. package/lib/esm/test/misc/EntitySubClasses.test.js.map +1 -1
  527. package/lib/esm/test/misc/GeoServices.test.js +43 -1
  528. package/lib/esm/test/misc/GeoServices.test.js.map +1 -1
  529. package/lib/esm/test/misc/PromiseMemoizer.test.js.map +1 -1
  530. package/lib/esm/test/native/DgnDbWorker.test.js.map +1 -1
  531. package/lib/esm/test/rpc/response.test.js.map +1 -1
  532. package/lib/esm/test/schema/ClassRegistry.test.js +99 -99
  533. package/lib/esm/test/schema/ClassRegistry.test.js.map +1 -1
  534. package/lib/esm/test/schema/FunctionalDomain.test.js.map +1 -1
  535. package/lib/esm/test/schema/GenericDomain.test.js.map +1 -1
  536. package/lib/esm/test/schema/IModelSchemaContext.test.js +9 -9
  537. package/lib/esm/test/schema/IModelSchemaContext.test.js.map +1 -1
  538. package/lib/esm/test/schema/SchemaImportCallbacks.test.js +19 -19
  539. package/lib/esm/test/schema/SchemaImportCallbacks.test.js.map +1 -1
  540. package/lib/esm/test/sheetindex/SheetIndex.test.js.map +1 -1
  541. package/lib/esm/test/standalone/ChangeMerge.test.js.map +1 -1
  542. package/lib/esm/test/standalone/ChangesetReader.test.js +4201 -1671
  543. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  544. package/lib/esm/test/standalone/CustomViewState3dCreator.test.js.map +1 -1
  545. package/lib/esm/test/standalone/DeleteElements.test.d.ts +2 -0
  546. package/lib/esm/test/standalone/DeleteElements.test.d.ts.map +1 -0
  547. package/lib/esm/test/standalone/DeleteElements.test.js +625 -0
  548. package/lib/esm/test/standalone/DeleteElements.test.js.map +1 -0
  549. package/lib/esm/test/standalone/DisplayStyle.test.js.map +1 -1
  550. package/lib/esm/test/standalone/Drawing.test.js.map +1 -1
  551. package/lib/esm/test/standalone/EditTxn.test.js.map +1 -1
  552. package/lib/esm/test/standalone/ElementGraphics.test.js.map +1 -1
  553. package/lib/esm/test/standalone/ElementMesh.test.js.map +1 -1
  554. package/lib/esm/test/standalone/ExportGraphics.test.js +14 -14
  555. package/lib/esm/test/standalone/ExportGraphics.test.js.map +1 -1
  556. package/lib/esm/test/standalone/GeometryChangeEvents.test.js.map +1 -1
  557. package/lib/esm/test/standalone/GeometryStream.test.js.map +1 -1
  558. package/lib/esm/test/standalone/HubMock.test.js.map +1 -1
  559. package/lib/esm/test/standalone/IModelLimits.test.js.map +1 -1
  560. package/lib/esm/test/standalone/IModelWrite.test.js +27 -27
  561. package/lib/esm/test/standalone/IModelWrite.test.js.map +1 -1
  562. package/lib/esm/test/standalone/ITwinWorkspace.test.js.map +1 -1
  563. package/lib/esm/test/standalone/InlineGeometryPartReferences.test.js.map +1 -1
  564. package/lib/esm/test/standalone/IntegrityCheck.test.js +214 -5
  565. package/lib/esm/test/standalone/IntegrityCheck.test.js.map +1 -1
  566. package/lib/esm/test/standalone/MergeConflict.test.js.map +1 -1
  567. package/lib/esm/test/standalone/NativeAppStorage.test.js.map +1 -1
  568. package/lib/esm/test/standalone/RenderMaterialElement.test.js.map +1 -1
  569. package/lib/esm/test/standalone/RenderTimeline.test.js.map +1 -1
  570. package/lib/esm/test/standalone/SQLiteDb.test.js.map +1 -1
  571. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.d.ts +2 -0
  572. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.d.ts.map +1 -0
  573. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +1862 -0
  574. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -0
  575. package/lib/esm/test/standalone/SchemaUtils.test.js.map +1 -1
  576. package/lib/esm/test/standalone/SectionDrawing.test.js.map +1 -1
  577. package/lib/esm/test/standalone/ServerBasedLocks.test.js +907 -3
  578. package/lib/esm/test/standalone/ServerBasedLocks.test.js.map +1 -1
  579. package/lib/esm/test/standalone/Setting.test.js.map +1 -1
  580. package/lib/esm/test/standalone/Settings.test.js.map +1 -1
  581. package/lib/esm/test/standalone/SettingsSchemas.test.js.map +1 -1
  582. package/lib/esm/test/standalone/SnapshotDb.test.js.map +1 -1
  583. package/lib/esm/test/standalone/StandaloneDb.test.js +20 -20
  584. package/lib/esm/test/standalone/StandaloneDb.test.js.map +1 -1
  585. package/lib/esm/test/standalone/Texture.test.js.map +1 -1
  586. package/lib/esm/test/standalone/TileCache.test.js.map +1 -1
  587. package/lib/esm/test/standalone/TileTree.test.js.map +1 -1
  588. package/lib/esm/test/standalone/TxnManager.test.js +90 -0
  589. package/lib/esm/test/standalone/TxnManager.test.js.map +1 -1
  590. package/lib/esm/test/standalone/ViewDefinition.test.js +18 -7
  591. package/lib/esm/test/standalone/ViewDefinition.test.js.map +1 -1
  592. package/lib/esm/test/standalone/ViewStoreDb.test.js.map +1 -1
  593. package/lib/esm/test/standalone/Workspace.test.js.map +1 -1
  594. package/lib/esm/test/standalone/iModelDb.test.js.map +1 -1
  595. package/lib/esm/test/workspace/SettingsDb.test.js.map +1 -1
  596. package/lib/esm/workspace/Settings.d.ts +6 -4
  597. package/lib/esm/workspace/Settings.d.ts.map +1 -1
  598. package/lib/esm/workspace/Settings.js.map +1 -1
  599. package/lib/esm/workspace/SettingsDb.js.map +1 -1
  600. package/lib/esm/workspace/SettingsEditor.js.map +1 -1
  601. package/lib/esm/workspace/SettingsSchemas.js.map +1 -1
  602. package/lib/esm/workspace/Workspace.js.map +1 -1
  603. package/lib/esm/workspace/WorkspaceEditor.js.map +1 -1
  604. package/package.json +15 -15
@@ -0,0 +1,1862 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ /*---------------------------------------------------------------------------------------------
54
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
55
+ * See LICENSE.md in the project root for license terms and full copyright notice.
56
+ *--------------------------------------------------------------------------------------------*/
57
+ import { DbResult, Id64 } from "@itwin/core-bentley";
58
+ import { Code, ColorDef, IModel, QueryBinder, QueryRowFormat, SubCategoryAppearance } from "@itwin/core-common";
59
+ import { Arc3d, IModelJson, Point3d } from "@itwin/core-geometry";
60
+ import * as chai from "chai";
61
+ import { assert, expect } from "chai";
62
+ import * as path from "node:path";
63
+ import { DrawingCategory } from "../../Category";
64
+ import { ChangesetECAdaptor, ChangesetECAdaptor as ECChangesetAdaptor, ECChangeUnifierCache, PartialECChangeUnifier } from "../../ChangesetECAdaptor";
65
+ import { _nativeDb, ChannelControl, GraphicalElement2d, Subject, SubjectOwnsSubjects } from "../../core-backend";
66
+ import { BriefcaseDb, SnapshotDb } from "../../IModelDb";
67
+ import { HubMock } from "../../internal/HubMock";
68
+ import { SqliteChangesetReader } from "../../SqliteChangesetReader";
69
+ import { HubWrappers, IModelTestUtils } from "../IModelTestUtils";
70
+ import { KnownTestLocations } from "../KnownTestLocations";
71
+ import { EditTxn } from "../../EditTxn";
72
+ /* eslint-disable @typescript-eslint/no-deprecated */ // This test file will be removed subsequently, so we can allow usage of deprecated APIs within it.
73
+ // This test file also contains tests outside of the ChangesetECAdaptor, so be cautious while removing it, remove just the tests which are related to ChangesetECAdaptor.
74
+ function startTestTxn(iModel, description = "changeset reader") {
75
+ const txn = new EditTxn(iModel, description);
76
+ txn.start();
77
+ return txn;
78
+ }
79
+ async function importSchemaStrings(txn, schemas) {
80
+ if (txn.isActive)
81
+ txn.saveChanges();
82
+ await txn.iModel.importSchemaStrings(schemas);
83
+ }
84
+ describe("Sqlite Changeset Reader + ChangesetECAdaptor API", async () => {
85
+ let iTwinId;
86
+ before(() => {
87
+ HubMock.startup("SqliteChangesetReaderAndChangesetECAdaptorTest", KnownTestLocations.outputDir);
88
+ iTwinId = HubMock.iTwinId;
89
+ });
90
+ after(() => HubMock.shutdown());
91
+ it("Able to recover from when ExclusiveRootClassId is NULL for overflow table", async () => {
92
+ /**
93
+ * 1. Import schema with class that span overflow table.
94
+ * 2. Insert a element for the class.
95
+ * 3. Push changes to hub.
96
+ * 4. Update the element.
97
+ * 5. Push changes to hub.
98
+ * 6. Delete the element.
99
+ * 7. Set ExclusiveRootClassId to NULL for overflow table. (Simulate the issue)
100
+ * 8. ECChangesetAdaptor should be able to read the changeset 2 in which element is updated against latest imodel where element is deleted.
101
+ */
102
+ const adminToken = "super manager token";
103
+ const iModelName = "test";
104
+ const nProps = 36;
105
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
106
+ assert.isNotEmpty(rwIModelId);
107
+ const rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
108
+ const txn = startTestTxn(rwIModel, "recover overflow table changeset reader");
109
+ // 1. Import schema with class that span overflow table.
110
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
111
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
112
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
113
+ <ECEntityClass typeName="Test2dElement">
114
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
115
+ ${Array(nProps).fill(undefined).map((_, i) => `<ECProperty propertyName="p${i}" typeName="string"/>`).join("\n")}
116
+ </ECEntityClass>
117
+ </ECSchema>`;
118
+ await importSchemaStrings(txn, [schema]);
119
+ rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
120
+ // Create drawing model and category
121
+ await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
122
+ const codeProps = Code.createEmpty();
123
+ codeProps.value = "DrawingModel";
124
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
125
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "MyDrawingCategory");
126
+ if (undefined === drawingCategoryId)
127
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
128
+ // Insert element with 100 properties
129
+ const geomArray = [
130
+ Arc3d.createXY(Point3d.create(0, 0), 5),
131
+ Arc3d.createXY(Point3d.create(5, 5), 2),
132
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
133
+ ];
134
+ const geometryStream = [];
135
+ for (const geom of geomArray) {
136
+ const arcData = IModelJson.Writer.toIModelJson(geom);
137
+ geometryStream.push(arcData);
138
+ }
139
+ const props = Array(nProps).fill(undefined).map((_, i) => {
140
+ return { [`p${i}`]: `test_${i}` };
141
+ }).reduce((acc, curr) => {
142
+ return { ...acc, ...curr };
143
+ }, {});
144
+ const geomElement = {
145
+ classFullName: `TestDomain:Test2dElement`,
146
+ model: drawingModelId,
147
+ category: drawingCategoryId,
148
+ code: Code.createEmpty(),
149
+ geom: geometryStream,
150
+ ...props,
151
+ };
152
+ // 2. Insert a element for the class.
153
+ const id = txn.insertElement(geomElement);
154
+ assert.isTrue(Id64.isValidId64(id), "insert worked");
155
+ txn.saveChanges();
156
+ // 3. Push changes to hub.
157
+ await rwIModel.pushChanges({ description: "insert element", accessToken: adminToken });
158
+ // 4. Update the element.
159
+ const updatedElementProps = Object.assign(rwIModel.elements.getElementProps(id), Array(nProps).fill(undefined).map((_, i) => {
160
+ return { [`p${i}`]: `updated_${i}` };
161
+ }).reduce((acc, curr) => {
162
+ return { ...acc, ...curr };
163
+ }, {}));
164
+ await rwIModel.locks.acquireLocks({ exclusive: id });
165
+ txn.updateElement(updatedElementProps);
166
+ txn.saveChanges();
167
+ // 5. Push changes to hub.
168
+ await rwIModel.pushChanges({ description: "update element", accessToken: adminToken });
169
+ await rwIModel.locks.acquireLocks({ exclusive: id });
170
+ // 6. Delete the element.
171
+ txn.deleteElement(id);
172
+ txn.saveChanges();
173
+ await rwIModel.pushChanges({ description: "delete element", accessToken: adminToken });
174
+ const targetDir = path.join(KnownTestLocations.outputDir, rwIModelId, "changesets");
175
+ const changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
176
+ const reader = SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, db: rwIModel, disableSchemaCheck: true });
177
+ // Set ExclusiveRootClassId to NULL for overflow table to simulate the issue
178
+ expect(rwIModel[_nativeDb].executeSql("UPDATE ec_Table SET ExclusiveRootClassId=NULL WHERE Name='bis_GeometricElement2d_Overflow'")).to.be.eq(DbResult.BE_SQLITE_OK);
179
+ const adaptor = new ECChangesetAdaptor(reader);
180
+ let assertOnOverflowTable = false;
181
+ const classId = getClassIdByName(rwIModel, "GeometricElement2d");
182
+ while (adaptor.step()) {
183
+ if (adaptor.op === "Updated" && adaptor.inserted?.$meta?.tables[0] === "bis_GeometricElement2d_Overflow") {
184
+ assert.isUndefined(adaptor.inserted.ECClassId);
185
+ assert.equal(adaptor.inserted.ECInstanceId, "");
186
+ assert.deepEqual(adaptor.inserted.$meta?.tables, ["bis_GeometricElement2d_Overflow"]);
187
+ assert.equal(adaptor.inserted.$meta?.op, "Updated");
188
+ assert.equal(adaptor.inserted.$meta?.classFullName, "BisCore:GeometricElement2d");
189
+ assert.equal(adaptor.inserted.$meta.fallbackClassId, classId);
190
+ assert.deepEqual(adaptor.inserted.$meta?.changeIndexes, [3]);
191
+ assert.equal(adaptor.inserted.$meta?.stage, "New");
192
+ assert.equal(adaptor.deleted.ECInstanceId, "");
193
+ assert.isUndefined(adaptor.deleted.ECClassId);
194
+ assert.deepEqual(adaptor.deleted.$meta?.tables, ["bis_GeometricElement2d_Overflow"]);
195
+ assert.equal(adaptor.deleted.$meta?.op, "Updated");
196
+ assert.equal(adaptor.deleted.$meta?.classFullName, "BisCore:GeometricElement2d");
197
+ assert.equal(adaptor.deleted.$meta.fallbackClassId, classId);
198
+ assert.deepEqual(adaptor.deleted.$meta?.changeIndexes, [3]);
199
+ assert.equal(adaptor.deleted.$meta?.stage, "Old");
200
+ assertOnOverflowTable = true;
201
+ }
202
+ }
203
+ assert.isTrue(assertOnOverflowTable);
204
+ txn.end();
205
+ rwIModel.close();
206
+ });
207
+ function getClassIdByName(iModel, className) {
208
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
209
+ return iModel.withPreparedStatement(`SELECT ECInstanceId from meta.ECClassDef where Name=?`, (stmt) => {
210
+ stmt.bindString(1, className);
211
+ assert.equal(stmt.step(), DbResult.BE_SQLITE_ROW);
212
+ return stmt.getValue(0).getId();
213
+ });
214
+ }
215
+ async function getClassNameById(iModel, classId) {
216
+ const reader = iModel.createQueryReader(`select ec_classname(${classId});`);
217
+ if (await reader.step())
218
+ return reader.current[0];
219
+ return undefined;
220
+ }
221
+ it("Changeset reader / EC adaptor", async () => {
222
+ const adminToken = "super manager token";
223
+ const iModelName = "test";
224
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
225
+ assert.isNotEmpty(rwIModelId);
226
+ const rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
227
+ const txn = startTestTxn(rwIModel, "changeset reader EC adaptor");
228
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
229
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
230
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
231
+ <ECEntityClass typeName="Test2dElement">
232
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
233
+ <ECProperty propertyName="s" typeName="string"/>
234
+ </ECEntityClass>
235
+ </ECSchema>`;
236
+ await importSchemaStrings(txn, [schema]);
237
+ if (true || "push changes") {
238
+ // Push the changes to the hub
239
+ const prePushChangeSetId = rwIModel.changeset.id;
240
+ await rwIModel.pushChanges({ description: "push schema changeset", accessToken: adminToken });
241
+ const postPushChangeSetId = rwIModel.changeset.id;
242
+ assert(!!postPushChangeSetId);
243
+ expect(prePushChangeSetId !== postPushChangeSetId);
244
+ rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
245
+ }
246
+ await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
247
+ const codeProps = Code.createEmpty();
248
+ codeProps.value = "DrawingModel";
249
+ let totalEl = 0;
250
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
251
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "MyDrawingCategory");
252
+ if (undefined === drawingCategoryId)
253
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
254
+ txn.saveChanges("user 1: create drawing partition");
255
+ if (true || "push changes") {
256
+ // Push the changes to the hub
257
+ const prePushChangeSetId = rwIModel.changeset.id;
258
+ await rwIModel.pushChanges({ description: "user 1: create drawing partition", accessToken: adminToken });
259
+ const postPushChangeSetId = rwIModel.changeset.id;
260
+ assert(!!postPushChangeSetId);
261
+ expect(prePushChangeSetId !== postPushChangeSetId);
262
+ }
263
+ await rwIModel.locks.acquireLocks({ shared: drawingModelId });
264
+ const insertElements = (className = "Test2dElement", noOfElements = 10, userProp) => {
265
+ for (let m = 0; m < noOfElements; ++m) {
266
+ const geomArray = [
267
+ Arc3d.createXY(Point3d.create(0, 0), 5),
268
+ Arc3d.createXY(Point3d.create(5, 5), 2),
269
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
270
+ ];
271
+ const geometryStream = [];
272
+ for (const geom of geomArray) {
273
+ const arcData = IModelJson.Writer.toIModelJson(geom);
274
+ geometryStream.push(arcData);
275
+ }
276
+ const prop = userProp(++totalEl);
277
+ // Create props
278
+ const geomElement = {
279
+ classFullName: `TestDomain:${className}`,
280
+ model: drawingModelId,
281
+ category: drawingCategoryId,
282
+ code: Code.createEmpty(),
283
+ geom: geometryStream,
284
+ ...prop,
285
+ };
286
+ const id = txn.insertElement(geomElement);
287
+ assert.isTrue(Id64.isValidId64(id), "insert worked");
288
+ }
289
+ };
290
+ const generatedStr = new Array(10).join("x");
291
+ insertElements("Test2dElement", 1, () => {
292
+ return { s: generatedStr };
293
+ });
294
+ const updatedElements = async () => {
295
+ await rwIModel.locks.acquireLocks({ exclusive: "0x20000000004" });
296
+ const updatedElement = rwIModel.elements.getElementProps("0x20000000004");
297
+ updatedElement.s = "updated property";
298
+ txn.updateElement(updatedElement);
299
+ txn.saveChanges("user 1: updated data");
300
+ await rwIModel.pushChanges({ description: "user 1: update property id=0x20000000004", accessToken: adminToken });
301
+ };
302
+ txn.saveChanges("user 1: data");
303
+ if (true || "test local changes") {
304
+ const testChanges = async (changes) => {
305
+ assert.equal(changes.length, 3);
306
+ assert.equal(changes[0].ECInstanceId, "0x20000000001");
307
+ assert.equal(changes[0].$meta?.classFullName, "BisCore:DrawingModel");
308
+ assert.equal(changes[0].$meta?.op, "Updated");
309
+ assert.equal(changes[0].$meta?.stage, "New");
310
+ assert.isNotNull(changes[0].LastMod);
311
+ assert.isNotNull(changes[0].GeometryGuid);
312
+ assert.equal(changes[1].ECInstanceId, "0x20000000001");
313
+ assert.equal(changes[1].$meta?.classFullName, "BisCore:DrawingModel");
314
+ assert.equal(changes[1].$meta?.op, "Updated");
315
+ assert.equal(changes[1].$meta?.stage, "Old");
316
+ assert.isNull(changes[1].LastMod);
317
+ assert.isNull(changes[1].GeometryGuid);
318
+ assert.equal(changes[2].ECInstanceId, "0x20000000004");
319
+ assert.equal(changes[2].$meta?.classFullName, "TestDomain:Test2dElement");
320
+ assert.equal(changes[2].$meta?.op, "Inserted");
321
+ assert.equal(changes[2].$meta?.stage, "New");
322
+ const el = changes.filter((x) => x.ECInstanceId === "0x20000000004")[0];
323
+ assert.equal(el.Rotation, 0);
324
+ // eslint-disable-next-line @typescript-eslint/naming-convention
325
+ assert.deepEqual(el.Origin, { X: 0, Y: 0 });
326
+ // eslint-disable-next-line @typescript-eslint/naming-convention
327
+ assert.deepEqual(el.BBoxLow, { X: -25, Y: -25 });
328
+ // eslint-disable-next-line @typescript-eslint/naming-convention
329
+ assert.deepEqual(el.BBoxHigh, { X: 15, Y: 15 });
330
+ assert.equal(el.Category.Id, "0x20000000002");
331
+ assert.isNotEmpty(el.Category.RelECClassId);
332
+ const categoryRelClass = await getClassNameById(rwIModel, el.Category.RelECClassId);
333
+ assert.equal("BisCore:GeometricElement2dIsInCategory", categoryRelClass);
334
+ assert.equal(el.s, "xxxxxxxxx");
335
+ assert.isNull(el.CodeValue);
336
+ assert.isNull(el.UserLabel);
337
+ assert.isNull(el.JsonProperties);
338
+ assert.instanceOf(el.GeometryStream, Uint8Array);
339
+ assert.typeOf(el.FederationGuid, "string");
340
+ assert.typeOf(el.LastMod, "string");
341
+ // eslint-disable-next-line @typescript-eslint/naming-convention
342
+ assert.deepEqual(el.Parent, { Id: null, RelECClassId: null });
343
+ // eslint-disable-next-line @typescript-eslint/naming-convention
344
+ assert.deepEqual(el.TypeDefinition, { Id: null, RelECClassId: null });
345
+ assert.equal(el.CodeSpec.Id, "0x1");
346
+ assert.isNotEmpty(el.CodeSpec.RelECClassId);
347
+ const codeSpecRelClass = await getClassNameById(rwIModel, el.CodeSpec.RelECClassId);
348
+ assert.equal("BisCore:CodeSpecSpecifiesCode", codeSpecRelClass);
349
+ assert.equal(el.CodeScope.Id, "0x1");
350
+ assert.isNotEmpty(el.CodeScope.RelECClassId);
351
+ const codeScopeRelClass = await getClassNameById(rwIModel, el.CodeScope.RelECClassId);
352
+ assert.equal("BisCore:ElementScopesCode", codeScopeRelClass);
353
+ assert.deepEqual(el.$meta, {
354
+ tables: [
355
+ "bis_GeometricElement2d",
356
+ "bis_Element",
357
+ ],
358
+ op: "Inserted",
359
+ classFullName: "TestDomain:Test2dElement",
360
+ changeIndexes: [
361
+ 2,
362
+ 1,
363
+ ],
364
+ stage: "New",
365
+ });
366
+ };
367
+ if (true || "test with InMemoryInstanceCache") {
368
+ const env_1 = { stack: [], error: void 0, hasError: false };
369
+ try {
370
+ const reader = __addDisposableResource(env_1, SqliteChangesetReader.openLocalChanges({ db: rwIModel, disableSchemaCheck: true }), false);
371
+ const adaptor = __addDisposableResource(env_1, new ECChangesetAdaptor(reader), false);
372
+ const pcu = __addDisposableResource(env_1, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
373
+ while (adaptor.step()) {
374
+ pcu.appendFrom(adaptor);
375
+ }
376
+ await testChanges(Array.from(pcu.instances));
377
+ }
378
+ catch (e_1) {
379
+ env_1.error = e_1;
380
+ env_1.hasError = true;
381
+ }
382
+ finally {
383
+ __disposeResources(env_1);
384
+ }
385
+ }
386
+ if (true || "test with SqliteBackedInstanceCache") {
387
+ const env_2 = { stack: [], error: void 0, hasError: false };
388
+ try {
389
+ const reader = __addDisposableResource(env_2, SqliteChangesetReader.openLocalChanges({ db: rwIModel, disableSchemaCheck: true }), false);
390
+ const adaptor = __addDisposableResource(env_2, new ECChangesetAdaptor(reader), false);
391
+ const pcu = __addDisposableResource(env_2, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
392
+ while (adaptor.step()) {
393
+ pcu.appendFrom(adaptor);
394
+ }
395
+ await testChanges(Array.from(pcu.instances));
396
+ }
397
+ catch (e_2) {
398
+ env_2.error = e_2;
399
+ env_2.hasError = true;
400
+ }
401
+ finally {
402
+ __disposeResources(env_2);
403
+ }
404
+ }
405
+ }
406
+ const targetDir = path.join(KnownTestLocations.outputDir, rwIModelId, "changesets");
407
+ await rwIModel.pushChanges({ description: "schema changeset", accessToken: adminToken });
408
+ await updatedElements();
409
+ const changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
410
+ if (true || "updated element") {
411
+ const testChanges = (changes) => {
412
+ assert.equal(changes.length, 4);
413
+ const classId = getClassIdByName(rwIModel, "Test2dElement");
414
+ // new value
415
+ assert.equal(changes[2].ECInstanceId, "0x20000000004");
416
+ assert.equal(changes[2].ECClassId, classId);
417
+ assert.equal(changes[2].s, "updated property");
418
+ assert.equal(changes[2].$meta?.classFullName, "TestDomain:Test2dElement");
419
+ assert.equal(changes[2].$meta?.op, "Updated");
420
+ assert.equal(changes[2].$meta?.stage, "New");
421
+ // old value
422
+ assert.equal(changes[3].ECInstanceId, "0x20000000004");
423
+ assert.equal(changes[3].ECClassId, classId);
424
+ assert.equal(changes[3].s, "xxxxxxxxx");
425
+ assert.equal(changes[3].$meta?.classFullName, "TestDomain:Test2dElement");
426
+ assert.equal(changes[3].$meta?.op, "Updated");
427
+ assert.equal(changes[3].$meta?.stage, "Old");
428
+ };
429
+ if (true || "test with InMemoryInstanceCache") {
430
+ const env_3 = { stack: [], error: void 0, hasError: false };
431
+ try {
432
+ const reader = __addDisposableResource(env_3, SqliteChangesetReader.openFile({ fileName: changesets[3].pathname, db: rwIModel, disableSchemaCheck: true }), false);
433
+ const adaptor = __addDisposableResource(env_3, new ECChangesetAdaptor(reader), false);
434
+ const pcu = __addDisposableResource(env_3, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
435
+ while (adaptor.step()) {
436
+ pcu.appendFrom(adaptor);
437
+ }
438
+ testChanges(Array.from(pcu.instances));
439
+ }
440
+ catch (e_3) {
441
+ env_3.error = e_3;
442
+ env_3.hasError = true;
443
+ }
444
+ finally {
445
+ __disposeResources(env_3);
446
+ }
447
+ }
448
+ if (true || "test with SqliteBackedInstanceCache") {
449
+ const env_4 = { stack: [], error: void 0, hasError: false };
450
+ try {
451
+ const reader = __addDisposableResource(env_4, SqliteChangesetReader.openFile({ fileName: changesets[3].pathname, db: rwIModel, disableSchemaCheck: true }), false);
452
+ const adaptor = __addDisposableResource(env_4, new ECChangesetAdaptor(reader), false);
453
+ const pcu = __addDisposableResource(env_4, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
454
+ while (adaptor.step()) {
455
+ pcu.appendFrom(adaptor);
456
+ }
457
+ testChanges(Array.from(pcu.instances));
458
+ }
459
+ catch (e_4) {
460
+ env_4.error = e_4;
461
+ env_4.hasError = true;
462
+ }
463
+ finally {
464
+ __disposeResources(env_4);
465
+ }
466
+ }
467
+ }
468
+ if (true || "updated element when no classId") {
469
+ const otherDb = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("test.bim"));
470
+ const testChanges = (changes) => {
471
+ assert.equal(changes.length, 4);
472
+ // new value
473
+ assert.equal(changes[2].ECInstanceId, "0x20000000004");
474
+ assert.isUndefined(changes[2].ECClassId);
475
+ assert.isDefined(changes[2].$meta?.fallbackClassId);
476
+ assert.equal(changes[2].$meta?.fallbackClassId, "0x3d");
477
+ assert.isUndefined(changes[2].s);
478
+ assert.equal(changes[2].$meta?.classFullName, "BisCore:GeometricElement2d");
479
+ assert.equal(changes[2].$meta?.op, "Updated");
480
+ assert.equal(changes[2].$meta?.stage, "New");
481
+ // old value
482
+ assert.equal(changes[3].ECInstanceId, "0x20000000004");
483
+ assert.isUndefined(changes[3].ECClassId);
484
+ assert.isDefined(changes[3].$meta?.fallbackClassId);
485
+ assert.equal(changes[3].$meta?.fallbackClassId, "0x3d");
486
+ assert.isUndefined(changes[3].s);
487
+ assert.equal(changes[3].$meta?.classFullName, "BisCore:GeometricElement2d");
488
+ assert.equal(changes[3].$meta?.op, "Updated");
489
+ assert.equal(changes[3].$meta?.stage, "Old");
490
+ };
491
+ if (true || "test with InMemoryInstanceCache") {
492
+ const env_5 = { stack: [], error: void 0, hasError: false };
493
+ try {
494
+ const reader = __addDisposableResource(env_5, SqliteChangesetReader.openFile({ fileName: changesets[3].pathname, db: otherDb, disableSchemaCheck: true }), false);
495
+ const adaptor = __addDisposableResource(env_5, new ECChangesetAdaptor(reader), false);
496
+ const pcu = __addDisposableResource(env_5, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
497
+ while (adaptor.step()) {
498
+ pcu.appendFrom(adaptor);
499
+ }
500
+ testChanges(Array.from(pcu.instances));
501
+ }
502
+ catch (e_5) {
503
+ env_5.error = e_5;
504
+ env_5.hasError = true;
505
+ }
506
+ finally {
507
+ __disposeResources(env_5);
508
+ }
509
+ }
510
+ if (true || "test with SqliteBackedInstanceCache") {
511
+ const env_6 = { stack: [], error: void 0, hasError: false };
512
+ try {
513
+ const reader = __addDisposableResource(env_6, SqliteChangesetReader.openFile({ fileName: changesets[3].pathname, db: otherDb, disableSchemaCheck: true }), false);
514
+ const adaptor = __addDisposableResource(env_6, new ECChangesetAdaptor(reader), false);
515
+ const pcu = __addDisposableResource(env_6, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
516
+ while (adaptor.step()) {
517
+ pcu.appendFrom(adaptor);
518
+ }
519
+ testChanges(Array.from(pcu.instances));
520
+ }
521
+ catch (e_6) {
522
+ env_6.error = e_6;
523
+ env_6.hasError = true;
524
+ }
525
+ finally {
526
+ __disposeResources(env_6);
527
+ }
528
+ }
529
+ }
530
+ if (true || "test changeset file") {
531
+ const testChanges = async (changes) => {
532
+ assert.equal(changes.length, 3);
533
+ assert.equal(changes[0].ECInstanceId, "0x20000000001");
534
+ assert.equal(changes[0].$meta?.classFullName, "BisCore:DrawingModel");
535
+ assert.equal(changes[0].$meta?.op, "Updated");
536
+ assert.equal(changes[0].$meta?.stage, "New");
537
+ assert.isNotNull(changes[0].LastMod);
538
+ assert.isNotNull(changes[0].GeometryGuid);
539
+ assert.equal(changes[1].ECInstanceId, "0x20000000001");
540
+ assert.equal(changes[1].$meta?.classFullName, "BisCore:DrawingModel");
541
+ assert.equal(changes[1].$meta?.op, "Updated");
542
+ assert.equal(changes[1].$meta?.stage, "Old");
543
+ assert.isNull(changes[1].LastMod);
544
+ assert.isNull(changes[1].GeometryGuid);
545
+ assert.equal(changes[2].ECInstanceId, "0x20000000004");
546
+ assert.equal(changes[2].$meta?.classFullName, "TestDomain:Test2dElement");
547
+ assert.equal(changes[2].$meta?.op, "Inserted");
548
+ assert.equal(changes[2].$meta?.stage, "New");
549
+ const el = changes.filter((x) => x.ECInstanceId === "0x20000000004")[0];
550
+ assert.equal(el.Rotation, 0);
551
+ // eslint-disable-next-line @typescript-eslint/naming-convention
552
+ assert.deepEqual(el.Origin, { X: 0, Y: 0 });
553
+ // eslint-disable-next-line @typescript-eslint/naming-convention
554
+ assert.deepEqual(el.BBoxLow, { X: -25, Y: -25 });
555
+ // eslint-disable-next-line @typescript-eslint/naming-convention
556
+ assert.deepEqual(el.BBoxHigh, { X: 15, Y: 15 });
557
+ assert.equal(el.Category.Id, "0x20000000002");
558
+ assert.isNotEmpty(el.Category.RelECClassId);
559
+ const categoryRelClass = await getClassNameById(rwIModel, el.Category.RelECClassId);
560
+ assert.equal("BisCore:GeometricElement2dIsInCategory", categoryRelClass);
561
+ assert.equal(el.s, "xxxxxxxxx");
562
+ assert.isNull(el.CodeValue);
563
+ assert.isNull(el.UserLabel);
564
+ assert.isNull(el.JsonProperties);
565
+ assert.instanceOf(el.GeometryStream, Uint8Array);
566
+ assert.typeOf(el.FederationGuid, "string");
567
+ assert.typeOf(el.LastMod, "string");
568
+ // eslint-disable-next-line @typescript-eslint/naming-convention
569
+ assert.deepEqual(el.Parent, { Id: null, RelECClassId: null });
570
+ // eslint-disable-next-line @typescript-eslint/naming-convention
571
+ assert.deepEqual(el.TypeDefinition, { Id: null, RelECClassId: null });
572
+ assert.equal(el.CodeSpec.Id, "0x1");
573
+ assert.isNotEmpty(el.CodeSpec.RelECClassId);
574
+ const codeSpecRelClass = await getClassNameById(rwIModel, el.CodeSpec.RelECClassId);
575
+ assert.equal("BisCore:CodeSpecSpecifiesCode", codeSpecRelClass);
576
+ assert.equal(el.CodeScope.Id, "0x1");
577
+ assert.isNotEmpty(el.CodeScope.RelECClassId);
578
+ const codeScopeRelClass = await getClassNameById(rwIModel, el.CodeScope.RelECClassId);
579
+ assert.equal("BisCore:ElementScopesCode", codeScopeRelClass);
580
+ assert.deepEqual(el.$meta, {
581
+ tables: [
582
+ "bis_GeometricElement2d",
583
+ "bis_Element",
584
+ ],
585
+ op: "Inserted",
586
+ classFullName: "TestDomain:Test2dElement",
587
+ changeIndexes: [
588
+ 2,
589
+ 1,
590
+ ],
591
+ stage: "New",
592
+ });
593
+ };
594
+ if (true || "test with InMemoryInstanceCache") {
595
+ const env_7 = { stack: [], error: void 0, hasError: false };
596
+ try {
597
+ const reader = __addDisposableResource(env_7, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
598
+ const adaptor = __addDisposableResource(env_7, new ECChangesetAdaptor(reader), false);
599
+ const pcu = __addDisposableResource(env_7, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
600
+ while (adaptor.step()) {
601
+ pcu.appendFrom(adaptor);
602
+ }
603
+ await testChanges(Array.from(pcu.instances));
604
+ }
605
+ catch (e_7) {
606
+ env_7.error = e_7;
607
+ env_7.hasError = true;
608
+ }
609
+ finally {
610
+ __disposeResources(env_7);
611
+ }
612
+ }
613
+ if (true || "test with SqliteBackedInstanceCache") {
614
+ const env_8 = { stack: [], error: void 0, hasError: false };
615
+ try {
616
+ const reader = __addDisposableResource(env_8, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
617
+ const adaptor = __addDisposableResource(env_8, new ECChangesetAdaptor(reader), false);
618
+ const pcu = __addDisposableResource(env_8, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
619
+ while (adaptor.step()) {
620
+ pcu.appendFrom(adaptor);
621
+ }
622
+ await testChanges(Array.from(pcu.instances));
623
+ }
624
+ catch (e_8) {
625
+ env_8.error = e_8;
626
+ env_8.hasError = true;
627
+ }
628
+ finally {
629
+ __disposeResources(env_8);
630
+ }
631
+ }
632
+ }
633
+ if (true || "test ChangesetAdaptor.acceptClass()") {
634
+ const testChanges = (changes) => {
635
+ assert.equal(changes.length, 1);
636
+ assert.equal(changes[0].$meta?.classFullName, "TestDomain:Test2dElement");
637
+ };
638
+ if (true || "test with InMemoryInstanceCache") {
639
+ const env_9 = { stack: [], error: void 0, hasError: false };
640
+ try {
641
+ const reader = __addDisposableResource(env_9, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
642
+ const adaptor = __addDisposableResource(env_9, new ECChangesetAdaptor(reader), false);
643
+ adaptor.acceptClass("TestDomain.Test2dElement");
644
+ const pcu = __addDisposableResource(env_9, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
645
+ while (adaptor.step()) {
646
+ pcu.appendFrom(adaptor);
647
+ }
648
+ testChanges(Array.from(pcu.instances));
649
+ }
650
+ catch (e_9) {
651
+ env_9.error = e_9;
652
+ env_9.hasError = true;
653
+ }
654
+ finally {
655
+ __disposeResources(env_9);
656
+ }
657
+ }
658
+ if (true || "test with SqliteBackedInstanceCache") {
659
+ const env_10 = { stack: [], error: void 0, hasError: false };
660
+ try {
661
+ const reader = __addDisposableResource(env_10, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
662
+ const adaptor = __addDisposableResource(env_10, new ECChangesetAdaptor(reader), false);
663
+ adaptor.acceptClass("TestDomain.Test2dElement");
664
+ const pcu = __addDisposableResource(env_10, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
665
+ while (adaptor.step()) {
666
+ pcu.appendFrom(adaptor);
667
+ }
668
+ testChanges(Array.from(pcu.instances));
669
+ }
670
+ catch (e_10) {
671
+ env_10.error = e_10;
672
+ env_10.hasError = true;
673
+ }
674
+ finally {
675
+ __disposeResources(env_10);
676
+ }
677
+ }
678
+ }
679
+ if (true || "test ChangesetAdaptor.adaptor()") {
680
+ const testChanges = (changes) => {
681
+ assert.equal(changes.length, 2);
682
+ assert.equal(changes[0].ECInstanceId, "0x20000000001");
683
+ assert.equal(changes[0].$meta?.classFullName, "BisCore:DrawingModel");
684
+ assert.equal(changes[0].$meta?.op, "Updated");
685
+ assert.equal(changes[0].$meta?.stage, "New");
686
+ assert.equal(changes[1].ECInstanceId, "0x20000000001");
687
+ assert.equal(changes[1].$meta?.classFullName, "BisCore:DrawingModel");
688
+ assert.equal(changes[1].$meta?.op, "Updated");
689
+ assert.equal(changes[1].$meta?.stage, "Old");
690
+ };
691
+ if (true || "test with InMemoryInstanceCache") {
692
+ const env_11 = { stack: [], error: void 0, hasError: false };
693
+ try {
694
+ const reader = __addDisposableResource(env_11, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
695
+ const adaptor = __addDisposableResource(env_11, new ECChangesetAdaptor(reader), false);
696
+ adaptor.acceptOp("Updated");
697
+ const pcu = __addDisposableResource(env_11, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createInMemoryCache()), false);
698
+ while (adaptor.step()) {
699
+ pcu.appendFrom(adaptor);
700
+ }
701
+ testChanges(Array.from(pcu.instances));
702
+ }
703
+ catch (e_11) {
704
+ env_11.error = e_11;
705
+ env_11.hasError = true;
706
+ }
707
+ finally {
708
+ __disposeResources(env_11);
709
+ }
710
+ }
711
+ if (true || "test with SqliteBackedInstanceCache") {
712
+ const env_12 = { stack: [], error: void 0, hasError: false };
713
+ try {
714
+ const reader = __addDisposableResource(env_12, SqliteChangesetReader.openFile({ fileName: changesets[2].pathname, db: rwIModel, disableSchemaCheck: true }), false);
715
+ const adaptor = __addDisposableResource(env_12, new ECChangesetAdaptor(reader), false);
716
+ adaptor.acceptOp("Updated");
717
+ const pcu = __addDisposableResource(env_12, new PartialECChangeUnifier(reader.db, ECChangeUnifierCache.createSqliteBackedCache(rwIModel)), false);
718
+ while (adaptor.step()) {
719
+ pcu.appendFrom(adaptor);
720
+ }
721
+ testChanges(Array.from(pcu.instances));
722
+ }
723
+ catch (e_12) {
724
+ env_12.error = e_12;
725
+ env_12.hasError = true;
726
+ }
727
+ finally {
728
+ __disposeResources(env_12);
729
+ }
730
+ }
731
+ }
732
+ txn.end();
733
+ rwIModel.close();
734
+ });
735
+ it("revert timeline changes", async () => {
736
+ const adminToken = "super manager token";
737
+ const iModelName = "test";
738
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
739
+ assert.isNotEmpty(rwIModelId);
740
+ const rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
741
+ const txn = startTestTxn(rwIModel, "revert timeline changes");
742
+ let nProps = 0;
743
+ // 1. Import schema with class that span overflow table.
744
+ const addPropertyAndImportSchema = async () => {
745
+ await rwIModel.acquireSchemaLock();
746
+ ++nProps;
747
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
748
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00.${nProps}" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
749
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
750
+ <ECEntityClass typeName="Test2dElement">
751
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
752
+ ${Array(nProps).fill(undefined).map((_, i) => `<ECProperty propertyName="p${i + 1}" typeName="string"/>`).join("\n")}
753
+ </ECEntityClass>
754
+ </ECSchema>`;
755
+ await importSchemaStrings(txn, [schema]);
756
+ };
757
+ await addPropertyAndImportSchema();
758
+ rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
759
+ // Create drawing model and category
760
+ await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
761
+ const codeProps = Code.createEmpty();
762
+ codeProps.value = "DrawingModel";
763
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
764
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "MyDrawingCategory");
765
+ if (undefined === drawingCategoryId)
766
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
767
+ txn.saveChanges();
768
+ await rwIModel.pushChanges({ description: "setup category", accessToken: adminToken });
769
+ const createEl = async (args) => {
770
+ await rwIModel.locks.acquireLocks({ exclusive: drawingModelId });
771
+ const geomArray = [
772
+ Arc3d.createXY(Point3d.create(0, 0), 5),
773
+ Arc3d.createXY(Point3d.create(5, 5), 2),
774
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
775
+ ];
776
+ const geometryStream = [];
777
+ for (const geom of geomArray) {
778
+ const arcData = IModelJson.Writer.toIModelJson(geom);
779
+ geometryStream.push(arcData);
780
+ }
781
+ const e1 = {
782
+ classFullName: `TestDomain:Test2dElement`,
783
+ model: drawingModelId,
784
+ category: drawingCategoryId,
785
+ code: Code.createEmpty(),
786
+ geom: geometryStream,
787
+ ...args,
788
+ };
789
+ return txn.insertElement(e1);
790
+ ;
791
+ };
792
+ const updateEl = async (id, args) => {
793
+ await rwIModel.locks.acquireLocks({ exclusive: id });
794
+ const updatedElementProps = Object.assign(rwIModel.elements.getElementProps(id), args);
795
+ txn.updateElement(updatedElementProps);
796
+ };
797
+ const deleteEl = async (id) => {
798
+ await rwIModel.locks.acquireLocks({ exclusive: id });
799
+ txn.deleteElement(id);
800
+ };
801
+ const getChanges = async () => {
802
+ return HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir: path.join(KnownTestLocations.outputDir, rwIModelId, "changesets") });
803
+ };
804
+ const findEl = (id) => {
805
+ try {
806
+ return rwIModel.elements.getElementProps(id);
807
+ }
808
+ catch {
809
+ return undefined;
810
+ }
811
+ };
812
+ // 2. Insert a element for the class
813
+ const el1 = await createEl({ p1: "test1" });
814
+ const el2 = await createEl({ p1: "test2" });
815
+ txn.saveChanges();
816
+ await rwIModel.pushChanges({ description: "insert 2 elements" });
817
+ // 3. Update the element.
818
+ await updateEl(el1, { p1: "test3" });
819
+ txn.saveChanges();
820
+ await rwIModel.pushChanges({ description: "update element 1" });
821
+ // 4. Delete the element.
822
+ await deleteEl(el2);
823
+ const el3 = await createEl({ p1: "test4" });
824
+ txn.saveChanges();
825
+ await rwIModel.pushChanges({ description: "delete element 2" });
826
+ // 5. import schema and insert element 4 & update element 3
827
+ await addPropertyAndImportSchema();
828
+ const el4 = await createEl({ p1: "test5", p2: "test6" });
829
+ await updateEl(el3, { p1: "test7", p2: "test8" });
830
+ txn.saveChanges();
831
+ await rwIModel.pushChanges({ description: "import schema, insert element 4 & update element 3" });
832
+ assert.isDefined(findEl(el1));
833
+ assert.isUndefined(findEl(el2));
834
+ assert.isDefined(findEl(el3));
835
+ assert.isDefined(findEl(el4));
836
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
837
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1", "p2"]);
838
+ // 6. Revert to timeline 2
839
+ await rwIModel.revertAndPushChanges({ toIndex: 2, description: "revert to timeline 2" });
840
+ assert.equal((await getChanges()).at(-1).description, "revert to timeline 2");
841
+ assert.isUndefined(findEl(el1));
842
+ assert.isUndefined(findEl(el2));
843
+ assert.isUndefined(findEl(el3));
844
+ assert.isUndefined(findEl(el4));
845
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
846
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1"]);
847
+ await rwIModel.revertAndPushChanges({ toIndex: 6, description: "reinstate last reverted changeset" });
848
+ assert.equal((await getChanges()).at(-1).description, "reinstate last reverted changeset");
849
+ assert.isDefined(findEl(el1));
850
+ assert.isUndefined(findEl(el2));
851
+ assert.isDefined(findEl(el3));
852
+ assert.isDefined(findEl(el4));
853
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
854
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1", "p2"]);
855
+ await addPropertyAndImportSchema();
856
+ const el5 = await createEl({ p1: "test9", p2: "test10", p3: "test11" });
857
+ await updateEl(el1, { p1: "test12", p2: "test13", p3: "test114" });
858
+ txn.saveChanges();
859
+ await rwIModel.pushChanges({ description: "import schema, insert element 5 & update element 1" });
860
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
861
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1", "p2", "p3"]);
862
+ // skip schema changes & auto generated comment
863
+ await rwIModel.revertAndPushChanges({ toIndex: 1, skipSchemaChanges: true });
864
+ assert.equal((await getChanges()).at(-1).description, "Reverted changes from 8 to 1 (schema changes skipped)");
865
+ assert.isUndefined(findEl(el1));
866
+ assert.isUndefined(findEl(el2));
867
+ assert.isUndefined(findEl(el3));
868
+ assert.isUndefined(findEl(el4));
869
+ assert.isUndefined(findEl(el5));
870
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
871
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1", "p2", "p3"]);
872
+ await rwIModel.revertAndPushChanges({ toIndex: 9 });
873
+ assert.equal((await getChanges()).at(-1).description, "Reverted changes from 9 to 9");
874
+ assert.isDefined(findEl(el1));
875
+ assert.isUndefined(findEl(el2));
876
+ assert.isDefined(findEl(el3));
877
+ assert.isDefined(findEl(el4));
878
+ assert.isDefined(findEl(el5));
879
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
880
+ assert.deepEqual(Object.getOwnPropertyNames(rwIModel.getMetaData("TestDomain:Test2dElement").properties), ["p1", "p2", "p3"]);
881
+ txn.end();
882
+ rwIModel.close();
883
+ });
884
+ it("openGroup() & writeToFile()", async () => {
885
+ const adminToken = "super manager token";
886
+ const iModelName = "test";
887
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
888
+ assert.isNotEmpty(rwIModelId);
889
+ const rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
890
+ const txn = startTestTxn(rwIModel, "openGroup writeToFile");
891
+ // 1. Import schema with class that span overflow table.
892
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
893
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
894
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
895
+ <ECEntityClass typeName="Test2dElement">
896
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
897
+ <ECProperty propertyName="p1" typeName="string"/>
898
+ </ECEntityClass>
899
+ </ECSchema>`;
900
+ await importSchemaStrings(txn, [schema]);
901
+ rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
902
+ // Create drawing model and category
903
+ await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
904
+ const codeProps = Code.createEmpty();
905
+ codeProps.value = "DrawingModel";
906
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
907
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "MyDrawingCategory");
908
+ if (undefined === drawingCategoryId)
909
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
910
+ txn.saveChanges();
911
+ await rwIModel.pushChanges({ description: "setup category", accessToken: adminToken });
912
+ const geomArray = [
913
+ Arc3d.createXY(Point3d.create(0, 0), 5),
914
+ Arc3d.createXY(Point3d.create(5, 5), 2),
915
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
916
+ ];
917
+ const geometryStream = [];
918
+ for (const geom of geomArray) {
919
+ const arcData = IModelJson.Writer.toIModelJson(geom);
920
+ geometryStream.push(arcData);
921
+ }
922
+ const e1 = {
923
+ classFullName: `TestDomain:Test2dElement`,
924
+ model: drawingModelId,
925
+ category: drawingCategoryId,
926
+ code: Code.createEmpty(),
927
+ geom: geometryStream,
928
+ ...{ p1: "test1" },
929
+ };
930
+ // 2. Insert a element for the class
931
+ await rwIModel.locks.acquireLocks({ shared: drawingModelId });
932
+ const e1id = txn.insertElement(e1);
933
+ assert.isTrue(Id64.isValidId64(e1id), "insert worked");
934
+ txn.saveChanges();
935
+ await rwIModel.pushChanges({ description: "insert element", accessToken: adminToken });
936
+ // 3. Update the element.
937
+ const updatedElementProps = Object.assign(rwIModel.elements.getElementProps(e1id), { p1: "test2" });
938
+ await rwIModel.locks.acquireLocks({ exclusive: e1id });
939
+ txn.updateElement(updatedElementProps);
940
+ txn.saveChanges();
941
+ await rwIModel.pushChanges({ description: "update element", accessToken: adminToken });
942
+ // 4. Delete the element.
943
+ await rwIModel.locks.acquireLocks({ exclusive: e1id });
944
+ txn.deleteElement(e1id);
945
+ txn.saveChanges();
946
+ await rwIModel.pushChanges({ description: "delete element", accessToken: adminToken });
947
+ const targetDir = path.join(KnownTestLocations.outputDir, rwIModelId, "changesets");
948
+ const changesets = (await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir })).slice(1);
949
+ const testElementClassId = getClassIdByName(rwIModel, "Test2dElement");
950
+ const drawingModelClassId = getClassIdByName(rwIModel, "DrawingModel");
951
+ if (true || "Grouping changeset [2,3,4] should not contain TestDomain:Test2dElement as insert+update+delete=noop") {
952
+ const reader = SqliteChangesetReader.openGroup({ changesetFiles: changesets.map((c) => c.pathname), db: rwIModel, disableSchemaCheck: true });
953
+ const adaptor = new ECChangesetAdaptor(reader);
954
+ const instances = [];
955
+ while (adaptor.step()) {
956
+ if (adaptor.inserted) {
957
+ instances.push({ id: adaptor.inserted?.ECInstanceId, classId: adaptor.inserted.ECClassId, op: adaptor.op, classFullName: adaptor.inserted.$meta?.classFullName });
958
+ }
959
+ else if (adaptor.deleted) {
960
+ instances.push({ id: adaptor.deleted?.ECInstanceId, classId: adaptor.deleted.ECClassId, op: adaptor.op, classFullName: adaptor.deleted.$meta?.classFullName });
961
+ }
962
+ }
963
+ expect(instances.length).to.eq(1);
964
+ expect(instances[0].id).to.eq("0x20000000001");
965
+ expect(instances[0].classId).to.eq(drawingModelClassId);
966
+ expect(instances[0].op).to.eq("Updated");
967
+ expect(instances[0].classFullName).to.eq("BisCore:DrawingModel");
968
+ }
969
+ if (true || "Grouping changeset [3,4] should contain update+delete=delete TestDomain:Test2dElement") {
970
+ const reader = SqliteChangesetReader.openGroup({ changesetFiles: changesets.slice(1).map((c) => c.pathname), db: rwIModel, disableSchemaCheck: true });
971
+ const adaptor = new ECChangesetAdaptor(reader);
972
+ const instances = [];
973
+ while (adaptor.step()) {
974
+ if (adaptor.inserted) {
975
+ instances.push({ id: adaptor.inserted?.ECInstanceId, classId: adaptor.inserted.ECClassId, op: adaptor.op, classFullName: adaptor.inserted.$meta?.classFullName });
976
+ }
977
+ else if (adaptor.deleted) {
978
+ instances.push({ id: adaptor.deleted?.ECInstanceId, classId: adaptor.deleted.ECClassId, op: adaptor.op, classFullName: adaptor.deleted.$meta?.classFullName });
979
+ }
980
+ }
981
+ expect(instances.length).to.eq(3);
982
+ expect(instances[0]).deep.eq({
983
+ id: "0x20000000004",
984
+ classId: testElementClassId,
985
+ op: "Deleted",
986
+ classFullName: "TestDomain:Test2dElement",
987
+ });
988
+ expect(instances[1]).deep.eq({
989
+ id: "0x20000000004",
990
+ classId: testElementClassId,
991
+ op: "Deleted",
992
+ classFullName: "TestDomain:Test2dElement",
993
+ });
994
+ expect(instances[2]).deep.eq({
995
+ id: "0x20000000001",
996
+ classId: drawingModelClassId,
997
+ op: "Updated",
998
+ classFullName: "BisCore:DrawingModel",
999
+ });
1000
+ }
1001
+ const groupCsFile = path.join(KnownTestLocations.outputDir, "changeset_grouping.ec");
1002
+ if (true || "Grouping changeset [2,3] should contain insert+update=insert TestDomain:Test2dElement") {
1003
+ const reader = SqliteChangesetReader.openGroup({ changesetFiles: changesets.slice(0, 2).map((c) => c.pathname), db: rwIModel, disableSchemaCheck: true });
1004
+ const adaptor = new ECChangesetAdaptor(reader);
1005
+ const instances = [];
1006
+ while (adaptor.step()) {
1007
+ if (adaptor.inserted) {
1008
+ instances.push({ id: adaptor.inserted?.ECInstanceId, classId: adaptor.inserted.ECClassId, op: adaptor.op, classFullName: adaptor.inserted.$meta?.classFullName });
1009
+ }
1010
+ else if (adaptor.deleted) {
1011
+ instances.push({ id: adaptor.deleted?.ECInstanceId, classId: adaptor.deleted.ECClassId, op: adaptor.op, classFullName: adaptor.deleted.$meta?.classFullName });
1012
+ }
1013
+ }
1014
+ expect(instances.length).to.eq(3);
1015
+ expect(instances[0]).deep.eq({
1016
+ id: "0x20000000004",
1017
+ classId: testElementClassId,
1018
+ op: "Inserted",
1019
+ classFullName: "TestDomain:Test2dElement",
1020
+ });
1021
+ expect(instances[1]).deep.eq({
1022
+ id: "0x20000000004",
1023
+ classId: testElementClassId,
1024
+ op: "Inserted",
1025
+ classFullName: "TestDomain:Test2dElement",
1026
+ });
1027
+ expect(instances[2]).deep.eq({
1028
+ id: "0x20000000001",
1029
+ classId: drawingModelClassId,
1030
+ op: "Updated",
1031
+ classFullName: "BisCore:DrawingModel",
1032
+ });
1033
+ reader.writeToFile({ fileName: groupCsFile, containsSchemaChanges: false, overwriteFile: true });
1034
+ }
1035
+ if (true || "writeToFile() test") {
1036
+ const reader = SqliteChangesetReader.openFile({ fileName: groupCsFile, db: rwIModel, disableSchemaCheck: true });
1037
+ const adaptor = new ECChangesetAdaptor(reader);
1038
+ const instances = [];
1039
+ while (adaptor.step()) {
1040
+ if (adaptor.inserted) {
1041
+ instances.push({ id: adaptor.inserted?.ECInstanceId, classId: adaptor.inserted.ECClassId, op: adaptor.op, classFullName: adaptor.inserted.$meta?.classFullName });
1042
+ }
1043
+ else if (adaptor.deleted) {
1044
+ instances.push({ id: adaptor.deleted?.ECInstanceId, classId: adaptor.deleted.ECClassId, op: adaptor.op, classFullName: adaptor.deleted.$meta?.classFullName });
1045
+ }
1046
+ }
1047
+ expect(instances.length).to.eq(3);
1048
+ expect(instances[0]).deep.eq({
1049
+ id: "0x20000000004",
1050
+ classId: testElementClassId,
1051
+ op: "Inserted",
1052
+ classFullName: "TestDomain:Test2dElement",
1053
+ });
1054
+ expect(instances[1]).deep.eq({
1055
+ id: "0x20000000004",
1056
+ classId: testElementClassId,
1057
+ op: "Inserted",
1058
+ classFullName: "TestDomain:Test2dElement",
1059
+ });
1060
+ expect(instances[2]).deep.eq({
1061
+ id: "0x20000000001",
1062
+ classId: drawingModelClassId,
1063
+ op: "Updated",
1064
+ classFullName: "BisCore:DrawingModel",
1065
+ });
1066
+ }
1067
+ txn.end();
1068
+ rwIModel.close();
1069
+ });
1070
+ it("Delete class FK constraint violation in cache table", async () => {
1071
+ // Helper to check if TestClass exists in schema and cache table for both briefcases
1072
+ function checkClass(firstBriefcase, isClassInFirst, secondBriefcase, isClassInSecond) {
1073
+ const firstItems = firstBriefcase.getSchemaProps("TestSchema").items;
1074
+ assert.equal(isClassInFirst, !!firstItems?.TestClass);
1075
+ const secondItems = secondBriefcase.getSchemaProps("TestSchema").items;
1076
+ assert.equal(isClassInSecond, !!secondItems?.TestClass);
1077
+ const sql = `SELECT ch.classId FROM ec_cache_ClassHierarchy ch JOIN ec_Class c ON ch.classId = c.Id WHERE c.Name = 'TestClass'`;
1078
+ const firstStmt = firstBriefcase.prepareSqliteStatement(sql);
1079
+ assert.equal(firstStmt.step(), isClassInFirst ? DbResult.BE_SQLITE_ROW : DbResult.BE_SQLITE_DONE);
1080
+ firstStmt[Symbol.dispose]();
1081
+ const secondStmt = secondBriefcase.prepareSqliteStatement(sql);
1082
+ assert.equal(secondStmt.step(), isClassInSecond ? DbResult.BE_SQLITE_ROW : DbResult.BE_SQLITE_DONE);
1083
+ secondStmt[Symbol.dispose]();
1084
+ }
1085
+ const adminToken = "super manager token";
1086
+ const iModelName = "test";
1087
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1088
+ assert.isNotEmpty(rwIModelId);
1089
+ // Open two briefcases for the same iModel
1090
+ const [firstBriefCase, secondBriefCase] = await Promise.all([
1091
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken }),
1092
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken })
1093
+ ]);
1094
+ const firstTxn = startTestTxn(firstBriefCase, "delete class FK constraint setup");
1095
+ // Enable shared channel for both
1096
+ [firstBriefCase, secondBriefCase].forEach(briefcase => briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName));
1097
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1098
+ <ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1099
+ <ECSchemaReference name="BisCore" version="1.0.0" alias="bis"/>
1100
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1101
+
1102
+ <ECCustomAttributes>
1103
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1104
+ </ECCustomAttributes>
1105
+
1106
+ <ECEntityClass typeName="TestClass">
1107
+ <BaseClass>bis:PhysicalElement</BaseClass>
1108
+ </ECEntityClass>
1109
+ </ECSchema>`]);
1110
+ // Push the changes to the hub
1111
+ await firstBriefCase.pushChanges({ description: "push initial schema changeset", accessToken: adminToken });
1112
+ // Sync the second briefcase with the iModel
1113
+ await secondBriefCase.pullChanges({ accessToken: adminToken });
1114
+ checkClass(firstBriefCase, true, secondBriefCase, true);
1115
+ // Import the schema
1116
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1117
+ <ECSchema schemaName="TestSchema" alias="ts" version="2.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1118
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1119
+
1120
+ <ECCustomAttributes>
1121
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1122
+ </ECCustomAttributes>
1123
+ </ECSchema>`]);
1124
+ // Push the changeset to the hub
1125
+ await firstBriefCase.pushChanges({ description: "Delete class major change", accessToken: adminToken });
1126
+ checkClass(firstBriefCase, false, secondBriefCase, true);
1127
+ // Apply the latest changeset to a new briefcase
1128
+ try {
1129
+ await secondBriefCase.pullChanges({ accessToken: adminToken });
1130
+ }
1131
+ catch (error) {
1132
+ assert.fail(`Should not have failed with the error: ${error.message}`);
1133
+ }
1134
+ checkClass(firstBriefCase, false, secondBriefCase, false);
1135
+ // Cleanup
1136
+ firstTxn.end();
1137
+ secondBriefCase.close();
1138
+ firstBriefCase.close();
1139
+ });
1140
+ it("Delete class FK constraint violation in cache table through a revert", async () => {
1141
+ // Helper to check if TestClass exists in schema and cache table for both briefcases
1142
+ function checkClass(className, firstBriefcase, isClassInFirst, secondBriefcase, isClassInSecond) {
1143
+ assert.equal(isClassInFirst, !!firstBriefcase.getSchemaProps("TestSchema").items?.[className]);
1144
+ assert.equal(isClassInSecond, !!secondBriefcase.getSchemaProps("TestSchema").items?.[className]);
1145
+ const sql = `SELECT ch.classId FROM ec_cache_ClassHierarchy ch JOIN ec_Class c ON ch.classId = c.Id WHERE c.Name = '${className}'`;
1146
+ const firstStmt = firstBriefcase.prepareSqliteStatement(sql);
1147
+ assert.equal(firstStmt.step(), isClassInFirst ? DbResult.BE_SQLITE_ROW : DbResult.BE_SQLITE_DONE);
1148
+ firstStmt[Symbol.dispose]();
1149
+ const secondStmt = secondBriefcase.prepareSqliteStatement(sql);
1150
+ assert.equal(secondStmt.step(), isClassInSecond ? DbResult.BE_SQLITE_ROW : DbResult.BE_SQLITE_DONE);
1151
+ secondStmt[Symbol.dispose]();
1152
+ }
1153
+ const adminToken = "super manager token";
1154
+ const iModelName = "test";
1155
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1156
+ assert.isNotEmpty(rwIModelId);
1157
+ // Open two briefcases for the same iModel
1158
+ const [firstBriefCase, secondBriefCase] = await Promise.all([
1159
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken }),
1160
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken })
1161
+ ]);
1162
+ const firstTxn = startTestTxn(firstBriefCase, "delete class FK revert");
1163
+ // Enable shared channel for both
1164
+ [firstBriefCase, secondBriefCase].forEach(briefcase => briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName));
1165
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1166
+ <ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1167
+ <ECSchemaReference name="BisCore" version="1.0.0" alias="bis"/>
1168
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1169
+
1170
+ <ECCustomAttributes>
1171
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1172
+ </ECCustomAttributes>
1173
+
1174
+ <ECEntityClass typeName="TestClass">
1175
+ <BaseClass>bis:PhysicalElement</BaseClass>
1176
+ </ECEntityClass>
1177
+ </ECSchema>`]);
1178
+ // Push the changes to the hub
1179
+ await firstBriefCase.pushChanges({ description: "push initial schema changeset", accessToken: adminToken });
1180
+ // Sync the second briefcase
1181
+ await secondBriefCase.pullChanges({ accessToken: adminToken });
1182
+ checkClass("TestClass", firstBriefCase, true, secondBriefCase, true);
1183
+ // Import the schema
1184
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1185
+ <ECSchema schemaName="TestSchema" alias="ts" version="1.0.1" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1186
+ <ECSchemaReference name="BisCore" version="1.0.0" alias="bis"/>
1187
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1188
+
1189
+ <ECCustomAttributes>
1190
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1191
+ </ECCustomAttributes>
1192
+
1193
+ <ECEntityClass typeName="TestClass">
1194
+ <BaseClass>bis:PhysicalElement</BaseClass>
1195
+ </ECEntityClass>
1196
+
1197
+ <ECEntityClass typeName="AnotherTestClass">
1198
+ <BaseClass>bis:PhysicalElement</BaseClass>
1199
+ </ECEntityClass>
1200
+ </ECSchema>`]);
1201
+ // Push the changeset to the hub
1202
+ await firstBriefCase.pushChanges({ description: "Add another class change", accessToken: adminToken });
1203
+ // Sync the second briefcase
1204
+ await secondBriefCase.pullChanges({ accessToken: adminToken });
1205
+ checkClass("TestClass", firstBriefCase, true, secondBriefCase, true);
1206
+ checkClass("AnotherTestClass", firstBriefCase, true, secondBriefCase, true);
1207
+ // Revert the latest changeset from the first briefcase
1208
+ try {
1209
+ await firstBriefCase.revertAndPushChanges({ toIndex: 2, description: "Revert last changeset" });
1210
+ }
1211
+ catch (error) {
1212
+ assert.fail(`Should not have failed with the error: ${error.message}`);
1213
+ }
1214
+ checkClass("TestClass", firstBriefCase, true, secondBriefCase, true);
1215
+ checkClass("AnotherTestClass", firstBriefCase, false, secondBriefCase, true);
1216
+ try {
1217
+ await secondBriefCase.pullChanges({ accessToken: adminToken });
1218
+ }
1219
+ catch (error) {
1220
+ assert.fail(`Should not have failed with the error: ${error.message}`);
1221
+ }
1222
+ checkClass("TestClass", firstBriefCase, true, secondBriefCase, true);
1223
+ checkClass("AnotherTestClass", firstBriefCase, false, secondBriefCase, false);
1224
+ // Cleanup
1225
+ firstTxn.end();
1226
+ secondBriefCase.close();
1227
+ firstBriefCase.close();
1228
+ });
1229
+ it("Track changeset health stats", async () => {
1230
+ const adminToken = "super manager token";
1231
+ const iModelName = "test";
1232
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1233
+ assert.isNotEmpty(rwIModelId);
1234
+ // Open two briefcases for the same iModel
1235
+ const [firstBriefcase, secondBriefcase] = await Promise.all([
1236
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken }),
1237
+ HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken })
1238
+ ]);
1239
+ const firstTxn = startTestTxn(firstBriefcase, "track changeset health first briefcase");
1240
+ const secondTxn = startTestTxn(secondBriefcase, "track changeset health second briefcase");
1241
+ [firstBriefcase, secondBriefcase].forEach(briefcase => briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName));
1242
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1243
+ <ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1244
+ <ECSchemaReference name="BisCore" version="1.0.0" alias="bis"/>
1245
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1246
+
1247
+ <ECCustomAttributes>
1248
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1249
+ </ECCustomAttributes>
1250
+
1251
+ <ECEntityClass typeName="TestClass">
1252
+ <BaseClass>bis:PhysicalElement</BaseClass>
1253
+ </ECEntityClass>
1254
+ </ECSchema>`]);
1255
+ // Enable changeset tracking for both briefcases
1256
+ await Promise.all([firstBriefcase.enableChangesetStatTracking(), secondBriefcase.enableChangesetStatTracking()]);
1257
+ await firstBriefcase.pushChanges({ description: "push initial schema changeset", accessToken: adminToken });
1258
+ await secondBriefcase.pullChanges({ accessToken: adminToken });
1259
+ // Schema upgrade
1260
+ await importSchemaStrings(secondTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1261
+ <ECSchema schemaName="TestSchema" alias="ts" version="2.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1262
+ <ECSchemaReference name="BisCore" version="1.0.0" alias="bis"/>
1263
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1264
+
1265
+ <ECCustomAttributes>
1266
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1267
+ </ECCustomAttributes>
1268
+
1269
+ <ECEntityClass typeName="TestClass">
1270
+ <BaseClass>bis:PhysicalElement</BaseClass>
1271
+ <ECProperty propertyName="TestProperty" typeName="string"/>
1272
+ </ECEntityClass>
1273
+
1274
+ <ECEnumeration typeName="TestEnum" backingTypeName="int" isStrict="true">
1275
+ <ECEnumerator name="Enumerator1" value="1" displayLabel="TestEnumerator1"/>
1276
+ <ECEnumerator name="Enumerator2" value="2" displayLabel="TestEnumerator2"/>
1277
+ </ECEnumeration>
1278
+ </ECSchema>`]);
1279
+ await secondBriefcase.pushChanges({ description: "Added a property to TestClass and an enum", accessToken: adminToken });
1280
+ await firstBriefcase.pullChanges({ accessToken: adminToken });
1281
+ // Major schema change
1282
+ await importSchemaStrings(firstTxn, [`<?xml version="1.0" encoding="UTF-8"?>
1283
+ <ECSchema schemaName="TestSchema" alias="ts" version="2.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
1284
+ <ECSchemaReference name="CoreCustomAttributes" version="1.0.0" alias="CoreCA" />
1285
+
1286
+ <ECCustomAttributes>
1287
+ <DynamicSchema xmlns = 'CoreCustomAttributes.1.0.0' />
1288
+ </ECCustomAttributes>
1289
+
1290
+ <ECEnumeration typeName="TestEnum" backingTypeName="int" isStrict="true">
1291
+ <ECEnumerator name="Enumerator1" value="1" displayLabel="TestEnumerator1"/>
1292
+ <ECEnumerator name="Enumerator2" value="2" displayLabel="TestEnumerator2"/>
1293
+ </ECEnumeration>
1294
+ </ECSchema>`]);
1295
+ await firstBriefcase.pushChanges({ description: "Deleted TestClass", accessToken: adminToken });
1296
+ await secondBriefcase.pullChanges({ accessToken: adminToken });
1297
+ const firstBriefcaseChangesets = await firstBriefcase.getAllChangesetHealthData();
1298
+ const secondBriefcaseChangesets = await secondBriefcase.getAllChangesetHealthData();
1299
+ assert.equal(firstBriefcaseChangesets.length, 1);
1300
+ const firstBriefcaseChangeset = firstBriefcaseChangesets[0];
1301
+ expect(firstBriefcaseChangeset.changesetIndex).to.be.eql(2);
1302
+ expect(firstBriefcaseChangeset.uncompressedSizeBytes).to.be.greaterThan(300);
1303
+ expect(firstBriefcaseChangeset.insertedRows).to.be.greaterThanOrEqual(4);
1304
+ expect(firstBriefcaseChangeset.updatedRows).to.be.greaterThanOrEqual(1);
1305
+ expect(firstBriefcaseChangeset.deletedRows).to.be.eql(0);
1306
+ expect(firstBriefcaseChangeset.totalFullTableScans).to.be.eql(0);
1307
+ expect(firstBriefcaseChangeset.perStatementStats.length).to.be.eql(5);
1308
+ assert.equal(secondBriefcaseChangesets.length, 2);
1309
+ const [secondBriefcaseChangeset1, secondBriefcaseChangeset2] = secondBriefcaseChangesets;
1310
+ expect(secondBriefcaseChangeset1.changesetIndex).to.be.eql(1);
1311
+ expect(secondBriefcaseChangeset1.uncompressedSizeBytes).to.be.greaterThan(40000);
1312
+ expect(secondBriefcaseChangeset1.insertedRows).to.be.eql(52);
1313
+ expect(secondBriefcaseChangeset1.updatedRows).to.be.greaterThanOrEqual(921);
1314
+ expect(secondBriefcaseChangeset1.deletedRows).to.be.greaterThanOrEqual(0);
1315
+ expect(secondBriefcaseChangeset1.totalFullTableScans).to.be.eql(0);
1316
+ expect(secondBriefcaseChangeset1.perStatementStats.length).to.be.eql(11);
1317
+ expect(secondBriefcaseChangeset2.changesetIndex).to.be.eql(3);
1318
+ expect(secondBriefcaseChangeset2.uncompressedSizeBytes).to.be.greaterThan(40000);
1319
+ expect(secondBriefcaseChangeset2.insertedRows).to.be.greaterThanOrEqual(0);
1320
+ expect(secondBriefcaseChangeset2.updatedRows).to.be.greaterThanOrEqual(921);
1321
+ expect(secondBriefcaseChangeset2.deletedRows).to.be.eql(52);
1322
+ expect(secondBriefcaseChangeset2.totalFullTableScans).to.be.eql(0);
1323
+ expect(secondBriefcaseChangeset2.perStatementStats.length).to.be.eql(11);
1324
+ // Cleanup
1325
+ secondTxn.end();
1326
+ firstTxn.end();
1327
+ secondBriefcase.close();
1328
+ firstBriefcase.close();
1329
+ });
1330
+ it("openInMemory() & step()", async () => {
1331
+ const adminToken = "super manager token";
1332
+ const iModelName = "test";
1333
+ const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1334
+ assert.isNotEmpty(rwIModelId);
1335
+ const rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
1336
+ const txn = startTestTxn(rwIModel, "openInMemory step");
1337
+ // 1. Import schema with class that span overflow table.
1338
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
1339
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
1340
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
1341
+ <ECEntityClass typeName="Test2dElement">
1342
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
1343
+ <ECProperty propertyName="p1" typeName="string"/>
1344
+ </ECEntityClass>
1345
+ </ECSchema>`;
1346
+ await importSchemaStrings(txn, [schema]);
1347
+ rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
1348
+ // Create drawing model and category
1349
+ await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
1350
+ const codeProps = Code.createEmpty();
1351
+ codeProps.value = "DrawingModel";
1352
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
1353
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "MyDrawingCategory");
1354
+ if (undefined === drawingCategoryId)
1355
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
1356
+ txn.saveChanges();
1357
+ await rwIModel.pushChanges({ description: "setup category", accessToken: adminToken });
1358
+ const geomArray = [
1359
+ Arc3d.createXY(Point3d.create(0, 0), 5),
1360
+ Arc3d.createXY(Point3d.create(5, 5), 2),
1361
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
1362
+ ];
1363
+ const geometryStream = [];
1364
+ for (const geom of geomArray) {
1365
+ const arcData = IModelJson.Writer.toIModelJson(geom);
1366
+ geometryStream.push(arcData);
1367
+ }
1368
+ const e1 = {
1369
+ classFullName: `TestDomain:Test2dElement`,
1370
+ model: drawingModelId,
1371
+ category: drawingCategoryId,
1372
+ code: Code.createEmpty(),
1373
+ geom: geometryStream,
1374
+ ...{ p1: "test1" },
1375
+ };
1376
+ // 2. Insert a element for the class
1377
+ await rwIModel.locks.acquireLocks({ shared: drawingModelId });
1378
+ const e1id = txn.insertElement(e1);
1379
+ assert.isTrue(Id64.isValidId64(e1id), "insert worked");
1380
+ const testElClassId = getClassIdByName(rwIModel, "Test2dElement");
1381
+ if (true) {
1382
+ const reader = SqliteChangesetReader.openInMemory({ db: rwIModel, disableSchemaCheck: true });
1383
+ const adaptor = new ChangesetECAdaptor(reader);
1384
+ const unifier = new PartialECChangeUnifier(rwIModel);
1385
+ while (adaptor.step()) {
1386
+ unifier.appendFrom(adaptor);
1387
+ }
1388
+ reader.close();
1389
+ // verify the inserted element's properties
1390
+ const instances = Array.from(unifier.instances);
1391
+ expect(instances.length).to.equals(1);
1392
+ const testEl = instances[0];
1393
+ expect(testEl.$meta?.op).to.equals("Inserted");
1394
+ expect(testEl.$meta?.classFullName).to.equals("TestDomain:Test2dElement");
1395
+ expect(testEl.$meta?.stage).to.equals("New");
1396
+ expect(testEl.ECClassId).to.equals(testElClassId);
1397
+ expect(testEl.ECInstanceId).to.equals(e1id);
1398
+ expect(testEl.Model.Id).to.equals(drawingModelId);
1399
+ expect(testEl.Category.Id).to.equals(drawingCategoryId);
1400
+ expect(testEl.Origin.X).to.equals(0);
1401
+ expect(testEl.Origin.Y).to.equals(0);
1402
+ expect(testEl.Rotation).to.equals(0);
1403
+ expect(testEl.BBoxLow.X).to.equals(-25);
1404
+ expect(testEl.BBoxLow.Y).to.equals(-25);
1405
+ expect(testEl.BBoxHigh.X).to.equals(15);
1406
+ expect(testEl.BBoxHigh.Y).to.equals(15);
1407
+ expect(testEl.p1).to.equals("test1");
1408
+ }
1409
+ // save changes and verify the the txn
1410
+ txn.saveChanges();
1411
+ if (true) {
1412
+ const txnId = rwIModel.txns.getLastSavedTxnProps()?.id;
1413
+ expect(txnId).to.not.be.undefined;
1414
+ const reader = SqliteChangesetReader.openTxn({ db: rwIModel, disableSchemaCheck: true, txnId });
1415
+ const adaptor = new ChangesetECAdaptor(reader);
1416
+ const unifier = new PartialECChangeUnifier(rwIModel);
1417
+ while (adaptor.step()) {
1418
+ unifier.appendFrom(adaptor);
1419
+ }
1420
+ reader.close();
1421
+ // verify the inserted element's properties
1422
+ const instances = Array.from(unifier.instances);
1423
+ expect(instances.length).to.equals(3);
1424
+ const drawingModelClassId = getClassIdByName(rwIModel, "DrawingModel");
1425
+ // DrawingModel new instance
1426
+ const drawingModelElNew = instances[0];
1427
+ expect(drawingModelElNew.$meta?.op).to.equals("Updated");
1428
+ expect(drawingModelElNew.$meta?.classFullName).to.equals("BisCore:DrawingModel");
1429
+ expect(drawingModelElNew.$meta?.stage).to.equals("New");
1430
+ expect(drawingModelElNew.ECClassId).to.equals(drawingModelClassId);
1431
+ expect(drawingModelElNew.ECInstanceId).to.equals(drawingModelId);
1432
+ expect(drawingModelElNew.LastMod).to.exist;
1433
+ expect(drawingModelElNew.GeometryGuid).to.exist;
1434
+ // DrawingModel old instance
1435
+ const drawingModelElOld = instances[1];
1436
+ expect(drawingModelElOld.$meta?.op).to.equals("Updated");
1437
+ expect(drawingModelElOld.$meta?.classFullName).to.equals("BisCore:DrawingModel");
1438
+ expect(drawingModelElOld.$meta?.stage).to.equals("Old");
1439
+ expect(drawingModelElOld.ECClassId).to.equals(drawingModelClassId);
1440
+ expect(drawingModelElOld.ECInstanceId).to.equals(drawingModelId);
1441
+ expect(drawingModelElOld.LastMod).to.null;
1442
+ expect(drawingModelElOld.GeometryGuid).to.null;
1443
+ // Test element instance
1444
+ const testEl = instances[2];
1445
+ expect(testEl.$meta?.op).to.equals("Inserted");
1446
+ expect(testEl.$meta?.classFullName).to.equals("TestDomain:Test2dElement");
1447
+ expect(testEl.$meta?.stage).to.equals("New");
1448
+ expect(testEl.ECClassId).to.equals(testElClassId);
1449
+ expect(testEl.ECInstanceId).to.equals(e1id);
1450
+ expect(testEl.Model.Id).to.equals(drawingModelId);
1451
+ expect(testEl.Category.Id).to.equals(drawingCategoryId);
1452
+ expect(testEl.Origin.X).to.equals(0);
1453
+ expect(testEl.Origin.Y).to.equals(0);
1454
+ expect(testEl.Rotation).to.equals(0);
1455
+ expect(testEl.BBoxLow.X).to.equals(-25);
1456
+ expect(testEl.BBoxLow.Y).to.equals(-25);
1457
+ expect(testEl.BBoxHigh.X).to.equals(15);
1458
+ expect(testEl.BBoxHigh.Y).to.equals(15);
1459
+ expect(testEl.p1).to.equals("test1");
1460
+ }
1461
+ await rwIModel.pushChanges({ description: "insert element", accessToken: adminToken });
1462
+ txn.end();
1463
+ rwIModel.close();
1464
+ });
1465
+ it("Instance update to a different class (bug)", async () => {
1466
+ /**
1467
+ * Test scenario: Verifies changeset reader behavior when an instance ID is reused with a different class.
1468
+ *
1469
+ * Steps:
1470
+ * 1. Import schema with two classes (T1 and T2) that inherit from GraphicalElement2d.
1471
+ * - T1 has property 'p' of type string
1472
+ * - T2 has property 'p' of type long
1473
+ * 2. Insert an element of type T1 with id=elId and property p="wwww"
1474
+ * 3. Push changeset #1: "insert element"
1475
+ * 4. Delete the T1 element
1476
+ * 5. Manipulate the element ID sequence to force reuse of the same ID
1477
+ * 6. Insert a new element of type T2 with the same id=elId but property p=1111
1478
+ * 7. Push changeset #2: "buggy changeset"
1479
+ *
1480
+ * Verification:
1481
+ * - Changeset #2 should show an "Updated" operation (not Delete+Insert)
1482
+ * - In bis_Element table: ECClassId changes from T1 to T2
1483
+ * - In bis_GeometricElement2d table: ECClassId changes from T1 to T2
1484
+ * - Property 'p' changes from string "wwww" to integer 1111
1485
+ *
1486
+ * This tests the changeset reader's ability to handle instance class changes,
1487
+ * which can occur in edge cases where IDs are reused with different types.
1488
+ */
1489
+ const adminToken = "super manager token";
1490
+ const iModelName = "test";
1491
+ const modelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1492
+ assert.isNotEmpty(modelId);
1493
+ let b1 = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: modelId, accessToken: adminToken });
1494
+ let txn = startTestTxn(b1, "instance update to different class");
1495
+ // 1. Import schema with classes that span overflow table.
1496
+ const schema = `<?xml version="1.0" encoding="UTF-8"?>
1497
+ <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
1498
+ <ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
1499
+ <ECEntityClass typeName="T1">
1500
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
1501
+ <ECProperty propertyName="p" typeName="string"/>
1502
+ </ECEntityClass>
1503
+ <ECEntityClass typeName="T2">
1504
+ <BaseClass>bis:GraphicalElement2d</BaseClass>
1505
+ <ECProperty propertyName="p" typeName="long"/>
1506
+ </ECEntityClass>
1507
+ </ECSchema>`;
1508
+ await importSchemaStrings(txn, [schema]);
1509
+ b1.channels.addAllowedChannel(ChannelControl.sharedChannelName);
1510
+ // Create drawing model and category
1511
+ await b1.locks.acquireLocks({ shared: IModel.dictionaryId });
1512
+ const codeProps = Code.createEmpty();
1513
+ codeProps.value = "DrawingModel";
1514
+ const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
1515
+ let drawingCategoryId = DrawingCategory.queryCategoryIdByName(b1, IModel.dictionaryId, "MyDrawingCategory");
1516
+ if (undefined === drawingCategoryId)
1517
+ drawingCategoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
1518
+ const geomArray = [
1519
+ Arc3d.createXY(Point3d.create(0, 0), 5),
1520
+ Arc3d.createXY(Point3d.create(5, 5), 2),
1521
+ Arc3d.createXY(Point3d.create(-5, -5), 20),
1522
+ ];
1523
+ const geometryStream = [];
1524
+ for (const geom of geomArray) {
1525
+ const arcData = IModelJson.Writer.toIModelJson(geom);
1526
+ geometryStream.push(arcData);
1527
+ }
1528
+ const geomElementT1 = {
1529
+ classFullName: `TestDomain:T1`,
1530
+ model: drawingModelId,
1531
+ category: drawingCategoryId,
1532
+ code: Code.createEmpty(),
1533
+ geom: geometryStream,
1534
+ p: "wwww",
1535
+ };
1536
+ const elId = txn.insertElement(geomElementT1);
1537
+ assert.isTrue(Id64.isValidId64(elId), "insert worked");
1538
+ txn.saveChanges();
1539
+ await b1.pushChanges({ description: "insert element" });
1540
+ await b1.locks.acquireLocks({ shared: drawingModelId, exclusive: elId });
1541
+ await b1.locks.acquireLocks({ shared: IModel.dictionaryId });
1542
+ txn.deleteElement(elId);
1543
+ txn.saveChanges();
1544
+ // Force id set to reproduce same instance with different classid
1545
+ const bid = BigInt(elId) - 1n;
1546
+ b1[_nativeDb].saveLocalValue("bis_elementidsequence", bid.toString());
1547
+ txn.saveChanges();
1548
+ const fileName = b1[_nativeDb].getFilePath();
1549
+ txn.end();
1550
+ b1.close();
1551
+ b1 = await BriefcaseDb.open({ fileName });
1552
+ b1.channels.addAllowedChannel(ChannelControl.sharedChannelName);
1553
+ txn = startTestTxn(b1, "instance update to different class reopened briefcase");
1554
+ const geomElementT2 = {
1555
+ classFullName: `TestDomain:T2`,
1556
+ model: drawingModelId,
1557
+ category: drawingCategoryId,
1558
+ code: Code.createEmpty(),
1559
+ geom: geometryStream,
1560
+ p: 1111,
1561
+ };
1562
+ const elId2 = txn.insertElement(geomElementT2);
1563
+ chai.expect(elId).equals(elId2);
1564
+ txn.saveChanges();
1565
+ await b1.pushChanges({ description: "buggy changeset" });
1566
+ const getChanges = async () => {
1567
+ return HubMock.downloadChangesets({ iModelId: modelId, targetDir: path.join(KnownTestLocations.outputDir, modelId, "changesets") });
1568
+ };
1569
+ const changesets = await getChanges();
1570
+ chai.expect(changesets.length).equals(2);
1571
+ chai.expect(changesets[0].description).equals("insert element");
1572
+ chai.expect(changesets[1].description).equals("buggy changeset");
1573
+ const getClassId = async (name) => {
1574
+ const r = b1.createQueryReader("SELECT FORMAT('0x%x', ec_classid(?))", QueryBinder.from([name]));
1575
+ if (await r.step()) {
1576
+ return r.current[0];
1577
+ }
1578
+ };
1579
+ const t1ClassId = await getClassId("TestDomain:T1");
1580
+ const t2ClassId = await getClassId("TestDomain:T2");
1581
+ const reader = SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 });
1582
+ let bisElementAsserted = false;
1583
+ let bisGeometricElement2dAsserted = false;
1584
+ while (reader.step()) {
1585
+ if (reader.tableName === "bis_Element" && reader.op === "Updated") {
1586
+ bisElementAsserted = true;
1587
+ chai.expect(reader.getColumnNames(reader.tableName)).deep.equals([
1588
+ "Id",
1589
+ "ECClassId",
1590
+ "ModelId",
1591
+ "LastMod",
1592
+ "CodeSpecId",
1593
+ "CodeScopeId",
1594
+ "CodeValue",
1595
+ "UserLabel",
1596
+ "ParentId",
1597
+ "ParentRelECClassId",
1598
+ "FederationGuid",
1599
+ "JsonProperties",
1600
+ ]);
1601
+ const oldId = reader.getChangeValueId(0, "Old");
1602
+ const newId = reader.getChangeValueId(0, "New");
1603
+ chai.expect(oldId).equals(elId);
1604
+ chai.expect(newId).to.be.undefined;
1605
+ const oldClassId = reader.getChangeValueId(1, "Old");
1606
+ const newClassId = reader.getChangeValueId(1, "New");
1607
+ chai.expect(oldClassId).equals(t1ClassId);
1608
+ chai.expect(newClassId).equals(t2ClassId);
1609
+ chai.expect(oldClassId).is.not.equal(newClassId);
1610
+ }
1611
+ if (reader.tableName === "bis_GeometricElement2d" && reader.op === "Updated") {
1612
+ bisGeometricElement2dAsserted = true;
1613
+ chai.expect(reader.getColumnNames(reader.tableName)).deep.equals([
1614
+ "ElementId",
1615
+ "ECClassId",
1616
+ "CategoryId",
1617
+ "Origin_X",
1618
+ "Origin_Y",
1619
+ "Rotation",
1620
+ "BBoxLow_X",
1621
+ "BBoxLow_Y",
1622
+ "BBoxHigh_X",
1623
+ "BBoxHigh_Y",
1624
+ "GeometryStream",
1625
+ "TypeDefinitionId",
1626
+ "TypeDefinitionRelECClassId",
1627
+ "js1",
1628
+ "js2",
1629
+ ]);
1630
+ // ECInstanceId
1631
+ const oldId = reader.getChangeValueId(0, "Old");
1632
+ const newId = reader.getChangeValueId(0, "New");
1633
+ chai.expect(oldId).equals(elId);
1634
+ chai.expect(newId).to.be.undefined;
1635
+ // ECClassId (changed)
1636
+ const oldClassId = reader.getChangeValueId(1, "Old");
1637
+ const newClassId = reader.getChangeValueId(1, "New");
1638
+ chai.expect(oldClassId).equals(t1ClassId);
1639
+ chai.expect(newClassId).equals(t2ClassId);
1640
+ chai.expect(oldClassId).is.not.equal(newClassId);
1641
+ // Property 'p' changed type and value.
1642
+ const oldP = reader.getChangeValueText(13, "Old");
1643
+ const newP = reader.getChangeValueInteger(13, "New");
1644
+ chai.expect(oldP).equals("wwww");
1645
+ chai.expect(newP).equals(1111);
1646
+ }
1647
+ }
1648
+ chai.expect(bisElementAsserted).to.be.true;
1649
+ chai.expect(bisGeometricElement2dAsserted).to.be.true;
1650
+ reader.close();
1651
+ // ChangesetECAdaptor works incorrectly as it does not expect ECClassId to change in an update.
1652
+ const adaptor = new ChangesetECAdaptor(SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 }));
1653
+ adaptor.acceptClass(GraphicalElement2d.classFullName);
1654
+ adaptor.acceptOp("Updated");
1655
+ let ecChangeForElementAsserted = false;
1656
+ let ecChangeForGeometricElement2dAsserted = false;
1657
+ while (adaptor.step()) {
1658
+ if (adaptor.reader.tableName === "bis_Element") {
1659
+ ecChangeForElementAsserted = true;
1660
+ chai.expect(adaptor.inserted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
1661
+ chai.expect(adaptor.deleted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
1662
+ }
1663
+ if (adaptor.reader.tableName === "bis_GeometricElement2d") {
1664
+ ecChangeForGeometricElement2dAsserted = true;
1665
+ chai.expect(adaptor.inserted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
1666
+ chai.expect(adaptor.deleted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
1667
+ chai.expect(adaptor.inserted?.p).equals("0x457"); // CORRECT p in T2 is integer
1668
+ chai.expect(adaptor.deleted?.p).equals("wwww"); // CORRECT p in T1 is string
1669
+ }
1670
+ }
1671
+ chai.expect(ecChangeForElementAsserted).to.be.true;
1672
+ chai.expect(ecChangeForGeometricElement2dAsserted).to.be.true;
1673
+ adaptor.close();
1674
+ // PartialECChangeUnifier fail to combine changes correctly when ECClassId is updated.
1675
+ const adaptor2 = new ChangesetECAdaptor(SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 }));
1676
+ const unifier = new PartialECChangeUnifier(b1);
1677
+ adaptor2.acceptClass(GraphicalElement2d.classFullName);
1678
+ adaptor2.acceptOp("Updated");
1679
+ while (adaptor2.step()) {
1680
+ unifier.appendFrom(adaptor2);
1681
+ }
1682
+ chai.expect(unifier.getInstanceCount()).to.be.equals(2); // WRONG should be 1
1683
+ txn.end();
1684
+ b1.close();
1685
+ });
1686
+ });
1687
+ describe("PRAGMA ECSQL Functions", async () => {
1688
+ let iTwinId;
1689
+ let iModel;
1690
+ before(() => {
1691
+ HubMock.startup("SqliteChangesetReaderAndChangesetECAdaptorTest", KnownTestLocations.outputDir);
1692
+ iTwinId = HubMock.iTwinId;
1693
+ });
1694
+ after(() => HubMock.shutdown());
1695
+ beforeEach(async () => {
1696
+ // Create new iModel
1697
+ const adminToken = "super manager token";
1698
+ const iModelName = "PRAGMA_test";
1699
+ const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
1700
+ assert.isNotEmpty(iModelId);
1701
+ iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken: adminToken });
1702
+ });
1703
+ afterEach(() => {
1704
+ // Cleanup
1705
+ iModel.close();
1706
+ });
1707
+ it("should call PRAGMA integrity_check on a new iModel and return no errors", async () => {
1708
+ // Call PRAGMA integrity_check
1709
+ const query = "PRAGMA integrity_check ECSQLOPTIONS ENABLE_EXPERIMENTAL_FEATURES";
1710
+ const result = iModel.createQueryReader(query, undefined, undefined);
1711
+ const results = await result.toArray();
1712
+ // Verify no errors
1713
+ assert(results.length > 0, "Results should be returned from PRAGMA integrity_check");
1714
+ assert(results[0][2] === true, "'check_data_columns' check should be true");
1715
+ assert(results[1][2] === true, "'check_ec_profile' check should be true");
1716
+ assert(results[2][2] === true, "'check_nav_class_ids' check should be true");
1717
+ assert(results[3][2] === true, "'check_nav_ids' check should be true");
1718
+ assert(results[4][2] === true, "'check_linktable_fk_class_ids' check should be true");
1719
+ assert(results[5][2] === true, "'check_linktable_fk_ids' check should be true");
1720
+ assert(results[6][2] === true, "'check_class_ids' check should be true");
1721
+ assert(results[7][2] === true, "'check_data_schema' check should be true");
1722
+ assert(results[8][2] === true, "'check_schema_load' check should be true");
1723
+ });
1724
+ it("should call PRAGMA integrity_check individual checks on a new iModel and return no errors", async () => {
1725
+ // Call check_ec_profile
1726
+ let query = "pragma integrity_check(check_ec_profile) options enable_experimental_features";
1727
+ let result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1728
+ let resultArray = await result.toArray();
1729
+ expect(resultArray.length).to.equal(0); // No errors expected
1730
+ // Call check_data_schema
1731
+ query = "pragma integrity_check(check_data_schema) options enable_experimental_features";
1732
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1733
+ resultArray = await result.toArray();
1734
+ expect(resultArray.length).to.equal(0); // No errors expected
1735
+ // Call check_data_columns
1736
+ query = "pragma integrity_check(check_data_columns) options enable_experimental_features";
1737
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1738
+ resultArray = await result.toArray();
1739
+ expect(resultArray.length).to.equal(0); // No errors expected
1740
+ // Call check_nav_class_ids
1741
+ query = "pragma integrity_check(check_nav_class_ids) options enable_experimental_features";
1742
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1743
+ resultArray = await result.toArray();
1744
+ expect(resultArray.length).to.equal(0); // No errors expected
1745
+ // Call check_nav_ids
1746
+ query = "pragma integrity_check(check_nav_ids) options enable_experimental_features";
1747
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1748
+ resultArray = await result.toArray();
1749
+ expect(resultArray.length).to.equal(0); // No errors expected
1750
+ // Call check_linktable_fk_class_ids
1751
+ query = "pragma integrity_check(check_linktable_fk_class_ids) options enable_experimental_features";
1752
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1753
+ resultArray = await result.toArray();
1754
+ expect(resultArray.length).to.equal(0); // No errors expected
1755
+ // Call check_linktable_fk_ids
1756
+ query = "pragma integrity_check(check_linktable_fk_ids) options enable_experimental_features";
1757
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1758
+ resultArray = await result.toArray();
1759
+ expect(resultArray.length).to.equal(0); // No errors expected
1760
+ // Call check_class_ids
1761
+ query = "pragma integrity_check(check_class_ids) options enable_experimental_features";
1762
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1763
+ resultArray = await result.toArray();
1764
+ expect(resultArray.length).to.equal(0); // No errors expected
1765
+ // Call check_schema_load
1766
+ query = "pragma integrity_check(check_schema_load) options enable_experimental_features";
1767
+ result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1768
+ resultArray = await result.toArray();
1769
+ expect(resultArray.length).to.equal(0); // No errors expected
1770
+ });
1771
+ it("should call PRAGMA integrity_check on a corrupted iModel and return an error", async () => {
1772
+ // Insert two elements
1773
+ iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
1774
+ await iModel.locks.acquireLocks({ shared: IModel.repositoryModelId });
1775
+ const txn = startTestTxn(iModel, "PRAGMA integrity check corrupted iModel");
1776
+ const element1Id = txn.insertElement({
1777
+ classFullName: Subject.classFullName,
1778
+ model: IModel.repositoryModelId,
1779
+ parent: new SubjectOwnsSubjects(IModel.rootSubjectId),
1780
+ code: Subject.createCode(iModel, IModel.rootSubjectId, "Subject1"),
1781
+ });
1782
+ const element2Id = txn.insertElement({
1783
+ classFullName: Subject.classFullName,
1784
+ model: IModel.repositoryModelId,
1785
+ parent: new SubjectOwnsSubjects(IModel.rootSubjectId),
1786
+ code: Subject.createCode(iModel, IModel.rootSubjectId, "Subject2"),
1787
+ });
1788
+ txn.saveChanges();
1789
+ // Create a relationship between them
1790
+ await iModel.locks.acquireLocks({ exclusive: Id64.toIdSet([element1Id, element2Id]) });
1791
+ const relationship = iModel.relationships.createInstance({
1792
+ classFullName: "BisCore:SubjectRefersToSubject",
1793
+ sourceId: element1Id,
1794
+ targetId: element2Id,
1795
+ });
1796
+ const relationshipId = txn.insertRelationship(relationship.toJSON());
1797
+ assert.isTrue(Id64.isValidId64(relationshipId));
1798
+ txn.saveChanges();
1799
+ // Delete one element without deleting the relationship to corrupt the iModel
1800
+ const deleteResult = iModel[_nativeDb].executeSql(`DELETE FROM bis_Element WHERE Id=${element2Id}`);
1801
+ expect(deleteResult).to.equal(DbResult.BE_SQLITE_OK);
1802
+ txn.saveChanges();
1803
+ // Call PRAGMA integrity_check
1804
+ const query = "PRAGMA integrity_check ECSQLOPTIONS ENABLE_EXPERIMENTAL_FEATURES";
1805
+ const result = iModel.createQueryReader(query, undefined, undefined);
1806
+ const results = await result.toArray();
1807
+ // Verify error is reported
1808
+ assert(results.length > 0, "Results should be returned from PRAGMA integrity_check");
1809
+ assert(results[0][2] === true, "'check_data_columns' check should be true");
1810
+ assert(results[1][2] === true, "'check_ec_profile' check should be true");
1811
+ assert(results[2][2] === true, "'check_nav_class_ids' check should be true");
1812
+ assert(results[3][2] === true, "'check_nav_ids' check should be true");
1813
+ assert(results[4][2] === true, "'check_linktable_fk_class_ids' check should be true");
1814
+ assert(results[5][2] === false, "'check_linktable_fk_ids' check should be false"); // Expecting error report here
1815
+ assert(results[6][2] === true, "'check_class_ids' check should be true");
1816
+ assert(results[7][2] === true, "'check_data_schema' check should be true");
1817
+ assert(results[8][2] === true, "'check_schema_load' check should be true");
1818
+ txn.end();
1819
+ });
1820
+ it("should call PRAGMA integrity_check(check_linktable_fk_class_ids) on a corrupted iModel and return an error", async () => {
1821
+ // Insert two elements
1822
+ iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
1823
+ await iModel.locks.acquireLocks({ shared: IModel.repositoryModelId });
1824
+ const txn = startTestTxn(iModel, "PRAGMA integrity check corrupted linktable fk ids");
1825
+ const element1Id = txn.insertElement({
1826
+ classFullName: Subject.classFullName,
1827
+ model: IModel.repositoryModelId,
1828
+ parent: new SubjectOwnsSubjects(IModel.rootSubjectId),
1829
+ code: Subject.createCode(iModel, IModel.rootSubjectId, "Subject1"),
1830
+ });
1831
+ const element2Id = txn.insertElement({
1832
+ classFullName: Subject.classFullName,
1833
+ model: IModel.repositoryModelId,
1834
+ parent: new SubjectOwnsSubjects(IModel.rootSubjectId),
1835
+ code: Subject.createCode(iModel, IModel.rootSubjectId, "Subject2"),
1836
+ });
1837
+ txn.saveChanges();
1838
+ // Create a relationship between them
1839
+ await iModel.locks.acquireLocks({ exclusive: Id64.toIdSet([element1Id, element2Id]) });
1840
+ const relationship = iModel.relationships.createInstance({
1841
+ classFullName: "BisCore:SubjectRefersToSubject",
1842
+ sourceId: element1Id,
1843
+ targetId: element2Id,
1844
+ });
1845
+ const relationshipId = txn.insertRelationship(relationship.toJSON());
1846
+ assert.isTrue(Id64.isValidId64(relationshipId));
1847
+ txn.saveChanges();
1848
+ // Delete one element without deleting the relationship to corrupt the iModel
1849
+ const deleteResult = iModel[_nativeDb].executeSql(`DELETE FROM bis_Element WHERE Id=${element2Id}`);
1850
+ expect(deleteResult).to.equal(DbResult.BE_SQLITE_OK);
1851
+ txn.saveChanges();
1852
+ // Call PRAGMA integrity_check
1853
+ const query = "pragma integrity_check(check_linktable_fk_ids) options enable_experimental_features";
1854
+ const result = iModel.createQueryReader(query, undefined, { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
1855
+ const resultArray = await result.toArray();
1856
+ expect(resultArray.length).to.equal(1); // 1 error report expected
1857
+ expect(resultArray[0].id).to.equal("0x20000000001");
1858
+ expect(resultArray[0].key_id).to.equal("0x20000000002");
1859
+ txn.end();
1860
+ });
1861
+ });
1862
+ //# sourceMappingURL=SQliteChangesetReaderAndChangesetECAdaptor.test.js.map