@itwin/imodel-transformer 1.0.0 → 1.0.1-customchanges.2
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 +2 -2
- package/lib/cjs/IModelExporter.d.ts +90 -3
- package/lib/cjs/IModelExporter.d.ts.map +1 -1
- package/lib/cjs/IModelExporter.js +154 -19
- package/lib/cjs/IModelExporter.js.map +1 -1
- package/lib/cjs/IModelTransformer.d.ts +34 -3
- package/lib/cjs/IModelTransformer.d.ts.map +1 -1
- package/lib/cjs/IModelTransformer.js +171 -86
- package/lib/cjs/IModelTransformer.js.map +1 -1
- package/package.json +1 -1
|
@@ -1770,6 +1770,35 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1770
1770
|
await this.processChangesets();
|
|
1771
1771
|
this._initialized = true;
|
|
1772
1772
|
}
|
|
1773
|
+
async handleCustomChanges(hasElementChangedCache, deleteIdsProcessed) {
|
|
1774
|
+
// The hasElementChangedCache gets populated by changes from this._csFileProps.
|
|
1775
|
+
// Because there is a possibility that someone could manually add ids to exporter.sourceDbChanges, we must separately process exporter.sourceDbChanges and add them to our hasElementChangedCache.
|
|
1776
|
+
// Without this change we risk onExportElement returning early because we use hasElementChangedCache to decide if an element has changed or not.
|
|
1777
|
+
this.exporter.sourceDbChanges?.element.updateIds.forEach((id) => hasElementChangedCache.add(id));
|
|
1778
|
+
this.exporter.sourceDbChanges?.element.insertIds.forEach((id) => hasElementChangedCache.add(id));
|
|
1779
|
+
// This loop is to process all custom deleteIds. Unclear if the special logic is still necessary for relationships or not (TODO!!). For all other entities, we assume that the element is still present in the sourceDb because it is not
|
|
1780
|
+
// a real delete and instead a simulated delete to update filtering criteria between source and target. Since the element is still present, we do not need to call processDeletedOp to find the corresponding targetId.
|
|
1781
|
+
// We can instead rely on `forEachTrackedElement` at the top of processChangesets to find the corresponding targetId.
|
|
1782
|
+
// Note this also assumes we don't need to handle entity recreation for these custom deletes. I.e. a caller of API would not be able to add a custom delete for an entity that was recreated.
|
|
1783
|
+
// a delete followed by an insert.
|
|
1784
|
+
// ASSUME: If a changeset has a deleteId then custom change will never reference it. Is this still true if it was re-inserted? (TODO!!)
|
|
1785
|
+
if (this.exporter.sourceDbChanges?.hasCustomRelationshipChanges) {
|
|
1786
|
+
for (const id of this.exporter.sourceDbChanges?.relationship.deleteIds.keys() ??
|
|
1787
|
+
[]) {
|
|
1788
|
+
if (deleteIdsProcessed?.has(id))
|
|
1789
|
+
continue;
|
|
1790
|
+
const customData = this.exporter.sourceDbChanges?.getCustomRelationshipDataFromId(id);
|
|
1791
|
+
if (customData === undefined) {
|
|
1792
|
+
core_bentley_1.Logger.logError(loggerCategory, "Custom data not found for relationship.", { id });
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
const classFullName = customData.classFullName;
|
|
1796
|
+
const sourceIdOfRelationshipInSource = customData?.sourceIdOfRelationship;
|
|
1797
|
+
const targetIdOfRelationshipInSource = customData?.targetIdOfRelationship;
|
|
1798
|
+
await this.processRelationshipDeleteOp(id, classFullName, sourceIdOfRelationshipInSource, targetIdOfRelationshipInSource);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1773
1802
|
/**
|
|
1774
1803
|
* Reads all the changeset files in the private member of the transformer: _csFileProps and does two things with these changesets.
|
|
1775
1804
|
* Finds the corresponding target entity for any deleted source entities and remaps the sourceId to the targetId.
|
|
@@ -1781,8 +1810,15 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1781
1810
|
this.forEachTrackedElement((sourceElementId, targetElementId) => {
|
|
1782
1811
|
this.context.remapElement(sourceElementId, targetElementId);
|
|
1783
1812
|
});
|
|
1784
|
-
|
|
1785
|
-
|
|
1813
|
+
await this.addCustomChanges(this.exporter.sourceDbChanges);
|
|
1814
|
+
if (this._csFileProps === undefined || this._csFileProps.length === 0) {
|
|
1815
|
+
if (this.exporter.sourceDbChanges === undefined ||
|
|
1816
|
+
!this.exporter.sourceDbChanges.hasChanges)
|
|
1817
|
+
return;
|
|
1818
|
+
// our sourcedbChanges aren't empty (probably due to someone adding custom changes), change our sourceChangeDataState to has-changes
|
|
1819
|
+
if (this._sourceChangeDataState === "no-changes")
|
|
1820
|
+
this._sourceChangeDataState = "has-changes";
|
|
1821
|
+
}
|
|
1786
1822
|
const hasElementChangedCache = new Set();
|
|
1787
1823
|
const relationshipECClassIdsToSkip = new Set();
|
|
1788
1824
|
for await (const row of this.sourceDb.createQueryReader("SELECT ECInstanceId FROM ECDbMeta.ECClassDef where ECInstanceId IS (BisCore.ElementDrivesElement)")) {
|
|
@@ -1810,7 +1846,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1810
1846
|
alreadyImportedModelInserts.add(targetModelId);
|
|
1811
1847
|
});
|
|
1812
1848
|
this._deletedSourceRelationshipData = new Map();
|
|
1813
|
-
|
|
1849
|
+
/** a map of element ids to this transformation scope's ESA data for that element, in case the ESA is deleted in the target */
|
|
1850
|
+
const elemIdToScopeEsa = new Map();
|
|
1851
|
+
const deleteIdsProcessed = new Set();
|
|
1852
|
+
for (const csFile of this._csFileProps ?? []) {
|
|
1814
1853
|
const csReader = core_backend_1.SqliteChangesetReader.openFile({
|
|
1815
1854
|
fileName: csFile.pathname,
|
|
1816
1855
|
db: this.sourceDb,
|
|
@@ -1822,8 +1861,6 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1822
1861
|
ecChangeUnifier.appendFrom(csAdaptor);
|
|
1823
1862
|
}
|
|
1824
1863
|
const changes = [...ecChangeUnifier.instances];
|
|
1825
|
-
/** a map of element ids to this transformation scope's ESA data for that element, in case the ESA is deleted in the target */
|
|
1826
|
-
const elemIdToScopeEsa = new Map();
|
|
1827
1864
|
for (const change of changes) {
|
|
1828
1865
|
if (change.ECClassId !== undefined &&
|
|
1829
1866
|
relationshipECClassIdsToSkip.has(change.ECClassId))
|
|
@@ -1851,115 +1888,163 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1851
1888
|
if (changeType !== "Deleted" ||
|
|
1852
1889
|
relationshipECClassIdsToSkip.has(ecClassId))
|
|
1853
1890
|
continue;
|
|
1854
|
-
|
|
1891
|
+
if (relationshipECClassIds.has(ecClassId)) {
|
|
1892
|
+
if (change.$meta?.classFullName === undefined) {
|
|
1893
|
+
core_bentley_1.Logger.logError(loggerCategory, "ClassFullName was not found for relationship when reading changes. Relationship delete will not propagate.", { relationshipId: change.ECInstanceId, ecClassId });
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1896
|
+
if (change.SourceECInstanceId === undefined ||
|
|
1897
|
+
change.TargetECInstanceId === undefined) {
|
|
1898
|
+
core_bentley_1.Logger.logError(loggerCategory, "SourceECInstanceId or TargetECInstanceId was not found for relationship when reading changes. Relationship delete will not propagate.", {
|
|
1899
|
+
relationshipId: change.ECInstanceId,
|
|
1900
|
+
ecClassId,
|
|
1901
|
+
classFullName: change.$meta.classFullName,
|
|
1902
|
+
});
|
|
1903
|
+
continue;
|
|
1904
|
+
}
|
|
1905
|
+
await this.processRelationshipDeleteOp(change.ECInstanceId, change.$meta.classFullName, change.SourceECInstanceId, change.TargetECInstanceId);
|
|
1906
|
+
}
|
|
1907
|
+
else {
|
|
1908
|
+
await this.processElementDeleteOp(change.ECInstanceId, alreadyImportedElementInserts, alreadyImportedModelInserts, elemIdToScopeEsa, change.FederationGuid);
|
|
1909
|
+
}
|
|
1910
|
+
deleteIdsProcessed.add(change.ECInstanceId);
|
|
1855
1911
|
}
|
|
1856
1912
|
csReader.close();
|
|
1857
1913
|
}
|
|
1914
|
+
await this.handleCustomChanges(hasElementChangedCache, deleteIdsProcessed);
|
|
1858
1915
|
this._hasElementChangedCache = hasElementChangedCache;
|
|
1859
1916
|
return;
|
|
1860
1917
|
}
|
|
1918
|
+
/**
|
|
1919
|
+
* Helper function for processChangesets.
|
|
1920
|
+
* Populates the '_deletedSourceRelationshipData' map, whose key is the id of the relationship in the source and the value is an object used to find that relationship in the target.
|
|
1921
|
+
* @param changedInstanceId The id of the relationship that was deleted
|
|
1922
|
+
* @param classFullName classFullName of relationship
|
|
1923
|
+
* @param sourceIdOfRelationshipInSource the element Id acting as the source of the relationship in the sourceDb
|
|
1924
|
+
* @param targetIdOfRelationshipInSource the element Id acting as the target of the relationship in the sourceDb
|
|
1925
|
+
* @returns
|
|
1926
|
+
*/
|
|
1927
|
+
async processRelationshipDeleteOp(changedInstanceId, classFullName, sourceIdOfRelationshipInSource, targetIdOfRelationshipInSource) {
|
|
1928
|
+
// we need a connected iModel with changes to remap elements with deletions
|
|
1929
|
+
const notConnectedModel = this.sourceDb.iTwinId === undefined;
|
|
1930
|
+
const noChanges = this.synchronizationVersion.index === this.sourceDb.changeset.index &&
|
|
1931
|
+
(this.exporter.sourceDbChanges === undefined ||
|
|
1932
|
+
!this.exporter.sourceDbChanges.hasChanges);
|
|
1933
|
+
if (notConnectedModel || noChanges)
|
|
1934
|
+
return;
|
|
1935
|
+
const sourceIdOfRelationshipInTarget = await this.getTargetIdFromSourceId(sourceIdOfRelationshipInSource, true);
|
|
1936
|
+
const targetIdOfRelationshipInTarget = await this.getTargetIdFromSourceId(targetIdOfRelationshipInSource, true);
|
|
1937
|
+
if (sourceIdOfRelationshipInTarget && targetIdOfRelationshipInTarget) {
|
|
1938
|
+
this._deletedSourceRelationshipData.set(changedInstanceId, {
|
|
1939
|
+
classFullName,
|
|
1940
|
+
sourceIdInTarget: sourceIdOfRelationshipInTarget,
|
|
1941
|
+
targetIdInTarget: targetIdOfRelationshipInTarget,
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
else if (this.sourceDb === this.provenanceSourceDb) {
|
|
1945
|
+
const relProvenance = this._queryProvenanceForRelationship(changedInstanceId, {
|
|
1946
|
+
classFullName,
|
|
1947
|
+
sourceId: sourceIdOfRelationshipInSource,
|
|
1948
|
+
targetId: targetIdOfRelationshipInSource,
|
|
1949
|
+
});
|
|
1950
|
+
if (relProvenance && relProvenance.relationshipId)
|
|
1951
|
+
this._deletedSourceRelationshipData.set(changedInstanceId, {
|
|
1952
|
+
classFullName,
|
|
1953
|
+
relId: relProvenance.relationshipId,
|
|
1954
|
+
provenanceAspectId: relProvenance.aspectId,
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* This function is called by the transformer as it is about to process the changesets passed to it in [[IModelTransformOptions.argsForProcessChanges]].
|
|
1960
|
+
* This would be after the exporter has already processed the same set of changesets passed to the transformer in [[IModelTransformOptions.argsForProcessChanges]].
|
|
1961
|
+
* This function should be used to modify the exporter's sourceDbChanges, if necessary, using [[ChangedInstanceIds.addCustomChange]]. See [[ChangedInstanceIds.addCustomChange]] for more information.
|
|
1962
|
+
* @param sourceDbChanges will only be defined if the transformer was called with [[IModelTransformOptions.argsForProcessChanges]].
|
|
1963
|
+
* @note If defined, sourceDbChanges will already be populated with the changesets passed to the transformer, if any when this function is called by the transformer.
|
|
1964
|
+
* @note The transformer will have built up the remap table between the source and target iModels before calling this function. This means that functions like [[IModelTransformer.context.findTargetElementId]] will return meaningful results.
|
|
1965
|
+
* @note Its expected that this function be overridden by a subclass of transformer if it needs to modify sourceDbChanges.
|
|
1966
|
+
*/
|
|
1967
|
+
async addCustomChanges(_sourceDbChanges) { }
|
|
1861
1968
|
/**
|
|
1862
1969
|
* Helper function for processChangesets. Remaps the id of element deleted found in the 'change' to an element in the targetDb.
|
|
1863
1970
|
* @param change the change to process, must be of changeType "Deleted"
|
|
1864
1971
|
* @param mapOfDeletedElemIdToScopeEsas a map of elementIds to changedECInstances (which are ESAs). the elementId is not the id of the esa itself, but the elementid that the esa was stored on before the esa's deletion.
|
|
1865
1972
|
* All ESAs in this map are part of the transformer's scope / ESA data and are tracked in case the ESA is deleted in the target.
|
|
1866
|
-
* @param isRelationship is relationship or not
|
|
1867
1973
|
* @param alreadyImportedElementInserts used to handle entity recreation and not delete already handled element inserts.
|
|
1868
1974
|
* @param alreadyImportedModelInserts used to handle entity recreation and not delete already handled model inserts.
|
|
1869
1975
|
* @returns void
|
|
1870
1976
|
*/
|
|
1871
|
-
async
|
|
1977
|
+
async processElementDeleteOp(changedInstanceId, alreadyImportedElementInserts, alreadyImportedModelInserts, mapOfDeletedElemIdToScopeEsas, federationGuid) {
|
|
1872
1978
|
// we need a connected iModel with changes to remap elements with deletions
|
|
1873
1979
|
const notConnectedModel = this.sourceDb.iTwinId === undefined;
|
|
1874
|
-
const noChanges = this.synchronizationVersion.index === this.sourceDb.changeset.index
|
|
1980
|
+
const noChanges = this.synchronizationVersion.index === this.sourceDb.changeset.index &&
|
|
1981
|
+
(this.exporter.sourceDbChanges === undefined ||
|
|
1982
|
+
!this.exporter.sourceDbChanges.hasChanges);
|
|
1875
1983
|
if (notConnectedModel || noChanges)
|
|
1876
1984
|
return;
|
|
1985
|
+
let targetId = await this.getTargetIdFromSourceId(changedInstanceId, false, mapOfDeletedElemIdToScopeEsas, federationGuid);
|
|
1986
|
+
if (targetId === undefined && this.sourceDb === this.provenanceSourceDb) {
|
|
1987
|
+
targetId = this._queryProvenanceForElement(changedInstanceId);
|
|
1988
|
+
}
|
|
1989
|
+
// since we are processing one changeset at a time, we can see local source deletes
|
|
1990
|
+
// of entities that were never synced and can be safely ignored
|
|
1991
|
+
const deletionNotInTarget = !targetId;
|
|
1992
|
+
if (deletionNotInTarget)
|
|
1993
|
+
return;
|
|
1994
|
+
this.context.remapElement(changedInstanceId, targetId);
|
|
1995
|
+
// If an entity insert and an entity delete both point to the same entity in target iModel, that means that entity was recreated.
|
|
1996
|
+
// In such case an entity update will be triggered and we no longer need to delete the entity.
|
|
1997
|
+
if (alreadyImportedElementInserts.has(targetId)) {
|
|
1998
|
+
this.exporter.sourceDbChanges?.element.deleteIds.delete(changedInstanceId);
|
|
1999
|
+
}
|
|
2000
|
+
if (alreadyImportedModelInserts.has(targetId)) {
|
|
2001
|
+
this.exporter.sourceDbChanges?.model.deleteIds.delete(changedInstanceId);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* Find the corresponding id in the targetDb given a id from the sourceDb
|
|
2006
|
+
* @param id the id in the source that we want to find the target id for
|
|
2007
|
+
* @param isRelationship Changes the way we look for the federationGuid , if true we look for the federationGuid on the element itself, if false we expect it to be passed in because it was part of the ChangedECInstance.
|
|
2008
|
+
* Typically the source and targetIds of the relationship and not the relationshipId itself is passed to this function
|
|
2009
|
+
* @param mapOfDeletedElemIdToScopeEsas a map of elementIds to changedECInstances (which are ESAs). the elementId is not the id of the esa itself, but the elementid that the esa was stored on before the esa's deletion.
|
|
2010
|
+
* All ESAs in this map are part of the transformer's scope / ESA data and are tracked in case the ESA is deleted in the target.
|
|
2011
|
+
* @param federationGuid
|
|
2012
|
+
* @returns id of the corresponding entity in the targetDb or undefined if not found
|
|
2013
|
+
*/
|
|
2014
|
+
async getTargetIdFromSourceId(id, isRelationship, mapOfDeletedElemIdToScopeEsas, federationGuid) {
|
|
1877
2015
|
/**
|
|
1878
2016
|
* if our ChangedECInstance is in the provenanceDb, then we can use the ids we find in the ChangedECInstance to query for ESAs.
|
|
1879
2017
|
* This is because the ESAs are stored on an element Id thats present in the provenanceDb.
|
|
1880
2018
|
*/
|
|
1881
2019
|
const changeDataInProvenanceDb = this.sourceDb === this.provenanceDb;
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
let element;
|
|
1885
|
-
if (isRelationship) {
|
|
1886
|
-
element = this.sourceDb.elements.tryGetElement(id);
|
|
1887
|
-
}
|
|
1888
|
-
const fedGuid = isRelationship
|
|
1889
|
-
? element?.federationGuid
|
|
1890
|
-
: change.FederationGuid;
|
|
1891
|
-
if (changeDataInProvenanceDb) {
|
|
1892
|
-
// TODO: clarify what happens if there are multiple (e.g. elements were merged)
|
|
1893
|
-
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([
|
|
1894
|
-
this.targetScopeElementId,
|
|
1895
|
-
core_backend_1.ExternalSourceAspect.Kind.Element,
|
|
1896
|
-
id,
|
|
1897
|
-
]))) {
|
|
1898
|
-
identifierValue = row.Identifier;
|
|
1899
|
-
}
|
|
1900
|
-
identifierValue =
|
|
1901
|
-
identifierValue ?? mapOfDeletedElemIdToScopeEsas.get(id)?.Identifier;
|
|
1902
|
-
}
|
|
1903
|
-
// Check for targetId by an esa first
|
|
1904
|
-
if (changeDataInProvenanceDb && identifierValue) {
|
|
1905
|
-
const targetId = identifierValue;
|
|
1906
|
-
return targetId;
|
|
1907
|
-
}
|
|
1908
|
-
// Check for targetId using sourceId's fedguid if we didn't find an esa.
|
|
1909
|
-
if (fedGuid) {
|
|
1910
|
-
const targetId = this._queryElemIdByFedGuid(this.targetDb, fedGuid);
|
|
1911
|
-
return targetId;
|
|
1912
|
-
}
|
|
1913
|
-
return undefined;
|
|
1914
|
-
};
|
|
1915
|
-
const changedInstanceId = change.ECInstanceId;
|
|
2020
|
+
let identifierValue;
|
|
2021
|
+
let element;
|
|
1916
2022
|
if (isRelationship) {
|
|
1917
|
-
|
|
1918
|
-
const targetIdOfRelationshipInSource = change.TargetECInstanceId;
|
|
1919
|
-
const classFullName = change.$meta?.classFullName;
|
|
1920
|
-
const sourceIdOfRelationshipInTarget = await getTargetIdFromSourceId(sourceIdOfRelationshipInSource);
|
|
1921
|
-
const targetIdOfRelationshipInTarget = await getTargetIdFromSourceId(targetIdOfRelationshipInSource);
|
|
1922
|
-
if (sourceIdOfRelationshipInTarget && targetIdOfRelationshipInTarget) {
|
|
1923
|
-
this._deletedSourceRelationshipData.set(changedInstanceId, {
|
|
1924
|
-
classFullName: classFullName ?? "",
|
|
1925
|
-
sourceIdInTarget: sourceIdOfRelationshipInTarget,
|
|
1926
|
-
targetIdInTarget: targetIdOfRelationshipInTarget,
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
else if (this.sourceDb === this.provenanceSourceDb) {
|
|
1930
|
-
const relProvenance = this._queryProvenanceForRelationship(changedInstanceId, {
|
|
1931
|
-
classFullName: classFullName ?? "",
|
|
1932
|
-
sourceId: sourceIdOfRelationshipInSource,
|
|
1933
|
-
targetId: targetIdOfRelationshipInSource,
|
|
1934
|
-
});
|
|
1935
|
-
if (relProvenance && relProvenance.relationshipId)
|
|
1936
|
-
this._deletedSourceRelationshipData.set(changedInstanceId, {
|
|
1937
|
-
classFullName: classFullName ?? "",
|
|
1938
|
-
relId: relProvenance.relationshipId,
|
|
1939
|
-
provenanceAspectId: relProvenance.aspectId,
|
|
1940
|
-
});
|
|
1941
|
-
}
|
|
2023
|
+
element = this.sourceDb.elements.tryGetElement(id);
|
|
1942
2024
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
this.
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
if (alreadyImportedModelInserts.has(targetId)) {
|
|
1960
|
-
this.exporter.sourceDbChanges?.model.deleteIds.delete(changedInstanceId);
|
|
2025
|
+
const fedGuid = isRelationship ? element?.federationGuid : federationGuid;
|
|
2026
|
+
// Check for targetId using sourceId's fedguid
|
|
2027
|
+
if (fedGuid) {
|
|
2028
|
+
const targetId = this._queryElemIdByFedGuid(this.targetDb, fedGuid);
|
|
2029
|
+
if (targetId !== undefined)
|
|
2030
|
+
return targetId;
|
|
2031
|
+
}
|
|
2032
|
+
// Check for targetId by esa
|
|
2033
|
+
if (changeDataInProvenanceDb) {
|
|
2034
|
+
// TODO: clarify what happens if there are multiple (e.g. elements were merged)
|
|
2035
|
+
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([
|
|
2036
|
+
this.targetScopeElementId,
|
|
2037
|
+
core_backend_1.ExternalSourceAspect.Kind.Element,
|
|
2038
|
+
id,
|
|
2039
|
+
]))) {
|
|
2040
|
+
identifierValue = row.Identifier;
|
|
1961
2041
|
}
|
|
2042
|
+
identifierValue =
|
|
2043
|
+
identifierValue ?? mapOfDeletedElemIdToScopeEsas?.get(id)?.Identifier;
|
|
2044
|
+
if (identifierValue)
|
|
2045
|
+
return identifierValue;
|
|
1962
2046
|
}
|
|
2047
|
+
return undefined;
|
|
1963
2048
|
}
|
|
1964
2049
|
async _tryInitChangesetData(args) {
|
|
1965
2050
|
if (!args ||
|