@itwin/core-backend 5.14.0-dev.1 → 5.14.0-dev.10
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.
- package/CHANGELOG.md +21 -1
- package/lib/cjs/BriefcaseManager.d.ts +6 -0
- package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
- package/lib/cjs/BriefcaseManager.js +12 -6
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/ChangesetReader.d.ts.map +1 -1
- package/lib/cjs/ChangesetReader.js +1 -0
- package/lib/cjs/ChangesetReader.js.map +1 -1
- package/lib/cjs/ChangesetReaderTypes.d.ts +2 -1
- package/lib/cjs/ChangesetReaderTypes.d.ts.map +1 -1
- package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
- package/lib/cjs/CloudSqlite.d.ts.map +1 -1
- package/lib/cjs/CloudSqlite.js +9 -2
- package/lib/cjs/CloudSqlite.js.map +1 -1
- package/lib/cjs/ECDb.d.ts.map +1 -1
- package/lib/cjs/ECDb.js +1 -0
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/Element.d.ts +1 -1
- package/lib/cjs/Element.js +1 -1
- package/lib/cjs/Element.js.map +1 -1
- package/lib/cjs/Entity.d.ts +3 -3
- package/lib/cjs/Entity.js +3 -3
- package/lib/cjs/Entity.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +83 -35
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +196 -89
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/IpcHost.d.ts.map +1 -1
- package/lib/cjs/IpcHost.js +51 -17
- package/lib/cjs/IpcHost.js.map +1 -1
- package/lib/cjs/SchemaSync.d.ts +126 -18
- package/lib/cjs/SchemaSync.d.ts.map +1 -1
- package/lib/cjs/SchemaSync.js +303 -81
- package/lib/cjs/SchemaSync.js.map +1 -1
- package/lib/cjs/SynchronousChannel.d.ts +11 -1
- package/lib/cjs/SynchronousChannel.d.ts.map +1 -1
- package/lib/cjs/SynchronousChannel.js.map +1 -1
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +16 -13
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/internal/IntegrityCheck.d.ts +57 -0
- package/lib/cjs/internal/IntegrityCheck.d.ts.map +1 -1
- package/lib/cjs/internal/IntegrityCheck.js.map +1 -1
- package/lib/cjs/internal/SchemaSyncReservations.d.ts.map +1 -1
- package/lib/cjs/internal/SchemaSyncReservations.js +13 -3
- package/lib/cjs/internal/SchemaSyncReservations.js.map +1 -1
- package/lib/esm/BriefcaseManager.d.ts +6 -0
- package/lib/esm/BriefcaseManager.d.ts.map +1 -1
- package/lib/esm/BriefcaseManager.js +12 -6
- package/lib/esm/BriefcaseManager.js.map +1 -1
- package/lib/esm/ChangesetReader.d.ts.map +1 -1
- package/lib/esm/ChangesetReader.js +1 -0
- package/lib/esm/ChangesetReader.js.map +1 -1
- package/lib/esm/ChangesetReaderTypes.d.ts +2 -1
- package/lib/esm/ChangesetReaderTypes.d.ts.map +1 -1
- package/lib/esm/ChangesetReaderTypes.js.map +1 -1
- package/lib/esm/CloudSqlite.d.ts.map +1 -1
- package/lib/esm/CloudSqlite.js +10 -3
- package/lib/esm/CloudSqlite.js.map +1 -1
- package/lib/esm/ECDb.d.ts.map +1 -1
- package/lib/esm/ECDb.js +1 -0
- package/lib/esm/ECDb.js.map +1 -1
- package/lib/esm/Element.d.ts +1 -1
- package/lib/esm/Element.js +1 -1
- package/lib/esm/Element.js.map +1 -1
- package/lib/esm/Entity.d.ts +3 -3
- package/lib/esm/Entity.js +3 -3
- package/lib/esm/Entity.js.map +1 -1
- package/lib/esm/IModelDb.d.ts +83 -35
- package/lib/esm/IModelDb.d.ts.map +1 -1
- package/lib/esm/IModelDb.js +196 -89
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/IpcHost.d.ts.map +1 -1
- package/lib/esm/IpcHost.js +52 -18
- package/lib/esm/IpcHost.js.map +1 -1
- package/lib/esm/SchemaSync.d.ts +126 -18
- package/lib/esm/SchemaSync.d.ts.map +1 -1
- package/lib/esm/SchemaSync.js +304 -82
- package/lib/esm/SchemaSync.js.map +1 -1
- package/lib/esm/SynchronousChannel.d.ts +11 -1
- package/lib/esm/SynchronousChannel.d.ts.map +1 -1
- package/lib/esm/SynchronousChannel.js.map +1 -1
- package/lib/esm/TxnManager.d.ts.map +1 -1
- package/lib/esm/TxnManager.js +17 -14
- package/lib/esm/TxnManager.js.map +1 -1
- package/lib/esm/internal/IntegrityCheck.d.ts +57 -0
- package/lib/esm/internal/IntegrityCheck.d.ts.map +1 -1
- package/lib/esm/internal/IntegrityCheck.js.map +1 -1
- package/lib/esm/internal/SchemaSyncReservations.d.ts.map +1 -1
- package/lib/esm/internal/SchemaSyncReservations.js +13 -3
- package/lib/esm/internal/SchemaSyncReservations.js.map +1 -1
- package/lib/esm/test/annotations/FrameGeometry.test.js +1 -1
- package/lib/esm/test/annotations/FrameGeometry.test.js.map +1 -1
- package/lib/esm/test/hubaccess/BriefcaseManager.test.js +65 -1
- package/lib/esm/test/hubaccess/BriefcaseManager.test.js.map +1 -1
- package/lib/esm/test/hubaccess/Rebase.test.js +3 -1
- package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -1
- package/lib/esm/test/hubaccess/SemanticRebase.test.js +218 -28
- package/lib/esm/test/hubaccess/SemanticRebase.test.js.map +1 -1
- package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts +3 -0
- package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.d.ts.map +1 -0
- package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js +15 -0
- package/lib/esm/test/hubaccess/SemanticRebaseTestUtils.js.map +1 -0
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/SchemaSyncDb.test.js +5 -25
- package/lib/esm/test/standalone/SchemaSyncDb.test.js.map +1 -1
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js +1 -0
- package/lib/esm/test/standalone/SchemaSyncElementReservation.test.js.map +1 -1
- package/package.json +14 -14
package/lib/cjs/IModelDb.js
CHANGED
|
@@ -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;
|
|
@@ -434,24 +444,30 @@ class IModelDb extends core_common_1.IModel {
|
|
|
434
444
|
}
|
|
435
445
|
/**
|
|
436
446
|
* Performs integrity checks on this iModel.
|
|
437
|
-
* Types of integrity checks that can be performed are:
|
|
438
447
|
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
448
|
+
* The quick check runs the ten checks below other than Missing Child Rows. It reports pass/fail for each check
|
|
449
|
+
* based on the first problem found, without returning problem details. The specific checks return all problem rows.
|
|
450
|
+
* Selecting both quickCheck and specific checks repeats the selected work in both modes.
|
|
451
|
+
*
|
|
452
|
+
* The checks are:
|
|
453
|
+
* - Data Columns Check: Checks for missing nonvirtual physical columns in mapped data tables. It does not compare column types.
|
|
454
|
+
* - EC Profile Check: Checks expected EC profile tables, indexes, and iModel triggers for missing or mismatching SQL definitions. It does not check be_* tables.
|
|
455
|
+
* - Navigation Class Ids Check: Checks that each non-null persisted RelECClassId is the declared relationship class or one of its derived classes.
|
|
456
|
+
* - Navigation Ids Check: Checks that a navigation property's non-null .Id (the referenced instance's ECInstanceId) resolves to a row in the first relationship constraint class in the navigation direction, including derived classes.
|
|
457
|
+
* - Linktable Foreign Key Class Ids Check: Checks that SourceECClassId and TargetECClassId have matching meta.ECClassDef entries. This checks class existence only, not endpoint-class validity.
|
|
458
|
+
* - Linktable Foreign Key Ids Check: Checks SourceECInstanceId and TargetECInstanceId for null or an unresolved row in the first endpoint constraint class, including derived classes.
|
|
459
|
+
* - Class Ids Check: Checks persisted ECClassId values for a corresponding class definition. This checks class existence, not whether the class belongs in that table.
|
|
460
|
+
* - Data Schema Check: Checks for missing mapped data tables and indexes. Results report object names and types, not DDL differences.
|
|
461
|
+
* - Schema Load Check: Checks whether the schema manager can load each schema recorded in the database. A problem reports the schema name without a reason.
|
|
462
|
+
* - Missing Child Rows Check: Checks whether each existing bis_Element row has all required mapped child-table rows.
|
|
463
|
+
* - Diverged Property Maps Check: Checks whether an inherited property maps to different columns for a base and derived class under the same physical table root.
|
|
441
464
|
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* - Navigation Class Ids Check: Checks if RelClassId of a Navigation property is a valid ECClassId. It does not check the value to match the relationship class.
|
|
446
|
-
* - Navigation Ids Check: Checks if Id of a Navigation property matches a valid row primary class.
|
|
447
|
-
* - Linktable Foreign Key Class Ids Check: Checks if SourceECClassId or TargetECClassId of a link table matches a valid ECClassId.
|
|
448
|
-
* - Linktable Foreign Key Ids Check: Checks if SourceECInstanceId or TargetECInstanceId of a link table matches a valid row in primary class.
|
|
449
|
-
* - Class Ids Check: Checks persisted ECClassId in all data tables and makes sure they are valid.
|
|
450
|
-
* - Data Schema Check: Checks if all the required data tables and indexes exist for mapped classes. Issues are returned as a list of tables/columns which were not found or have different DDL.
|
|
451
|
-
* - Schema Load Check: Checks if all schemas can be loaded into memory.
|
|
452
|
-
* - Missing Child Rows Check: Checks if all child rows have a corresponding parent row.
|
|
465
|
+
* If no options are provided, or if quickCheck is false and no specific check is enabled, a quick check is performed by default.
|
|
466
|
+
* The checks are read-only and use the current primary connection. They have no callbacks, and the native operation
|
|
467
|
+
* blocks the backend while each check runs.
|
|
453
468
|
*
|
|
454
|
-
* @
|
|
469
|
+
* @see [ECSQL integrity checks]($docs/learning/ECSqlReference/Pragmas.md#pragma-integrity_check-experimental)
|
|
470
|
+
* @param options Options specifying which integrity checks to perform.
|
|
455
471
|
* @returns An array of integrity check results.
|
|
456
472
|
* @throws [[IModelError]] if the iModel is not open.
|
|
457
473
|
* @beta
|
|
@@ -938,7 +954,7 @@ class IModelDb extends core_common_1.IModel {
|
|
|
938
954
|
async dropSchemas(schemaNames) {
|
|
939
955
|
if (schemaNames.length === 0)
|
|
940
956
|
return;
|
|
941
|
-
if (
|
|
957
|
+
if (SchemaSync_1.SchemaSync.isEnabled(this))
|
|
942
958
|
throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot drop schemas when schema sync is enabled");
|
|
943
959
|
if (this[Symbols_1._nativeDb].hasUnsavedChanges())
|
|
944
960
|
throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasUncommittedChanges, "Cannot drop schemas with unsaved changes");
|
|
@@ -1024,26 +1040,34 @@ class IModelDb extends core_common_1.IModel {
|
|
|
1024
1040
|
this.cleanupSnapshot(context.resources);
|
|
1025
1041
|
}
|
|
1026
1042
|
}
|
|
1027
|
-
/**
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1043
|
+
/** Refuse a schema import this briefcase is in no state to run. Shared by [[importSchemas]] and
|
|
1044
|
+
* [[BriefcaseDb.upgradeSchemas]], which reach the native importer by different routes.
|
|
1045
|
+
* @internal
|
|
1046
|
+
*/
|
|
1047
|
+
assertCanImportSchemas() {
|
|
1048
|
+
if (!this.isBriefcaseDb())
|
|
1049
|
+
return;
|
|
1050
|
+
if (this.txns.rebaser.isRebasing) {
|
|
1051
|
+
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while rebasing");
|
|
1052
|
+
}
|
|
1053
|
+
if (this.txns.isIndirectChanges) {
|
|
1054
|
+
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas while in an indirect change scope");
|
|
1055
|
+
}
|
|
1056
|
+
// Additional checks when semantic rebase is enabled
|
|
1057
|
+
if (IModelHost_1.IModelHost.useSemanticRebase) {
|
|
1058
|
+
if (this[Symbols_1._nativeDb].hasUnsavedChanges()) {
|
|
1059
|
+
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Cannot import schemas with unsaved changes when useSemanticRebase flag is on");
|
|
1060
|
+
}
|
|
1061
|
+
if (SchemaSync_1.SchemaSync.isEnabled(this)) {
|
|
1062
|
+
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
1063
|
}
|
|
1046
1064
|
}
|
|
1065
|
+
}
|
|
1066
|
+
/** Shared implementation for importing schemas from file or string.
|
|
1067
|
+
* @internal
|
|
1068
|
+
*/
|
|
1069
|
+
async importSchemasInternal(schemas, options, nativeImportOp) {
|
|
1070
|
+
this.assertCanImportSchemas();
|
|
1047
1071
|
if (options?.channelUpgrade) {
|
|
1048
1072
|
const channelUpgrade = options.channelUpgrade;
|
|
1049
1073
|
try {
|
|
@@ -1061,30 +1085,52 @@ class IModelDb extends core_common_1.IModel {
|
|
|
1061
1085
|
if (options?.schemaImportCallbacks?.preSchemaImportCallback)
|
|
1062
1086
|
preSchemaImportCallbackResult = await this.preSchemaImportCallback(options.schemaImportCallbacks, { iModel: this, data: options.data, schemaData: schemas });
|
|
1063
1087
|
const maybeCustomNativeContext = options?.ecSchemaXmlContext?.nativeContext;
|
|
1064
|
-
if (
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
this.
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1088
|
+
if (SchemaSync_1.SchemaSync.isEnabled(this)) {
|
|
1089
|
+
// The shared lock lets concurrent updates through while blocking anyone taking the exclusive lock for an upgrade.
|
|
1090
|
+
if (this[Symbols_1._nativeDb].getITwinId() !== core_bentley_1.Guid.empty)
|
|
1091
|
+
await this.locks.acquireLocks({ shared: core_common_1.IModel.repositoryModelId });
|
|
1092
|
+
// The native import adopts rows from the attached SchemaSyncDb. Attach and detach commit
|
|
1093
|
+
// implicitly, so abandoning changes cannot undo the adoption. A later failure must roll the
|
|
1094
|
+
// briefcase back before those ec_ rows can be pushed.
|
|
1095
|
+
let txnBeforeAdopt;
|
|
1096
|
+
// Set once the caller's own work is committed. Getting a token or the container write lock happens
|
|
1097
|
+
// before that, and abandonSchemaChanges discards every unsaved change rather than only this import's,
|
|
1098
|
+
// so abandoning on a failure from that window would throw away work the import never touched.
|
|
1099
|
+
let callerChangesSaved = false;
|
|
1100
|
+
try {
|
|
1101
|
+
await SchemaSync_1.SchemaSync.withLockedAccess(this, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
|
|
1102
|
+
const schemaSyncDbUri = syncAccess.getUri();
|
|
1103
|
+
this.saveSchemaChanges();
|
|
1104
|
+
callerChangesSaved = true;
|
|
1105
|
+
// After saveSchemaChanges, so rolling back cannot reach the caller's own work.
|
|
1106
|
+
if (this.isBriefcaseDb())
|
|
1107
|
+
txnBeforeAdopt = this.txns.getCurrentTxnId();
|
|
1108
|
+
try {
|
|
1109
|
+
nativeImportOp(schemas, { schemaLockHeld: false, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
|
|
1082
1110
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1111
|
+
catch (err) {
|
|
1112
|
+
if (SchemaSync_1.SchemaSync.requiresUpgrade(err))
|
|
1113
|
+
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.`);
|
|
1114
|
+
throw new core_common_1.IModelError(err.errorNumber, err.message);
|
|
1085
1115
|
}
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
catch (err) {
|
|
1119
|
+
if (callerChangesSaved)
|
|
1120
|
+
this.abandonSchemaChanges();
|
|
1121
|
+
if (this.isBriefcaseDb() && undefined !== txnBeforeAdopt && this.txns.getCurrentTxnId() !== txnBeforeAdopt) {
|
|
1122
|
+
// Saving the adopt's txn started a new undo session, because schema changes are kept out of the
|
|
1123
|
+
// user's undo stack, so this reverses across that boundary. The changes themselves reverse like
|
|
1124
|
+
// any other - a rebase does it to every local txn on every pull. It does not reverse DDL: a table
|
|
1125
|
+
// or column the adopt created stays behind with no ec_ row describing it, which is the state a
|
|
1126
|
+
// briefcase already tolerates, and the next successful import finds the table up to date and
|
|
1127
|
+
// carries on. Cancel rather than reverse, so the rows cannot come back through undo either.
|
|
1128
|
+
const status = this[Symbols_1._nativeDb].cancelTo(txnBeforeAdopt, true);
|
|
1129
|
+
if (core_bentley_1.IModelStatus.Success !== status)
|
|
1130
|
+
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
1131
|
}
|
|
1087
|
-
|
|
1132
|
+
throw err;
|
|
1133
|
+
}
|
|
1088
1134
|
}
|
|
1089
1135
|
else {
|
|
1090
1136
|
const nativeImportOptions = {
|
|
@@ -2850,7 +2896,9 @@ function processSchemaWriteStatus(status) {
|
|
|
2850
2896
|
try {
|
|
2851
2897
|
props.push(imodel.elements.getElementProps(id));
|
|
2852
2898
|
}
|
|
2853
|
-
catch {
|
|
2899
|
+
catch {
|
|
2900
|
+
return;
|
|
2901
|
+
}
|
|
2854
2902
|
});
|
|
2855
2903
|
return props;
|
|
2856
2904
|
}
|
|
@@ -2873,7 +2921,9 @@ function processSchemaWriteStatus(status) {
|
|
|
2873
2921
|
break;
|
|
2874
2922
|
}
|
|
2875
2923
|
}
|
|
2876
|
-
catch {
|
|
2924
|
+
catch {
|
|
2925
|
+
continue;
|
|
2926
|
+
}
|
|
2877
2927
|
}
|
|
2878
2928
|
return finished;
|
|
2879
2929
|
}
|
|
@@ -3083,9 +3133,6 @@ class BriefcaseDb extends IModelDb {
|
|
|
3083
3133
|
get isBriefcase() { return true; }
|
|
3084
3134
|
/* the BriefcaseId of the briefcase opened with this BriefcaseDb */
|
|
3085
3135
|
briefcaseId;
|
|
3086
|
-
_skipSyncSchemasOnPullAndPush;
|
|
3087
|
-
/** @internal */
|
|
3088
|
-
get skipSyncSchemasOnPullAndPush() { return this._skipSyncSchemasOnPullAndPush ?? false; }
|
|
3089
3136
|
/**
|
|
3090
3137
|
* Event raised just before a BriefcaseDb is opened. Supplies the arguments that will be used to open the BriefcaseDb.
|
|
3091
3138
|
* Throw an exception to stop the open.
|
|
@@ -3168,6 +3215,8 @@ class BriefcaseDb extends IModelDb {
|
|
|
3168
3215
|
}
|
|
3169
3216
|
constructor(args) {
|
|
3170
3217
|
super({ ...args, changeset: args.nativeDb.getCurrentChangeset() });
|
|
3218
|
+
// Native invokes this private callback dynamically through the object registered by IModelDb.
|
|
3219
|
+
void this.onChangesetConflict;
|
|
3171
3220
|
this._openMode = args.openMode;
|
|
3172
3221
|
this.briefcaseId = args.briefcaseId;
|
|
3173
3222
|
this.makeLockControl();
|
|
@@ -3180,26 +3229,33 @@ class BriefcaseDb extends IModelDb {
|
|
|
3180
3229
|
wasChanges = nativeDb.hasPendingTxns();
|
|
3181
3230
|
nativeDb.closeFile();
|
|
3182
3231
|
};
|
|
3183
|
-
const
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
}
|
|
3187
|
-
|
|
3232
|
+
const push = async () => {
|
|
3233
|
+
if (wasChanges)
|
|
3234
|
+
await withBriefcaseDb(briefcase, async (db) => db.pushChanges({ ...briefcase, description, retainLocks: true }));
|
|
3235
|
+
};
|
|
3236
|
+
// Asked of the closed file, so an iModel without schema sync never gets opened for this.
|
|
3237
|
+
if (SchemaSync_1.SchemaSync.isEnabled(briefcase)) {
|
|
3238
|
+
await withBriefcaseDb(briefcase, async (db) => SchemaSync_1.SchemaSync.updateDbSchema(db));
|
|
3188
3239
|
await SchemaSync_1.SchemaSync.withLockedAccess(briefcase, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
|
|
3189
3240
|
const schemaSyncDbUri = syncAccess.getUri();
|
|
3190
3241
|
executeUpgrade();
|
|
3242
|
+
// Overwriting advances the SchemaSync data version, so a no-op upgrade must not call it.
|
|
3243
|
+
if (!wasChanges)
|
|
3244
|
+
return;
|
|
3191
3245
|
await withBriefcaseDb(briefcase, async (db) => {
|
|
3192
|
-
db[Symbols_1._nativeDb].
|
|
3246
|
+
db[Symbols_1._nativeDb].schemaSyncOverwrite(schemaSyncDbUri);
|
|
3193
3247
|
db[Symbols_1._nativeDb].saveChanges();
|
|
3194
3248
|
});
|
|
3195
|
-
|
|
3249
|
+
// Publish the sync db before the changeset while retaining both locks.
|
|
3250
|
+
syncAccess.closeDb();
|
|
3251
|
+
await syncAccess.container.uploadChanges();
|
|
3252
|
+
await push();
|
|
3196
3253
|
});
|
|
3197
3254
|
}
|
|
3198
3255
|
else {
|
|
3199
3256
|
executeUpgrade();
|
|
3257
|
+
await push();
|
|
3200
3258
|
}
|
|
3201
|
-
if (wasChanges)
|
|
3202
|
-
await withBriefcaseDb(briefcase, async (db) => db.pushChanges({ ...briefcase, description, retainLocks: true }));
|
|
3203
3259
|
}
|
|
3204
3260
|
/** Upgrades the schemas in the iModel based on the current version of the software. Follows a sequence of operations -
|
|
3205
3261
|
* * Acquires a schema lock to prevent other users from making any other changes while upgrade is happening
|
|
@@ -3219,6 +3275,22 @@ class BriefcaseDb extends IModelDb {
|
|
|
3219
3275
|
// - push changes
|
|
3220
3276
|
// - release schema lock
|
|
3221
3277
|
// 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.
|
|
3278
|
+
// schemaSyncOverwrite can discard unpushed imports, so hold the exclusive lock across both upgrades.
|
|
3279
|
+
if (SchemaSync_1.SchemaSync.isEnabled(briefcase)) {
|
|
3280
|
+
try {
|
|
3281
|
+
await withBriefcaseDb(briefcase, async (db) => {
|
|
3282
|
+
if (!db.locks.isServerBased)
|
|
3283
|
+
throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot upgrade schemas with SchemaSync without server-based locking");
|
|
3284
|
+
await db.acquireSchemaLock();
|
|
3285
|
+
});
|
|
3286
|
+
await this.doUpgrade(briefcase, { profile: core_common_1.ProfileOptions.Upgrade, schemaLockHeld: true }, "Upgraded profile");
|
|
3287
|
+
await this.doUpgrade(briefcase, { domain: core_common_1.DomainOptions.Upgrade, schemaLockHeld: true }, "Upgraded domain schemas");
|
|
3288
|
+
}
|
|
3289
|
+
finally {
|
|
3290
|
+
await withBriefcaseDb(briefcase, async (db) => db.locks[Symbols_1._releaseAllLocks]());
|
|
3291
|
+
}
|
|
3292
|
+
return;
|
|
3293
|
+
}
|
|
3222
3294
|
try {
|
|
3223
3295
|
await this.doUpgrade(briefcase, { profile: core_common_1.ProfileOptions.Upgrade }, "Upgraded profile");
|
|
3224
3296
|
}
|
|
@@ -3519,8 +3591,7 @@ class BriefcaseDb extends IModelDb {
|
|
|
3519
3591
|
async pullChanges(arg) {
|
|
3520
3592
|
await this.executeWritable(async () => {
|
|
3521
3593
|
await BriefcaseManager_1.BriefcaseManager.pullAndApplyChangesets(this, arg ?? {});
|
|
3522
|
-
|
|
3523
|
-
await SchemaSync_1.SchemaSync.pull(this);
|
|
3594
|
+
SchemaSync_1.SchemaSync.updateDbSchema(this);
|
|
3524
3595
|
this.initializeIModelDb("pullMerge");
|
|
3525
3596
|
});
|
|
3526
3597
|
// If this pull enabled or disabled SchemaSync for this briefcase, its reservations must now be re-initialized
|
|
@@ -3605,24 +3676,10 @@ class BriefcaseDb extends IModelDb {
|
|
|
3605
3676
|
if (nativeDb.hasPendingTxns()) {
|
|
3606
3677
|
throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasLocalChanges, "Cannot revert with pending txns");
|
|
3607
3678
|
}
|
|
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
3679
|
this.clearCaches();
|
|
3623
|
-
await
|
|
3680
|
+
await this.pullChanges({ ...arg, toIndex: undefined });
|
|
3624
3681
|
await this.acquireSchemaLock();
|
|
3625
|
-
if (
|
|
3682
|
+
if (SchemaSync_1.SchemaSync.isEnabled(this)) {
|
|
3626
3683
|
arg.skipSchemaChanges = true;
|
|
3627
3684
|
}
|
|
3628
3685
|
// The native side enables file-based txns during revert. Restore the original setting afterward.
|
|
@@ -3643,7 +3700,7 @@ class BriefcaseDb extends IModelDb {
|
|
|
3643
3700
|
pushRetryDelay: arg.pushRetryDelay,
|
|
3644
3701
|
retainLocks: arg.retainLocks,
|
|
3645
3702
|
};
|
|
3646
|
-
await
|
|
3703
|
+
await this.pushChanges(pushArgs);
|
|
3647
3704
|
this.clearCaches();
|
|
3648
3705
|
}
|
|
3649
3706
|
catch (err) {
|
|
@@ -3720,6 +3777,56 @@ class BriefcaseDb extends IModelDb {
|
|
|
3720
3777
|
this.txns._onChangesPushed(this.changeset);
|
|
3721
3778
|
BriefcaseManager_1.BriefcaseManager.deleteRebaseFolders(this);
|
|
3722
3779
|
}
|
|
3780
|
+
/** Import schemas while allowing changes that move or delete data.
|
|
3781
|
+
*
|
|
3782
|
+
* Takes the exclusive schema lock, requires the briefcase to be at the timeline tip, imports, updates the sync db, and pushes the result.
|
|
3783
|
+
* @note The briefcase must have no local changes.
|
|
3784
|
+
* @see [[BriefcaseDb.upgradeSchemas]] (static) for upgrading the software's profile and domain schemas.
|
|
3785
|
+
* @alpha
|
|
3786
|
+
*/
|
|
3787
|
+
async upgradeSchemas(schemaFileNames, arg) {
|
|
3788
|
+
return this.upgradeSchemasInternal(schemaFileNames, arg, (schemas, importOptions) => this[Symbols_1._nativeDb].importSchemas(schemas, importOptions));
|
|
3789
|
+
}
|
|
3790
|
+
/** The [[importSchemaStrings]] counterpart of [[upgradeSchemas]].
|
|
3791
|
+
* @alpha
|
|
3792
|
+
*/
|
|
3793
|
+
async upgradeSchemaStrings(serializedXmlSchemas, arg) {
|
|
3794
|
+
return this.upgradeSchemasInternal(serializedXmlSchemas, arg, (schemas, importOptions) => this[Symbols_1._nativeDb].importXmlSchemas(schemas, importOptions));
|
|
3795
|
+
}
|
|
3796
|
+
async upgradeSchemasInternal(schemas, arg, nativeImportOp) {
|
|
3797
|
+
if (schemas.length === 0)
|
|
3798
|
+
return;
|
|
3799
|
+
this.assertCanImportSchemas();
|
|
3800
|
+
if (this[Symbols_1._nativeDb].hasUnsavedChanges() || this.txns.hasLocalChanges)
|
|
3801
|
+
throw new core_common_1.IModelError(core_bentley_1.ChangeSetStatus.HasLocalChanges, "Cannot upgrade schemas while there are local changes");
|
|
3802
|
+
if (SchemaSync_1.SchemaSync.isEnabled(this) && !this.locks.isServerBased)
|
|
3803
|
+
throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Cannot upgrade schemas with SchemaSync without server-based locking");
|
|
3804
|
+
await this.acquireSchemaLock();
|
|
3805
|
+
await this.pullChanges({ accessToken: arg.accessToken });
|
|
3806
|
+
if (!SchemaSync_1.SchemaSync.isEnabled(this)) {
|
|
3807
|
+
await this.importSchemasInternal(schemas, { ecSchemaXmlContext: arg.ecSchemaXmlContext }, nativeImportOp);
|
|
3808
|
+
await this.pushChanges(arg);
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
await SchemaSync_1.SchemaSync.withLockedAccess(this, { openMode: core_bentley_1.OpenMode.Readonly, operationName: "schema upgrade" }, async (syncAccess) => {
|
|
3812
|
+
this.saveSchemaChanges();
|
|
3813
|
+
try {
|
|
3814
|
+
nativeImportOp(schemas, {
|
|
3815
|
+
schemaLockHeld: true,
|
|
3816
|
+
ecSchemaXmlContext: arg.ecSchemaXmlContext?.nativeContext,
|
|
3817
|
+
schemaSyncDbUri: syncAccess.getUri(),
|
|
3818
|
+
});
|
|
3819
|
+
}
|
|
3820
|
+
catch (err) {
|
|
3821
|
+
this.abandonSchemaChanges();
|
|
3822
|
+
throw new core_common_1.IModelError(err.errorNumber, err.message);
|
|
3823
|
+
}
|
|
3824
|
+
this.clearCaches();
|
|
3825
|
+
syncAccess.closeDb();
|
|
3826
|
+
await syncAccess.container.uploadChanges();
|
|
3827
|
+
await this.pushChanges(arg);
|
|
3828
|
+
});
|
|
3829
|
+
}
|
|
3723
3830
|
close(options) {
|
|
3724
3831
|
if (this.isBriefcase && this.isOpen && !this.isReadonly && this.txns.rebaser.inProgress()) {
|
|
3725
3832
|
this[Symbols_1._nativeDb].abandonChanges();
|