Condition Expressions
Introduction
Conditions can be used to control how triggers and workflows are executed. A condition uses a simple expression language to return a boolean (true/false) value.
- Triggers - If a condition is added to a trigger it is evaluated when the trigger (event or webhook) is processed. If the condition evaluates to false the workflow specified in the trigger will not be executed.
- Workflow (all steps except Start) - An optional condition can be specified. If the condition evaluates to false the step is skipped.
- Workflow Test Step - A condition is used to evaluate which branch of the test should be followed - true or false.
- Workflow End Step - An optional "failed" condition can be configured to specify if the workflow should be marked as failed.
Syntax
- Strings are specified in single quotes.
-
Variable names and Global Properties can be specified in curly brackets.
- The expression inside the curly brackets uses string interpolation to build the result.
- The curly brackets can be omitted if:
- The first character of the name is A-Z, a-z, or underscore
- The rest of the name only uses characters A-Z, a-z, 0-9, underscore (_), dot (.), and square brackets ([ or ]).
- Global Properties are referenced using the prefix wfglobal. followed by the property name. They can be managed by selecting the Global Properties button on the Workflows or Triggers page.
-
Parenthesis can be used to group expressions.
-
Operators
Operator Description Example == Equal (case insensitive for strings) status == 'success' != Not Equal (case insensitive for strings) status != 'failed' > Greater Than (numeric only) score > 50.0 >= GreaterThan or Equal To (numeric only) score >= 55 < Less Than (numeric only) score < 50.0 <= Less Than or Equal To (numeric only) score <= 55 and Logical AND status == 'success' and score > 50.0 or Logical OR status == 'success' or score > 50.0 not Logical NOT not Time(wfsystem.starttime, 800, 1700) ! Same as 'not' !Time(wfsystem.starttime, 800, 1700) -
Functions can be used for more complex scenarios. See the Functions section below.
Examples
- status == 'Test'
- {status} == 'Test'
- status == 'Test' and score > 0.50
- (status != 'Test') and (score > 0.50)
NOTE: A variable name that does not exist evaluates as an empty string.
The expression {doesnotexist} == ''
will be true.
Values (constants)
Can be: string, numeric or boolean.
- String can be expressed as values between single quotes (e.g. 'value' ). Inside a string, curly braces can be used to express a variable name.
- Numeric values are expressed as digits, or as hexadecimal numbers started with 0x. Real numbers can be used, the decimal separator must be a dot (.)
- Boolean values can be expressed as true (true, on, yes) or false (false, off, no).
Examples
- simple string:
'user name'
- string with variable:
'age is {wfresult.age}'
- natural number:
23, 0xf95c
- real number:
3.1416
Arrays
All variable names are strings: name
, index
, etc. During condition evaluation the variable name is resolved by looking up the variable name to retrieve the value.
Variable names can contain square brackets such as name[0]
or attachments[1].data
. If a variable name lookup fails because it does not exist and the variable name contains square brackets, an attempt is made to do variable substitution and attempt the lookup again. This allows using variables as array indexes.
The variable name inside of the array index must not start with a number: digit (0-9), plus: +, minus: -, or dot (.).
Functions can be used inside of an array index but:
- The expression must be inside of curly brackets to be parsed correctly
- The function must be preceded by a question mark - "?"
Examples
The variables are:
index = '2'
name[0] = 'name_zero'
name[1] = 'name_one'
name[2] = 'name_two'
name[3] = 'name_three'
Condition | Value | Variable Lookups Performed |
---|---|---|
name[2] | name_two | name[2] - succeeded |
name[index] | name_two | name[index] - failed name[2] - succeeded |
{name[?Add(index, 1)]} | name_three | name[3] - succeeded |
Functions
- Functions are used by using the function name with the parameters in parenthesis.
- Functions can be used in conditions.
- Functions can be used in string interpolation such as in a workflow
Set step.
- The first character of the interpolation (inside the curly brackets) should be a '?' to mark the rest of the interpolation as an expression to be evaluated instead of as a variable name.
- Example:
"The next value is {?Add(counter, 1)}"
- Function parameters can be constant values (see above) or properties from the current context
- If a property of the current context will be used as a function parameter, then its name must start with '_' or a letter, and next characters can only be '_', alphanumeric, or '.'
- Functions can be nested, as the parameter of a function call can be another function call.
- Example:
{?Replace(Trim(input),'b','c')}
- Example:
Examples
The following examples are conditions using functions.
Function | Description |
---|---|
Add(index, 1) >= 5 |
Add 1 to the variable 'index' |
Left(attachments[0].name, ':') |
Get the text to the left of a colon in the variable 'attachments[0].name' |
Left(attachments[index].name, ':') |
Get the text to the left of a colon in the variable 'attachments[index].name' |
Left(fullname, ',') != '' |
Get the text to the left of a comma in the variable 'fullname' |
Variable Functions
Variable functions are used to determine the state of a variable.
Function | Description | Example | Returns |
---|---|---|---|
IsDefined(name) | Returns true if a variable of name is present | IsDefined('status') |
|
IsDefined(propname) |
If propname has a value of 'status' then the variable status is checked. | ||
IsDefined({propname}) |
If propname has a value of 'status' then the variable status is checked. | ||
IsEmpty(name) | Returns true if a variable of name is either not defined or has an empty value | IsEmpty('status') |
|
IsNumeric(value) | Returns true if a variable has a numeric value. | IsNumeric(score) |
true if score has a numeric value (e.g. 50) |
GetValue('property name') | Gets value of the property with the specified name. This can be used when the property name contains illegal characters. | GetValue('message') |
'Hello' if message variable has value 'Hello'. |
GetValue('property name', expand) | Gets value of the property with the specified name and optionally expands references to other properties if the expand boolean is set to true. This can be used when a property name contains illegal characters and contains a reference to another property. | GetValue('message',true) |
'This message contains some text.' |
content == 'some text' message == 'This message contains {content}.' |
GetValue('message',false) |
'This message contains {content}.' |
String Functions
Function | Description | Example | Returns |
---|---|---|---|
DateFormat(input, format) | Format a date time using the given format string. The format strings are the .NET DateTime format strings. Empty format string will format as ISO-8601. The date time will be converted to the timezone in the workflow settings before formatting. |
DateFormat('2018-02-05T17:00:03-05:00', 'g') |
2/5/2018 5:00 PM |
DateFormat(input, format, forceUTC) | Format a date time using the given format string. The format strings are the .NET DateTime format strings. Empty format string will format as ISO-8601. Set forceUTC to true to convert the date time to UTC before formatting; otherwise, the date time will be converted to the timezone in the workflow settings before formatting. |
DateFormat('2018-02-05T17:00:03-05:00', '', true) |
2018-02-05T22:00:03Z |
GetDigits(count) | Returns a random generated sequence of digits containing count digits. | GetDigits(4) |
0719 |
GetUUID() | Returns a random generated Universal Unique Identifier. | GetUUID() |
90e51d3b-b116-4a4d-8dbd-b4f655796375 |
Left(input, split) | Split a string on the first occurrence of split and returns the left side. If split is not found the entire value is returned; The return value is not trimmed |
Left('Last, First', ',') |
'Last' |
Left(input, split, trim) | The optional third parameter (boolean) specifies if the value should be trimmed. |
Left('Last , First', ',', true) |
'Last' |
Length(input) | Returns the length of the input string | Length('abc') |
3 |
Regex(input, pattern) | Matches the input against the regex pattern and returns the matched part of the string | Regex('abcde', '^abc') |
'abc' |
Regex(input, pattern, flags) | Matches the input against the regex pattern and returns the matched part of the string. The third parameter provides options for regex match. Options: 'i' = ignore case 's' = single line mode(change meaning of dot(.)) 'm' = multiline mode(changes meaning of ^ and $) 'x' = ignore pattern whitespace |
Regex('abc', '^abc', 'is') |
'abc' |
RegexMatch(input, pattern) | Check if the input value matches a regular expression pattern. | RegexMatch('abc', '^abc$') RegexMatch('abc-456-4532', '\d{3}') |
true in both cases |
RegexMatch(input, pattern, flags) | The optional flags parameter specifies how the regular expression is evaluated. The flag parameter is a string: 'i' - case insensitive search 's' - single line mode 'm' - multiline mode 'x' - ignore pattern whitespace |
RegexMatch('ABC', 'abc', 'i') RegexMatch('ABC', 'abc', 'is') |
|
RegexReplace(input, pattern, replacement) | Same as Replace except that the find argument is a regular expression. | RegexReplace('abc123def456', '\d', 'M') Replace all digits with 'M'. |
'abcMMMdefMMM' |
RegexReplace(input, pattern, replacement, flags) | The optional flags parameter specifies how the regular expression is evaluated. The flags parameter is the same as the RegexMatch function. |
||
Replace(input, find, replacement) | Replace all instances of find with replacement in input and returns the result. | Replace('abc-def-123', '-', 'QQ') |
'abcQQdefQQ123' |
Right(input, split) | Split a string and on the first occurrence of split and returns the right side If split is not found empty string is returned. The return value is not trimmed |
Right('Last, 'First', ',') |
' First' |
Right(input, split, trim) | The optional third parameter (boolean) specifies if the value should be trimmed. | Right('Last, First', ',', true) |
'First' |
Substring(input,count) | Returns the first 'count' characters of the string. If the string is less than 'count' length the entire string is returned. |
Substring('abcdefgh',2) |
'ab' |
Trim(input) | Trim whitespace from the beginning and end of the input and return it. | Trim(' abc ') |
'abc' |
UrlEncode(input) | URL encode a string. This is used when building a URL to send to an adapter command. | UrlEncode('a b c') |
'a+b+c' |
Numeric Functions
Function | Description | Example | Returns |
---|---|---|---|
Abs(value) | Returns the absolute value of the input value | Abs(-10) |
10 |
Abs(10) |
10 |
||
Add(value) | Add one to the input value and return the result | Add(counter) |
Returns '4' if counter has the value '3'. |
Add(value1,value2... value5) | Returns the sum of up to five values | Add(1, counter, 7, score, 2) |
Returns '18' if counter is '-4' and score is '12'. |
Ceil(value) | Returns the smallest integer that is greater than or equal to the value | Ceil(1.1) |
2 |
Ceil(-1.1) |
-1 |
||
Div(value,divisor) | Divide the value by the divisor and return the result | Div(8,2) |
4 |
Div(value,divisor,precision) | Divide the value by the divisor and return the result rounded to the specified precision [0-28] | Div(3,2,4) |
1.3333 |
Floor(value) | Returns the largest integer that is less than or equal to the value | Floor(1.1) |
1 |
Floor(-1.1) |
-2 |
||
Max(value1,value2) | Returns the larger of two values | Max(5,10) |
10 |
Min(value1,value2) | Returns the smaller of two values | Min(5,10) |
5 |
Mod(value,divisor) | Divide the value by the divisor and return the modulus (remainder) as result | Mod(10,3) |
1 |
Mod(value,divisor,precision) | Divide the value by the divisor and return the modulus (remainder) as result rounded to the specified precision [0-28] | Mod(1.23456789,1,4) |
0.2346 |
Mul(value1,value2) | Multiply two numbers together and return the result | Mul(3,2) |
6 |
Mul(value1,value2,precision) | Multiply two numbers together and return the result rounded to the specified precision [0-28] | Mul(2.23,3.31,2) |
7.38 |
Round(value,precision) | Round value to specified precision [0-28] | Round(1.6666666666,4) |
1.6667 |
Sub(value1,value2) | Subtract value2 from value1 and return the result | Sub(5,2) |
3 |
Date/Time Functions
Date and time functions can be used to evaluate a date/time string. Adapters can send a date/time property in an event or command response.
The format of the input string must be one of:
- YYYY-MM-DDTHH:MM:SS
- YYYY-MM-DDTHH:MM:SS.sss
The time zone can be added. UTC is assumed if no timezone is specified.
Examples:
Time String | TimeZone |
---|---|
2018-02-05T17:00:03 | No timezone - UTC timezone is assumed |
2018-02-05T17:00:03Z | UTC timezone |
2018-02-05T17:00:03-05:00 | Timezone of -5 hours from UTC |
2018-02-05T17:00:03+02:00 | Timezone of +2 hours from UTC |
A default time zone can be set in the Administration > Workflow page. When evaluating the date time function the argument is converted to a date/time in the default time zone before the check is made.
System level date time properties are available during trigger evaluation and when workflows are started:
- When a trigger (event or webhook) is being evaluated there are system level properties available to use in the condition:
- wfsystem.starttime - a string with the trigger start date time in local time zone of the server
- wfsystem.starttimeUTC - a string with the trigger start date time in UTC time zone.
- When a workflow is started the following system level properties are automatically added to the workflow:
- wfsystem.starttime - a string with the workflow start date time in local time zone of the server
- wfsystem.starttimeUTC - a string with the workflow start date time in UTC time zone.
There are eight date time functions. All of these functions convert the passed in time string to the default time zone and then examples are described below. The function names are:
- Year - use the year component
- Month - use the month component
- Day - use the day component
- Hour - use the hour component (0 to 23)
- Minute - use the minute component
- DayOfWeek - use the day of week component (0 = Sunday through 6 = Saturday)
- Date - Combine the Month/Day as (Month*100)+Day - so December 8 is the value 1208.
- Time - Combine the Hour/Minutes as (Hour*100)+Minute - so 3:45 PM is the value 1545.
Each function has three forms it can be called in. Each form takes the date time string as the first parameter.
- One parameter: Returns the value for the component (based on the function name).
- Two parameters: Returns true if the component (based on the function name) equals the second parameter.
- Three parameters: Returns true if the component (based on the function name) is between the second and third parameters. This is an inclusive compare (
value >= parameter2 and value <= parameter3
)
Examples
These examples can be used in a trigger or workflow condition. They use the wfsystem.starttime variable but could use any variable that is in the supported format - such as matchTime from the Neoface watch match event, or the wfsystem.starttimeUTC variable (since the time is converted to the default time zone when being evaluated).
Example 1: Check if it is between 8 AM and 5 PM:
- Three parameter version: Time(wfsystem.starttime, 800, 1659)
Example 2: Check if the day of week is Monday:
- One parameter version: DayOfWeek(wfsystem.starttime) == 1
- Two parameter version: DayOfWeek(wfsystem.starttime, 1)
Example 3: Check if the date is December 25:
- One parameter version: Date(wfsystem.starttime) == 1225
- Two parameter version: Date(wfsystem.starttime, 1225)
- Three parameter version: Date(wfsystem.starttime, 1225, 1225)
Other Examples:
- Composing a string from various input values:
[Entry {i}]: The id is {id} and the text is '{?Trim(text)}'
- Increment a numeric value:
The next id is {?Add(id)}
- Math on values:
Quantity {quantity1} and {quantity2} and a total of {?Add(quantity1, quantity2)}
- Condition: `{i} <= '10'