/// <inheritdoc /> protected override async Task <IEnumerable <IDocument> > ExecuteContextAsync(IExecutionContext context) { // Create a dictionary of tree nodes TreeNodeEqualityComparer treeNodeEqualityComparer = new TreeNodeEqualityComparer(); Dictionary <string[], TreeNode> nodesDictionary = await context.Inputs .ToAsyncEnumerable() .SelectAwait(async input => new TreeNode(await _treePath.GetValueAsync(input, context), input)) .Where(x => x.TreePath != null) .Distinct(treeNodeEqualityComparer) .ToDictionaryAsync(x => x.TreePath, new TreePathEqualityComparer()); // Add links between parent and children (creating empty tree nodes as needed) Queue <TreeNode> nodesToProcess = new Queue <TreeNode>(nodesDictionary.Values); while (nodesToProcess.Count > 0) { TreeNode node = nodesToProcess.Dequeue(); // Skip root nodes if (node.TreePath.Length == 0 || (node.InputDocument != null && await _isRoot.GetValueAsync(node.InputDocument, context))) { continue; } // Skip the root node if not nesting or if collapsing the root string[] parentTreePath = node.GetParentTreePath(); if (parentTreePath.Length == 0 && (!_nesting || _collapseRoot)) { continue; } // Find (or create) the parent if (!nodesDictionary.TryGetValue(parentTreePath, out TreeNode parent)) { parent = new TreeNode(parentTreePath); nodesDictionary.Add(parentTreePath, parent); nodesToProcess.Enqueue(parent); } // Add the parent and child relationship node.Parent = parent; parent.Children.Add(node); } // Recursively generate child output documents foreach (TreeNode node in nodesDictionary.Values.Where(x => x.Parent == null)) { await node.GenerateOutputDocumentsAsync(this, context); } // Return parent nodes or all nodes depending on nesting return(nodesDictionary.Values .Where(x => (!_nesting || x.Parent == null) && x.OutputDocument != null) .Select(x => x.OutputDocument)); }
/// <inheritdoc /> public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { // Create a dictionary of tree nodes TreeNodeEqualityComparer treeNodeEqualityComparer = new TreeNodeEqualityComparer(); Dictionary <object[], TreeNode> nodes = inputs .Select(x => new TreeNode(this, x, context)) .Where(x => x.TreePath != null) .Distinct(treeNodeEqualityComparer) .ToDictionary(x => x.TreePath, new TreePathEqualityComparer()); // Add links between parent and children (creating empty tree nodes as needed) Queue <TreeNode> nodesToProcess = new Queue <TreeNode>(nodes.Values); while (nodesToProcess.Count > 0) { TreeNode node = nodesToProcess.Dequeue(); // Skip root nodes if (node.TreePath.Length == 0 || (node.InputDocument != null && _isRoot.Invoke <bool>(node.InputDocument, context))) { continue; } // Skip the root node if not nesting or if collapsing the root object[] parentTreePath = node.GetParentTreePath(); if (parentTreePath.Length == 0 && (!_nesting || _collapseRoot)) { continue; } // Find (or create) the parent TreeNode parent; if (!nodes.TryGetValue(parentTreePath, out parent)) { parent = new TreeNode(parentTreePath); nodes.Add(parentTreePath, parent); nodesToProcess.Enqueue(parent); } // Add the parent and child relationship node.Parent = parent; parent.Children.Add(node); } // Recursively generate child output documents foreach (TreeNode node in nodes.Values.Where(x => x.Parent == null)) { node.GenerateOutputDocuments(this, context); } // Return parent nodes or all nodes depending on nesting return(nodes.Values .Where(x => (!_nesting || x.Parent == null) && x.OutputDocument != null) .Select(x => x.OutputDocument)); }