public static patch()

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,
        };
    }