Implement Switch expression evaluation
This commit is contained in:
parent
b00eea3c6d
commit
094eccd572
|
|
@ -18,7 +18,7 @@ namespace Elsa.Activities.ControlFlow
|
|||
DisplayName = "Switch",
|
||||
Category = "Control Flow",
|
||||
Description = "Evaluate multiple conditions and continue execution depending on the results.",
|
||||
Outcomes = new[] { OutcomeNames.Done }
|
||||
Outcomes = new[] { OutcomeNames.Default }
|
||||
)]
|
||||
public class Switch : Activity, INotificationHandler<ScopeEvicted>
|
||||
{
|
||||
|
|
@ -55,8 +55,9 @@ namespace Elsa.Activities.ControlFlow
|
|||
}
|
||||
|
||||
var matches = Cases.Where(x => x.Condition).Select(x => x.Name).ToList();
|
||||
var results = Mode == SwitchMode.MatchFirst ? matches.Any() ? new[] { matches.First() } : new string[0] : matches.ToArray();
|
||||
var outcomes = results;
|
||||
var hasAnyMatches = matches.Any();
|
||||
var results = Mode == SwitchMode.MatchFirst ? hasAnyMatches ? new[] { matches.First() } : new string[0] : matches.ToArray();
|
||||
var outcomes = hasAnyMatches ? results : new[] { OutcomeNames.Default };
|
||||
|
||||
return Outcomes(outcomes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Serialization;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Activities.ControlFlow
|
||||
{
|
||||
public class SwitchHandler : IExpressionHandler
|
||||
{
|
||||
private readonly IContentSerializer _contentSerializer;
|
||||
public string Syntax => "Switch";
|
||||
|
||||
public SwitchHandler(IContentSerializer contentSerializer)
|
||||
{
|
||||
_contentSerializer = contentSerializer;
|
||||
}
|
||||
|
||||
public async Task<object?> EvaluateAsync(string expression, Type returnType, ActivityExecutionContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
var caseModels = TryDeserializeExpression(expression);
|
||||
var evaluatedCases = await EvaluateCasesAsync(caseModels, context, cancellationToken).ToListAsync(cancellationToken);
|
||||
return evaluatedCases;
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<SwitchCase> EvaluateCasesAsync(IEnumerable<SwitchCaseModel> caseModels, ActivityExecutionContext context, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
var validCaseModels = caseModels.Where(x => x.Expressions != null && !string.IsNullOrWhiteSpace(x.Syntax) && x.Expressions.ContainsKey(x.Syntax)).ToList();
|
||||
var evaluator = context.GetService<IExpressionEvaluator>();
|
||||
|
||||
foreach (var caseModel in validCaseModels)
|
||||
{
|
||||
var syntax = caseModel.Syntax!;
|
||||
var expression = caseModel.Expressions![syntax];
|
||||
var result = await evaluator.EvaluateAsync<bool>(expression, syntax, context, cancellationToken);
|
||||
|
||||
yield return new SwitchCase(caseModel.Name, result);
|
||||
}
|
||||
}
|
||||
|
||||
private IList<SwitchCaseModel> TryDeserializeExpression(string expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _contentSerializer.Deserialize<IList<SwitchCaseModel>>(expression);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<SwitchCaseModel>();
|
||||
}
|
||||
}
|
||||
|
||||
public record SwitchCaseModel(string Name, IDictionary<string, string>? Expressions, string? Syntax);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using Elsa;
|
||||
using Elsa.Activities.ControlFlow;
|
||||
using Elsa.Activities.Signaling;
|
||||
using Elsa.Activities.Signaling.Services;
|
||||
using Elsa.Activities.Workflows;
|
||||
|
|
@ -147,6 +148,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.TryAddProvider<IExpressionHandler, LiteralHandler>(ServiceLifetime.Singleton)
|
||||
.TryAddProvider<IExpressionHandler, VariableHandler>(ServiceLifetime.Singleton)
|
||||
.TryAddProvider<IExpressionHandler, JsonHandler>(ServiceLifetime.Singleton)
|
||||
.TryAddProvider<IExpressionHandler, SwitchHandler>(ServiceLifetime.Singleton)
|
||||
.AddScoped<IExpressionEvaluator, ExpressionEvaluator>();
|
||||
|
||||
// Workflow providers.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import {ElsaPlugin} from "../services/elsa-plugin";
|
||||
import {eventBus} from '../services/event-bus';
|
||||
import {ActivityDesignDisplayContext, EventTypes, SyntaxNames} from "../models";
|
||||
import {h} from "@stencil/core";
|
||||
import {parseJson} from "../utils/utils";
|
||||
import {SwitchCase} from "../components/editors/properties/elsa-switch-cases-property/models";
|
||||
|
||||
export class SwitchPlugin implements ElsaPlugin {
|
||||
constructor() {
|
||||
eventBus.on(EventTypes.ActivityDesignDisplaying, this.onActivityDesignDisplaying);
|
||||
}
|
||||
|
||||
onActivityDesignDisplaying(context: ActivityDesignDisplayContext) {
|
||||
const activityModel = context.activityModel;
|
||||
|
||||
if (activityModel.type !== 'Switch')
|
||||
return;
|
||||
|
||||
const props = activityModel.properties || [];
|
||||
const syntax = 'Switch';
|
||||
const casesProp = props.find(x => x.name == 'Cases') || { expressions: {'Switch': ''}, syntax: syntax };
|
||||
const expression = casesProp.expressions[syntax];
|
||||
const cases: Array<SwitchCase> = parseJson(expression) || [];
|
||||
context.outcomes = [...cases.map(x => x.name), 'Default'];
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import {DefaultDriversPlugin} from "../plugins/default-drivers-plugin";
|
|||
import {ForkPlugin} from "../plugins/fork-plugin";
|
||||
import {RunJavascriptPlugin} from "../plugins/run-javascript-plugin";
|
||||
import {ActivityIconProviderPlugin} from "../plugins/activity-icon-provider-plugin";
|
||||
import {SwitchPlugin} from "../plugins/switch-plugin";
|
||||
|
||||
export class PluginManager {
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ export class PluginManager {
|
|||
new ActivityIconProviderPlugin(),
|
||||
new IfPlugin(),
|
||||
new ForkPlugin(),
|
||||
new SwitchPlugin(),
|
||||
new HttpEndpointPlugin(),
|
||||
new TimerPlugin(),
|
||||
new WriteLinePlugin(),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddScoped<ITypeDefinitionProvider, EnumTypeDefinitionProvider>()
|
||||
.AddScoped<ITypeDefinitionProvider, EnumerableTypeDefinitionProvider>()
|
||||
.AddScoped<IJavaScriptService, JintJavaScriptEvaluator>()
|
||||
.AddTransient<IConvertsJintEvaluationResult>(s => new JintEvaluationResultConverterFactory(s).GetConverter())
|
||||
.AddTransient(s => new JintEvaluationResultConverterFactory(s).GetConverter())
|
||||
.AddTransient<IConvertsEnumerableToObject>(s => new EnumerableResultConverter(default))
|
||||
.TryAddProvider<IExpressionHandler, JavaScriptExpressionHandler>(ServiceLifetime.Scoped)
|
||||
.AddNotificationHandlers(typeof(JavaScriptServiceCollectionExtensions));
|
||||
|
|
|
|||
Loading…
Reference in a new issue