Skip to content

Commit bad9b0b

Browse files
author
Michael Ng
authored
refac(api): Flatten out user attributes entity. (#46)
1 parent 540f3f3 commit bad9b0b

18 files changed

+299
-344
lines changed

cmd/is_feature_enabled.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ package cmd
1818

1919
import (
2020
"fmt"
21+
2122
"github.com/optimizely/go-sdk/optimizely/client"
2223
"github.com/optimizely/go-sdk/optimizely/entities"
2324
"github.com/spf13/cobra"
2425
)
2526

2627
var (
27-
userId string
28+
userId string
2829
featurekKey string
2930
)
3031

@@ -46,7 +47,7 @@ var isFeatureEnabledCmd = &cobra.Command{
4647

4748
user := entities.UserContext{
4849
ID: userId,
49-
Attributes: entities.UserAttributes{},
50+
Attributes: map[string]interface{}{},
5051
}
5152

5253
enabled, _ := client.IsFeatureEnabled(featurekKey, user)

examples/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ func main() {
2222
}
2323

2424
user := entities.UserContext{
25-
ID: "mike ng",
26-
Attributes: entities.UserAttributes{},
25+
ID: "mike ng",
26+
Attributes: map[string]interface{}{
27+
"country": "Unknown",
28+
"likes_donuts": true,
29+
},
2730
}
2831

2932
enabled, _ := client.IsFeatureEnabled("go_sdk", user)

optimizely/decision/evaluator/condition_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ func TestCustomAttributeConditionEvaluator(t *testing.T) {
3434

3535
// Test condition passes
3636
user := entities.UserContext{
37-
Attributes: entities.UserAttributes{
38-
Attributes: map[string]interface{}{
39-
"string_foo": "foo",
40-
},
37+
Attributes: map[string]interface{}{
38+
"string_foo": "foo",
4139
},
4240
}
4341

@@ -47,10 +45,8 @@ func TestCustomAttributeConditionEvaluator(t *testing.T) {
4745

4846
// Test condition fails
4947
user = entities.UserContext{
50-
Attributes: entities.UserAttributes{
51-
Attributes: map[string]interface{}{
52-
"string_foo": "not_foo",
53-
},
48+
Attributes: map[string]interface{}{
49+
"string_foo": "not_foo",
5450
},
5551
}
5652
result, _ = conditionEvaluator.Evaluate(condition, condTreeParams)

optimizely/decision/evaluator/condition_tree_test.go

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ func TestConditionTreeEvaluateSimpleCondition(t *testing.T) {
4242

4343
// Test match
4444
user := e.UserContext{
45-
Attributes: e.UserAttributes{
46-
Attributes: map[string]interface{}{
47-
"string_foo": "foo",
48-
},
45+
Attributes: map[string]interface{}{
46+
"string_foo": "foo",
4947
},
5048
}
5149
condTreeParams := e.NewTreeParameters(&user, map[string]e.Audience{})
@@ -54,10 +52,8 @@ func TestConditionTreeEvaluateSimpleCondition(t *testing.T) {
5452

5553
// Test no match
5654
user = e.UserContext{
57-
Attributes: e.UserAttributes{
58-
Attributes: map[string]interface{}{
59-
"string_foo": "not foo",
60-
},
55+
Attributes: map[string]interface{}{
56+
"string_foo": "not foo",
6157
},
6258
}
6359
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
@@ -80,10 +76,8 @@ func TestConditionTreeEvaluateMultipleOrConditions(t *testing.T) {
8076

8177
// Test match string
8278
user := e.UserContext{
83-
Attributes: e.UserAttributes{
84-
Attributes: map[string]interface{}{
85-
"string_foo": "foo",
86-
},
79+
Attributes: map[string]interface{}{
80+
"string_foo": "foo",
8781
},
8882
}
8983

@@ -93,34 +87,28 @@ func TestConditionTreeEvaluateMultipleOrConditions(t *testing.T) {
9387

9488
// Test match bool
9589
user = e.UserContext{
96-
Attributes: e.UserAttributes{
97-
Attributes: map[string]interface{}{
98-
"bool_true": true,
99-
},
90+
Attributes: map[string]interface{}{
91+
"bool_true": true,
10092
},
10193
}
10294
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
10395
assert.True(t, result)
10496

10597
// Test match both
10698
user = e.UserContext{
107-
Attributes: e.UserAttributes{
108-
Attributes: map[string]interface{}{
109-
"string_foo": "foo",
110-
"bool_true": true,
111-
},
99+
Attributes: map[string]interface{}{
100+
"string_foo": "foo",
101+
"bool_true": true,
112102
},
113103
}
114104
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
115105
assert.True(t, result)
116106

117107
// Test no match
118108
user = e.UserContext{
119-
Attributes: e.UserAttributes{
120-
Attributes: map[string]interface{}{
121-
"string_foo": "not foo",
122-
"bool_true": false,
123-
},
109+
Attributes: map[string]interface{}{
110+
"string_foo": "not foo",
111+
"bool_true": false,
124112
},
125113
}
126114
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
@@ -143,10 +131,8 @@ func TestConditionTreeEvaluateMultipleAndConditions(t *testing.T) {
143131

144132
// Test only string match with NULL bubbling
145133
user := e.UserContext{
146-
Attributes: e.UserAttributes{
147-
Attributes: map[string]interface{}{
148-
"string_foo": "foo",
149-
},
134+
Attributes: map[string]interface{}{
135+
"string_foo": "foo",
150136
},
151137
}
152138

@@ -156,34 +142,28 @@ func TestConditionTreeEvaluateMultipleAndConditions(t *testing.T) {
156142

157143
// Test only bool match with NULL bubbling
158144
user = e.UserContext{
159-
Attributes: e.UserAttributes{
160-
Attributes: map[string]interface{}{
161-
"bool_true": true,
162-
},
145+
Attributes: map[string]interface{}{
146+
"bool_true": true,
163147
},
164148
}
165149
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
166150
assert.False(t, result)
167151

168152
// Test match both
169153
user = e.UserContext{
170-
Attributes: e.UserAttributes{
171-
Attributes: map[string]interface{}{
172-
"string_foo": "foo",
173-
"bool_true": true,
174-
},
154+
Attributes: map[string]interface{}{
155+
"string_foo": "foo",
156+
"bool_true": true,
175157
},
176158
}
177159
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
178160
assert.True(t, result)
179161

180162
// Test no match
181163
user = e.UserContext{
182-
Attributes: e.UserAttributes{
183-
Attributes: map[string]interface{}{
184-
"string_foo": "not foo",
185-
"bool_true": false,
186-
},
164+
Attributes: map[string]interface{}{
165+
"string_foo": "not foo",
166+
"bool_true": false,
187167
},
188168
}
189169
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
@@ -217,10 +197,8 @@ func TestConditionTreeEvaluateNotCondition(t *testing.T) {
217197

218198
// Test match string
219199
user := e.UserContext{
220-
Attributes: e.UserAttributes{
221-
Attributes: map[string]interface{}{
222-
"string_foo": "not foo",
223-
},
200+
Attributes: map[string]interface{}{
201+
"string_foo": "not foo",
224202
},
225203
}
226204

@@ -230,34 +208,28 @@ func TestConditionTreeEvaluateNotCondition(t *testing.T) {
230208

231209
// Test match bool
232210
user = e.UserContext{
233-
Attributes: e.UserAttributes{
234-
Attributes: map[string]interface{}{
235-
"bool_true": false,
236-
},
211+
Attributes: map[string]interface{}{
212+
"bool_true": false,
237213
},
238214
}
239215
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
240216
assert.True(t, result)
241217

242218
// Test match both
243219
user = e.UserContext{
244-
Attributes: e.UserAttributes{
245-
Attributes: map[string]interface{}{
246-
"string_foo": "not foo",
247-
"bool_true": false,
248-
},
220+
Attributes: map[string]interface{}{
221+
"string_foo": "not foo",
222+
"bool_true": false,
249223
},
250224
}
251225
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
252226
assert.True(t, result)
253227

254228
// Test no match
255229
user = e.UserContext{
256-
Attributes: e.UserAttributes{
257-
Attributes: map[string]interface{}{
258-
"string_foo": "foo",
259-
"bool_true": true,
260-
},
230+
Attributes: map[string]interface{}{
231+
"string_foo": "foo",
232+
"bool_true": true,
261233
},
262234
}
263235
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
@@ -302,12 +274,10 @@ func TestConditionTreeEvaluateMultipleMixedConditions(t *testing.T) {
302274

303275
// Test only match AND condition
304276
user := e.UserContext{
305-
Attributes: e.UserAttributes{
306-
Attributes: map[string]interface{}{
307-
"string_foo": "foo",
308-
"bool_true": true,
309-
"int_42": 43,
310-
},
277+
Attributes: map[string]interface{}{
278+
"string_foo": "foo",
279+
"bool_true": true,
280+
"int_42": 43,
311281
},
312282
}
313283

@@ -317,38 +287,32 @@ func TestConditionTreeEvaluateMultipleMixedConditions(t *testing.T) {
317287

318288
// Test only match the NOT condition
319289
user = e.UserContext{
320-
Attributes: e.UserAttributes{
321-
Attributes: map[string]interface{}{
322-
"string_foo": "not foo",
323-
"bool_true": true,
324-
"int_42": 43,
325-
},
290+
Attributes: map[string]interface{}{
291+
"string_foo": "not foo",
292+
"bool_true": true,
293+
"int_42": 43,
326294
},
327295
}
328296
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
329297
assert.True(t, result)
330298

331299
// Test only match the int condition
332300
user = e.UserContext{
333-
Attributes: e.UserAttributes{
334-
Attributes: map[string]interface{}{
335-
"string_foo": "foo",
336-
"bool_true": false,
337-
"int_42": 42,
338-
},
301+
Attributes: map[string]interface{}{
302+
"string_foo": "foo",
303+
"bool_true": false,
304+
"int_42": 42,
339305
},
340306
}
341307
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)
342308
assert.True(t, result)
343309

344310
// Test no match
345311
user = e.UserContext{
346-
Attributes: e.UserAttributes{
347-
Attributes: map[string]interface{}{
348-
"string_foo": "foo",
349-
"bool_true": false,
350-
"int_42": 43,
351-
},
312+
Attributes: map[string]interface{}{
313+
"string_foo": "foo",
314+
"bool_true": false,
315+
"int_42": 43,
352316
},
353317
}
354318
result = conditionTreeEvaluator.Evaluate(conditionTree, condTreeParams)

optimizely/decision/evaluator/matchers/exact.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,23 @@ type ExactMatcher struct {
3131
// Match returns true if the user's attribute match the condition's string value
3232
func (m ExactMatcher) Match(user entities.UserContext) (bool, error) {
3333
if stringValue, ok := m.Condition.Value.(string); ok {
34-
attributeValue, err := user.Attributes.GetString(m.Condition.Name)
34+
attributeValue, err := user.GetStringAttribute(m.Condition.Name)
3535
if err != nil {
3636
return false, err
3737
}
3838
return stringValue == attributeValue, nil
3939
}
4040

4141
if boolValue, ok := m.Condition.Value.(bool); ok {
42-
attributeValue, err := user.Attributes.GetBool(m.Condition.Name)
42+
attributeValue, err := user.GetBoolAttribute(m.Condition.Name)
4343
if err != nil {
4444
return false, err
4545
}
4646
return boolValue == attributeValue, nil
4747
}
4848

4949
if floatValue, ok := utils.ToFloat(m.Condition.Value); ok {
50-
attributeValue, err := user.Attributes.GetFloat(m.Condition.Name)
50+
attributeValue, err := user.GetFloatAttribute(m.Condition.Name)
5151
if err != nil {
5252
return false, err
5353
}

0 commit comments

Comments
 (0)