Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import dev.cel.common.values.CelByteString;
import dev.cel.common.values.NullValue;
import dev.cel.compiler.CelCompiler;
import dev.cel.expr.conformance.proto3.NestedTestAllTypes;
import dev.cel.expr.conformance.proto3.TestAllTypes;
import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage;
import dev.cel.parser.CelMacro;
Expand Down Expand Up @@ -603,6 +604,16 @@ public void optionalFieldSelection_onMap_returnsOptionalValue() throws Exception
assertThat(result).hasValue(2L);
}

@Test
public void optionalFieldSelection_onMap_chained_returnsSinglyWrappedOptional() throws Exception {
Cel cel = newCelBuilder().setResultType(OptionalType.create(SimpleType.STRING)).build();
CelAbstractSyntaxTree ast = compile(cel, "{'foo': {'bar': 'baz'}}.?foo.?bar");

Optional<String> result = (Optional<String>) cel.createProgram(ast).eval();

assertThat(result).hasValue("baz");
}

@Test
public void optionalFieldSelection_onProtoMessage_returnsOptionalEmpty() throws Exception {
Cel cel =
Expand All @@ -619,6 +630,30 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalEmpty() throws
assertThat(result).isEmpty();
}

@Test
public void optionalFieldSelection_onProtoMessage_chained_returnsSinglyWrappedOptional()
throws Exception {
Cel cel =
newCelBuilder()
.setResultType(OptionalType.create(SimpleType.INT))
.addVar(
"msg", StructTypeReference.create(NestedTestAllTypes.getDescriptor().getFullName()))
.build();
CelAbstractSyntaxTree ast = compile(cel, "msg.?payload.?single_int32");

Optional<Long> result =
(Optional<Long>)
cel.createProgram(ast)
.eval(
ImmutableMap.of(
"msg",
NestedTestAllTypes.newBuilder()
.setPayload(TestAllTypes.newBuilder().setSingleInt32(5).build())
.build()));

assertThat(result).hasValue(5L);
}

@Test
public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws Exception {
Cel cel =
Expand Down
8 changes: 6 additions & 2 deletions runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,12 @@ private Optional<IntermediateResult> maybeEvalOptionalSelectField(
}

IntermediateResult result = evalFieldSelect(frame, expr, operand, field, false);
return Optional.of(
IntermediateResult.create(result.attribute(), Optional.of(result.value())));
// Ensure only one level of optional is wrapped when chaining optional field selections.
Object resultValue = result.value();
if (!(resultValue instanceof Optional)) {
resultValue = Optional.of(resultValue);
}
return Optional.of(IntermediateResult.create(result.attribute(), resultValue));
}

private IntermediateResult evalBoolean(ExecutionFrame frame, CelExpr expr, boolean strict)
Expand Down
Loading