Skip to content

Commit 3aa41f1

Browse files
author
John Chadwick
committed
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: bufbuild/protovalidate#352
1 parent b34f08d commit 3aa41f1

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

buf/validate/internal/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ cc_library(
139139
"@com_google_absl//absl/status",
140140
"@com_google_cel_cpp//eval/public:cel_function_adapter",
141141
"@com_google_cel_cpp//eval/public:cel_function_registry",
142+
"@com_google_cel_cpp//eval/public/containers:field_access",
142143
"@com_google_cel_cpp//eval/public/containers:container_backed_map_impl",
143144
"@com_googlesource_code_re2//:re2",
144145
],

buf/validate/internal/extra_func.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "eval/public/cel_function_adapter.h"
2727
#include "eval/public/cel_value.h"
2828
#include "eval/public/containers/container_backed_map_impl.h"
29+
#include "eval/public/containers/field_access.h"
2930
#include "google/protobuf/arena.h"
3031
#include "re2/re2.h"
3132

@@ -52,6 +53,32 @@ bool isPathValid(const std::string_view path) {
5253

5354
namespace cel = google::api::expr::runtime;
5455

56+
cel::CelValue getField(
57+
google::protobuf::Arena* arena, cel::CelValue msgval, cel::CelValue nameval) {
58+
if (!msgval.IsMessage()) {
59+
auto* error = google::protobuf::Arena::Create<cel::CelError>(
60+
arena, absl::StatusCode::kInvalidArgument, "expected a message value for first argument");
61+
return cel::CelValue::CreateError(error);
62+
}
63+
if (!nameval.IsString()) {
64+
auto* error = google::protobuf::Arena::Create<cel::CelError>(
65+
arena, absl::StatusCode::kInvalidArgument, "expected a string value for second argument");
66+
return cel::CelValue::CreateError(error);
67+
}
68+
const auto* message = msgval.MessageOrDie();
69+
auto name = nameval.StringOrDie();
70+
const auto* field = message->GetDescriptor()->FindFieldByName(name.value());
71+
if (field == nullptr) {
72+
auto* error = google::protobuf::Arena::Create<cel::CelError>(
73+
arena, absl::StatusCode::kInvalidArgument, "no such field");
74+
return cel::CelValue::CreateError(error);
75+
}
76+
if (cel::CelValue result; cel::CreateValueFromSingleField(message, field, arena, &result).ok()) {
77+
return result;
78+
}
79+
return cel::CelValue::CreateNull();
80+
}
81+
5582
cel::CelValue isNan(google::protobuf::Arena* arena, cel::CelValue rhs) {
5683
if (!rhs.IsDouble()) {
5784
auto* error = google::protobuf::Arena::Create<cel::CelError>(
@@ -352,6 +379,12 @@ absl::Status RegisterExtraFuncs(
352379
if (!status.ok()) {
353380
return status;
354381
}
382+
auto getFieldStatus =
383+
cel::FunctionAdapter<cel::CelValue, cel::CelValue, cel::CelValue>::CreateAndRegister(
384+
"getField", false, &getField, &registry);
385+
if (!getFieldStatus.ok()) {
386+
return getFieldStatus;
387+
}
355388
auto isNanStatus = cel::FunctionAdapter<cel::CelValue, cel::CelValue>::CreateAndRegister(
356389
"isNan", true, &isNan, &registry);
357390
if (!isNanStatus.ok()) {

0 commit comments

Comments
 (0)