Skip to content

Commit f75fa8f

Browse files
authored
[FFM-5876]: Extending existing query interface to improve FF-Server integration (#106)
* Extending existing query interface to take advantage from feature store list and improve performance. * Amending unit tests to the new code.
1 parent de17fd9 commit f75fa8f

File tree

3 files changed

+74
-36
lines changed

3 files changed

+74
-36
lines changed

evaluation/evaluator.go

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ const (
3232
type Query interface {
3333
GetSegment(identifier string) (rest.Segment, error)
3434
GetFlag(identifier string) (rest.FeatureConfig, error)
35+
GetFlags() ([]rest.FeatureConfig, error)
36+
}
37+
38+
// FlagVariations list of FlagVariations
39+
type FlagVariations []FlagVariation
40+
41+
// FlagVariation contains all required for ff-server to evaluate.
42+
type FlagVariation struct {
43+
FlagIdentifier string
44+
Kind rest.FeatureConfigKind
45+
Variation rest.Variation
3546
}
3647

3748
// PostEvalData holds information for post evaluation processing
@@ -327,28 +338,55 @@ func (e Evaluator) checkPreRequisite(fc *rest.FeatureConfig, target *Target) (bo
327338
return true, nil
328339
}
329340

330-
// Evaluate exposes evaluate to the caller.
331-
func (e Evaluator) Evaluate(identifier string, target *Target, kind string) (rest.Variation, error) {
341+
// EvaluateAll evaluates all the flags
342+
func (e Evaluator) EvaluateAll(target *Target) (FlagVariations, error) {
343+
return e.evaluateAll(target)
344+
}
345+
346+
// takes uses feature store.List function to get all the flags.
347+
func (e Evaluator) evaluateAll(target *Target) ([]FlagVariation, error) {
348+
var variations []FlagVariation
349+
flags, err := e.query.GetFlags()
350+
if err != nil {
351+
return variations, err
352+
}
353+
for _, f := range flags {
354+
v, _ := e.getVariationForTheFlag(f, target)
355+
variations = append(variations, FlagVariation{f.Feature, f.Kind, v})
356+
}
357+
358+
return variations, nil
359+
}
332360

333-
return e.evaluate(identifier, target, kind)
361+
// Evaluate exposes evaluate to the caller.
362+
func (e Evaluator) Evaluate(identifier string, target *Target) (FlagVariation, error) {
363+
return e.evaluate(identifier, target)
334364
}
335365

336-
func (e Evaluator) evaluate(identifier string, target *Target, kind string) (rest.Variation, error) {
366+
// this is evaluating flag.
367+
func (e Evaluator) evaluate(identifier string, target *Target) (FlagVariation, error) {
337368

338369
if e.query == nil {
339370
e.logger.Errorf(ErrQueryProviderMissing.Error())
340-
return rest.Variation{}, ErrQueryProviderMissing
371+
return FlagVariation{}, ErrQueryProviderMissing
341372
}
342373
flag, err := e.query.GetFlag(identifier)
343374
if err != nil {
344-
return rest.Variation{}, err
375+
return FlagVariation{}, err
345376
}
346-
if string(flag.Kind) != kind {
347-
return rest.Variation{}, fmt.Errorf("%w, expected: %s, got: %s", ErrFlagKindMismatch, kind, flag.Kind)
377+
378+
variation, err := e.getVariationForTheFlag(flag, target)
379+
if err != nil {
380+
return FlagVariation{}, err
348381
}
382+
return FlagVariation{flag.Feature, flag.Kind, variation}, nil
383+
}
384+
385+
// evaluates the flag and returns a proper variation.
386+
func (e Evaluator) getVariationForTheFlag(flag rest.FeatureConfig, target *Target) (rest.Variation, error) {
349387

350388
if flag.Prerequisites != nil {
351-
prereq, err := e.checkPreRequisite(&flag, target) // equivalent of evaluateWithPreReqq
389+
prereq, err := e.checkPreRequisite(&flag, target)
352390
if err != nil || !prereq {
353391
return findVariation(flag.Variations, flag.OffVariation)
354392
}
@@ -371,34 +409,33 @@ func (e Evaluator) evaluate(identifier string, target *Target, kind string) (res
371409

372410
// BoolVariation returns boolean evaluation for target
373411
func (e Evaluator) BoolVariation(identifier string, target *Target, defaultValue bool) bool {
374-
variation, err := e.evaluate(identifier, target, "boolean")
412+
//flagVariation, err := e.evaluate(identifier, target, "boolean")
413+
flagVariation, err := e.evaluate(identifier, target)
375414
if err != nil {
376415
e.logger.Errorf("Error while evaluating boolean flag '%s', err: %v", identifier, err)
377416
return defaultValue
378417
}
379-
return strings.ToLower(variation.Value) == "true"
418+
return strings.ToLower(flagVariation.Variation.Value) == "true"
380419
}
381420

382421
// StringVariation returns string evaluation for target
383422
func (e Evaluator) StringVariation(identifier string, target *Target, defaultValue string) string {
384-
385-
variation, err := e.evaluate(identifier, target, "string")
423+
flagVariation, err := e.evaluate(identifier, target)
386424
if err != nil {
387425
e.logger.Errorf("Error while evaluating string flag '%s', err: %v", identifier, err)
388426
return defaultValue
389427
}
390-
return variation.Value
428+
return flagVariation.Variation.Value
391429
}
392430

393431
// IntVariation returns int evaluation for target
394432
func (e Evaluator) IntVariation(identifier string, target *Target, defaultValue int) int {
395-
396-
variation, err := e.evaluate(identifier, target, "int")
433+
flagVariation, err := e.evaluate(identifier, target)
397434
if err != nil {
398435
e.logger.Errorf("Error while evaluating int flag '%s', err: %v", identifier, err)
399436
return defaultValue
400437
}
401-
val, err := strconv.Atoi(variation.Value)
438+
val, err := strconv.Atoi(flagVariation.Variation.Value)
402439
if err != nil {
403440
return defaultValue
404441
}
@@ -408,12 +445,12 @@ func (e Evaluator) IntVariation(identifier string, target *Target, defaultValue
408445
// NumberVariation returns number evaluation for target
409446
func (e Evaluator) NumberVariation(identifier string, target *Target, defaultValue float64) float64 {
410447
//all numbers are stored as ints in the database
411-
variation, err := e.evaluate(identifier, target, "int")
448+
flagVariation, err := e.evaluate(identifier, target)
412449
if err != nil {
413450
e.logger.Errorf("Error while evaluating number flag '%s', err: %v", identifier, err)
414451
return defaultValue
415452
}
416-
val, err := strconv.ParseFloat(variation.Value, 64)
453+
val, err := strconv.ParseFloat(flagVariation.Variation.Value, 64)
417454
if err != nil {
418455
return defaultValue
419456
}
@@ -423,14 +460,13 @@ func (e Evaluator) NumberVariation(identifier string, target *Target, defaultVal
423460
// JSONVariation returns json evaluation for target
424461
func (e Evaluator) JSONVariation(identifier string, target *Target,
425462
defaultValue map[string]interface{}) map[string]interface{} {
426-
427-
variation, err := e.evaluate(identifier, target, "json")
463+
flagVariation, err := e.evaluate(identifier, target)
428464
if err != nil {
429465
e.logger.Errorf("Error while evaluating json flag '%s', err: %v", identifier, err)
430466
return defaultValue
431467
}
432468
val := make(map[string]interface{})
433-
err = json.Unmarshal([]byte(variation.Value), &val)
469+
err = json.Unmarshal([]byte(flagVariation.Variation.Value), &val)
434470
if err != nil {
435471
return defaultValue
436472
}

evaluation/evaluator_test.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@ func (m TestRepository) GetFlag(identifier string) (rest.FeatureConfig, error) {
303303
}
304304
return flag, nil
305305
}
306+
func (m TestRepository) GetFlags() ([]rest.FeatureConfig, error) {
307+
308+
var flags []rest.FeatureConfig
309+
for _, f := range m.flags {
310+
flags = append(flags, f)
311+
}
312+
return flags, nil
313+
}
306314

307315
func TestNewEvaluator(t *testing.T) {
308316
noOpLogger := logger.NewNoOpLogger()
@@ -1329,18 +1337,6 @@ func TestEvaluator_evaluate(t *testing.T) {
13291337
want: rest.Variation{},
13301338
wantErr: true,
13311339
},
1332-
{
1333-
name: "flag kind mismatch",
1334-
fields: fields{
1335-
query: testRepo,
1336-
},
1337-
args: args{
1338-
identifier: simple,
1339-
kind: "string",
1340-
},
1341-
want: rest.Variation{},
1342-
wantErr: true,
1343-
},
13441340
{
13451341
name: "prereq flag simple should return true",
13461342
fields: fields{
@@ -1394,12 +1390,12 @@ func TestEvaluator_evaluate(t *testing.T) {
13941390
query: tt.fields.query,
13951391
logger: logger.NewNoOpLogger(),
13961392
}
1397-
got, err := e.evaluate(tt.args.identifier, tt.args.target, tt.args.kind)
1393+
got, err := e.evaluate(tt.args.identifier, tt.args.target)
13981394
if (err != nil) != tt.wantErr {
13991395
t.Errorf("Evaluator.evaluate() error = %v, wantErr %v", err, tt.wantErr)
14001396
return
14011397
}
1402-
if !reflect.DeepEqual(got, tt.want) {
1398+
if !reflect.DeepEqual(got.Variation, tt.want) {
14031399
t.Errorf("Evaluator.evaluate() = %v, want %v", got, tt.want)
14041400
}
14051401
})

pkg/repository/repository.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
type Repository interface {
1313
GetFlag(identifier string) (rest.FeatureConfig, error)
1414
GetSegment(identifier string) (rest.Segment, error)
15+
GetFlags() ([]rest.FeatureConfig, error)
1516

1617
SetFlag(featureConfig rest.FeatureConfig, initialLoad bool)
1718
SetSegment(segment rest.Segment, initialLoad bool)
@@ -84,6 +85,11 @@ func (r FFRepository) GetFlag(identifier string) (rest.FeatureConfig, error) {
8485
return r.getFlagAndCache(identifier, true)
8586
}
8687

88+
// GetFlags returns all the flags /* Not implemented */
89+
func (r FFRepository) GetFlags() ([]rest.FeatureConfig, error) {
90+
return []rest.FeatureConfig{}, nil
91+
}
92+
8793
func (r FFRepository) getSegmentAndCache(identifier string, cacheable bool) (rest.Segment, error) {
8894
segmentKey := formatSegmentKey(identifier)
8995
flag, ok := r.cache.Get(segmentKey)

0 commit comments

Comments
 (0)