github.com/openfga/openfga@v1.5.4-rc1/internal/condition/eval/eval.go (about) 1 package eval 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 "time" 8 9 openfgav1 "github.com/openfga/api/proto/openfga/v1" 10 "go.opentelemetry.io/otel" 11 "go.opentelemetry.io/otel/attribute" 12 "go.opentelemetry.io/otel/trace" 13 "google.golang.org/protobuf/types/known/structpb" 14 15 "github.com/openfga/openfga/internal/condition" 16 "github.com/openfga/openfga/internal/condition/metrics" 17 "github.com/openfga/openfga/pkg/telemetry" 18 "github.com/openfga/openfga/pkg/typesystem" 19 ) 20 21 var tracer = otel.Tracer("openfga/internal/condition/eval") 22 23 // EvaluateTupleCondition looks at the given tuple's condition and returns an evaluation result for the given context. 24 // If the tuple doesn't have a condition, it exits early and doesn't create a span. 25 // If the tuple's condition isn't found in the model it returns an EvaluationError. 26 func EvaluateTupleCondition( 27 ctx context.Context, 28 tupleKey *openfgav1.TupleKey, 29 typesys *typesystem.TypeSystem, 30 context *structpb.Struct, 31 ) (*condition.EvaluationResult, error) { 32 tupleCondition := tupleKey.GetCondition() 33 conditionName := tupleCondition.GetName() 34 if conditionName == "" { 35 return &condition.EvaluationResult{ 36 ConditionMet: true, 37 }, nil 38 } 39 40 ctx, span := tracer.Start(ctx, "EvaluateTupleCondition", trace.WithAttributes( 41 attribute.String("tuple_key", tupleKey.String()), 42 attribute.String("condition_name", conditionName))) 43 defer span.End() 44 45 start := time.Now() 46 47 evaluableCondition, ok := typesys.GetCondition(conditionName) 48 if !ok { 49 err := condition.NewEvaluationError(conditionName, fmt.Errorf("condition was not found")) 50 telemetry.TraceError(span, err) 51 return nil, err 52 } 53 54 span.SetAttributes(attribute.String("condition_expression", evaluableCondition.GetExpression())) 55 56 // merge both contexts 57 contextFields := []map[string]*structpb.Value{ 58 {}, 59 } 60 if context != nil { 61 contextFields = []map[string]*structpb.Value{context.GetFields()} 62 } 63 64 tupleContext := tupleCondition.GetContext() 65 if tupleContext != nil { 66 contextFields = append(contextFields, tupleContext.GetFields()) 67 } 68 69 conditionResult, err := evaluableCondition.Evaluate(ctx, contextFields...) 70 if err != nil { 71 telemetry.TraceError(span, err) 72 return nil, err 73 } 74 75 metrics.Metrics.ObserveEvaluationDuration(time.Since(start)) 76 metrics.Metrics.ObserveEvaluationCost(conditionResult.Cost) 77 78 span.SetAttributes(attribute.Bool("condition_met", conditionResult.ConditionMet), 79 attribute.String("condition_cost", strconv.FormatUint(conditionResult.Cost, 10)), 80 attribute.StringSlice("condition_missing_params", conditionResult.MissingParameters), 81 ) 82 return &conditionResult, nil 83 }