Skip to content

Commit

Permalink
Add an adapter for legacy runtime to consume CelValueProvider. Add in…
Browse files Browse the repository at this point in the history
…terpreter test for CelValues.

PiperOrigin-RevId: 563598718
  • Loading branch information
l46kok authored and copybara-github committed Dec 2, 2023
1 parent aa6875c commit 39a99ef
Show file tree
Hide file tree
Showing 44 changed files with 1,411 additions and 180 deletions.
38 changes: 38 additions & 0 deletions bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,24 @@ public void program_withVars() throws Exception {
assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
}

@Test
public void program_withCelValue() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(CelOptions.current().enableCelValue(true).build())
.addDeclarations(
Decl.newBuilder()
.setName("variable")
.setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING))
.build())
.setResultType(SimpleType.BOOL)
.build();

CelRuntime.Program program = cel.createProgram(cel.compile("variable == 'hello'").getAst());

assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
}

@Test
public void program_withProtoVars() throws Exception {
Cel cel =
Expand Down Expand Up @@ -1285,6 +1303,26 @@ public void programAdvanceEvaluation_nestedSelect() throws Exception {
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
}

@Test
public void programAdvanceEvaluation_nestedSelect_withCelValue() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(
CelOptions.current().enableUnknownTracking(true).enableCelValue(true).build())
.addVar("com", MapType.create(SimpleType.STRING, SimpleType.DYN))
.addFunctionBindings()
.setResultType(SimpleType.BOOL)
.build();
CelRuntime.Program program = cel.createProgram(cel.compile("com.google.a || false").getAst());

assertThat(
program.advanceEvaluation(
UnknownContext.create(
fromMap(ImmutableMap.of()),
ImmutableList.of(CelAttributePattern.fromQualifiedIdentifier("com.google.a")))))
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
}

@Test
public void programAdvanceEvaluation_argumentMergeErrorPriority() throws Exception {
Cel cel =
Expand Down
12 changes: 12 additions & 0 deletions common/src/main/java/dev/cel/common/CelOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public abstract class CelOptions {

public abstract boolean enableUnknownTracking();

public abstract boolean enableCelValue();

public abstract int comprehensionMaxIterations();

public abstract Builder toBuilder();
Expand Down Expand Up @@ -176,6 +178,7 @@ public static Builder newBuilder() {
.errorOnDuplicateMapKeys(false)
.resolveTypeDependencies(true)
.enableUnknownTracking(false)
.enableCelValue(false)
.comprehensionMaxIterations(-1);
}

Expand Down Expand Up @@ -428,6 +431,15 @@ public abstract static class Builder {
*/
public abstract Builder enableUnknownTracking(boolean value);

/**
* Enables the usage of {@code CelValue} for the runtime. It is a native value representation of
* CEL that wraps Java native objects, and comes with extended capabilities, such as allowing
* value constructs not understood by CEL (ex: POJOs).
*
* <p>Warning: This option is experimental.
*/
public abstract Builder enableCelValue(boolean value);

/**
* Limit the total number of iterations permitted within comprehension loops.
*
Expand Down
1 change: 1 addition & 0 deletions common/src/main/java/dev/cel/common/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ java_library(
],
deps = [
"//common/annotations",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ public static DynamicProto create(ProtoMessageFactory protoMessageFactory) {
this.protoMessageFactory = checkNotNull(protoMessageFactory);
}

/**
* Gets the underlying message factory used to construct new protobuf messages upon unpacking an
* Any message.
*/
public ProtoMessageFactory getProtoMessageFactory() {
return protoMessageFactory;
}

/** Attempts to unpack an Any message. */
public Optional<Message> maybeUnpackAny(Message msg) {
try {
Expand Down
17 changes: 6 additions & 11 deletions common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static java.util.Arrays.stream;

import dev.cel.expr.ExprValue;
import com.google.common.collect.ImmutableList;
Expand All @@ -25,7 +24,7 @@
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.CheckReturnValue;
import javax.annotation.concurrent.ThreadSafe;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.Any;
import com.google.protobuf.BoolValue;
import com.google.protobuf.ByteString;
Expand Down Expand Up @@ -60,7 +59,6 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import org.jspecify.nullness.Nullable;

/**
Expand All @@ -73,7 +71,7 @@
*
* <p>CEL Library Internals. Do Not Use.
*/
@ThreadSafe
@Immutable
@CheckReturnValue
@Internal
public final class ProtoAdapter {
Expand Down Expand Up @@ -139,10 +137,6 @@ public final class ProtoAdapter {
public static final BidiConverter<Number, Number> DOUBLE_CONVERTER =
BidiConverter.of(Number::doubleValue, Number::floatValue);

private static final ImmutableMap<String, WellKnownProto> WELL_KNOWN_PROTOS =
stream(WellKnownProto.values())
.collect(toImmutableMap(WellKnownProto::typeName, Function.identity()));

private final DynamicProto dynamicProto;
private final boolean enableUnsignedLongs;

Expand All @@ -163,7 +157,8 @@ public Object adaptProtoToValue(MessageOrBuilder proto) {
}
// If the proto is not a well-known type, then the input Message is what's expected as the
// output return value.
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(typeName(proto.getDescriptorForType()));
WellKnownProto wellKnownProto =
WellKnownProto.getByDescriptorName(typeName(proto.getDescriptorForType()));
if (wellKnownProto == null) {
return proto;
}
Expand Down Expand Up @@ -328,7 +323,7 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) {
* considered, such as a packing an {@code google.protobuf.StringValue} into a {@code Any} value.
*/
public Optional<Message> adaptValueToProto(Object value, String protoTypeName) {
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(protoTypeName);
WellKnownProto wellKnownProto = WellKnownProto.getByDescriptorName(protoTypeName);
if (wellKnownProto == null) {
if (value instanceof Message) {
return Optional.of((Message) value);
Expand Down Expand Up @@ -644,7 +639,7 @@ private static boolean isWrapperType(FieldDescriptor fieldDescriptor) {
return false;
}
String fieldTypeName = fieldDescriptor.getMessageType().getFullName();
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(fieldTypeName);
WellKnownProto wellKnownProto = WellKnownProto.getByDescriptorName(fieldTypeName);
return wellKnownProto != null && wellKnownProto.isWrapperType();
}

Expand Down
19 changes: 18 additions & 1 deletion common/src/main/java/dev/cel/common/internal/WellKnownProto.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

package dev.cel.common.internal;

import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static java.util.Arrays.stream;

import com.google.common.collect.ImmutableMap;
import com.google.protobuf.Any;
import com.google.protobuf.BoolValue;
import com.google.protobuf.BytesValue;
Expand All @@ -31,6 +35,7 @@
import com.google.protobuf.UInt64Value;
import com.google.protobuf.Value;
import dev.cel.common.annotations.Internal;
import java.util.function.Function;

/**
* WellKnownProto types used throughout CEL. These types are specially handled to ensure that
Expand Down Expand Up @@ -58,6 +63,14 @@ public enum WellKnownProto {
private final Descriptor descriptor;
private final boolean isWrapperType;

private static final ImmutableMap<String, WellKnownProto> WELL_KNOWN_PROTO_MAP;

static {
WELL_KNOWN_PROTO_MAP =
stream(WellKnownProto.values())
.collect(toImmutableMap(WellKnownProto::typeName, Function.identity()));
}

WellKnownProto(Descriptor descriptor) {
this(descriptor, /* isWrapperType= */ false);
}
Expand All @@ -75,7 +88,11 @@ public String typeName() {
return descriptor.getFullName();
}

boolean isWrapperType() {
public boolean isWrapperType() {
return isWrapperType;
}

public static WellKnownProto getByDescriptorName(String name) {
return WELL_KNOWN_PROTO_MAP.get(name);
}
}
12 changes: 10 additions & 2 deletions common/src/main/java/dev/cel/common/types/TypeType.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
@Immutable
public abstract class TypeType extends CelType {

static final TypeType TYPE = create(SimpleType.DYN);

@Override
public CelKind kind() {
return CelKind.TYPE;
Expand All @@ -38,6 +36,16 @@ public String name() {
return "type";
}

/** Retrieves the underlying type name of the type-kind held. */
public String containingTypeName() {
CelType containingType = type();
if (containingType.kind() == CelKind.DYN) {
return "type";
}

return containingType.name();
}

@Override
public abstract ImmutableList<CelType> parameters();

Expand Down
37 changes: 37 additions & 0 deletions common/src/main/java/dev/cel/common/values/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CEL_VALUES_SOURCES = [
"NullValue.java",
"OpaqueValue.java",
"OptionalValue.java",
"SelectableValue.java",
"StringValue.java",
"StructValue.java",
"TimestampValue.java",
Expand All @@ -49,6 +50,20 @@ java_library(
],
)

java_library(
name = "cel_value_provider",
srcs = [
"CelValueProvider.java",
],
tags = [
],
deps = [
":cel_value",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)

java_library(
name = "values",
srcs = CEL_VALUES_SOURCES,
Expand All @@ -58,7 +73,9 @@ java_library(
":cel_byte_string",
":cel_value",
"//:auto_value",
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
"//common/annotations",
"//common/types",
"//common/types:type_providers",
Expand Down Expand Up @@ -104,3 +121,23 @@ java_library(
"@maven//:org_jspecify_jspecify",
],
)

java_library(
name = "proto_message_value_provider",
srcs = ["ProtoMessageValueProvider.java"],
tags = [
],
deps = [
":cel_value",
":cel_value_provider",
":proto_message_value",
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
"//common/annotations",
"//common/internal:dynamic_proto",
"//common/internal:proto_message_factory",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_protobuf_protobuf_java",
],
)
Loading

0 comments on commit 39a99ef

Please sign in to comment.