# Expressions in Novulo

**URL:** <https://community.novulo.com/t/expressions-in-novulo/156>\
**Category:** Wiki\
**Tags:** implementation, getting-started\
**Created:** [May 2, 2024, 11:52am UTC](https://community.novulo.com/t/expressions-in-novulo/156 "2024-05-02T11:52:29Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Reinier](https://avatars.discourse-cdn.com/v4/letter/r/f08c70/32.png) [@Reinier](https://community.novulo.com/u/Reinier)\
**Post date:** [May 2, 2024, 11:52am UTC](https://community.novulo.com/t/expressions-in-novulo/156/1 "2024-05-02T11:52:29Z")

</div>

# Expressions in Novulo

Novulo has its own expression language. It is used for the development of components and for the configuration of applications. It allows for the retrieval of data and the calculation of values. Novulo expressions are parsed into SQL SELECT statements during their execution. They can be built/displayed visually in the architect or as plain text.

Novulo has its own expression language, for several reasons:

- It allows for creating expressions visually using low code in the Architect
- It has a convenient syntax
- Evaluating a Novulo expressions is divided in useful steps

And more technical reasons that I won’t elaborate on for now:

- It can work with the Reference Architecture
- It can get data from the database, IIS webserver and Javascript
- It’s independent of database software and version

Our expression language is used everywhere: **in development _and_ implementation**. You can approach the expression language from different angles, but in this article I’ll start with the development angle, as the most fundamental aspects of the language will make the most sense.

# Novulo Expressions in the Architect

In development you’ll use expressions to:

- Give **properties** to elements  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/5b57af27d420974c3fa87c20b1ef23588ddbccea.png)  
Example of a visibility property
- Create **functions**  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/0c3164a844e28dd772f80cbe57eaeb9cf3b3f7ec.png)  
Example of functions
- Fill in **parameters** of processes.  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/924aa12643355e9ca477ba8f1d87319cf0db3714.png)  
Example of the parameters of a process component

Every expression can be created using the low code **Expression Editor** , where the **palette** shows all the available operators and the **context** shows all the available data

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/8e38b939f6dfd80b46e6e558d2058f98ad75cea9.png)  
Example of a function in the Expression Editor

## Datatype

Depending on the **datatype** of your expression, you can choose the appropriate operators. For instance, if your expression has to return the datatype `string (text)`, you can use the operator `Concat` to concatenate multiple string values.

The datatype of your expression depends on where the expression is used. If your expression is a function, you can set the type as you wish.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/779168b34841a90a07304577dff16547e870f63b.png)  
Setting the datatype for a new function

If your expression is used for a property or a parameter, the type is predetermined and your expression needs to adhere to the property or parameter. For instance, a visibility condition always has the datatype `Boolean`, meaning you can use operators like `Equals`, `GreaterThan`, `And`, `Or`, `If`, etc.

We can seperate datatypes in 5 categories:

- **Primary** datatypes
  - Are readable for humans
  - `int`, `string`, `date`, `money`, etc.

- **Enumerations**
  - Fixed tables with descriptions and id’s
  - Are not readable for humans; we either read the description or the id
  - Can be created in the Architect
  - `YesNo`, `DraftFinal`, `ContactType`, etc.

- **Record datatypes** or **RecordTypes**
  - Dynamic tables with defined columns and undefined rows
  - Are not readable for humans; we only read the columns with primary datatypes
  - Are all created in the Architect
  - `contacts`, `products`, etc.

- **Lists**
  - Lists of the same datatype
  - Can be made with fixed items of a dynamic range of items
  - `LiteralList`, `List<int>`, `List<YesNo>`, `List<products>`, etc.

- **Tuples**
  - Pairs of values of any datatype
  - Often the first value is a string, which functions as a ‘key value’
  - `Tuple<string,products>`, etc,

You can always see the expected datatype in the expression editor at the top or top-right of the grey input box. Furthermore, if you select the box, your palette will grey out all operators that won’t work and leave the available operators blue.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/fae503f94ee6778a2f2ba12a066e4c579469102b.png)  
A `String` function can use `Concat`, but not `Contains`

Most operators have parameters, which are again specified in the grey boxes.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/fa5c3658f84f4086419c29c2e9f4f11e955fe4f1.png)  
The `StringJoin` operator has a `String` parameter called “separator” and a `List<String>` parameter called “input”

## Context

Depending on **_where_ you make your expression** , you have **access to different data**. For instance, if you add a function to the Person page, you can use the data from the Persons record. The Persons record is the **context** of this expression.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/0709bc30250d839eb207d6821632959e3058bde5.png)  
The function “Telephone number” uses the data `mobile` and `telephone` from the Persons record

This applies to _every_ expression.

- Expressions on a **page** can use the data of that record;
  - Functions on the page
  - Properties of elements (visibility, editability, validation)

- Expressions on a **grid** can use the data of that list of records;
  - Filter property of the table
  - Function columns

- Expressions in a **process** use the data of that process (trigger, action return values);
  - Parameters of actions and decisions

Every expression has a context, and some expressions have different _layers_ of context. If you are working in a context, and include a list of different data, then that list will have it’s own context. A couple of examples are:

- When grids are added to a detail page. The first context is the record of the page, the second context is the records in the grid.  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/1c18af07df496528e9595864294be403bf10e904.png)  
On the Organization page, the Addresses table is added. The first context is the Organization record and the second context is the Addresses records\*
- When a dropdown field or a search link is added to a detail page. The first context is the record of the page, the second context is the records of the data source of the dropdown field/search link.  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/cc2e5898fcff8c2755a003ec778085ea559bf2c5.png)  
On the Person page, the dropdown field “Primary employer” is added. The first context is the Person record and the second context is the data source of the dropdown field “Connection contacts”\*
- When a list expressions is used in another expression.  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/a9a98fcf80c2cb609875bfcc612e2f45bb8ff22b.png)  
The function “Has user account” on the Person page uses the `Count` operator, which has `List of N_ApplicationLoginAccount`, a list of “User accounts”, as input. The first context is the Person record and the second context is the User account records\*

> Note that I sometimes refer to context as one record, and sometimes as multiple records. Technically, the context of an expression is always one record. If an expression is made in the context of a list, you have to imagine the expression being evaluated for _every one record_ within that list seperately.

#### Parent context

Usually, when an expression is in a second layer of context, you need to refer to the upper layer. We call this referring to the **parent context**. You do this with the `ParentContext` operator. The most common example is **filtering** your list based on the parent context.

In the previous 3 examples, all lists are filtered: the Addresses grid only shows addresses that belong to the Organization; the Primary employer dropdown only shows connection contacts that belong to the Person and the “Has user account” function only counts user accounts that belong to the person.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/3f40233f23d7e5947c7aa718ad205d6fec3575a3.png) ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/930e4d76825648f9476d788abe026917d41ceab1.png) ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/5bacd7b5506f5643f714b34023fbced90f1a7966.png)  
Notice how the context in the Expression Editor changes depending on the selected parameter

If you want to test the expressions that you build in the architect you can of course deploy the component and view the result in your application. However, it is also possible to [debug architect expressions](https://community.novulo.com/t/debugging-architect-expressions/355) without having to wait for whole deployment cycle. This can significantly speed up your development process.

# Novulo Expressions in your application

If you want to use Novulo Expressions in your configuration, you need to know _where_ the expressions are used, and _how_.

## Expression field

In the configuration of your application, you’ll use expressions in every instance of an **expression field**. These are implemented in various components with various functionalities. These expression fields have a predefined [datatype](https://community.novulo.com/t/expressions-in-novulo/156#p-308-datatype-3), and a predefined [context](https://community.novulo.com/t/expressions-in-novulo/156#p-308-context-4). This means that the expression field _knows_ which expressions are (in)valid, and this allows for the expression field to have auto-complete functionality.

Examples of implementations of the expression field are:

- Novulo Export  
 ![afbeelding](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/1bacb7626960f9ead467ea0265e5d071cbb77e23.png)  
In an export dataset, the proofing record, filter expression and sort expression are all expression fields. The proofing record has _no_ context, and returns the datatype `addresses`. The filter expression has the context `addresses` and returns the datatype `boolean`. The sort expression has the context `addresses` and returns the datatype `[sortfunctions]` (`[]` meaning a _list_ of sortfunctions)

#### Auto-complete

The auto-complete functionality is triggered by `Ctrl + Space`. You’ll get a list of all the available fields and functions within the context of the expression field. If the context of your expression changes, the auto-complete follows.

 ![afbeelding](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/55fbb55f12c3c0306560742f38c61260b4a02ec7.png)  
The auto-complete of this filter expressions shows the fields and functions of the `addresses` datatype

#### Error handling

Before saving your record, the expression field will validate your expression. It will check whether:

- The expression returns the correct datatype
- The fields and functions used in the expression exist within the context
- Correct **syntax** is used

If your expression is invalid, you can read the error by hovering over the orange triangle.  
 ![afbeelding](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/046ab0541e32bed6c0dcc872c6bd0644a939fe89.png)  
The filter expression requires the datatype `boolean`, but the expression `"this is not a boolean expression"` returns the datatype `string`

#### Expression debugger

Every application is deployed with the expression debugger. This tool has a couple of features that help you to write expressions more easily.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/beef6bce38a839a3f2cee5e48936f6230ba4d518.png)  
You can find the expression debugger in the toolbar at the top-right of your application.

- **Evaluate** expressions on the left
- Open the **data model** to get an overview of all _primary_, _enumeration_ and _record_ datatypes, and all _fields_ and _functions_ that exist for those datatypes  
 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/3550c05dfa549a8d53b3ffe87a1ec3cfdefe31a9.png)  
Use the “Evaluate” button to get a result for your written expression, and use the “Datamodel” button to open the data model on the right.

Make sure to test out the examples used in the next chapter in the expression debugger of your application!

## Syntax

I’ll divide the syntax of our expression language into two categories: evaluating a _single_ expression vs. evaluating _multiple_ expressions. If you know how to evaluate a single expression, you can use this expression in a _list_ or _tuple_ format to evaluate multiple expressions at the same time (returning a list or tuple of results)

#### Syntax for evaluating a single expression

An expression can be evaluated with or without [context](https://community.novulo.com/t/expressions-in-novulo/156#p-308-context-4), where evaluating an expression _with context_ is an extension of evaluating _without context_. As such, we’ll start by looking at the syntax for expressions without context, and then look at what shortcuts are provided by context.

- The basis of every expression starts by declaring a data type, followed by a colon, and then calling a function, which always ends in two brackets: **`DataType:function()`**. The most basic function is `load()`; allowing you to select a specific value from a data type

> `int:load(1)` returns the integer number 1  
> `money:load(1)` the value 1 for the current currency (i.e. €1,00)  
> `yesno:load(1)` returns from the enumeration `yesno` the item with id 1 (yes)  
> `persons:load(2)` returns from the table `persons` the record with id 2  
> `datetime:now()` returns the current date and time  
> ` string:getnull()` returns an empty string (not to be mistaken with the string `""`, which is _not_ empty!

- The result of evaluating a function - or any expression - is a **context object**. You can expand on this context object with a period, and then calling a field or another function: **`.field`** or **`.function()`**. This can happen as often as needed

> `yesno:load(1).description` returns the description of `yesno:load(1)`, “Yes”  
> `persons:load(2).age()` returns the age of the person with id 2  
> `persons:load(2).primary_address.country.iso_code` returns the ISO code of the country of the primary address of the person with id 2

- Sometimes, a function requires one or more **parameters**. The amount and data type of the parameters is determined by the function, and by the data type from which the function is called. As seen in the examples above, `load()` usually requires one integer parameter. However, `date:load()` requires a string parameter in the format “YYYY-MM-DD”

> `date:load("2024-06-12")` returns the date of writing this chapter  
> `date:load("2024-06-12").adddays(int:load(-1))` returns the date of the first Novulo Composable Futures event  
> `int:load(1).add(int:load(1))` returns the integer number 2  
> `persons:load(2).primary_address.country.iso_code.substring(0,1)` returns the first letter of the ISO code of the country of the primary address of the person with id 2

- Sometimes basic functions for primary values can be skipped

> `int:load(1).add(1)` returns the integer number 2  
> `money:load(1).add(1)` returns the value 2 for the current currency (i.e. €2,00)

Usually, an expression is written in some existing context. This means that a context object is already available and you can immediately evaluate an expression to it: you can **skip the `DataType:function()` part**.

You can simulate context in the expression debugger, by selecting a record in the “Context” area. The following examples assume that the context is `persons:load(2)`.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/a41cc67eb53eac6ca0bf39ab4f496ea54b766e26.png)

- **`this`** returns the current context

> `this` returns the person with id 2  
> `this.age()` returns the age of the person with id 2  
> `persons:load(3).equals(this)` returns `false`

- In most cases, you can **skip** `this` in your expressions

> `age()` returns the age of the person with id 2  
> `primary_address.country.iso_code` returns the ISO code of the country of the primary address of the person with id 2

Sometimes, your expression also has [parent context](https://community.novulo.com/t/expressions-in-novulo/156#p-308-parent-context-5). This can be simulated in the expression debugger by selecting another record in the context area, seperated by a comma. The following examples assume that the context is `persons:load(2)` and that the parent context is `organizations:load(1)`.

 ![image](https://canada1.discourse-cdn.com/flex008/uploads/novulo/original/1X/785f545603887bee360548b7c38f443a2347b227.png)

- **`parent`** returns the current parent context

> `parent` returns the organization with id 1  
> `parent.is_my_organization` returns the value of the check box “Is my organization” of the organization with id 1  
> `this.primary_connection.connection_to.organization().equals(parent)` returns the answer to the question “Is organization 1 the primary employer of person 2?”

#### Syntax for evaluating multiple expressions

Now that you know how to evaluate a singular expression, you can create lists or tuples. Lists can be static or dynamic, and tuples are always a static pair of two expressions.

- Static lists are created by putting expressions, comma seperated, between square brackets: **`[Expression1, Expression2, ...etc.]`**

> `[1,2,3]` returns a list of numbers 1-3  
> `[1,"2",money:load(3)]` returns a list of the number 1, the string “2”, and the value 3 for the current currency (i.e. €3,00)  
> `[persons:load(2).age(),persons:load(3).age(),persons:load(4).age()]` returns a list of the age of the persons with id 2-4

- Dynamic lists are created by declaring the data type, the expression you want to evaluate, the filter of your data, and finally the sorting of your data:  
**`{RecordType, Expression, Filter, Sorting}`**.  
The expressions used in this list, always have the data type as context. The filter and sorting are optional.

> `{persons,this}` returns a list of all persons  
> `{persons,age()}` returns a list of the age of all persons  
> `{persons,name, id.isgreater(2)}` returns a list of the names of all persons with an ID higher than 2  
> `{persons,name, true, id.desc}` returns a list of the names of all persons without filtering. The list is sorted by ID descendiing. The person with the highest ID is the first one in the returned list.

---

<div class="post-metadata">

**Author:** ![Reinier](https://avatars.discourse-cdn.com/v4/letter/r/f08c70/32.png) [@Reinier](https://community.novulo.com/u/Reinier)\
**Post date:** [January 10, 2025, 9:14am UTC](https://community.novulo.com/t/expressions-in-novulo/156/2 "2025-01-10T09:14:58Z")

</div>

If you have a background in SQL, have a look at [this article](https://community.novulo.com/t/learn-expressions-for-new-novulo-users-with-a-sql-background) for comparisons between Novulo expressions and SQL queries!
