◷ Reading Time: 4 minutes
Approach
Extending a Natural Language is not very different from extending other types of logic (i.e., Validation or Decision tree). You have the following options:
- Calling an object’s method
- Calling a function
- Encapsulate method/function with logic
Example
Let’s say we have the following rule and we want to extend it:
input person when Person has name Name of person is not null and Name of person is not empty end
Required Extension: Checking in Database for Name duplication
Extension
First we need to implement a type that knows how to do the check
Check names database for duplication
The implementation below is just to give you an example. You can fill the TODO part on your own:
class PersonDbUtil
{
public bool CheckDbExists(object input)
{
var name = input as string;
if (name == null)
return false;
var result = true;
// TODO: go to your database and check for
// duplication of name
return result;
}
}
Calling Method
You can always inject an object into a rule and use the object members (i.e., methods) inside your rule. In this way, you can take advantage of your existing code. Or sometimes it is just easier to implement logic in the code and reuse it in a rule (e.g., web service call, complex algorithm, etc.).
To do this, you just need to define an input for your utility object, as shown below:
input person, db when Person has name Name of person is not null and Name of person is not empty and db.CheckDbExists(person.Name) is false end
Calling Function
Functions are a type of expression that is very similar to methods, but the way these are used is independent of the object reference. The other benefit of using function is that you can associate a new name to the method if you need to change the name of the function. However, these need to be registered before use.
To register your method as a function:
1. You need to add an attribute on top of your method:
class PersonDbUtil
{
[Function("NameExists")]
public bool CheckDbExists(object input)
}
2. You need to register on execution:
var engine = RuntimeEngine.FromXml(Encoding.UTF8.GetBytes(ruleDocument));
engine.OnRunning = (e) =>
{
e.Context.VariableContainer.RegisterFunction(typeof(PersonDbUtil));
};
Then the function will be ready to use:
input person when Person has name Name of person is not null and Name of person is not empty and NameExists(person.Name) is false end
As you can see in the above example:
- There is no input parameter for the reference of the extension class, so the usage is direct by calling the name of the function
- The new name NameExists is used to call the method of class
Using logic
The other benefit of using Natural Language is that you can introduce a logic in the rules that is easier to read.
input person when Person has name Name of person is not null and Name of person is not empty and Ensure (person) name is not duplicated end when Ensure {person} name is not duplicated NameExists(person.Name) is false end
Complete Sample
Rule
Here is the complete rule in the Natural Language XML container:
<Natural name="test a person identity"> <Dsl> input person when Person has name Name of person is not null and Name of person is not empty and Ensure (person) name is not duplicated end when Ensure {person} name is not duplicated NameExists(person.Name) is false end </Dsl> </Natural>
Database Class Utility
class PersonDbUtil
{
[Function("NameExists")]
public bool CheckDbExists(object input)
{
var name = input as string;
if (name == null)
return false;
var result = true;
// TODO: go to your database and check for
// duplication of name
return result;
}
}
Running Sample
var engine = RuntimeEngine.FromXml(Encoding.UTF8.GetBytes(ruleDocument));
engine.OnRunning = (e) =>
{
e.Context.VariableContainer.RegisterFunction(typeof(PersonDbUtil));
};
var per = new Person();
per.Name = "test";
per.Family = "test";
var res = engine.Run(per);
Assert.IsTrue(res.Outcome.Value);