Expressions and Dynamic Attributes
Expressions
In the previous chapter you have had some minor exposure to CaseMaster Scripting as the client.cms descriptor is written in CMS.
CMS is a rich, yet easy to learn language. One important concept of that language are expressions.
The following is an example of an expression:
random()
Expressions are build-up using functions. Functions may or may not have parameters but a function will always have the open- and close parenthesis even if there are no parameters. The random function in our example, was called without parameters.
You can also use the random function with two parameters, for the random function the parameters are optional.
random( 1, 6 )
will generate random number between 1 and 6 and can thus be used as a dice.
Function names are also not case sesntive; random() and Random() are both valid.
Examples of other simple functions are:
| Function | Use | Example |
|---|---|---|
| today() | Date of today | 2024-12-28 |
| now() | Timestamp for now | 2024-12-28T20:46:12 |
| user() | Primary key for current user | 2 |
Some developers may struggle with the fact that CaseMaster uses functions for everyting. It does not understand 8 + 4 or 12 \\ 3. Instead, you would have to use the function-equivalent:
| Traditional | CaseMaster |
|---|---|
| 8 + 4 | add( 8, 4 ) |
| 12 \ 2 | div( 12, 2 ) |
| 6 * 3 | mul( 6, 3 ) |
| 6 * 3 + 2 | add( mul( 6, 3 ), 2 ) |
The final example shows how functions are nested.
Note: it is beyond the scope of this document to list all the functions. The training application has a menu option to list all the functions.
Logical Functions
I want to pay special attention to the logical functions. These are:
- and()
- or()
- not()
- xor()
- xand()
- _and()
- _or()
- true()
- false()
The functions and() and or() do short-cutting; the and() function will return false() as soon as one parameter evaluates to false() and the remaining parameters are not evaluated.
The same is true for the or() function but this will return true() as soon as a parameter is found that evaluates to true().
The functions _and() and _or() are special versions of and() and or() where all parameters are always evaluated (i.e. no short-cutting takes place).
The functions and(), or(), _and(), _or(), xand() and xor() can all take 2 or more parameters.
Datatypes
CaseMaster supports the following datatypes:
- Integer
- Double
- Decimal
- String
- Date
- Time
- Timestamp
- Boolean
- Business Object
- Property bag
- Qualifier
- Lambda function
The latter 4 are for advanced use only.
Other Function Groups
- Math functions
- String functions
- Comparison functions
- Date functions
- CaseMaster functions
- Datatype conversion functions
- Datatype test functions
Tokens in Expressions
| Token | Use | Examples |
|---|---|---|
| String | Can start with ', " or `; must end with same quote as start-quote. Use backslash (\) to escape next character | 'Hello world' |
| "Hello World" | ||
| "That's all" | ||
| 'That\s all' | ||
| Integer | Digits | 1 |
| 12 | ||
| 06 | ||
| -8 | ||
| Decimal | Digits, '.' as decimal separator | 18.8876 |
| 18.8876 | ||
| -6.3 | ||
| Date | Starts and ends with '#' | #1/1/2025# |
| #2024/12/6# | ||
| #6jan2024# | ||
| Time | String with hh:mm and optionally :ss | '12:10' |
| '18:06:45' | ||
| Boolean | true() or false(), 1 or 0, 't' or 'f' | true |
| 't' | ||
| 'F' |
Automatic Conversion
CaseMaster is lenient and will convert parameters from one datatype to another where possible or required. For example, the expression add( 1, '6' ) will return 7. CaseMaster will simply convert the string '6' to the integer 6.
Other examples of automatic conversion are:
| Expression | Result | Explanation |
|---|---|---|
concat( 'Hello', ' ', 1 ) |
'Hello 1' | The integer 1 will be converted to the string '1' |
addDay( '1 jan 2024', 1 ) |
#2/1/2024# | The string '1 jan 2024' will be converted to a date |
gt( '12', 2 ) |
false() |
The datatype of the first parameter is leading, the integer 2 will be converted into the string '2' and '12' is less than '2' (gt means greater than) |
The latter example shows that automatic conversion does not always give the desired results.
Dynamic Values
Dynamic values are a special type of attributes. The majority of attributes are linked to a column; the data is stored in the database on insert / update and retrieved from the database when read.
The following is a snippet taken from a typical BO .cms file:
firstName: <@bo/attribute
label: 'First name'
column: 'firstName'
dataType: datatype.String
length: 200
optional: false()
>
A dynamic attribute does not have a column; instead, the value is calculated on the fly based on an expression.
Imagine we have 4 attributes; title, firstName, middleName and surName and we would like to have an attribute fullName that takes the 4 attributes to create a full name for display purposes; as per following examples:
| Title | First name | Middle name | Sur name | Full name |
|---|---|---|---|---|
| Mr | John | - | Smith | Mr John Smith |
| Mrs | Josie | - | Brown | Mrs Josie Brown |
| Mr | Kees | van der | Broek | Mr Kees van der Broek |
An expression would have to implement something along the following lines:
- Concatenate title, first name, middle name and surname and seperate by a spaces
- As middle name is optional, make sure we do not end up with 2 consecutive spaces between first- and surname when there is no middle name
The definition of the attribute could look as follows:
_fullname: <@bo/attribute/dynamic
label: 'Name'
ensureLoadGroup: 'title,forename,middleName,surname'
sortAttr: 'surName'
dynamicValue: $buildstring(
' ',
bo.attrFormatted( [_me], 'title' ),
bo.attr( [_me], 'firstName' ),
bo.attr( [_me], 'middleName' ),
bo.attr( [_me], 'surname' )
)
>
- As a convention, we start the names of dynamic attributes with an underscore. This is not a CaseMaster requirements but simply a convention in our team to make dynamic attributes stand out
- The optional ensureLoadGroup tag can be used to list any number of attributes (from this BO and with exception of dynamic attributes) that must be loaded from the database to successfully evaluate the expression
- By default, CaseMaster does not allow you to sort on (or search by) dynamic attributes; simply because sorting and searching is done through the database. You can however use the optional sortAttr tag to list an attribute (again, from the same BO and not a dynamic attribute) that the user can sort by so it feels the result list is sorted by the dynamic attribute
- The \$-sign in front of the expression that makes up the dynamic value is essential. The \$-sign will let CaseMaster know to not evaluate and cache the expression when the file is first loaded and parsed but to re-evaluate the expression every time it is required.
- The
buildString()function will concatenate any number of strings using the first parameter as the separator and only inserting the separator when needed - The
bo.attr()andbo.attrFormatted()functions will be covered later in this chapter
Function Handlers
In the last paragraph you have seen a reference to the functions bo.attr() and bo.attrFormatted(). You see their name differs from, say, random() and now() in that they are prefixed with bo..
The prefix bo refers to the function handler. All functions we have looked at so far are part of, what is known as, the default function handler and do not require any prefix.
The CaseMaster runtime comes with over 50 function handlers for different purposes and it is possible to add bespoke function handlers (developed in a .Net language and following the function handler guidelines). Find more information here.