17
17
import Foundation
18
18
19
19
class ProjectConfig {
20
- private var isUpdating = false // Flag to prevent recursion
21
-
22
20
var project : Project ! {
23
21
didSet {
24
- if !isUpdating {
25
- updateProjectDependentProps ( )
26
- }
22
+ updateProjectDependentProps ( )
27
23
}
28
24
}
29
25
@@ -45,6 +41,7 @@ class ProjectConfig {
45
41
var flagVariationsMap = [ String: [ Variation] ] ( )
46
42
var allSegments = [ String] ( )
47
43
var holdoutIdMap = [ String: Holdout] ( )
44
+ var flagHoldoutsMap : [ String : [ String ] ] = [ : ]
48
45
49
46
// MARK: - Init
50
47
@@ -71,21 +68,18 @@ class ProjectConfig {
71
68
init ( ) { }
72
69
73
70
func updateProjectDependentProps( ) {
74
- isUpdating = true
75
- defer { isUpdating = false }
76
71
77
72
self . allExperiments = project. experiments + project. groups. map { $0. experiments } . flatMap { $0 }
78
73
74
+ // Reset flag holdouts mapping with the change of datafile
75
+ flagHoldoutsMap = [ : ]
76
+
79
77
holdoutIdMap = {
80
78
var map = [ String: Holdout] ( )
81
79
project. holdouts. forEach { map [ $0. id] = $0 }
82
80
return map
83
81
} ( )
84
82
85
- if !project. holdouts. isEmpty {
86
- assignHoldoutIdsToFeatureFlags ( )
87
- }
88
-
89
83
self . experimentKeyMap = {
90
84
var map = [ String: Experiment] ( )
91
85
allExperiments. forEach { exp in
@@ -173,32 +167,40 @@ class ProjectConfig {
173
167
174
168
}
175
169
176
- private func assignHoldoutIdsToFeatureFlags( ) {
177
- let flagsWithHoldoutIds = project. featureFlags. map { flag -> FeatureFlag in
178
- var updatedFlag = flag
179
- var holdoutIds = [ String] ( )
180
- for holdout in project. holdouts {
181
- if !holdout. includedFlags. isEmpty {
182
- if holdout. includedFlags. contains ( flag. id) {
170
+ func getHoldoutIdsForFlag( id: String ) -> [ String ] {
171
+ guard !project. holdouts. isEmpty else { return [ ] }
172
+
173
+ if let holdoutIds = flagHoldoutsMap [ id] {
174
+ return holdoutIds
175
+ }
176
+
177
+ updateHoldoutsMapForFlag ( id: id)
178
+
179
+ return flagHoldoutsMap [ id] ?? [ ]
180
+ }
181
+
182
+ private func updateHoldoutsMapForFlag( id: String ) {
183
+ var holdoutIds = [ String] ( )
184
+
185
+ for holdout in project. holdouts {
186
+ switch ( holdout. includedFlags. isEmpty, holdout. excludedFlags. isEmpty) {
187
+ case ( true , true ) :
188
+ // Global holdout
189
+ holdoutIds. append ( holdout. id)
190
+
191
+ case ( false , _) :
192
+ if holdout. includedFlags. contains ( id) {
183
193
holdoutIds. append ( holdout. id)
184
194
}
185
- } else if !holdout. excludedFlags. isEmpty {
186
- if !holdout. excludedFlags. contains ( flag. id) {
195
+
196
+ case ( _, false ) :
197
+ if !holdout. excludedFlags. contains ( id) {
187
198
holdoutIds. append ( holdout. id)
188
199
}
189
- } else {
190
- // Global holdout
191
- holdoutIds. append ( holdout. id)
192
- }
193
200
}
194
-
195
- /// Update holdoutIds for the flag
196
- updatedFlag. holdoutIds = holdoutIds
197
- return updatedFlag
198
201
}
199
202
200
- // Update project featureFlags after mapping with holdoutIds
201
- project. featureFlags = flagsWithHoldoutIds
203
+ flagHoldoutsMap [ id] = holdoutIds
202
204
}
203
205
204
206
func getAllRulesForFlag( _ flag: FeatureFlag ) -> [ Experiment ] {
0 commit comments