github.com/openfga/openfga@v1.5.4-rc1/internal/condition/types/types.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/google/cel-go/cel" 8 openfgav1 "github.com/openfga/api/proto/openfga/v1" 9 ) 10 11 var CustomParamTypes = map[openfgav1.ConditionParamTypeRef_TypeName][]cel.EnvOption{} 12 13 var paramTypeDefinitions = map[openfgav1.ConditionParamTypeRef_TypeName]paramTypeDefinition{} 14 15 // typedParamValueConverter defines a signature that implementations can provide to enforce type enforcements 16 // over any values provided. 17 type typedParamValueConverter func(value any) (any, error) 18 19 // paramTypeDefinition represents a parameter type definition included in a relationship condition. 20 // 21 // For example, the following condition defines two parameter type definitions (user and color), and 22 // the 'user' parameter has a type that is a map<any> (a map with a generic type of any) and the 'color' 23 // parameter has a type that is a string. 24 // 25 // condition favorite_color(user map<any>, color string) { 26 // user.favoriteColor == color 27 // } 28 type paramTypeDefinition struct { 29 // name is the name/keyword for the type (e.g. 'string', 'timestamp', 'duration', 'map', 'list', 'ipaddress') 30 name openfgav1.ConditionParamTypeRef_TypeName 31 32 genericTypeCount uint 33 34 toParameterType func(genericType []ParameterType) (*ParameterType, error) 35 } 36 37 var paramTypeString = map[openfgav1.ConditionParamTypeRef_TypeName]string{ 38 openfgav1.ConditionParamTypeRef_TYPE_NAME_ANY: "any", 39 openfgav1.ConditionParamTypeRef_TYPE_NAME_BOOL: "bool", 40 openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING: "string", 41 openfgav1.ConditionParamTypeRef_TYPE_NAME_INT: "int", 42 openfgav1.ConditionParamTypeRef_TYPE_NAME_UINT: "uint", 43 openfgav1.ConditionParamTypeRef_TYPE_NAME_DOUBLE: "double", 44 openfgav1.ConditionParamTypeRef_TYPE_NAME_DURATION: "duration", 45 openfgav1.ConditionParamTypeRef_TYPE_NAME_TIMESTAMP: "timestamp", 46 openfgav1.ConditionParamTypeRef_TYPE_NAME_MAP: "map", 47 openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST: "list", 48 openfgav1.ConditionParamTypeRef_TYPE_NAME_IPADDRESS: "ipaddress", 49 } 50 51 func registerParamTypeWithGenerics( 52 paramTypeKeyword openfgav1.ConditionParamTypeRef_TypeName, 53 genericTypeCount uint, 54 toParameterType func(genericType []ParameterType) ParameterType, 55 ) func(genericTypes ...ParameterType) (ParameterType, error) { 56 paramTypeDefinitions[paramTypeKeyword] = paramTypeDefinition{ 57 name: paramTypeKeyword, 58 genericTypeCount: genericTypeCount, 59 toParameterType: func(genericTypes []ParameterType) (*ParameterType, error) { 60 if uint(len(genericTypes)) != genericTypeCount { 61 return nil, fmt.Errorf("type `%s` requires %d generic types; found %d", paramTypeKeyword, genericTypeCount, len(genericTypes)) 62 } 63 64 built := toParameterType(genericTypes) 65 return &built, nil 66 }, 67 } 68 69 return func(genericTypes ...ParameterType) (ParameterType, error) { 70 if uint(len(genericTypes)) != genericTypeCount { 71 return ParameterType{}, fmt.Errorf("invalid number of parameters given to type constructor. expected: %d, found: %d", genericTypeCount, len(genericTypes)) 72 } 73 74 return toParameterType(genericTypes), nil 75 } 76 } 77 78 func registerParamType( 79 paramTypeKeyword openfgav1.ConditionParamTypeRef_TypeName, 80 celType *cel.Type, 81 typedParamConverter typedParamValueConverter, 82 ) ParameterType { 83 paramType := ParameterType{ 84 name: paramTypeKeyword, 85 celType: celType, 86 genericTypes: nil, 87 typedParamConverter: typedParamConverter, 88 } 89 90 paramTypeDefinitions[paramTypeKeyword] = paramTypeDefinition{ 91 name: paramTypeKeyword, 92 genericTypeCount: 0, 93 toParameterType: func(genericTypes []ParameterType) (*ParameterType, error) { 94 return ¶mType, nil 95 }, 96 } 97 98 return paramType 99 } 100 101 func registerCustomParamType( 102 paramTypeKeyword openfgav1.ConditionParamTypeRef_TypeName, 103 celType *cel.Type, 104 typeConverter typedParamValueConverter, 105 celOpts ...cel.EnvOption, 106 ) ParameterType { 107 CustomParamTypes[paramTypeKeyword] = celOpts 108 return registerParamType(paramTypeKeyword, celType, typeConverter) 109 } 110 111 // ParameterType defines the canonical representation of parameter types supported in conditions. 112 type ParameterType struct { 113 name openfgav1.ConditionParamTypeRef_TypeName 114 celType *cel.Type 115 genericTypes []ParameterType 116 typedParamConverter typedParamValueConverter 117 } 118 119 func NewParameterType( 120 name openfgav1.ConditionParamTypeRef_TypeName, 121 celType *cel.Type, 122 generics []ParameterType, 123 typedParamConverter typedParamValueConverter, 124 ) ParameterType { 125 return ParameterType{ 126 name, 127 celType, 128 generics, 129 typedParamConverter, 130 } 131 } 132 133 // CelType returns the underlying Google CEL type for the variable type. 134 func (pt ParameterType) CelType() *cel.Type { 135 return pt.celType 136 } 137 138 func (pt ParameterType) String() string { 139 if len(pt.genericTypes) > 0 { 140 genericTypeStrings := make([]string, 0, len(pt.genericTypes)) 141 142 for _, genericType := range pt.genericTypes { 143 genericTypeStrings = append(genericTypeStrings, genericType.String()) 144 } 145 146 // e.g. map<int> 147 return fmt.Sprintf("%s<%s>", pt.name, strings.Join(genericTypeStrings, ", ")) 148 } 149 150 str, ok := paramTypeString[pt.name] 151 if !ok { 152 return "unknown" 153 } 154 155 return str 156 } 157 158 func (pt ParameterType) ConvertValue(value any) (any, error) { 159 converted, err := pt.typedParamConverter(value) 160 if err != nil { 161 return nil, err 162 } 163 164 return converted, nil 165 }