From 90322d708be81f2bf52f412910343e62ea247999 Mon Sep 17 00:00:00 2001 From: John Chadwick Date: Tue, 22 Apr 2025 02:55:12 -0400 Subject: [PATCH] Implement getField CEL function I'm proposing this as an eventual replacement (before 1.0) of our hack around the fact that the `in` identifier is reserved in CEL. We need this for protovalidate-cc especially so we can start removing our cel-cpp patches. Protovalidate PR: https://github.com/bufbuild/protovalidate/pull/352 --- .../buf/protovalidate/CustomDeclarations.java | 7 +++++ .../buf/protovalidate/CustomOverload.java | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/main/java/build/buf/protovalidate/CustomDeclarations.java b/src/main/java/build/buf/protovalidate/CustomDeclarations.java index 5c7310fc..095478bd 100644 --- a/src/main/java/build/buf/protovalidate/CustomDeclarations.java +++ b/src/main/java/build/buf/protovalidate/CustomDeclarations.java @@ -38,6 +38,13 @@ static List create() { // Add 'now' variable declaration decls.add(Decls.newVar("now", Decls.newObjectType(TimestampT.TimestampType.typeName()))); + // Add 'getField' function declaration + decls.add( + Decls.newFunction( + "getField", + Decls.newOverload( + "get_field_any_string", Arrays.asList(Decls.Any, Decls.String), Decls.Any))); + // Add 'isIp' function declaration decls.add( Decls.newFunction( diff --git a/src/main/java/build/buf/protovalidate/CustomOverload.java b/src/main/java/build/buf/protovalidate/CustomOverload.java index cd60e93f..f8cdea5e 100644 --- a/src/main/java/build/buf/protovalidate/CustomOverload.java +++ b/src/main/java/build/buf/protovalidate/CustomOverload.java @@ -18,6 +18,8 @@ import com.google.common.base.Splitter; import com.google.common.net.InetAddresses; import com.google.common.primitives.Bytes; +import com.google.protobuf.Descriptors; +import com.google.protobuf.Message; import inet.ipaddr.IPAddress; import inet.ipaddr.IPAddressString; import jakarta.mail.internet.AddressException; @@ -35,6 +37,7 @@ import org.projectnessie.cel.common.types.ListT; import org.projectnessie.cel.common.types.StringT; import org.projectnessie.cel.common.types.Types; +import org.projectnessie.cel.common.types.pb.DefaultTypeAdapter; import org.projectnessie.cel.common.types.ref.TypeEnum; import org.projectnessie.cel.common.types.ref.Val; import org.projectnessie.cel.common.types.traits.Lister; @@ -43,6 +46,7 @@ /** Defines custom function overloads (the implementation). */ final class CustomOverload { + private static final String OVERLOAD_GET_FIELD = "getField"; private static final String OVERLOAD_FORMAT = "format"; private static final String OVERLOAD_UNIQUE = "unique"; private static final String OVERLOAD_STARTS_WITH = "startsWith"; @@ -65,6 +69,7 @@ final class CustomOverload { */ static Overload[] create() { return new Overload[] { + getField(), format(), unique(), startsWith(), @@ -82,6 +87,30 @@ static Overload[] create() { }; } + /** + * Creates a custom function overload for the "getField" operation. + * + * @return The {@link Overload} instance for the "getField" operation. + */ + private static Overload getField() { + return Overload.binary( + OVERLOAD_GET_FIELD, + (msgarg, namearg) -> { + if (msgarg.type().typeEnum() != TypeEnum.Object + || namearg.type().typeEnum() != TypeEnum.String) { + return Err.newErr("no such overload"); + } + Message message = msgarg.convertToNative(Message.class); + String fieldName = namearg.convertToNative(String.class); + Descriptors.FieldDescriptor field = + message.getDescriptorForType().findFieldByName(fieldName); + if (field == null) { + return Err.newErr("no such field: " + fieldName); + } + return DefaultTypeAdapter.Instance.nativeToValue(message.getField(field)); + }); + } + /** * Creates a custom binary function overload for the "format" operation. *