2525import dev .cel .common .values .CelValueConverter ;
2626import dev .cel .runtime .GlobalResolver ;
2727import java .util .NoSuchElementException ;
28+ import org .jspecify .annotations .Nullable ;
2829
2930@ Immutable
3031final class NamespacedAttribute implements Attribute {
@@ -34,6 +35,14 @@ final class NamespacedAttribute implements Attribute {
3435 private final CelValueConverter celValueConverter ;
3536 private final CelTypeProvider typeProvider ;
3637
38+ ImmutableList <Qualifier > qualifiers () {
39+ return qualifiers ;
40+ }
41+
42+ ImmutableSet <String > candidateVariableNames () {
43+ return namespacedNames ;
44+ }
45+
3746 @ Override
3847 public Object resolve (GlobalResolver ctx , ExecutionFrame frame ) {
3948 GlobalResolver inputVars = ctx ;
@@ -59,41 +68,58 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
5968 }
6069 }
6170
62- CelType type = typeProvider .findType (name ).orElse (null );
63- if (type != null ) {
64- if (qualifiers .isEmpty ()) {
65- // Resolution of a fully qualified type name: foo.bar.baz
66- return TypeType .create (type );
67- } else {
68- // This is potentially a fully qualified reference to an enum value
69- if (type instanceof EnumType && qualifiers .size () == 1 ) {
70- EnumType enumType = (EnumType ) type ;
71- String strQualifier = (String ) qualifiers .get (0 ).value ();
72- return enumType
73- .findNumberByName (strQualifier )
74- .orElseThrow (
75- () ->
76- new NoSuchElementException (
77- String .format (
78- "Field %s was not found on enum %s" ,
79- enumType .name (), strQualifier )));
80- }
81- }
82-
83- throw new IllegalStateException (
84- "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
71+ // Attempt to resolve the qualify type name if the name is not a variable identifier
72+ value = findIdent (name );
73+ if (value != null ) {
74+ return value ;
8575 }
8676 }
8777
8878 return MissingAttribute .newMissingAttribute (namespacedNames );
8979 }
9080
91- ImmutableList <Qualifier > qualifiers () {
92- return qualifiers ;
81+ private @ Nullable Object findIdent (String name ) {
82+ CelType type = typeProvider .findType (name ).orElse (null );
83+ // If the name resolves directly, this is either a fully qualified type name
84+ // (ex: 'int' or 'google.protobuf.Timestamp')
85+ // or an enum with a string qualifier
86+ // (ex: my.enum_type, qualifier: .BAR)
87+ if (type != null ) {
88+ if (qualifiers .isEmpty ()) {
89+ // Resolution of a fully qualified type name: foo.bar.baz
90+ return TypeType .create (type );
91+ }
92+
93+ throw new IllegalStateException (
94+ "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
95+ }
96+
97+ // The name itself could be a fully qualified reference to an enum value
98+ // (e.g: my.enum_type.BAR)
99+ int lastDotIndex = name .lastIndexOf ('.' );
100+ if (lastDotIndex > 0 ) {
101+ String enumTypeName = name .substring (0 , lastDotIndex );
102+ String enumValueQualifier = name .substring (lastDotIndex + 1 );
103+
104+ return typeProvider
105+ .findType (enumTypeName )
106+ .filter (EnumType .class ::isInstance )
107+ .map (EnumType .class ::cast )
108+ .map (enumType -> getEnumValue (enumType , enumValueQualifier ))
109+ .orElse (null );
110+ }
111+
112+ return null ;
93113 }
94114
95- ImmutableSet <String > candidateVariableNames () {
96- return namespacedNames ;
115+ private static Long getEnumValue (EnumType enumType , String field ) {
116+ return enumType
117+ .findNumberByName (field )
118+ .map (Integer ::longValue )
119+ .orElseThrow (
120+ () ->
121+ new NoSuchElementException (
122+ String .format ("Field %s was not found on enum %s" , enumType .name (), field )));
97123 }
98124
99125 private GlobalResolver unwrapToNonLocal (GlobalResolver resolver ) {
0 commit comments