Skip to main content

Expressions

Reqon uses the Vague expression language for data manipulation. This page covers the most common expressions; for complete documentation, see the Vague documentation.

Literals​

// Numbers
42
3.14
-100

// Strings (double quotes only - there is no single-quoted form)
"hello world"

// Booleans
true
false

// Null
null

// Arrays
[1, 2, 3]
["a", "b", "c"]

// Objects
{ key: "value", nested: { a: 1 } }

Property access​

// Dot notation
.name
.address.city
.items[0].name

// Within context
user.name
response.data.items

// Array indexing
.items[0]
.items[length(.items) - 1]

Operators​

Arithmetic​

1 + 2 // 3
10 - 3 // 7
4 * 5 // 20
20 / 4 // 5

There's no modulo operator. The + operator also concatenates strings (see below).

Comparison​

.a == .b // equality
.a != .b // inequality
.a > .b // greater than
.a >= .b // greater or equal
.a < .b // less than
.a <= .b // less or equal

Logical​

.a and .b // logical AND
.a or .b // logical OR
not .a // logical NOT

String​

The + operator concatenates strings (and coerces a number operand to a string). There are no string-matching operators like contains, startsWith, or endsWith:

.first + " " + .last // concatenation
"id-" + .id // number coerced to string

Conditional expressions​

Ternary​

The ternary operator is the only inline conditional. There's no if/then/else expression:

.status == "active" ? "Yes" : "No"

// Chain for multiple branches
.age >= 18 ? "Adult" : .age >= 13 ? "Teen" : "Child"

Null coalescing​

or returns its left side when truthy, otherwise the right side:

.name or "Unknown"
.email or .backup_email or "no-email@example.com"

Built-in functions​

The expression language ships a small, fixed set of functions. Anything not in this list isn't available.

// Collections
length([1, 2, 3]) // 3 (also works on strings)
count([1, 2, 3]) // 3
sum([1, 2, 3]) // 6 (array of numbers)
first([1, 2, 3]) // 1
last([1, 2, 3]) // 3

// Number sequence: start-inclusive, end-exclusive
range(3) // [0, 1, 2]
range(1, 4) // [1, 2, 3]

// Rounding
round(3.7) // 4
floor(3.7) // 3
ceil(3.2) // 4

// Current time (ISO 8601 string)
now()

// Environment variable (name must be a string literal)
env("API_KEY")

range() materialises the whole array, because a for loop consumes an array. That makes it the way to drive a bulk fetch over contiguous ids without writing an input file first:

for id in range(1, 500001) concurrency 192 {
get "/entry/{id}/" { source: API }
}

It's capped at 20,000,000 items, so a mistaken bound fails loudly instead of exhausting memory.

There are no string, date, object, or higher-order array functions (no lowercase, split, parseDate, map, filter, keys, and so on). Build derived values from operators and these functions, or shape data upstream.

Type checks​

Use is to test a value's runtime type:

.value is string
.value is number
.value is boolean
.value is array
.value is object
.value is null

Environment variables​

env("API_KEY")
env("BASE_URL")
env("DEBUG") == "true"

The argument to env must be a string literal, not a dynamic expression.

Pattern matching in expressions​

A match expression compares a value against literal patterns with =>, using equality, and returns the matching arm's value. The _ arm is the catch-all:

match .status {
"active" => "Active User",
"pending" => "Pending Approval",
"inactive" => "Deactivated",
_ => "Unknown Status"
}

This is the inline match expression. It's distinct from the match step (see Match), which routes on schemas and uses ->.

Other expression forms​

The Vague language also supports a few forms you'll see occasionally:

  • ^parent references a value in an enclosing scope.
  • a..b is a range.
  • any of <collection> where <condition> finds the first matching element.
  • response always refers to the latest fetch response.

Complex expression examples​

Data transformation​

map user -> Output {
fullName: .firstName + " " + .lastName,
isAdult: .age >= 18,
displayName: .nickname or .firstName
}

Aggregation​

map order -> Summary {
itemCount: length(.items),
totalRevenue: sum(.amounts),
avgItemValue: sum(.amounts) / length(.items)
}

Conditional logic​

map order -> PricedOrder {
discount: match .customerTier {
"gold" => 0.20,
"silver" => 0.10,
"bronze" => 0.05,
_ => 0
},
shippingFee: .total > 100 ? 0 : 9.99
}

Validation conditions​

validate order {
assume .id is string,
assume length(.items) > 0,
assume sum(.amounts) > 0,
assume .createdAt != null,
assume .shippingDate == null or .shippingDate >= .createdAt
}

For the complete expression language reference, visit the Vague documentation.