Expressions and Rules
What to know
Expression rules are reusable logic: typed rule inputs plus an expression body. a! functions cover components and queries (for example a!queryRecordType and a!queryFilter); built-in scalar functions cover strings, dates and maths (concat(), text(), date(), sum()). Use a!localVariables for intermediate values, and test a rule in the expression editor with realistic inputs before wiring it into a process.
Queries return a data subset with .data, .totalCount, and paging information. Filtering, sorting, and paging belong inside the query object; fetching a whole record type and filtering in memory is a classic performance trap.
Traps
- Nulls. Comparisons against null do not behave intuitively; use
a!isNullOrEmpty()or an explicit null check, and remember nulls can propagate through arithmetic and concatenation. - Types. Text '5' and Integer 5 are different; cast with
tointeger(),todecimal()ortext()instead of relying on implicit conversion. - Empty lists. Guard before indexing with
index(), or the rule errors at runtime even if the branch looks safe. - Blank filter values. An empty filter value can silently widen a query, so test what happens when the user leaves a filter empty.
Worked example
Fetch open tickets for a status input:
a!queryRecordType(recordType: recordType!Ticket, filters: a!queryFilter(field: recordType!Ticket.fields.status, operator: "=", value: ri!status), pagingInfo: a!pagingInfo(startIndex: 1, batchSize: 50))
Run it in the test tab with a real status and with a blank one, checking .totalCount as well as .data.
Rule of thumb: filter, sort and page inside the query - never inside the interface.