Skip to content

Commit 0c169de

Browse files
committed
fixup: add support for old selector
Signed-off-by: Todd Baert <[email protected]>
1 parent c589463 commit 0c169de

File tree

3 files changed

+100
-24
lines changed

3 files changed

+100
-24
lines changed

core/pkg/store/query.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,21 @@ func NewSelector(selectorExpression string) Selector {
4141
}
4242
}
4343

44-
func expressionToMap(selector string) map[string]string {
44+
func expressionToMap(sExp string) map[string]string {
4545
selectorMap := make(map[string]string)
46-
if selector == "" {
46+
if sExp == "" {
47+
return selectorMap
48+
}
49+
50+
if strings.Index(sExp, "=") == -1 {
51+
// if no '=' is found, treat the whole string as as source (backwards compatibility)
52+
// we may may support interpreting this as a flagSetId in the future as an option
53+
selectorMap[sourceIndex] = sExp
4754
return selectorMap
4855
}
4956

5057
// Split the selector by commas
51-
pairs := strings.Split(selector, ",")
58+
pairs := strings.Split(sExp, ",")
5259
for _, pair := range pairs {
5360
// Split each pair by the first equal sign
5461
parts := strings.Split(pair, "=")
@@ -109,9 +116,13 @@ func (s Selector) ToQuery() (indexId string, constraints []interface{}) {
109116

110117
// SelectorToMetadata converts the selector's internal map to metadata for logging or tracing purposes.
111118
// Only includes known indices to avoid leaking sensitive information, and is usually returned as the "top level" metadata
112-
func (s Selector) ToMetadata() model.Metadata {
119+
func (s *Selector) ToMetadata() model.Metadata {
113120
meta := model.Metadata{}
114121

122+
if s == nil || s.indexMap == nil {
123+
return meta
124+
}
125+
115126
if s.indexMap[flagSetIdIndex] != "" {
116127
meta[flagSetIdIndex] = s.indexMap[flagSetIdIndex]
117128
}

core/pkg/store/query_test.go

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package store
33
import (
44
"reflect"
55
"testing"
6+
7+
"github.com/open-feature/flagd/core/pkg/model"
68
)
79

810
func TestSelector_IsEmpty(t *testing.T) {
@@ -100,25 +102,92 @@ func TestSelector_ToQuery(t *testing.T) {
100102
}
101103

102104
func TestSelector_ToMetadata(t *testing.T) {
103-
s := Selector{indexMap: map[string]string{"flagSetId": "fsid", "source": "src", "key": "myKey"}}
104-
meta := s.ToMetadata()
105-
if meta["flagSetId"] != "fsid" {
106-
t.Errorf("ToMetadata missing flagSetId")
107-
}
108-
if meta["source"] != "src" {
109-
t.Errorf("ToMetadata missing source")
105+
tests := []struct {
106+
name string
107+
selector *Selector
108+
want model.Metadata
109+
}{
110+
{
111+
name: "nil selector",
112+
selector: nil,
113+
want: model.Metadata{},
114+
},
115+
{
116+
name: "nil indexMap",
117+
selector: &Selector{indexMap: nil},
118+
want: model.Metadata{},
119+
},
120+
{
121+
name: "empty indexMap",
122+
selector: &Selector{indexMap: map[string]string{}},
123+
want: model.Metadata{},
124+
},
125+
{
126+
name: "flagSetId only",
127+
selector: &Selector{indexMap: map[string]string{"flagSetId": "fsid"}},
128+
want: model.Metadata{"flagSetId": "fsid"},
129+
},
130+
{
131+
name: "source only",
132+
selector: &Selector{indexMap: map[string]string{"source": "src"}},
133+
want: model.Metadata{"source": "src"},
134+
},
135+
{
136+
name: "flagSetId and source",
137+
selector: &Selector{indexMap: map[string]string{"flagSetId": "fsid", "source": "src"}},
138+
want: model.Metadata{"flagSetId": "fsid", "source": "src"},
139+
},
140+
{
141+
name: "flagSetId, source, and key (key should be ignored)",
142+
selector: &Selector{indexMap: map[string]string{"flagSetId": "fsid", "source": "src", "key": "myKey"}},
143+
want: model.Metadata{"flagSetId": "fsid", "source": "src"},
144+
},
110145
}
111-
if _, ok := meta["key"]; ok {
112-
t.Errorf("ToMetadata should not include key")
146+
147+
for _, tt := range tests {
148+
t.Run(tt.name, func(t *testing.T) {
149+
got := tt.selector.ToMetadata()
150+
if !reflect.DeepEqual(got, tt.want) {
151+
t.Errorf("ToMetadata() = %v, want %v", got, tt.want)
152+
}
153+
})
113154
}
114155
}
115156

116157
func TestNewSelector(t *testing.T) {
117-
s := NewSelector("source=abc,flagSetId=1234")
118-
if s.indexMap["source"] != "abc" {
119-
t.Errorf("NewSelector did not parse source")
158+
tests := []struct {
159+
name string
160+
input string
161+
wantMap map[string]string
162+
}{
163+
{
164+
name: "source and flagSetId",
165+
input: "source=abc,flagSetId=1234",
166+
wantMap: map[string]string{"source": "abc", "flagSetId": "1234"},
167+
},
168+
{
169+
name: "source",
170+
input: "source=abc",
171+
wantMap: map[string]string{"source": "abc"},
172+
},
173+
{
174+
name: "no equals, treat as source",
175+
input: "mysource",
176+
wantMap: map[string]string{"source": "mysource"},
177+
},
178+
{
179+
name: "empty string",
180+
input: "",
181+
wantMap: map[string]string{},
182+
},
120183
}
121-
if s.indexMap["flagSetId"] != "1234" {
122-
t.Errorf("NewSelector did not parse flagSetId")
184+
185+
for _, tt := range tests {
186+
t.Run(tt.name, func(t *testing.T) {
187+
s := NewSelector(tt.input)
188+
if !reflect.DeepEqual(s.indexMap, tt.wantMap) {
189+
t.Errorf("NewSelector(%q) indexMap = %v, want %v", tt.input, s.indexMap, tt.wantMap)
190+
}
191+
})
123192
}
124193
}

core/pkg/store/store.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,10 @@ func NewFlags() *Store {
154154
func (s *Store) Get(_ context.Context, key string, selector *Selector) (model.Flag, model.Metadata, error) {
155155
s.logger.Debug(fmt.Sprintf("getting flag %s", key))
156156
txn := s.db.Txn(false)
157-
queryMeta := model.Metadata{}
157+
queryMeta := selector.ToMetadata()
158158

159159
// if present, use the selector to query the flags
160160
if !selector.IsEmpty() {
161-
queryMeta = selector.ToMetadata()
162161
selector := selector.WithIndex("key", key)
163162
indexId, constraints := selector.ToQuery()
164163
s.logger.Debug(fmt.Sprintf("getting flag with query: %s, %v", indexId, constraints))
@@ -218,10 +217,7 @@ func (f *Store) String() (string, error) {
218217
// GetAll returns a copy of the store's state (copy in order to be concurrency safe)
219218
func (s *Store) GetAll(ctx context.Context, selector *Selector) (map[string]model.Flag, model.Metadata, error) {
220219
flags := make(map[string]model.Flag)
221-
queryMeta := model.Metadata{}
222-
if selector != nil && !selector.IsEmpty() {
223-
queryMeta = selector.ToMetadata()
224-
}
220+
queryMeta := selector.ToMetadata()
225221
it, err := s.selectOrAll(selector)
226222

227223
if err != nil {

0 commit comments

Comments
 (0)