* fixed namespace issue (#82)
* fixed namespace issue * added editorconfig * cleaned up files based on editorconfigpull/93/head v3.0.1
parent
2886bca157
commit
9c8b9d484e
|
@ -0,0 +1,134 @@
|
||||||
|
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\abcy\source\repos\RulesEngine codebase based on best match to current usage at 22-12-2020
|
||||||
|
# You can modify the rules from these initially generated values to suit your own policies
|
||||||
|
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
|
||||||
|
#Core editorconfig formatting - indentation
|
||||||
|
|
||||||
|
#use soft tabs (spaces) for indentation
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
#Formatting - indentation options
|
||||||
|
|
||||||
|
#indent switch case contents.
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
#indent switch labels
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
|
#Formatting - new line options
|
||||||
|
|
||||||
|
#place catch statements on a new line
|
||||||
|
csharp_new_line_before_catch = true
|
||||||
|
#place else statements on a new line
|
||||||
|
csharp_new_line_before_else = true
|
||||||
|
#require members of anonymous types to be on separate lines
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
#require members of object intializers to be on separate lines
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
#require braces to be on a new line for methods, control_blocks, and types (also known as "Allman" style)
|
||||||
|
csharp_new_line_before_open_brace = methods, control_blocks, types
|
||||||
|
|
||||||
|
#Formatting - organize using options
|
||||||
|
|
||||||
|
#do not place System.* using directives before other using directives
|
||||||
|
dotnet_sort_system_directives_first = false
|
||||||
|
|
||||||
|
#Formatting - spacing options
|
||||||
|
|
||||||
|
#require NO space between a cast and the value
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
#require a space before the colon for bases or interfaces in a type declaration
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
#require a space after a keyword in a control flow statement such as a for loop
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
#require a space before the colon for bases or interfaces in a type declaration
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
#remove space within empty argument list parentheses
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
#remove space between method call name and opening parenthesis
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
#remove space within empty parameter list parentheses for a method declaration
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
|
||||||
|
#Formatting - wrapping options
|
||||||
|
|
||||||
|
#leave code block on single line
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
#leave statements and member declarations on the same line
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
|
||||||
|
#Style - Code block preferences
|
||||||
|
|
||||||
|
#prefer curly braces even for one line of code
|
||||||
|
csharp_prefer_braces = true:suggestion
|
||||||
|
|
||||||
|
#Style - expression bodied member options
|
||||||
|
|
||||||
|
#prefer block bodies for constructors
|
||||||
|
csharp_style_expression_bodied_constructors = false:suggestion
|
||||||
|
#prefer block bodies for methods
|
||||||
|
csharp_style_expression_bodied_methods = false:suggestion
|
||||||
|
|
||||||
|
#Style - expression level options
|
||||||
|
|
||||||
|
#prefer out variables to be declared inline in the argument list of a method call when possible
|
||||||
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
|
||||||
|
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||||
|
|
||||||
|
#Style - Expression-level preferences
|
||||||
|
|
||||||
|
#prefer objects to be initialized using object initializers when possible
|
||||||
|
dotnet_style_object_initializer = true:suggestion
|
||||||
|
#prefer inferred anonymous type member names
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
|
||||||
|
|
||||||
|
#Style - implicit and explicit types
|
||||||
|
|
||||||
|
#prefer var over explicit type in all cases, unless overridden by another code style rule
|
||||||
|
csharp_style_var_elsewhere = true:suggestion
|
||||||
|
#prefer var is used to declare variables with built-in system types such as int
|
||||||
|
csharp_style_var_for_built_in_types = true:suggestion
|
||||||
|
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
|
||||||
|
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||||
|
|
||||||
|
#Style - language keyword and framework type options
|
||||||
|
|
||||||
|
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||||
|
|
||||||
|
#Style - Miscellaneous preferences
|
||||||
|
|
||||||
|
#prefer anonymous functions over local functions
|
||||||
|
csharp_style_pattern_local_over_anonymous_function = false:suggestion
|
||||||
|
|
||||||
|
#Style - modifier options
|
||||||
|
|
||||||
|
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||||
|
|
||||||
|
#Style - Modifier preferences
|
||||||
|
|
||||||
|
#when this rule is set to a list of modifiers, prefer the specified ordering.
|
||||||
|
csharp_preferred_modifier_order = public,private,internal,readonly,static,async,override,sealed:suggestion
|
||||||
|
|
||||||
|
#Style - qualification options
|
||||||
|
|
||||||
|
#prefer fields not to be prefaced with this. or Me. in Visual Basic
|
||||||
|
dotnet_style_qualification_for_field = false:suggestion
|
||||||
|
#prefer methods not to be prefaced with this. or Me. in Visual Basic
|
||||||
|
dotnet_style_qualification_for_method = false:suggestion
|
||||||
|
#prefer properties not to be prefaced with this. or Me. in Visual Basic
|
||||||
|
dotnet_style_qualification_for_property = false:suggestion
|
||||||
|
|
||||||
|
|
||||||
|
#file header
|
||||||
|
[*.{cs,vb}]
|
||||||
|
file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.
|
||||||
|
file_header_template_style = prepend:error
|
||||||
|
file_header_template_style = replace:suggestion
|
|
@ -2,9 +2,9 @@ name: "Code scanning"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ main ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ main ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 18 * * 1'
|
- cron: '0 18 * * 1'
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ name: build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ main ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master, develop ]
|
branches: [ main, develop ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [3.0.1]
|
||||||
|
- Moved ActionResult and ActionRuleResult under RulesEngine.Models namespace
|
||||||
|
|
||||||
|
|
||||||
## [3.0.0]
|
## [3.0.0]
|
||||||
### Major Enhancements
|
### Major Enhancements
|
||||||
- Added support for Actions. More details on [actions wiki](https://github.com/microsoft/RulesEngine/wiki/Actions)
|
- Added support for Actions. More details on [actions wiki](https://github.com/microsoft/RulesEngine/wiki/Actions)
|
||||||
|
|
|
@ -14,6 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp", "demo\DemoApp\Dem
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{019DF693-8442-45B4-88C3-55CB7AFCB42E}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{019DF693-8442-45B4-88C3-55CB7AFCB42E}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
CHANGELOG.md = CHANGELOG.md
|
CHANGELOG.md = CHANGELOG.md
|
||||||
global.json = global.json
|
global.json = global.json
|
||||||
README.md = README.md
|
README.md = README.md
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using BenchmarkDotNet.Attributes;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
using BenchmarkDotNet.Running;
|
using BenchmarkDotNet.Running;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
|
@ -14,7 +17,8 @@ namespace RulesEngineBenchmark
|
||||||
private readonly RulesEngine.RulesEngine rulesEngine;
|
private readonly RulesEngine.RulesEngine rulesEngine;
|
||||||
private readonly object ruleInput;
|
private readonly object ruleInput;
|
||||||
private readonly List<WorkflowRules> workflows;
|
private readonly List<WorkflowRules> workflows;
|
||||||
class ListItem
|
|
||||||
|
private class ListItem
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
|
@ -25,7 +29,9 @@ namespace RulesEngineBenchmark
|
||||||
{
|
{
|
||||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
||||||
if (files == null || files.Length == 0)
|
if (files == null || files.Length == 0)
|
||||||
|
{
|
||||||
throw new Exception("Rules not found.");
|
throw new Exception("Rules not found.");
|
||||||
|
}
|
||||||
|
|
||||||
var fileData = File.ReadAllText(files[0]);
|
var fileData = File.ReadAllText(files[0]);
|
||||||
workflows = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
workflows = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
||||||
|
@ -35,11 +41,9 @@ namespace RulesEngineBenchmark
|
||||||
EnableLocalParams = false
|
EnableLocalParams = false
|
||||||
});
|
});
|
||||||
|
|
||||||
ruleInput = new
|
ruleInput = new {
|
||||||
{
|
|
||||||
SimpleProp = "simpleProp",
|
SimpleProp = "simpleProp",
|
||||||
NestedProp = new
|
NestedProp = new {
|
||||||
{
|
|
||||||
SimpleProp = "nestedSimpleProp",
|
SimpleProp = "nestedSimpleProp",
|
||||||
ListProp = new List<ListItem>
|
ListProp = new List<ListItem>
|
||||||
{
|
{
|
||||||
|
@ -67,15 +71,15 @@ namespace RulesEngineBenchmark
|
||||||
{
|
{
|
||||||
foreach (var workflow in workflows)
|
foreach (var workflow in workflows)
|
||||||
{
|
{
|
||||||
List<RuleResultTree> resultList = rulesEngine.ExecuteAllRulesAsync(workflow.WorkflowName, ruleInput).Result;
|
_ = rulesEngine.ExecuteAllRulesAsync(workflow.WorkflowName, ruleInput).Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Program
|
public class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var summary = BenchmarkRunner.Run<REBenchmark>();
|
_ = BenchmarkRunner.Run<REBenchmark>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using Newtonsoft.Json;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
|
@ -44,13 +47,11 @@ namespace DemoApp
|
||||||
|
|
||||||
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;
|
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;
|
||||||
|
|
||||||
resultList.OnSuccess((eventName) =>
|
resultList.OnSuccess((eventName) => {
|
||||||
{
|
|
||||||
discountOffered = $"Discount offered is {eventName} % over MRP.";
|
discountOffered = $"Discount offered is {eventName} % over MRP.";
|
||||||
});
|
});
|
||||||
|
|
||||||
resultList.OnFail(() =>
|
resultList.OnFail(() => {
|
||||||
{
|
|
||||||
discountOffered = "The user is not eligible for any discount.";
|
discountOffered = "The user is not eligible for any discount.";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
using Newtonsoft.Json;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using RulesEngine.Extensions;
|
using RulesEngine.Extensions;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Dynamic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DemoApp
|
namespace DemoApp
|
||||||
{
|
{
|
||||||
class ListItem {
|
internal class ListItem
|
||||||
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -20,8 +23,7 @@ namespace DemoApp
|
||||||
Console.WriteLine($"Running {nameof(NestedInputDemo)}....");
|
Console.WriteLine($"Running {nameof(NestedInputDemo)}....");
|
||||||
var nestedInput = new {
|
var nestedInput = new {
|
||||||
SimpleProp = "simpleProp",
|
SimpleProp = "simpleProp",
|
||||||
NestedProp = new
|
NestedProp = new {
|
||||||
{
|
|
||||||
SimpleProp = "nestedSimpleProp",
|
SimpleProp = "nestedSimpleProp",
|
||||||
ListProp = new List<ListItem>
|
ListProp = new List<ListItem>
|
||||||
{
|
{
|
||||||
|
@ -42,7 +44,9 @@ namespace DemoApp
|
||||||
|
|
||||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
|
||||||
if (files == null || files.Length == 0)
|
if (files == null || files.Length == 0)
|
||||||
|
{
|
||||||
throw new Exception("Rules not found.");
|
throw new Exception("Rules not found.");
|
||||||
|
}
|
||||||
|
|
||||||
var fileData = File.ReadAllText(files[0]);
|
var fileData = File.ReadAllText(files[0]);
|
||||||
var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
|
||||||
|
@ -50,13 +54,11 @@ namespace DemoApp
|
||||||
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null);
|
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null);
|
||||||
foreach (var workflow in workflowRules)
|
foreach (var workflow in workflowRules)
|
||||||
{
|
{
|
||||||
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, nestedInput).Result;
|
var resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, nestedInput).Result;
|
||||||
|
|
||||||
resultList.OnSuccess((eventName) =>
|
resultList.OnSuccess((eventName) => {
|
||||||
{
|
|
||||||
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in succees - {eventName}");
|
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in succees - {eventName}");
|
||||||
}).OnFail(() =>
|
}).OnFail(() => {
|
||||||
{
|
|
||||||
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in failure");
|
Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in failure");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
namespace DemoApp
|
namespace DemoApp
|
||||||
{
|
{
|
||||||
static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
new BasicDemo().Run();
|
new BasicDemo().Run();
|
||||||
new NestedInputDemo().Run();
|
new NestedInputDemo().Run();
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.Models;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RulesEngine.Models;
|
|
||||||
|
|
||||||
namespace RulesEngine.Actions
|
namespace RulesEngine.Actions
|
||||||
{
|
{
|
||||||
public abstract class ActionBase
|
public abstract class ActionBase
|
||||||
{
|
{
|
||||||
internal virtual async ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters,bool includeRuleResults=false){
|
internal async virtual ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
|
||||||
ActionRuleResult result = new ActionRuleResult();
|
{
|
||||||
|
var result = new ActionRuleResult();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result.Output = await Run(context, ruleParameters);
|
result.Output = await Run(context, ruleParameters);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
result.Exception = new Exception($"Exception while executing {this.GetType().Name}: {ex.Message}",ex);
|
result.Exception = new Exception($"Exception while executing {GetType().Name}: {ex.Message}", ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if(includeRuleResults){
|
if (includeRuleResults)
|
||||||
|
{
|
||||||
result.Results = new List<RuleResultTree>()
|
result.Results = new List<RuleResultTree>()
|
||||||
{
|
{
|
||||||
context.GetParentRuleResult()
|
context.GetParentRuleResult()
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using Newtonsoft.Json;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -22,7 +25,8 @@ namespace RulesEngine.Actions
|
||||||
_parentResult = parentResult;
|
_parentResult = parentResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuleResultTree GetParentRuleResult(){
|
public RuleResultTree GetParentRuleResult()
|
||||||
|
{
|
||||||
return _parentResult;
|
return _parentResult;
|
||||||
}
|
}
|
||||||
public T GetContext<T>(string name)
|
public T GetContext<T>(string name)
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RulesEngine.Actions
|
namespace RulesEngine.Actions
|
||||||
|
@ -14,7 +17,8 @@ namespace RulesEngine.Actions
|
||||||
}
|
}
|
||||||
internal ActionFactory(IDictionary<string, Func<ActionBase>> actionRegistry) : this()
|
internal ActionFactory(IDictionary<string, Func<ActionBase>> actionRegistry) : this()
|
||||||
{
|
{
|
||||||
foreach(var kv in actionRegistry){
|
foreach (var kv in actionRegistry)
|
||||||
|
{
|
||||||
_actionRegistry.Add(kv.Key, kv.Value);
|
_actionRegistry.Add(kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RulesEngine.ExpressionBuilders;
|
|
||||||
using RulesEngine.Models;
|
|
||||||
|
|
||||||
namespace RulesEngine.Actions
|
namespace RulesEngine.Actions
|
||||||
{
|
{
|
||||||
|
@ -14,11 +16,13 @@ namespace RulesEngine.Actions
|
||||||
_ruleEngine = ruleEngine;
|
_ruleEngine = ruleEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults=false){
|
internal async override ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
|
||||||
|
{
|
||||||
var innerResult = await base.ExecuteAndReturnResultAsync(context, ruleParameters, includeRuleResults);
|
var innerResult = await base.ExecuteAndReturnResultAsync(context, ruleParameters, includeRuleResults);
|
||||||
var output = innerResult.Output as ActionRuleResult;
|
var output = innerResult.Output as ActionRuleResult;
|
||||||
List<RuleResultTree> resultList = null;
|
List<RuleResultTree> resultList = null;
|
||||||
if(includeRuleResults){
|
if (includeRuleResults)
|
||||||
|
{
|
||||||
resultList = new List<RuleResultTree>(output.Results);
|
resultList = new List<RuleResultTree>(output.Results);
|
||||||
resultList.AddRange(innerResult.Results);
|
resultList.AddRange(innerResult.Results);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +33,7 @@ namespace RulesEngine.Actions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
public async override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
||||||
{
|
{
|
||||||
var workflowName = context.GetContext<string>("workflowName");
|
var workflowName = context.GetContext<string>("workflowName");
|
||||||
var ruleName = context.GetContext<string>("ruleName");
|
var ruleName = context.GetContext<string>("ruleName");
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Collections.Generic;
|
// Copyright (c) Microsoft Corporation.
|
||||||
using System.Threading.Tasks;
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using RulesEngine.ExpressionBuilders;
|
using RulesEngine.ExpressionBuilders;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace RulesEngine.Actions
|
namespace RulesEngine.Actions
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
using System.Collections.Generic;
|
// Licensed under the MIT License.
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace RulesEngine.Enums
|
namespace RulesEngine.Enums
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
|
|
||||||
namespace RulesEngine.ExpressionBuilders
|
namespace RulesEngine.ExpressionBuilders
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using FastExpressionCompiler;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using FastExpressionCompiler;
|
|
||||||
|
|
||||||
namespace RulesEngine.ExpressionBuilders
|
namespace RulesEngine.ExpressionBuilders
|
||||||
{
|
{
|
||||||
|
@ -36,9 +39,10 @@ namespace RulesEngine.ExpressionBuilders
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression<Func<object[],T>> WrapExpression<T>(LambdaExpression expression, ParameterExpression[] parameters){
|
private Expression<Func<object[], T>> WrapExpression<T>(LambdaExpression expression, ParameterExpression[] parameters)
|
||||||
|
{
|
||||||
var argExp = Expression.Parameter(typeof(object[]), "args");
|
var argExp = Expression.Parameter(typeof(object[]), "args");
|
||||||
IEnumerable<Expression> paramExps = parameters.Select((c, i) => {
|
var paramExps = parameters.Select((c, i) => {
|
||||||
var arg = Expression.ArrayAccess(argExp, Expression.Constant(i));
|
var arg = Expression.ArrayAccess(argExp, Expression.Constant(i));
|
||||||
return (Expression)Expression.Assign(c, Expression.Convert(arg, c.Type));
|
return (Expression)Expression.Assign(c, Expression.Convert(arg, c.Type));
|
||||||
});
|
});
|
||||||
|
@ -77,7 +81,8 @@ namespace RulesEngine.ExpressionBuilders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCacheKey(string expression, RuleParameter[] ruleParameters,Type returnType){
|
private string GetCacheKey(string expression, RuleParameter[] ruleParameters, Type returnType)
|
||||||
|
{
|
||||||
var paramKey = string.Join("|", ruleParameters.Select(c => c.Type.ToString()));
|
var paramKey = string.Join("|", ruleParameters.Select(c => c.Type.ToString()));
|
||||||
var returnTypeKey = returnType?.ToString() ?? "null";
|
var returnTypeKey = returnType?.ToString() ?? "null";
|
||||||
var combined = $"Expression:{expression}-Params:{paramKey}-ReturnType:{returnTypeKey}";
|
var combined = $"Expression:{expression}-Params:{paramKey}-ReturnType:{returnTypeKey}";
|
||||||
|
|
|
@ -5,7 +5,6 @@ using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
|
||||||
|
|
||||||
namespace RulesEngine.HelperFunctions
|
namespace RulesEngine.HelperFunctions
|
||||||
{
|
{
|
||||||
|
@ -16,8 +15,7 @@ namespace RulesEngine.HelperFunctions
|
||||||
{
|
{
|
||||||
internal static RuleFunc<RuleResultTree> ToResultTree(Rule rule, IEnumerable<RuleResultTree> childRuleResults, Func<object[], bool> isSuccessFunc, string exceptionMessage = "")
|
internal static RuleFunc<RuleResultTree> ToResultTree(Rule rule, IEnumerable<RuleResultTree> childRuleResults, Func<object[], bool> isSuccessFunc, string exceptionMessage = "")
|
||||||
{
|
{
|
||||||
return (inputs) => new RuleResultTree
|
return (inputs) => new RuleResultTree {
|
||||||
{
|
|
||||||
Rule = rule,
|
Rule = rule,
|
||||||
Inputs = inputs.ToDictionary(c => c.Name, c => c.Value),
|
Inputs = inputs.ToDictionary(c => c.Name, c => c.Value),
|
||||||
IsSuccess = isSuccessFunc(inputs.Select(c => c.Value).ToArray()),
|
IsSuccess = isSuccessFunc(inputs.Select(c => c.Value).ToArray()),
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace RulesEngine.Models
|
namespace RulesEngine.Models
|
||||||
{
|
{
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
public class ActionInfo
|
public class ActionInfo
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
public class ActionResult{
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace RulesEngine.Models
|
||||||
|
{
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
public class ActionResult
|
||||||
|
{
|
||||||
public object Output { get; set; }
|
public object Output { get; set; }
|
||||||
public Exception Exception { get; set; }
|
public Exception Exception { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using RulesEngine.Models;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace RulesEngine.Models
|
||||||
public class ActionRuleResult : ActionResult{
|
{
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
public class ActionRuleResult : ActionResult
|
||||||
|
{
|
||||||
public List<RuleResultTree> Results { get; set; }
|
public List<RuleResultTree> Results { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
using System;
|
// Copyright (c) Microsoft Corporation.
|
||||||
using System.Collections.Generic;
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace RulesEngine.Models
|
namespace RulesEngine.Models
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using Newtonsoft.Json;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace RulesEngine.Models
|
namespace RulesEngine.Models
|
||||||
|
|
|
@ -6,7 +6,6 @@ using Newtonsoft.Json.Converters;
|
||||||
using RulesEngine.Enums;
|
using RulesEngine.Enums;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace RulesEngine.Models
|
namespace RulesEngine.Models
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.HelperFunctions;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using RulesEngine.HelperFunctions;
|
|
||||||
|
|
||||||
namespace RulesEngine.Models
|
namespace RulesEngine.Models
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,8 @@ namespace RulesEngine.Models
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal RuleParameter(string name,Type type){
|
internal RuleParameter(string name, Type type)
|
||||||
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using RulesEngine.Models;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.ExpressionBuilders;
|
||||||
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using RulesEngine.ExpressionBuilders;
|
|
||||||
using RulesEngine.HelperFunctions;
|
|
||||||
|
|
||||||
namespace RulesEngine
|
namespace RulesEngine
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,18 +38,8 @@ namespace RulesEngine
|
||||||
/// <exception cref="ArgumentNullException">expressionBuilderFactory</exception>
|
/// <exception cref="ArgumentNullException">expressionBuilderFactory</exception>
|
||||||
internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFactory, ILogger logger)
|
internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFactory, ILogger logger)
|
||||||
{
|
{
|
||||||
if (expressionBuilderFactory == null)
|
_logger = logger ?? throw new ArgumentNullException($"{nameof(logger)} can't be null.");
|
||||||
{
|
_expressionBuilderFactory = expressionBuilderFactory ?? throw new ArgumentNullException($"{nameof(expressionBuilderFactory)} can't be null.");
|
||||||
throw new ArgumentNullException($"{nameof(expressionBuilderFactory)} can't be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException($"{nameof(logger)} can't be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger = logger;
|
|
||||||
_expressionBuilderFactory = expressionBuilderFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -68,7 +58,7 @@ namespace RulesEngine
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(rule));
|
throw new ArgumentNullException(nameof(rule));
|
||||||
}
|
}
|
||||||
RuleFunc<RuleResultTree> ruleExpression = GetDelegateForRule(rule,ruleParams);
|
var ruleExpression = GetDelegateForRule(rule, ruleParams);
|
||||||
return ruleExpression;
|
return ruleExpression;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -89,9 +79,7 @@ namespace RulesEngine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private RuleFunc<RuleResultTree> GetDelegateForRule(Rule rule, RuleParameter[] ruleParams)
|
private RuleFunc<RuleResultTree> GetDelegateForRule(Rule rule, RuleParameter[] ruleParams)
|
||||||
{
|
{
|
||||||
ExpressionType nestedOperator;
|
if (Enum.TryParse(rule.Operator, out ExpressionType nestedOperator) && nestedOperators.Contains(nestedOperator) &&
|
||||||
|
|
||||||
if (Enum.TryParse(rule.Operator, out nestedOperator) && nestedOperators.Contains(nestedOperator) &&
|
|
||||||
rule.Rules != null && rule.Rules.Any())
|
rule.Rules != null && rule.Rules.Any())
|
||||||
{
|
{
|
||||||
return BuildNestedRuleFunc(rule, nestedOperator, ruleParams);
|
return BuildNestedRuleFunc(rule, nestedOperator, ruleParams);
|
||||||
|
@ -142,11 +130,10 @@ namespace RulesEngine
|
||||||
ruleFuncList.Add(GetDelegateForRule(r, ruleParams));
|
ruleFuncList.Add(GetDelegateForRule(r, ruleParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (paramArray) =>
|
return (paramArray) => {
|
||||||
{
|
|
||||||
var resultList = ruleFuncList.Select(fn => fn(paramArray));
|
var resultList = ruleFuncList.Select(fn => fn(paramArray));
|
||||||
Func<object[], bool> isSuccess = (p) => ApplyOperation(resultList, operation);
|
Func<object[], bool> isSuccess = (p) => ApplyOperation(resultList, operation);
|
||||||
RuleFunc<RuleResultTree> result = Helpers.ToResultTree(parentRule, resultList,isSuccess);
|
var result = Helpers.ToResultTree(parentRule, resultList, isSuccess);
|
||||||
return result(paramArray);
|
return result(paramArray);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -11,6 +10,7 @@ using Newtonsoft.Json.Linq;
|
||||||
using RulesEngine.Actions;
|
using RulesEngine.Actions;
|
||||||
using RulesEngine.Enums;
|
using RulesEngine.Enums;
|
||||||
using RulesEngine.Exceptions;
|
using RulesEngine.Exceptions;
|
||||||
|
using RulesEngine.ExpressionBuilders;
|
||||||
using RulesEngine.Interfaces;
|
using RulesEngine.Interfaces;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using RulesEngine.Validators;
|
using RulesEngine.Validators;
|
||||||
|
@ -18,7 +18,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using RulesEngine.ExpressionBuilders;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace RulesEngine
|
namespace RulesEngine
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,8 @@ namespace RulesEngine
|
||||||
{
|
{
|
||||||
var actionDictionary = GetDefaultActionRegistry();
|
var actionDictionary = GetDefaultActionRegistry();
|
||||||
var customActions = reSettings.CustomActions ?? new Dictionary<string, Func<ActionBase>>();
|
var customActions = reSettings.CustomActions ?? new Dictionary<string, Func<ActionBase>>();
|
||||||
foreach(var customAction in customActions){
|
foreach (var customAction in customActions)
|
||||||
|
{
|
||||||
actionDictionary.Add(customAction);
|
actionDictionary.Add(customAction);
|
||||||
}
|
}
|
||||||
return actionDictionary;
|
return actionDictionary;
|
||||||
|
@ -88,7 +89,7 @@ namespace RulesEngine
|
||||||
|
|
||||||
var ruleParams = new List<RuleParameter>();
|
var ruleParams = new List<RuleParameter>();
|
||||||
|
|
||||||
for (int i = 0; i < inputs.Length; i++)
|
for (var i = 0; i < inputs.Length; i++)
|
||||||
{
|
{
|
||||||
var input = inputs[i];
|
var input = inputs[i];
|
||||||
ruleParams.Add(new RuleParameter($"input{i + 1}", input));
|
ruleParams.Add(new RuleParameter($"input{i + 1}", input));
|
||||||
|
@ -106,7 +107,8 @@ namespace RulesEngine
|
||||||
public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params RuleParameter[] ruleParams)
|
public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params RuleParameter[] ruleParams)
|
||||||
{
|
{
|
||||||
var ruleResultList = ValidateWorkflowAndExecuteRule(workflowName, ruleParams);
|
var ruleResultList = ValidateWorkflowAndExecuteRule(workflowName, ruleParams);
|
||||||
foreach(var ruleResult in ruleResultList){
|
foreach (var ruleResult in ruleResultList)
|
||||||
|
{
|
||||||
var actionResult = await ExecuteActionForRuleResult(ruleResult, false);
|
var actionResult = await ExecuteActionForRuleResult(ruleResult, false);
|
||||||
ruleResult.ActionResult = new ActionResult {
|
ruleResult.ActionResult = new ActionResult {
|
||||||
Output = actionResult.Output,
|
Output = actionResult.Output,
|
||||||
|
@ -126,7 +128,7 @@ namespace RulesEngine
|
||||||
|
|
||||||
private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults = false)
|
private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults = false)
|
||||||
{
|
{
|
||||||
ActionTriggerType triggerType = resultTree?.IsSuccess == true ? ActionTriggerType.onSuccess : ActionTriggerType.onFailure;
|
var triggerType = resultTree?.IsSuccess == true ? ActionTriggerType.onSuccess : ActionTriggerType.onFailure;
|
||||||
|
|
||||||
if (resultTree?.Rule?.Actions != null && resultTree.Rule.Actions.ContainsKey(triggerType))
|
if (resultTree?.Rule?.Actions != null && resultTree.Rule.Actions.ContainsKey(triggerType))
|
||||||
{
|
{
|
||||||
|
@ -138,8 +140,7 @@ namespace RulesEngine
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//If there is no action,return output as null and return the result for rule
|
//If there is no action,return output as null and return the result for rule
|
||||||
return new ActionRuleResult
|
return new ActionRuleResult {
|
||||||
{
|
|
||||||
Output = null,
|
Output = null,
|
||||||
Results = includeRuleResults ? new List<RuleResultTree>() { resultTree } : null
|
Results = includeRuleResults ? new List<RuleResultTree>() { resultTree } : null
|
||||||
};
|
};
|
||||||
|
@ -226,9 +227,11 @@ namespace RulesEngine
|
||||||
/// </returns>
|
/// </returns>
|
||||||
private bool RegisterRule(string workflowName, params RuleParameter[] ruleParams)
|
private bool RegisterRule(string workflowName, params RuleParameter[] ruleParams)
|
||||||
{
|
{
|
||||||
string compileRulesKey = GetCompiledRulesKey(workflowName,ruleParams);
|
var compileRulesKey = GetCompiledRulesKey(workflowName, ruleParams);
|
||||||
if (_rulesCache.ContainsCompiledRules(compileRulesKey))
|
if (_rulesCache.ContainsCompiledRules(compileRulesKey))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var workflowRules = _rulesCache.GetWorkFlowRules(workflowName);
|
var workflowRules = _rulesCache.GetWorkFlowRules(workflowName);
|
||||||
if (workflowRules != null)
|
if (workflowRules != null)
|
||||||
|
@ -250,10 +253,12 @@ namespace RulesEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private RuleFunc<RuleResultTree> CompileRule(string workflowName,string ruleName,RuleParameter[] ruleParameters){
|
private RuleFunc<RuleResultTree> CompileRule(string workflowName, string ruleName, RuleParameter[] ruleParameters)
|
||||||
|
{
|
||||||
var rules = _rulesCache.GetRules(workflowName);
|
var rules = _rulesCache.GetRules(workflowName);
|
||||||
var currentRule = rules?.SingleOrDefault(c => c.RuleName == ruleName);
|
var currentRule = rules?.SingleOrDefault(c => c.RuleName == ruleName);
|
||||||
if(currentRule == null){
|
if (currentRule == null)
|
||||||
|
{
|
||||||
throw new ArgumentException($"Workflow `{workflowName}` does not contain any rule named `{ruleName}`");
|
throw new ArgumentException($"Workflow `{workflowName}` does not contain any rule named `{ruleName}`");
|
||||||
}
|
}
|
||||||
return CompileRule(workflowName, ruleParameters, currentRule);
|
return CompileRule(workflowName, ruleParameters, currentRule);
|
||||||
|
@ -261,19 +266,19 @@ namespace RulesEngine
|
||||||
|
|
||||||
private RuleFunc<RuleResultTree> CompileRule(string workflowName, RuleParameter[] ruleParams, Rule rule)
|
private RuleFunc<RuleResultTree> CompileRule(string workflowName, RuleParameter[] ruleParams, Rule rule)
|
||||||
{
|
{
|
||||||
if(!_reSettings.EnableLocalParams){
|
if (!_reSettings.EnableLocalParams)
|
||||||
|
{
|
||||||
return _ruleCompiler.CompileRule(rule, ruleParams);
|
return _ruleCompiler.CompileRule(rule, ruleParams);
|
||||||
}
|
}
|
||||||
var compiledParamsKey = GetCompiledParamsCacheKey(workflowName, rule.RuleName, ruleParams);
|
var compiledParamsKey = GetCompiledParamsCacheKey(workflowName, rule.RuleName, ruleParams);
|
||||||
IEnumerable<CompiledParam> compiledParamList = _compiledParamsCache.GetOrCreate(compiledParamsKey, (entry) => _ruleParamCompiler.CompileParamsExpression(rule, ruleParams));
|
var compiledParamList = _compiledParamsCache.GetOrCreate(compiledParamsKey, (entry) => _ruleParamCompiler.CompileParamsExpression(rule, ruleParams));
|
||||||
var compiledRuleParameters = compiledParamList?.Select(c => c.AsRuleParameter()) ?? new List<RuleParameter>();
|
var compiledRuleParameters = compiledParamList?.Select(c => c.AsRuleParameter()) ?? new List<RuleParameter>();
|
||||||
var updatedRuleParams = ruleParams?.Concat(compiledRuleParameters);
|
var updatedRuleParams = ruleParams?.Concat(compiledRuleParameters);
|
||||||
var compiledRule = _ruleCompiler.CompileRule(rule, updatedRuleParams?.ToArray());
|
var compiledRule = _ruleCompiler.CompileRule(rule, updatedRuleParams?.ToArray());
|
||||||
|
|
||||||
RuleFunc<RuleResultTree> updatedRule = (RuleParameter[] paramList) =>
|
RuleFunc<RuleResultTree> updatedRule = (RuleParameter[] paramList) => {
|
||||||
{
|
|
||||||
var inputs = paramList.AsEnumerable();
|
var inputs = paramList.AsEnumerable();
|
||||||
IEnumerable<CompiledParam> localParams = compiledParamList ?? new List<CompiledParam>();
|
var localParams = compiledParamList ?? new List<CompiledParam>();
|
||||||
var evaluatedParamList = new List<RuleParameter>();
|
var evaluatedParamList = new List<RuleParameter>();
|
||||||
foreach (var localParam in localParams)
|
foreach (var localParam in localParams)
|
||||||
{
|
{
|
||||||
|
@ -300,8 +305,8 @@ namespace RulesEngine
|
||||||
{
|
{
|
||||||
_logger.LogTrace($"Compiled rules found for {workflowName} workflow and executed");
|
_logger.LogTrace($"Compiled rules found for {workflowName} workflow and executed");
|
||||||
|
|
||||||
List<RuleResultTree> result = new List<RuleResultTree>();
|
var result = new List<RuleResultTree>();
|
||||||
string compiledRulesCacheKey = GetCompiledRulesKey(workflowName,ruleParameters);
|
var compiledRulesCacheKey = GetCompiledRulesKey(workflowName, ruleParameters);
|
||||||
foreach (var compiledRule in _rulesCache.GetCompiledRules(compiledRulesCacheKey)?.Values)
|
foreach (var compiledRule in _rulesCache.GetCompiledRules(compiledRulesCacheKey)?.Values)
|
||||||
{
|
{
|
||||||
var resultTree = compiledRule(ruleParameters);
|
var resultTree = compiledRule(ruleParameters);
|
||||||
|
@ -314,17 +319,18 @@ namespace RulesEngine
|
||||||
|
|
||||||
private string GetCompiledRulesKey(string workflowName, RuleParameter[] ruleParams)
|
private string GetCompiledRulesKey(string workflowName, RuleParameter[] ruleParams)
|
||||||
{
|
{
|
||||||
var key = $"{workflowName}-" + String.Join("-", ruleParams.Select(c => c.Type.Name));
|
var key = $"{workflowName}-" + string.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCompiledParamsCacheKey(string workflowName, string ruleName, RuleParameter[] ruleParams)
|
private string GetCompiledParamsCacheKey(string workflowName, string ruleName, RuleParameter[] ruleParams)
|
||||||
{
|
{
|
||||||
var key = $"compiledparams-{workflowName}-{ruleName}" + String.Join("-", ruleParams.Select(c => c.Type.Name));
|
var key = $"compiledparams-{workflowName}-{ruleName}" + string.Join("-", ruleParams.Select(c => c.Type.Name));
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDictionary<string,Func<ActionBase>> GetDefaultActionRegistry(){
|
private IDictionary<string, Func<ActionBase>> GetDefaultActionRegistry()
|
||||||
|
{
|
||||||
return new Dictionary<string, Func<ActionBase>>{
|
return new Dictionary<string, Func<ActionBase>>{
|
||||||
{"OutputExpression",() => new OutputExpressionAction(_ruleExpressionParser) },
|
{"OutputExpression",() => new OutputExpressionAction(_ruleExpressionParser) },
|
||||||
{"EvaluateRule", () => new EvaluateRuleAction(this) }
|
{"EvaluateRule", () => new EvaluateRuleAction(this) }
|
||||||
|
@ -338,11 +344,13 @@ namespace RulesEngine
|
||||||
/// <returns>Updated error message.</returns>
|
/// <returns>Updated error message.</returns>
|
||||||
private IEnumerable<RuleResultTree> FormatErrorMessages(IEnumerable<RuleResultTree> ruleResultList)
|
private IEnumerable<RuleResultTree> FormatErrorMessages(IEnumerable<RuleResultTree> ruleResultList)
|
||||||
{
|
{
|
||||||
if(_reSettings.EnableFormattedErrorMessage){
|
if (_reSettings.EnableFormattedErrorMessage)
|
||||||
|
{
|
||||||
foreach (var ruleResult in ruleResultList?.Where(r => !r.IsSuccess))
|
foreach (var ruleResult in ruleResultList?.Where(r => !r.IsSuccess))
|
||||||
{
|
{
|
||||||
var errorMessage = ruleResult?.Rule?.ErrorMessage;
|
var errorMessage = ruleResult?.Rule?.ErrorMessage;
|
||||||
if(errorMessage != null){
|
if (errorMessage != null)
|
||||||
|
{
|
||||||
var errorParameters = Regex.Matches(errorMessage, ParamParseRegex);
|
var errorParameters = Regex.Matches(errorMessage, ParamParseRegex);
|
||||||
|
|
||||||
var inputs = ruleResult.Inputs;
|
var inputs = ruleResult.Inputs;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<Version>3.0.0</Version>
|
<Version>3.0.1</Version>
|
||||||
<Copyright>Copyright (c) Microsoft Corporation.</Copyright>
|
<Copyright>Copyright (c) Microsoft Corporation.</Copyright>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<PackageProjectUrl>https://github.com/microsoft/RulesEngine</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/microsoft/RulesEngine</PackageProjectUrl>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using FluentValidation;
|
||||||
|
using RulesEngine.HelperFunctions;
|
||||||
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using FluentValidation;
|
|
||||||
using RulesEngine.HelperFunctions;
|
|
||||||
using RulesEngine.Models;
|
|
||||||
|
|
||||||
namespace RulesEngine.Validators
|
namespace RulesEngine.Validators
|
||||||
{
|
{
|
||||||
|
@ -19,15 +19,13 @@ namespace RulesEngine.Validators
|
||||||
RuleFor(c => c.RuleName).NotEmpty().WithMessage(Constants.RULE_NAME_NULL_ERRMSG);
|
RuleFor(c => c.RuleName).NotEmpty().WithMessage(Constants.RULE_NAME_NULL_ERRMSG);
|
||||||
|
|
||||||
//Nested expression check
|
//Nested expression check
|
||||||
When(c => c.RuleExpressionType == null,() =>
|
When(c => c.RuleExpressionType == null, () => {
|
||||||
{
|
|
||||||
RuleFor(c => c.Operator)
|
RuleFor(c => c.Operator)
|
||||||
.NotNull().WithMessage(Constants.OPERATOR_NULL_ERRMSG)
|
.NotNull().WithMessage(Constants.OPERATOR_NULL_ERRMSG)
|
||||||
.Must(op => _nestedOperators.Any(x => x.ToString().Equals(op, StringComparison.OrdinalIgnoreCase)))
|
.Must(op => _nestedOperators.Any(x => x.ToString().Equals(op, StringComparison.OrdinalIgnoreCase)))
|
||||||
.WithMessage(Constants.OPERATOR_INCORRECT_ERRMSG);
|
.WithMessage(Constants.OPERATOR_INCORRECT_ERRMSG);
|
||||||
|
|
||||||
When(c => c.Rules?.Any() != true, () =>
|
When(c => c.Rules?.Any() != true, () => {
|
||||||
{
|
|
||||||
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
||||||
})
|
})
|
||||||
.Otherwise(() => {
|
.Otherwise(() => {
|
||||||
|
@ -39,8 +37,7 @@ namespace RulesEngine.Validators
|
||||||
|
|
||||||
private void RegisterExpressionTypeRules()
|
private void RegisterExpressionTypeRules()
|
||||||
{
|
{
|
||||||
When(c => c.RuleExpressionType == RuleExpressionType.LambdaExpression, () =>
|
When(c => c.RuleExpressionType == RuleExpressionType.LambdaExpression, () => {
|
||||||
{
|
|
||||||
RuleFor(c => c.Expression).NotEmpty().WithMessage(Constants.LAMBDA_EXPRESSION_EXPRESSION_NULL_ERRMSG);
|
RuleFor(c => c.Expression).NotEmpty().WithMessage(Constants.LAMBDA_EXPRESSION_EXPRESSION_NULL_ERRMSG);
|
||||||
RuleFor(c => c.Operator).Null().WithMessage(Constants.LAMBDA_EXPRESSION_OPERATOR_ERRMSG);
|
RuleFor(c => c.Operator).Null().WithMessage(Constants.LAMBDA_EXPRESSION_OPERATOR_ERRMSG);
|
||||||
RuleFor(c => c.Rules).Null().WithMessage(Constants.LAMBDA_EXPRESSION_RULES_ERRMSG);
|
RuleFor(c => c.Rules).Null().WithMessage(Constants.LAMBDA_EXPRESSION_RULES_ERRMSG);
|
||||||
|
@ -52,7 +49,8 @@ namespace RulesEngine.Validators
|
||||||
if (rules?.Any() != true) return false;
|
if (rules?.Any() != true) return false;
|
||||||
var validator = new RuleValidator();
|
var validator = new RuleValidator();
|
||||||
var isValid = true;
|
var isValid = true;
|
||||||
foreach(var rule in rules){
|
foreach (var rule in rules)
|
||||||
|
{
|
||||||
isValid &= validator.Validate(rule).IsValid;
|
isValid &= validator.Validate(rule).IsValid;
|
||||||
if (!isValid) break;
|
if (!isValid) break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using RulesEngine.HelperFunctions;
|
using RulesEngine.HelperFunctions;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace RulesEngine.Validators
|
namespace RulesEngine.Validators
|
||||||
{
|
{
|
||||||
|
@ -13,8 +13,7 @@ namespace RulesEngine.Validators
|
||||||
public WorkflowRulesValidator()
|
public WorkflowRulesValidator()
|
||||||
{
|
{
|
||||||
RuleFor(c => c.WorkflowName).NotEmpty().WithMessage(Constants.WORKFLOW_NAME_NULL_ERRMSG);
|
RuleFor(c => c.WorkflowName).NotEmpty().WithMessage(Constants.WORKFLOW_NAME_NULL_ERRMSG);
|
||||||
When(c => c.Rules?.Any() != true, () =>
|
When(c => c.Rules?.Any() != true, () => {
|
||||||
{
|
|
||||||
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
RuleFor(c => c.WorkflowRulesToInject).NotEmpty().WithMessage(Constants.INJECT_WORKFLOW_RULES_ERRMSG);
|
||||||
}).Otherwise(() => {
|
}).Otherwise(() => {
|
||||||
var ruleValidator = new RuleValidator();
|
var ruleValidator = new RuleValidator();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using AutoFixture;
|
using AutoFixture;
|
||||||
using Moq;
|
|
||||||
using RulesEngine.Actions;
|
using RulesEngine.Actions;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.Enums;
|
||||||
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RulesEngine.Enums;
|
|
||||||
using RulesEngine.Models;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest{
|
namespace RulesEngine.UnitTest
|
||||||
|
{
|
||||||
|
|
||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
public class RulesEngineWithActionsTests{
|
public class RulesEngineWithActionsTests
|
||||||
|
{
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task WhenExpressionIsSuccess_OutputExpressionAction_ReturnsExpressionEvaluation(){
|
public async Task WhenExpressionIsSuccess_OutputExpressionAction_ReturnsExpressionEvaluation()
|
||||||
|
{
|
||||||
var engine = new RulesEngine(GetWorkflowWithActions());
|
var engine = new RulesEngine(GetWorkflowWithActions());
|
||||||
var result = await engine.ExecuteActionWorkflowAsync("ActionWorkflow", "ExpressionOutputRuleTest", new RuleParameter[0]);
|
var result = await engine.ExecuteActionWorkflowAsync("ActionWorkflow", "ExpressionOutputRuleTest", new RuleParameter[0]);
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
|
@ -50,7 +55,8 @@ namespace RulesEngine.UnitTest{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private WorkflowRules[] GetWorkflowRulesWithoutActions(){
|
private WorkflowRules[] GetWorkflowRulesWithoutActions()
|
||||||
|
{
|
||||||
var workflow1 = new WorkflowRules {
|
var workflow1 = new WorkflowRules {
|
||||||
WorkflowName = "NoActionWorkflow",
|
WorkflowName = "NoActionWorkflow",
|
||||||
Rules = new List<Rule>{
|
Rules = new List<Rule>{
|
||||||
|
@ -65,7 +71,8 @@ namespace RulesEngine.UnitTest{
|
||||||
return new[] { workflow1 };
|
return new[] { workflow1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorkflowRules[] GetWorkflowWithActions(){
|
private WorkflowRules[] GetWorkflowWithActions()
|
||||||
|
{
|
||||||
|
|
||||||
var workflow1 = new WorkflowRules {
|
var workflow1 = new WorkflowRules {
|
||||||
WorkflowName = "ActionWorkflow",
|
WorkflowName = "ActionWorkflow",
|
||||||
|
|
|
@ -2,20 +2,20 @@
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using RulesEngine.Exceptions;
|
|
||||||
using RulesEngine.Models;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using RulesEngine.Exceptions;
|
||||||
|
using RulesEngine.HelperFunctions;
|
||||||
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
using RulesEngine.HelperFunctions;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
{
|
{
|
||||||
|
@ -177,14 +177,12 @@ namespace RulesEngine.UnitTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RulesEngine_New_IncorrectJSON_ThrowsException()
|
public void RulesEngine_New_IncorrectJSON_ThrowsException()
|
||||||
{
|
{
|
||||||
Assert.Throws<RuleValidationException>(() =>
|
Assert.Throws<RuleValidationException>(() => {
|
||||||
{
|
|
||||||
var workflow = new WorkflowRules();
|
var workflow = new WorkflowRules();
|
||||||
var re = CreateRulesEngine(workflow);
|
var re = CreateRulesEngine(workflow);
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Throws<RuleValidationException>(() =>
|
Assert.Throws<RuleValidationException>(() => {
|
||||||
{
|
|
||||||
var workflow = new WorkflowRules() { WorkflowName = "test" };
|
var workflow = new WorkflowRules() { WorkflowName = "test" };
|
||||||
var re = CreateRulesEngine(workflow);
|
var re = CreateRulesEngine(workflow);
|
||||||
});
|
});
|
||||||
|
@ -263,11 +261,11 @@ namespace RulesEngine.UnitTest
|
||||||
[InlineData("rules4.json")]
|
[InlineData("rules4.json")]
|
||||||
public async Task RulesEngine_Execute_Rule_For_Nested_Rule_Params_Returns_Success(string ruleFileName)
|
public async Task RulesEngine_Execute_Rule_For_Nested_Rule_Params_Returns_Success(string ruleFileName)
|
||||||
{
|
{
|
||||||
dynamic[] inputs = GetInputs4();
|
var inputs = GetInputs4();
|
||||||
|
|
||||||
var ruleParams = new List<RuleParameter>();
|
var ruleParams = new List<RuleParameter>();
|
||||||
|
|
||||||
for (int i = 0; i < inputs.Length; i++)
|
for (var i = 0; i < inputs.Length; i++)
|
||||||
{
|
{
|
||||||
var input = inputs[i];
|
var input = inputs[i];
|
||||||
var obj = Utils.GetTypedObject(input);
|
var obj = Utils.GetTypedObject(input);
|
||||||
|
@ -276,7 +274,9 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), ruleFileName, SearchOption.AllDirectories);
|
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), ruleFileName, SearchOption.AllDirectories);
|
||||||
if (files == null || files.Length == 0)
|
if (files == null || files.Length == 0)
|
||||||
|
{
|
||||||
throw new Exception("Rules not found.");
|
throw new Exception("Rules not found.");
|
||||||
|
}
|
||||||
|
|
||||||
var fileData = File.ReadAllText(files[0]);
|
var fileData = File.ReadAllText(files[0]);
|
||||||
var bre = new RulesEngine(JsonConvert.DeserializeObject<WorkflowRules[]>(fileData), null);
|
var bre = new RulesEngine(JsonConvert.DeserializeObject<WorkflowRules[]>(fileData), null);
|
||||||
|
@ -295,7 +295,7 @@ namespace RulesEngine.UnitTest
|
||||||
var input2 = new RuleParameter("input2", GetInput2());
|
var input2 = new RuleParameter("input2", GetInput2());
|
||||||
var input3 = new RuleParameter("input3", GetInput3());
|
var input3 = new RuleParameter("input3", GetInput3());
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", input1,input2, input3);
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", input1, input2, input3);
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.Contains(result.First().ChildResults, c => c.ExceptionMessage.Contains("Unknown identifier 'input1'"));
|
Assert.Contains(result.First().ChildResults, c => c.ExceptionMessage.Contains("Unknown identifier 'input1'"));
|
||||||
|
@ -310,14 +310,18 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
dynamic input1 = new ExpandoObject();
|
dynamic input1 = new ExpandoObject();
|
||||||
if (propValue != null)
|
if (propValue != null)
|
||||||
|
{
|
||||||
input1.Property1 = propValue;
|
input1.Property1 = propValue;
|
||||||
|
}
|
||||||
|
|
||||||
if (propValue == null)
|
if (propValue == null)
|
||||||
|
{
|
||||||
input1.Property1 = null;
|
input1.Property1 = null;
|
||||||
|
}
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1",input1),new RuleParameter("utils",utils));
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1), new RuleParameter("utils", utils));
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.All(result, c => Assert.Equal(expectedResult, c.IsSuccess));
|
Assert.All(result, c => Assert.Equal(expectedResult, c.IsSuccess));
|
||||||
|
@ -338,7 +342,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.All(result, c => Assert.True(c.IsSuccess));
|
Assert.All(result, c => Assert.True(c.IsSuccess));
|
||||||
|
@ -355,7 +359,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.All(result, c => Assert.True(c.IsSuccess));
|
Assert.All(result, c => Assert.True(c.IsSuccess));
|
||||||
|
@ -372,7 +376,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.All(result, c => Assert.False(c.IsSuccess));
|
Assert.All(result, c => Assert.False(c.IsSuccess));
|
||||||
|
@ -390,9 +394,8 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
await Assert.ThrowsAsync<System.Linq.Dynamic.Core.Exceptions.ParseException>(async()=>
|
await Assert.ThrowsAsync<System.Linq.Dynamic.Core.Exceptions.ParseException>(async () => {
|
||||||
{
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +411,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var utils = new TestInstanceUtils();
|
var utils = new TestInstanceUtils();
|
||||||
|
|
||||||
List<RuleResultTree> result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
var result = await re.ExecuteAllRulesAsync("inputWorkflow", new RuleParameter("input1", input1));
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.IsType<List<RuleResultTree>>(result);
|
Assert.IsType<List<RuleResultTree>>(result);
|
||||||
Assert.All(result, c => Assert.False(c.IsSuccess));
|
Assert.All(result, c => Assert.False(c.IsSuccess));
|
||||||
|
@ -424,8 +427,7 @@ namespace RulesEngine.UnitTest
|
||||||
var filePath = Path.Combine(Directory.GetCurrentDirectory() as string, "TestData", filename);
|
var filePath = Path.Combine(Directory.GetCurrentDirectory() as string, "TestData", filename);
|
||||||
var data = File.ReadAllText(filePath);
|
var data = File.ReadAllText(filePath);
|
||||||
|
|
||||||
var injectWorkflow = new WorkflowRules
|
var injectWorkflow = new WorkflowRules {
|
||||||
{
|
|
||||||
WorkflowName = "inputWorkflowReference",
|
WorkflowName = "inputWorkflowReference",
|
||||||
WorkflowRulesToInject = new List<string> { "inputWorkflow" }
|
WorkflowRulesToInject = new List<string> { "inputWorkflow" }
|
||||||
};
|
};
|
||||||
|
@ -490,10 +492,15 @@ namespace RulesEngine.UnitTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
private class TestInstanceUtils{
|
private class TestInstanceUtils
|
||||||
public bool CheckExists(string str){
|
{
|
||||||
|
public bool CheckExists(string str)
|
||||||
|
{
|
||||||
if (str != null && str.Length > 0)
|
if (str != null && str.Length > 0)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using RulesEngine;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using Xunit;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
{
|
{
|
||||||
|
@ -13,15 +12,15 @@ namespace RulesEngine.UnitTest
|
||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
public class CustomTypeProviderTests : IDisposable
|
public class CustomTypeProviderTests : IDisposable
|
||||||
{
|
{
|
||||||
private MockRepository mockRepository;
|
private readonly MockRepository _mockRepository;
|
||||||
public CustomTypeProviderTests()
|
public CustomTypeProviderTests()
|
||||||
{
|
{
|
||||||
this.mockRepository = new MockRepository(MockBehavior.Strict);
|
_mockRepository = new MockRepository(MockBehavior.Strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.mockRepository.VerifyAll();
|
_mockRepository.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomTypeProvider CreateProvider()
|
private CustomTypeProvider CreateProvider()
|
||||||
|
@ -33,7 +32,7 @@ namespace RulesEngine.UnitTest
|
||||||
public void GetCustomTypes_StateUnderTest_ExpectedBehavior()
|
public void GetCustomTypes_StateUnderTest_ExpectedBehavior()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var unitUnderTest = this.CreateProvider();
|
var unitUnderTest = CreateProvider();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = unitUnderTest.GetCustomTypes();
|
var result = unitUnderTest.GetCustomTypes();
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using RulesEngine;
|
|
||||||
using RulesEngine.ExpressionBuilders;
|
using RulesEngine.ExpressionBuilders;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
|
@ -29,15 +27,17 @@ namespace RulesEngine.UnitTest
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Rule mainRule = new Rule();
|
var mainRule = new Rule {
|
||||||
mainRule.RuleName = "rule1";
|
RuleName = "rule1",
|
||||||
mainRule.Operator = "And";
|
Operator = "And",
|
||||||
mainRule.Rules = new List<Rule>();
|
Rules = new List<Rule>()
|
||||||
|
};
|
||||||
|
|
||||||
Rule dummyRule = new Rule();
|
var dummyRule = new Rule {
|
||||||
dummyRule.RuleName = "testRule1";
|
RuleName = "testRule1",
|
||||||
dummyRule.RuleExpressionType = RuleExpressionType.LambdaExpression;
|
RuleExpressionType = RuleExpressionType.LambdaExpression,
|
||||||
dummyRule.Expression = "RequestType == \"vod\"";
|
Expression = "RequestType == \"vod\""
|
||||||
|
};
|
||||||
|
|
||||||
mainRule.Rules.Add(dummyRule);
|
mainRule.Rules.Add(dummyRule);
|
||||||
var func = builder.BuildDelegateForRule(dummyRule, ruleParameters);
|
var func = builder.BuildDelegateForRule(dummyRule, ruleParameters);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using RulesEngine.Extensions;
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using RulesEngine.Extensions;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
|
@ -44,8 +45,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var successEventName = string.Empty;
|
var successEventName = string.Empty;
|
||||||
|
|
||||||
rulesResultTree.OnSuccess((eventName) =>
|
rulesResultTree.OnSuccess((eventName) => {
|
||||||
{
|
|
||||||
successEventName = eventName;
|
successEventName = eventName;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -85,8 +85,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var successEventName = string.Empty;
|
var successEventName = string.Empty;
|
||||||
|
|
||||||
rulesResultTree.OnSuccess((eventName) =>
|
rulesResultTree.OnSuccess((eventName) => {
|
||||||
{
|
|
||||||
successEventName = eventName;
|
successEventName = eventName;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -125,8 +124,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var successEventName = string.Empty;
|
var successEventName = string.Empty;
|
||||||
|
|
||||||
rulesResultTree.OnSuccess((eventName) =>
|
rulesResultTree.OnSuccess((eventName) => {
|
||||||
{
|
|
||||||
successEventName = eventName;
|
successEventName = eventName;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -166,8 +164,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var successEventName = true;
|
var successEventName = true;
|
||||||
|
|
||||||
rulesResultTree.OnFail(() =>
|
rulesResultTree.OnFail(() => {
|
||||||
{
|
|
||||||
successEventName = false;
|
successEventName = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -206,8 +203,7 @@ namespace RulesEngine.UnitTest
|
||||||
|
|
||||||
var successEventName = true;
|
var successEventName = true;
|
||||||
|
|
||||||
rulesResultTree.OnFail(() =>
|
rulesResultTree.OnFail(() => {
|
||||||
{
|
|
||||||
successEventName = false;
|
successEventName = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
using RulesEngine;
|
|
||||||
using RulesEngine.ExpressionBuilders;
|
using RulesEngine.ExpressionBuilders;
|
||||||
using RulesEngine.Models;
|
using RulesEngine.Models;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using Newtonsoft.Json;
|
// Copyright (c) Microsoft Corporation.
|
||||||
using System;
|
// Licensed under the MIT License.
|
||||||
using System.Collections.Generic;
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
using System.Text;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace RulesEngine.UnitTest
|
namespace RulesEngine.UnitTest
|
||||||
|
@ -14,8 +13,8 @@ namespace RulesEngine.UnitTest
|
||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
public class TestClass
|
public class TestClass
|
||||||
{
|
{
|
||||||
public string test { get; set; }
|
public string Test { get; set; }
|
||||||
public List<int> testList { get; set; }
|
public List<int> TestList { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Trait("Category", "Unit")]
|
[Trait("Category", "Unit")]
|
||||||
|
@ -27,26 +26,26 @@ namespace RulesEngine.UnitTest
|
||||||
public void GetTypedObject_dynamicObject()
|
public void GetTypedObject_dynamicObject()
|
||||||
{
|
{
|
||||||
dynamic obj = new ExpandoObject();
|
dynamic obj = new ExpandoObject();
|
||||||
obj.test = "hello";
|
obj.Test = "hello";
|
||||||
obj.testList = new List<int> { 1, 2, 3 };
|
obj.TestList = new List<int> { 1, 2, 3 };
|
||||||
object typedobj = Utils.GetTypedObject(obj);
|
object typedobj = Utils.GetTypedObject(obj);
|
||||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetTypedObject_dynamicObject_multipleObjects()
|
public void GetTypedObject_dynamicObject_multipleObjects()
|
||||||
{
|
{
|
||||||
dynamic obj = new ExpandoObject();
|
dynamic obj = new ExpandoObject();
|
||||||
obj.test = "hello";
|
obj.Test = "hello";
|
||||||
obj.testList = new List<int> { 1, 2, 3 };
|
obj.TestList = new List<int> { 1, 2, 3 };
|
||||||
dynamic obj2 = new ExpandoObject();
|
dynamic obj2 = new ExpandoObject();
|
||||||
obj2.test = "world";
|
obj2.Test = "world";
|
||||||
obj2.testList = new List<int> { 1, 2, 3 };
|
obj2.TestList = new List<int> { 1, 2, 3 };
|
||||||
object typedobj = Utils.GetTypedObject(obj);
|
object typedobj = Utils.GetTypedObject(obj);
|
||||||
object typedobj2 = Utils.GetTypedObject(obj2);
|
object typedobj2 = Utils.GetTypedObject(obj2);
|
||||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||||
Assert.Equal(typedobj.GetType(), typedobj2.GetType());
|
Assert.Equal(typedobj.GetType(), typedobj2.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,23 +54,23 @@ namespace RulesEngine.UnitTest
|
||||||
public void GetTypedObject_nonDynamicObject()
|
public void GetTypedObject_nonDynamicObject()
|
||||||
{
|
{
|
||||||
var obj = new {
|
var obj = new {
|
||||||
test = "hello"
|
Test = "hello"
|
||||||
};
|
};
|
||||||
object typedobj = Utils.GetTypedObject(obj);
|
var typedobj = Utils.GetTypedObject(obj);
|
||||||
Assert.IsNotType<ExpandoObject>(typedobj);
|
Assert.IsNotType<ExpandoObject>(typedobj);
|
||||||
Assert.NotNull(typedobj.GetType().GetProperty("test"));
|
Assert.NotNull(typedobj.GetType().GetProperty("Test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateObject_dynamicObject()
|
public void CreateObject_dynamicObject()
|
||||||
{
|
{
|
||||||
dynamic obj = new ExpandoObject();
|
dynamic obj = new ExpandoObject();
|
||||||
obj.test = "test";
|
obj.Test = "test";
|
||||||
obj.testList = new List<int> { 1, 2, 3 };
|
obj.TestList = new List<int> { 1, 2, 3 };
|
||||||
|
|
||||||
object newObj = Utils.CreateObject(typeof(TestClass), obj);
|
object newObj = Utils.CreateObject(typeof(TestClass), obj);
|
||||||
Assert.IsNotType<ExpandoObject>(newObj);
|
Assert.IsNotType<ExpandoObject>(newObj);
|
||||||
Assert.NotNull(newObj.GetType().GetProperty("test"));
|
Assert.NotNull(newObj.GetType().GetProperty("Test"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +78,13 @@ namespace RulesEngine.UnitTest
|
||||||
public void CreateAbstractType_dynamicObject()
|
public void CreateAbstractType_dynamicObject()
|
||||||
{
|
{
|
||||||
dynamic obj = new ExpandoObject();
|
dynamic obj = new ExpandoObject();
|
||||||
obj.test = "test";
|
obj.Test = "test";
|
||||||
obj.testList = new List<int> { 1, 2, 3 };
|
obj.TestList = new List<int> { 1, 2, 3 };
|
||||||
obj.testEmptyList = new List<object>();
|
obj.testEmptyList = new List<object>();
|
||||||
|
|
||||||
Type type = Utils.CreateAbstractClassType(obj);
|
Type type = Utils.CreateAbstractClassType(obj);
|
||||||
Assert.NotEqual(typeof(ExpandoObject), type);
|
Assert.NotEqual(typeof(ExpandoObject), type);
|
||||||
Assert.NotNull(type.GetProperty("test"));
|
Assert.NotNull(type.GetProperty("Test"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue