@itwin/imodel-transformer 2.0.0-dev.29 → 2.0.0-dev.30
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/lib/cjs/ChangesetScanner.d.ts +60 -0
- package/lib/cjs/ChangesetScanner.d.ts.map +1 -0
- package/lib/cjs/ChangesetScanner.js +101 -0
- package/lib/cjs/ChangesetScanner.js.map +1 -0
- package/lib/cjs/IModelExporter.d.ts +4 -4
- package/lib/cjs/IModelExporter.d.ts.map +1 -1
- package/lib/cjs/IModelExporter.js +9 -41
- package/lib/cjs/IModelExporter.js.map +1 -1
- package/lib/cjs/IModelTransformer.d.ts +2 -0
- package/lib/cjs/IModelTransformer.d.ts.map +1 -1
- package/lib/cjs/IModelTransformer.js +63 -62
- package/lib/cjs/IModelTransformer.js.map +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,7 @@ const EntityUnifier_1 = require("./EntityUnifier");
|
|
|
24
24
|
const Algo_1 = require("./Algo");
|
|
25
25
|
const SyncTypeResolver_1 = require("./SyncTypeResolver");
|
|
26
26
|
const ProvenanceManager_1 = require("./ProvenanceManager");
|
|
27
|
+
const ChangesetScanner_1 = require("./ChangesetScanner");
|
|
27
28
|
const IModelTransformerError_1 = require("./IModelTransformerError");
|
|
28
29
|
const loggerCategory = TransformerLoggerCategory_1.TransformerLoggerCategory.IModelTransformer;
|
|
29
30
|
/**
|
|
@@ -1287,6 +1288,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1287
1288
|
_sourceChangeDataState = "uninited";
|
|
1288
1289
|
/** length === 0 when _changeDataState = "no-change", length > 0 means "has-changes", otherwise undefined */
|
|
1289
1290
|
_csFileProps = undefined;
|
|
1291
|
+
_deletionRecordsByChangeset;
|
|
1290
1292
|
/**
|
|
1291
1293
|
* Initialize prerequisites of processing, you must initialize with an [[InitOptions]] if you
|
|
1292
1294
|
* are intending to process changes. Callers may wish to explicitly call initialize if they need to execute code after initialize but before [[process]] is called.
|
|
@@ -1300,12 +1302,33 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1300
1302
|
await this.initScopeProvenance();
|
|
1301
1303
|
await this._tryInitChangesetData(this._options.argsForProcessChanges);
|
|
1302
1304
|
await this.context.initialize();
|
|
1303
|
-
|
|
1304
|
-
await this.
|
|
1305
|
+
const exporterInitOptions = await this.getExportInitOpts(this._options.argsForProcessChanges ?? {});
|
|
1306
|
+
await this.initializeChangesetScanAndExporter(exporterInitOptions);
|
|
1305
1307
|
// Exporter must be initialized prior to processing changesets in order to properly handle entity recreations (an entity delete followed by an insert of that same entity).
|
|
1306
1308
|
await this.processChangesets();
|
|
1307
1309
|
this._initialized = true;
|
|
1308
1310
|
}
|
|
1311
|
+
async initializeChangesetScanAndExporter(exporterInitOptions) {
|
|
1312
|
+
if (this._csFileProps !== undefined &&
|
|
1313
|
+
this._csFileProps.length > 0 &&
|
|
1314
|
+
this.sourceDb.isBriefcaseDb()) {
|
|
1315
|
+
const changedInstanceIds = this.exporter.sourceDbChanges ??
|
|
1316
|
+
("changedInstanceIds" in exporterInitOptions
|
|
1317
|
+
? exporterInitOptions.changedInstanceIds
|
|
1318
|
+
: new IModelExporter_1.ChangedInstanceIds(this.sourceDb));
|
|
1319
|
+
this._deletionRecordsByChangeset = await ChangesetScanner_1.ChangesetScanner.scan(this.sourceDb, this._csFileProps, changedInstanceIds, {
|
|
1320
|
+
populateChangedInstanceIds: this.exporter.sourceDbChanges === undefined &&
|
|
1321
|
+
!("changedInstanceIds" in exporterInitOptions),
|
|
1322
|
+
});
|
|
1323
|
+
await this.exporter.initialize({
|
|
1324
|
+
changedInstanceIds,
|
|
1325
|
+
skipPropagateChangesToRootElements: exporterInitOptions.skipPropagateChangesToRootElements,
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
await this.exporter.initialize(exporterInitOptions);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1309
1332
|
/**
|
|
1310
1333
|
* Reads all the changeset files in the private member of the transformer: _csFileProps
|
|
1311
1334
|
* and finds the corresponding target entity for any deleted source entities and remaps the sourceId to the targetId.
|
|
@@ -1318,7 +1341,8 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1318
1341
|
});
|
|
1319
1342
|
if (this.exporter.sourceDbChanges)
|
|
1320
1343
|
await this.addCustomChanges(this.exporter.sourceDbChanges);
|
|
1321
|
-
|
|
1344
|
+
const csFileProps = this._csFileProps;
|
|
1345
|
+
if (csFileProps === undefined || csFileProps.length === 0) {
|
|
1322
1346
|
if (this.exporter.sourceDbChanges === undefined ||
|
|
1323
1347
|
!this.exporter.sourceDbChanges.hasChanges)
|
|
1324
1348
|
return;
|
|
@@ -1326,6 +1350,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1326
1350
|
if (this._sourceChangeDataState === "no-changes")
|
|
1327
1351
|
this._sourceChangeDataState = "has-changes";
|
|
1328
1352
|
}
|
|
1353
|
+
const deletionRecordsByChangeset = this._deletionRecordsByChangeset;
|
|
1354
|
+
if (deletionRecordsByChangeset === undefined)
|
|
1355
|
+
return;
|
|
1329
1356
|
const relationshipECClassIdsToSkip = new Set();
|
|
1330
1357
|
for await (const row of this.sourceDb.createQueryReader("SELECT ECInstanceId FROM ECDbMeta.ECClassDef where ECInstanceId IS (BisCore.ElementDrivesElement)", undefined, { usePrimaryConn: true })) {
|
|
1331
1358
|
relationshipECClassIdsToSkip.add(row.ECInstanceId);
|
|
@@ -1348,63 +1375,25 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1348
1375
|
alreadyImportedModelInserts.add(targetModelId);
|
|
1349
1376
|
});
|
|
1350
1377
|
this._deletedSourceRelationshipData = new Map();
|
|
1351
|
-
for (const
|
|
1352
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1353
|
-
const csReader = core_backend_1.SqliteChangesetReader.openFile({
|
|
1354
|
-
fileName: csFile.pathname,
|
|
1355
|
-
db: this.sourceDb,
|
|
1356
|
-
disableSchemaCheck: true,
|
|
1357
|
-
});
|
|
1358
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1359
|
-
const csAdaptor = new core_backend_1.ChangesetECAdaptor(csReader);
|
|
1360
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1361
|
-
const ecChangeUnifier = new core_backend_1.PartialECChangeUnifier(this.sourceDb);
|
|
1362
|
-
while (csAdaptor.step()) {
|
|
1363
|
-
ecChangeUnifier.appendFrom(csAdaptor);
|
|
1364
|
-
}
|
|
1365
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1366
|
-
const changes = [...ecChangeUnifier.instances];
|
|
1378
|
+
for (const changes of deletionRecordsByChangeset) {
|
|
1367
1379
|
/** a map of element ids to this transformation scope's ESA data for that element, in case the ESA is deleted in the target */
|
|
1368
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1369
1380
|
const elemIdToScopeEsa = new Map();
|
|
1370
1381
|
for (const change of changes) {
|
|
1371
|
-
if (change.
|
|
1372
|
-
relationshipECClassIdsToSkip.has(change.ECClassId))
|
|
1382
|
+
if (relationshipECClassIdsToSkip.has(change.ecClassId))
|
|
1373
1383
|
continue;
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
change
|
|
1377
|
-
change.
|
|
1378
|
-
change.
|
|
1379
|
-
elemIdToScopeEsa.set(change.Element.Id, change);
|
|
1384
|
+
if (change.classFullName === core_backend_1.ExternalSourceAspect.classFullName &&
|
|
1385
|
+
change.scopeId === this.targetScopeElementId &&
|
|
1386
|
+
change.kind === core_backend_1.ExternalSourceAspect.Kind.Element &&
|
|
1387
|
+
change.elementId !== undefined) {
|
|
1388
|
+
elemIdToScopeEsa.set(change.elementId, change);
|
|
1380
1389
|
}
|
|
1381
1390
|
}
|
|
1382
1391
|
// Loop to process deletes.
|
|
1383
1392
|
for (const change of changes) {
|
|
1384
|
-
|
|
1385
|
-
const ecClassId = change.ECClassId ?? change.$meta?.fallbackClassId;
|
|
1386
|
-
if (ecClassId === undefined)
|
|
1387
|
-
core_bentley_1.ITwinError.throwError({
|
|
1388
|
-
iTwinErrorId: {
|
|
1389
|
-
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
1390
|
-
key: IModelTransformerError_1.IModelTransformerError.ChangedInstanceMetadataMissing,
|
|
1391
|
-
},
|
|
1392
|
-
message: `ECClassId was not found for id: ${change.ECInstanceId}! Table is : ${change?.$meta?.tables}`,
|
|
1393
|
-
});
|
|
1394
|
-
if (changeType === undefined)
|
|
1395
|
-
core_bentley_1.ITwinError.throwError({
|
|
1396
|
-
iTwinErrorId: {
|
|
1397
|
-
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
1398
|
-
key: IModelTransformerError_1.IModelTransformerError.ChangedInstanceMetadataMissing,
|
|
1399
|
-
},
|
|
1400
|
-
message: `ChangeType was undefined for id: ${change.ECInstanceId}.`,
|
|
1401
|
-
});
|
|
1402
|
-
if (changeType !== "Deleted" ||
|
|
1403
|
-
relationshipECClassIdsToSkip.has(ecClassId))
|
|
1393
|
+
if (relationshipECClassIdsToSkip.has(change.ecClassId))
|
|
1404
1394
|
continue;
|
|
1405
|
-
await this.processDeletedOp(change, elemIdToScopeEsa, relationshipECClassIds.has(ecClassId
|
|
1395
|
+
await this.processDeletedOp(change, elemIdToScopeEsa, relationshipECClassIds.has(change.ecClassId), alreadyImportedElementInserts, alreadyImportedModelInserts);
|
|
1406
1396
|
}
|
|
1407
|
-
csReader.close();
|
|
1408
1397
|
}
|
|
1409
1398
|
return;
|
|
1410
1399
|
}
|
|
@@ -1427,11 +1416,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1427
1416
|
* @param alreadyImportedModelInserts used to handle entity recreation and not delete already handled model inserts.
|
|
1428
1417
|
* @returns void
|
|
1429
1418
|
*/
|
|
1430
|
-
async processDeletedOp(
|
|
1431
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1432
|
-
change,
|
|
1433
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
1434
|
-
mapOfDeletedElemIdToScopeEsas, isRelationship, alreadyImportedElementInserts, alreadyImportedModelInserts) {
|
|
1419
|
+
async processDeletedOp(change, mapOfDeletedElemIdToScopeEsas, isRelationship, alreadyImportedElementInserts, alreadyImportedModelInserts) {
|
|
1435
1420
|
// we need a connected iModel with changes to remap elements with deletions
|
|
1436
1421
|
const notConnectedModel = this.sourceDb.iTwinId === undefined;
|
|
1437
1422
|
const noChanges = (await this.getSynchronizationVersion()).index ===
|
|
@@ -1441,7 +1426,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1441
1426
|
if (notConnectedModel || noChanges)
|
|
1442
1427
|
return;
|
|
1443
1428
|
/**
|
|
1444
|
-
*
|
|
1429
|
+
* If the deleted source entity is in the provenanceDb, then we can use its ids to query for ESAs.
|
|
1445
1430
|
* This is because the ESAs are stored on an element Id thats present in the provenanceDb.
|
|
1446
1431
|
*/
|
|
1447
1432
|
const changeDataInProvenanceDb = this.sourceDb === (await this.getProvenanceDb());
|
|
@@ -1453,7 +1438,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1453
1438
|
}
|
|
1454
1439
|
const fedGuid = isRelationship
|
|
1455
1440
|
? element?.federationGuid
|
|
1456
|
-
: change.
|
|
1441
|
+
: change.federationGuid;
|
|
1457
1442
|
if (changeDataInProvenanceDb) {
|
|
1458
1443
|
// TODO: clarify what happens if there are multiple (e.g. elements were merged)
|
|
1459
1444
|
for await (const row of this.sourceDb.createQueryReader("SELECT esa.Identifier FROM bis.ExternalSourceAspect esa WHERE Scope.Id=:scopeId AND Kind=:kind AND Element.Id=:relatedElementId LIMIT 1", core_common_1.QueryBinder.from([
|
|
@@ -1464,7 +1449,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1464
1449
|
identifierValue = row.Identifier;
|
|
1465
1450
|
}
|
|
1466
1451
|
identifierValue =
|
|
1467
|
-
identifierValue ?? mapOfDeletedElemIdToScopeEsas.get(id)?.
|
|
1452
|
+
identifierValue ?? mapOfDeletedElemIdToScopeEsas.get(id)?.identifier;
|
|
1468
1453
|
}
|
|
1469
1454
|
// Check for targetId by an esa first
|
|
1470
1455
|
if (changeDataInProvenanceDb && identifierValue) {
|
|
@@ -1478,11 +1463,21 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1478
1463
|
}
|
|
1479
1464
|
return undefined;
|
|
1480
1465
|
};
|
|
1481
|
-
const changedInstanceId = change.
|
|
1466
|
+
const changedInstanceId = change.ecInstanceId;
|
|
1482
1467
|
if (isRelationship) {
|
|
1483
|
-
const sourceIdOfRelationshipInSource = change.
|
|
1484
|
-
const targetIdOfRelationshipInSource = change.
|
|
1485
|
-
const classFullName = change
|
|
1468
|
+
const sourceIdOfRelationshipInSource = change.sourceECInstanceId;
|
|
1469
|
+
const targetIdOfRelationshipInSource = change.targetECInstanceId;
|
|
1470
|
+
const classFullName = change.classFullName;
|
|
1471
|
+
if (sourceIdOfRelationshipInSource === undefined ||
|
|
1472
|
+
targetIdOfRelationshipInSource === undefined) {
|
|
1473
|
+
core_bentley_1.ITwinError.throwError({
|
|
1474
|
+
iTwinErrorId: {
|
|
1475
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
1476
|
+
key: IModelTransformerError_1.IModelTransformerError.ChangedInstanceMetadataMissing,
|
|
1477
|
+
},
|
|
1478
|
+
message: `Relationship deletion ${changedInstanceId} is missing an endpoint.`,
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1486
1481
|
const sourceIdOfRelationshipInTarget = await getTargetIdFromSourceId(sourceIdOfRelationshipInSource);
|
|
1487
1482
|
const targetIdOfRelationshipInTarget = await getTargetIdFromSourceId(targetIdOfRelationshipInSource);
|
|
1488
1483
|
if (sourceIdOfRelationshipInTarget && targetIdOfRelationshipInTarget) {
|
|
@@ -1711,6 +1706,12 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1711
1706
|
async getExportInitOpts(opts) {
|
|
1712
1707
|
if (!this._options.argsForProcessChanges)
|
|
1713
1708
|
return {};
|
|
1709
|
+
if ("changedInstanceIds" in opts) {
|
|
1710
|
+
return {
|
|
1711
|
+
changedInstanceIds: opts.changedInstanceIds,
|
|
1712
|
+
skipPropagateChangesToRootElements: this._options.skipPropagateChangesToRootElements,
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1714
1715
|
const startChangeset = "startChangeset" in opts ? opts.startChangeset : undefined;
|
|
1715
1716
|
return {
|
|
1716
1717
|
skipPropagateChangesToRootElements: this._options.skipPropagateChangesToRootElements,
|