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