pkg/provider/provider.go (118 lines of code) (raw):

package provider import ( "context" "github.com/open-feature/go-sdk/openfeature" c "github.com/spotify/confidence-sdk-go/pkg/confidence" "reflect" ) type FlagProvider struct { confidence c.Confidence } func NewFlagProvider(confidence c.Confidence) *FlagProvider { return &FlagProvider{ confidence: confidence, } } func (e FlagProvider) Metadata() openfeature.Metadata { return openfeature.Metadata{Name: "ConfidenceFlagProvider"} } func (e FlagProvider) BooleanEvaluation(ctx context.Context, flag string, defaultValue bool, evalCtx openfeature.FlattenedContext) openfeature.BoolResolutionDetail { confidence := e.confidence.WithContext(processTargetingKey(evalCtx)) res := confidence.ResolveFlag(ctx, flag, defaultValue, reflect.Bool) boolDetail := c.ToBoolResolutionDetail(res, defaultValue) return openfeature.BoolResolutionDetail{ Value: boolDetail.Value, ProviderResolutionDetail: toOFResolutionDetail(boolDetail.ResolutionDetail), } } func (e FlagProvider) StringEvaluation(ctx context.Context, flag string, defaultValue string, evalCtx openfeature.FlattenedContext) openfeature.StringResolutionDetail { confidence := e.confidence.WithContext(processTargetingKey(evalCtx)) res := confidence.ResolveFlag(ctx, flag, defaultValue, reflect.String) detail := c.ToStringResolutionDetail(res, defaultValue) return openfeature.StringResolutionDetail{ Value: detail.Value, ProviderResolutionDetail: toOFResolutionDetail(detail.ResolutionDetail), } } func (e FlagProvider) FloatEvaluation(ctx context.Context, flag string, defaultValue float64, evalCtx openfeature.FlattenedContext) openfeature.FloatResolutionDetail { confidence := e.confidence.WithContext(processTargetingKey(evalCtx)) res := confidence.ResolveFlag(ctx, flag, defaultValue, reflect.Float64) detail := c.ToFloatResolutionDetail(res, defaultValue) return openfeature.FloatResolutionDetail{ Value: detail.Value, ProviderResolutionDetail: toOFResolutionDetail(detail.ResolutionDetail), } } func (e FlagProvider) IntEvaluation(ctx context.Context, flag string, defaultValue int64, evalCtx openfeature.FlattenedContext) openfeature.IntResolutionDetail { confidence := e.confidence.WithContext(processTargetingKey(evalCtx)) res := confidence.ResolveFlag(ctx, flag, defaultValue, reflect.Int64) detail := c.ToIntResolutionDetail(res, defaultValue) return openfeature.IntResolutionDetail{ Value: detail.Value, ProviderResolutionDetail: toOFResolutionDetail(detail.ResolutionDetail), } } func (e FlagProvider) ObjectEvaluation(ctx context.Context, flag string, defaultValue interface{}, evalCtx openfeature.FlattenedContext) openfeature.InterfaceResolutionDetail { confidence := e.confidence.WithContext(processTargetingKey(evalCtx)) res := confidence.ResolveFlag(ctx, flag, defaultValue, reflect.Map) detail := c.ToObjectResolutionDetail(res, defaultValue) return openfeature.InterfaceResolutionDetail{ Value: detail.Value, ProviderResolutionDetail: toOFResolutionDetail(detail.ResolutionDetail), } } func (e FlagProvider) Hooks() []openfeature.Hook { return []openfeature.Hook{} } func toOFResolutionDetail(detail c.ResolutionDetail) openfeature.ProviderResolutionDetail { return openfeature.ProviderResolutionDetail{ ResolutionError: toOFResolutionError(detail.ErrorCode, detail.ErrorMessage), Reason: toOFReason(detail.Reason), Variant: detail.Variant, FlagMetadata: toOFFlagMetadata(detail.FlagMetadata), } } func toOFResolutionError(code c.ErrorCode, message string) openfeature.ResolutionError { switch code { case c.TypeMismatchCode: return openfeature.NewTypeMismatchResolutionError(message) case c.FlagNotFoundCode: return openfeature.NewFlagNotFoundResolutionError(message) case c.GeneralCode: return openfeature.NewGeneralResolutionError(message) case c.InvalidContextCode: return openfeature.NewInvalidContextResolutionError(message) case c.ProviderNotReadyCode: return openfeature.NewProviderNotReadyResolutionError(message) case c.ParseErrorCode: return openfeature.NewParseErrorResolutionError(message) } return openfeature.ResolutionError{} } func processTargetingKey(evalCtx openfeature.FlattenedContext) openfeature.FlattenedContext { newEvalContext := openfeature.FlattenedContext{} newEvalContext = evalCtx if targetingKey, exists := evalCtx["targetingKey"]; exists { newEvalContext["targeting_key"] = targetingKey } delete(newEvalContext, "targetingKey") return newEvalContext } func toOFFlagMetadata(metadata c.FlagMetadata) map[string]interface{} { return metadata } func toOFReason(reason c.Reason) openfeature.Reason { switch reason { case c.TargetingMatchReason: return openfeature.TargetingMatchReason case c.DefaultReason: return openfeature.DefaultReason default: return openfeature.ErrorReason } }