in uui-core/src/data/processing/views/tree/treeStructure/helpers/PatchHelper.ts [93:201]
public static patch<TItem, TId>({
itemsMap: originalItemsMap,
treeStructure,
sortedPatch,
patchAtLastSort,
getItemTemporaryOrder,
isDeleted,
sorting,
sortBy,
}: PatchIntoTreeStructureOptions<TItem, TId>) {
if (!sortedPatch || !sortedPatch.size) return { treeStructure, itemsMap: originalItemsMap, newItems: [] };
const newByParentId = cloneMap(treeStructure.byParentId); // shallow clone, still need to copy arrays inside!
let patchedItemsMap = originalItemsMap;
let newItems: TItem[] = [];
const comparators = buildComparators({ sorting, sortBy, getId: treeStructure.getParams().getId });
const composedComparator = composeComparators(comparators, treeStructure.getParams().getId);
const complexIds = treeStructure.getParams().complexIds;
const parentsWithNewChildren = newMap<TId, boolean>({ complexIds });
let isUpdated = false;
for (const [patchParentId, sorted] of sortedPatch) {
patchedItemsMap = patchedItemsMap.setItems(sorted.newItems);
newItems = newItems.concat(sorted.newItems);
const itemIds = newByParentId.get(patchParentId) ?? [];
// eslint-disable-next-line no-loop-func
const isDeletedFn = (id: TId) => isDeleted?.(patchedItemsMap.get(id)) ?? false;
const [sortedItems, isUpdatedOnPatch] = this.applyPatchWithSorting(
sorted.updated,
itemIds,
{
comparator: composedComparator,
patchAtLastSort,
originalItemsMap,
patchedItemsMap,
isDeleted: isDeletedFn,
complexIds,
},
sorted.top,
);
const sortedItemsWithBottom = sortedItems.concat(sorted.bottom);
const [reorderedItems, isUpdatedOnReordering] = this.applyPatchTemporaryReordering(
sorted.withTempOrder,
sortedItemsWithBottom,
{
getItemTemporaryOrder,
patchedItemsMap,
isDeleted: isDeletedFn,
complexIds,
},
);
// eslint-disable-next-line no-loop-func
sorted.moved.forEach((id) => {
const item = treeStructure.getById(id);
if (item !== NOT_FOUND_RECORD) {
const parentId = treeStructure.getParams().getParentId?.(item) ?? undefined;
const prevItems = newByParentId.get(parentId);
newByParentId.set(parentId, prevItems.filter((itemId) => itemId !== id));
}
const newItem = patchedItemsMap.get(id);
const newParentId = treeStructure.getParams().getParentId?.(newItem) ?? undefined;
parentsWithNewChildren.set(newParentId, true);
});
newByParentId.set(patchParentId, reorderedItems);
if (isUpdatedOnReordering || isUpdatedOnPatch || sorted.top.length || sorted.bottom.length || sorted.moved.length) {
isUpdated = true;
}
}
if (!isUpdated) {
return { treeStructure, itemsMap: originalItemsMap, newItems };
}
const newNodeInfoById = cloneMap(treeStructure.nodeInfoById);
for (const [parentId, ids] of newByParentId) {
if (treeStructure.nodeInfoById.has(parentId)) {
const prevNodeInfo = treeStructure.nodeInfoById.get(parentId);
if (prevNodeInfo.count !== undefined) {
// Count, different from ids.length can be sent by server.
// After patch, it is required to add a delta of new and old children, to figure out,
// how patch affected count by adding/deleting/moving children.
const newCount = prevNodeInfo.count + (ids.length - (treeStructure.byParentId.get(parentId)?.length ?? 0));
newNodeInfoById.set(parentId, { ...prevNodeInfo, count: newCount });
} else if (parentsWithNewChildren.has(parentId)) {
const { assumedCount, ...prev } = prevNodeInfo;
newNodeInfoById.set(parentId, { ...prev, ...(assumedCount === undefined ? { count: ids.length } : { assumedCount }) });
}
} else {
newNodeInfoById.set(parentId, { count: ids.length });
}
}
return {
treeStructure: TreeStructure.create(
treeStructure.getParams(),
ItemsAccessor.toItemsAccessor(patchedItemsMap),
newByParentId,
newNodeInfoById,
),
itemsMap: patchedItemsMap,
newItems,
};
}