< Summary

Information
Class: Elsa.Workflows.Management.Services.WorkflowReferenceGraphBuilder
Assembly: Elsa.Workflows.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Services/WorkflowReferenceGraphBuilder.cs
Line coverage
100%
Covered lines: 28
Uncovered lines: 0
Coverable lines: 28
Total lines: 75
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
BuildGraphAsync()100%11100%
BuildGraphAsync()100%44100%
BuildEdgesAsync()100%2020100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Services/WorkflowReferenceGraphBuilder.cs

#LineLine coverage
 1using Elsa.Workflows.Management.Models;
 2using Elsa.Workflows.Management.Options;
 3using Microsoft.Extensions.Options;
 4
 5namespace Elsa.Workflows.Management.Services;
 6
 7/// <summary>
 8/// Default implementation of <see cref="IWorkflowReferenceGraphBuilder"/> that uses <see cref="IWorkflowReferenceQuery"
 9/// to recursively build a complete graph of workflow references.
 10/// </summary>
 42411public class WorkflowReferenceGraphBuilder(IWorkflowReferenceQuery workflowReferenceQuery, IOptions<WorkflowReferenceGra
 12{
 42413    private readonly WorkflowReferenceGraphOptions _options = options.Value;
 14    /// <inheritdoc />
 15    public async Task<WorkflowReferenceGraph> BuildGraphAsync(string definitionId, CancellationToken cancellationToken =
 16    {
 1317        var edges = await BuildEdgesAsync(definitionId, cancellationToken).ToListAsync(cancellationToken);
 1318        return new([definitionId], edges);
 1319    }
 20
 21    /// <inheritdoc />
 22    public async Task<WorkflowReferenceGraph> BuildGraphAsync(IEnumerable<string> definitionIds, CancellationToken cance
 23    {
 524        var allEdges = new List<WorkflowReferenceEdge>();
 525        var visitedIds = new HashSet<string>();
 526        var rootIds = definitionIds.ToList();
 27
 2228        foreach (var definitionId in rootIds)
 29        {
 3030            await foreach (var edge in BuildEdgesAsync(definitionId, cancellationToken, visitedIds))
 31            {
 932                allEdges.Add(edge);
 33            }
 34        }
 35
 36        // Deduplicate edges
 537        var distinctEdges = allEdges.Distinct().ToList();
 38
 539        return new(rootIds, distinctEdges);
 540    }
 41
 42    private async IAsyncEnumerable<WorkflowReferenceEdge> BuildEdgesAsync(
 43        string definitionId,
 44        [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken,
 45        HashSet<string>? visitedIds = null,
 46        int currentDepth = 0)
 47    {
 5248        visitedIds ??= new();
 49
 50        // Check depth limit
 5251        if (_options.MaxDepth > 0 && currentDepth >= _options.MaxDepth)
 152            yield break;
 53
 54        // Check max definitions limit
 5155        if (_options.MaxDefinitions > 0 && visitedIds.Count >= _options.MaxDefinitions)
 156            yield break;
 57
 58        // If we've already processed this definition ID, skip it to prevent infinite recursion.
 5059        if (!visitedIds.Add(definitionId))
 660            yield break;
 61
 4462        var consumerIds = (await workflowReferenceQuery.ExecuteAsync(definitionId, cancellationToken)).ToList();
 63
 64        // For each consumer, create an edge: Consumer (Source) → definitionId (Target)
 15465        foreach (var consumerId in consumerIds)
 66        {
 3367            yield return new(Source: consumerId, Target: definitionId);
 68
 69            // Recursively process the consumer
 9870            await foreach (var childEdge in BuildEdgesAsync(consumerId, cancellationToken, visitedIds, currentDepth + 1)
 1671                yield return childEdge;
 3372        }
 5273    }
 74}
 75