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.
Syntax Changes
Section titled “Syntax Changes”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.
Field Selection
Section titled “Field Selection”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.subfieldobj.?field.?subfieldIndexing
Section titled “Indexing”Similar to field selection, the optional syntax can be used in index expressions on maps and lists:
list[?0]map[?key]Optional Field Setting
Section titled “Optional Field Setting”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}Optional Element Setting
Section titled “Optional Element Setting”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.
Optional.Of
Section titled “Optional.Of”Create an optional(T) value of a given value with type T.
optional.of(10)Optional.OfNonZeroValue
Section titled “Optional.OfNonZeroValue”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("")Optional.None
Section titled “Optional.None”Create an empty optional value.
HasValue
Section titled “HasValue”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)OrValue
Section titled “OrValue”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")OptMap
Section titled “OptMap”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)OptFlatMap
Section titled “OptFlatMap”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() == 1Introduced in version 2. Returns an optional with the last value from the
right-hand list, or optional.none().
[1, 2, 3].last().value() == 3This is syntactic sugar for msg.elements[msg.elements.size()-1].
Unwrap / UnwrapOpt
Section titled “Unwrap / UnwrapOpt”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]Parameters
Section titled “Parameters”options?
Section titled “options?”OptionalTypesOptions = {}