@@ -62,126 +62,192 @@ extension OptimizelyClient {
6262 key: String ,
6363 options: [ OptimizelyDecideOption ] ? = nil ) -> OptimizelyDecision {
6464
65- guard let config = self . config else {
65+ guard config != nil else {
6666 return OptimizelyDecision . errorDecision ( key: key, user: user, error: . sdkNotReady)
6767 }
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] ( )
6890
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+ }
71115 }
72116
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)
79118
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+ }
81133
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+ }
83148
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 {
88158
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) )
104161 }
105162
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+
106171 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,
111176 userId: userId,
112177 attributes: attributes,
113178 flagKey: feature. key,
114179 ruleType: ruleType,
115- enabled: enabled )
180+ enabled: flagEnabled )
116181 decisionEventDispatched = true
117182 }
118183 }
119184
120185 var variableMap = [ String: Any] ( )
121186 if !allOptions. contains ( . excludeVariables) {
122187 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)
126191 variableMap = decisionResponse. result ?? [ : ]
127192 }
128193
129194 var optimizelyJSON : OptimizelyJSON
130195 if let opt = OptimizelyJSON ( map: variableMap) {
131196 optimizelyJSON = opt
132197 } else {
133- reasons . addError ( OptimizelyError . invalidJSONVariable)
198+ decisionReasons . addError ( OptimizelyError . invalidJSONVariable)
134199 optimizelyJSON = OptimizelyJSON . createEmpty ( )
135200 }
136201
137- let ruleKey = decision ? . experiment? . key
138- let reasonsToReport = reasons . toReport ( )
202+ let ruleKey = flagDecision ? . experiment? . key
203+ let reasonsToReport = decisionReasons . toReport ( )
139204
140205 sendDecisionNotification ( userId: userId,
141206 attributes: attributes,
142207 decisionInfo: DecisionInfo ( decisionType: . flag,
143- experiment: decision ? . experiment,
144- variation: decision ? . variation,
208+ experiment: flagDecision ? . experiment,
209+ variation: flagDecision ? . variation,
145210 feature: feature,
146- featureEnabled: enabled ,
211+ featureEnabled: flagEnabled ,
147212 variableValues: variableMap,
148213 ruleKey: ruleKey,
149214 reasons: reasonsToReport,
150215 decisionEventDispatched: decisionEventDispatched) )
151216
152- return OptimizelyDecision ( variationKey: decision ? . variation. key,
153- enabled: enabled ,
217+ return OptimizelyDecision ( variationKey: flagDecision ? . variation. key,
218+ enabled: flagEnabled ,
154219 variables: optimizelyJSON,
155220 ruleKey: ruleKey,
156221 flagKey: feature. key,
157222 userContext: user,
158223 reasons: reasonsToReport)
159224 }
160225
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+ // }
185251
186252 func decideAll( user: OptimizelyUserContext ,
187253 options: [ OptimizelyDecideOption ] ? = nil ) -> [ String : OptimizelyDecision ] {
0 commit comments