w4c-workflows-api/Services/Nodes/Executors/SwitchNodeExecutor.cs
2026-09-12 01:02:46 +03:00

69 lines
2.6 KiB
C#

using System.Text.Json.Nodes;
using w4c_workflows.Models.Nodes;
namespace w4c_workflows.Services.Nodes.Executors;
/// <summary>
/// Switch node. Evaluates an ordered rule list per item and routes the item to
/// the first matching rule's output port (port 0..3). Unmatched items go to the
/// fallback port (4) unless <c>fallbackEnabled</c> is false. Rules beyond the
/// blueprint's four rule ports are ignored.
/// </summary>
public sealed class SwitchNodeExecutor : INodeExecutor
{
/// <summary>Number of rule output ports on the blueprint (fallback is the next one).</summary>
public const int RulePorts = 4;
private const int FallbackPort = RulePorts;
public string Type => "core.switch";
public Task<NodeExecutionOutcome> RunAsync(NodeExecutionContext context, CancellationToken ct)
{
var item = context.Input(0).FirstOrDefault();
if (item == null)
return Task.FromResult(NodeExecutionOutcome.Empty);
var ports = new List<IReadOnlyList<FlowItem>>(RulePorts + 1);
for (var i = 0; i <= RulePorts; i++)
ports.Add(Array.Empty<FlowItem>());
var rules = context.Parameters["rules"] as JsonArray ?? new JsonArray();
for (var i = 0; i < rules.Count && i < RulePorts; i++)
{
if (rules[i] is not JsonObject rule)
continue;
var op = rule["operator"] is JsonValue value && value.TryGetValue<string>(out var text)
? text
: NodeConditionEvaluator.DefaultOperator;
var caseSensitive = rule["caseSensitive"] is JsonValue flag
&& flag.TryGetValue<bool>(out var cs) && cs;
bool matched;
try
{
matched = NodeConditionEvaluator.Evaluate(rule["left"], op, rule["right"], caseSensitive);
}
catch (ArgumentException ex)
{
return Task.FromResult(NodeExecutionOutcome.Failed(ex.Message, "invalid_condition"));
}
if (!matched)
continue;
ports[i] = new List<FlowItem> { item };
return Task.FromResult(new NodeExecutionOutcome { Outputs = ports });
}
if (ReadBool(context, "fallbackEnabled", defaultValue: true))
ports[FallbackPort] = new List<FlowItem> { item };
return Task.FromResult(new NodeExecutionOutcome { Outputs = ports });
}
private static bool ReadBool(NodeExecutionContext context, string name, bool defaultValue)
=> context.Parameters[name] is JsonValue value && value.TryGetValue<bool>(out var flag) ? flag : defaultValue;
}