Skip to content

Commit 9e493fd

Browse files
WIP: decide method updated
1 parent 541b9f5 commit 9e493fd

File tree

1 file changed

+136
-70
lines changed

1 file changed

+136
-70
lines changed

Sources/Optimizely+Decide/OptimizelyClient+Decide.swift

Lines changed: 136 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)