@itwin/imodel-transformer 2.0.0-dev.2 → 2.0.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -77,6 +77,15 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
77
77
  targetDb;
78
78
  /** The IModelTransformContext for this IModelTransformer. */
79
79
  context;
80
+ /** The transform to be applied to the placement of spatial elements
81
+ * This transform should be applied when:
82
+ * - source and target db have different ECEF locations
83
+ * - source and target db have matching GCS/CRS data, but differing `geographicCoordinateSystem.additionalTransform.helmert2DWithZOffset`
84
+ * @note for ECEF transforms, this can only be used when source and target are linearly located imodels
85
+ * @note for non linearly located imodels, this transform will be a linear transform derived from Helmert Transforms from the src and target iModels.
86
+ * @beta
87
+ */
88
+ _linearSpatialTransform;
80
89
  _syncType;
81
90
  /** The Id of the Element in the **target** iModel that represents the **source** repository as a whole and scopes its [ExternalSourceAspect]($backend) instances. */
82
91
  get targetScopeElementId() {
@@ -111,7 +120,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
111
120
  AND Identifier=:identifier
112
121
  LIMIT 1
113
122
  `;
114
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
123
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
115
124
  return dbToQuery.withPreparedStatement(sql, (statement) => {
116
125
  statement.bindId("elementId", aspectProps.element.id);
117
126
  if (aspectProps.scope === undefined)
@@ -230,10 +239,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
230
239
  // non-falsy defaults
231
240
  cloneUsingBinaryGeometry: options?.cloneUsingBinaryGeometry ?? true,
232
241
  targetScopeElementId: options?.targetScopeElementId ?? core_common_1.IModel.rootSubjectId,
233
- // eslint-disable-next-line deprecation/deprecation
242
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
234
243
  danglingReferencesBehavior: options?.danglingReferencesBehavior ?? "reject",
235
244
  branchRelationshipDataBehavior: options?.branchRelationshipDataBehavior ?? "reject",
236
245
  skipPropagateChangesToRootElements: options?.skipPropagateChangesToRootElements ?? true,
246
+ tryAlignGeolocation: options?.tryAlignGeolocation ?? false,
237
247
  };
238
248
  // check if authorization client is defined
239
249
  if (core_backend_1.IModelHost.authorizationClient === undefined) {
@@ -289,6 +299,20 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
289
299
  this.targetDb.codeValueBehavior = "exact";
290
300
  }
291
301
  /* eslint-enable @itwin/no-internal */
302
+ if (this._options.tryAlignGeolocation) {
303
+ if (this.sourceDb.geographicCoordinateSystem ||
304
+ this.targetDb.geographicCoordinateSystem) {
305
+ core_bentley_1.Logger.logTrace(loggerCategory, "Aligning Additional transforms between imodels due to imodels containing GeographicCoordinateSystem data");
306
+ this._linearSpatialTransform =
307
+ this.calculateTransformFromHelmertTransforms();
308
+ }
309
+ else if (this.sourceDb.ecefLocation && this.targetDb.ecefLocation) {
310
+ core_bentley_1.Logger.logTrace(loggerCategory, "Aligning ECEF Location's between imodels due to imodels not containing GeographicCoordinateSystem data");
311
+ this._linearSpatialTransform = this.calculateEcefTransform();
312
+ }
313
+ else
314
+ core_bentley_1.Logger.logTrace(loggerCategory, "No Geolcation data to align, both GCS and ECEF are undefined");
315
+ }
292
316
  }
293
317
  /** validates that the importer set on the transformer has the same values for its shared options as the transformer.
294
318
  * @note This expects that the importer is already set on the transformer.
@@ -371,7 +395,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
371
395
  const provenanceRelInstanceId = args.isReverseSynchronization
372
396
  ? sourceRelInstanceId
373
397
  : targetRelInstanceId;
374
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
398
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
375
399
  const elementId = provenanceDb.withPreparedStatement("SELECT SourceECInstanceId FROM bis.ElementRefersToElements WHERE ECInstanceId=?", (stmt) => {
376
400
  stmt.bindId(1, provenanceRelInstanceId);
377
401
  nodeAssert(stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW);
@@ -524,9 +548,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
524
548
  AND Kind=:kind
525
549
  LIMIT 1
526
550
  `;
527
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
551
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
528
552
  const hasConflictingScope = this.provenanceDb.withPreparedStatement(sql,
529
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
553
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
530
554
  (statement) => {
531
555
  statement.bindId("elementId", aspectProps.element.id);
532
556
  statement.bindId("scopeId", aspectProps.scope.id); // this scope.id can never be invalid, we create it above
@@ -649,9 +673,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
649
673
  // NOTE: if we exposed the native attach database support,
650
674
  // we could get the intersection of fed guids in one query, not sure if it would be faster
651
675
  // OR we could do a raw sqlite query...
652
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
676
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
653
677
  sourceDb.withStatement(elementIdByFedGuidQuery, (sourceStmt) =>
654
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
678
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
655
679
  targetDb.withStatement(elementIdByFedGuidQuery, (targetStmt) => {
656
680
  if (sourceStmt.step() !== core_bentley_1.DbResult.BE_SQLITE_ROW)
657
681
  return;
@@ -695,7 +719,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
695
719
  // Technically this will a second time call the function (as documented) on
696
720
  // victims of the old provenance method that have both fedguids and an inserted aspect.
697
721
  // But this is a private function with one known caller where that doesn't matter
698
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
722
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
699
723
  args.provenanceDb.withPreparedStatement(provenanceAspectsQuery, (stmt) => {
700
724
  const runFnInDataFlowDirection = (sourceId, targetId) => args.isReverseSynchronization
701
725
  ? args.fn(sourceId, targetId)
@@ -728,7 +752,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
728
752
  * @returns the elementId that the ESA is stored on, esa.Element.Id
729
753
  */
730
754
  _queryProvenanceForElement(entityInProvenanceSourceId) {
731
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
755
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
732
756
  return this.provenanceDb.withPreparedStatement(`
733
757
  SELECT esa.Element.Id
734
758
  FROM Bis.ExternalSourceAspect esa
@@ -753,7 +777,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
753
777
  * @returns
754
778
  */
755
779
  _queryProvenanceForRelationship(entityInProvenanceSourceId, sourceRelInfo) {
756
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
780
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
757
781
  return this.provenanceDb.withPreparedStatement(`
758
782
  SELECT
759
783
  ECInstanceId,
@@ -788,7 +812,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
788
812
  if (targetRelInfo.sourceId === undefined ||
789
813
  targetRelInfo.targetId === undefined)
790
814
  return undefined; // couldn't find an element, rel is invalid or deleted
791
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
815
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
792
816
  return this.targetDb.withPreparedStatement(`
793
817
  SELECT ECInstanceId
794
818
  FROM bis.ElementRefersToElements
@@ -816,7 +840,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
816
840
  // NOTE: this doesn't handle remapped element classes,
817
841
  // but is only used for relationships rn
818
842
  _getRelClassId(db, classFullName) {
819
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
843
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
820
844
  return db.withPreparedStatement(`
821
845
  SELECT c.ECInstanceId
822
846
  FROM ECDbMeta.ECClassDef c
@@ -834,7 +858,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
834
858
  });
835
859
  }
836
860
  _queryElemIdByFedGuid(db, fedGuid) {
837
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
861
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
838
862
  return db.withPreparedStatement("SELECT ECInstanceId FROM Bis.Element WHERE FederationGuid=?", (stmt) => {
839
863
  stmt.bindGuid(1, fedGuid);
840
864
  if (stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW)
@@ -870,7 +894,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
870
894
  `;
871
895
  nodeAssert(!this.isReverseSynchronization, "synchronizations with processChanges already detect element deletes, don't call detectElementDeletes");
872
896
  // Reported issue: https://github.com/iTwin/itwinjs-core/issues/7989
873
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
897
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
874
898
  this.provenanceDb.withPreparedStatement(sql, (stmt) => {
875
899
  stmt.bindId("scopeId", this.targetScopeElementId);
876
900
  stmt.bindString("kind", core_backend_1.ExternalSourceAspect.Kind.Element);
@@ -918,8 +942,87 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
918
942
  targetElementProps.jsonProperties.Subject.Job = undefined;
919
943
  }
920
944
  }
945
+ if (this._linearSpatialTransform !== undefined &&
946
+ sourceElement instanceof core_backend_1.GeometricElement3d) {
947
+ // can check the sourceElement since this IModelTransformer does not remap classes
948
+ const placement = core_common_1.Placement3d.fromJSON(targetElementProps.placement);
949
+ if (placement.isValid) {
950
+ placement.multiplyTransform(this._linearSpatialTransform);
951
+ targetElementProps.placement = placement;
952
+ }
953
+ }
921
954
  return targetElementProps;
922
955
  }
956
+ /**
957
+ * Calculate the transform between two ECEF locations
958
+ * @param srcDb
959
+ * @param targetDb
960
+ * @returns Transform that converts relative coordinates in the source iModel to relative coordinates in the target iModel.
961
+ * @note This can only be used if both source and target iModels are linearly located
962
+ */
963
+ calculateEcefTransform() {
964
+ const srcEcefLoc = this.sourceDb.ecefLocation;
965
+ const targetEcefLoc = this.targetDb.ecefLocation;
966
+ if (srcEcefLoc === undefined || targetEcefLoc === undefined) {
967
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NoGeoLocation, "Both source and target ECEF locations must be defined to calculate the transform.");
968
+ }
969
+ if (srcEcefLoc.getTransform().isAlmostEqual(targetEcefLoc.getTransform())) {
970
+ core_bentley_1.Logger.logTrace(loggerCategory, "ECEF data is already aligned. No spatial transforms needed.");
971
+ return undefined;
972
+ }
973
+ const srcSpatialToECEF = srcEcefLoc.getTransform(); // converts relative to ECEF in relation to source
974
+ const targetECEFToSpatial = targetEcefLoc.getTransform().inverse(); // converts ECEF to relative in relation to target
975
+ if (!targetECEFToSpatial) {
976
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NoGeoLocation, "Failed to invert target ECEF transform.");
977
+ }
978
+ const ecefTransform = targetECEFToSpatial.multiplyTransformTransform(srcSpatialToECEF); // chain both transforms
979
+ return ecefTransform;
980
+ }
981
+ static convertHelmertToTransform(helmert) {
982
+ if (!helmert) {
983
+ return core_geometry_1.Transform.createIdentity();
984
+ }
985
+ const rotationXY = core_geometry_1.Matrix3d.createRotationAroundAxisIndex(core_geometry_1.AxisIndex.Z, core_geometry_1.Angle.createDegrees(helmert?.rotDeg));
986
+ rotationXY.scaleColumnsInPlace(helmert.scale, helmert.scale, 1.0);
987
+ const translation = core_geometry_1.Vector3d.create(helmert.translationX, helmert.translationY, helmert.translationZ);
988
+ const helmertTransform = core_geometry_1.Transform.createRefs(translation, rotationXY);
989
+ return helmertTransform;
990
+ }
991
+ calculateTransformFromHelmertTransforms() {
992
+ if (this.sourceDb.geographicCoordinateSystem?.horizontalCRS === undefined ||
993
+ this.sourceDb.geographicCoordinateSystem?.verticalCRS === undefined) {
994
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Source iModel does not have a geographic coordinate system defined.");
995
+ }
996
+ if (this.targetDb.geographicCoordinateSystem?.horizontalCRS === undefined ||
997
+ this.targetDb.geographicCoordinateSystem.verticalCRS === undefined) {
998
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "Target iModel does not have a geographic coordinate system defined.");
999
+ }
1000
+ if (!this.sourceDb.geographicCoordinateSystem.horizontalCRS.equals(this.targetDb.geographicCoordinateSystem.horizontalCRS) ||
1001
+ !this.sourceDb.geographicCoordinateSystem.verticalCRS.equals(this.targetDb.geographicCoordinateSystem.verticalCRS)) {
1002
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.MismatchGcs, "Source and target geographic coordinate systems must match to calculate the spatial transform.");
1003
+ }
1004
+ if (this.sourceDb.geographicCoordinateSystem.additionalTransform ===
1005
+ this.targetDb.geographicCoordinateSystem.additionalTransform) {
1006
+ core_bentley_1.Logger.logTrace(loggerCategory, "Geolocation data is already aligned. No spatial transforms needed.");
1007
+ return undefined;
1008
+ }
1009
+ const srcScale = this.sourceDb.geographicCoordinateSystem.additionalTransform
1010
+ ?.helmert2DWithZOffset?.scale ?? 1;
1011
+ const targetScale = this.targetDb.geographicCoordinateSystem.additionalTransform
1012
+ ?.helmert2DWithZOffset?.scale ?? 1;
1013
+ if (srcScale !== targetScale) {
1014
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.MismatchGcs, "Spatial transform is non rigid. Source and target Helmert transforms must have the same scale to calculate a rigid spatial transform.");
1015
+ }
1016
+ const srcTransform = IModelTransformer.convertHelmertToTransform(this.sourceDb.geographicCoordinateSystem.additionalTransform
1017
+ ?.helmert2DWithZOffset); // moves elements to where src helmert transform would move them at render time
1018
+ const targetTransformInv = IModelTransformer.convertHelmertToTransform(this.targetDb.geographicCoordinateSystem.additionalTransform
1019
+ ?.helmert2DWithZOffset).inverse(); // negates target helmert transform that is applied at render time
1020
+ if (!targetTransformInv) {
1021
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NoGeoLocation, "Failed to invert target Helmert transform.");
1022
+ }
1023
+ const combinedTransform = targetTransformInv.multiplyTransformTransform(srcTransform);
1024
+ return combinedTransform;
1025
+ }
923
1026
  // if undefined, it can be initialized by calling [[this.processChangesets]]
924
1027
  _deletedSourceRelationshipData = undefined;
925
1028
  /** Returns true if a change within sourceElement is detected.
@@ -1162,7 +1265,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1162
1265
  if (!this._options.wasSourceIModelCopiedToTarget) {
1163
1266
  this.importer.importElement(targetElementProps); // don't need to import if iModel was copied
1164
1267
  }
1165
- this.context.remapElement(sourceElement.id, targetElementProps.id); // targetElementProps.id assigned by importElement
1268
+ if (targetElementProps.id === undefined) {
1269
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadElement, "targetElementProps.id should be assigned by importElement");
1270
+ }
1271
+ this.context.remapElement(sourceElement.id, targetElementProps.id);
1166
1272
  // the transformer does not currently 'split' or 'join' any elements, therefore, it does not
1167
1273
  // insert external source aspects because federation guids are sufficient for this.
1168
1274
  // Other transformer subclasses must insert the appropriate aspect (as provided by a TBD API)
@@ -1233,7 +1339,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1233
1339
  WHERE ECInstanceId=:targetModelId
1234
1340
  `;
1235
1341
  if (this.exporter.sourceDbChanges?.element.deleteIds.has(sourceModelId)) {
1236
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1342
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1237
1343
  const isDefinitionPartition = this.targetDb.withPreparedStatement(sql, (stmt) => {
1238
1344
  stmt.bindId("targetModelId", targetModelId);
1239
1345
  const val = stmt.step();
@@ -1301,9 +1407,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1301
1407
  await this.initialize();
1302
1408
  // import DefinitionModels first
1303
1409
  const childDefinitionPartitionSql = `SELECT ECInstanceId FROM ${core_backend_1.DefinitionPartition.classFullName} WHERE Parent.Id=:subjectId`;
1304
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1410
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1305
1411
  await this.sourceDb.withPreparedStatement(childDefinitionPartitionSql,
1306
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1412
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1307
1413
  async (statement) => {
1308
1414
  statement.bindId("subjectId", sourceSubjectId);
1309
1415
  while (core_bentley_1.DbResult.BE_SQLITE_ROW === statement.step()) {
@@ -1312,9 +1418,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1312
1418
  });
1313
1419
  // import other partitions next
1314
1420
  const childPartitionSql = `SELECT ECInstanceId FROM ${core_backend_1.InformationPartitionElement.classFullName} WHERE Parent.Id=:subjectId`;
1315
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1421
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1316
1422
  await this.sourceDb.withPreparedStatement(childPartitionSql,
1317
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1423
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1318
1424
  async (statement) => {
1319
1425
  statement.bindId("subjectId", sourceSubjectId);
1320
1426
  while (core_bentley_1.DbResult.BE_SQLITE_ROW === statement.step()) {
@@ -1327,9 +1433,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1327
1433
  });
1328
1434
  // recurse into child Subjects
1329
1435
  const childSubjectSql = `SELECT ECInstanceId FROM ${core_backend_1.Subject.classFullName} WHERE Parent.Id=:subjectId`;
1330
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1436
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1331
1437
  await this.sourceDb.withPreparedStatement(childSubjectSql,
1332
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1438
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1333
1439
  async (statement) => {
1334
1440
  statement.bindId("subjectId", sourceSubjectId);
1335
1441
  while (core_bentley_1.DbResult.BE_SQLITE_ROW === statement.step()) {
@@ -1351,6 +1457,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1351
1457
  id: targetModeledElementId,
1352
1458
  };
1353
1459
  targetModelProps.id = targetModeledElementId;
1460
+ if (targetModelProps.parentModel === undefined) {
1461
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadElement, "targetElementProps must have a defined parentModel");
1462
+ }
1354
1463
  targetModelProps.parentModel = this.context.findTargetElementId(targetModelProps.parentModel);
1355
1464
  return targetModelProps;
1356
1465
  }
@@ -1400,6 +1509,8 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1400
1509
  (this._startingChangesetIndices && initializeReverseSyncVersion)) {
1401
1510
  nodeAssert(this.targetDb.changeset.index !== undefined &&
1402
1511
  this._startingChangesetIndices !== undefined, "updateSynchronizationVersion was called without change history");
1512
+ // Store in a local variable, so typescript knows it's defined (due to the assert above)
1513
+ const startingChangesetIndices = this._startingChangesetIndices;
1403
1514
  const jsonProps = this._targetScopeProvenanceProps.jsonProperties;
1404
1515
  core_bentley_1.Logger.logTrace(loggerCategory, `previous pendingReverseSyncChanges: ${jsonProps.pendingReverseSyncChangesetIndices}`);
1405
1516
  core_bentley_1.Logger.logTrace(loggerCategory, `previous pendingSyncChanges: ${jsonProps.pendingSyncChangesetIndices}`);
@@ -1420,16 +1531,16 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1420
1531
  // transformation finalization, the work will be saved immediately, otherwise we've
1421
1532
  // just marked this changeset as a synchronization to ignore, and the user can add other
1422
1533
  // stuff to it which would break future synchronizations
1423
- for (let i = this._startingChangesetIndices.target + 1; i <= this.targetDb.changeset.index + 1; i++)
1534
+ for (let i = startingChangesetIndices.target + 1; i <= this.targetDb.changeset.index + 1; i++)
1424
1535
  jsonProps[syncChangesetsToUpdateKey].push(i);
1425
1536
  // Only keep the changeset indices which are greater than the source, this means they haven't been processed yet.
1426
1537
  jsonProps[syncChangesetsToClearKey] = jsonProps[syncChangesetsToClearKey].filter((csIndex) => {
1427
- return csIndex > this._startingChangesetIndices.source;
1538
+ return csIndex > startingChangesetIndices.source;
1428
1539
  });
1429
1540
  // if reverse sync then we may have received provenance changes which should be marked as sync changes
1430
1541
  if (this.isReverseSynchronization) {
1431
1542
  nodeAssert(this.sourceDb.changeset.index !== undefined, "changeset didn't exist");
1432
- for (let i = this._startingChangesetIndices.source + 1; i <= this.sourceDb.changeset.index + 1; i++)
1543
+ for (let i = startingChangesetIndices.source + 1; i <= this.sourceDb.changeset.index + 1; i++)
1433
1544
  jsonProps.pendingReverseSyncChangesetIndices.push(i);
1434
1545
  }
1435
1546
  core_bentley_1.Logger.logTrace(loggerCategory, `new pendingReverseSyncChanges: ${jsonProps.pendingReverseSyncChangesetIndices}`);
@@ -1551,9 +1662,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1551
1662
  WHERE aspect.Scope.Id=:scopeId
1552
1663
  AND aspect.Kind=:kind
1553
1664
  `;
1554
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1665
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1555
1666
  await this.targetDb.withPreparedStatement(sql,
1556
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
1667
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
1557
1668
  async (statement) => {
1558
1669
  statement.bindId("scopeId", this.targetScopeElementId);
1559
1670
  statement.bindString("kind", core_backend_1.ExternalSourceAspect.Kind.Relationship);
@@ -1685,7 +1796,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1685
1796
  nodeAssert(schemaFileName.length <= systemMaxPathSegmentSize, "Schema name was still long. This is a bug.");
1686
1797
  this._longNamedSchemasMap.set(schema.name, schemaFileName);
1687
1798
  }
1688
- /* eslint-disable-next-line deprecation/deprecation */
1799
+ /* eslint-disable-next-line @typescript-eslint/no-deprecated */
1689
1800
  this.sourceDb.exportSchema({
1690
1801
  schemaName: schema.name,
1691
1802
  outputDirectory: this._schemaExportDir,
@@ -1848,7 +1959,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1848
1959
  disableSchemaCheck: true,
1849
1960
  });
1850
1961
  const csAdaptor = new core_backend_1.ChangesetECAdaptor(csReader);
1851
- const ecChangeUnifier = new core_backend_1.PartialECChangeUnifier();
1962
+ const ecChangeUnifier = new core_backend_1.PartialECChangeUnifier(this.sourceDb);
1852
1963
  while (csAdaptor.step()) {
1853
1964
  ecChangeUnifier.appendFrom(csAdaptor);
1854
1965
  }
@@ -1957,7 +2068,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1957
2068
  const sourceIdOfRelationshipInTarget = await getTargetIdFromSourceId(sourceIdOfRelationshipInSource);
1958
2069
  const targetIdOfRelationshipInTarget = await getTargetIdFromSourceId(targetIdOfRelationshipInSource);
1959
2070
  if (sourceIdOfRelationshipInTarget && targetIdOfRelationshipInTarget) {
1960
- this._deletedSourceRelationshipData.set(changedInstanceId, {
2071
+ this._deletedSourceRelationshipData?.set(changedInstanceId, {
1961
2072
  classFullName: classFullName ?? "",
1962
2073
  sourceIdInTarget: sourceIdOfRelationshipInTarget,
1963
2074
  targetIdInTarget: targetIdOfRelationshipInTarget,
@@ -1970,7 +2081,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1970
2081
  targetId: targetIdOfRelationshipInSource,
1971
2082
  });
1972
2083
  if (relProvenance && relProvenance.relationshipId)
1973
- this._deletedSourceRelationshipData.set(changedInstanceId, {
2084
+ this._deletedSourceRelationshipData?.set(changedInstanceId, {
1974
2085
  classFullName: classFullName ?? "",
1975
2086
  relId: relProvenance.relationshipId,
1976
2087
  provenanceAspectId: relProvenance.aspectId,
@@ -1987,6 +2098,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
1987
2098
  const deletionNotInTarget = !targetId;
1988
2099
  if (deletionNotInTarget)
1989
2100
  return;
2101
+ if (targetId === undefined) {
2102
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadElement, "targetId should aquired from source id or element provenance");
2103
+ }
1990
2104
  this.context.remapElement(changedInstanceId, targetId);
1991
2105
  // If an entity insert and an entity delete both point to the same entity in target iModel, that means that entity was recreated.
1992
2106
  // In such case an entity update will be triggered and we no longer need to delete the entity.
@@ -2020,13 +2134,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
2020
2134
  const endChangesetId = this.sourceDb.changeset.id;
2021
2135
  const [startChangesetIndex, endChangesetIndex] = await Promise.all([startChangesetIndexOrId, endChangesetId].map(async (indexOrId) => typeof indexOrId === "number"
2022
2136
  ? indexOrId
2023
- : core_backend_1.BriefcaseManager
2024
- .queryChangeset({
2137
+ : core_backend_1.BriefcaseManager.queryChangeset({
2025
2138
  iModelId: this.sourceDb.iModelId,
2026
- // eslint-disable-next-line deprecation/deprecation
2139
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
2027
2140
  changeset: { id: indexOrId },
2028
- })
2029
- .then((changeset) => changeset.index)));
2141
+ }).then((changeset) => changeset.index)));
2030
2142
  const missingChangesets = startChangesetIndex > this.synchronizationVersion.index + 1;
2031
2143
  if (!this._options.argsForProcessChanges
2032
2144
  ?.ignoreMissingChangesetsInSynchronizations &&
@@ -2115,9 +2227,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
2115
2227
  await this.exporter.exportRelationships(core_backend_1.ElementRefersToElements.classFullName);
2116
2228
  if (this._options.forceExternalSourceAspectProvenance &&
2117
2229
  this.shouldDetectDeletes()) {
2118
- // eslint-disable-next-line deprecation/deprecation
2230
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
2119
2231
  await this.detectElementDeletes();
2120
- // eslint-disable-next-line deprecation/deprecation
2232
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
2121
2233
  await this.detectRelationshipDeletes();
2122
2234
  }
2123
2235
  if (this._options.optimizeGeometry)
@@ -2294,13 +2406,13 @@ class TemplateModelCloner extends IModelTransformer {
2294
2406
  targetElementProps.placement = placement;
2295
2407
  }
2296
2408
  }
2297
- this._sourceIdToTargetIdMap.set(sourceElement.id, core_bentley_1.Id64.invalid); // keep track of (source) elementIds from the template model, but the target hasn't been inserted yet
2409
+ this._sourceIdToTargetIdMap?.set(sourceElement.id, core_bentley_1.Id64.invalid); // keep track of (source) elementIds from the template model, but the target hasn't been inserted yet
2298
2410
  return targetElementProps;
2299
2411
  }
2300
2412
  }
2301
2413
  exports.TemplateModelCloner = TemplateModelCloner;
2302
2414
  function queryElemFedGuid(db, elemId) {
2303
- // eslint-disable-next-line @itwin/no-internal, deprecation/deprecation
2415
+ // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-deprecated
2304
2416
  return db.withPreparedStatement(`
2305
2417
  SELECT FederationGuid
2306
2418
  FROM bis.Element