Open sswapniljadhav opened 3 years ago
copy/paste and then nest? maybe not elegant but its a possible solution? although it would be nice to reference other rules like include a header file (c++) or use using (c#)
@sswapniljadhav Are you looking for referencing Rules into another rule or are you looking at referencing output of Rules within another rule?
@sswapniljadhav Are you looking for referencing Rules into another rule or are you looking at referencing output of Rules within another rule?
Referencing output of rules in another rule
@sswapniljadhav It sounds you should use ScopedParams (see also LocalParams). For across rules and accessing the expression via other rules (really just expressions) use a GlobalParam (inside the Workflow object) with the original rule as the expression and then reference the global param in the other rules. In the original rule, the expression would simply be the name of the global param and in the others it would be GlobalParam1 && Input1.Foo == 0
. More info, here are the unit tests, take a look at the sample workflows at the bottom here.
I have a fork that does this if anyone is interested. I'm not really sure if it's pull request material though.
I have a fork that does this if anyone is interested. I'm not really sure if its pull request material though.
Is this what you mean? Can you put it in a new branch and create some unit tests for it?
That's one small portion of it. I'm working on a project that required me to fork RulesEngine to add a few features I needed that weren't already baked in. As a disclaimer, I'm focused on moving my project forward so my implementations are "quick and dirty" so to speak, while they are functional, they aren't necessarily ideal.
With that said, my fork (in its current state) adds the following features:
ExclusiveOr
operator, Value
, and DefaultValue
parameters to Rule
. Value
is technically an expression under the hood.Rule
may reference the Value
of another Rule
in its Expression
. To implement this, I used a DAG to store rule dependencies and I altered RuleEngine
to execute rules sequentially, in order, according to the DAG. Things like circular dependencies are checked for.RegexExpression
and RegexCasedExpression
expression types, which are mostly specific to my project, but they are shorthand for a regex match that assumes the first input is a string. This allows the Expression
field to only list a regex pattern, and not any regex functions or equals signs. The way I implement this is maybe a bit hacky, the DAG is traversed and rules are registered and executed one at a time. When a rule is complete, I package its result into a GlobalParam
which is provided to the execution context of all subsequent rules. This GlobalParam
method is a bit of a kludge, but it allowed me to implement the feature with minimal effort and changes to the code. I'm not sure if it's the best way as well. Secondly, I share a Value
, not the Expression
between rules, this is because my project has tags that are passed along instead of expressions so I'm not sure if this is something other people would want, or if we should just switch this to Expression
references instead.
Here is an example of how my rule referencing system works:
[
{
"WorkflowName": "Workflow1",
"Rules": [
{
"RuleName": "HasDiscount",
"Expression": "FetchDiscount > 0"
},
{
"RuleName": "FetchDiscount",
"Operator": "ExclusiveOr",
"DefaultValue": "0",
"Rules": [
{
"RuleName": "Discount20",
"Value": "20",
"ExpressionType": "LambdaExpression",
"Expression": "input1.loyaltyFactor <= 2"
},
{
"RuleName": "Discount30",
"Value": "30",
"ExpressionType": "LambdaExpression",
"Expression": "input1.loyaltyFactor >= 3"
}
]
}
]
}
]
First, my altered RuleEngine
noticies that the rule HasDiscount
depends on FetchDiscount
, so it will set up an execution plan where FetchDiscount
is executed first, and HasDiscount
is executed second. Secondly, the ExclusiveOr
requires exactly one of its children to evaluate to true (IsSuccess = true
). If this is not the case, the rule will fail — with one exception: if all child rules fail DefaultValue
is returned. Value
doesn't need to be a fixed value like it is here, it could be an Expression
as well. I haven't added support for Values
referencing other rules or values yet. Finally the Value
evaluated from FetchDiscount
is inserted into the expression HasDiscount
and HasDiscount
is registered and executed.
Let me know if you have any questions.
Hello,
I am stuck with one scenario where I need to call multiple rules in 1 rule, here is simple example which I would like to achieve. Any help in solving the scenario or direction will be appreciated.
[ { "WorkflowName": "PaymentRule", "Rules": [ { "RuleName": "MinimumPayment", "SuccessEvent": "10", "ErrorMessage": "Error", "ErrorType": "Error", "RuleExpressionType": "LambdaExpression", "Operator": "OrElse", "Rules": [ { "RuleName": "IsPaymentEligible", "ErrorMessage": "Error", "ErrorType": "Error", "RuleExpressionType": "LambdaExpression", "Expression": "input1.PaymentAmount > 0 AND (input1.IsEligible==\"true\" AND input1.PaymentFrequency==input1.PaymentDuration ) AND input1.PaymentFrequency < input1.PaymentCycle ", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "(input1.PaymentAmount)" } } } }, { "RuleName": "elsePaymentEligible", "ErrorMessage": "Error", "ErrorType": "Error", "RuleExpressionType": "LambdaExpression", "Expression": "input1.PaymentAmount > 0 AND input1.IsEligible==\"false\" ", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "input1.PaymentFrequency" } } } } ]
} ]