5959import dev .cel .common .types .CelTypes ;
6060import dev .cel .common .types .ListType ;
6161import dev .cel .common .types .SimpleType ;
62+ import dev .cel .common .types .TypeParamType ;
63+ import dev .cel .common .types .TypeType ;
6264import dev .cel .common .values .CelByteString ;
6365import dev .cel .optimizer .AstMutator ;
6466import dev .cel .optimizer .CelAstOptimizer ;
103105 * <p>Expressions are rewritten into the following forms:
104106 *
105107 * <pre>
106- * // Selection chains (user message is 3-tuple, leaf scalar is 4-tuple)
108+ * // Selection chains (user message is 3-tuple, leaf scalar is 4-tuple, leaf type is 3rd argument )
107109 * request.user.age -> cel.@attribute(request,
108- * [[user_num, "user", type_code], [age_num, "age", type_code, default_val]])
110+ * [[user_num, "user", type_code], [age_num, "age", type_code, default_val]], int )
109111 *
110112 * // Presence tests (2-tuples)
111113 * has(request.user.age) -> cel.@hasField(request,
@@ -127,15 +129,18 @@ public final class SelectOptimizer implements CelAstOptimizer {
127129 private static final String CEL_ATTRIBUTE_FUNCTION_NAME = "cel.@attribute" ;
128130 private static final String CEL_HAS_FIELD_FUNCTION_NAME = "cel.@hasField" ;
129131
132+ private static final TypeParamType TYPE_PARAM_T = TypeParamType .create ("T" );
133+
130134 @ VisibleForTesting
131135 static final CelFunctionDecl CEL_ATTRIBUTE_FUNCTION_DECL =
132136 CelFunctionDecl .newFunctionDeclaration (
133137 CEL_ATTRIBUTE_FUNCTION_NAME ,
134138 CelOverloadDecl .newGlobalOverload (
135139 "cel_attribute_list" ,
140+ TYPE_PARAM_T ,
136141 SimpleType .DYN ,
137- SimpleType .DYN ,
138- ListType .create (SimpleType . DYN )));
142+ ListType . create ( SimpleType .DYN ) ,
143+ TypeType .create (TYPE_PARAM_T )));
139144
140145 @ VisibleForTesting
141146 static final CelFunctionDecl CEL_HAS_FIELD_FUNCTION_DECL =
@@ -295,8 +300,19 @@ private void rewriteSelectChain(
295300
296301 CelMutableExpr qualifiersExpr =
297302 CelMutableExpr .ofList (idGenerator .nextExprId (), CelMutableList .create (qualifierLists ));
298- String functionName = isHasField ? CEL_HAS_FIELD_FUNCTION_NAME : CEL_ATTRIBUTE_FUNCTION_NAME ;
299- topNode .expr ().setCall (CelMutableCall .create (functionName , currentExpr , qualifiersExpr ));
303+ if (isHasField ) {
304+ topNode
305+ .expr ()
306+ .setCall (CelMutableCall .create (CEL_HAS_FIELD_FUNCTION_NAME , currentExpr , qualifiersExpr ));
307+ } else {
308+ CelMutableExpr typeExpr =
309+ CelMutableExpr .ofIdent (idGenerator .nextExprId (), resolveTypeIdent (topField ));
310+ topNode
311+ .expr ()
312+ .setCall (
313+ CelMutableCall .create (
314+ CEL_ATTRIBUTE_FUNCTION_NAME , currentExpr , qualifiersExpr , typeExpr ));
315+ }
300316 }
301317
302318 private static long resolveTypeCode (FieldDescriptor field ) {
@@ -306,6 +322,43 @@ private static long resolveTypeCode(FieldDescriptor field) {
306322 return field .getType ().toProto ().getNumber ();
307323 }
308324
325+ private static String resolveTypeIdent (FieldDescriptor field ) {
326+ if (field .isMapField ()) {
327+ return "map" ;
328+ }
329+ if (field .isRepeated ()) {
330+ return "list" ;
331+ }
332+ switch (field .getType ()) {
333+ case DOUBLE :
334+ case FLOAT :
335+ return "double" ;
336+ case INT64 :
337+ case SINT64 :
338+ case SFIXED64 :
339+ case INT32 :
340+ case SINT32 :
341+ case SFIXED32 :
342+ case ENUM :
343+ return "int" ;
344+ case UINT64 :
345+ case FIXED64 :
346+ case UINT32 :
347+ case FIXED32 :
348+ return "uint" ;
349+ case BOOL :
350+ return "bool" ;
351+ case STRING :
352+ return "string" ;
353+ case BYTES :
354+ return "bytes" ;
355+ case MESSAGE :
356+ return field .getMessageType ().getFullName ();
357+ default :
358+ throw new IllegalArgumentException ("Unsupported protobuf field type: " + field .getType ());
359+ }
360+ }
361+
309362 private boolean isTopOfSelectChain (CelNavigableMutableAst navAst , CelNavigableMutableExpr node ) {
310363 return getOptimizableField (navAst , node ).isPresent ()
311364 && !node .parent ().flatMap (parent -> getOptimizableField (navAst , parent )).isPresent ();
@@ -414,13 +467,6 @@ private static CelAbstractSyntaxTree tagAstExtension(CelAbstractSyntaxTree ast)
414467 return CelAbstractSyntaxTree .newParsedAst (ast .getExpr (), celSourceBuilder .build ());
415468 }
416469
417- private SelectOptimizer (
418- SelectOptimizerOptions options , Iterable <FileDescriptor > fileDescriptors ) {
419- this .options = checkNotNull (options );
420- this .astMutator = AstMutator .newInstance (options .iterationLimit ());
421- this .descriptorPool = newDescriptorPool (options , checkNotNull (fileDescriptors ));
422- }
423-
424470 private static CelDescriptorPool newDescriptorPool (
425471 SelectOptimizerOptions options , Iterable <FileDescriptor > fileDescriptors ) {
426472 CelDescriptors celDescriptors =
@@ -432,6 +478,13 @@ private static CelDescriptorPool newDescriptorPool(
432478 return CombinedDescriptorPool .create (descriptorPools .build ());
433479 }
434480
481+ private SelectOptimizer (
482+ SelectOptimizerOptions options , Iterable <FileDescriptor > fileDescriptors ) {
483+ this .options = checkNotNull (options );
484+ this .astMutator = AstMutator .newInstance (options .iterationLimit ());
485+ this .descriptorPool = newDescriptorPool (options , checkNotNull (fileDescriptors ));
486+ }
487+
435488 /** Options configuring the behavior of {@link SelectOptimizer}. */
436489 @ AutoValue
437490 public abstract static class SelectOptimizerOptions {
0 commit comments