diff --git a/internal/flag/internal_flag.go b/internal/flag/internal_flag.go index 0ea7394bc67..d9b6d35666e 100644 --- a/internal/flag/internal_flag.go +++ b/internal/flag/internal_flag.go @@ -27,7 +27,7 @@ type InternalFlag struct { Rules *[]Rule `json:"targeting,omitempty" yaml:"targeting,omitempty" toml:"targeting,omitempty"` // BucketingKey defines a source for a dynamic targeting key - BucketingKey string `json:"bucketingKey,omitempty" yaml:"bucketingKey,omitempty" toml:"bucketingKey,omitempty"` + BucketingKey *string `json:"bucketingKey,omitempty" yaml:"bucketingKey,omitempty" toml:"bucketingKey,omitempty"` // DefaultRule is the originalRule applied after checking that any other rules // matched the user. @@ -80,7 +80,7 @@ func (f *InternalFlag) Value( maps.Copy(evaluationCtx.GetCustom(), flagContext.EvaluationContextEnrichment) } - key, keyError := flag.GetBucketingKey(evaluationCtx) + key, keyError := flag.GetBucketingKeyValue(evaluationCtx) if keyError != nil { return flagContext.DefaultSdkValue, ResolutionDetails{ @@ -380,9 +380,22 @@ func (f *InternalFlag) GetVariationValue(name string) interface{} { return nil } -func (f *InternalFlag) GetBucketingKey(ctx ffcontext.Context) (string, error) { - if f.BucketingKey != "" { - value := ctx.GetCustom()[f.BucketingKey] +// GetBucketingKey return the name of the custom bucketing key if we are using one. +func (f *InternalFlag) GetBucketingKey() string { + if f.BucketingKey == nil { + return "" + } + return *f.BucketingKey +} + +// GetBucketingKeyValue return the value of the bucketing key from the context +func (f *InternalFlag) GetBucketingKeyValue(ctx ffcontext.Context) (string, error) { + if f.BucketingKey != nil { + key := f.GetBucketingKey() + if key == "" { + return ctx.GetKey(), nil + } + value := ctx.GetCustom()[f.GetBucketingKey()] switch v := value.(type) { case string: return v, nil @@ -390,7 +403,6 @@ func (f *InternalFlag) GetBucketingKey(ctx ffcontext.Context) (string, error) { return "", fmt.Errorf("invalid bucketing key") } } - return ctx.GetKey(), nil } diff --git a/internal/flag/internal_flag_test.go b/internal/flag/internal_flag_test.go index e76677e314c..6ab74b0bb7f 100644 --- a/internal/flag/internal_flag_test.go +++ b/internal/flag/internal_flag_test.go @@ -1731,7 +1731,7 @@ func TestInternalFlag_ValueWithBucketingKey(t *testing.T) { "variation_B": testconvert.Interface("value_B"), "variation_C": testconvert.Interface("value_C"), }, - BucketingKey: "teamId", + BucketingKey: testconvert.String("teamId"), DefaultRule: &flag.Rule{ Percentages: &map[string]float64{ "variation_A": 33, @@ -1758,7 +1758,7 @@ func TestInternalFlag_ValueWithBucketingKey(t *testing.T) { assert.Equal(t, tt.wantForTeamID, got.Variant) flagWithoutBucketingKey := tt.flag - flagWithoutBucketingKey.BucketingKey = "" + flagWithoutBucketingKey.BucketingKey = testconvert.String("") _, got = flagWithoutBucketingKey.Value(tt.args.flagName, tt.args.user, tt.args.flagContext) assert.Equal(t, tt.wantForTargetingKey, got.Variant) @@ -1773,7 +1773,7 @@ func TestInternalFlag_ValueWithBucketingKeyNotFound(t *testing.T) { "variation_B": testconvert.Interface("value_B"), "variation_C": testconvert.Interface("value_C"), }, - BucketingKey: "teamId", + BucketingKey: testconvert.String("teamId"), DefaultRule: &flag.Rule{ Percentages: &map[string]float64{ "variation_A": 33, diff --git a/model/dto/dto.go b/model/dto/dto.go index ff87ce0292f..d1fab169c32 100644 --- a/model/dto/dto.go +++ b/model/dto/dto.go @@ -38,7 +38,7 @@ type DTOv1 struct { Rules *[]flag.Rule `json:"targeting,omitempty" yaml:"targeting,omitempty" toml:"targeting,omitempty" jsonschema:"title=targeting,description=List of rule to target a subset of the users based on the evaluation context."` // nolint: lll // BucketingKey defines a source for a dynamic targeting key - BucketingKey string `json:"bucketingKey,omitempty" yaml:"bucketingKey,omitempty" toml:"bucketingKey,omitempty"` + BucketingKey *string `json:"bucketingKey,omitempty" yaml:"bucketingKey,omitempty" toml:"bucketingKey,omitempty"` // DefaultRule is the rule applied after checking that any other rules // matched the user.