Skip to content

optionalTypes

optionalTypes(options?): OptionalTypesLibrary

optionalTypes enables support for optional syntax and types in CEL.

The optional value type makes it possible to express whether variables have been provided, whether a result has been computed, and in the future whether an object field path, map key value, or list index has a value.

Optional types are unlike other CEL extensions because they modify the CEL syntax itself, notably through the use of a ? preceding a field name or index value.

The optional syntax in field selection is denoted as obj.?field. In other words, if a field is set, return optional.of(obj.field), else optional.none(). The optional field selection is viral in the sense that after the first optional selection all subsequent selections or indices are treated as optional, so the following expressions are equivalent:

obj.?field.subfield
obj.?field.?subfield

Similar to field selection, the optional syntax can be used in index expressions on maps and lists:

list[?0]
map[?key]

When creating map or message literals, if a field may be optionally set based on its presence, then placing a ? before the field name or key ensures the type on the right-hand side is optional(T), where T is the type of the field or key-value.

The following returns a map with the key expression set only if the subfield is present, otherwise an empty map is created:

{?key: obj.?field.subfield}

When creating list literals, an element may be optionally added when the element expression is preceded by a ?:

[a, ?b, ?c]

The result contains [a], [a, b], [a, b, c], or [a, c] depending on which optional values are present.

Create an optional(T) value of a given value with type T.

optional.of(10)

Create an optional(T) value of a given value with type T if it is not a zero-value. A zero-value is the default empty value for any given CEL type, including empty protobuf message types. If the value is empty, the result of this call is optional.none().

optional.ofNonZeroValue([1, 2, 3])
optional.ofNonZeroValue([])
optional.ofNonZeroValue(0)
optional.ofNonZeroValue("")

Create an empty optional value.

Determine whether the optional contains a value.

optional.of(b'hello').hasValue()
optional.ofNonZeroValue({}).hasValue()

Get the value contained by the optional. If the optional does not have a value, the result is a CEL error.

optional.of(b'hello').value()
optional.ofNonZeroValue({}).value()

If the value on the left-hand side is optional.none(), the optional value on the right-hand side is returned. If the value on the left-hand side is valued, then it is returned. This operation is short-circuiting and only evaluates as many links in the or chain as needed to return a non-empty optional value.

obj.?field.or(m[?key])
l[?index].or(obj.?field.subfield).or(obj.?other)

Either return the value contained within the optional on the left-hand side or return the alternative value on the right-hand side.

m[?key].orValue("none")

Apply a transformation to the optional’s underlying value if it is not empty and return an optional typed result based on the transformation. The transformation expression type must return a type T which is wrapped into an optional.

msg.?elements.optMap(e, e.size()).orValue(0)

Introduced in version 1.

Apply a transformation to the optional’s underlying value if it is not empty and return the result. The transform expression must return an optional(T) rather than type T. This can be useful when dealing with zero values and conditionally generating an empty or non-empty result in ways which cannot be expressed with optMap.

msg.?elements.optFlatMap(e, e[?0])

Introduced in version 2. Returns an optional with the first value from the right-hand list, or optional.none().

[1, 2, 3].first().value() == 1

Introduced in version 2. Returns an optional with the last value from the right-hand list, or optional.none().

[1, 2, 3].last().value() == 3

This is syntactic sugar for msg.elements[msg.elements.size()-1].

Introduced in version 2. Returns a list of all values that are not empty in the input list of optional values. It can be used as optional.unwrap(List[T]) or with postfix notation as List[T].unwrapOpt().

optional.unwrap([optional.of(42), optional.none()]) == [42]
[optional.of(42), optional.none()].unwrapOpt() == [42]

OptionalTypesOptions = {}

OptionalTypesLibrary