Coverage Report

Created: 2026-09-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/eval/eval/select_step.cc
Line
Count
Source
1
#include "eval/eval/select_step.h"
2
3
#include <cstdint>
4
#include <memory>
5
#include <optional>
6
#include <string>
7
#include <utility>
8
9
#include "absl/base/nullability.h"
10
#include "absl/log/absl_check.h"
11
#include "absl/log/absl_log.h"
12
#include "absl/status/status.h"
13
#include "absl/status/statusor.h"
14
#include "absl/strings/string_view.h"
15
#include "absl/types/optional.h"
16
#include "common/legacy_value.h"
17
#include "common/memory.h"
18
#include "common/type.h"
19
#include "common/value.h"
20
#include "common/value_kind.h"
21
#include "eval/eval/attribute_trail.h"
22
#include "eval/eval/direct_expression_step.h"
23
#include "eval/eval/evaluator_core.h"
24
#include "eval/eval/expression_step_base.h"
25
#include "eval/public/cel_value.h"
26
#include "eval/public/structs/proto_message_type_adapter.h"
27
#include "internal/status_macros.h"
28
#include "runtime/runtime_options.h"
29
#include "google/protobuf/arena.h"
30
#include "google/protobuf/descriptor.h"
31
#include "google/protobuf/message.h"
32
33
namespace google::api::expr::runtime {
34
35
namespace {
36
37
using ::cel::BoolValue;
38
using ::cel::ErrorValue;
39
using ::cel::MapValue;
40
using ::cel::OptionalValue;
41
using ::cel::ProtoWrapperTypeOptions;
42
using ::cel::StringValue;
43
using ::cel::StructValue;
44
using ::cel::Value;
45
using ::cel::ValueKind;
46
47
// Common error for cases where evaluation attempts to perform select operations
48
// on an unsupported type.
49
//
50
// This should not happen under normal usage of the evaluator, but useful for
51
// troubleshooting broken invariants.
52
97.3k
absl::Status InvalidSelectTargetError() {
53
97.3k
  return absl::Status(absl::StatusCode::kInvalidArgument,
54
97.3k
                      "Applying SELECT to non-message type");
55
97.3k
}
56
57
absl::optional<Value> CheckForMarkedAttributes(const AttributeTrail& trail,
58
201k
                                               ExecutionFrameBase& frame) {
59
201k
  if (frame.unknown_processing_enabled() &&
60
0
      frame.attribute_utility().CheckForUnknownExact(trail)) {
61
0
    return frame.attribute_utility().CreateUnknownSet(trail.attribute());
62
0
  }
63
64
201k
  if (frame.missing_attribute_errors_enabled() &&
65
0
      frame.attribute_utility().CheckForMissingAttribute(trail)) {
66
0
    auto result = frame.attribute_utility().CreateMissingAttributeError(
67
0
        trail.attribute());
68
69
0
    if (result.ok()) {
70
0
      return std::move(result).value();
71
0
    }
72
    // Invariant broken (an invalid CEL Attribute shouldn't match anything).
73
    // Log and return a CelError.
74
0
    ABSL_LOG(ERROR) << "Invalid attribute pattern matched select path: "
75
0
                    << result.status().ToString();  // NOLINT: OSS compatibility
76
0
    return cel::ErrorValue(std::move(result).status());
77
0
  }
78
79
201k
  return std::nullopt;
80
201k
}
81
82
// Helper for StructValue::GetFieldByName. Used for opting out of old reflection
83
// implementation.
84
absl::Status WrappedStructGet(
85
    const Value& target, absl::string_view field,
86
    ProtoWrapperTypeOptions unboxing_option,
87
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
88
    google::protobuf::MessageFactory* absl_nonnull message_factory,
89
    google::protobuf::Arena* absl_nonnull arena,
90
    bool enable_use_new_field_select_implementation,
91
195k
    Value* absl_nonnull result) {
92
195k
  if (!enable_use_new_field_select_implementation) {
93
0
    if (const google::protobuf::Message* message =
94
0
            cel::interop_internal::GetLegacyMessage(target);
95
0
        message != nullptr) {
96
0
      CelValue::MessageWrapper message_wrapper(
97
0
          message, &GetGenericProtoTypeInfoInstance());
98
0
      CEL_ASSIGN_OR_RETURN(
99
0
          CelValue cel_value,
100
0
          internal::GetGenericProtoAccessApisInstance().GetField(
101
0
              field, message_wrapper, unboxing_option,
102
0
              cel::MemoryManagerRef::Pooling(arena)));
103
0
      return cel::ModernValue(arena, cel_value, *result);
104
0
    }
105
0
  }
106
195k
  return target.GetStruct().GetFieldByName(
107
195k
      field, unboxing_option, descriptor_pool, message_factory, arena, result);
108
195k
}
109
110
absl::Status PerformHas(const Value& target, absl::string_view field,
111
                        const StringValue& field_value,
112
                        const google::protobuf::DescriptorPool* descriptor_pool,
113
                        google::protobuf::MessageFactory* message_factory,
114
0
                        google::protobuf::Arena* arena, Value& result) {
115
0
  switch (target.kind()) {
116
0
    case ValueKind::kMap: {
117
0
      CEL_RETURN_IF_ERROR(target.GetMap().Has(field_value, descriptor_pool,
118
0
                                              message_factory, arena, &result));
119
0
      return absl::OkStatus();
120
0
    }
121
0
    case ValueKind::kStruct: {
122
0
      auto has_field = target.GetStruct().HasFieldByName(field);
123
0
      if (!has_field.ok()) {
124
0
        result = ErrorValue(std::move(has_field).status());
125
0
      } else {
126
0
        result = BoolValue{*has_field};
127
0
      }
128
0
      return absl::OkStatus();
129
0
    }
130
0
    default:
131
0
      return InvalidSelectTargetError();
132
0
  }
133
0
}
134
135
absl::Status PerformGet(const Value& target, absl::string_view field,
136
                        const StringValue& field_value,
137
                        ProtoWrapperTypeOptions unboxing_option,
138
                        const google::protobuf::DescriptorPool* descriptor_pool,
139
                        google::protobuf::MessageFactory* message_factory,
140
                        google::protobuf::Arena* arena,
141
                        bool enable_use_new_field_select_implementation,
142
201k
                        Value& result) {
143
201k
  switch (target.kind()) {
144
5.72k
    case ValueKind::kMap: {
145
5.72k
      auto status = target.GetMap().Get(field_value, descriptor_pool,
146
5.72k
                                        message_factory, arena, &result);
147
5.72k
      if (!status.ok()) {
148
0
        result = ErrorValue(std::move(status));
149
0
      }
150
5.72k
      return absl::OkStatus();
151
0
    }
152
195k
    case ValueKind::kStruct: {
153
195k
      auto status = WrappedStructGet(
154
195k
          target, field, unboxing_option, descriptor_pool, message_factory,
155
195k
          arena, enable_use_new_field_select_implementation, &result);
156
195k
      if (!status.ok()) {
157
0
        result = ErrorValue(std::move(status));
158
0
      }
159
195k
      return absl::OkStatus();
160
0
    }
161
0
    default:
162
0
      return InvalidSelectTargetError();
163
201k
  }
164
201k
}
165
166
absl::Status PerformOptionalGet(const Value& target, absl::string_view field,
167
                                const StringValue& field_value,
168
                                ProtoWrapperTypeOptions unboxing_option,
169
                                const google::protobuf::DescriptorPool* descriptor_pool,
170
                                google::protobuf::MessageFactory* message_factory,
171
                                google::protobuf::Arena* arena,
172
                                bool enable_use_new_field_select_implementation,
173
0
                                Value& result) {
174
0
  switch (target.kind()) {
175
0
    case ValueKind::kMap: {
176
0
      CEL_ASSIGN_OR_RETURN(
177
0
          bool found, target.GetMap().Find(field_value, descriptor_pool,
178
0
                                           message_factory, arena, &result));
179
0
      if (!found) {
180
0
        result = OptionalValue::None();
181
0
        return absl::OkStatus();
182
0
      }
183
0
      ABSL_DCHECK(!result.IsUnknown());
184
0
      result = OptionalValue::Of(std::move(result), arena);
185
0
      return absl::OkStatus();
186
0
    }
187
0
    case ValueKind::kStruct: {
188
0
      CEL_ASSIGN_OR_RETURN(bool found,
189
0
                           target.GetStruct().HasFieldByName(field));
190
0
      if (!found) {
191
0
        result = OptionalValue::None();
192
0
        return absl::OkStatus();
193
0
      }
194
0
      CEL_RETURN_IF_ERROR(WrappedStructGet(
195
0
          target, field, unboxing_option, descriptor_pool, message_factory,
196
0
          arena, enable_use_new_field_select_implementation, &result));
197
198
0
      ABSL_DCHECK(!result.IsUnknown());
199
0
      result = OptionalValue::Of(std::move(result), arena);
200
0
      return absl::OkStatus();
201
0
    }
202
0
    default:
203
0
      return InvalidSelectTargetError();
204
0
  }
205
0
}
206
207
// SelectStep performs message field access specified by Expr::Select
208
// message.
209
class SelectStep : public ExpressionStepBase {
210
 public:
211
  SelectStep(StringValue value, bool test_field_presence, int64_t expr_id,
212
             bool enable_wrapper_type_null_unboxing, bool enable_optional_types)
213
17.7k
      : ExpressionStepBase(expr_id),
214
17.7k
        field_value_(std::move(value)),
215
17.7k
        field_(field_value_.ToString()),
216
17.7k
        test_field_presence_(test_field_presence),
217
17.7k
        unboxing_option_(enable_wrapper_type_null_unboxing
218
17.7k
                             ? ProtoWrapperTypeOptions::kUnsetNull
219
17.7k
                             : ProtoWrapperTypeOptions::kUnsetProtoDefault),
220
17.7k
        enable_optional_types_(enable_optional_types) {}
221
222
  absl::Status Evaluate(ExecutionFrame* frame) const override;
223
224
 protected:
225
  cel::StringValue field_value_;
226
  std::string field_;
227
  bool test_field_presence_;
228
  ProtoWrapperTypeOptions unboxing_option_;
229
  bool enable_optional_types_;
230
};
231
232
1.12M
absl::Status SelectStep::Evaluate(ExecutionFrame* frame) const {
233
1.12M
  if (!frame->value_stack().HasEnough(1)) {
234
0
    return absl::Status(absl::StatusCode::kInternal,
235
0
                        "No arguments supplied for Select-type expression");
236
0
  }
237
238
1.12M
  const Value& arg = frame->value_stack().Peek();
239
1.12M
  const AttributeTrail& trail = frame->value_stack().PeekAttribute();
240
241
1.12M
  if (arg.IsUnknown() || arg.IsError()) {
242
    // Bubble up unknowns and errors.
243
823k
    return absl::OkStatus();
244
823k
  }
245
246
298k
  AttributeTrail result_trail;
247
248
  // Handle unknown resolution.
249
298k
  if (frame->attribute_tracking_enabled()) {
250
0
    result_trail = trail.Step(&field_);
251
0
  }
252
253
298k
  absl::optional<OptionalValue> optional_arg;
254
255
298k
  if (enable_optional_types_ && arg.IsOptional()) {
256
0
    optional_arg = arg.GetOptional();
257
0
  }
258
259
298k
  if (!(optional_arg || arg.IsMap() || arg.IsStruct())) {
260
97.3k
    frame->value_stack().PopAndPush(cel::ErrorValue(InvalidSelectTargetError()),
261
97.3k
                                    std::move(result_trail));
262
97.3k
    return absl::OkStatus();
263
97.3k
  }
264
265
201k
  absl::optional<Value> marked_attribute_check =
266
201k
      CheckForMarkedAttributes(result_trail, *frame);
267
201k
  if (marked_attribute_check.has_value()) {
268
0
    frame->value_stack().PopAndPush(std::move(marked_attribute_check).value(),
269
0
                                    std::move(result_trail));
270
0
    return absl::OkStatus();
271
0
  }
272
273
201k
  Value result;
274
201k
  if (test_field_presence_) {
275
0
    const Value* target = &arg;
276
0
    if (optional_arg) {
277
0
      if (!optional_arg->HasValue()) {
278
0
        frame->value_stack().PopAndPush(cel::BoolValue{false},
279
0
                                        std::move(result_trail));
280
0
        return absl::OkStatus();
281
0
      }
282
0
      optional_arg->Value(&result);
283
0
      target = &result;
284
0
    }
285
0
    CEL_RETURN_IF_ERROR(
286
0
        PerformHas(*target, field_, field_value_, frame->descriptor_pool(),
287
0
                   frame->message_factory(), frame->arena(), result));
288
0
    frame->value_stack().PopAndPush(std::move(result), std::move(result_trail));
289
0
    return absl::OkStatus();
290
0
  }
291
292
201k
  if (optional_arg) {
293
0
    if (!optional_arg->HasValue()) {
294
0
      frame->value_stack().PopAndPush(OptionalValue::None(),
295
0
                                      std::move(result_trail));
296
0
      return absl::OkStatus();
297
0
    }
298
0
    Value value;
299
0
    optional_arg->Value(&value);
300
0
    auto status = PerformOptionalGet(
301
0
        value, field_, field_value_, unboxing_option_, frame->descriptor_pool(),
302
0
        frame->message_factory(), frame->arena(),
303
0
        frame->options().enable_use_new_field_select_implementation, result);
304
0
    if (!status.ok()) {
305
0
      result = ErrorValue(std::move(status));
306
0
    }
307
0
    frame->value_stack().PopAndPush(std::move(result), std::move(result_trail));
308
0
    return absl::OkStatus();
309
0
  }
310
311
201k
  CEL_RETURN_IF_ERROR(PerformGet(
312
201k
      arg, field_, field_value_, unboxing_option_, frame->descriptor_pool(),
313
201k
      frame->message_factory(), frame->arena(),
314
201k
      frame->options().enable_use_new_field_select_implementation, result));
315
201k
  frame->value_stack().PopAndPush(std::move(result), std::move(result_trail));
316
201k
  return absl::OkStatus();
317
201k
}
318
319
class DirectSelectStep : public DirectExpressionStep {
320
 public:
321
  DirectSelectStep(int64_t expr_id,
322
                   std::unique_ptr<DirectExpressionStep> operand,
323
                   StringValue field, bool test_only,
324
                   bool enable_wrapper_type_null_unboxing,
325
                   bool enable_optional_types)
326
0
      : DirectExpressionStep(expr_id),
327
0
        operand_(std::move(operand)),
328
0
        field_value_(std::move(field)),
329
0
        field_(field_value_.ToString()),
330
0
        test_only_(test_only),
331
0
        unboxing_option_(enable_wrapper_type_null_unboxing
332
0
                             ? ProtoWrapperTypeOptions::kUnsetNull
333
0
                             : ProtoWrapperTypeOptions::kUnsetProtoDefault),
334
0
        enable_optional_types_(enable_optional_types) {}
335
336
  absl::Status Evaluate(ExecutionFrameBase& frame, Value& result,
337
0
                        AttributeTrail& attribute) const override {
338
0
    CEL_RETURN_IF_ERROR(operand_->Evaluate(frame, result, attribute));
339
340
0
    if (result.IsError() || result.IsUnknown()) {
341
      // Just forward.
342
0
      return absl::OkStatus();
343
0
    }
344
345
0
    if (frame.attribute_tracking_enabled()) {
346
0
      attribute = attribute.Step(&field_);
347
0
      absl::optional<Value> value = CheckForMarkedAttributes(attribute, frame);
348
0
      if (value.has_value()) {
349
0
        result = std::move(value).value();
350
0
        return absl::OkStatus();
351
0
      }
352
0
    }
353
354
0
    absl::optional<OptionalValue> optional_arg;
355
356
0
    if (enable_optional_types_ && result.IsOptional()) {
357
0
      optional_arg = result.GetOptional();
358
0
    }
359
360
0
    switch (result.kind()) {
361
0
      case ValueKind::kStruct:
362
0
      case ValueKind::kMap:
363
0
        break;
364
0
      default:
365
0
        if (optional_arg) {
366
0
          break;
367
0
        }
368
0
        result = cel::ErrorValue(InvalidSelectTargetError());
369
0
        return absl::OkStatus();
370
0
    }
371
372
0
    if (test_only_) {
373
0
      if (optional_arg) {
374
0
        if (!optional_arg->HasValue()) {
375
0
          result = cel::BoolValue{false};
376
0
          return absl::OkStatus();
377
0
        }
378
0
        Value value;
379
0
        optional_arg->Value(&value);
380
0
        return PerformHas(value, field_, field_value_, frame.descriptor_pool(),
381
0
                          frame.message_factory(), frame.arena(), result);
382
0
      }
383
0
      return PerformHas(result, field_, field_value_, frame.descriptor_pool(),
384
0
                        frame.message_factory(), frame.arena(), result);
385
0
    }
386
387
0
    if (optional_arg) {
388
0
      if (!optional_arg->HasValue()) {
389
        // result is still buffer for the container. just return.
390
0
        return absl::OkStatus();
391
0
      }
392
0
      Value value;
393
0
      optional_arg->Value(&value);
394
0
      auto status = PerformOptionalGet(
395
0
          value, field_, field_value_, unboxing_option_,
396
0
          frame.descriptor_pool(), frame.message_factory(), frame.arena(),
397
0
          frame.options().enable_use_new_field_select_implementation, result);
398
0
      if (!status.ok()) {
399
0
        result = ErrorValue(std::move(status));
400
0
      }
401
0
      return absl::OkStatus();
402
0
    }
403
404
0
    return PerformGet(
405
0
        result, field_, field_value_, unboxing_option_, frame.descriptor_pool(),
406
0
        frame.message_factory(), frame.arena(),
407
0
        frame.options().enable_use_new_field_select_implementation, result);
408
0
  }
409
410
 private:
411
  std::unique_ptr<DirectExpressionStep> operand_;
412
413
  // Field name in formats supported by each of the map and struct field access
414
  // APIs.
415
  //
416
  // ToString or ValueManager::CreateString may force a copy so we do this at
417
  // plan time.
418
  StringValue field_value_;
419
  std::string field_;
420
421
  // whether this is a has() expression.
422
  bool test_only_;
423
  ProtoWrapperTypeOptions unboxing_option_;
424
  bool enable_optional_types_;
425
};
426
427
class ProtoSelectStep : public SelectStep {
428
 public:
429
  ProtoSelectStep(StringValue value, int64_t expr_id,
430
                  bool enable_wrapper_type_null_unboxing,
431
                  bool enable_optional_types,
432
                  const google::protobuf::Descriptor* descriptor,
433
                  const google::protobuf::FieldDescriptor* field_descriptor)
434
0
      : SelectStep(std::move(value), /*test_field_presence=*/false, expr_id,
435
0
                   enable_wrapper_type_null_unboxing, enable_optional_types),
436
0
        descriptor_(descriptor),
437
0
        field_descriptor_(field_descriptor) {
438
0
    ABSL_DCHECK(descriptor_ != nullptr);
439
0
    ABSL_DCHECK(field_descriptor_ != nullptr);
440
0
  }
441
442
0
  absl::Status Evaluate(ExecutionFrame* frame) const override {
443
0
    if (!frame->value_stack().HasEnough(1)) {
444
0
      return absl::InternalError(
445
0
          "No arguments supplied for Select-type expression");
446
0
    }
447
448
0
    const Value& arg = frame->value_stack().Peek();
449
0
    if (auto unwrapped = arg.AsParsedMessage();
450
0
        unwrapped.has_value() && unwrapped->GetDescriptor() == descriptor_) {
451
0
      return EvaluateModernMessageGetField(frame, *unwrapped);
452
0
    } else if (const google::protobuf::Message* legacy_message =
453
0
                   cel::interop_internal::GetLegacyMessage(arg);
454
0
               legacy_message != nullptr &&
455
0
               legacy_message->GetDescriptor() == descriptor_) {
456
      // A little unfortunate, but need to special case for legacy values so we
457
      // can minimize back and forth interop conversions.
458
0
      return EvaluateLegacyMessageGetField(frame, legacy_message);
459
0
    }
460
    // If we get an unexpected value type, fall back to the generic
461
    // implementation.
462
0
    return SelectStep::Evaluate(frame);
463
0
  }
464
465
 private:
466
  absl::Status EvaluateModernMessageGetField(
467
      ExecutionFrame* frame,
468
      const cel::ParsedMessageValue& parsed_message) const;
469
  absl::Status EvaluateLegacyMessageGetField(
470
      ExecutionFrame* frame, const google::protobuf::Message* legacy_message) const;
471
472
  const google::protobuf::Descriptor* descriptor_;
473
  const google::protobuf::FieldDescriptor* field_descriptor_;
474
};
475
476
0
bool CheckAttributeTrail(const std::string& field, ExecutionFrame* frame) {
477
0
  if (!frame->attribute_tracking_enabled()) {
478
0
    return false;
479
0
  }
480
0
  AttributeTrail& attr = frame->value_stack().PeekAttribute();
481
0
  attr = attr.Step(&field);
482
483
0
  absl::optional<Value> marked_attribute_check =
484
0
      CheckForMarkedAttributes(attr, *frame);
485
0
  if (marked_attribute_check.has_value()) {
486
0
    frame->value_stack().Peek() = std::move(marked_attribute_check).value();
487
0
    return true;
488
0
  }
489
490
0
  return false;
491
0
}
492
493
absl::Status ProtoSelectStep::EvaluateModernMessageGetField(
494
    ExecutionFrame* frame,
495
0
    const cel::ParsedMessageValue& parsed_message) const {
496
0
  if (CheckAttributeTrail(field_, frame)) {
497
0
    return absl::OkStatus();
498
0
  }
499
0
  return parsed_message.GetField(
500
0
      field_descriptor_, unboxing_option_, frame->descriptor_pool(),
501
0
      frame->message_factory(), frame->arena(), &frame->value_stack().Peek());
502
0
}
503
504
absl::Status ProtoSelectStep::EvaluateLegacyMessageGetField(
505
0
    ExecutionFrame* frame, const google::protobuf::Message* legacy_message) const {
506
0
  if (CheckAttributeTrail(field_, frame)) {
507
0
    return absl::OkStatus();
508
0
  }
509
0
  return cel::interop_internal::WrapLegacyMessageField(
510
0
      legacy_message, field_descriptor_, unboxing_option_,
511
0
      frame->descriptor_pool(), frame->message_factory(), frame->arena(),
512
0
      &frame->value_stack().Peek());
513
0
}
514
515
class ProtoHasStep : public SelectStep {
516
 public:
517
  ProtoHasStep(StringValue value, int64_t expr_id,
518
               bool enable_wrapper_type_null_unboxing,
519
               bool enable_optional_types, const google::protobuf::Descriptor* descriptor,
520
               const google::protobuf::FieldDescriptor* field_descriptor)
521
0
      : SelectStep(std::move(value), /*test_field_presence=*/true, expr_id,
522
0
                   enable_wrapper_type_null_unboxing, enable_optional_types),
523
0
        descriptor_(descriptor),
524
0
        field_descriptor_(field_descriptor) {
525
0
    ABSL_DCHECK(descriptor_ != nullptr);
526
0
    ABSL_DCHECK(field_descriptor_ != nullptr);
527
0
  }
528
529
0
  absl::Status Evaluate(ExecutionFrame* frame) const override {
530
0
    if (!frame->value_stack().HasEnough(1)) {
531
0
      return absl::InternalError(
532
0
          "No arguments supplied for Select-type expression");
533
0
    }
534
535
0
    const Value& arg = frame->value_stack().Peek();
536
0
    if (auto unwrapped = arg.AsParsedMessage();
537
0
        unwrapped.has_value() && unwrapped->GetDescriptor() == descriptor_) {
538
0
      return EvaluateHas(frame, *unwrapped);
539
0
    } else if (const google::protobuf::Message* legacy_message =
540
0
                   cel::interop_internal::GetLegacyMessage(arg);
541
0
               legacy_message != nullptr &&
542
0
               legacy_message->GetDescriptor() == descriptor_) {
543
0
      cel::ParsedMessageValue parsed_message =
544
0
          cel::UnsafeParsedMessageValue(legacy_message);
545
0
      return EvaluateHas(frame, parsed_message);
546
0
    }
547
    // If we get an unexpected value type, fall back to the generic
548
    // implementation.
549
0
    return SelectStep::Evaluate(frame);
550
0
  }
551
552
 private:
553
  absl::Status EvaluateHas(ExecutionFrame* frame,
554
                           const cel::ParsedMessageValue& parsed_message) const;
555
556
  const google::protobuf::Descriptor* descriptor_;
557
  const google::protobuf::FieldDescriptor* field_descriptor_;
558
};
559
560
absl::Status ProtoHasStep::EvaluateHas(
561
    ExecutionFrame* frame,
562
0
    const cel::ParsedMessageValue& parsed_message) const {
563
0
  if (CheckAttributeTrail(field_, frame)) {
564
0
    return absl::OkStatus();
565
0
  }
566
0
  frame->value_stack().Peek() =
567
0
      BoolValue{parsed_message.HasField(field_descriptor_)};
568
0
  return absl::OkStatus();
569
0
}
570
571
}  // namespace
572
573
std::unique_ptr<DirectExpressionStep> CreateDirectSelectStep(
574
    std::unique_ptr<DirectExpressionStep> operand, StringValue field,
575
    bool test_only, int64_t expr_id, bool enable_wrapper_type_null_unboxing,
576
0
    bool enable_optional_types) {
577
0
  return std::make_unique<DirectSelectStep>(
578
0
      expr_id, std::move(operand), std::move(field), test_only,
579
0
      enable_wrapper_type_null_unboxing, enable_optional_types);
580
0
}
581
582
// Factory method for Select - based Execution step
583
absl::StatusOr<std::unique_ptr<ExpressionStep>> CreateSelectStep(
584
    cel::StringValue field, bool test_only, int64_t expr_id,
585
17.7k
    bool enable_wrapper_type_null_unboxing, bool enable_optional_types) {
586
17.7k
  return std::make_unique<SelectStep>(std::move(field), test_only, expr_id,
587
17.7k
                                      enable_wrapper_type_null_unboxing,
588
17.7k
                                      enable_optional_types);
589
17.7k
}
590
591
// Factory method for Select - based Execution step
592
absl::StatusOr<std::unique_ptr<ExpressionStep>> CreateTypedSelectStep(
593
    cel::StringValue field, cel::StructType resolved_operand_type,
594
    cel::StructTypeField resolved_field, bool test_only, int64_t expr_id,
595
0
    bool enable_wrapper_type_null_unboxing, bool enable_optional_types) {
596
0
  if (!resolved_operand_type.IsMessage()) {
597
    // The specialization only supports messages. Fallback to the generic
598
    // implementation for other types.
599
    // TODO(uncreated-issue/89): support optional select and chaining.
600
0
    return CreateSelectStep(std::move(field), test_only, expr_id,
601
0
                            enable_wrapper_type_null_unboxing,
602
0
                            enable_optional_types);
603
0
  }
604
0
  const google::protobuf::Descriptor* descriptor =
605
0
      resolved_operand_type.GetMessage().descriptor();
606
607
0
  ABSL_DCHECK(resolved_field.IsMessage());
608
0
  const google::protobuf::FieldDescriptor* field_descriptor =
609
0
      resolved_field.GetMessage().descriptor();
610
611
0
  if (test_only) {
612
0
    return std::make_unique<ProtoHasStep>(
613
0
        std::move(field), expr_id, enable_wrapper_type_null_unboxing,
614
0
        enable_optional_types, descriptor, field_descriptor);
615
0
  }
616
617
0
  return std::make_unique<ProtoSelectStep>(
618
0
      std::move(field), expr_id, enable_wrapper_type_null_unboxing,
619
0
      enable_optional_types, descriptor, field_descriptor);
620
0
}
621
622
}  // namespace google::api::expr::runtime