in source/packages/services/assetlibrary/src/types/types.full.dao.ts [491:672]
private identifyChangedRelations(
existing: TypeRelationsModel,
updated: TypeRelationsModel
): ChangedRelations {
logger.debug(
`types.full.dao identifyChangedRelations: in: existing: ${JSON.stringify(
existing
)}, updated: ${JSON.stringify(updated)}`
);
// before we diff, sort the relations. this avoids reporting any unnecessary modifications where just the ordering may have changed
const sortRelationTarget = (a: RelationTarget, b: RelationTarget) => {
const aName = isRelationTargetExpanded(a) ? a.name : a;
const bName = isRelationTargetExpanded(b) ? b.name : b;
return aName.localeCompare(bName);
};
if (existing?.in) {
for (const key of Object.keys(existing.in)) {
existing.in[key] = existing.in[key].sort(sortRelationTarget);
}
}
if (existing?.out) {
for (const key of Object.keys(existing.out)) {
existing.out[key] = existing.out[key].sort(sortRelationTarget);
}
}
if (updated?.in) {
for (const key of Object.keys(updated.in)) {
updated.in[key] = updated.in[key].sort(sortRelationTarget);
}
}
if (updated?.out) {
for (const key of Object.keys(updated.out)) {
updated.out[key] = updated.out[key].sort(sortRelationTarget);
}
}
// perform a diff of the relations so we can determine what specifically to add and remove
logger.silly(
`types.full.dao identifyChangedRelations: sorted: existing: ${JSON.stringify(
existing
)}, updated: ${JSON.stringify(updated)}`
);
const diff = jsonpatch.compare(existing, updated);
logger.silly(`types.full.dao identifyChangedRelations: diff: ${JSON.stringify(diff)}`);
// based on the changes, build up the relation changes query
const toRemove = new TypeRelationsModel();
toRemove.in = {};
toRemove.out = {};
const toAdd = new TypeRelationsModel();
toAdd.in = {};
toAdd.out = {};
const processed4Levels: string[] = [];
diff.forEach((d) => {
const p = d.path.split('/');
if (p.length === 2) {
//////////////////// entire in/out
if (d.op === 'remove') {
if (p[1] === 'in') {
for (const key of Object.keys(existing.in)) {
toRemove.in[key] = existing['in'][key];
}
} else if (p[1] === 'out') {
for (const key of Object.keys(existing.out)) {
toRemove.out[key] = existing['out'][key];
}
}
} else if (d.op === 'add') {
if (p[1] === 'in') {
for (const key of Object.keys(updated.in)) {
toAdd.in[key] = updated['in'][key];
}
} else if (p[1] === 'out') {
for (const key of Object.keys(updated.out)) {
toAdd.out[key] = updated['out'][key];
}
}
} else {
logger.warn(
`types.full.dao identifyChangedRelations: Unsupported diff op: ${JSON.stringify(
d
)}`
);
}
} else if (p.length === 3) {
//////////////////// specific relation changed
if (d.op === 'remove') {
if (p[1] === 'in') {
toRemove.in[p[2]] = existing['in'][p[2]];
} else if (p[1] === 'out') {
toRemove.out[p[2]] = existing['out'][p[2]];
}
} else if (d.op === 'add') {
if (p[1] === 'in') {
toAdd.in[p[2]] = updated['in'][p[2]];
} else if (p[1] === 'out') {
toAdd.out[p[2]] = updated['out'][p[2]];
}
} else {
logger.warn(
`types.full.dao identifyChangedRelations: Unsupported diff op: ${JSON.stringify(
d
)}`
);
}
} else if (p.length === 4) {
//////////////////// a target type of a relation has changed
// the diff output isn't great to work with for array diffs, therefore calculate the diff ourselves
if (processed4Levels.indexOf(`${p[1]}/${p[2]}`) < 0) {
processed4Levels.push(`${p[1]}/${p[2]}`);
const existingTypes =
p[1] === 'in' ? existing['in'][p[2]] : existing['out'][p[2]];
const updatedTypes =
p[1] === 'in' ? updated['in'][p[2]] : updated['out'][p[2]];
// first find removed
const findDifferences = (
sourceArray: RelationTarget[],
targetArray: RelationTarget[],
differences: TypeRelationsModel
) => {
sourceArray.forEach((source) => {
const sourceIsExpanded = isRelationTargetExpanded(source);
const indexOf = (target: RelationTarget) => {
const targetIsExpanded = isRelationTargetExpanded(target);
if (sourceIsExpanded !== targetIsExpanded) {
return false;
}
if (sourceIsExpanded) {
return (
(source as RelationTargetExpanded).name ===
(target as RelationTargetExpanded).name
);
} else {
return source === target;
}
};
if (targetArray.findIndex(indexOf) < 0) {
if (p[1] === 'in') {
if (differences.in[p[2]] === undefined) {
differences.in[p[2]] = [];
}
differences.in[p[2]].push(source);
} else {
if (differences.out[p[2]] === undefined) {
differences.out[p[2]] = [];
}
differences.out[p[2]].push(source);
}
}
});
};
if (existingTypes) {
findDifferences(existingTypes, updatedTypes, toRemove);
}
// then find added
if (updatedTypes) {
findDifferences(updatedTypes, existingTypes, toAdd);
}
}
} else {
logger.warn(
`types.full.dao identifyChangedRelations: Unsupported diff op: ${JSON.stringify(
d
)}`
);
}
});
const response = {
add: toAdd,
remove: toRemove,
};
logger.debug(`types.full.dao identifyChangedRelations: exit: ${JSON.stringify(response)}`);
return response;
}