> ## Documentation Index
> Fetch the complete documentation index at: https://docs.iru.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Iru Query Language

> Iru Query Language (IQL) is Iru's expression language for shaping mapped values: fields, operators, string functions, conditionals, and null-safe helpers.

When you map what an application receives at sign-on - the **Subject (NameID)**
for a [SAML app](/en/identity/applications/saml-applications), or the **subject
and claims** for an [OIDC app](/en/identity/applications/oidc-applications) - each
value is an **IQL expression**. IQL lets you pull from a user's profile and reshape
the value before it is sent.

<Info>
  **IQL** (Iru Query Language) is Iru's expression language for **mapping**, used in several places:

  * The attributes and claims an application receives at sign-on.
  * The fields a connected source maps into your directory (see
    [Attribute mapping](/en/identity/directory/attribute-mapping)).
  * [Auto Group](/en/identity/directory/auto-groups) rules and list filters.

  The same syntax works everywhere IQL appears.

  IQL is built on [CEL (Common Expression Language)](https://cel.dev), the open
  expression-language standard, so any expression that is valid in CEL is valid in
  IQL.
</Info>

As you type, the mapping editor suggests the available fields, functions, and
operators, and shows a live **preview** of the result. An expression must
**type-check** in the editor and again when you save, so mistakes surface before
they ever reach a sign-on or a sync.

## Referencing your data

What you reference depends on where the expression runs:

* **Application mapping** starts from the `user` object, whose fields are your
  directory's [profile attributes](/en/identity/directory/schema):

  ```
  user.email
  user.username
  user.id
  ```

  The defaults reflect this: an OIDC app's subject defaults to `user.id`, and a
  SAML app's Subject defaults to `user.username`.

* **Directory Sync mapping** references the **source's field names** directly, as
  they come from the connected system:

  ```
  email_work
  first_name
  ```

Field names are **case-sensitive**. Reach into nested values with a dot
(`user.profile.team`), and into a list or map with `[...]` (covered below).

## Building blocks

| Form             | Example                    | What it is                                   |
| ---------------- | -------------------------- | -------------------------------------------- |
| Field / variable | `first_name`, `user.email` | A value by name, or a field on a value.      |
| Method call      | `user.email.upperAscii()`  | A function called **on** a value.            |
| Indexing         | `parts[0]`                 | An element of a list by zero-based position. |
| Map key          | `entry["label"]`           | The value stored under a string key.         |
| Grouping         | `(a + b) * c`              | Parentheses to control evaluation order.     |

## Literals

```
"hello"                             // string (double quotes)
'hello'                             // string (single quotes)
42                                  // whole number
3.14                                // decimal number
true   false                        // booleans
null                                // null
["a", "b", "c"]                     // list
{"label": "work", "primary": true}  // map (string keys)
```

Strings support the usual escapes, such as `\n`, `\t`, `\\`, `\"`, and `\uXXXX`.

## Operators

<Tabs>
  <Tab title="Arithmetic">
    | Operator    | Example                        | What it does                        |
    | ----------- | ------------------------------ | ----------------------------------- |
    | `+`         | `first_name + " " + last_name` | Adds numbers, or **joins strings**. |
    | `-` `*` `/` | `a * b`                        | Subtract, multiply, divide.         |
    | `%`         | `a % b`                        | Remainder (modulo).                 |
  </Tab>

  <Tab title="Comparison">
    | Operator          | Example                     | What it does          |
    | ----------------- | --------------------------- | --------------------- |
    | `==` `!=`         | `user.domain == "acme.com"` | Equal, not equal.     |
    | `<` `<=` `>` `>=` | `user.level >= 3`           | Ordering comparisons. |
  </Tab>

  <Tab title="Logical">
    | Operator          | Example               | What it does |
    | ----------------- | --------------------- | ------------ |
    | `&&`              | `a && b`              | And.         |
    | <code>\|\|</code> | <code>a \|\| b</code> | Or.          |
    | `!`               | `!a`                  | Not.         |
  </Tab>

  <Tab title="Membership & choice">
    | Operator | Example                                  | What it does                                          |
    | -------- | ---------------------------------------- | ----------------------------------------------------- |
    | `in`     | `user.domain in ["acme.com", "acme.io"]` | True if the value is in a list, or a key is in a map. |
    | `? :`    | `name != "" ? name : "unknown"`          | Conditional: choose one value or another.             |
  </Tab>
</Tabs>

### Precedence

From tightest-binding to loosest. When in doubt, add parentheses.

```
1) a.b   a()   a[i]   ()      // member access, calls, indexing, grouping
2) !a    -a                   // unary not, negation
3) *  /  %                    // multiply, divide, remainder
4) +  -                       // add, subtract (and string +)
5) <  <=  >  >=  in           // comparison and membership
6) ==  !=                     // equality
7) &&                         // and
8) ||                         // or
9) ? :                        // conditional
```

## String functions

String operations are written as **methods** on a value, in the form
`value.method(...)`:

| Method                      | Example                                     | What it does                                                 |
| --------------------------- | ------------------------------------------- | ------------------------------------------------------------ |
| `upperAscii` / `lowerAscii` | `user.email.lowerAscii()`                   | Upper- or lower-case the value.                              |
| `trim`                      | `first_name.trim()`                         | Remove surrounding whitespace.                               |
| `split`                     | `user.email.split("@")`                     | Split into a list by a separator; index it with `[n]`.       |
| `replace`                   | `phone.replace("-", "")`                    | Replace every occurrence of one substring with another.      |
| `contains`                  | `user.email.contains("+")`                  | True if the value contains a substring.                      |
| `startsWith` / `endsWith`   | `user.email.endsWith("@acme.com")`          | Test how the value begins or ends.                           |
| `indexOf`                   | `username.indexOf(".")`                     | Position of a substring, or `-1` if absent.                  |
| `matches`                   | `user.email.matches("^[a-z]+@acme\\.com$")` | True if the value matches a regular expression.              |
| `size`                      | `user.email.split("@").size()`              | Length of a string or list. Also available as `size(value)`. |

## Conditionals and defaults

The conditional operator is the simplest way to supply a fallback when a value
might be blank:

```
// Use the first name, or fall back to the username when it's empty
user.firstName != "" ? user.firstName : user.username
```

For richer null handling, IQL also has **optional** (null-safe) helpers, below.

## Optional values

Optional helpers let you work with values that **might be missing** without
causing an error. An *optional* either holds a value or is empty.

<Tabs>
  <Tab title="Create">
    ```
    optional.of(value)            // wrap a value as an optional
    optional.ofNonZeroValue(value) // empty if the value is "zero" (see below)
    optional.none()               // an empty optional
    ```

    `ofNonZeroValue` treats these as empty: an empty string `""`, `0`, `false`,
    an empty list `[]`, an empty map `{}`, and `null`.
  </Tab>

  <Tab title="Access safely">
    ```
    value.?field     // optional field access (yields an optional)
    list[?i]         // optional index (empty instead of an error if out of range)
    ```
  </Tab>

  <Tab title="Unwrap">
    ```
    opt.hasValue()          // true if the optional holds a value
    opt.value()             // the inner value (errors if empty)
    opt.orValue(fallback)   // the value, or the fallback if empty
    a.or(b)                 // the first of two optionals that has a value
    ```
  </Tab>

  <Tab title="Transform">
    ```
    opt.optMap(x, expr)      // transform the inner value if present, else stay empty
    opt.optFlatMap(x, expr)  // like optMap, when expr itself returns an optional
    ```
  </Tab>
</Tabs>

```
// A default when a field is empty
optional.ofNonZeroValue(first_name).orValue("anon")

// Split an email and safely take the domain, falling back to ""
optional.ofNonZeroValue(email_work).optMap(e, e.split("@"))[?1].orValue("")
```

## Comments and whitespace

Whitespace is not significant, and `//` starts a comment that runs to the end of
the line:

```
user.firstName + " " + user.lastName   // build a display name
```

## Examples

```
// A field, as-is
user.email

// Upper-case the value
user.email.upperAscii()

// Build a display name from two fields
user.firstName + " " + user.lastName

// The local part of an email, before the "@"
user.email.split("@")[0]

// A field from the person's first address
user.addresses[0].city

// Choose a fallback when a field is blank
user.firstName != "" ? user.firstName : user.username

// A structured value, built as a map
{"email": user.email, "primary": true}
```

<Tip>
  Use the **preview** in the mapping editor to confirm an expression produces what
  you expect before publishing - it renders the exact value Iru will send or store.
</Tip>

## Where to go next

<CardGroup cols={2}>
  <Card title="Application mapping" icon="arrows-left-right" href="/en/identity/applications/application-mapping">
    Map IQL values into the assertion or token an application receives.
  </Card>

  <Card title="Attribute mapping" icon="code" href="/en/identity/directory/attribute-mapping">
    Use the same IQL to map a connected source into your directory.
  </Card>

  <Card title="Auto Groups" icon="wand-magic-sparkles" href="/en/identity/directory/auto-groups">
    Drive group membership from IQL rules over profile attributes.
  </Card>

  <Card title="Profile attributes" icon="table-list" href="/en/identity/directory/schema">
    The `user` fields your expressions draw from.
  </Card>
</CardGroup>
