About | Tutorial | Rule Engine | GRL | GRL JSON | RETE Algorithm | Functions | FAQ | Benchmark
Built-in functions are all defined within the ast/BuiltInFunctions.go file. As of now, they are:
MakeTime will create a time.Time with local locale.
yearis the Year number.monthis the Month number, January = 1.dayis the day number in a month.hourthe hour of the day starting from 0.minutethe minute of the hour starting from 0.secondthe second of the minute starting from 0.
time.Timevalue representing the time as specified in the argument inlocallocale.
rule SetExpire "Set the expire date for Fact created before 2020" {
when
Fact.CreateTime < MakeTime(2020,1,1,0,0,0)
then
Fact.ExpireTime = MakeTime(2021,1,1,0,0,0);
}Changed will ensure the specified variableName is removed from the working
memory before the next cycle.
variableNamethe variable name to be removed from working memory.
rule SetExpire "Set new expire date" {
when
IsZero(Fact.ExpireTime)
then
Fact.CalculateExpire(); // this function will internally change the ExpireTime variable
Changed("Fact.ExpireTime")
}Now function will create a new time.Time value containing the current time.
time.Timevalue representing the current value
rule ResetTime "Reset the lastUpdate time" {
when
Fact.LastUpdate < Now()
then
Fact.LastUpdate = Now();
}Log will emit a log-debug string from within the rule.
textThe text to emit into the Log-Debug
rule SomeRule "Log candidate name if he is below 17 years old" {
when
Candidate.Age < 17
then
Log("Under aged: " + Candidate.Name);
}IsNil will check if the argument is a nil value.
ia variable to check.
trueif the specified argument isnilor an invalidptrvalue.falseif the specified argument is a validptrvalue.
rule CheckEducation "Check candidate's education fact" {
when
IsNil(Candidate.Education) == false &&
Candidate.Education.Grade == "PHD"
then
Candidate.Onboard = true;
}IsZero will check any variable in the argument for its Zero status value. Zero means
that the variable is newly defined and has not been assigned an initial value.
This is usually applied to types like string, int64, uint64, bool,
time.Time, etc.
ia variable to check.
trueif the specified argument is Zero.falseif the specified argument not Zero.
rule CheckStartTime "Check device's starting time." {
when
IsZero(Device.StartTime) == true
then
Device.StartTime = Now();
}Retract will exclude the specified rule from the subsequent cycle evaluations. If a
rule is retracted its when scope will not be evaluated on the next cycles after the call to Retract.
The engine will automatically resets all rule back inplace when it starts again from the beginning.
ruleNamename of the rule to retract.
rule CheckStartTime "Check device's starting time." salience 1000 {
when
IsZero(Device.StartTime) == true
then
Device.StartTime = Now();
Retract("CheckStartTime");
}GetTimeYear will extract the Year value of the time argument.
timeThe time variable
- Year value of the time.
rule StartNewYearProcess "Check if it's a new year to restart new FinancialYear." salience 1000 {
when
GetTimeYear(Now()) != GL.FinancialYear
then
GL.CloseYear(GL.FinancialYear)
}GetTimeMonth will extract the Month value of the time argument.
timeThe time variable
- Month value of the time. 1 = January.
// TODO: something's not right here. The description is copy/pasted from above
// but the condition/action doesn't make sense to me
rule StartNewYearProcess "Check if its a new year to restart new FinancialYear." salience 1000 {
when
isZero(Process.Month)
then
Process.Month = GetTimeMonth(Process.Month);
}GetTimeDay will extract the Day of the month value of the time argument.
timeThe time variable
- Day of month value of the time.
rule GreetEveryDay "Log a greeting every day." salience 1000 {
when
Greeting.Day != GetTimeDay(Now())
then
Log("Its a new Day !!!")
Retract("GreetEveryDay")
}GetTimeHour will extract the Hour value of the time argument.
timeThe time variable
- Hour value of the time. Is between 0 to 23
rule DailyCheckBuild "Execute build every 6AM and 6PM." {
when
GetTimeHour(Now()) == 6 || GetTimeHour(Now()) == 18
then
CiCd.BuildDaily();
Retract("DailyCheckBuild");
}GetTimeMinute will extract the Minute value of the time argument.
timeThe time variable
- Minute value of the time, between 0 to 59
rule DailyCheckBuild "Execute build every 6.30AM and 6.30PM." {
when
(GetTimeHour(Now()) == 6 || GetTimeHour(Now()) == 18) &&
GetTimeMinute(Now()) == 30
then
CiCd.BuildDaily();
Retract("DailyCheckBuild");
}GetTimeSecond will extract the Second value of the time argument.
timeThe time variable
- Second value of the time, between 0 to 59
rule DailyCheckBuild "Execute build every 6.30AM and 6.30PM." {
when
(GetTimeHour(Now()) == 6 || GetTimeHour(Now()) == 18) &&
GetTimeMinute(Now()) == 30 && GetTimeSecond(Now()) == 0
then
CiCd.BuildDaily();
Retract("DailyCheckBuild");
}IsTimeBefore will check if a time value precedes another time value.
timeThe time value you wish to have checkedbeforeThe time value against which the above is checked
- True if the
beforetime value precedes thetimevalue. - False if the
beforetime value does not precede thetimevalue.
rule PromotionExpireCheck "Apply a promotion if promotion hasn't yet expired." {
when
IsTimeBefore(Now(), Promotion.ExpireDateTime)
then
Promotion.Discount = 0.10;
Retract("PromotionExpireCheck");
}IsTimeAfter will check if a time value follows another time value.
timeThe time value you wish to have checkedafterThe time value against which the above is checked
- True if the
aftertime value followstimevalue. - False if the
aftertime value does not follow thetimevalue.
rule AdditionalTax "Apply additional tax if new tax rules are in effect." {
when
IsTimeAfter(Purchase.TransactionTime, TaxRegulation.StartSince)
then
Purchase.Tax = Purchase.Tax + 0.01;
}TimeFormat will format a time argument as specified by layout argument.
timeThe time value you wish to have formatted.layoutString variable specifying the date format layout.
For the layout format, you can read this article
- A string formatted as specified.
rule LogPurchaseDate "Log the purchase date." {
when
IsZero(Purchase.TransactionDate) == false
then
Log(TimeFormat(Purchase.TransactionDate, "2006-01-02T15:04:05-0700");
}Complete will cause the engine to stop processing further rules in its
current cycle. This is useful if you want to terminate further rule evaluation
under a set condition.
rule DailyCheckBuild "Execute build at 6.30AM and 6.30PM." {
when
(GetTimeHour(Now()) == 6 || GetTimeHour(Now()) == 18) &&
GetTimeMinute(Now()) == 30 && GetTimeSecond(Now()) == 0
then
CiCd.BuildDaily();
Complete();
}All the functions bellow is a wrapper to their golang math functions. You should read Golang math page to know how to use each function.
Unlike go, you don't have to use the math. prefix
to use them in your GRL.
Use them like normal built in function.
when
Max(Fact.A, Fact.C, Fact.B) > 10
then
Fact.X = Acosh(Fact.C);- Max(vals ...float64) float64
- Min(vals ...float64) float64
- Abs(x float64) float64
- Acos(x float64) float64
- Acosh(x float64) float64
- Asin(x float64) float64
- Asinh(x float64) float64
- Atan(x float64) float64
- Atan2(y, x float64) float64
- Atanh(x float64) float64
- Cbrt(x float64) float64
- Ceil(x float64) float64
- Copysign(x, y float64) float64
- Cos(x float64) float64
- Cosh(x float64) float64
- Dim(x, y float64) float64
- Erf(x float64) float64
- Erfc(x float64) float64
- Erfcinv(x float64) float64
- Erfinv(x float64) float64
- Exp(x float64) float64
- Exp2(x float64) float64
- Expm1(x float64) float64
- Float64bits(f float64) uint64
- Float64frombits(b uint64) float64
- Floor(x float64) float64
- Gamma(x float64) float64
- Hypot(p, q float64) float64
- Ilogb(x float64) int
- IsInf(f float64, sign int64) bool
- IsNaN(f float64) (is bool)
- J0(x float64) float64
- J1(x float64) float64
- Jn(n int64, x float64) float64
- Ldexp(frac float64, exp int64) float64
- MathLog(x float64) float64
- Log10(x float64) float64
- Log1p(x float64) float64
- Log2(x float64) float64
- Logb(x float64) float64
- Mod(x, y float64) float64
- NaN() float64
- Pow(x, y float64) float64
- Pow10(n int64) float64
- Remainder(x, y float64) float64
- Round(x float64) float64
- RoundToEven(x float64) float64
- Signbit(x float64) bool
- Sin(x float64) float64
- Sinh(x float64) float64
- Sqrt(x float64) float64
- Tan(x float64) float64
- Tanh(x float64) float64
- Trunc(x float64) float64
The following functions can be called from within GRL as long as the receiver value type is correct.
Len will return string's length.
- The length of string's receiver
rule DoSomething "Do something when string length is sufficient" {
when
Fact.Name.Len() > "ATextConstant".Len()
then
Fact.DoSomething();
}Compare will compare the receiver string to the argument.
stringThe string to compare to
< 0if receiver is less than the argument0if receiver is equal to the argument> 0if receiver is greater thant the argument
rule CompareString "Do something when Fact.Text is greater than A" {
when
Fact.Text.Compare("A") > 0
then
Fact.DoSomething();
}Contains will check if its argument is contained within the receiver.
stringThe substring to check within the receiver
trueif the argument string is contained within the receiver.falseif the argument string is not contained within the receiver.
rule ContainString "Do something when Fact.Text is contains XXX" {
when
Fact.Text.Contains("XXX")
then
Fact.DoSomething();
}In will check if the any of the argument is equals to the receiver.
stringThe variadic string argument to check
- bolean
trueif any of the argument is equals to the receiver, orfalseif otherwise.
rule CheckArgumentIn "Do something when Fact.Text is equals to 'ABC' or 'BCD' or 'CDE' " {
when
Fact.Text.In("ABC", "BCD", "CDE")
then
Fact.DoSomething();
}Count will count the number of occurences of argument in receiver string.
stringThe substring to count within the receiver
- number of occurences of the argument in the receiver.
rule CountString "Do something when Fact.Text contains 3 occurrences of 'ABC'" {
when
Fact.Text.Count("ABC") == 3
then
Fact.DoSomething();
}HasPrefix will check if the receiver string has a specific prefix.
stringThe expected prefix.
trueif the receiver has the argument as its prefix.falseif the receiver does not have the argument as its prefix.
rule IsPrefixed "Do something when Fact.Text started with PREF" {
when
Fact.Text.HasPrefix("PREF")
then
Fact.DoSomething();
}HasSuffix will check if the receiver string has a specific suffix.
stringThe expected suffix.
trueif the receiver has the argument as its suffix.falseif the receiver does not have the argument as its suffix.
rule IsSuffixed "Do something when Fact.Text ends with SUFF" {
when
Fact.Text.HasSuffix("SUFF")
then
Fact.DoSomething();
}Index will return the index of the first occurrence of the argument in the receiver string.
stringThe substring to search for.
- The index value of the first occurrence of the argument.
rule IndexCheck "Do something when Fact.Text ABC occurs as specified" {
when
Fact.Text.Index("ABC") == "abABCabABC".Index("ABC")
then
Fact.DoSomething();
}LastIndex will return the index of last occurrence of the argument in the receiver string.
stringThe substring to search for.
- The index of the last occurrence of the argument.
rule LastIndexCheck "Do something when Fact.Text ABC occurs in the last position as specified" {
when
Fact.Text.LastIndex("ABC") == "abABCabABC".LastIndex("ABC")
then
Fact.DoSomething();
}Repeat will return a string containing n occurrences of the receiver string.
int64the repeat count
- A new string containing
noccurrences of the receiver.
rule StringRepeat "Do something when Fact.Text contains ABCABCABC" {
when
Fact.Text == "ABC".Repeat(3)
then
Fact.DoSomething();
}Replace will return a string with all occurrences of old replaced with new.
oldthe substring you wish to have replaced.newthe string you wish to replace all occurrences ofold.
- A string where all instances of
oldin the receiver have been replaced withnew.
rule ReplaceString "Do something when Fact.Text contains replaced string" {
when
Fact.Text == "ABC123ABC".Replace("123","ABC")
then
Fact.DoSomething();
}Split will return a string slice whose elements are determined after
splitting the receiver by the string token argument. The token will not be
present in the resulting slice elements.
stringthe token you wish to use to split the receiver.
- The string slice containing parts of the original string as split by the token.
rule SplitString "Do something when Fact.Text is prefixed by 'ABC,'" {
when
Fact.Text.Split(",")[0] == "ABC"
then
Fact.DoSomething();
}ToLower will return a string whose contents are all lower case instances of
characters in the receiver.
- A new string that is a lower-cased version of the receiver.
rule LowerText "Do something when Fact.Text is equal to 'abc'" {
when
Fact.Text.ToLower() == "Abc".ToLower()
then
Fact.DoSomething();
}ToUpper will return a string whose contents are all upper case instances of
characters in the receiver.
- A new string that is an upper-cased version of the receiver.
rule UpperText "Do something when Fact.Text is equal to 'ABC'" {
when
Fact.Text.ToUpper() == "Abc".ToUpper()
then
Fact.DoSomething();
}Trim will return a string where the whitespace on either end of the string has been removed.
- A string with the whitespace removed from the beginning and end.
rule TrimText "Do something when Fact.Text is 'ABC'" {
when
Fact.Text == " Abc ".Trim().ToUpper()
then
Fact.DoSomething();
}MatchString MatchString reports whether the string s contains any match of the regular expression pattern. Similar to golang MatchString
- True if the
regexPatternmatches the string s - False if the
regexPatterndoesn't match the string s
rule MatchStringText "Return true when regex pattern matches the string" {
when
Fact.Text.MatchString("B([a-z]+)ck")
then
Fact.DoSomething();
}Len will return the length of the array/slice.
- The length of array/slice.
rule DoSomething "Do something when array length is sufficient" {
when
Fact.ChildrenArray.Len() > 2
then
Fact.DoSomething();
}Append will append val onto the end of the receiver array.
valvalue to have appended.
rule DoSomething "Add a new child when the array has less than 2 children" {
when
Fact.ChildrenArray.Len() < 2
then
Fact.ChildrenArray.Append(Fact.NewChild());
}Len will return map's length.
- The length of map receiver.
rule DoSomething "Do something when map length is sufficient" {
when
Fact.ChildrenMap.Len() > 2
then
Fact.DoSomething();
}All functions that are acessible from the DataContext are Invocable from within the rule, both in the "When" scope and the "Then" scope.
You can create functions and have your Fact as receiver, and those functions can be called from GRL.
For example. Given:
type MyPoGo struct {
}
func (p *MyPoGo) GetStringLength(sarg string) int {
return len(sarg)
}
func (p *MyPoGo) AppendString(aString, subString string) string {
return sprintf("%s%s", aString, subString)
}You can make calls to the defined methods:
dctx := grule.context.NewDataContext()
dctx.Add("Pogo", &MyPoGo{})
rule "If it's possible to Groool, Groool" {
when
Pogo.GetStringLength(some.variable) < 100
then
some.variable = Pogo.AppendString(some.variable, "Groooling");
}Variadic arguments are supported for custom functions.
func (p *MyPoGo) GetLongestString(strs... string) string {
var longestStr string
for _, s := range strs {
if len(s) > len(longestStr) {
longestStr = s
}
}
return longestStr
}This function can then be called from within a rule with zero or more values supplied for the variadic argument.
when
Pogo.GetStringLength(some.variable) < 100
then
some.longest = Pogo.GetLongestString(some.stringA, some.stringB, some.stringC);Since it is possible to provide zero values to satisfy a variadic argument, they can also be used to simulate optional parameters.
func (p *MyPoGo) AddTax(cost int64, optionalTaxRate... float64) int64 {
var taxRate float64 = 0.2
if len(optionalTaxRate) > 0 {
taxRate = optionalTaxRate[0]
}
return cost * (1+taxRate)
}when
Pogo.IsTaxApplied() == false
then
some.cost = Pogo.AddTax(come.cost);
//or
when
Pogo.IsTaxApplied() == false
then
some.cost = Pogo.AddTax(come.cost, 0.15);When you make your own function to be called from the rule engine, you need to know the following laws:
- The function must be visible, meaning that functions must start with a capital letter. Private functions cannot be executed.
- The function must only return one value type. Returning multiple values from a function is not supported and the rule execution will fail if there are multiple return values.
- The way number literals are treated in Grule's GRL is such that a
integer will always be taken as an
int64type and a real asfloat64, thus you must always define your numeric types accordingly.