public static IList <KeyExtractorNode <T> > Aggregate(IEnumerable <KeyExtractorNode <T> > source)
        {
            var aggregator = new NodeAggregator <T>();
            var result     = source
                             .GroupBy(ken => ken.Path, (path, @group) =>
                                      (Node)@group.First().ReplaceNestedNodes(
                                          new ReadOnlyCollection <BaseFieldNode>(
                                              @group.SelectMany(ken => ken.NestedNodes).ToList())))
                             .Select(aggregator.Visit)
                             .Cast <KeyExtractorNode <T> >()
                             .ToList();

            return(result);
        }
        public IEnumerator <TItem> GetEnumerator()
        {
            var currentTaskCount = sessionHandler.PrefetchTaskExecutionCount;
            var aggregatedNodes  = NodeAggregator <TItem> .Aggregate(nodes);

            var resultQueue = new Queue <TItem>();
            var container   = new StrongReferenceContainer(null);

            foreach (var item in source)
            {
                resultQueue.Enqueue(item);
                if (item != null)
                {
                    foreach (var extractorNode in aggregatedNodes)
                    {
                        container.JoinIfPossible(RegisterPrefetch(extractorNode.ExtractKeys(item), extractorNode));
                    }
                }

                if (currentTaskCount == sessionHandler.PrefetchTaskExecutionCount)
                {
                    continue;
                }

                while (container.JoinIfPossible(sessionHandler.ExecutePrefetchTasks()))
                {
                    container.JoinIfPossible(ProcessFetchedElements());
                }

                while (resultQueue.TryDequeue(out var resultItem))
                {
                    yield return(resultItem);
                }

                currentTaskCount = sessionHandler.PrefetchTaskExecutionCount;
            }

            while (container.JoinIfPossible(sessionHandler.ExecutePrefetchTasks()))
            {
                container.JoinIfPossible(ProcessFetchedElements());
            }

            while (resultQueue.TryDequeue(out var resultItem))
            {
                yield return(resultItem);
            }
        }
        public async IAsyncEnumerator <TItem> GetAsyncEnumerator(CancellationToken token = default)
        {
            var currentTaskCount = sessionHandler.PrefetchTaskExecutionCount;
            var aggregatedNodes  = NodeAggregator <TItem> .Aggregate(nodes);

            var resultQueue = new Queue <TItem>();

            strongReferenceContainer = new StrongReferenceContainer(null);
            var enumerationIdentifier = Guid.NewGuid();

            async IAsyncEnumerable <TItem> ProcessItem(TItem item1)
            {
                resultQueue.Enqueue(item1);
                if (item1 != null)
                {
                    foreach (var extractorNode in aggregatedNodes)
                    {
                        var fetchedItems =
                            await RegisterPrefetchAsync(extractorNode.ExtractKeys(item1), extractorNode, enumerationIdentifier, token).ConfigureAwait(false);

                        _ = strongReferenceContainer.JoinIfPossible(fetchedItems);
                    }
                }

                if (currentTaskCount == sessionHandler.PrefetchTaskExecutionCount)
                {
                    yield break;
                }

                while (strongReferenceContainer.JoinIfPossible(
                           await sessionHandler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false)))
                {
                    _ = strongReferenceContainer.JoinIfPossible(await ProcessFetchedElementsAsync(enumerationIdentifier, token).ConfigureAwait(false));
                }

                while (resultQueue.TryDequeue(out var resultItem))
                {
                    yield return(resultItem);
                }

                currentTaskCount = sessionHandler.PrefetchTaskExecutionCount;
            }

            if (source is IAsyncEnumerable <TItem> asyncItemSource)
            {
                await foreach (var item in asyncItemSource.WithCancellation(token).ConfigureAwait(false))
                {
                    await foreach (var p in ProcessItem(item).WithCancellation(token).ConfigureAwait(false))
                    {
                        yield return(p);
                    }
                }
            }
            else
            {
                var items = source is IQueryable <TItem> queryableSource
          ? await queryableSource.ExecuteAsync(token).ConfigureAwait(false)
          : source;

                foreach (var item in items)
                {
                    await foreach (var p in ProcessItem(item).WithCancellation(token).ConfigureAwait(false))
                    {
                        yield return(p);
                    }
                }
            }

            while (strongReferenceContainer.JoinIfPossible(
                       await sessionHandler.ExecutePrefetchTasksAsync(token).ConfigureAwait(false)))
            {
                _ = strongReferenceContainer.JoinIfPossible(await ProcessFetchedElementsAsync(enumerationIdentifier, token).ConfigureAwait(false));
            }

            while (resultQueue.TryDequeue(out var resultItem))
            {
                yield return(resultItem);
            }
        }