IQL Semantics

Evaluation

IQL statements executes in two phases.

  1. The evaluation phase, where the entire IQL expression is evaluated into a list of actions.

  2. The execution phase, where those actions are executed, causing side effects

In other words, IQL expressions are pure - there are no side effects during the evaluation phase. This comes with some implications, one being that if you use set, you cannot immediately read the results.

Let’s take a look at an example:

Example

set F1 = F1 + 1
set F2 = F1

It may come as a surprise that after this rule has been executed, F2 is not the same as F1, but rather one less! This is because at the time of evaluation, nothing has been executed yet - the second line doesn’t see the side effects of the first line.

The solution to this is to use let to store intermediate values. This is not a side effect, since the value is only visible inside the expression:

Example with let

let @val = F1 + 1
set F1 = @val
set F2 = @val

It is sometimes effective to split your IQL into separate actions, or into separate rules. In the example below, an IQL Rule, the evaluation phase determines that a new record must be created, and a count of records must be calculated, but there’s a subtle problem: the new record has not yet been created when the count is evaluated.

for Invoice where Service = Installation do
    insert Log
        values Description = 'Installation invoiced on ' || today()
end
set "Number of logs" = count(recordname) from Log

Instead, you must split the above into two actions:

for Invoice where Service = Installation do
    insert Log
        values Description = 'Installation invoiced on ' || today()
end
set "Number of logs" = count(recordname) from Log

Another way to solve this would be to simply add 1 to the count.

This also applies to IQL in Forms, with the exception that actions cannot be split there, but you can combine variables and triggering of rules.

Consider using the Rule debug tool when triggering rules where you can see the evaluation and execution results per action.

Execution

Actions are executed sequentially in the order they are evaluated, with one exception. trigger actions are pushed to the end.

Example 1 (with actual execution order in numbers)

insert Log
    values Description = 'Log created on ' || today() (1)

trigger "Calculation of Number of logs" (3)

set "Contains historical log" = true (2)

Based on the sequence of the evaluation phase, in this query a record will be created first, then a checkbox will be ticked, and at the end the calculation of number of logs will be set. If the "Contains historical log" field is used in "Calculation of Number of logs", it will see the true value, despite it being set later.

The same is true if a loop is used. All trigger actions are grouped together at the end. This rule:

Example with execution actual order:

for Invoice where Status = "Not sent" do
    set Status = Sent (1)
    set "Invoice date" = now() (2)
    trigger "Send invoice mail" (3)
end

will first update the fields on all matching records, then trigger the other rule once for each matching Invoice.