private static async loadMissing()

in uui-core/src/data/processing/views/tree/treeStructure/helpers/FetchingHelper.ts [70:193]


    private static async loadMissing<TItem, TId, TFilter = any>({
        tree,
        options,
        dataSourceState,
    }: LoadOptionsMissing<TItem, TId, TFilter>) {
        const requiredRowsCount = dataSourceState.topIndex + dataSourceState.visibleCount;

        const byParentId = newMap<TId, TId[]>(tree.getParams());
        const nodeInfoById = newMap<TId, ITreeNodeInfo>(tree.getParams());

        const newItemsMap = newMap<TId, TItem>(tree.getParams());
        const flatten = dataSourceState.search && options.flattenSearchResults;
        const loadAllChildren: (id: TId) => LoadAllConfig = options.loadAllChildren ?? (() => ({ nestedChildren: true, children: false }));

        let newItems: TItem[] = [];
        const loadRecursive = async (
            parentId: TId,
            parent: TItem,
            { children: parentLoadAllChildren, nestedChildren: parentLoadAllNestedChildren }: LoadAllConfig,
            remainingRowsCount: number,
        ) => {
            let recursiveLoadedCount = 0;

            const { ids, nodeInfo, loadedItems } = await this.loadItems<TItem, TId, TFilter>({
                tree,
                byParentId,
                options,
                parentId,
                parent,
                dataSourceState,
                remainingRowsCount,
                loadAll: parentLoadAllChildren,
            });

            const { ids: originalIds, ...originalNodeInfo } = tree.getItems(parentId);
            const currentIds = byParentId.has(parentId) ? byParentId.get(parentId) : originalIds;

            if (ids !== currentIds
                    || nodeInfo.count !== originalNodeInfo.count
                    || nodeInfo.totalCount !== originalNodeInfo.totalCount
                    || nodeInfo.assumedCount !== originalNodeInfo.assumedCount
                    || nodeInfo.cursor !== originalNodeInfo.cursor) {
                nodeInfoById.set(parentId, nodeInfo);
            }

            byParentId.set(parentId, ids);

            recursiveLoadedCount += ids.length;
            if (loadedItems.length > 0) {
                loadedItems.forEach((item) => {
                    const id = tree.getParams().getId(item);
                    const prevNodeInfo = nodeInfoById.get(id) ?? {};
                    const assumedCount = flatten ? undefined : prevNodeInfo.assumedCount ?? tree.getParams().getChildCount?.(item);
                    nodeInfoById.set(id, { ...prevNodeInfo, ...(tree.getParams().getChildCount ? { assumedCount } : {}) });
                    newItemsMap.set(id, item);
                });
                newItems = newItems.concat(loadedItems);
            }

            if (!flatten && tree.getParams().getChildCount) {
                const childrenPromises: Promise<any>[] = [];

                for (let n = 0; n < ids.length; n++) {
                    const id = ids[n];
                    const itemInTree = tree.getById(id);
                    let item: TItem = itemInTree === NOT_FOUND_RECORD ? undefined : itemInTree;
                    if (newItemsMap.has(id)) {
                        item = newItemsMap.get(id);
                    }

                    let isFolded = false;
                    let hasChildren = false;

                    if (tree.getParams().getChildCount) {
                        // not a root node
                        const childrenCount = tree.getParams().getChildCount(item);
                        if (childrenCount) {
                            // foldable
                            isFolded = options.isFolded(item);
                            hasChildren = true;
                        }
                    }

                    const { nestedChildren, children } = loadAllChildren(id);

                    const shouldLoadAllChildren = hasChildren && children;
                    const loadAll = parentLoadAllNestedChildren ? parentLoadAllChildren || shouldLoadAllChildren : shouldLoadAllChildren;

                    remainingRowsCount--;

                    if (hasChildren && ((!isFolded && remainingRowsCount > 0) || loadAll)) {
                        const childPromise = loadRecursive(id, item, { children: loadAll, nestedChildren }, remainingRowsCount);

                        childrenPromises.push(childPromise);

                        if (options.fetchStrategy === 'sequential') {
                            const loadedCount = await childPromise;
                            remainingRowsCount -= loadedCount;
                            recursiveLoadedCount += loadedCount;
                        }
                    }
                }

                const childCounts = await Promise.all(childrenPromises);
                if (options.fetchStrategy === 'parallel') {
                    const recursiveChildrenCount = childCounts.reduce((a, b) => a + b, 0);
                    recursiveLoadedCount += recursiveChildrenCount;
                    remainingRowsCount -= recursiveChildrenCount;
                }
            }

            return recursiveLoadedCount;
        };

        await loadRecursive(undefined, undefined, loadAllChildren(undefined), requiredRowsCount);

        return {
            tree,
            loadedItemsMap: newItemsMap,
            loadedItems: newItems,
            byParentId,
            nodeInfoById,
        };
    }