Enhancements (#282)
* * fixed workflowInjection not working * added optional Inputs filter for EvaluateRuleAction * * ActionContext now supports optional inputs * Added support to pass additionalInputs to EvaluateRule Actionpull/283/head
parent
e6624621df
commit
108fa91968
|
@ -21,7 +21,6 @@ namespace RulesEngine.Data
|
|||
|
||||
modelBuilder.Entity<Workflow>(entity => {
|
||||
entity.HasKey(k => k.WorkflowName);
|
||||
entity.Ignore(b => b.WorkflowRulesToInject);
|
||||
entity.Ignore(b => b.WorkflowsToInject);
|
||||
});
|
||||
|
||||
|
|
|
@ -40,6 +40,21 @@ namespace RulesEngine.Actions
|
|||
{
|
||||
return _parentResult;
|
||||
}
|
||||
|
||||
public bool TryGetContext<T>(string name,out T output)
|
||||
{
|
||||
try
|
||||
{
|
||||
output = GetContext<T>(name);
|
||||
return true;
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
output = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public T GetContext<T>(string name)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RulesEngine.Actions
|
||||
|
@ -10,10 +13,12 @@ namespace RulesEngine.Actions
|
|||
public class EvaluateRuleAction : ActionBase
|
||||
{
|
||||
private readonly RulesEngine _ruleEngine;
|
||||
private readonly RuleExpressionParser _ruleExpressionParser;
|
||||
|
||||
public EvaluateRuleAction(RulesEngine ruleEngine)
|
||||
public EvaluateRuleAction(RulesEngine ruleEngine, RuleExpressionParser ruleExpressionParser)
|
||||
{
|
||||
_ruleEngine = ruleEngine;
|
||||
_ruleExpressionParser = ruleExpressionParser;
|
||||
}
|
||||
|
||||
internal async override ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
|
||||
|
@ -23,11 +28,11 @@ namespace RulesEngine.Actions
|
|||
List<RuleResultTree> resultList = null;
|
||||
if (includeRuleResults)
|
||||
{
|
||||
resultList = new List<RuleResultTree>(output.Results);
|
||||
resultList = new List<RuleResultTree>(output?.Results ?? new List<RuleResultTree>() { });
|
||||
resultList.AddRange(innerResult.Results);
|
||||
}
|
||||
return new ActionRuleResult {
|
||||
Output = output.Output,
|
||||
Output = output?.Output,
|
||||
Exception = innerResult.Exception,
|
||||
Results = resultList
|
||||
};
|
||||
|
@ -37,7 +42,22 @@ namespace RulesEngine.Actions
|
|||
{
|
||||
var workflowName = context.GetContext<string>("workflowName");
|
||||
var ruleName = context.GetContext<string>("ruleName");
|
||||
var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName, ruleName, ruleParameters);
|
||||
var filteredRuleParameters = new List<RuleParameter>(ruleParameters);
|
||||
if(context.TryGetContext<List<string>>("inputFilter",out var inputFilter))
|
||||
{
|
||||
filteredRuleParameters = ruleParameters.Where(c => inputFilter.Contains(c.Name)).ToList();
|
||||
}
|
||||
if (context.TryGetContext<List<ScopedParam>>("additionalInputs", out var additionalInputs))
|
||||
{
|
||||
foreach(var additionalInput in additionalInputs)
|
||||
{
|
||||
dynamic value = _ruleExpressionParser.Evaluate<object>(additionalInput.Expression, ruleParameters);
|
||||
filteredRuleParameters.Add(new RuleParameter(additionalInput.Name, value));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName, ruleName, filteredRuleParameters.ToArray());
|
||||
return ruleResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ namespace RulesEngine.Models
|
|||
/// <value>The workflow rules to inject.</value>
|
||||
[Obsolete("WorkflowRulesToInject is deprecated. Use WorkflowsToInject instead.")]
|
||||
public IEnumerable<string> WorkflowRulesToInject {
|
||||
get { return WorkflowsToInject; }
|
||||
set { WorkflowsToInject = value; }
|
||||
}
|
||||
public IEnumerable<string> WorkflowsToInject { get; set; }
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace RulesEngine
|
|||
throw new Exception($"Could not find injected Workflow: {wfname}");
|
||||
}
|
||||
|
||||
workflow.Rules.ToList().AddRange(injectedWorkflow.Rules);
|
||||
workflow.Rules = workflow.Rules.Concat(injectedWorkflow.Rules).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ namespace RulesEngine
|
|||
{
|
||||
return new Dictionary<string, Func<ActionBase>>{
|
||||
{"OutputExpression",() => new OutputExpressionAction(_ruleExpressionParser) },
|
||||
{"EvaluateRule", () => new EvaluateRuleAction(this) }
|
||||
{"EvaluateRule", () => new EvaluateRuleAction(this,_ruleExpressionParser) }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,26 @@ namespace RulesEngine.UnitTest
|
|||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteActionWorkflowAsync_SelfReferencingAction_NoFilter_ExecutesSuccessfully()
|
||||
{
|
||||
|
||||
var engine = new RulesEngine(GetWorkflowWithActions());
|
||||
var result = await engine.ExecuteActionWorkflowAsync("WorkflowWithGlobalsAndSelfRefActions", "RuleReferencingSameWorkflow", new RuleParameter[0]);
|
||||
Assert.NotNull(result);
|
||||
Assert.Null(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteActionWorkflowAsync_SelfReferencingAction_WithFilter_ExecutesSuccessfully()
|
||||
{
|
||||
|
||||
var engine = new RulesEngine(GetWorkflowWithActions());
|
||||
var result = await engine.ExecuteActionWorkflowAsync("WorkflowWithGlobalsAndSelfRefActions", "RuleReferencingSameWorkflowWithInputFilter", new RuleParameter[0]);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(4,result.Output);
|
||||
}
|
||||
|
||||
private Workflow[] GetWorkflowsWithoutActions()
|
||||
{
|
||||
var workflow1 = new Workflow {
|
||||
|
@ -104,8 +124,74 @@ namespace RulesEngine.UnitTest
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
return new[] { workflow1 };
|
||||
|
||||
var workflow2 = new Workflow {
|
||||
WorkflowName = "WorkflowWithGlobalsAndSelfRefActions",
|
||||
GlobalParams = new[] {
|
||||
new ScopedParam {
|
||||
Name = "global1",
|
||||
Expression = "\"Hello\""
|
||||
}
|
||||
},
|
||||
Rules = new[] {
|
||||
|
||||
new Rule{
|
||||
RuleName = "RuleReferencingSameWorkflow",
|
||||
Expression = "1 == 1",
|
||||
Actions = new RuleActions {
|
||||
OnSuccess = new ActionInfo{
|
||||
Name = "EvaluateRule",
|
||||
Context = new Dictionary<string, object>{
|
||||
{"workflowName", "WorkflowWithGlobalsAndSelfRefActions"},
|
||||
{"ruleName","OtherRule"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},new Rule{
|
||||
RuleName = "RuleReferencingSameWorkflowWithInputFilter",
|
||||
Expression = "1 == 1",
|
||||
Actions = new RuleActions {
|
||||
OnSuccess = new ActionInfo{
|
||||
Name = "EvaluateRule",
|
||||
Context = new Dictionary<string, object>{
|
||||
{"workflowName", "WorkflowWithGlobalsAndSelfRefActions"},
|
||||
{"ruleName","OtherRule"},
|
||||
{"inputFilter",new string[] { } },
|
||||
{"additionalInputs", new [] {
|
||||
new ScopedParam(){
|
||||
Name = "additionalValue",
|
||||
Expression = "1"
|
||||
}
|
||||
|
||||
} }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
, new Rule{
|
||||
RuleName = "OtherRule",
|
||||
Expression = "additionalValue == 1",
|
||||
Actions = new RuleActions {
|
||||
OnSuccess = new ActionInfo{
|
||||
Name = "OutputExpression",
|
||||
Context = new Dictionary<string, object>{
|
||||
{"expression", "2*2"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
return new[] { workflow1, workflow2 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ namespace RulesEngine.UnitTest
|
|||
|
||||
[Theory]
|
||||
[InlineData("rules2.json")]
|
||||
public async Task RulesEngine_InjectedRules_ReturnsListOfRuleResultTree(string ruleFileName)
|
||||
public async Task RulesEngine_InjectedRules_ContainsInjectedRules(string ruleFileName)
|
||||
{
|
||||
var re = GetRulesEngine(ruleFileName);
|
||||
|
||||
|
@ -43,9 +43,9 @@ namespace RulesEngine.UnitTest
|
|||
dynamic input2 = GetInput2();
|
||||
dynamic input3 = GetInput3();
|
||||
|
||||
var result = await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3);
|
||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<List<RuleResultTree>>(result);
|
||||
Assert.True(result.Any());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
Loading…
Reference in New Issue