@itwin/core-backend 5.15.0-dev.9 → 5.16.0-dev.3

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 (218) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/lib/cjs/BlobContainerService.d.ts +2 -0
  3. package/lib/cjs/BlobContainerService.d.ts.map +1 -1
  4. package/lib/cjs/BlobContainerService.js.map +1 -1
  5. package/lib/cjs/BriefcaseManager.d.ts +2 -1
  6. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  7. package/lib/cjs/BriefcaseManager.js +39 -9
  8. package/lib/cjs/BriefcaseManager.js.map +1 -1
  9. package/lib/cjs/ChangeUnifier.d.ts +82 -0
  10. package/lib/cjs/ChangeUnifier.d.ts.map +1 -0
  11. package/lib/cjs/ChangeUnifier.js +163 -0
  12. package/lib/cjs/ChangeUnifier.js.map +1 -0
  13. package/lib/cjs/ChangesetReader.d.ts +21 -2
  14. package/lib/cjs/ChangesetReader.d.ts.map +1 -1
  15. package/lib/cjs/ChangesetReader.js +37 -1
  16. package/lib/cjs/ChangesetReader.js.map +1 -1
  17. package/lib/cjs/CloudSqlite.d.ts +15 -0
  18. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  19. package/lib/cjs/CloudSqlite.js.map +1 -1
  20. package/lib/cjs/ECDb.d.ts +1 -0
  21. package/lib/cjs/ECDb.d.ts.map +1 -1
  22. package/lib/cjs/ECDb.js +4 -1
  23. package/lib/cjs/ECDb.js.map +1 -1
  24. package/lib/cjs/EditTxn.d.ts +5 -0
  25. package/lib/cjs/EditTxn.d.ts.map +1 -1
  26. package/lib/cjs/EditTxn.js +30 -10
  27. package/lib/cjs/EditTxn.js.map +1 -1
  28. package/lib/cjs/GeoCoordConfig.d.ts +1 -0
  29. package/lib/cjs/GeoCoordConfig.d.ts.map +1 -1
  30. package/lib/cjs/GeoCoordConfig.js +12 -8
  31. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  32. package/lib/cjs/IModelDb.d.ts +19 -6
  33. package/lib/cjs/IModelDb.d.ts.map +1 -1
  34. package/lib/cjs/IModelDb.js +50 -9
  35. package/lib/cjs/IModelDb.js.map +1 -1
  36. package/lib/cjs/NativeHost.d.ts.map +1 -1
  37. package/lib/cjs/NativeHost.js +5 -1
  38. package/lib/cjs/NativeHost.js.map +1 -1
  39. package/lib/cjs/Relationship.d.ts +28 -0
  40. package/lib/cjs/Relationship.d.ts.map +1 -1
  41. package/lib/cjs/Relationship.js +78 -0
  42. package/lib/cjs/Relationship.js.map +1 -1
  43. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  44. package/lib/cjs/SchemaSync.js +1 -0
  45. package/lib/cjs/SchemaSync.js.map +1 -1
  46. package/lib/cjs/TxnManager.d.ts +126 -89
  47. package/lib/cjs/TxnManager.d.ts.map +1 -1
  48. package/lib/cjs/TxnManager.js +114 -76
  49. package/lib/cjs/TxnManager.js.map +1 -1
  50. package/lib/cjs/ViewStateHydrator.d.ts.map +1 -1
  51. package/lib/cjs/ViewStateHydrator.js.map +1 -1
  52. package/lib/cjs/ViewStore.d.ts.map +1 -1
  53. package/lib/cjs/ViewStore.js +62 -19
  54. package/lib/cjs/ViewStore.js.map +1 -1
  55. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  56. package/lib/cjs/annotations/LeaderGeometry.js +3 -0
  57. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  58. package/lib/cjs/core-backend.d.ts +1 -0
  59. package/lib/cjs/core-backend.d.ts.map +1 -1
  60. package/lib/cjs/core-backend.js +1 -0
  61. package/lib/cjs/core-backend.js.map +1 -1
  62. package/lib/cjs/internal/BriefcaseUtils.d.ts +19 -0
  63. package/lib/cjs/internal/BriefcaseUtils.d.ts.map +1 -0
  64. package/lib/cjs/internal/BriefcaseUtils.js +65 -0
  65. package/lib/cjs/internal/BriefcaseUtils.js.map +1 -0
  66. package/lib/cjs/internal/QueryMetadataCache.d.ts +44 -0
  67. package/lib/cjs/internal/QueryMetadataCache.d.ts.map +1 -0
  68. package/lib/cjs/internal/QueryMetadataCache.js +107 -0
  69. package/lib/cjs/internal/QueryMetadataCache.js.map +1 -0
  70. package/lib/cjs/internal/Symbols.d.ts +9 -0
  71. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  72. package/lib/cjs/internal/Symbols.js +10 -1
  73. package/lib/cjs/internal/Symbols.js.map +1 -1
  74. package/lib/cjs/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  75. package/lib/cjs/internal/workspace/WorkspaceImpl.js +20 -6
  76. package/lib/cjs/internal/workspace/WorkspaceImpl.js.map +1 -1
  77. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts +6 -6
  78. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts.map +1 -1
  79. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  80. package/lib/cjs/workspace/SettingsEditor.d.ts +4 -3
  81. package/lib/cjs/workspace/SettingsEditor.d.ts.map +1 -1
  82. package/lib/cjs/workspace/SettingsEditor.js +7 -5
  83. package/lib/cjs/workspace/SettingsEditor.js.map +1 -1
  84. package/lib/esm/BlobContainerService.d.ts +2 -0
  85. package/lib/esm/BlobContainerService.d.ts.map +1 -1
  86. package/lib/esm/BlobContainerService.js.map +1 -1
  87. package/lib/esm/BriefcaseManager.d.ts +2 -1
  88. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  89. package/lib/esm/BriefcaseManager.js +40 -10
  90. package/lib/esm/BriefcaseManager.js.map +1 -1
  91. package/lib/esm/ChangeUnifier.d.ts +82 -0
  92. package/lib/esm/ChangeUnifier.d.ts.map +1 -0
  93. package/lib/esm/ChangeUnifier.js +159 -0
  94. package/lib/esm/ChangeUnifier.js.map +1 -0
  95. package/lib/esm/ChangesetReader.d.ts +21 -2
  96. package/lib/esm/ChangesetReader.d.ts.map +1 -1
  97. package/lib/esm/ChangesetReader.js +38 -2
  98. package/lib/esm/ChangesetReader.js.map +1 -1
  99. package/lib/esm/CloudSqlite.d.ts +15 -0
  100. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  101. package/lib/esm/CloudSqlite.js.map +1 -1
  102. package/lib/esm/ECDb.d.ts +1 -0
  103. package/lib/esm/ECDb.d.ts.map +1 -1
  104. package/lib/esm/ECDb.js +4 -1
  105. package/lib/esm/ECDb.js.map +1 -1
  106. package/lib/esm/EditTxn.d.ts +5 -0
  107. package/lib/esm/EditTxn.d.ts.map +1 -1
  108. package/lib/esm/EditTxn.js +32 -12
  109. package/lib/esm/EditTxn.js.map +1 -1
  110. package/lib/esm/GeoCoordConfig.d.ts +1 -0
  111. package/lib/esm/GeoCoordConfig.d.ts.map +1 -1
  112. package/lib/esm/GeoCoordConfig.js +12 -8
  113. package/lib/esm/GeoCoordConfig.js.map +1 -1
  114. package/lib/esm/IModelDb.d.ts +19 -6
  115. package/lib/esm/IModelDb.d.ts.map +1 -1
  116. package/lib/esm/IModelDb.js +52 -11
  117. package/lib/esm/IModelDb.js.map +1 -1
  118. package/lib/esm/NativeHost.d.ts.map +1 -1
  119. package/lib/esm/NativeHost.js +5 -1
  120. package/lib/esm/NativeHost.js.map +1 -1
  121. package/lib/esm/Relationship.d.ts +28 -0
  122. package/lib/esm/Relationship.d.ts.map +1 -1
  123. package/lib/esm/Relationship.js +78 -0
  124. package/lib/esm/Relationship.js.map +1 -1
  125. package/lib/esm/SchemaSync.d.ts.map +1 -1
  126. package/lib/esm/SchemaSync.js +1 -0
  127. package/lib/esm/SchemaSync.js.map +1 -1
  128. package/lib/esm/TxnManager.d.ts +126 -89
  129. package/lib/esm/TxnManager.d.ts.map +1 -1
  130. package/lib/esm/TxnManager.js +116 -78
  131. package/lib/esm/TxnManager.js.map +1 -1
  132. package/lib/esm/ViewStateHydrator.d.ts.map +1 -1
  133. package/lib/esm/ViewStateHydrator.js.map +1 -1
  134. package/lib/esm/ViewStore.d.ts.map +1 -1
  135. package/lib/esm/ViewStore.js +62 -19
  136. package/lib/esm/ViewStore.js.map +1 -1
  137. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  138. package/lib/esm/annotations/LeaderGeometry.js +3 -0
  139. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  140. package/lib/esm/core-backend.d.ts +1 -0
  141. package/lib/esm/core-backend.d.ts.map +1 -1
  142. package/lib/esm/core-backend.js +1 -0
  143. package/lib/esm/core-backend.js.map +1 -1
  144. package/lib/esm/internal/BriefcaseUtils.d.ts +19 -0
  145. package/lib/esm/internal/BriefcaseUtils.d.ts.map +1 -0
  146. package/lib/esm/internal/BriefcaseUtils.js +61 -0
  147. package/lib/esm/internal/BriefcaseUtils.js.map +1 -0
  148. package/lib/esm/internal/QueryMetadataCache.d.ts +44 -0
  149. package/lib/esm/internal/QueryMetadataCache.d.ts.map +1 -0
  150. package/lib/esm/internal/QueryMetadataCache.js +103 -0
  151. package/lib/esm/internal/QueryMetadataCache.js.map +1 -0
  152. package/lib/esm/internal/Symbols.d.ts +9 -0
  153. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  154. package/lib/esm/internal/Symbols.js +9 -0
  155. package/lib/esm/internal/Symbols.js.map +1 -1
  156. package/lib/esm/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  157. package/lib/esm/internal/workspace/WorkspaceImpl.js +20 -6
  158. package/lib/esm/internal/workspace/WorkspaceImpl.js.map +1 -1
  159. package/lib/esm/rpc-impl/IModelReadRpcImpl.d.ts +6 -6
  160. package/lib/esm/rpc-impl/IModelReadRpcImpl.d.ts.map +1 -1
  161. package/lib/esm/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  162. package/lib/esm/test/annotations/LeaderGeometry.test.js +15 -1
  163. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  164. package/lib/esm/test/ecdb/CTE.test.js +21 -0
  165. package/lib/esm/test/ecdb/CTE.test.js.map +1 -1
  166. package/lib/esm/test/ecdb/ConcurrentQuery.test.js +144 -30
  167. package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
  168. package/lib/esm/test/ecdb/QueryMetadataCache.test.d.ts +2 -0
  169. package/lib/esm/test/ecdb/QueryMetadataCache.test.d.ts.map +1 -0
  170. package/lib/esm/test/ecdb/QueryMetadataCache.test.js +630 -0
  171. package/lib/esm/test/ecdb/QueryMetadataCache.test.js.map +1 -0
  172. package/lib/esm/test/element/RelationshipBatchLookup.test.d.ts +2 -0
  173. package/lib/esm/test/element/RelationshipBatchLookup.test.d.ts.map +1 -0
  174. package/lib/esm/test/element/RelationshipBatchLookup.test.js +202 -0
  175. package/lib/esm/test/element/RelationshipBatchLookup.test.js.map +1 -0
  176. package/lib/esm/test/hubaccess/BriefcaseManager.test.js +187 -1
  177. package/lib/esm/test/hubaccess/BriefcaseManager.test.js.map +1 -1
  178. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts +2 -0
  179. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts.map +1 -0
  180. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js +142 -0
  181. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js.map +1 -0
  182. package/lib/esm/test/imodel/IModelGeolocation.test.js +8 -6
  183. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -1
  184. package/lib/esm/test/imodel/IModelProps.test.d.ts +2 -0
  185. package/lib/esm/test/imodel/IModelProps.test.d.ts.map +1 -0
  186. package/lib/esm/test/imodel/IModelProps.test.js +411 -0
  187. package/lib/esm/test/imodel/IModelProps.test.js.map +1 -0
  188. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts +2 -0
  189. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts.map +1 -0
  190. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js +240 -0
  191. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js.map +1 -0
  192. package/lib/esm/test/schema/SchemaViewValidation.test.js +2 -8
  193. package/lib/esm/test/schema/SchemaViewValidation.test.js.map +1 -1
  194. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.d.ts +2 -0
  195. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.d.ts.map +1 -0
  196. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.js +159 -0
  197. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.js.map +1 -0
  198. package/lib/esm/test/standalone/ChangeUnifier.test.d.ts +2 -0
  199. package/lib/esm/test/standalone/ChangeUnifier.test.d.ts.map +1 -0
  200. package/lib/esm/test/standalone/ChangeUnifier.test.js +732 -0
  201. package/lib/esm/test/standalone/ChangeUnifier.test.js.map +1 -0
  202. package/lib/esm/test/standalone/EditTxn.test.js +72 -1
  203. package/lib/esm/test/standalone/EditTxn.test.js.map +1 -1
  204. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts +2 -0
  205. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts.map +1 -0
  206. package/lib/esm/test/standalone/GeoCoordConfig.test.js +158 -0
  207. package/lib/esm/test/standalone/GeoCoordConfig.test.js.map +1 -0
  208. package/lib/esm/test/standalone/ViewStoreDb.test.js +53 -0
  209. package/lib/esm/test/standalone/ViewStoreDb.test.js.map +1 -1
  210. package/lib/esm/test/workspace/SettingsContainers.test.d.ts +2 -0
  211. package/lib/esm/test/workspace/SettingsContainers.test.d.ts.map +1 -0
  212. package/lib/esm/test/workspace/SettingsContainers.test.js +95 -0
  213. package/lib/esm/test/workspace/SettingsContainers.test.js.map +1 -0
  214. package/lib/esm/workspace/SettingsEditor.d.ts +4 -3
  215. package/lib/esm/workspace/SettingsEditor.d.ts.map +1 -1
  216. package/lib/esm/workspace/SettingsEditor.js +7 -5
  217. package/lib/esm/workspace/SettingsEditor.js.map +1 -1
  218. package/package.json +18 -18
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryMetadataCache.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/QueryMetadataCache.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { expect } from \"chai\";\r\nimport * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\nimport * as sinon from \"sinon\";\r\nimport { Guid, IModelStatus } from \"@itwin/core-bentley\";\r\nimport {\r\n Code, DbQueryRequest, DbQueryResponse, DbResponseKind, DbResponseStatus, DbValueFormat, IModel, PhysicalElementProps, QueryOptions, QueryPropertyMetaData,\r\n QueryRowFormat, SubCategoryAppearance,\r\n} from \"@itwin/core-common\";\r\nimport { ConcurrentQuery } from \"../../ConcurrentQuery\";\r\nimport { ChannelControl } from \"../../ChannelControl\";\r\nimport { ECDb } from \"../../ECDb\";\r\nimport { EditTxn, withEditTxn } from \"../../EditTxn\";\r\nimport { BriefcaseDb, IModelDb, StandaloneDb } from \"../../IModelDb\";\r\nimport { BriefcaseManager } from \"../../BriefcaseManager\";\r\nimport { IModelJsFs } from \"../../IModelJsFs\";\r\nimport { SpatialCategory } from \"../../Category\";\r\nimport { HubMock } from \"../../internal/HubMock\";\r\nimport { QueryMetadataCache } from \"../../internal/QueryMetadataCache\";\r\nimport { HubWrappers, IModelTestUtils, TestUserType } from \"../IModelTestUtils\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\nimport { ECDbTestHelper } from \"./ECDbTestHelper\";\r\n\r\nfunction makeMeta(...names: string[]): QueryPropertyMetaData[] {\r\n return names.map((name, index) => ({ className: \"\", accessString: name, generated: false, index, jsonName: name.toLowerCase(), name, extendType: \"\", typeName: \"string\" }));\r\n}\r\n\r\nfunction makeResponse(meta: QueryPropertyMetaData[], status = DbResponseStatus.Done): DbQueryResponse {\r\n return {\r\n stats: { cpuTime: 0, totalTime: 0, timeLimit: 0, memLimit: 0, memUsed: 0, prepareTime: 0 },\r\n status,\r\n kind: DbResponseKind.ECSql,\r\n meta,\r\n data: [],\r\n rowCount: 0,\r\n };\r\n}\r\n\r\nfunction makeRequest(props?: Partial<DbQueryRequest>): DbQueryRequest {\r\n return { query: \"SELECT 1\", includeMetaData: true, ...props };\r\n}\r\n\r\n/** A fake native executor: returns `meta` when metadata is requested, an empty array otherwise. */\r\nclass FakeExecutor {\r\n public readonly requests: DbQueryRequest[] = [];\r\n public status = DbResponseStatus.Done;\r\n public constructor(public meta: QueryPropertyMetaData[]) { }\r\n public readonly execute = async (request: DbQueryRequest): Promise<DbQueryResponse> => {\r\n this.requests.push(request);\r\n return makeResponse(request.includeMetaData ? this.meta.map((p) => ({ ...p })) : [], this.status);\r\n };\r\n}\r\n\r\ndescribe(\"QueryMetadataCache\", () => {\r\n it(\"passes through requests that do not ask for metadata\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n const request = makeRequest({ includeMetaData: false });\r\n await cache.executeCachedQueryRequest(request, exec.execute);\r\n expect(exec.requests[0]).to.equal(request);\r\n expect(cache.size).to.equal(0);\r\n });\r\n\r\n it(\"asks native for metadata only once per query\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\", \"B\"));\r\n const request = makeRequest();\r\n\r\n const first = await cache.executeCachedQueryRequest(request, exec.execute);\r\n const second = await cache.executeCachedQueryRequest(request, exec.execute);\r\n\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, false]);\r\n expect(request.includeMetaData).to.be.true; // caller's request is not modified\r\n expect(second.meta).to.deep.equal(first.meta);\r\n expect(second.meta).to.deep.equal(makeMeta(\"A\", \"B\"));\r\n expect(cache.size).to.equal(1);\r\n });\r\n\r\n it(\"keys entries by every option that affects metadata\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n const variants: DbQueryRequest[] = [\r\n makeRequest(),\r\n makeRequest({ query: \"SELECT 2\" }),\r\n makeRequest({ valueFormat: DbValueFormat.JsNames }),\r\n makeRequest({ abbreviateBlobs: true }),\r\n makeRequest({ convertClassIdsToClassNames: true }),\r\n makeRequest({ usePrimaryConn: true }),\r\n ];\r\n for (const request of variants)\r\n await cache.executeCachedQueryRequest(request, exec.execute);\r\n\r\n expect(exec.requests.every((r) => r.includeMetaData)).to.be.true;\r\n expect(cache.size).to.equal(variants.length);\r\n });\r\n\r\n it(\"shares one entry across options that do not affect metadata\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n const variants: DbQueryRequest[] = [\r\n makeRequest({ args: { 1: { type: \"id\", value: \"0x1\" } } }),\r\n makeRequest({ args: { 1: { type: \"id\", value: \"0x2\" } } }),\r\n makeRequest({ limit: { count: 1 } }),\r\n makeRequest({ limit: { count: 10, offset: 5 } }),\r\n makeRequest({ rowFormat: QueryRowFormat.UseECSqlPropertyIndexes }),\r\n makeRequest({ rowFormat: QueryRowFormat.UseECSqlPropertyNames }),\r\n makeRequest({ rowFormat: QueryRowFormat.UseJsPropertyNames }), // eslint-disable-line @typescript-eslint/no-deprecated\r\n makeRequest({ priority: 5, restartToken: \"token\", suppressLogErrors: true, quota: { time: 10 }, delay: 1 }),\r\n ];\r\n for (const request of variants)\r\n await cache.executeCachedQueryRequest(request, exec.execute);\r\n\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, ...variants.slice(1).map(() => false)]);\r\n expect(cache.size).to.equal(1);\r\n });\r\n\r\n it(\"does not let callers mutate cached metadata\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n\r\n const first = await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n first.meta[0].name = \"changed\";\r\n const second = await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n second.meta[0].name = \"changed again\";\r\n const third = await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n\r\n expect(third.meta).to.deep.equal(makeMeta(\"A\"));\r\n });\r\n\r\n it(\"does not cache metadata from error or non-result responses\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n for (const status of [DbResponseStatus.Error_ECSql_PreparedFailed, DbResponseStatus.QueueFull, DbResponseStatus.Timeout]) {\r\n exec.status = status;\r\n await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n expect(cache.size).to.equal(0);\r\n }\r\n\r\n exec.status = DbResponseStatus.Done;\r\n await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, true, true, true]);\r\n expect(cache.size).to.equal(1);\r\n\r\n exec.status = DbResponseStatus.QueueFull;\r\n const busy = await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n expect(busy.meta).to.deep.equal([]);\r\n });\r\n\r\n it(\"does not cache metadata from a request that was in flight during clear\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"Old\"));\r\n await cache.executeCachedQueryRequest(makeRequest(), async (request) => {\r\n cache.clear();\r\n return exec.execute(request);\r\n });\r\n expect(cache.size).to.equal(0);\r\n });\r\n\r\n it(\"re-requests metadata without the restart token when cleared while a cache hit is in flight\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"Old\"));\r\n const request = makeRequest({ restartToken: \"token\" });\r\n await cache.executeCachedQueryRequest(request, exec.execute);\r\n\r\n exec.meta = makeMeta(\"New\");\r\n const response = await cache.executeCachedQueryRequest(request, async (r) => {\r\n if (!r.includeMetaData)\r\n cache.clear();\r\n return exec.execute(r);\r\n });\r\n\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, false, true]);\r\n // A newer request may already own the token; resubmitting with it would cancel that request.\r\n expect(exec.requests.map((r) => r.restartToken)).to.deep.equal([\"token\", \"token\", undefined]);\r\n expect(request.restartToken).to.equal(\"token\"); // caller's request is not modified\r\n expect(response.meta).to.deep.equal(makeMeta(\"New\"));\r\n expect(cache.size).to.equal(1);\r\n });\r\n\r\n it(\"returns a cancelled or failed cache hit as is, even when cleared while in flight\", async () => {\r\n for (const status of [DbResponseStatus.Cancel, DbResponseStatus.QueueFull, DbResponseStatus.Error_ECSql_PreparedFailed]) {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n const request = makeRequest({ restartToken: \"token\" });\r\n await cache.executeCachedQueryRequest(request, exec.execute);\r\n\r\n exec.status = status;\r\n const response = await cache.executeCachedQueryRequest(request, async (r) => {\r\n cache.clear();\r\n return exec.execute(r);\r\n });\r\n\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, false]);\r\n expect(response.status).to.equal(status);\r\n expect(response.meta).to.deep.equal([]);\r\n }\r\n });\r\n\r\n it(\"clear drops all entries\", async () => {\r\n const cache = new QueryMetadataCache();\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n cache.clear();\r\n expect(cache.size).to.equal(0);\r\n await cache.executeCachedQueryRequest(makeRequest(), exec.execute);\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([true, true]);\r\n });\r\n\r\n it(\"evicts the least recently used entry when full\", async () => {\r\n const cache = new QueryMetadataCache(2);\r\n const exec = new FakeExecutor(makeMeta(\"A\"));\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q1\" }), exec.execute);\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q2\" }), exec.execute);\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q1\" }), exec.execute); // hit: q1 becomes most recent\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q3\" }), exec.execute); // evicts q2\r\n expect(cache.size).to.equal(2);\r\n\r\n exec.requests.length = 0;\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q1\" }), exec.execute);\r\n await cache.executeCachedQueryRequest(makeRequest({ query: \"q2\" }), exec.execute);\r\n expect(exec.requests.map((r) => r.includeMetaData)).to.deep.equal([false, true]);\r\n });\r\n});\r\n\r\nconst schemaV1 = `<ECSchema schemaName=\"MetaCacheTest\" alias=\"mct\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\">\r\n <ECProperty propertyName=\"PropA\" typeName=\"string\"/>\r\n </ECEntityClass>\r\n</ECSchema>`;\r\n\r\nconst schemaV2 = `<ECSchema schemaName=\"MetaCacheTest\" alias=\"mct\" version=\"01.00.01\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\">\r\n <ECProperty propertyName=\"PropA\" typeName=\"string\"/>\r\n <ECProperty propertyName=\"PropB\" typeName=\"int\"/>\r\n </ECEntityClass>\r\n</ECSchema>`;\r\n\r\nconst bisSchema = (version: string, withPropB: boolean) => `<ECSchema schemaName=\"MetaCacheBisTest\" alias=\"mcbt\" version=\"${version}\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECSchemaReference name=\"BisCore\" version=\"01.00.00\" alias=\"bis\"/>\r\n <ECEntityClass typeName=\"Foo\">\r\n <BaseClass>bis:PhysicalElement</BaseClass>\r\n <ECProperty propertyName=\"PropA\" typeName=\"string\"/>\r\n ${withPropB ? `<ECProperty propertyName=\"PropB\" typeName=\"int\"/>` : \"\"}\r\n </ECEntityClass>\r\n</ECSchema>`;\r\n\r\nasync function readMetaData(db: ECDb | IModelDb, ecsql: string, config?: QueryOptions): Promise<QueryPropertyMetaData[]> {\r\n return db.createQueryReader(ecsql, undefined, config).getMetaData();\r\n}\r\n\r\nasync function readColumnNames(db: ECDb | IModelDb, ecsql: string, config?: QueryOptions): Promise<string[]> {\r\n return (await readMetaData(db, ecsql, config)).map((p) => p.name);\r\n}\r\n\r\n/** Read the metadata of a fresh reader and check whether it had to ask native for it, i.e. whether the cache missed. */\r\nasync function expectMetadataRequested(db: ECDb | IModelDb, ecsql: string, requested: boolean, config?: QueryOptions): Promise<void> {\r\n const spy = sinon.spy(ConcurrentQuery, \"executeQueryRequest\");\r\n try {\r\n await readMetaData(db, ecsql, config);\r\n expect(spy.args[0][1].includeMetaData).to.equal(requested);\r\n } finally {\r\n spy.restore();\r\n }\r\n}\r\n\r\ndescribe(\"createQueryReader metadata cache\", () => {\r\n afterEach(() => sinon.restore());\r\n\r\n describe(\"ECDb\", () => {\r\n const outDir = KnownTestLocations.outputDir;\r\n\r\n function importSchemaXml(ecdb: ECDb, xml: string) {\r\n const schemaPath = path.join(outDir, `${Guid.createValue()}.ecschema.xml`);\r\n IModelJsFs.writeFileSync(schemaPath, xml);\r\n try {\r\n ecdb.importSchema(schemaPath);\r\n } finally {\r\n IModelJsFs.unlinkSync(schemaPath);\r\n }\r\n }\r\n\r\n it(\"sends includeMetaData:false for later readers of the same query and returns equal metadata\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-hit.ecdb\", schemaV1);\r\n ecdb.withCachedWriteStatement(\"INSERT INTO mct.Foo(PropA) VALUES('a')\", (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n\r\n const spy = sinon.spy(ConcurrentQuery, \"executeQueryRequest\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n for (const config of [{}, { usePrimaryConn: true }, { rowFormat: QueryRowFormat.UseJsPropertyNames }, { abbreviateBlobs: true }]) {\r\n spy.resetHistory();\r\n const ecsql = \"SELECT * FROM mct.Foo\";\r\n const firstReader = ecdb.createQueryReader(ecsql, undefined, config);\r\n const firstRows = await firstReader.toArray();\r\n const firstMeta = await firstReader.getMetaData();\r\n const secondReader = ecdb.createQueryReader(ecsql, undefined, config);\r\n const secondRows = await secondReader.toArray();\r\n const secondMeta = await secondReader.getMetaData();\r\n\r\n expect(spy.args.map((args) => args[1].includeMetaData)).to.deep.equal([true, false]);\r\n expect(secondMeta).to.deep.equal(firstMeta);\r\n expect(secondRows).to.deep.equal(firstRows);\r\n expect(secondMeta.map((p) => p.name)).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"PropA\"]);\r\n }\r\n });\r\n\r\n it(\"returns rows keyed by the cached metadata\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-rows.ecdb\", schemaV1);\r\n ecdb.withCachedWriteStatement(\"INSERT INTO mct.Foo(PropA) VALUES('a')\", (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n\r\n const ecsql = \"SELECT PropA FROM mct.Foo\";\r\n for (let i = 0; i < 2; ++i) {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const reader = ecdb.createQueryReader(ecsql, undefined, { rowFormat: QueryRowFormat.UseJsPropertyNames });\r\n expect(await reader.step()).to.be.true;\r\n expect(reader.current.toRow()).to.deep.equal({ propA: \"a\" });\r\n expect(reader.current.propA).to.equal(\"a\");\r\n expect(reader.current[0]).to.equal(\"a\");\r\n }\r\n });\r\n\r\n it(\"is cleared by importSchema so SELECT * sees new columns\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-schema.ecdb\", schemaV1);\r\n const ecsql = \"SELECT * FROM mct.Foo\";\r\n expect(await readColumnNames(ecdb, ecsql)).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"PropA\"]);\r\n expect(await readColumnNames(ecdb, ecsql, { usePrimaryConn: true })).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"PropA\"]);\r\n\r\n importSchemaXml(ecdb, schemaV2);\r\n\r\n expect(await readColumnNames(ecdb, ecsql)).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"PropA\", \"PropB\"]);\r\n expect(await readColumnNames(ecdb, ecsql, { usePrimaryConn: true })).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"PropA\", \"PropB\"]);\r\n });\r\n\r\n it(\"is cleared by clearCaches but kept across saveChanges and abandonChanges\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-clear.ecdb\", schemaV1);\r\n const ecsql = \"SELECT * FROM mct.Foo\";\r\n\r\n await expectMetadataRequested(ecdb, ecsql, true);\r\n await expectMetadataRequested(ecdb, ecsql, false);\r\n ecdb.clearCaches();\r\n await expectMetadataRequested(ecdb, ecsql, true);\r\n ecdb.withCachedWriteStatement(\"INSERT INTO mct.Foo(PropA) VALUES('a')\", (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n await expectMetadataRequested(ecdb, ecsql, false);\r\n ecdb.abandonChanges();\r\n await expectMetadataRequested(ecdb, ecsql, false);\r\n });\r\n\r\n it(\"is cleared by dropSchemas\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-drop.ecdb\", schemaV1);\r\n const ecsql = \"SELECT * FROM mct.Foo\";\r\n await readMetaData(ecdb, ecsql);\r\n ecdb.dropSchemas([\"MetaCacheTest\"]);\r\n\r\n const spy = sinon.spy(ConcurrentQuery, \"executeQueryRequest\");\r\n let error: unknown;\r\n try {\r\n await readMetaData(ecdb, ecsql);\r\n } catch (e) {\r\n error = e;\r\n }\r\n expect(error).to.not.be.undefined; // the class is gone, so the query must fail to prepare instead of reusing stale metadata\r\n expect(spy.args[0][1].includeMetaData).to.be.true;\r\n });\r\n\r\n it(\"does not cancel a newer reader that shares the restart token when cleared during a cache hit\", async () => {\r\n using ecdb = ECDbTestHelper.createECDb(outDir, \"query-metadata-cache-restart.ecdb\", schemaV1);\r\n for (let i = 0; i < 10; ++i)\r\n ecdb.withCachedWriteStatement(`INSERT INTO mct.Foo(PropA) VALUES('${i}')`, (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n\r\n const ecsql = \"SELECT PropA FROM mct.Foo ORDER BY PropA\";\r\n const config = { restartToken: \"shared-token\" };\r\n const expected = (await ecdb.createQueryReader(ecsql, undefined, config).toArray()).map((row) => row[0]);\r\n expect(expected).to.have.length(10);\r\n\r\n // Once reader A's cache-hit request has returned rows, clear the cache and start reader B with the same token, then\r\n // let A see its response. A must re-request metadata without the token: native cancels the older of two requests\r\n // sharing a token, so resubmitting with it would cancel B.\r\n // (Clearing while A's request is still in flight is not tested here: native then answers A with ShuttingDown and\r\n // ECSqlReader retries the original request, token included, exactly as it does without the metadata cache.)\r\n const executeQueryRequest = ConcurrentQuery.executeQueryRequest.bind(ConcurrentQuery);\r\n let readerB: Promise<any[]> | undefined;\r\n const requests: DbQueryRequest[] = [];\r\n sinon.stub(ConcurrentQuery, \"executeQueryRequest\").callsFake(async (db, request) => {\r\n requests.push(request);\r\n const response = await executeQueryRequest(db, request);\r\n if (readerB === undefined && !request.includeMetaData && request.restartToken === config.restartToken) {\r\n ecdb.clearCaches();\r\n readerB = ecdb.createQueryReader(ecsql, undefined, config).toArray();\r\n }\r\n return response;\r\n });\r\n\r\n const resultA = await ecdb.createQueryReader(ecsql, undefined, config).toArray();\r\n expect(readerB).to.not.be.undefined;\r\n expect((await readerB!).map((row) => row[0])).to.deep.equal(expected);\r\n expect(resultA.map((row) => row[0])).to.deep.equal(expected);\r\n expect(requests.map((r) => ({ includeMetaData: r.includeMetaData, restartToken: r.restartToken }))).to.have.deep.members([\r\n { includeMetaData: false, restartToken: config.restartToken }, // A's cache hit\r\n { includeMetaData: true, restartToken: config.restartToken }, // B\r\n { includeMetaData: true, restartToken: undefined }, // A's re-request after the clear\r\n ]);\r\n });\r\n });\r\n\r\n describe(\"IModelDb\", () => {\r\n let imodel: StandaloneDb;\r\n\r\n beforeEach(async () => {\r\n imodel = StandaloneDb.createEmpty(IModelTestUtils.prepareOutputFile(\"QueryMetadataCache\", `${Guid.createValue()}.bim`), { rootSubject: { name: \"QueryMetadataCache\" }, enableTransactions: true });\r\n await imodel.importSchemaStrings([bisSchema(\"01.00.00\", false)]);\r\n });\r\n\r\n afterEach(() => imodel.close());\r\n\r\n const fooEcsql = \"SELECT * FROM mcbt.Foo\";\r\n\r\n function insertCategory(txn: EditTxn) {\r\n SpatialCategory.insert(txn, IModelDb.dictionaryId, Guid.createValue(), new SubCategoryAppearance());\r\n }\r\n\r\n it(\"sends includeMetaData:false for later readers of the same query\", async () => {\r\n const spy = sinon.spy(ConcurrentQuery, \"executeQueryRequest\");\r\n const first = await readMetaData(imodel, \"SELECT ECInstanceId, CodeValue FROM bis.Element\");\r\n const second = await readMetaData(imodel, \"SELECT ECInstanceId, CodeValue FROM bis.Element\");\r\n expect(spy.args.map((args) => args[1].includeMetaData)).to.deep.equal([true, false]);\r\n expect(second).to.deep.equal(first);\r\n });\r\n\r\n it(\"is cleared by a schema import so SELECT * sees new columns\", async () => {\r\n const ecsql = \"SELECT * FROM mcbt.Foo\";\r\n for (const config of [{}, { usePrimaryConn: true }]) {\r\n const names = await readColumnNames(imodel, ecsql, config);\r\n expect(names).to.include(\"PropA\");\r\n expect(names).to.not.include(\"PropB\");\r\n }\r\n\r\n await imodel.importSchemaStrings([bisSchema(\"01.00.01\", true)]);\r\n\r\n for (const config of [{}, { usePrimaryConn: true }]) {\r\n const names = await readColumnNames(imodel, ecsql, config);\r\n expect(names).to.include(\"PropA\");\r\n expect(names).to.include(\"PropB\");\r\n }\r\n });\r\n\r\n it(\"is kept on commit, undo and redo\", async () => {\r\n await readMetaData(imodel, fooEcsql);\r\n withEditTxn(imodel, (txn) => insertCategory(txn));\r\n await expectMetadataRequested(imodel, fooEcsql, false);\r\n\r\n expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success);\r\n await expectMetadataRequested(imodel, fooEcsql, false);\r\n\r\n expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success);\r\n await expectMetadataRequested(imodel, fooEcsql, false);\r\n });\r\n\r\n it(\"never needs clearing on undo because undo cannot cross a schema import\", async () => {\r\n withEditTxn(imodel, (txn) => insertCategory(txn));\r\n await imodel.importSchemaStrings([bisSchema(\"01.00.01\", true)]);\r\n expect(await readColumnNames(imodel, fooEcsql)).to.include(\"PropB\");\r\n\r\n // Saving a schema txn starts a new undo session, so neither the import nor anything before it can be undone.\r\n expect(imodel.txns.isUndoPossible).to.be.false;\r\n expect(imodel.txns.reverseAll()).to.equal(IModelStatus.NothingToUndo);\r\n withEditTxn(imodel, (txn) => insertCategory(txn));\r\n expect(imodel.txns.reverseAll()).to.equal(IModelStatus.Success);\r\n expect(imodel.txns.isUndoPossible).to.be.false;\r\n expect(await readColumnNames(imodel, fooEcsql)).to.include(\"PropB\");\r\n expect(await readColumnNames(imodel, fooEcsql, { usePrimaryConn: true })).to.include(\"PropB\");\r\n });\r\n\r\n it(\"is kept on abandon and instance-only clearCaches, and cleared by a full clearCaches\", async () => {\r\n await readMetaData(imodel, fooEcsql);\r\n const txn = new EditTxn(imodel, \"abandon\");\r\n txn.start();\r\n insertCategory(txn);\r\n txn.end(\"abandon\");\r\n await expectMetadataRequested(imodel, fooEcsql, false);\r\n\r\n imodel.clearCaches({ instanceCachesOnly: true });\r\n await expectMetadataRequested(imodel, fooEcsql, false);\r\n\r\n imodel.clearCaches();\r\n await expectMetadataRequested(imodel, fooEcsql, true);\r\n });\r\n });\r\n});\r\n\r\n// HubMock.startup stubs CloudSqlite with sinon, so this suite must not call sinon.restore().\r\ndescribe(\"createQueryReader metadata cache across briefcases\", () => {\r\n const ecsql = \"SELECT * FROM mcbt.Foo ORDER BY PropA\";\r\n const configs: QueryOptions[] = [{}, { usePrimaryConn: true }];\r\n\r\n before(() => HubMock.startup(\"QueryMetadataCache\", KnownTestLocations.outputDir));\r\n after(() => HubMock.shutdown());\r\n\r\n async function insertFoo(db: BriefcaseDb, props: { propA: string, propB?: number }): Promise<void> {\r\n await db.locks.acquireLocks({ shared: IModel.dictionaryId });\r\n const txn = new EditTxn(db, \"insert Foo\");\r\n txn.start();\r\n const [, model] = await IModelTestUtils.createAndInsertPhysicalPartitionAndModelAsync(txn, IModelTestUtils.getUniqueModelCode(db, \"MetaCacheModel\"), true);\r\n const category = SpatialCategory.insert(txn, IModel.dictionaryId, Guid.createValue(), new SubCategoryAppearance());\r\n const element: PhysicalElementProps = { classFullName: \"MetaCacheBisTest:Foo\", model, category, code: Code.createEmpty() };\r\n txn.insertElement({ ...element, ...props });\r\n txn.end();\r\n }\r\n\r\n /** Verify both the metadata and the rows a fresh reader returns, on the worker and on the primary connection. */\r\n async function expectFoo(db: IModelDb, withPropB: boolean, rows: Array<{ propA: string, propB?: number }>) {\r\n for (const config of configs) {\r\n const reader = db.createQueryReader(ecsql, undefined, { ...config, rowFormat: QueryRowFormat.UseECSqlPropertyNames });\r\n const actualRows = await reader.toArray();\r\n const names = (await reader.getMetaData()).map((p) => p.name);\r\n expect(names).to.include(\"PropA\");\r\n expect(names.includes(\"PropB\")).to.equal(withPropB);\r\n expect(actualRows.map((row) => ({ propA: row.PropA, propB: row.PropB }))).to.deep.equal(rows.map((row) => ({ propA: row.propA, propB: row.propB })));\r\n }\r\n }\r\n\r\n async function warm(db: IModelDb) {\r\n for (const config of configs) {\r\n await readMetaData(db, ecsql, config);\r\n await expectMetadataRequested(db, ecsql, false, config);\r\n }\r\n }\r\n\r\n it(\"sees new columns after pulling a schema changeset\", async () => {\r\n const accessToken = await HubWrappers.getAccessToken(TestUserType.SuperManager);\r\n const iTwinId = HubMock.iTwinId;\r\n const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName: \"QueryMetadataCachePull\" });\r\n const writer = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken });\r\n const reader = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken });\r\n try {\r\n writer.channels.addAllowedChannel(ChannelControl.sharedChannelName);\r\n await writer.importSchemaStrings([bisSchema(\"01.00.00\", false)]);\r\n await insertFoo(writer, { propA: \"a\" });\r\n await writer.pushChanges({ accessToken, description: \"schema v1\" });\r\n\r\n await reader.pullChanges({ accessToken });\r\n await warm(reader);\r\n await expectFoo(reader, false, [{ propA: \"a\" }]);\r\n\r\n await writer.importSchemaStrings([bisSchema(\"01.00.01\", true)]);\r\n await insertFoo(writer, { propA: \"b\", propB: 42 });\r\n await writer.pushChanges({ accessToken, description: \"schema v2\" });\r\n\r\n await reader.pullChanges({ accessToken });\r\n await expectFoo(reader, true, [{ propA: \"a\" }, { propA: \"b\", propB: 42 }]);\r\n } finally {\r\n writer.close();\r\n reader.close();\r\n }\r\n });\r\n\r\n it(\"sees new columns after replaying a schema change made by another connection\", async () => {\r\n const accessToken = await HubWrappers.getAccessToken(TestUserType.SuperManager);\r\n const iTwinId = HubMock.iTwinId;\r\n const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName: \"QueryMetadataCacheReplay\" });\r\n const briefcaseProps = await BriefcaseManager.downloadBriefcase({ accessToken, iTwinId, iModelId });\r\n\r\n const fsWatcher = { callback: () => { }, close: () => { } };\r\n const watchStub = sinon.stub(fs, \"watch\").callsFake(((_filename: fs.PathLike, _opts: fs.WatchOptions, fn: () => void) => {\r\n fsWatcher.callback = fn;\r\n return fsWatcher;\r\n }) as any);\r\n let writer: BriefcaseDb | undefined;\r\n let reader: BriefcaseDb | undefined;\r\n try {\r\n writer = await BriefcaseDb.open({ fileName: briefcaseProps.fileName });\r\n writer.channels.addAllowedChannel(ChannelControl.sharedChannelName);\r\n reader = await BriefcaseDb.open({ fileName: briefcaseProps.fileName, watchForChanges: true });\r\n\r\n await writer.importSchemaStrings([bisSchema(\"01.00.00\", false)]);\r\n await insertFoo(writer, { propA: \"a\" });\r\n fsWatcher.callback();\r\n await warm(reader);\r\n await expectFoo(reader, false, [{ propA: \"a\" }]);\r\n\r\n await writer.importSchemaStrings([bisSchema(\"01.00.01\", true)]);\r\n await insertFoo(writer, { propA: \"b\", propB: 42 });\r\n fsWatcher.callback();\r\n await expectFoo(reader, true, [{ propA: \"a\" }, { propA: \"b\", propB: 42 }]);\r\n } finally {\r\n reader?.close();\r\n writer?.close();\r\n watchStub.restore();\r\n }\r\n });\r\n});\r\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RelationshipBatchLookup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelationshipBatchLookup.test.d.ts","sourceRoot":"","sources":["../../../../src/test/element/RelationshipBatchLookup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,202 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { expect } from "chai";
6
+ import * as sinon from "sinon";
7
+ import { Guid, Id64 } from "@itwin/core-bentley";
8
+ import { Code, IModel } from "@itwin/core-common";
9
+ import { withEditTxn } from "../../EditTxn";
10
+ import { RepositoryLink } from "../../Element";
11
+ import { SnapshotDb } from "../../IModelDb";
12
+ import { ElementDrivesElement, ElementGroupsMembers, ElementRefersToElements } from "../../Relationship";
13
+ import { IModelTestUtils } from "../IModelTestUtils";
14
+ describe("Relationships batched lookup", () => {
15
+ const testSchema = `<?xml version="1.0" encoding="UTF-8"?>
16
+ <ECSchema schemaName="BatchLookupTest" alias="blt" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
17
+ <ECSchemaReference name="BisCore" version="01.00.00" alias="bis"/>
18
+ <ECStructClass typeName="TestStruct">
19
+ <ECProperty propertyName="label" typeName="string"/>
20
+ <ECProperty propertyName="origin" typeName="point2d"/>
21
+ </ECStructClass>
22
+ <ECRelationshipClass typeName="TestRefersToElements" strength="referencing" modifier="Sealed">
23
+ <BaseClass>bis:ElementRefersToElements</BaseClass>
24
+ <Source multiplicity="(0..*)" roleLabel="refers to" polymorphic="true">
25
+ <Class class="bis:Element"/>
26
+ </Source>
27
+ <Target multiplicity="(0..*)" roleLabel="is referenced by" polymorphic="true">
28
+ <Class class="bis:Element"/>
29
+ </Target>
30
+ <ECProperty propertyName="Location" typeName="point3d"/>
31
+ <ECStructProperty propertyName="Info" typeName="TestStruct"/>
32
+ <ECArrayProperty propertyName="Points" typeName="point3d" minOccurs="0" maxOccurs="unbounded"/>
33
+ </ECRelationshipClass>
34
+ </ECSchema>`;
35
+ const testRelClass = "BatchLookupTest:TestRefersToElements";
36
+ let imodel;
37
+ let elementIds;
38
+ let relIds;
39
+ before(async () => {
40
+ imodel = SnapshotDb.createEmpty(IModelTestUtils.prepareOutputFile("Relationship", "BatchLookup.bim"), { rootSubject: { name: "BatchLookup" } });
41
+ await imodel.importSchemaStrings([testSchema]);
42
+ withEditTxn(imodel, (txn) => {
43
+ elementIds = [];
44
+ for (let i = 0; i < 6; ++i) {
45
+ const props = {
46
+ classFullName: RepositoryLink.classFullName,
47
+ model: IModel.repositoryModelId,
48
+ code: Code.createEmpty(),
49
+ repositoryGuid: Guid.createValue(),
50
+ };
51
+ elementIds.push(txn.insertElement(props));
52
+ }
53
+ // Chain e0->e1->e2->e3->e4 with memberPriority equal to the source index.
54
+ relIds = [];
55
+ for (let i = 0; i < 4; ++i)
56
+ relIds.push(txn.insertRelationship(ElementGroupsMembers.create(imodel, elementIds[i], elementIds[i + 1], i).toJSON()));
57
+ });
58
+ });
59
+ after(() => imodel.close());
60
+ it("matches tryGetInstanceProps for ids and source/target pairs, preserving order", async () => {
61
+ const [e0, e1, e2, e3, e4, e5] = elementIds;
62
+ const criteria = [
63
+ relIds[2],
64
+ { sourceId: e0, targetId: e1 },
65
+ Id64.fromLocalAndBriefcaseIds(0x7fff, 0), // non-existent id
66
+ { sourceId: e3, targetId: e4 },
67
+ { sourceId: e0, targetId: e2 }, // both ends requested elsewhere, but not related as a pair
68
+ { sourceId: e4, targetId: e5 }, // unrelated
69
+ Id64.invalid,
70
+ relIds[2], // duplicate
71
+ { sourceId: e1, targetId: e2 },
72
+ relIds[0],
73
+ ];
74
+ const batch = await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, criteria);
75
+ expect(batch.length).to.equal(criteria.length);
76
+ criteria.forEach((criterion, i) => {
77
+ expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(ElementGroupsMembers.classFullName, criterion), `criterion ${i}`);
78
+ });
79
+ expect(batch[0]?.id).to.equal(relIds[2]);
80
+ expect(batch[0]?.classFullName).to.equal(ElementGroupsMembers.classFullName);
81
+ expect(batch[1].memberPriority).to.equal(0);
82
+ expect(batch[1]?.id).to.equal(relIds[0]);
83
+ expect(batch[2]).to.be.undefined;
84
+ expect(batch[3]?.id).to.equal(relIds[3]);
85
+ expect(batch[4]).to.be.undefined;
86
+ expect(batch[5]).to.be.undefined;
87
+ expect(batch[6]).to.be.undefined;
88
+ expect(batch[7]?.id).to.equal(relIds[2]);
89
+ expect(batch[8]?.id).to.equal(relIds[1]);
90
+ // The concurrent query connection sees the same saved data.
91
+ expect(await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, criteria, { usePrimaryConn: false })).to.deep.equal(batch);
92
+ });
93
+ it("returns an empty array for empty criteria", async () => {
94
+ expect(await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, [])).to.deep.equal([]);
95
+ expect(await imodel.relationships.queryInstances(ElementGroupsMembers.classFullName, [])).to.deep.equal([]);
96
+ });
97
+ it("queries polymorphically and respects the relationship class", async () => {
98
+ const criteria = [relIds[0], { sourceId: elementIds[1], targetId: elementIds[2] }];
99
+ const viaBase = await imodel.relationships.queryInstancesProps(ElementRefersToElements.classFullName, criteria);
100
+ expect(viaBase.map((p) => p?.classFullName)).to.deep.equal([ElementGroupsMembers.classFullName, ElementGroupsMembers.classFullName]);
101
+ criteria.forEach((criterion, i) => expect(viaBase[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(ElementRefersToElements.classFullName, criterion), `criterion ${i}`));
102
+ const viaOther = await imodel.relationships.queryInstancesProps(ElementDrivesElement.classFullName, criteria);
103
+ expect(viaOther).to.deep.equal([undefined, undefined]);
104
+ });
105
+ it("queryInstances constructs Relationship entities", async () => {
106
+ const criteria = [relIds[1], { sourceId: elementIds[3], targetId: elementIds[4] }, Id64.invalid];
107
+ const rels = await imodel.relationships.queryInstances(ElementGroupsMembers.classFullName, criteria);
108
+ expect(rels.length).to.equal(3);
109
+ expect(rels[0]).to.be.instanceOf(ElementGroupsMembers);
110
+ expect(rels[0]?.id).to.equal(relIds[1]);
111
+ expect(rels[0]?.memberPriority).to.equal(1);
112
+ expect(rels[1]).to.be.instanceOf(ElementGroupsMembers);
113
+ expect(rels[1]?.sourceId).to.equal(elementIds[3]);
114
+ expect(rels[1]?.targetId).to.equal(elementIds[4]);
115
+ expect(rels[2]).to.be.undefined;
116
+ criteria.forEach((criterion, i) => expect(rels[i]?.toJSON()).to.deep.equal(imodel.relationships.tryGetInstance(ElementGroupsMembers.classFullName, criterion)?.toJSON(), `criterion ${i}`));
117
+ });
118
+ it("sees unsaved changes by default", async () => {
119
+ const cls = ElementGroupsMembers.classFullName;
120
+ const pair = { sourceId: elementIds[4], targetId: elementIds[5] };
121
+ await withEditTxn(imodel, async (txn) => {
122
+ const id = txn.insertRelationship(ElementGroupsMembers.create(imodel, pair.sourceId, pair.targetId, 4).toJSON());
123
+ const found = await imodel.relationships.queryInstances(cls, [id, pair]);
124
+ expect(found.map((r) => r?.id)).to.deep.equal([id, id]);
125
+ txn.deleteRelationship(imodel.relationships.getInstanceProps(cls, id));
126
+ });
127
+ });
128
+ it("converts point, struct and array properties like tryGetInstanceProps", async () => {
129
+ const pair = { sourceId: elementIds[0], targetId: elementIds[5] };
130
+ await withEditTxn(imodel, async (txn) => {
131
+ const id = txn.insertRelationship({
132
+ classFullName: testRelClass,
133
+ ...pair,
134
+ location: { x: 1, y: 2, z: 3 },
135
+ info: { label: "a", origin: { x: 4, y: 5 } },
136
+ points: [{ x: 6, y: 7, z: 8 }, { x: 9, y: 10, z: 11 }],
137
+ });
138
+ const criteria = [id, pair];
139
+ const batch = await imodel.relationships.queryInstancesProps(testRelClass, criteria);
140
+ criteria.forEach((criterion, i) => expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(testRelClass, criterion), `criterion ${i}`));
141
+ expect(batch[0]).to.include({ id, classFullName: testRelClass });
142
+ expect(batch[0]).to.deep.include({
143
+ location: { x: 1, y: 2, z: 3 },
144
+ info: { label: "a", origin: { x: 4, y: 5 } },
145
+ points: [{ x: 6, y: 7, z: 8 }, { x: 9, y: 10, z: 11 }],
146
+ });
147
+ txn.deleteRelationship(batch[0]);
148
+ });
149
+ });
150
+ it("reads only the requested pairs in a dense many-to-many graph", async () => {
151
+ const cls = ElementGroupsMembers.classFullName;
152
+ const n = 5;
153
+ await withEditTxn(imodel, async (txn) => {
154
+ const sources = [];
155
+ const targets = [];
156
+ for (let i = 0; i < 2 * n; ++i) {
157
+ const id = txn.insertElement({ classFullName: RepositoryLink.classFullName, model: IModel.repositoryModelId, code: Code.createEmpty(), repositoryGuid: Guid.createValue() });
158
+ (i < n ? sources : targets).push(id);
159
+ }
160
+ // Connect every source to every target, then request only the "diagonal" pairs.
161
+ for (const sourceId of sources)
162
+ for (const targetId of targets)
163
+ txn.insertRelationship(ElementGroupsMembers.create(imodel, sourceId, targetId, 0).toJSON());
164
+ const pairs = sources.map((sourceId, i) => ({ sourceId, targetId: targets[i] }));
165
+ let rowsRead = 0;
166
+ const createQueryReader = imodel.createQueryReader.bind(imodel);
167
+ const stub = sinon.stub(imodel, "createQueryReader").callsFake((ecsql, params, config) => {
168
+ const reader = createQueryReader(ecsql, params, config);
169
+ const step = reader.step.bind(reader);
170
+ reader.step = async () => {
171
+ const hasRow = await step();
172
+ if (hasRow)
173
+ ++rowsRead;
174
+ return hasRow;
175
+ };
176
+ return reader;
177
+ });
178
+ try {
179
+ const found = await imodel.relationships.queryInstancesProps(cls, pairs);
180
+ expect(found.map((p) => p && { sourceId: p.sourceId, targetId: p.targetId })).to.deep.equal(pairs);
181
+ }
182
+ finally {
183
+ stub.restore();
184
+ }
185
+ expect(rowsRead).to.equal(n);
186
+ });
187
+ });
188
+ it("supports relationships stored as navigation properties and ids from any briefcase", async () => {
189
+ const cls = "BisCore:ModelContainsElements";
190
+ const highBriefcaseId = Id64.fromLocalAndBriefcaseIds(1, 0xfffffd);
191
+ const criteria = [
192
+ elementIds[0],
193
+ { sourceId: IModel.repositoryModelId, targetId: elementIds[1] },
194
+ highBriefcaseId,
195
+ { sourceId: highBriefcaseId, targetId: elementIds[1] },
196
+ ];
197
+ const batch = await imodel.relationships.queryInstancesProps(cls, criteria);
198
+ criteria.forEach((criterion, i) => expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(cls, criterion), `criterion ${i}`));
199
+ expect(batch.map((p) => p?.targetId)).to.deep.equal([elementIds[0], elementIds[1], undefined, undefined]);
200
+ });
201
+ });
202
+ //# sourceMappingURL=RelationshipBatchLookup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelationshipBatchLookup.test.js","sourceRoot":"","sources":["../../../../src/test/element/RelationshipBatchLookup.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { Guid, Id64, Id64String } from \"@itwin/core-bentley\";\r\nimport { Code, IModel, RelationshipProps, RepositoryLinkProps, SourceAndTarget } from \"@itwin/core-common\";\r\nimport { withEditTxn } from \"../../EditTxn\";\r\nimport { RepositoryLink } from \"../../Element\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { ElementDrivesElement, ElementGroupsMembers, ElementRefersToElements } from \"../../Relationship\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\ndescribe(\"Relationships batched lookup\", () => {\r\n const testSchema = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n <ECSchema schemaName=\"BatchLookupTest\" alias=\"blt\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECSchemaReference name=\"BisCore\" version=\"01.00.00\" alias=\"bis\"/>\r\n <ECStructClass typeName=\"TestStruct\">\r\n <ECProperty propertyName=\"label\" typeName=\"string\"/>\r\n <ECProperty propertyName=\"origin\" typeName=\"point2d\"/>\r\n </ECStructClass>\r\n <ECRelationshipClass typeName=\"TestRefersToElements\" strength=\"referencing\" modifier=\"Sealed\">\r\n <BaseClass>bis:ElementRefersToElements</BaseClass>\r\n <Source multiplicity=\"(0..*)\" roleLabel=\"refers to\" polymorphic=\"true\">\r\n <Class class=\"bis:Element\"/>\r\n </Source>\r\n <Target multiplicity=\"(0..*)\" roleLabel=\"is referenced by\" polymorphic=\"true\">\r\n <Class class=\"bis:Element\"/>\r\n </Target>\r\n <ECProperty propertyName=\"Location\" typeName=\"point3d\"/>\r\n <ECStructProperty propertyName=\"Info\" typeName=\"TestStruct\"/>\r\n <ECArrayProperty propertyName=\"Points\" typeName=\"point3d\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\r\n </ECRelationshipClass>\r\n </ECSchema>`;\r\n const testRelClass = \"BatchLookupTest:TestRefersToElements\";\r\n\r\n let imodel: SnapshotDb;\r\n let elementIds: Id64String[];\r\n let relIds: Id64String[];\r\n\r\n before(async () => {\r\n imodel = SnapshotDb.createEmpty(IModelTestUtils.prepareOutputFile(\"Relationship\", \"BatchLookup.bim\"), { rootSubject: { name: \"BatchLookup\" } });\r\n await imodel.importSchemaStrings([testSchema]);\r\n withEditTxn(imodel, (txn) => {\r\n elementIds = [];\r\n for (let i = 0; i < 6; ++i) {\r\n const props: RepositoryLinkProps = {\r\n classFullName: RepositoryLink.classFullName,\r\n model: IModel.repositoryModelId,\r\n code: Code.createEmpty(),\r\n repositoryGuid: Guid.createValue(),\r\n };\r\n elementIds.push(txn.insertElement(props));\r\n }\r\n\r\n // Chain e0->e1->e2->e3->e4 with memberPriority equal to the source index.\r\n relIds = [];\r\n for (let i = 0; i < 4; ++i)\r\n relIds.push(txn.insertRelationship(ElementGroupsMembers.create(imodel, elementIds[i], elementIds[i + 1], i).toJSON()));\r\n });\r\n });\r\n\r\n after(() => imodel.close());\r\n\r\n it(\"matches tryGetInstanceProps for ids and source/target pairs, preserving order\", async () => {\r\n const [e0, e1, e2, e3, e4, e5] = elementIds;\r\n const criteria: Array<Id64String | SourceAndTarget> = [\r\n relIds[2],\r\n { sourceId: e0, targetId: e1 },\r\n Id64.fromLocalAndBriefcaseIds(0x7fff, 0), // non-existent id\r\n { sourceId: e3, targetId: e4 },\r\n { sourceId: e0, targetId: e2 }, // both ends requested elsewhere, but not related as a pair\r\n { sourceId: e4, targetId: e5 }, // unrelated\r\n Id64.invalid,\r\n relIds[2], // duplicate\r\n { sourceId: e1, targetId: e2 },\r\n relIds[0],\r\n ];\r\n\r\n const batch = await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, criteria);\r\n expect(batch.length).to.equal(criteria.length);\r\n criteria.forEach((criterion, i) => {\r\n expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(ElementGroupsMembers.classFullName, criterion), `criterion ${i}`);\r\n });\r\n\r\n expect(batch[0]?.id).to.equal(relIds[2]);\r\n expect(batch[0]?.classFullName).to.equal(ElementGroupsMembers.classFullName);\r\n expect((batch[1] as any).memberPriority).to.equal(0);\r\n expect(batch[1]?.id).to.equal(relIds[0]);\r\n expect(batch[2]).to.be.undefined;\r\n expect(batch[3]?.id).to.equal(relIds[3]);\r\n expect(batch[4]).to.be.undefined;\r\n expect(batch[5]).to.be.undefined;\r\n expect(batch[6]).to.be.undefined;\r\n expect(batch[7]?.id).to.equal(relIds[2]);\r\n expect(batch[8]?.id).to.equal(relIds[1]);\r\n\r\n // The concurrent query connection sees the same saved data.\r\n expect(await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, criteria, { usePrimaryConn: false })).to.deep.equal(batch);\r\n });\r\n\r\n it(\"returns an empty array for empty criteria\", async () => {\r\n expect(await imodel.relationships.queryInstancesProps(ElementGroupsMembers.classFullName, [])).to.deep.equal([]);\r\n expect(await imodel.relationships.queryInstances(ElementGroupsMembers.classFullName, [])).to.deep.equal([]);\r\n });\r\n\r\n it(\"queries polymorphically and respects the relationship class\", async () => {\r\n const criteria = [relIds[0], { sourceId: elementIds[1], targetId: elementIds[2] }];\r\n\r\n const viaBase = await imodel.relationships.queryInstancesProps(ElementRefersToElements.classFullName, criteria);\r\n expect(viaBase.map((p) => p?.classFullName)).to.deep.equal([ElementGroupsMembers.classFullName, ElementGroupsMembers.classFullName]);\r\n criteria.forEach((criterion, i) => expect(viaBase[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(ElementRefersToElements.classFullName, criterion), `criterion ${i}`));\r\n\r\n const viaOther = await imodel.relationships.queryInstancesProps(ElementDrivesElement.classFullName, criteria);\r\n expect(viaOther).to.deep.equal([undefined, undefined]);\r\n });\r\n\r\n it(\"queryInstances constructs Relationship entities\", async () => {\r\n const criteria = [relIds[1], { sourceId: elementIds[3], targetId: elementIds[4] }, Id64.invalid];\r\n const rels = await imodel.relationships.queryInstances<ElementGroupsMembers>(ElementGroupsMembers.classFullName, criteria);\r\n expect(rels.length).to.equal(3);\r\n expect(rels[0]).to.be.instanceOf(ElementGroupsMembers);\r\n expect(rels[0]?.id).to.equal(relIds[1]);\r\n expect(rels[0]?.memberPriority).to.equal(1);\r\n expect(rels[1]).to.be.instanceOf(ElementGroupsMembers);\r\n expect(rels[1]?.sourceId).to.equal(elementIds[3]);\r\n expect(rels[1]?.targetId).to.equal(elementIds[4]);\r\n expect(rels[2]).to.be.undefined;\r\n criteria.forEach((criterion, i) => expect(rels[i]?.toJSON()).to.deep.equal(imodel.relationships.tryGetInstance(ElementGroupsMembers.classFullName, criterion)?.toJSON(), `criterion ${i}`));\r\n });\r\n\r\n it(\"sees unsaved changes by default\", async () => {\r\n const cls = ElementGroupsMembers.classFullName;\r\n const pair = { sourceId: elementIds[4], targetId: elementIds[5] };\r\n await withEditTxn(imodel, async (txn) => {\r\n const id = txn.insertRelationship(ElementGroupsMembers.create(imodel, pair.sourceId, pair.targetId, 4).toJSON());\r\n const found = await imodel.relationships.queryInstances(cls, [id, pair]);\r\n expect(found.map((r) => r?.id)).to.deep.equal([id, id]);\r\n txn.deleteRelationship(imodel.relationships.getInstanceProps(cls, id));\r\n });\r\n });\r\n\r\n it(\"converts point, struct and array properties like tryGetInstanceProps\", async () => {\r\n const pair = { sourceId: elementIds[0], targetId: elementIds[5] };\r\n await withEditTxn(imodel, async (txn) => {\r\n const id = txn.insertRelationship({\r\n classFullName: testRelClass,\r\n ...pair,\r\n location: { x: 1, y: 2, z: 3 },\r\n info: { label: \"a\", origin: { x: 4, y: 5 } },\r\n points: [{ x: 6, y: 7, z: 8 }, { x: 9, y: 10, z: 11 }],\r\n } as RelationshipProps);\r\n\r\n const criteria = [id, pair];\r\n const batch = await imodel.relationships.queryInstancesProps(testRelClass, criteria);\r\n criteria.forEach((criterion, i) => expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(testRelClass, criterion), `criterion ${i}`));\r\n expect(batch[0]).to.include({ id, classFullName: testRelClass });\r\n expect(batch[0]).to.deep.include({\r\n location: { x: 1, y: 2, z: 3 },\r\n info: { label: \"a\", origin: { x: 4, y: 5 } },\r\n points: [{ x: 6, y: 7, z: 8 }, { x: 9, y: 10, z: 11 }],\r\n });\r\n txn.deleteRelationship(batch[0]!);\r\n });\r\n });\r\n\r\n it(\"reads only the requested pairs in a dense many-to-many graph\", async () => {\r\n const cls = ElementGroupsMembers.classFullName;\r\n const n = 5;\r\n await withEditTxn(imodel, async (txn) => {\r\n const sources: Id64String[] = [];\r\n const targets: Id64String[] = [];\r\n for (let i = 0; i < 2 * n; ++i) {\r\n const id = txn.insertElement({ classFullName: RepositoryLink.classFullName, model: IModel.repositoryModelId, code: Code.createEmpty(), repositoryGuid: Guid.createValue() } as RepositoryLinkProps);\r\n (i < n ? sources : targets).push(id);\r\n }\r\n\r\n // Connect every source to every target, then request only the \"diagonal\" pairs.\r\n for (const sourceId of sources)\r\n for (const targetId of targets)\r\n txn.insertRelationship(ElementGroupsMembers.create(imodel, sourceId, targetId, 0).toJSON());\r\n\r\n const pairs = sources.map((sourceId, i) => ({ sourceId, targetId: targets[i] }));\r\n let rowsRead = 0;\r\n const createQueryReader = imodel.createQueryReader.bind(imodel);\r\n const stub = sinon.stub(imodel, \"createQueryReader\").callsFake((ecsql, params, config) => {\r\n const reader = createQueryReader(ecsql, params, config);\r\n const step = reader.step.bind(reader);\r\n reader.step = async () => {\r\n const hasRow = await step();\r\n if (hasRow)\r\n ++rowsRead;\r\n return hasRow;\r\n };\r\n return reader;\r\n });\r\n try {\r\n const found = await imodel.relationships.queryInstancesProps(cls, pairs);\r\n expect(found.map((p) => p && { sourceId: p.sourceId, targetId: p.targetId })).to.deep.equal(pairs);\r\n } finally {\r\n stub.restore();\r\n }\r\n expect(rowsRead).to.equal(n);\r\n });\r\n });\r\n\r\n it(\"supports relationships stored as navigation properties and ids from any briefcase\", async () => {\r\n const cls = \"BisCore:ModelContainsElements\";\r\n const highBriefcaseId = Id64.fromLocalAndBriefcaseIds(1, 0xfffffd);\r\n const criteria: Array<Id64String | SourceAndTarget> = [\r\n elementIds[0],\r\n { sourceId: IModel.repositoryModelId, targetId: elementIds[1] },\r\n highBriefcaseId,\r\n { sourceId: highBriefcaseId, targetId: elementIds[1] },\r\n ];\r\n const batch = await imodel.relationships.queryInstancesProps(cls, criteria);\r\n criteria.forEach((criterion, i) => expect(batch[i]).to.deep.equal(imodel.relationships.tryGetInstanceProps(cls, criterion), `criterion ${i}`));\r\n expect(batch.map((p) => p?.targetId)).to.deep.equal([elementIds[0], elementIds[1], undefined, undefined]);\r\n });\r\n});\r\n"]}
@@ -2,15 +2,19 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { assert } from "chai";
5
+ import * as chai from "chai";
6
+ import * as chaiAsPromised from "chai-as-promised";
6
7
  import { Guid } from "@itwin/core-bentley";
7
8
  import { BriefcaseIdValue } from "@itwin/core-common";
9
+ import { Range3d } from "@itwin/core-geometry";
8
10
  import { HubWrappers, IModelTestUtils } from "../IModelTestUtils";
9
11
  import { KnownTestLocations } from "../KnownTestLocations";
10
12
  import { HubMock } from "../../internal/HubMock";
11
13
  import { TestChangeSetUtility } from "../TestChangeSetUtility";
12
14
  import { _nativeDb, ChannelControl, ProgressStatus } from "../../core-backend";
13
15
  import { withEditTxn } from "../../EditTxn";
16
+ chai.use(chaiAsPromised);
17
+ const assert = chai.assert;
14
18
  describe("BriefcaseManager", async () => {
15
19
  const testITwinId = Guid.createValue();
16
20
  const managerAccessToken = "manager mock token";
@@ -234,5 +238,187 @@ describe("BriefcaseManager", async () => {
234
238
  await testUtility.deleteTestIModel();
235
239
  });
236
240
  });
241
+ describe("TxnManager.onPrePushValidation", () => {
242
+ const user2 = "user2 mock token";
243
+ const user3 = "user3 mock token";
244
+ /** Creates an empty iModel and opens a briefcase with one local, unpushed change to the root subject's user label. */
245
+ async function setupBriefcaseWithLocalChange(testName) {
246
+ HubMock.startup(testName, KnownTestLocations.outputDir);
247
+ const iTwinId = HubMock.iTwinId;
248
+ const iModelId = await HubWrappers.recreateIModel({ accessToken: user2, iTwinId, iModelName: testName, noLocks: true });
249
+ const briefcase = await HubWrappers.downloadAndOpenBriefcase({ accessToken: user2, iTwinId, iModelId });
250
+ briefcase.channels.addAllowedChannel(ChannelControl.sharedChannelName);
251
+ const rootEl = briefcase.elements.getRootSubject();
252
+ rootEl.userLabel = "local change";
253
+ withEditTxn(briefcase, (txn) => txn.updateElement(rootEl.toJSON()));
254
+ assert.isTrue(briefcase.txns.hasPendingTxns);
255
+ return { iTwinId, iModelId, briefcase };
256
+ }
257
+ it("delays the push until the listener's promise resolves", async () => {
258
+ const { briefcase } = await setupBriefcaseWithLocalChange("prePushDelay");
259
+ const changesetBeforePush = briefcase.changeset.id;
260
+ const events = [];
261
+ let changesetWhenListenerFinished;
262
+ let releaseListener;
263
+ const gate = new Promise((resolve) => { releaseListener = resolve; });
264
+ let listenerStarted;
265
+ const started = new Promise((resolve) => { listenerStarted = resolve; });
266
+ const removeListener = briefcase.txns.onPrePushValidation.addListener(async () => {
267
+ events.push("listener started");
268
+ listenerStarted();
269
+ await gate;
270
+ changesetWhenListenerFinished = briefcase.changeset.id;
271
+ events.push("listener finished");
272
+ });
273
+ try {
274
+ const pushPromise = briefcase.pushChanges({ accessToken: user2, description: "delayed push" }).then(() => { events.push("push settled"); });
275
+ await started;
276
+ events.push("listener released");
277
+ releaseListener();
278
+ await pushPromise;
279
+ assert.deepEqual(events, ["listener started", "listener released", "listener finished", "push settled"]);
280
+ assert.strictEqual(changesetWhenListenerFinished, changesetBeforePush, "nothing should be pushed before the listener resolves");
281
+ assert.notStrictEqual(briefcase.changeset.id, changesetBeforePush, "push should complete once the listener resolves");
282
+ assert.isFalse(briefcase.txns.hasPendingTxns);
283
+ }
284
+ finally {
285
+ releaseListener();
286
+ removeListener();
287
+ }
288
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, briefcase);
289
+ });
290
+ it("includes a Txn written by the listener in the pushed changeset", async () => {
291
+ const { iTwinId, iModelId, briefcase } = await setupBriefcaseWithLocalChange("prePushWriteTxn");
292
+ const changesetBeforePush = briefcase.changeset.id;
293
+ const txnCountBeforePush = Array.from(briefcase.txns.queryTxns()).length;
294
+ let txnCountInListener = 0;
295
+ const removeListener = briefcase.txns.onPrePushValidation.addListener(async () => {
296
+ const rootEl = briefcase.elements.getRootSubject();
297
+ rootEl.description = "written during pre-push validation";
298
+ withEditTxn(briefcase, (txn) => txn.updateElement(rootEl.toJSON()));
299
+ txnCountInListener = Array.from(briefcase.txns.queryTxns()).length;
300
+ });
301
+ try {
302
+ await briefcase.pushChanges({ accessToken: user2, description: "push with pre-push txn" });
303
+ }
304
+ finally {
305
+ removeListener();
306
+ }
307
+ assert.isAbove(txnCountInListener, txnCountBeforePush, "listener should have written a new Txn");
308
+ assert.notStrictEqual(briefcase.changeset.id, changesetBeforePush);
309
+ assert.isFalse(briefcase.txns.hasPendingTxns, "the listener's Txn should have been pushed, not left pending");
310
+ // A fresh briefcase at the tip only sees the listener's change if it was part of the pushed changeset.
311
+ const verifier = await HubWrappers.downloadAndOpenBriefcase({ accessToken: user3, iTwinId, iModelId });
312
+ const pushedRoot = verifier.elements.getRootSubject();
313
+ assert.strictEqual(pushedRoot.userLabel, "local change");
314
+ assert.strictEqual(pushedRoot.description, "written during pre-push validation");
315
+ await HubWrappers.closeAndDeleteBriefcaseDb(user3, verifier);
316
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, briefcase);
317
+ });
318
+ it("aborts the push when the listener rejects", async () => {
319
+ const { briefcase } = await setupBriefcaseWithLocalChange("prePushReject");
320
+ const changesetBeforePush = briefcase.changeset.id;
321
+ const removeListener = briefcase.txns.onPrePushValidation.addListener(async () => {
322
+ throw new Error("validation failed");
323
+ });
324
+ try {
325
+ await assert.isRejected(briefcase.pushChanges({ accessToken: user2, description: "rejected push" }), "validation failed");
326
+ }
327
+ finally {
328
+ removeListener();
329
+ }
330
+ assert.strictEqual(briefcase.changeset.id, changesetBeforePush, "briefcase should not have advanced");
331
+ assert.isTrue(briefcase.txns.hasPendingTxns, "local changes should still be pending");
332
+ // With the listener removed, the same changes can still be pushed.
333
+ await briefcase.pushChanges({ accessToken: user2, description: "retry push" });
334
+ assert.notStrictEqual(briefcase.changeset.id, changesetBeforePush);
335
+ assert.isFalse(briefcase.txns.hasPendingTxns);
336
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, briefcase);
337
+ });
338
+ it("handles a listener that calls pushChanges, recursing asynchronously", async () => {
339
+ const { briefcase } = await setupBriefcaseWithLocalChange("prePushRecursion");
340
+ const changesetBeforePush = briefcase.changeset.id;
341
+ let listenerCalls = 0;
342
+ let changesetAfterNestedPush;
343
+ // addOnce removes the listener before invoking it, so the nested push does not re-enter it endlessly.
344
+ const removeListener = briefcase.txns.onPrePushValidation.addOnce(async () => {
345
+ ++listenerCalls;
346
+ await briefcase.pushChanges({ accessToken: user2, description: "nested push" });
347
+ changesetAfterNestedPush = briefcase.changeset.id;
348
+ });
349
+ try {
350
+ // The nested push consumes all pending Txns, so the outer push has nothing left to push and completes quietly.
351
+ await briefcase.pushChanges({ accessToken: user2, description: "outer push" });
352
+ }
353
+ finally {
354
+ removeListener();
355
+ }
356
+ assert.strictEqual(listenerCalls, 1, "listener should only run for the outer push");
357
+ assert.isDefined(changesetAfterNestedPush);
358
+ assert.notStrictEqual(changesetAfterNestedPush, changesetBeforePush, "nested push should have pushed the changes");
359
+ assert.strictEqual(briefcase.changeset.id, changesetAfterNestedPush);
360
+ assert.isFalse(briefcase.txns.hasPendingTxns);
361
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, briefcase);
362
+ });
363
+ describe("after pull/merge", () => {
364
+ const incomingExtents = new Range3d(-100, -200, -300, 400, 500, 600);
365
+ // Note: only project extents are covered. The native getIModelProps("pullMerge") does not reload geolocation (ECEF location, global origin) after a merge.
366
+ /** user2 has a local unpushed change; user3 then pushes new project extents that user2 has not yet pulled. */
367
+ async function setup(testName) {
368
+ HubMock.startup(testName, KnownTestLocations.outputDir);
369
+ const iTwinId = HubMock.iTwinId;
370
+ const iModelId = await HubWrappers.recreateIModel({ accessToken: user2, iTwinId, iModelName: testName, noLocks: true });
371
+ const local = await HubWrappers.downloadAndOpenBriefcase({ accessToken: user2, iTwinId, iModelId });
372
+ local.channels.addAllowedChannel(ChannelControl.sharedChannelName);
373
+ const rootEl = local.elements.getRootSubject();
374
+ rootEl.userLabel = "local change";
375
+ withEditTxn(local, (txn) => txn.updateElement(rootEl.toJSON()));
376
+ const remote = await HubWrappers.downloadAndOpenBriefcase({ accessToken: user3, iTwinId, iModelId });
377
+ remote.channels.addAllowedChannel(ChannelControl.sharedChannelName);
378
+ withEditTxn(remote, (txn) => txn.updateProjectExtents(incomingExtents));
379
+ await remote.pushChanges({ accessToken: user3, description: "project extents" });
380
+ return { iTwinId, iModelId, local, remote };
381
+ }
382
+ it("exposes the merged project extents to listeners", async () => {
383
+ const { local, remote } = await setup("prePushMergedProps");
384
+ let seenExtents;
385
+ const removeListener = local.txns.onPrePushValidation.addListener(async () => {
386
+ seenExtents = local.projectExtents.clone();
387
+ });
388
+ try {
389
+ await local.pushChanges({ accessToken: user2, description: "push after merge" });
390
+ }
391
+ finally {
392
+ removeListener();
393
+ }
394
+ assert.isDefined(seenExtents);
395
+ assert.isTrue(seenExtents.isAlmostEqual(incomingExtents), "listener should see the merged project extents");
396
+ await HubWrappers.closeAndDeleteBriefcaseDb(user3, remote);
397
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, local);
398
+ });
399
+ it("lets a listener extend the merged project extents", async () => {
400
+ const { iTwinId, iModelId, local, remote } = await setup("prePushExtendExtents");
401
+ const extra = new Range3d(500, 600, 700, 800, 900, 1000);
402
+ const expected = incomingExtents.clone();
403
+ expected.extendRange(extra);
404
+ const removeListener = local.txns.onPrePushValidation.addListener(async () => {
405
+ const extended = local.projectExtents.clone();
406
+ extended.extendRange(extra);
407
+ withEditTxn(local, (txn) => txn.updateProjectExtents(extended));
408
+ });
409
+ try {
410
+ await local.pushChanges({ accessToken: user2, description: "push after merge" });
411
+ }
412
+ finally {
413
+ removeListener();
414
+ }
415
+ const verifier = await HubWrappers.downloadAndOpenBriefcase({ accessToken: user3, iTwinId, iModelId, briefcaseId: BriefcaseIdValue.Unassigned });
416
+ assert.isTrue(verifier.projectExtents.isAlmostEqual(expected), "pushed extents should extend the merged extents, not the stale pre-merge extents");
417
+ await HubWrappers.closeAndDeleteBriefcaseDb(user3, verifier);
418
+ await HubWrappers.closeAndDeleteBriefcaseDb(user3, remote);
419
+ await HubWrappers.closeAndDeleteBriefcaseDb(user2, local);
420
+ });
421
+ });
422
+ });
237
423
  });
238
424
  //# sourceMappingURL=BriefcaseManager.test.js.map