@itwin/core-backend 5.13.0-dev.9 → 5.13.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 (261) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  3. package/lib/cjs/BriefcaseManager.js +11 -5
  4. package/lib/cjs/BriefcaseManager.js.map +1 -1
  5. package/lib/cjs/Category.d.ts +4 -4
  6. package/lib/cjs/Category.js.map +1 -1
  7. package/lib/cjs/ChangesetECAdaptor.d.ts +5 -0
  8. package/lib/cjs/ChangesetECAdaptor.d.ts.map +1 -1
  9. package/lib/cjs/ChangesetECAdaptor.js +13 -3
  10. package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
  11. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  12. package/lib/cjs/CloudSqlite.js +9 -2
  13. package/lib/cjs/CloudSqlite.js.map +1 -1
  14. package/lib/cjs/CodeSpecs.d.ts +3 -3
  15. package/lib/cjs/CodeSpecs.js.map +1 -1
  16. package/lib/cjs/DisplayStyle.d.ts +2 -2
  17. package/lib/cjs/DisplayStyle.js.map +1 -1
  18. package/lib/cjs/ECDb.d.ts.map +1 -1
  19. package/lib/cjs/ECDb.js +1 -0
  20. package/lib/cjs/ECDb.js.map +1 -1
  21. package/lib/cjs/EditTxn.d.ts.map +1 -1
  22. package/lib/cjs/EditTxn.js +1 -0
  23. package/lib/cjs/EditTxn.js.map +1 -1
  24. package/lib/cjs/Element.d.ts +48 -12
  25. package/lib/cjs/Element.d.ts.map +1 -1
  26. package/lib/cjs/Element.js +120 -24
  27. package/lib/cjs/Element.js.map +1 -1
  28. package/lib/cjs/IModelDb.d.ts +72 -22
  29. package/lib/cjs/IModelDb.d.ts.map +1 -1
  30. package/lib/cjs/IModelDb.js +226 -89
  31. package/lib/cjs/IModelDb.js.map +1 -1
  32. package/lib/cjs/Model.d.ts +5 -5
  33. package/lib/cjs/Model.d.ts.map +1 -1
  34. package/lib/cjs/Model.js.map +1 -1
  35. package/lib/cjs/PropertyStore.js +1 -1
  36. package/lib/cjs/PropertyStore.js.map +1 -1
  37. package/lib/cjs/SchemaSync.d.ts +158 -22
  38. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  39. package/lib/cjs/SchemaSync.js +417 -76
  40. package/lib/cjs/SchemaSync.js.map +1 -1
  41. package/lib/cjs/SynchronousChannel.d.ts +72 -0
  42. package/lib/cjs/SynchronousChannel.d.ts.map +1 -0
  43. package/lib/cjs/SynchronousChannel.js +11 -0
  44. package/lib/cjs/SynchronousChannel.js.map +1 -0
  45. package/lib/cjs/Texture.d.ts +1 -1
  46. package/lib/cjs/Texture.js.map +1 -1
  47. package/lib/cjs/TxnManager.d.ts +44 -4
  48. package/lib/cjs/TxnManager.d.ts.map +1 -1
  49. package/lib/cjs/TxnManager.js +80 -19
  50. package/lib/cjs/TxnManager.js.map +1 -1
  51. package/lib/cjs/ViewDefinition.d.ts +6 -6
  52. package/lib/cjs/ViewDefinition.d.ts.map +1 -1
  53. package/lib/cjs/ViewDefinition.js.map +1 -1
  54. package/lib/cjs/annotations/LeaderGeometry.d.ts +22 -7
  55. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  56. package/lib/cjs/annotations/LeaderGeometry.js +104 -36
  57. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  58. package/lib/cjs/annotations/TextAnnotationElement.d.ts +1 -1
  59. package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
  60. package/lib/cjs/annotations/TextAnnotationElement.js +25 -10
  61. package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
  62. package/lib/cjs/core-backend.d.ts +1 -0
  63. package/lib/cjs/core-backend.d.ts.map +1 -1
  64. package/lib/cjs/core-backend.js +1 -0
  65. package/lib/cjs/core-backend.js.map +1 -1
  66. package/lib/cjs/internal/IntegrityCheck.d.ts +22 -0
  67. package/lib/cjs/internal/IntegrityCheck.d.ts.map +1 -1
  68. package/lib/cjs/internal/IntegrityCheck.js +13 -0
  69. package/lib/cjs/internal/IntegrityCheck.js.map +1 -1
  70. package/lib/cjs/internal/NoReservations.d.ts +6 -0
  71. package/lib/cjs/internal/NoReservations.d.ts.map +1 -0
  72. package/lib/cjs/internal/NoReservations.js +21 -0
  73. package/lib/cjs/internal/NoReservations.js.map +1 -0
  74. package/lib/cjs/internal/SchemaSyncReservations.d.ts +4 -0
  75. package/lib/cjs/internal/SchemaSyncReservations.d.ts.map +1 -0
  76. package/lib/cjs/internal/SchemaSyncReservations.js +128 -0
  77. package/lib/cjs/internal/SchemaSyncReservations.js.map +1 -0
  78. package/lib/cjs/internal/Symbols.d.ts +1 -0
  79. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  80. package/lib/cjs/internal/Symbols.js +2 -1
  81. package/lib/cjs/internal/Symbols.js.map +1 -1
  82. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  83. package/lib/esm/BriefcaseManager.js +11 -5
  84. package/lib/esm/BriefcaseManager.js.map +1 -1
  85. package/lib/esm/Category.d.ts +4 -4
  86. package/lib/esm/Category.js.map +1 -1
  87. package/lib/esm/ChangesetECAdaptor.d.ts +5 -0
  88. package/lib/esm/ChangesetECAdaptor.d.ts.map +1 -1
  89. package/lib/esm/ChangesetECAdaptor.js +13 -3
  90. package/lib/esm/ChangesetECAdaptor.js.map +1 -1
  91. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  92. package/lib/esm/CloudSqlite.js +10 -3
  93. package/lib/esm/CloudSqlite.js.map +1 -1
  94. package/lib/esm/CodeSpecs.d.ts +3 -3
  95. package/lib/esm/CodeSpecs.js.map +1 -1
  96. package/lib/esm/DisplayStyle.d.ts +2 -2
  97. package/lib/esm/DisplayStyle.js.map +1 -1
  98. package/lib/esm/ECDb.d.ts.map +1 -1
  99. package/lib/esm/ECDb.js +1 -0
  100. package/lib/esm/ECDb.js.map +1 -1
  101. package/lib/esm/EditTxn.d.ts.map +1 -1
  102. package/lib/esm/EditTxn.js +1 -0
  103. package/lib/esm/EditTxn.js.map +1 -1
  104. package/lib/esm/Element.d.ts +48 -12
  105. package/lib/esm/Element.d.ts.map +1 -1
  106. package/lib/esm/Element.js +121 -25
  107. package/lib/esm/Element.js.map +1 -1
  108. package/lib/esm/IModelDb.d.ts +72 -22
  109. package/lib/esm/IModelDb.d.ts.map +1 -1
  110. package/lib/esm/IModelDb.js +227 -90
  111. package/lib/esm/IModelDb.js.map +1 -1
  112. package/lib/esm/Model.d.ts +5 -5
  113. package/lib/esm/Model.d.ts.map +1 -1
  114. package/lib/esm/Model.js.map +1 -1
  115. package/lib/esm/PropertyStore.js +1 -1
  116. package/lib/esm/PropertyStore.js.map +1 -1
  117. package/lib/esm/SchemaSync.d.ts +158 -22
  118. package/lib/esm/SchemaSync.d.ts.map +1 -1
  119. package/lib/esm/SchemaSync.js +419 -78
  120. package/lib/esm/SchemaSync.js.map +1 -1
  121. package/lib/esm/SynchronousChannel.d.ts +72 -0
  122. package/lib/esm/SynchronousChannel.d.ts.map +1 -0
  123. package/lib/esm/SynchronousChannel.js +9 -0
  124. package/lib/esm/SynchronousChannel.js.map +1 -0
  125. package/lib/esm/Texture.d.ts +1 -1
  126. package/lib/esm/Texture.js.map +1 -1
  127. package/lib/esm/TxnManager.d.ts +44 -4
  128. package/lib/esm/TxnManager.d.ts.map +1 -1
  129. package/lib/esm/TxnManager.js +81 -20
  130. package/lib/esm/TxnManager.js.map +1 -1
  131. package/lib/esm/ViewDefinition.d.ts +6 -6
  132. package/lib/esm/ViewDefinition.d.ts.map +1 -1
  133. package/lib/esm/ViewDefinition.js.map +1 -1
  134. package/lib/esm/annotations/LeaderGeometry.d.ts +22 -7
  135. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  136. package/lib/esm/annotations/LeaderGeometry.js +104 -36
  137. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  138. package/lib/esm/annotations/TextAnnotationElement.d.ts +1 -1
  139. package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
  140. package/lib/esm/annotations/TextAnnotationElement.js +25 -10
  141. package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
  142. package/lib/esm/core-backend.d.ts +1 -0
  143. package/lib/esm/core-backend.d.ts.map +1 -1
  144. package/lib/esm/core-backend.js +1 -0
  145. package/lib/esm/core-backend.js.map +1 -1
  146. package/lib/esm/internal/IntegrityCheck.d.ts +22 -0
  147. package/lib/esm/internal/IntegrityCheck.d.ts.map +1 -1
  148. package/lib/esm/internal/IntegrityCheck.js +13 -0
  149. package/lib/esm/internal/IntegrityCheck.js.map +1 -1
  150. package/lib/esm/internal/NoReservations.d.ts +6 -0
  151. package/lib/esm/internal/NoReservations.d.ts.map +1 -0
  152. package/lib/esm/internal/NoReservations.js +18 -0
  153. package/lib/esm/internal/NoReservations.js.map +1 -0
  154. package/lib/esm/internal/SchemaSyncReservations.d.ts +4 -0
  155. package/lib/esm/internal/SchemaSyncReservations.d.ts.map +1 -0
  156. package/lib/esm/internal/SchemaSyncReservations.js +125 -0
  157. package/lib/esm/internal/SchemaSyncReservations.js.map +1 -0
  158. package/lib/esm/internal/Symbols.d.ts +1 -0
  159. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  160. package/lib/esm/internal/Symbols.js +1 -0
  161. package/lib/esm/internal/Symbols.js.map +1 -1
  162. package/lib/esm/test/IModelTestUtils.d.ts +1 -1
  163. package/lib/esm/test/IModelTestUtils.d.ts.map +1 -1
  164. package/lib/esm/test/IModelTestUtils.js +8 -3
  165. package/lib/esm/test/IModelTestUtils.js.map +1 -1
  166. package/lib/esm/test/annotations/LeaderGeometry.test.js +178 -2
  167. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  168. package/lib/esm/test/annotations/TextAnnotation.test.js +48 -18
  169. package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
  170. package/lib/esm/test/ecdb/ECSqlStatement.test.js +177 -0
  171. package/lib/esm/test/ecdb/ECSqlStatement.test.js.map +1 -1
  172. package/lib/esm/test/ecdb/QueryReaders.test.js +2 -16
  173. package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
  174. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js +2 -2
  175. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js.map +1 -1
  176. package/lib/esm/test/element/ElementRoundTrip.test.js +80 -2
  177. package/lib/esm/test/element/ElementRoundTrip.test.js.map +1 -1
  178. package/lib/esm/test/hubaccess/Rebase.test.js +3 -1
  179. package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -1
  180. package/lib/esm/test/hubaccess/SemanticRebase.test.js +29 -28
  181. package/lib/esm/test/hubaccess/SemanticRebase.test.js.map +1 -1
  182. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts +3 -0
  183. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts.map +1 -0
  184. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js +15 -0
  185. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js.map +1 -0
  186. package/lib/esm/test/imodel/IModelECSql.test.d.ts +2 -0
  187. package/lib/esm/test/imodel/IModelECSql.test.d.ts.map +1 -0
  188. package/lib/esm/test/imodel/IModelECSql.test.js +367 -0
  189. package/lib/esm/test/imodel/IModelECSql.test.js.map +1 -0
  190. package/lib/esm/test/imodel/IModelElements.test.d.ts +2 -0
  191. package/lib/esm/test/imodel/IModelElements.test.d.ts.map +1 -0
  192. package/lib/esm/test/imodel/IModelElements.test.js +969 -0
  193. package/lib/esm/test/imodel/IModelElements.test.js.map +1 -0
  194. package/lib/esm/test/imodel/IModelGeolocation.test.d.ts +2 -0
  195. package/lib/esm/test/imodel/IModelGeolocation.test.d.ts.map +1 -0
  196. package/lib/esm/test/imodel/IModelGeolocation.test.js +539 -0
  197. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -0
  198. package/lib/esm/test/imodel/IModelLifecycle.test.d.ts +2 -0
  199. package/lib/esm/test/imodel/IModelLifecycle.test.d.ts.map +1 -0
  200. package/lib/esm/test/imodel/IModelLifecycle.test.js +499 -0
  201. package/lib/esm/test/imodel/IModelLifecycle.test.js.map +1 -0
  202. package/lib/esm/test/imodel/IModelMetadata.test.d.ts +2 -0
  203. package/lib/esm/test/imodel/IModelMetadata.test.d.ts.map +1 -0
  204. package/lib/esm/test/imodel/IModelMetadata.test.js +274 -0
  205. package/lib/esm/test/imodel/IModelMetadata.test.js.map +1 -0
  206. package/lib/esm/test/imodel/IModelModels.test.d.ts +2 -0
  207. package/lib/esm/test/imodel/IModelModels.test.d.ts.map +1 -0
  208. package/lib/esm/test/imodel/IModelModels.test.js +357 -0
  209. package/lib/esm/test/imodel/IModelModels.test.js.map +1 -0
  210. package/lib/esm/test/imodel/IModelRelationships.test.d.ts +2 -0
  211. package/lib/esm/test/imodel/IModelRelationships.test.d.ts.map +1 -0
  212. package/lib/esm/test/imodel/IModelRelationships.test.js +407 -0
  213. package/lib/esm/test/imodel/IModelRelationships.test.js.map +1 -0
  214. package/lib/esm/test/imodel/IModelTestFixtures.d.ts +53 -0
  215. package/lib/esm/test/imodel/IModelTestFixtures.d.ts.map +1 -0
  216. package/lib/esm/test/imodel/IModelTestFixtures.js +107 -0
  217. package/lib/esm/test/imodel/IModelTestFixtures.js.map +1 -0
  218. package/lib/esm/test/imodel/IModelViews.test.d.ts +2 -0
  219. package/lib/esm/test/imodel/IModelViews.test.d.ts.map +1 -0
  220. package/lib/esm/test/imodel/IModelViews.test.js +199 -0
  221. package/lib/esm/test/imodel/IModelViews.test.js.map +1 -0
  222. package/lib/esm/test/index.d.ts +0 -1
  223. package/lib/esm/test/index.d.ts.map +1 -1
  224. package/lib/esm/test/index.js +0 -1
  225. package/lib/esm/test/index.js.map +1 -1
  226. package/lib/esm/test/standalone/ChangesetReader.test.js +8 -26
  227. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  228. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts +2 -0
  229. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.d.ts.map +1 -0
  230. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js +263 -0
  231. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js.map +1 -0
  232. package/lib/esm/test/standalone/GeometryStream.test.js +1 -3
  233. package/lib/esm/test/standalone/GeometryStream.test.js.map +1 -1
  234. package/lib/esm/test/standalone/IModelWrite.test.d.ts.map +1 -1
  235. package/lib/esm/test/standalone/IModelWrite.test.js +78 -1
  236. package/lib/esm/test/standalone/IModelWrite.test.js.map +1 -1
  237. package/lib/esm/test/standalone/IntegrityCheck.test.js +29 -10
  238. package/lib/esm/test/standalone/IntegrityCheck.test.js.map +1 -1
  239. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +23 -0
  240. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -1
  241. package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts +2 -0
  242. package/lib/esm/test/standalone/SchemaSyncDb.test.d.ts.map +1 -0
  243. package/lib/esm/test/standalone/SchemaSyncDb.test.js +201 -0
  244. package/lib/esm/test/standalone/SchemaSyncDb.test.js.map +1 -0
  245. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts +2 -0
  246. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.d.ts.map +1 -0
  247. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js +460 -0
  248. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js.map +1 -0
  249. package/lib/esm/test/standalone/SnapshotDb.test.js +1 -0
  250. package/lib/esm/test/standalone/SnapshotDb.test.js.map +1 -1
  251. package/lib/esm/test/standalone/TxnManager.test.js +108 -8
  252. package/lib/esm/test/standalone/TxnManager.test.js.map +1 -1
  253. package/package.json +13 -16
  254. package/lib/esm/test/RevisionUtility.d.ts +0 -33
  255. package/lib/esm/test/RevisionUtility.d.ts.map +0 -1
  256. package/lib/esm/test/RevisionUtility.js +0 -52
  257. package/lib/esm/test/RevisionUtility.js.map +0 -1
  258. package/lib/esm/test/imodel/IModel.test.d.ts +0 -2
  259. package/lib/esm/test/imodel/IModel.test.d.ts.map +0 -1
  260. package/lib/esm/test/imodel/IModel.test.js +0 -3277
  261. package/lib/esm/test/imodel/IModel.test.js.map +0 -1
@@ -5,127 +5,462 @@
5
5
  /** @packageDocumentation
6
6
  * @module SQLiteDb
7
7
  */
8
+ import * as semver from "semver";
8
9
  import { CloudSqlite } from "./CloudSqlite";
9
10
  import { VersionedSqliteDb } from "./SQLiteDb";
10
11
  import { BriefcaseDb, IModelDb } from "./IModelDb";
11
- import { DbResult, OpenMode } from "@itwin/core-bentley";
12
- import { IModelError } from "@itwin/core-common";
12
+ import { BentleyError, ChangeSetStatus, DbResult, Guid, Id64, IModelStatus, Logger, OpenMode } from "@itwin/core-bentley";
13
+ import { BriefcaseIdValue, Code, ElementReservationError, IModelError } from "@itwin/core-common";
13
14
  import { IModelNative } from "./internal/NativePlatform";
14
15
  import { _implicitTxn, _nativeDb } from "./internal/Symbols";
15
16
  /** @internal */
16
17
  export var SchemaSync;
17
18
  (function (SchemaSync) {
18
- const lockParams = { retryDelayMs: 1000, nRetries: 30 };
19
+ /** How long a briefcase waits for another briefcase's schema import to finish before giving up.
20
+ *
21
+ * `nRetries` alone does not bound the wait: when the count runs out `CloudSqlite.withLockedDb` asks
22
+ * `onFailure` what to do, and anything other than "stop" restarts the whole cycle. Without an
23
+ * `onFailure` the caller waits forever with no way to give up, so this supplies one.
24
+ */
25
+ const lockParams = {
26
+ retryDelayMs: 6000,
27
+ nRetries: 10,
28
+ onFailure: async (lockedBy, expires) => {
29
+ Logger.logInfo("SchemaSync", `schema sync container is held by ${lockedBy} until ${expires}; giving up`);
30
+ return "stop";
31
+ },
32
+ };
33
+ const reservedElementsTableName = "reserved_elements";
34
+ const maxLocalIdExclusive = 0x10000000000; // 2^40
35
+ const idSequenceProp = { namespace: "schemasync", name: "nextReservedElementLocalId" };
19
36
  /** A CloudSqlite database for synchronizing schema changes across briefcases. */
20
37
  class SchemaSyncDb extends VersionedSqliteDb {
21
- myVersion = "4.0.0";
22
- createDDL() { }
38
+ _supportsReservations;
39
+ myVersion = "5.0.0";
40
+ createDDL() {
41
+ this.ensureReservedElementsTable();
42
+ }
43
+ openDb(dbName, openMode, container) {
44
+ super.openDb(dbName, openMode, container);
45
+ this._supportsReservations = semver.lte(this.myVersion, semver.minVersion(this.getRequiredVersions().readVersion) ?? "0.0.0");
46
+ }
47
+ ensureReservedElementsTable() {
48
+ if (this._supportsReservations)
49
+ return;
50
+ this.executeSQL(`
51
+ CREATE TABLE IF NOT EXISTS ${reservedElementsTableName} (
52
+ federationGuid BLOB PRIMARY KEY,
53
+ elementId INTEGER NOT NULL UNIQUE,
54
+ ecClassId INTEGER NOT NULL,
55
+ codeSpecId INTEGER NOT NULL,
56
+ codeScope TEXT NOT NULL,
57
+ codeValue TEXT COLLATE NOCASE
58
+ )`);
59
+ this.executeSQL(`CREATE UNIQUE INDEX IF NOT EXISTS idx_reserved_elem_code ON ${reservedElementsTableName}(codeSpecId, codeScope, codeValue)`);
60
+ const minVersion = `^${this.myVersion}`;
61
+ this.setRequiredVersions({ readVersion: minVersion, writeVersion: minVersion });
62
+ this._supportsReservations = true;
63
+ }
64
+ findReservedElement(federationGuid) {
65
+ if (!this._supportsReservations)
66
+ return undefined;
67
+ return this.withPreparedSqliteStatement(`SELECT elementId, ecClassId, codeSpecId, codeScope, codeValue FROM ${reservedElementsTableName} WHERE federationGuid=?`, (stmt) => {
68
+ stmt.bindGuid(1, federationGuid);
69
+ if (!stmt.nextRow())
70
+ return undefined;
71
+ return {
72
+ federationGuid,
73
+ elementId: stmt.getValueId(0),
74
+ ecClassId: stmt.getValueId(1),
75
+ code: new Code({
76
+ spec: stmt.getValueId(2),
77
+ scope: stmt.getValueString(3),
78
+ value: stmt.getValueStringMaybe(4),
79
+ }),
80
+ };
81
+ });
82
+ }
83
+ insertReservedElement(id, elementId) {
84
+ this.withPreparedSqliteStatement(`INSERT INTO ${reservedElementsTableName} (federationGuid, elementId, ecClassId, codeSpecId, codeScope, codeValue) VALUES (?, ?, ?, ?, ?, ?)`, (stmt) => {
85
+ stmt.bindGuid(1, id.federationGuid);
86
+ stmt.bindId(2, elementId);
87
+ stmt.bindId(3, id.ecClassId);
88
+ stmt.bindId(4, id.code.spec);
89
+ stmt.bindString(5, id.code.scope);
90
+ if (id.code.value === "")
91
+ stmt.bindNull(6);
92
+ else
93
+ stmt.bindString(6, id.code.value);
94
+ stmt.stepForWrite();
95
+ });
96
+ }
97
+ async reserveElements(elements) {
98
+ this.ensureReservedElementsTable();
99
+ // Insert new reservations as we go, so later entries in `elements` can dedupe against earlier ones
100
+ // through the shared (still-uncommitted) transaction. The caller commits on success and abandons on error.
101
+ let nextLocalId = this.getNextReservedElementLocalId();
102
+ const firstLocalId = nextLocalId;
103
+ for (const def of elements) {
104
+ if (!def.federationGuid || !Guid.isGuid(def.federationGuid)) {
105
+ ElementReservationError.throwError("invalid-reservation", {
106
+ message: "Element reservation requires an explicit, valid federationGuid",
107
+ });
108
+ }
109
+ // Identity is always the federationGuid. If a reservation already exists for it, it must match exactly.
110
+ const existing = this.findReservedElement(def.federationGuid);
111
+ if (existing) {
112
+ if (!this.existingMatches(existing, def)) {
113
+ ElementReservationError.throwError("reservation-conflict", {
114
+ message: `Element reservation conflict for federationGuid ${existing.federationGuid}: existing row does not match requested class/code`,
115
+ federationGuid: existing.federationGuid,
116
+ });
117
+ }
118
+ continue;
119
+ }
120
+ const elementId = Id64.fromLocalAndBriefcaseIds(nextLocalId, BriefcaseIdValue.SchemaSyncElementReserved);
121
+ this.insertReservedElement(def, elementId);
122
+ // skip a local id for each reserved category because category inserts always trigger a second insert for default subcategory
123
+ nextLocalId += def.isCategory ? 2 : 1;
124
+ if (nextLocalId >= maxLocalIdExclusive) {
125
+ this.abandonChanges();
126
+ ElementReservationError.throwError("id-sequence-exhausted", { message: `SchemaSync reserved-element local-id sequence exhausted` });
127
+ }
128
+ }
129
+ if (nextLocalId !== firstLocalId)
130
+ this.setNextReservedElementLocalId(nextLocalId);
131
+ }
132
+ existingMatches(existing, id) {
133
+ return existing.federationGuid === id.federationGuid
134
+ && existing.ecClassId === id.ecClassId
135
+ && existing.code.equals(id.code);
136
+ }
137
+ getNextReservedElementLocalId() {
138
+ const stored = this[_nativeDb].queryFileProperty(idSequenceProp, true);
139
+ const current = stored ? Number(stored) : 1;
140
+ if (!Number.isInteger(current) || current < 1)
141
+ ElementReservationError.throwError("corrupt-reservation-data", { message: `Corrupt SchemaSync reserved-element local-id counter: '${stored}'` });
142
+ return current;
143
+ }
144
+ setNextReservedElementLocalId(next) {
145
+ this[_nativeDb].saveFileProperty(idSequenceProp, String(next));
146
+ }
23
147
  }
24
148
  SchemaSync.SchemaSyncDb = SchemaSyncDb;
25
149
  const syncProperty = { namespace: "itwinjs", name: "SchemaSync" };
26
150
  const defaultDbName = "SchemaSyncDb";
151
+ /** The `containerType` recorded on a BlobContainer that holds an iModel's `SchemaSyncDb`. */
152
+ SchemaSync.containerType = "schema-sync";
27
153
  const testSyncCachePropKey = "test.schema_sync.cache_name";
28
154
  // for tests only
29
- SchemaSync.setTestCache = (iModel, cacheName) => {
155
+ function setTestCache(iModel, cacheName) {
30
156
  if (cacheName)
31
157
  iModel[_nativeDb].saveLocalValue(testSyncCachePropKey, cacheName);
32
158
  else
33
159
  iModel[_nativeDb].deleteLocalValue(testSyncCachePropKey);
34
- };
35
- const getCloudAccess = async (arg) => {
36
- let nativeDb;
37
- const argIsIModelDb = arg instanceof IModelDb;
38
- if (argIsIModelDb) {
39
- nativeDb = arg[_nativeDb];
40
- }
41
- else {
42
- nativeDb = new IModelNative.platform.DgnDb();
43
- nativeDb.openIModel(arg.fileName, OpenMode.Readonly);
44
- }
45
- const propsString = nativeDb.queryFileProperty(syncProperty, true);
46
- if (!propsString)
47
- throw new Error("iModel does not have a SchemaSyncDb");
160
+ }
161
+ SchemaSync.setTestCache = setTestCache;
162
+ /** Read from an open iModel, or from a closed file opened readonly for the duration of `operation`. */
163
+ function readFromIModel(arg, operation) {
164
+ if (arg instanceof IModelDb)
165
+ return operation(arg[_nativeDb]);
166
+ const nativeDb = new IModelNative.platform.DgnDb();
167
+ nativeDb.openIModel(arg.fileName, OpenMode.Readonly);
48
168
  try {
49
- const props = JSON.parse(propsString);
50
- const accessToken = await CloudSqlite.requestToken(props);
51
- const access = new CloudAccess({ ...props, accessToken });
52
- Object.assign(access.lockParams, lockParams);
53
- const testSyncCache = nativeDb.queryLocalValue(testSyncCachePropKey);
54
- if (testSyncCache)
55
- access.setCache(CloudSqlite.CloudCaches.getCache({ cacheName: testSyncCache }));
56
- return access;
169
+ return operation(nativeDb);
57
170
  }
58
171
  finally {
59
- if (!argIsIModelDb) {
60
- nativeDb.closeFile();
172
+ nativeDb.closeFile();
173
+ }
174
+ }
175
+ /** Whether this iModel's ECSchemas are governed by a `SchemaSyncDb`.
176
+ *
177
+ * This is the single question every schema operation branches on. It reads one `be_Prop` row written when
178
+ * schema sync was enabled and carried to every other briefcase by that changeset - no cloud access, and it
179
+ * works on a readonly briefcase, a checkpoint, or a closed file.
180
+ * @note This says nothing about whether the container is reachable, or even named. Use
181
+ * [[queryContainerProps]] for that. The two are separate on purpose: a file that says it is governed by a
182
+ * sync db must never fall back to importing schemas on its own, whatever state the container is in.
183
+ */
184
+ function isEnabled(arg) {
185
+ return readFromIModel(arg, (nativeDb) => nativeDb.schemaSyncEnabled());
186
+ }
187
+ SchemaSync.isEnabled = isEnabled;
188
+ /** One pass over the values schema sync keeps in the file: which container holds the sync db, plus the
189
+ * test-only cache override. Read together so a closed file is opened once.
190
+ */
191
+ function readLocalSyncProps(arg) {
192
+ return readFromIModel(arg, (nativeDb) => {
193
+ const propsString = nativeDb.queryFileProperty(syncProperty, true);
194
+ let containerProps;
195
+ if (propsString !== undefined) {
196
+ try {
197
+ containerProps = JSON.parse(propsString);
198
+ }
199
+ catch (e) {
200
+ // Deliberately not swallowed into `undefined`: that would read as "schema sync was never
201
+ // enabled" and let this briefcase import schemas on its own.
202
+ throw new IModelError(DbResult.BE_SQLITE_CORRUPT, `iModel names a SchemaSyncDb container but the property cannot be read: ${BentleyError.getErrorMessage(e)}`);
203
+ }
204
+ }
205
+ return {
206
+ containerProps,
207
+ testCacheName: nativeDb.queryLocalValue(testSyncCachePropKey),
208
+ };
209
+ });
210
+ }
211
+ /** The container holding this iModel's `SchemaSyncDb`, or `undefined` if schema sync was never enabled.
212
+ *
213
+ * Local read of the same `be_Prop` file property that [[initializeForIModel]] wrote. Requesting an access
214
+ * token for the container is a separate, asynchronous step.
215
+ */
216
+ function queryContainerProps(arg) {
217
+ return readLocalSyncProps(arg).containerProps;
218
+ }
219
+ SchemaSync.queryContainerProps = queryContainerProps;
220
+ const sharedAccessByContainer = new Map();
221
+ const sharedAccessByInstance = new WeakMap();
222
+ async function getCloudAccess(arg) {
223
+ const { containerProps, testCacheName } = readLocalSyncProps(arg);
224
+ if (undefined === containerProps)
225
+ throw new IModelError(DbResult.BE_SQLITE_NOTFOUND, "iModel does not have a SchemaSyncDb");
226
+ const sharedAccessKey = JSON.stringify(containerProps) + (testCacheName ?? "");
227
+ let shared = sharedAccessByContainer.get(sharedAccessKey);
228
+ if (undefined === shared) {
229
+ const pending = (async () => {
230
+ const accessToken = await CloudSqlite.requestToken(containerProps);
231
+ const access = new CloudAccess({ ...containerProps, accessToken });
232
+ Object.assign(access.lockParams, lockParams);
233
+ if (testCacheName)
234
+ access.setCache(CloudSqlite.CloudCaches.getCache({ cacheName: testCacheName }));
235
+ const created = { access, key: sharedAccessKey, referenceCount: 0 };
236
+ sharedAccessByInstance.set(access, created);
237
+ return created;
238
+ })();
239
+ sharedAccessByContainer.set(sharedAccessKey, pending);
240
+ try {
241
+ shared = await pending;
242
+ if (sharedAccessByContainer.get(sharedAccessKey) === pending)
243
+ sharedAccessByContainer.set(sharedAccessKey, shared);
244
+ }
245
+ catch (error) {
246
+ if (sharedAccessByContainer.get(sharedAccessKey) === pending)
247
+ sharedAccessByContainer.delete(sharedAccessKey);
248
+ throw error;
61
249
  }
62
250
  }
63
- };
64
- SchemaSync.withLockedAccess = async (iModel, args, operation) => {
65
- const access = await getCloudAccess(iModel);
66
- try {
67
- await access.withLockedDb(args, async () => operation(access));
251
+ else if (shared instanceof Promise) {
252
+ shared = await shared;
68
253
  }
69
- finally {
254
+ ++shared.referenceCount;
255
+ return shared.access;
256
+ }
257
+ SchemaSync.getCloudAccess = getCloudAccess;
258
+ /** Release an access obtained through [[getCloudAccess]]. */
259
+ function releaseCloudAccess(access) {
260
+ const shared = sharedAccessByInstance.get(access);
261
+ if (undefined === shared) {
70
262
  access.close();
263
+ return;
71
264
  }
72
- };
73
- SchemaSync.withReadonlyAccess = async (iModel, operation) => {
74
- const access = await getCloudAccess(iModel);
75
- access.synchronizeWithCloud();
76
- access.openForRead();
265
+ if (--shared.referenceCount > 0)
266
+ return;
267
+ sharedAccessByInstance.delete(access);
268
+ if (sharedAccessByContainer.get(shared.key) === shared)
269
+ sharedAccessByContainer.delete(shared.key);
270
+ access.close();
271
+ }
272
+ SchemaSync.releaseCloudAccess = releaseCloudAccess;
273
+ async function withLockedAccess(iModel, args, operation) {
274
+ const access = await SchemaSync.getCloudAccess(iModel);
77
275
  try {
78
- await operation(access);
276
+ await access.withLockedDb(args, async () => operation(access));
79
277
  }
80
278
  finally {
81
- access.close();
279
+ releaseCloudAccess(access);
82
280
  }
83
- };
84
- SchemaSync.isEnabled = (iModel) => {
85
- return iModel[_nativeDb].schemaSyncEnabled();
86
- };
87
- /** Synchronize local briefcase schemas with cloud container */
88
- SchemaSync.pull = async (iModel) => {
89
- if (iModel[_nativeDb].schemaSyncEnabled() && !iModel.isReadonly) {
90
- await SchemaSync.withReadonlyAccess(iModel, async (syncAccess) => {
91
- const schemaSyncDbUri = syncAccess.getUri();
92
- iModel.clearCaches();
93
- iModel[_nativeDb].schemaSyncPull(schemaSyncDbUri);
94
- iModel[_implicitTxn].saveChanges("schema synchronized with cloud container");
95
- });
281
+ }
282
+ SchemaSync.withLockedAccess = withLockedAccess;
283
+ /** Build the tables and indexes the briefcase's `ec_` rows describe. A merged schema changeset carries
284
+ * those rows but no DDL, so the physical columns are missing until this runs. Needs no cloud access.
285
+ */
286
+ function updateDbSchema(iModel) {
287
+ if (isEnabled(iModel) && !iModel.isReadonly) {
288
+ iModel.clearCaches();
289
+ iModel[_nativeDb].schemaSyncUpdateDbSchema();
290
+ iModel[_implicitTxn].saveChanges("materialized db schema from ec_ tables");
96
291
  }
97
- };
98
- SchemaSync.initializeForIModel = async (arg) => {
99
- const props = { baseUri: arg.containerProps.baseUri, containerId: arg.containerProps.containerId, storageType: arg.containerProps.storageType }; // sanitize to only known properties
292
+ }
293
+ SchemaSync.updateDbSchema = updateDbSchema;
294
+ /** Whether a failed [[IModelDb.importSchemas]] can be retried through the upgrade path.
295
+ *
296
+ * The update tier refuses two kinds of change: one that has to move data between columns, and one
297
+ * that destroys instances or property values. They arrive as different statuses because they are
298
+ * different changes, but they mean one thing to a caller - this needs
299
+ * [[BriefcaseDb.upgradeSchemas]], which takes the exclusive schema lock.
300
+ *
301
+ * The retry is the app's decision, not the platform's: taking that lock disturbs everyone else, so
302
+ * only the app knows whether to do it now, schedule it, or tell the user.
303
+ * ```ts
304
+ * try {
305
+ * await db.importSchemas(files);
306
+ * } catch (e) {
307
+ * if (!SchemaSync.requiresUpgrade(e)) throw e;
308
+ * await db.upgradeSchemas(files, { description: "..." });
309
+ * }
310
+ * ```
311
+ * @internal
312
+ */
313
+ function requiresUpgrade(error) {
314
+ const errorNumber = error?.errorNumber;
315
+ return errorNumber === DbResult.BE_SQLITE_ERROR_DataTransformRequired
316
+ || errorNumber === DbResult.BE_SQLITE_ERROR_DataDeletionRequired;
317
+ }
318
+ SchemaSync.requiresUpgrade = requiresUpgrade;
319
+ /** Create a cloud container to hold this iModel's `SchemaSyncDb`, and initialize it as empty.
320
+ *
321
+ * The container is scoped to the iModel, so the service deletes it when the iModel is deleted. Pass the
322
+ * returned props to [[initializeForIModel]] - the two calls together are what enables schema sync on an
323
+ * iModel that was created without it.
324
+ * @note The current user must be authorized to create containers for the iTwin.
325
+ */
326
+ async function createContainerForIModel(arg) {
100
327
  const iModel = arg.iModel;
328
+ const iTwinId = iModel.iTwinId;
329
+ if (undefined === iTwinId)
330
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot create a SchemaSync container for an iModel that has no iTwin");
331
+ return CloudAccess.createNewContainer({
332
+ scope: { iTwinId, iModelId: iModel.iModelId },
333
+ metadata: { label: arg.label ?? `SchemaSync for ${iModel.name}`, description: arg.description },
334
+ });
335
+ }
336
+ SchemaSync.createContainerForIModel = createContainerForIModel;
337
+ /** Refuse initialization before a caller provisions a container, then hold the exclusive schema lock and pull to the tip. */
338
+ async function prepareToInitializeForIModel(iModel, overrideContainer) {
101
339
  const briefcase = iModel instanceof BriefcaseDb ? iModel : undefined;
340
+ if (briefcase && !briefcase.locks.isServerBased)
341
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot enable SchemaSync without server-based locking");
342
+ if (briefcase && (iModel[_nativeDb].hasUnsavedChanges() || briefcase.txns.hasLocalChanges))
343
+ throw new IModelError(ChangeSetStatus.HasLocalChanges, "Cannot enable SchemaSync while there are local changes");
344
+ const assertContainerCanBeInitialized = () => {
345
+ const localInfo = iModel[_nativeDb].schemaSyncGetLocalDbInfo();
346
+ if (localInfo && !overrideContainer)
347
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, `Local db already initialized to schema sync (container-id: ${localInfo.id})`);
348
+ };
349
+ assertContainerCanBeInitialized();
102
350
  await iModel.acquireSchemaLock();
103
- if (briefcase) {
104
- if (briefcase.txns.hasLocalChanges) {
105
- throw new IModelError(DbResult.BE_SQLITE_ERROR, "Enabling SchemaSync for iModel failed. There are unsaved or un-pushed local changes.");
106
- }
107
- await briefcase.pullChanges();
108
- }
351
+ await briefcase?.pullChanges();
352
+ assertContainerCanBeInitialized();
353
+ return briefcase;
354
+ }
355
+ async function initializeAfterPreflight(arg, briefcase) {
356
+ const props = { baseUri: arg.containerProps.baseUri, containerId: arg.containerProps.containerId, storageType: arg.containerProps.storageType }; // sanitize to only known properties
357
+ const iModel = arg.iModel;
358
+ const description = arg.overrideContainer
359
+ ? `Overriding SchemaSync for iModel with container-id: ${props.containerId}`
360
+ : `Enable SchemaSync for iModel with container-id: ${props.containerId}`;
361
+ const txnBeforeInit = briefcase?.txns.getCurrentTxnId();
109
362
  try {
110
363
  iModel[_implicitTxn].saveFileProperty(syncProperty, JSON.stringify(props));
111
- await SchemaSync.withLockedAccess(arg.iModel, { operationName: "initialize schemaSync", openMode: OpenMode.Readonly }, async (syncAccess) => {
112
- iModel[_nativeDb].schemaSyncInit(syncAccess.getUri(), props.containerId, arg.overrideContainer ?? false);
113
- iModel[_implicitTxn].saveChanges(`Enable SchemaSync (container id: ${props.containerId})`);
114
- });
115
- }
116
- catch (err) {
117
- throw err;
364
+ try {
365
+ await withLockedAccess(iModel, { operationName: "initialize schemaSync", openMode: OpenMode.Readonly }, async (syncAccess) => {
366
+ iModel[_nativeDb].schemaSyncInit(syncAccess.getUri(), props.containerId, arg.overrideContainer ?? false);
367
+ iModel[_implicitTxn].saveChanges(description);
368
+ });
369
+ }
370
+ catch (error) {
371
+ iModel[_implicitTxn].abandonChanges();
372
+ if (briefcase && txnBeforeInit !== undefined && briefcase.txns.getCurrentTxnId() !== txnBeforeInit) {
373
+ const status = briefcase[_nativeDb].cancelTo(txnBeforeInit, true);
374
+ if (status !== IModelStatus.Success)
375
+ Logger.logError("SchemaSync", `Failed to roll back schema sync initialization after the container upload failed: ${IModelStatus[status] ?? status}`);
376
+ }
377
+ throw error;
378
+ }
379
+ // Upload the initialized container before publishing the property that tells every briefcase to use it.
380
+ // If the push fails, this briefcase keeps the local txn and exclusive schema lock so the push can be retried.
381
+ await briefcase?.pushChanges({ description });
118
382
  }
119
383
  finally {
120
384
  iModel[_implicitTxn].abandonChanges();
121
385
  }
122
- if (briefcase) {
123
- if (arg.overrideContainer)
124
- await briefcase.pushChanges({ description: `Overriding SchemaSync for iModel with container-id: ${props.containerId}` });
125
- else
126
- await briefcase.pushChanges({ description: `Enable SchemaSync for iModel with container-id: ${props.containerId}` });
127
- }
386
+ await iModel.initializeSharedElementReservations();
387
+ }
388
+ /** Enable schema sync for an iModel, seeding the container from this briefcase.
389
+ * @note Takes the exclusive schema lock, refuses local changes, and pulls the briefcase to the tip before writing the container.
390
+ * If this operation fails after acquiring the schema lock, it leaves the lock held.
391
+ */
392
+ async function initializeForIModel(arg) {
393
+ const briefcase = await prepareToInitializeForIModel(arg.iModel, arg.overrideContainer ?? false);
394
+ await initializeAfterPreflight(arg, briefcase);
395
+ }
396
+ SchemaSync.initializeForIModel = initializeForIModel;
397
+ const nativeRepairScope = {
398
+ schemaMetadata: 0,
399
+ schemaMetadataAndProfile: 1,
128
400
  };
401
+ /** Restore the schema-owned portion of the SchemaSyncDb from a briefcase at the tip of the timeline.
402
+ *
403
+ * This operation takes the exclusive schema lock and refuses to pull or modify the briefcase. Element
404
+ * reservations and all other target-only state in the SchemaSyncDb are preserved.
405
+ * @alpha
406
+ */
407
+ async function repairForIModel(arg) {
408
+ const iModel = arg.iModel;
409
+ if (!isEnabled(iModel))
410
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot repair SchemaSync because it is not enabled for this iModel");
411
+ if (iModel[_nativeDb].hasUnsavedChanges() || iModel.txns.hasLocalChanges)
412
+ throw new IModelError(ChangeSetStatus.HasLocalChanges, "Cannot repair SchemaSync while there are local changes");
413
+ if (!iModel.locks.isServerBased)
414
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot repair SchemaSync without server-based locking");
415
+ if (arg.scope !== undefined && arg.scope !== "schemaMetadata" && arg.scope !== "schemaMetadataAndProfile")
416
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Unknown SchemaSync repair scope");
417
+ const briefcaseManagerModule = await import("./BriefcaseManager");
418
+ const assertBriefcaseIsAtTip = async () => {
419
+ const latestChangeset = await briefcaseManagerModule.BriefcaseManager.getLatestChangeset({ iModelId: iModel.iModelId });
420
+ if (latestChangeset.id !== iModel.changeset.id)
421
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot repair SchemaSync from a briefcase that is not at the tip of the iModel timeline");
422
+ };
423
+ // Avoid asking Hub for an exclusive lock it cannot grant to a briefcase that first needs to pull.
424
+ await assertBriefcaseIsAtTip();
425
+ const schemaLockWasHeld = iModel.holdsSchemaLock;
426
+ if (!schemaLockWasHeld)
427
+ await iModel.acquireSchemaLock();
428
+ try {
429
+ // Close the race between the preflight query and acquiring the exclusive lock.
430
+ await assertBriefcaseIsAtTip();
431
+ const repairScope = nativeRepairScope[arg.scope ?? "schemaMetadata"];
432
+ await withLockedAccess(iModel, { openMode: OpenMode.Readonly, operationName: "repair schema sync" }, async (syncAccess) => {
433
+ const nativeDb = iModel[_nativeDb];
434
+ nativeDb.schemaSyncRepair(syncAccess.getUri(), repairScope);
435
+ });
436
+ Logger.logInfo("SchemaSync", `Repaired SchemaSyncDb from changeset ${iModel.changeset.id || "0"}`);
437
+ }
438
+ finally {
439
+ if (!schemaLockWasHeld)
440
+ await iModel.locks.abandonAllLocks();
441
+ }
442
+ }
443
+ SchemaSync.repairForIModel = repairForIModel;
444
+ /** Turn schema sync on for an iModel: create the container if needed, record it, and seed it.
445
+ *
446
+ * The single call callers should use. [[createContainerForIModel]] and [[initializeForIModel]] have
447
+ * to happen in this order, and an iModel left between the two is one that names a container nothing
448
+ * has seeded.
449
+ * @returns the container props recorded on the iModel.
450
+ * @note Takes the exclusive schema lock and pushes, same protocol as [[BriefcaseDb.upgradeSchemas]] -
451
+ * every operation that changes how a file is governed uses it. If this operation fails after acquiring the schema lock,
452
+ * it leaves the lock held.
453
+ */
454
+ async function enableForIModel(arg) {
455
+ if (undefined === arg.containerProps && undefined === arg.iModel.iTwinId)
456
+ throw new IModelError(DbResult.BE_SQLITE_ERROR, "Cannot create a SchemaSync container for an iModel that has no iTwin");
457
+ const briefcase = await prepareToInitializeForIModel(arg.iModel, arg.overrideContainer ?? false);
458
+ const containerProps = arg.containerProps
459
+ ?? await createContainerForIModel({ iModel: arg.iModel, label: arg.label, description: arg.description });
460
+ await initializeAfterPreflight({ iModel: arg.iModel, containerProps, overrideContainer: arg.overrideContainer }, briefcase);
461
+ return containerProps;
462
+ }
463
+ SchemaSync.enableForIModel = enableForIModel;
129
464
  /** Provides access to a cloud-based `SchemaSyncDb` to hold ECSchemas. */
130
465
  class CloudAccess extends CloudSqlite.DbAccess {
131
466
  constructor(props) {
@@ -142,6 +477,12 @@ export var SchemaSync;
142
477
  static async initializeDb(props) {
143
478
  return super._initializeDb({ props, dbType: SchemaSyncDb, dbName: defaultDbName });
144
479
  }
480
+ /** Create and initialize a new `schema-sync` BlobContainer to hold a `SchemaSyncDb`. */
481
+ static async createNewContainer(args) {
482
+ const props = await this.createBlobContainer({ scope: args.scope, metadata: { ...args.metadata, containerType: SchemaSync.containerType } });
483
+ await this.initializeDb(props);
484
+ return props;
485
+ }
145
486
  }
146
487
  SchemaSync.CloudAccess = CloudAccess;
147
488
  })(SchemaSync || (SchemaSync = {}));