@@ -62,126 +62,192 @@ extension OptimizelyClient {
62
62
key: String ,
63
63
options: [ OptimizelyDecideOption ] ? = nil ) -> OptimizelyDecision {
64
64
65
- guard let config = self . config else {
65
+ guard config != nil else {
66
66
return OptimizelyDecision . errorDecision ( key: key, user: user, error: . sdkNotReady)
67
67
}
68
+
69
+ let allOptions = defaultDecideOptions + ( options ?? [ ] )
70
+ let decisionMap = decide ( user: user, keys: [ key] , options: allOptions)
71
+ return decisionMap [ key] ?? OptimizelyDecision . errorDecision ( key: key, user: user, error: . generic)
72
+ }
73
+
74
+ func decide( user: OptimizelyUserContext ,
75
+ keys: [ String ] ,
76
+ options: [ OptimizelyDecideOption ] ? = nil ) -> [ String : OptimizelyDecision ] {
77
+ guard let config = self . config else {
78
+ logger. e ( OptimizelyError . sdkNotReady)
79
+ return [ : ]
80
+ }
81
+
82
+ var decisionMap = [ String : OptimizelyDecision] ( )
83
+
84
+ guard keys. count > 0 else { return decisionMap }
85
+
86
+ var validKeys = [ String] ( )
87
+ var flagsWithoutForceDecision = [ FeatureFlag] ( )
88
+ var flagDecisions = [ String: FeatureDecision] ( )
89
+ var decisionReasonMap = [ String : DecisionReasons] ( )
68
90
69
- guard let feature = config. getFeatureFlag ( key: key) else {
70
- return OptimizelyDecision . errorDecision ( key: key, user: user, error: . featureKeyInvalid( key) )
91
+ let allOptions = options ?? [ ]
92
+
93
+ for key in keys {
94
+ guard let flags = config. getFeatureFlag ( key: key) else {
95
+ decisionMap [ key] = OptimizelyDecision . errorDecision ( key: key, user: user, error: . featureKeyInvalid( key) )
96
+ continue
97
+ }
98
+ validKeys. append ( key)
99
+
100
+ // check forced-decisions first
101
+ let decisionReasons = DecisionReasons ( options: allOptions)
102
+ let forcedDecisionResponse = decisionService. findValidatedForcedDecision ( config: config,
103
+ user: user,
104
+ context: OptimizelyDecisionContext ( flagKey: key) )
105
+
106
+ decisionReasons. merge ( forcedDecisionResponse. reasons)
107
+ decisionReasonMap [ key] = decisionReasons
108
+
109
+ if let variation = forcedDecisionResponse. result {
110
+ let featureDecision = FeatureDecision ( experiment: nil , variation: variation, source: Constants . DecisionSource. featureTest. rawValue)
111
+ flagDecisions [ key] = featureDecision
112
+ } else {
113
+ flagsWithoutForceDecision. append ( flags)
114
+ }
71
115
}
72
116
73
- let userId = user. userId
74
- let attributes = user. attributes
75
- let allOptions = defaultDecideOptions + ( options ?? [ ] )
76
- let reasons = DecisionReasons ( options: allOptions)
77
- var decisionEventDispatched = false
78
- var enabled = false
117
+ let decisionList = ( decisionService as? DefaultDecisionService ) ? . getVariationForFeatureList ( config: config, featureFlags: flagsWithoutForceDecision, user: user, options: allOptions)
79
118
80
- var decision : FeatureDecision ?
119
+ for index in 0 ..< flagsWithoutForceDecision. count {
120
+ if decisionList? . indices. contains ( index) ?? false ,
121
+ let decision = decisionList ? [ index] ,
122
+ let result = decision. result {
123
+ let flagKey = flagsWithoutForceDecision [ index] . key
124
+ flagDecisions [ flagKey] = result
125
+ let _reasons = decisionReasonMap [ flagKey]
126
+ _reasons? . merge ( decision. reasons)
127
+ decisionReasonMap [ flagKey] = _reasons
128
+
129
+ } else {
130
+ logger. e ( " Decsion not found in decisionList " )
131
+ }
132
+ }
81
133
82
- // check forced-decisions first
134
+ for index in 0 ..< validKeys. count {
135
+ let key = validKeys [ index]
136
+ let flagDecision = flagDecisions [ key]
137
+ let decisionReasons = decisionReasonMap [ key] ?? DecisionReasons ( options: allOptions)
138
+ let optimizelyDecision = createOptimizelyDecision ( flagKey: key,
139
+ user: user,
140
+ flagDecision: flagDecision,
141
+ decisionReasons: decisionReasons,
142
+ allOptions: allOptions,
143
+ config: config)
144
+ if ( !allOptions. contains ( . enabledFlagsOnly) || optimizelyDecision. enabled) {
145
+ decisionMap [ key] = optimizelyDecision
146
+ }
147
+ }
83
148
84
- let forcedDecisionResponse = decisionService. findValidatedForcedDecision ( config: config,
85
- user: user,
86
- context: OptimizelyDecisionContext ( flagKey: key) )
87
- reasons. merge ( forcedDecisionResponse. reasons)
149
+ return decisionMap
150
+ }
151
+
152
+ private func createOptimizelyDecision( flagKey: String ,
153
+ user: OptimizelyUserContext ,
154
+ flagDecision: FeatureDecision ? ,
155
+ decisionReasons: DecisionReasons ,
156
+ allOptions: [ OptimizelyDecideOption ] ,
157
+ config: ProjectConfig ) -> OptimizelyDecision {
88
158
89
- if let variation = forcedDecisionResponse. result {
90
- decision = FeatureDecision ( experiment: nil , variation: variation, source: Constants . DecisionSource. featureTest. rawValue)
91
- } else {
92
- // regular decision
93
-
94
- let decisionResponse = decisionService. getVariationForFeature ( config: config,
95
- featureFlag: feature,
96
- user: user,
97
- options: allOptions)
98
- reasons. merge ( decisionResponse. reasons)
99
- decision = decisionResponse. result
100
- }
101
-
102
- if let featureEnabled = decision? . variation. featureEnabled {
103
- enabled = featureEnabled
159
+ guard let feature = config. getFeatureFlag ( key: flagKey) else {
160
+ return OptimizelyDecision . errorDecision ( key: flagKey, user: user, error: . featureKeyInvalid( flagKey) )
104
161
}
105
162
163
+ let userId = user. userId
164
+ let attributes = user. attributes
165
+ let flagEnabled = flagDecision? . variation. featureEnabled ?? false
166
+
167
+ logger. i ( " Feature \( flagKey) is enabled for user \( userId) \( flagEnabled) " )
168
+
169
+ var decisionEventDispatched = false
170
+
106
171
if !allOptions. contains ( . disableDecisionEvent) {
107
- let ruleType = decision ? . source ?? Constants . DecisionSource. rollout. rawValue
108
- if shouldSendDecisionEvent ( source: ruleType, decision: decision ) {
109
- sendImpressionEvent ( experiment: decision ? . experiment,
110
- variation: decision ? . variation,
172
+ let ruleType = flagDecision ? . source ?? Constants . DecisionSource. rollout. rawValue
173
+ if shouldSendDecisionEvent ( source: ruleType, decision: flagDecision ) {
174
+ sendImpressionEvent ( experiment: flagDecision ? . experiment,
175
+ variation: flagDecision ? . variation,
111
176
userId: userId,
112
177
attributes: attributes,
113
178
flagKey: feature. key,
114
179
ruleType: ruleType,
115
- enabled: enabled )
180
+ enabled: flagEnabled )
116
181
decisionEventDispatched = true
117
182
}
118
183
}
119
184
120
185
var variableMap = [ String: Any] ( )
121
186
if !allOptions. contains ( . excludeVariables) {
122
187
let decisionResponse = getDecisionVariableMap ( feature: feature,
123
- variation: decision ? . variation,
124
- enabled: enabled )
125
- reasons . merge ( decisionResponse. reasons)
188
+ variation: flagDecision ? . variation,
189
+ enabled: flagEnabled )
190
+ decisionReasons . merge ( decisionResponse. reasons)
126
191
variableMap = decisionResponse. result ?? [ : ]
127
192
}
128
193
129
194
var optimizelyJSON : OptimizelyJSON
130
195
if let opt = OptimizelyJSON ( map: variableMap) {
131
196
optimizelyJSON = opt
132
197
} else {
133
- reasons . addError ( OptimizelyError . invalidJSONVariable)
198
+ decisionReasons . addError ( OptimizelyError . invalidJSONVariable)
134
199
optimizelyJSON = OptimizelyJSON . createEmpty ( )
135
200
}
136
201
137
- let ruleKey = decision ? . experiment? . key
138
- let reasonsToReport = reasons . toReport ( )
202
+ let ruleKey = flagDecision ? . experiment? . key
203
+ let reasonsToReport = decisionReasons . toReport ( )
139
204
140
205
sendDecisionNotification ( userId: userId,
141
206
attributes: attributes,
142
207
decisionInfo: DecisionInfo ( decisionType: . flag,
143
- experiment: decision ? . experiment,
144
- variation: decision ? . variation,
208
+ experiment: flagDecision ? . experiment,
209
+ variation: flagDecision ? . variation,
145
210
feature: feature,
146
- featureEnabled: enabled ,
211
+ featureEnabled: flagEnabled ,
147
212
variableValues: variableMap,
148
213
ruleKey: ruleKey,
149
214
reasons: reasonsToReport,
150
215
decisionEventDispatched: decisionEventDispatched) )
151
216
152
- return OptimizelyDecision ( variationKey: decision ? . variation. key,
153
- enabled: enabled ,
217
+ return OptimizelyDecision ( variationKey: flagDecision ? . variation. key,
218
+ enabled: flagEnabled ,
154
219
variables: optimizelyJSON,
155
220
ruleKey: ruleKey,
156
221
flagKey: feature. key,
157
222
userContext: user,
158
223
reasons: reasonsToReport)
159
224
}
160
225
161
- func decide( user: OptimizelyUserContext ,
162
- keys: [ String ] ,
163
- options: [ OptimizelyDecideOption ] ? = nil ) -> [ String : OptimizelyDecision ] {
164
- guard config != nil else {
165
- logger. e ( OptimizelyError . sdkNotReady)
166
- return [ : ]
167
- }
168
-
169
- guard keys. count > 0 else { return [ : ] }
170
-
171
- let allOptions = defaultDecideOptions + ( options ?? [ ] )
172
-
173
- var decisions = [ String: OptimizelyDecision] ( )
174
-
175
- let enabledFlagsOnly = allOptions. contains ( . enabledFlagsOnly)
176
- keys. forEach { key in
177
- let decision = decide ( user: user, key: key, options: options)
178
- if !enabledFlagsOnly || decision. enabled {
179
- decisions [ key] = decision
180
- }
181
- }
182
-
183
- return decisions
184
- }
226
+
227
+ // func decide(user: OptimizelyUserContext,
228
+ // keys: [String],
229
+ // options: [OptimizelyDecideOption]? = nil) -> [String: OptimizelyDecision] {
230
+ // guard config != nil else {
231
+ // logger.e(OptimizelyError.sdkNotReady)
232
+ // return [:]
233
+ // }
234
+ //
235
+ // guard keys.count > 0 else { return [:] }
236
+ //
237
+ // let allOptions = defaultDecideOptions + (options ?? [])
238
+ //
239
+ // var decisions = [String: OptimizelyDecision]()
240
+ //
241
+ // let enabledFlagsOnly = allOptions.contains(.enabledFlagsOnly)
242
+ // keys.forEach { key in
243
+ // let decision = decide(user: user, key: key, options: options)
244
+ // if !enabledFlagsOnly || decision.enabled {
245
+ // decisions[key] = decision
246
+ // }
247
+ // }
248
+ //
249
+ // return decisions
250
+ // }
185
251
186
252
func decideAll( user: OptimizelyUserContext ,
187
253
options: [ OptimizelyDecideOption ] ? = nil ) -> [ String : OptimizelyDecision ] {
0 commit comments