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
.
year
is the Year number.month
is the Month number, January = 1.day
is the day number in a month.hour
the hour of the day starting from 0.minute
the minute of the hour starting from 0.second
the second of the minute starting from 0.
time.Time
value representing the time as specified in the argument inlocal
locale.
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.
variableName
the 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.Time
value 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.
text
The 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.
i
a variable to check.
true
if the specified argument isnil
or an invalidptr
value.false
if the specified argument is a validptr
value.
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.
i
a variable to check.
true
if the specified argument is Zero.false
if 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 start again from the beginning.
ruleName
name 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.
time
The 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.
time
The 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.
time
The 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.
time
The 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.
time
The 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.
time
The 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.
time
The time value you wish to have checkedbefore
The time value against which the above is checked
- True if the
before
time value precedes thetime
value. - False if the
before
time value does not precede thetime
value.
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.
time
The time value you wish to have checkedafter
The time value against which the above is checked
- True if the
after
time value followstime
value. - False if the
after
time value does not follow thetime
value.
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.
time
The time value you wish to have formatted.layout
String 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.
string
The string to compare to
< 0
if receiver is less than the argument0
if receiver is equal to the argument> 0
if 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.
string
The substring to check within the receiver
true
if the argument string is contained within the receiver.false
if 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.
string
The variadic string argument to check
- bolean
true
if any of the argument is equals to the receiver, orfalse
if 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.
string
The 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.
string
The expected prefix.
true
if the receiver has the argument as its prefix.false
if 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.
string
The expected suffix.
true
if the receiver has the argument as its suffix.false
if 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.
string
The 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.
string
The 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.
int64
the repeat count
- A new string containing
n
occurrences 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
.
old
the substring you wish to have replaced.new
the string you wish to replace all occurrences ofold
.
- A string where all instances of
old
in 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.
string
the 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
regexPattern
matches the string s - False if the
regexPattern
doesn'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.
val
value 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
int64
type and a real asfloat64
, thus you must always define your numeric types accordingly.