Skip to content

Commit 25ecdac

Browse files
authored
feat!: changed client details signatures to return new type (#84)
* feat!: changed client details signatures to return new type Signed-off-by: Skye Gill <[email protected]>
1 parent a9f4429 commit 25ecdac

File tree

7 files changed

+188
-47
lines changed

7 files changed

+188
-47
lines changed

pkg/openfeature/client.go

Lines changed: 159 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ type IClient interface {
1919
FloatValue(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (float64, error)
2020
IntValue(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (int64, error)
2121
ObjectValue(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (interface{}, error)
22-
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
23-
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
24-
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
25-
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
26-
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
22+
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (BooleanEvaluationDetails, error)
23+
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (StringEvaluationDetails, error)
24+
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (FloatEvaluationDetails, error)
25+
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (IntEvaluationDetails, error)
26+
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (InterfaceEvaluationDetails, error)
2727
}
2828

2929
// ClientMetadata provides a client's metadata
@@ -110,10 +110,34 @@ var typeToString = map[Type]string{
110110
type EvaluationDetails struct {
111111
FlagKey string
112112
FlagType Type
113-
Value interface{}
114113
ResolutionDetail
115114
}
116115

116+
type BooleanEvaluationDetails struct {
117+
Value bool
118+
EvaluationDetails
119+
}
120+
121+
type StringEvaluationDetails struct {
122+
Value string
123+
EvaluationDetails
124+
}
125+
126+
type FloatEvaluationDetails struct {
127+
Value float64
128+
EvaluationDetails
129+
}
130+
131+
type IntEvaluationDetails struct {
132+
Value int64
133+
EvaluationDetails
134+
}
135+
136+
type InterfaceEvaluationDetails struct {
137+
Value interface{}
138+
EvaluationDetails
139+
}
140+
117141
type ResolutionDetail struct {
118142
Variant string
119143
Reason Reason
@@ -292,13 +316,41 @@ func (c Client) ObjectValue(ctx context.Context, flag string, defaultValue inter
292316
// - defaultValue is returned if an error occurs
293317
// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx)
294318
// - options are optional additional evaluation options e.g. WithHooks & WithHookHints
295-
func (c Client) BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error) {
319+
func (c Client) BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (BooleanEvaluationDetails, error) {
296320
evalOptions := &EvaluationOptions{}
297321
for _, option := range options {
298322
option(evalOptions)
299323
}
300324

301-
return c.evaluate(ctx, flag, Boolean, defaultValue, evalCtx, *evalOptions)
325+
evalDetails, err := c.evaluate(ctx, flag, Boolean, defaultValue, evalCtx, *evalOptions)
326+
if err != nil {
327+
return BooleanEvaluationDetails{
328+
Value: defaultValue,
329+
EvaluationDetails: evalDetails.EvaluationDetails,
330+
}, err
331+
}
332+
333+
value, ok := evalDetails.Value.(bool)
334+
if !ok {
335+
err := errors.New("evaluated value is not a boolean")
336+
c.logger().Error(
337+
err, "invalid flag resolution type", "expectedType", "boolean",
338+
"gotType", fmt.Sprintf("%T", evalDetails.Value),
339+
)
340+
boolEvalDetails := BooleanEvaluationDetails{
341+
Value: defaultValue,
342+
EvaluationDetails: evalDetails.EvaluationDetails,
343+
}
344+
boolEvalDetails.EvaluationDetails.ErrorCode = TypeMismatchCode
345+
boolEvalDetails.EvaluationDetails.ErrorMessage = err.Error()
346+
347+
return boolEvalDetails, err
348+
}
349+
350+
return BooleanEvaluationDetails{
351+
Value: value,
352+
EvaluationDetails: evalDetails.EvaluationDetails,
353+
}, nil
302354
}
303355

304356
// StringValueDetails performs a flag evaluation that returns an evaluation details struct.
@@ -309,13 +361,41 @@ func (c Client) BooleanValueDetails(ctx context.Context, flag string, defaultVal
309361
// - defaultValue is returned if an error occurs
310362
// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx)
311363
// - options are optional additional evaluation options e.g. WithHooks & WithHookHints
312-
func (c Client) StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error) {
364+
func (c Client) StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (StringEvaluationDetails, error) {
313365
evalOptions := &EvaluationOptions{}
314366
for _, option := range options {
315367
option(evalOptions)
316368
}
317369

318-
return c.evaluate(ctx, flag, String, defaultValue, evalCtx, *evalOptions)
370+
evalDetails, err := c.evaluate(ctx, flag, String, defaultValue, evalCtx, *evalOptions)
371+
if err != nil {
372+
return StringEvaluationDetails{
373+
Value: defaultValue,
374+
EvaluationDetails: evalDetails.EvaluationDetails,
375+
}, err
376+
}
377+
378+
value, ok := evalDetails.Value.(string)
379+
if !ok {
380+
err := errors.New("evaluated value is not a string")
381+
c.logger().Error(
382+
err, "invalid flag resolution type", "expectedType", "string",
383+
"gotType", fmt.Sprintf("%T", evalDetails.Value),
384+
)
385+
strEvalDetails := StringEvaluationDetails{
386+
Value: defaultValue,
387+
EvaluationDetails: evalDetails.EvaluationDetails,
388+
}
389+
strEvalDetails.EvaluationDetails.ErrorCode = TypeMismatchCode
390+
strEvalDetails.EvaluationDetails.ErrorMessage = err.Error()
391+
392+
return strEvalDetails, err
393+
}
394+
395+
return StringEvaluationDetails{
396+
Value: value,
397+
EvaluationDetails: evalDetails.EvaluationDetails,
398+
}, nil
319399
}
320400

321401
// FloatValueDetails performs a flag evaluation that returns an evaluation details struct.
@@ -326,13 +406,41 @@ func (c Client) StringValueDetails(ctx context.Context, flag string, defaultValu
326406
// - defaultValue is returned if an error occurs
327407
// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx)
328408
// - options are optional additional evaluation options e.g. WithHooks & WithHookHints
329-
func (c Client) FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error) {
409+
func (c Client) FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (FloatEvaluationDetails, error) {
330410
evalOptions := &EvaluationOptions{}
331411
for _, option := range options {
332412
option(evalOptions)
333413
}
334414

335-
return c.evaluate(ctx, flag, Float, defaultValue, evalCtx, *evalOptions)
415+
evalDetails, err := c.evaluate(ctx, flag, Float, defaultValue, evalCtx, *evalOptions)
416+
if err != nil {
417+
return FloatEvaluationDetails{
418+
Value: defaultValue,
419+
EvaluationDetails: evalDetails.EvaluationDetails,
420+
}, err
421+
}
422+
423+
value, ok := evalDetails.Value.(float64)
424+
if !ok {
425+
err := errors.New("evaluated value is not a float64")
426+
c.logger().Error(
427+
err, "invalid flag resolution type", "expectedType", "float64",
428+
"gotType", fmt.Sprintf("%T", evalDetails.Value),
429+
)
430+
floatEvalDetails := FloatEvaluationDetails{
431+
Value: defaultValue,
432+
EvaluationDetails: evalDetails.EvaluationDetails,
433+
}
434+
floatEvalDetails.EvaluationDetails.ErrorCode = TypeMismatchCode
435+
floatEvalDetails.EvaluationDetails.ErrorMessage = err.Error()
436+
437+
return floatEvalDetails, err
438+
}
439+
440+
return FloatEvaluationDetails{
441+
Value: value,
442+
EvaluationDetails: evalDetails.EvaluationDetails,
443+
}, nil
336444
}
337445

338446
// IntValueDetails performs a flag evaluation that returns an evaluation details struct.
@@ -343,13 +451,41 @@ func (c Client) FloatValueDetails(ctx context.Context, flag string, defaultValue
343451
// - defaultValue is returned if an error occurs
344452
// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx)
345453
// - options are optional additional evaluation options e.g. WithHooks & WithHookHints
346-
func (c Client) IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error) {
454+
func (c Client) IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (IntEvaluationDetails, error) {
347455
evalOptions := &EvaluationOptions{}
348456
for _, option := range options {
349457
option(evalOptions)
350458
}
351459

352-
return c.evaluate(ctx, flag, Int, defaultValue, evalCtx, *evalOptions)
460+
evalDetails, err := c.evaluate(ctx, flag, Int, defaultValue, evalCtx, *evalOptions)
461+
if err != nil {
462+
return IntEvaluationDetails{
463+
Value: defaultValue,
464+
EvaluationDetails: evalDetails.EvaluationDetails,
465+
}, err
466+
}
467+
468+
value, ok := evalDetails.Value.(int64)
469+
if !ok {
470+
err := errors.New("evaluated value is not an int64")
471+
c.logger().Error(
472+
err, "invalid flag resolution type", "expectedType", "int64",
473+
"gotType", fmt.Sprintf("%T", evalDetails.Value),
474+
)
475+
intEvalDetails := IntEvaluationDetails{
476+
Value: defaultValue,
477+
EvaluationDetails: evalDetails.EvaluationDetails,
478+
}
479+
intEvalDetails.EvaluationDetails.ErrorCode = TypeMismatchCode
480+
intEvalDetails.EvaluationDetails.ErrorMessage = err.Error()
481+
482+
return intEvalDetails, err
483+
}
484+
485+
return IntEvaluationDetails{
486+
Value: value,
487+
EvaluationDetails: evalDetails.EvaluationDetails,
488+
}, nil
353489
}
354490

355491
// ObjectValueDetails performs a flag evaluation that returns an evaluation details struct.
@@ -360,7 +496,7 @@ func (c Client) IntValueDetails(ctx context.Context, flag string, defaultValue i
360496
// - defaultValue is returned if an error occurs
361497
// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx)
362498
// - options are optional additional evaluation options e.g. WithHooks & WithHookHints
363-
func (c Client) ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error) {
499+
func (c Client) ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (InterfaceEvaluationDetails, error) {
364500
evalOptions := &EvaluationOptions{}
365501
for _, option := range options {
366502
option(evalOptions)
@@ -371,7 +507,7 @@ func (c Client) ObjectValueDetails(ctx context.Context, flag string, defaultValu
371507

372508
func (c Client) evaluate(
373509
ctx context.Context, flag string, flagType Type, defaultValue interface{}, evalCtx EvaluationContext, options EvaluationOptions,
374-
) (EvaluationDetails, error) {
510+
) (InterfaceEvaluationDetails, error) {
375511
c.logger().V(debug).Info(
376512
"evaluating flag", "flag", flag, "type", flagType.String(), "defaultValue", defaultValue,
377513
"evaluationContext", evalCtx, "evaluationOptions", options,
@@ -387,10 +523,12 @@ func (c Client) evaluate(
387523
providerMetadata: api.provider.Metadata(),
388524
evaluationContext: evalCtx,
389525
}
390-
evalDetails := EvaluationDetails{
391-
FlagKey: flag,
392-
FlagType: flagType,
393-
Value: defaultValue,
526+
evalDetails := InterfaceEvaluationDetails{
527+
Value: defaultValue,
528+
EvaluationDetails: EvaluationDetails{
529+
FlagKey: flag,
530+
FlagType: flagType,
531+
},
394532
}
395533

396534
apiClientInvocationProviderHooks := append(append(append(api.hooks, c.hooks...), options.hooks...), api.provider.Hooks()...) // API, Client, Invocation, Provider
@@ -500,7 +638,7 @@ func (c Client) beforeHooks(
500638
}
501639

502640
func (c Client) afterHooks(
503-
hookCtx HookContext, hooks []Hook, evalDetails EvaluationDetails, options EvaluationOptions,
641+
hookCtx HookContext, hooks []Hook, evalDetails InterfaceEvaluationDetails, options EvaluationOptions,
504642
) error {
505643
c.logger().V(debug).Info("executing after hooks")
506644
defer c.logger().V(debug).Info("executed after hooks")

pkg/openfeature/client_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ func TestRequirement_1_4_1(t *testing.T) {
8282
client := NewClient("test-client")
8383

8484
type requirements interface {
85-
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
86-
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
87-
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
88-
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
89-
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
85+
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (BooleanEvaluationDetails, error)
86+
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (StringEvaluationDetails, error)
87+
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (FloatEvaluationDetails, error)
88+
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (IntEvaluationDetails, error)
89+
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (InterfaceEvaluationDetails, error)
9090
}
9191

9292
var clientI interface{} = client
@@ -298,7 +298,7 @@ func TestRequirement_1_4_9(t *testing.T) {
298298
t.Error("expected BooleanValueDetails to return an error, got nil")
299299
}
300300

301-
if valueDetails.Value.(bool) != defaultValue {
301+
if valueDetails.Value != defaultValue {
302302
t.Errorf("expected default value from BooleanValueDetails, got %v", value)
303303
}
304304
})
@@ -332,7 +332,7 @@ func TestRequirement_1_4_9(t *testing.T) {
332332
t.Error("expected StringValueDetails to return an error, got nil")
333333
}
334334

335-
if valueDetails.Value.(string) != defaultValue {
335+
if valueDetails.Value != defaultValue {
336336
t.Errorf("expected default value from StringValueDetails, got %v", value)
337337
}
338338
})
@@ -366,7 +366,7 @@ func TestRequirement_1_4_9(t *testing.T) {
366366
t.Error("expected FloatValueDetails to return an error, got nil")
367367
}
368368

369-
if valueDetails.Value.(float64) != defaultValue {
369+
if valueDetails.Value != defaultValue {
370370
t.Errorf("expected default value from FloatValueDetails, got %v", value)
371371
}
372372
})
@@ -400,7 +400,7 @@ func TestRequirement_1_4_9(t *testing.T) {
400400
t.Error("expected FloatValueDetails to return an error, got nil")
401401
}
402402

403-
if valueDetails.Value.(int64) != defaultValue {
403+
if valueDetails.Value != defaultValue {
404404
t.Errorf("expected default value from IntValueDetails, got %v", value)
405405
}
406406
})

pkg/openfeature/evaluation_context_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ func TestRequirement_3_2_1(t *testing.T) {
6969
FloatValue(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (float64, error)
7070
IntValue(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (int64, error)
7171
ObjectValue(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (interface{}, error)
72-
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
73-
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
74-
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
75-
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
76-
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
72+
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (BooleanEvaluationDetails, error)
73+
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (StringEvaluationDetails, error)
74+
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (FloatEvaluationDetails, error)
75+
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (IntEvaluationDetails, error)
76+
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (InterfaceEvaluationDetails, error)
7777
}
7878

7979
var clientI interface{} = client

pkg/openfeature/hooks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package openfeature
55
// https://github.com/open-feature/spec/blob/main/specification/hooks.md
66
type Hook interface {
77
Before(hookContext HookContext, hookHints HookHints) (*EvaluationContext, error)
8-
After(hookContext HookContext, flagEvaluationDetails EvaluationDetails, hookHints HookHints) error
8+
After(hookContext HookContext, flagEvaluationDetails InterfaceEvaluationDetails, hookHints HookHints) error
99
Error(hookContext HookContext, err error, hookHints HookHints)
1010
Finally(hookContext HookContext, hookHints HookHints)
1111
}
@@ -81,7 +81,7 @@ func (u UnimplementedHook) Before(hookContext HookContext, hookHints HookHints)
8181
return nil, nil
8282
}
8383

84-
func (u UnimplementedHook) After(hookContext HookContext, flagEvaluationDetails EvaluationDetails, hookHints HookHints) error {
84+
func (u UnimplementedHook) After(hookContext HookContext, flagEvaluationDetails InterfaceEvaluationDetails, hookHints HookHints) error {
8585
return nil
8686
}
8787

pkg/openfeature/hooks_mock_test.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)