# CEL Reference

This is a reference for Common Expression Language (CEL) methods, functions, and macros available in Dsynct transformations.

## Methods

### bytes

| Method         | Return Type |
| -------------- | ----------- |
| `bytes.size()` | `int`       |

### google.protobuf.Duration

| Method                                       | Return Type |
| -------------------------------------------- | ----------- |
| `google.protobuf.Duration.getHours()`        | `int`       |
| `google.protobuf.Duration.getMilliseconds()` | `int`       |
| `google.protobuf.Duration.getMinutes()`      | `int`       |
| `google.protobuf.Duration.getSeconds()`      | `int`       |

### google.protobuf.Timestamp

| Method                                              | Return Type |
| --------------------------------------------------- | ----------- |
| `google.protobuf.Timestamp.getDate()`               | `int`       |
| `google.protobuf.Timestamp.getDate(string)`         | `int`       |
| `google.protobuf.Timestamp.getDayOfMonth()`         | `int`       |
| `google.protobuf.Timestamp.getDayOfMonth(string)`   | `int`       |
| `google.protobuf.Timestamp.getDayOfWeek()`          | `int`       |
| `google.protobuf.Timestamp.getDayOfWeek(string)`    | `int`       |
| `google.protobuf.Timestamp.getDayOfYear()`          | `int`       |
| `google.protobuf.Timestamp.getDayOfYear(string)`    | `int`       |
| `google.protobuf.Timestamp.getFullYear()`           | `int`       |
| `google.protobuf.Timestamp.getFullYear(string)`     | `int`       |
| `google.protobuf.Timestamp.getHours()`              | `int`       |
| `google.protobuf.Timestamp.getHours(string)`        | `int`       |
| `google.protobuf.Timestamp.getMilliseconds()`       | `int`       |
| `google.protobuf.Timestamp.getMilliseconds(string)` | `int`       |
| `google.protobuf.Timestamp.getMinutes()`            | `int`       |
| `google.protobuf.Timestamp.getMinutes(string)`      | `int`       |
| `google.protobuf.Timestamp.getMonth()`              | `int`       |
| `google.protobuf.Timestamp.getMonth(string)`        | `int`       |
| `google.protobuf.Timestamp.getSeconds()`            | `int`       |
| `google.protobuf.Timestamp.getSeconds(string)`      | `int`       |

### list

| Method                                   | Return Type                       |
| ---------------------------------------- | --------------------------------- |
| `list<A>.size()`                         | `int`                             |
| `list<T>.distinct()`                     | `list<T>`                         |
| `list<T>.reverse()`                      | `list<T>`                         |
| `list<T>.slice(int, int)`                | `list<T>`                         |
| `list<V>.first()`                        | `optional_type<V>`                |
| `list<V>.last()`                         | `optional_type<V>`                |
| `list<bool>.sort()`                      | `list<bool>`                      |
| `list<bytes>.sort()`                     | `list<bytes>`                     |
| `list<double>.sort()`                    | `list<double>`                    |
| `list<dyn>.flatten(int)`                 | `list<dyn>`                       |
| `list<google.protobuf.Duration>.sort()`  | `list<google.protobuf.Duration>`  |
| `list<google.protobuf.Timestamp>.sort()` | `list<google.protobuf.Timestamp>` |
| `list<int>.sort()`                       | `list<int>`                       |
| `list<list<T>>.flatten()`                | `list<T>`                         |
| `list<optional_type<V>>.unwrapOpt()`     | `list<V>`                         |
| `list<string>.join()`                    | `string`                          |
| `list<string>.join(string)`              | `string`                          |
| `list<string>.sort()`                    | `list<string>`                    |
| `list<uint>.sort()`                      | `list<uint>`                      |

### map

| Method             | Return Type |
| ------------------ | ----------- |
| `map<A, B>.size()` | `int`       |

### optional\_type

| Method                                  | Return Type        |
| --------------------------------------- | ------------------ |
| `optional_type<V>.hasValue()`           | `bool`             |
| `optional_type<V>.or(optional_type<V>)` | `optional_type<V>` |
| `optional_type<V>.orValue(V)`           | `V`                |
| `optional_type<V>.value()`              | `V`                |

### string

| Method                                | Return Type    |
| ------------------------------------- | -------------- |
| `string.charAt(int)`                  | `string`       |
| `string.contains(string)`             | `bool`         |
| `string.endsWith(string)`             | `bool`         |
| `string.format(list<dyn>)`            | `string`       |
| `string.indexOf(string)`              | `int`          |
| `string.indexOf(string, int)`         | `int`          |
| `string.lastIndexOf(string)`          | `int`          |
| `string.lastIndexOf(string, int)`     | `int`          |
| `string.lowerAscii()`                 | `string`       |
| `string.matches(string)`              | `bool`         |
| `string.replace(string, string)`      | `string`       |
| `string.replace(string, string, int)` | `string`       |
| `string.reverse()`                    | `string`       |
| `string.size()`                       | `int`          |
| `string.split(string)`                | `list<string>` |
| `string.split(string, int)`           | `list<string>` |
| `string.startsWith(string)`           | `bool`         |
| `string.substring(int)`               | `string`       |
| `string.substring(int, int)`          | `string`       |
| `string.trim()`                       | `string`       |
| `string.upperAscii()`                 | `string`       |

## Functions

### Base64

| Function                | Return Type |
| ----------------------- | ----------- |
| `base64.decode(string)` | `bytes`     |
| `base64.encode(bytes)`  | `string`    |

### Byte Order

| Function             | Return Type |
| -------------------- | ----------- |
| `be_to_int32(dyn)`   | `dyn`       |
| `be_to_int64(dyn)`   | `dyn`       |
| `reverse_bytes(dyn)` | `bytes`     |
| `to_be_int32(dyn)`   | `bytes`     |
| `to_be_int64(dyn)`   | `bytes`     |

### BSON

| Function                      | Return Type |
| ----------------------------- | ----------- |
| `bson_decimal128(dyn)`        | `dyn`       |
| `bson_decimal128_string(dyn)` | `string`    |
| `bson_object_id_string(dyn)`  | `string`    |
| `bson_uuid(dyn)`              | `dyn`       |
| `bson_uuid_string(dyn)`       | `string`    |

### Type Conversion

| Function                            | Return Type |
| ----------------------------------- | ----------- |
| `bool(bool)`                        | `bool`      |
| `bool(string)`                      | `bool`      |
| `bytes(bytes)`                      | `bytes`     |
| `bytes(string)`                     | `bytes`     |
| `double(double)`                    | `double`    |
| `double(int)`                       | `double`    |
| `double(string)`                    | `double`    |
| `double(uint)`                      | `double`    |
| `dyn(A)`                            | `dyn`       |
| `int(double)`                       | `int`       |
| `int(google.protobuf.Duration)`     | `int`       |
| `int(google.protobuf.Timestamp)`    | `int`       |
| `int(int)`                          | `int`       |
| `int(string)`                       | `int`       |
| `int(uint)`                         | `int`       |
| `string(bool)`                      | `string`    |
| `string(bytes)`                     | `string`    |
| `string(double)`                    | `string`    |
| `string(google.protobuf.Duration)`  | `string`    |
| `string(google.protobuf.Timestamp)` | `string`    |
| `string(int)`                       | `string`    |
| `string(string)`                    | `string`    |
| `string(uint)`                      | `string`    |
| `type(A)`                           | `type<A>`   |
| `uint(double)`                      | `uint`      |
| `uint(int)`                         | `uint`      |
| `uint(string)`                      | `uint`      |
| `uint(uint)`                        | `uint`      |

### Duration and Timestamp

| Function                               | Return Type                 |
| -------------------------------------- | --------------------------- |
| `duration(google.protobuf.Duration)`   | `google.protobuf.Duration`  |
| `duration(int)`                        | `google.protobuf.Duration`  |
| `duration(string)`                     | `google.protobuf.Duration`  |
| `timestamp(google.protobuf.Timestamp)` | `google.protobuf.Timestamp` |
| `timestamp(int)`                       | `google.protobuf.Timestamp` |
| `timestamp(string)`                    | `google.protobuf.Timestamp` |
| `now_millis()`                         | `int`                       |
| `now_nanos()`                          | `int`                       |

### JSON

| Function           | Return Type |
| ------------------ | ----------- |
| `json_decode(dyn)` | `dyn`       |
| `json_encode(dyn)` | `dyn`       |
| `json_number(dyn)` | `dyn`       |

### Collections

| Function                            | Return Type |
| ----------------------------------- | ----------- |
| `in(A, list<A>)`                    | `bool`      |
| `in(A, map<A, B>)`                  | `bool`      |
| `lists.range(int)`                  | `list<int>` |
| `sets.contains(list<T>, list<T>)`   | `bool`      |
| `sets.equivalent(list<T>, list<T>)` | `bool`      |
| `sets.intersects(list<T>, list<T>)` | `bool`      |
| `size(bytes)`                       | `int`       |
| `size(list<A>)`                     | `int`       |
| `size(map<A, B>)`                   | `int`       |
| `size(string)`                      | `int`       |

### Math

| Function                        | Return Type |
| ------------------------------- | ----------- |
| `math.abs(double)`              | `double`    |
| `math.abs(int)`                 | `int`       |
| `math.abs(uint)`                | `uint`      |
| `math.bitAnd(int, int)`         | `int`       |
| `math.bitAnd(uint, uint)`       | `uint`      |
| `math.bitNot(int)`              | `int`       |
| `math.bitNot(uint)`             | `uint`      |
| `math.bitOr(int, int)`          | `int`       |
| `math.bitOr(uint, uint)`        | `uint`      |
| `math.bitShiftLeft(int, int)`   | `int`       |
| `math.bitShiftLeft(uint, int)`  | `uint`      |
| `math.bitShiftRight(int, int)`  | `int`       |
| `math.bitShiftRight(uint, int)` | `uint`      |
| `math.bitXor(int, int)`         | `int`       |
| `math.bitXor(uint, uint)`       | `uint`      |
| `math.ceil(double)`             | `double`    |
| `math.floor(double)`            | `double`    |
| `math.isFinite(double)`         | `bool`      |
| `math.isInf(double)`            | `bool`      |
| `math.isNaN(double)`            | `bool`      |
| `math.round(double)`            | `double`    |
| `math.sign(double)`             | `double`    |
| `math.sign(int)`                | `int`       |
| `math.sign(uint)`               | `uint`      |
| `math.sqrt(double)`             | `double`    |
| `math.sqrt(int)`                | `double`    |
| `math.sqrt(uint)`               | `double`    |
| `math.trunc(double)`            | `double`    |

### Hashing

| Function      | Return Type |
| ------------- | ----------- |
| `md5(dyn)`    | `bytes`     |
| `sha1(dyn)`   | `bytes`     |
| `sha256(dyn)` | `bytes`     |

### Optional

| Function                                  | Return Type        |
| ----------------------------------------- | ------------------ |
| `optional.none()`                         | `optional_type<V>` |
| `optional.of(V)`                          | `optional_type<V>` |
| `optional.ofNonZeroValue(V)`              | `optional_type<V>` |
| `optional.unwrap(list<optional_type<V>>)` | `list<V>`          |

### Regex

| Function                                     | Return Type             |
| -------------------------------------------- | ----------------------- |
| `matches(string, string)`                    | `bool`                  |
| `regex.extract(string, string)`              | `optional_type<string>` |
| `regex.extractAll(string, string)`           | `list<string>`          |
| `regex.replace(string, string, string)`      | `string`                |
| `regex.replace(string, string, string, int)` | `string`                |

### Strings

| Function                | Return Type |
| ----------------------- | ----------- |
| `strings.quote(string)` | `string`    |

### UUID

| Function                   | Return Type |
| -------------------------- | ----------- |
| `uuid_v3_bytes(dyn, dyn)`  | `bytes`     |
| `uuid_v3_string(dyn, dyn)` | `string`    |
| `uuid_v4_bytes()`          | `bytes`     |
| `uuid_v4_string()`         | `string`    |
| `uuid_v5_bytes(dyn, dyn)`  | `bytes`     |
| `uuid_v5_string(dyn, dyn)` | `string`    |

## Macros

Macros are special constructs that are expanded at parse time and provide control flow and comprehension capabilities that cannot be expressed as regular functions.

### has

Tests whether a field is available on a message or key exists in a map.

**Signature:** `has(e.f)` -> `bool`

**Examples:**

```cel
has(user.address)           // true if 'address' field exists in the 'user' message
has(m.key_name)             // true if map 'm' has a key named 'key_name'
has(order.items)            // false if 'items' field is not set
```

### all

Tests whether all elements in a list or all keys in a map satisfy the given predicate. Behaves consistently with logical AND, including short-circuit evaluation and error absorption.

**Signatures:**

* `list(A).all(x, predicate)` -> `bool`
* `map(A, B).all(x, predicate)` -> `bool`

**Examples:**

```cel
[1, 2, 3].all(x, x > 0)                          // true
[1, 2, 0].all(x, x > 0)                          // false
['apple', 'banana'].all(fruit, fruit.size() > 3) // true
{'a': 1, 'b': 2}.all(key, key != 'b')            // false
```

### exists

Tests whether any element in a list or any key in a map satisfies the predicate. Behaves consistently with logical OR, including short-circuit evaluation and error absorption.

**Signatures:**

* `list(A).exists(x, predicate)` -> `bool`
* `map(A, B).exists(x, predicate)` -> `bool`

**Examples:**

```cel
[1, 2, 3].exists(i, i % 2 != 0)                     // true
[].exists(i, i > 0)                                 // false
[0, -1, 5].exists(num, num < 0)                     // true
{'x': 'foo', 'y': 'bar'}.exists(key, key == 'x')    // true
```

### exists\_one

Tests whether exactly one element in a list or key in a map satisfies the predicate. Does not short-circuit to ensure exactly one match.

**Signatures:**

* `list(A).exists_one(x, predicate)` -> `bool`
* `map(A, B).exists_one(x, predicate)` -> `bool`

**Examples:**

```cel
[1, 2, 2].exists_one(i, i < 2)                              // true (only 1 is < 2)
[1, 2, 3, 4].exists_one(num, num % 2 == 0)                  // false (2 and 4 are even)
{'a': 'hello', 'aa': 'world'}.exists_one(k, k.startsWith('a')) // false (both match)
```

### map

Transforms each element in a list or each key in a map by applying an expression. The three-argument form transforms all elements; the four-argument form only transforms elements matching a filter predicate.

**Signatures:**

* `list(A).map(x, transform)` -> `list(T)`
* `list(A).map(x, filter, transform)` -> `list(T)`
* `map(A, B).map(x, transform)` -> `list(T)`
* `map(A, B).map(x, filter, transform)` -> `list(T)`

**Examples:**

```cel
[1, 2, 3].map(x, x * 2)                              // [2, 4, 6]
[5, 10, 15].map(x, x / 5)                            // [1, 2, 3]
['apple', 'banana'].map(fruit, fruit.upperAscii())   // ['APPLE', 'BANANA']
[1, 2, 3, 4].map(num, num % 2 == 0, num * 2)         // [4, 8] (only even numbers)
```

### filter

Returns a list containing only the elements from the input list or keys from a map that satisfy the predicate.

**Signatures:**

* `list(A).filter(x, predicate)` -> `list(A)`
* `map(A, B).filter(x, predicate)` -> `list(A)`

**Examples:**

```cel
[1, 2, 3].filter(x, x > 1)                           // [2, 3]
['cat', 'dog', 'bird', 'fish'].filter(pet, pet.size() == 3) // ['cat', 'dog']
{'a': 1, 'b': 2, 'c': 3}.filter(key, key != 'b')     // ['a', 'c']
```

### cel.bind

Binds an identifier to an initialization expression for use in a subsequent result expression. Useful for avoiding repeated computation of complex sub-expressions.

**Signature:** `cel.bind(varName, initExpr, resultExpr)`

**Examples:**

```cel
cel.bind(x, self.field1 + self.field2, x * x)        // computes sum once, then squares it
cel.bind(name, user.firstName + ' ' + user.lastName, name.size() > 0 && name != 'Anonymous')
```

### optMap

Applies a transformation to the value inside an optional if it has a value, otherwise returns `optional.none()`.

**Signature:** `optional(V).optMap(x, transform)` -> `optional(T)`

**Examples:**

```cel
optional.of(5).optMap(x, x * 2)       // optional.of(10)
optional.none().optMap(x, x * 2)     // optional.none()
```

### optFlatMap

Like `optMap`, but the transformation must return an optional. Useful for chaining optional operations without nested optionals.

**Signature:** `optional(V).optFlatMap(x, transform)` -> `optional(T)`

**Examples:**

```cel
optional.of(5).optFlatMap(x, optional.of(x * 2))    // optional.of(10)
optional.of(5).optFlatMap(x, optional.none())      // optional.none()
```

### math.least

Returns the minimum value from a variable number of arguments. All arguments must be numeric (int, uint, or double).

**Signature:** `math.least(arg1, arg2, ...)` -> `double|int|uint`

**Examples:**

```cel
math.least(1, 2, 3)          // 1
math.least(3.14, 2.71, 1.0)  // 1.0
math.least(5u, 3u, 8u)       // 3u
```

### math.greatest

Returns the maximum value from a variable number of arguments. All arguments must be numeric (int, uint, or double).

**Signature:** `math.greatest(arg1, arg2, ...)` -> `double|int|uint`

**Examples:**

```cel
math.greatest(1, 2, 3)          // 3
math.greatest(3.14, 2.71, 1.0)  // 3.14
math.greatest(5u, 3u, 8u)       // 8u
```

### sortBy

Sorts a list by a key expression. Each element is transformed by the key expression, and the list is sorted by those keys.

**Signature:** `list(T).sortBy(x, keyExpr)` -> `list(T)`

**Examples:**

```cel
[{'name': 'bob', 'age': 30}, {'name': 'alice', 'age': 25}].sortBy(p, p.age)
// [{'name': 'alice', 'age': 25}, {'name': 'bob', 'age': 30}]

['banana', 'apple', 'cherry'].sortBy(s, s.size())
// ['apple', 'banana', 'cherry'] (sorted by string length)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.adiom.io/enterprise/running-dsynct/cel-reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
