@itwin/core-backend 5.14.0-dev.2 → 5.14.0-dev.4

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 (59) hide show
  1. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  2. package/lib/cjs/BriefcaseManager.js +11 -5
  3. package/lib/cjs/BriefcaseManager.js.map +1 -1
  4. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  5. package/lib/cjs/CloudSqlite.js +9 -2
  6. package/lib/cjs/CloudSqlite.js.map +1 -1
  7. package/lib/cjs/ECDb.d.ts.map +1 -1
  8. package/lib/cjs/ECDb.js +1 -0
  9. package/lib/cjs/ECDb.js.map +1 -1
  10. package/lib/cjs/IModelDb.d.ts +42 -7
  11. package/lib/cjs/IModelDb.d.ts.map +1 -1
  12. package/lib/cjs/IModelDb.js +175 -74
  13. package/lib/cjs/IModelDb.js.map +1 -1
  14. package/lib/cjs/SchemaSync.d.ts +126 -18
  15. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  16. package/lib/cjs/SchemaSync.js +303 -81
  17. package/lib/cjs/SchemaSync.js.map +1 -1
  18. package/lib/cjs/TxnManager.d.ts.map +1 -1
  19. package/lib/cjs/TxnManager.js +2 -5
  20. package/lib/cjs/TxnManager.js.map +1 -1
  21. package/lib/cjs/internal/SchemaSyncReservations.d.ts.map +1 -1
  22. package/lib/cjs/internal/SchemaSyncReservations.js +13 -3
  23. package/lib/cjs/internal/SchemaSyncReservations.js.map +1 -1
  24. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  25. package/lib/esm/BriefcaseManager.js +11 -5
  26. package/lib/esm/BriefcaseManager.js.map +1 -1
  27. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  28. package/lib/esm/CloudSqlite.js +10 -3
  29. package/lib/esm/CloudSqlite.js.map +1 -1
  30. package/lib/esm/ECDb.d.ts.map +1 -1
  31. package/lib/esm/ECDb.js +1 -0
  32. package/lib/esm/ECDb.js.map +1 -1
  33. package/lib/esm/IModelDb.d.ts +42 -7
  34. package/lib/esm/IModelDb.d.ts.map +1 -1
  35. package/lib/esm/IModelDb.js +175 -74
  36. package/lib/esm/IModelDb.js.map +1 -1
  37. package/lib/esm/SchemaSync.d.ts +126 -18
  38. package/lib/esm/SchemaSync.d.ts.map +1 -1
  39. package/lib/esm/SchemaSync.js +304 -82
  40. package/lib/esm/SchemaSync.js.map +1 -1
  41. package/lib/esm/TxnManager.d.ts.map +1 -1
  42. package/lib/esm/TxnManager.js +2 -5
  43. package/lib/esm/TxnManager.js.map +1 -1
  44. package/lib/esm/internal/SchemaSyncReservations.d.ts.map +1 -1
  45. package/lib/esm/internal/SchemaSyncReservations.js +13 -3
  46. package/lib/esm/internal/SchemaSyncReservations.js.map +1 -1
  47. package/lib/esm/test/hubaccess/Rebase.test.js +3 -1
  48. package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -1
  49. package/lib/esm/test/hubaccess/SemanticRebase.test.js +29 -28
  50. package/lib/esm/test/hubaccess/SemanticRebase.test.js.map +1 -1
  51. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts +3 -0
  52. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts.map +1 -0
  53. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js +15 -0
  54. package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js.map +1 -0
  55. package/lib/esm/test/standalone/SchemaSyncDb.test.js +5 -25
  56. package/lib/esm/test/standalone/SchemaSyncDb.test.js.map +1 -1
  57. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js +1 -0
  58. package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js.map +1 -1
  59. package/package.json +13 -13
@@ -320,7 +320,9 @@ class IModelDb extends core_common_1.IModel {
320
320
  db[Symbols_1._nativeDb].abandonChanges();
321
321
  db.close();
322
322
  }
323
- catch { }
323
+ catch {
324
+ return;
325
+ }
324
326
  });
325
327
  });
326
328
  }
@@ -386,12 +388,20 @@ class IModelDb extends core_common_1.IModel {
386
388
  this._codeService = undefined;
387
389
  this[Symbols_1._nativeDb].closeFile();
388
390
  }
391
+ /**
392
+ * Save any unsaved schema changes in this iModel.
393
+ * @internal
394
+ */
389
395
  saveSchemaChanges(args) {
390
396
  if (!this[Symbols_1._nativeDb].hasUnsavedChanges())
391
397
  return;
392
398
  const saveArgs = typeof args === "string" ? { description: args } : args;
393
399
  saveArgs === undefined ? this[Symbols_1._nativeDb].saveChanges() : this[Symbols_1._nativeDb].saveChanges(JSON.stringify(saveArgs));
394
400
  }
401
+ /**
402
+ * Abandon any unsaved schema changes in this iModel.
403
+ * @internal
404
+ */
395
405
  abandonSchemaChanges() {
396
406
  if (!this[Symbols_1._nativeDb].hasUnsavedChanges())
397
407
  return;
@@ -938,7 +948,7 @@ class IModelDb extends core_common_1.IModel {
938
948
  async dropSchemas(schemaNames) {
939
949
  if (schemaNames.length === 0)
940
950
  return;
941
- if (this[Symbols_1._nativeDb].schemaSyncEnabled())
951
+ if (SchemaSync_1.SchemaSync.isEnabled(this))
942
952
  throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot drop schemas when schema sync is enabled");
943
953
  if (this[Symbols_1._nativeDb].hasUnsavedChanges())
944
954
  throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasUncommittedChanges, "Cannot drop schemas with unsaved changes");
@@ -1024,26 +1034,34 @@ class IModelDb extends core_common_1.IModel {
1024
1034
  this.cleanupSnapshot(context.resources);
1025
1035
  }
1026
1036
  }
1027
- /** Shared implementation for importing schemas from file or string. */
1028
- async importSchemasInternal(schemas, options, nativeImportOp) {
1029
- // BriefcaseDb-specific validation checks
1030
- if (this.isBriefcaseDb()) {
1031
- if (this.txns.rebaser.isRebasing) {
1032
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while rebasing");
1033
- }
1034
- if (this.txns.isIndirectChanges) {
1035
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while in an indirect change scope");
1036
- }
1037
- // Additional checks when semantic rebase is enabled
1038
- if (IModelHost_1.IModelHost.useSemanticRebase) {
1039
- if (this[Symbols_1._nativeDb].hasUnsavedChanges()) {
1040
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas with unsaved changes when useSemanticRebase flag is on");
1041
- }
1042
- if (this[Symbols_1._nativeDb].schemaSyncEnabled()) {
1043
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas when schema sync is enabled and also useSemanticRebase flag is on");
1044
- }
1037
+ /** Refuse a schema import this briefcase is in no state to run. Shared by [[importSchemas]] and
1038
+ * [[BriefcaseDb.upgradeSchemas]], which reach the native importer by different routes.
1039
+ * @internal
1040
+ */
1041
+ assertCanImportSchemas() {
1042
+ if (!this.isBriefcaseDb())
1043
+ return;
1044
+ if (this.txns.rebaser.isRebasing) {
1045
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while rebasing");
1046
+ }
1047
+ if (this.txns.isIndirectChanges) {
1048
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while in an indirect change scope");
1049
+ }
1050
+ // Additional checks when semantic rebase is enabled
1051
+ if (IModelHost_1.IModelHost.useSemanticRebase) {
1052
+ if (this[Symbols_1._nativeDb].hasUnsavedChanges()) {
1053
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas with unsaved changes when useSemanticRebase flag is on");
1054
+ }
1055
+ if (SchemaSync_1.SchemaSync.isEnabled(this)) {
1056
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas when schema sync is enabled and also useSemanticRebase flag is on");
1045
1057
  }
1046
1058
  }
1059
+ }
1060
+ /** Shared implementation for importing schemas from file or string.
1061
+ * @internal
1062
+ */
1063
+ async importSchemasInternal(schemas, options, nativeImportOp) {
1064
+ this.assertCanImportSchemas();
1047
1065
  if (options?.channelUpgrade) {
1048
1066
  const channelUpgrade = options.channelUpgrade;
1049
1067
  try {
@@ -1061,30 +1079,52 @@ class IModelDb extends core_common_1.IModel {
1061
1079
  if (options?.schemaImportCallbacks?.preSchemaImportCallback)
1062
1080
  preSchemaImportCallbackResult = await this.preSchemaImportCallback(options.schemaImportCallbacks, { iModel: this, data: options.data, schemaData: schemas });
1063
1081
  const maybeCustomNativeContext = options?.ecSchemaXmlContext?.nativeContext;
1064
- if (this[Symbols_1._nativeDb].schemaSyncEnabled()) {
1065
- await SchemaSync_1.SchemaSync.withLockedAccess(this, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
1066
- const schemaSyncDbUri = syncAccess.getUri();
1067
- this.saveSchemaChanges();
1068
- try {
1069
- nativeImportOp(schemas, { schemaLockHeld: false, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
1070
- }
1071
- catch (outerErr) {
1072
- if (core_bentley_1.DbResult.BE_SQLITE_ERROR_DataTransformRequired === outerErr.errorNumber) {
1073
- this.abandonSchemaChanges();
1074
- if (this[Symbols_1._nativeDb].getITwinId() !== core_bentley_1.Guid.empty)
1075
- await this.acquireSchemaLock();
1076
- try {
1077
- nativeImportOp(schemas, { schemaLockHeld: true, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
1078
- }
1079
- catch (innerErr) {
1080
- throw new core_common_1.IModelError(innerErr.errorNumber, innerErr.message);
1081
- }
1082
+ if (SchemaSync_1.SchemaSync.isEnabled(this)) {
1083
+ // The shared lock lets concurrent updates through while blocking anyone taking the exclusive lock for an upgrade.
1084
+ if (this[Symbols_1._nativeDb].getITwinId() !== core_bentley_1.Guid.empty)
1085
+ await this.locks.acquireLocks({ shared: core_common_1.IModel.repositoryModelId });
1086
+ // The native import adopts rows from the attached SchemaSyncDb. Attach and detach commit
1087
+ // implicitly, so abandoning changes cannot undo the adoption. A later failure must roll the
1088
+ // briefcase back before those ec_ rows can be pushed.
1089
+ let txnBeforeAdopt;
1090
+ // Set once the caller's own work is committed. Getting a token or the container write lock happens
1091
+ // before that, and abandonSchemaChanges discards every unsaved change rather than only this import's,
1092
+ // so abandoning on a failure from that window would throw away work the import never touched.
1093
+ let callerChangesSaved = false;
1094
+ try {
1095
+ await SchemaSync_1.SchemaSync.withLockedAccess(this, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
1096
+ const schemaSyncDbUri = syncAccess.getUri();
1097
+ this.saveSchemaChanges();
1098
+ callerChangesSaved = true;
1099
+ // After saveSchemaChanges, so rolling back cannot reach the caller's own work.
1100
+ if (this.isBriefcaseDb())
1101
+ txnBeforeAdopt = this.txns.getCurrentTxnId();
1102
+ try {
1103
+ nativeImportOp(schemas, { schemaLockHeld: false, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
1082
1104
  }
1083
- else {
1084
- throw new core_common_1.IModelError(outerErr.errorNumber, outerErr.message);
1105
+ catch (err) {
1106
+ if (SchemaSync_1.SchemaSync.requiresUpgrade(err))
1107
+ throw new core_common_1.IModelError(err.errorNumber, `${err.message} - this schema change needs the upgrade path. Use BriefcaseDb.upgradeSchemas, which takes the exclusive schema lock and pushes the result.`);
1108
+ throw new core_common_1.IModelError(err.errorNumber, err.message);
1085
1109
  }
1110
+ });
1111
+ }
1112
+ catch (err) {
1113
+ if (callerChangesSaved)
1114
+ this.abandonSchemaChanges();
1115
+ if (this.isBriefcaseDb() && undefined !== txnBeforeAdopt && this.txns.getCurrentTxnId() !== txnBeforeAdopt) {
1116
+ // Saving the adopt's txn started a new undo session, because schema changes are kept out of the
1117
+ // user's undo stack, so this reverses across that boundary. The changes themselves reverse like
1118
+ // any other - a rebase does it to every local txn on every pull. It does not reverse DDL: a table
1119
+ // or column the adopt created stays behind with no ec_ row describing it, which is the state a
1120
+ // briefcase already tolerates, and the next successful import finds the table up to date and
1121
+ // carries on. Cancel rather than reverse, so the rows cannot come back through undo either.
1122
+ const status = this[Symbols_1._nativeDb].cancelTo(txnBeforeAdopt, true);
1123
+ if (core_bentley_1.IModelStatus.Success !== status)
1124
+ core_bentley_1.Logger.logError(loggerCategory, `Failed to roll back the adopted schema rows after a failed import: ${core_bentley_1.IModelStatus[status] ?? status}`);
1086
1125
  }
1087
- });
1126
+ throw err;
1127
+ }
1088
1128
  }
1089
1129
  else {
1090
1130
  const nativeImportOptions = {
@@ -2850,7 +2890,9 @@ function processSchemaWriteStatus(status) {
2850
2890
  try {
2851
2891
  props.push(imodel.elements.getElementProps(id));
2852
2892
  }
2853
- catch { }
2893
+ catch {
2894
+ return;
2895
+ }
2854
2896
  });
2855
2897
  return props;
2856
2898
  }
@@ -2873,7 +2915,9 @@ function processSchemaWriteStatus(status) {
2873
2915
  break;
2874
2916
  }
2875
2917
  }
2876
- catch { }
2918
+ catch {
2919
+ continue;
2920
+ }
2877
2921
  }
2878
2922
  return finished;
2879
2923
  }
@@ -3083,9 +3127,6 @@ class BriefcaseDb extends IModelDb {
3083
3127
  get isBriefcase() { return true; }
3084
3128
  /* the BriefcaseId of the briefcase opened with this BriefcaseDb */
3085
3129
  briefcaseId;
3086
- _skipSyncSchemasOnPullAndPush;
3087
- /** @internal */
3088
- get skipSyncSchemasOnPullAndPush() { return this._skipSyncSchemasOnPullAndPush ?? false; }
3089
3130
  /**
3090
3131
  * Event raised just before a BriefcaseDb is opened. Supplies the arguments that will be used to open the BriefcaseDb.
3091
3132
  * Throw an exception to stop the open.
@@ -3168,6 +3209,8 @@ class BriefcaseDb extends IModelDb {
3168
3209
  }
3169
3210
  constructor(args) {
3170
3211
  super({ ...args, changeset: args.nativeDb.getCurrentChangeset() });
3212
+ // Native invokes this private callback dynamically through the object registered by IModelDb.
3213
+ void this.onChangesetConflict;
3171
3214
  this._openMode = args.openMode;
3172
3215
  this.briefcaseId = args.briefcaseId;
3173
3216
  this.makeLockControl();
@@ -3180,26 +3223,33 @@ class BriefcaseDb extends IModelDb {
3180
3223
  wasChanges = nativeDb.hasPendingTxns();
3181
3224
  nativeDb.closeFile();
3182
3225
  };
3183
- const isSchemaSyncEnabled = await withBriefcaseDb(briefcase, async (db) => {
3184
- await SchemaSync_1.SchemaSync.pull(db);
3185
- return db[Symbols_1._nativeDb].schemaSyncEnabled();
3186
- });
3187
- if (isSchemaSyncEnabled) {
3226
+ const push = async () => {
3227
+ if (wasChanges)
3228
+ await withBriefcaseDb(briefcase, async (db) => db.pushChanges({ ...briefcase, description, retainLocks: true }));
3229
+ };
3230
+ // Asked of the closed file, so an iModel without schema sync never gets opened for this.
3231
+ if (SchemaSync_1.SchemaSync.isEnabled(briefcase)) {
3232
+ await withBriefcaseDb(briefcase, async (db) => SchemaSync_1.SchemaSync.updateDbSchema(db));
3188
3233
  await SchemaSync_1.SchemaSync.withLockedAccess(briefcase, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
3189
3234
  const schemaSyncDbUri = syncAccess.getUri();
3190
3235
  executeUpgrade();
3236
+ // Overwriting advances the SchemaSync data version, so a no-op upgrade must not call it.
3237
+ if (!wasChanges)
3238
+ return;
3191
3239
  await withBriefcaseDb(briefcase, async (db) => {
3192
- db[Symbols_1._nativeDb].schemaSyncPush(schemaSyncDbUri);
3240
+ db[Symbols_1._nativeDb].schemaSyncOverwrite(schemaSyncDbUri);
3193
3241
  db[Symbols_1._nativeDb].saveChanges();
3194
3242
  });
3195
- syncAccess.synchronizeWithCloud();
3243
+ // Publish the sync db before the changeset while retaining both locks.
3244
+ syncAccess.closeDb();
3245
+ await syncAccess.container.uploadChanges();
3246
+ await push();
3196
3247
  });
3197
3248
  }
3198
3249
  else {
3199
3250
  executeUpgrade();
3251
+ await push();
3200
3252
  }
3201
- if (wasChanges)
3202
- await withBriefcaseDb(briefcase, async (db) => db.pushChanges({ ...briefcase, description, retainLocks: true }));
3203
3253
  }
3204
3254
  /** Upgrades the schemas in the iModel based on the current version of the software. Follows a sequence of operations -
3205
3255
  * * Acquires a schema lock to prevent other users from making any other changes while upgrade is happening
@@ -3219,6 +3269,22 @@ class BriefcaseDb extends IModelDb {
3219
3269
  // - push changes
3220
3270
  // - release schema lock
3221
3271
  // good thing computers are fast. Fortunately upgrading should be rare (and the push time will dominate anyway.) Don't try to optimize any of this away.
3272
+ // schemaSyncOverwrite can discard unpushed imports, so hold the exclusive lock across both upgrades.
3273
+ if (SchemaSync_1.SchemaSync.isEnabled(briefcase)) {
3274
+ try {
3275
+ await withBriefcaseDb(briefcase, async (db) => {
3276
+ if (!db.locks.isServerBased)
3277
+ throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot upgrade schemas with SchemaSync without server-based locking");
3278
+ await db.acquireSchemaLock();
3279
+ });
3280
+ await this.doUpgrade(briefcase, { profile: core_common_1.ProfileOptions.Upgrade, schemaLockHeld: true }, "Upgraded profile");
3281
+ await this.doUpgrade(briefcase, { domain: core_common_1.DomainOptions.Upgrade, schemaLockHeld: true }, "Upgraded domain schemas");
3282
+ }
3283
+ finally {
3284
+ await withBriefcaseDb(briefcase, async (db) => db.locks[Symbols_1._releaseAllLocks]());
3285
+ }
3286
+ return;
3287
+ }
3222
3288
  try {
3223
3289
  await this.doUpgrade(briefcase, { profile: core_common_1.ProfileOptions.Upgrade }, "Upgraded profile");
3224
3290
  }
@@ -3519,8 +3585,7 @@ class BriefcaseDb extends IModelDb {
3519
3585
  async pullChanges(arg) {
3520
3586
  await this.executeWritable(async () => {
3521
3587
  await BriefcaseManager_1.BriefcaseManager.pullAndApplyChangesets(this, arg ?? {});
3522
- if (!this.skipSyncSchemasOnPullAndPush)
3523
- await SchemaSync_1.SchemaSync.pull(this);
3588
+ SchemaSync_1.SchemaSync.updateDbSchema(this);
3524
3589
  this.initializeIModelDb("pullMerge");
3525
3590
  });
3526
3591
  // If this pull enabled or disabled SchemaSync for this briefcase, its reservations must now be re-initialized
@@ -3605,24 +3670,10 @@ class BriefcaseDb extends IModelDb {
3605
3670
  if (nativeDb.hasPendingTxns()) {
3606
3671
  throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasLocalChanges, "Cannot revert with pending txns");
3607
3672
  }
3608
- const skipSchemaSyncPull = async (func) => {
3609
- if (nativeDb.schemaSyncEnabled()) {
3610
- this._skipSyncSchemasOnPullAndPush = true;
3611
- try {
3612
- return await func();
3613
- }
3614
- finally {
3615
- this._skipSyncSchemasOnPullAndPush = undefined;
3616
- }
3617
- }
3618
- else {
3619
- return func();
3620
- }
3621
- };
3622
3673
  this.clearCaches();
3623
- await skipSchemaSyncPull(async () => this.pullChanges({ ...arg, toIndex: undefined }));
3674
+ await this.pullChanges({ ...arg, toIndex: undefined });
3624
3675
  await this.acquireSchemaLock();
3625
- if (nativeDb.schemaSyncEnabled()) {
3676
+ if (SchemaSync_1.SchemaSync.isEnabled(this)) {
3626
3677
  arg.skipSchemaChanges = true;
3627
3678
  }
3628
3679
  // The native side enables file-based txns during revert. Restore the original setting afterward.
@@ -3643,7 +3694,7 @@ class BriefcaseDb extends IModelDb {
3643
3694
  pushRetryDelay: arg.pushRetryDelay,
3644
3695
  retainLocks: arg.retainLocks,
3645
3696
  };
3646
- await skipSchemaSyncPull(async () => this.pushChanges(pushArgs));
3697
+ await this.pushChanges(pushArgs);
3647
3698
  this.clearCaches();
3648
3699
  }
3649
3700
  catch (err) {
@@ -3720,6 +3771,56 @@ class BriefcaseDb extends IModelDb {
3720
3771
  this.txns._onChangesPushed(this.changeset);
3721
3772
  BriefcaseManager_1.BriefcaseManager.deleteRebaseFolders(this);
3722
3773
  }
3774
+ /** Import schemas while allowing changes that move or delete data.
3775
+ *
3776
+ * Takes the exclusive schema lock, requires the briefcase to be at the timeline tip, imports, updates the sync db, and pushes the result.
3777
+ * @note The briefcase must have no local changes.
3778
+ * @see [[BriefcaseDb.upgradeSchemas]] (static) for upgrading the software's profile and domain schemas.
3779
+ * @alpha
3780
+ */
3781
+ async upgradeSchemas(schemaFileNames, arg) {
3782
+ return this.upgradeSchemasInternal(schemaFileNames, arg, (schemas, importOptions) => this[Symbols_1._nativeDb].importSchemas(schemas, importOptions));
3783
+ }
3784
+ /** The [[importSchemaStrings]] counterpart of [[upgradeSchemas]].
3785
+ * @alpha
3786
+ */
3787
+ async upgradeSchemaStrings(serializedXmlSchemas, arg) {
3788
+ return this.upgradeSchemasInternal(serializedXmlSchemas, arg, (schemas, importOptions) => this[Symbols_1._nativeDb].importXmlSchemas(schemas, importOptions));
3789
+ }
3790
+ async upgradeSchemasInternal(schemas, arg, nativeImportOp) {
3791
+ if (schemas.length === 0)
3792
+ return;
3793
+ this.assertCanImportSchemas();
3794
+ if (this[Symbols_1._nativeDb].hasUnsavedChanges() || this.txns.hasLocalChanges)
3795
+ throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasLocalChanges, "Cannot upgrade schemas while there are local changes");
3796
+ if (SchemaSync_1.SchemaSync.isEnabled(this) && !this.locks.isServerBased)
3797
+ throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot upgrade schemas with SchemaSync without server-based locking");
3798
+ await this.acquireSchemaLock();
3799
+ await this.pullChanges({ accessToken: arg.accessToken });
3800
+ if (!SchemaSync_1.SchemaSync.isEnabled(this)) {
3801
+ await this.importSchemasInternal(schemas, { ecSchemaXmlContext: arg.ecSchemaXmlContext }, nativeImportOp);
3802
+ await this.pushChanges(arg);
3803
+ return;
3804
+ }
3805
+ await SchemaSync_1.SchemaSync.withLockedAccess(this, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema upgrade" }, async (syncAccess) => {
3806
+ this.saveSchemaChanges();
3807
+ try {
3808
+ nativeImportOp(schemas, {
3809
+ schemaLockHeld: true,
3810
+ ecSchemaXmlContext: arg.ecSchemaXmlContext?.nativeContext,
3811
+ schemaSyncDbUri: syncAccess.getUri(),
3812
+ });
3813
+ }
3814
+ catch (err) {
3815
+ this.abandonSchemaChanges();
3816
+ throw new core_common_1.IModelError(err.errorNumber, err.message);
3817
+ }
3818
+ this.clearCaches();
3819
+ syncAccess.closeDb();
3820
+ await syncAccess.container.uploadChanges();
3821
+ await this.pushChanges(arg);
3822
+ });
3823
+ }
3723
3824
  close(options) {
3724
3825
  if (this.isBriefcase && this.isOpen && !this.isReadonly && this.txns.rebaser.inProgress()) {
3725
3826
  this[Symbols_1._nativeDb].abandonChanges();