Skip to content

Commit fd6535a

Browse files
wip: update flag to holdout mapping approach
1 parent c694a57 commit fd6535a

File tree

3 files changed

+42
-40
lines changed

3 files changed

+42
-40
lines changed

Sources/Data Model/FeatureFlag.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct FeatureFlag: Codable, Equatable, OptimizelyFeature {
3535
case variables
3636
}
3737

38-
var holdoutIds: [String] = []
38+
// var holdoutIds: [String] = []
3939

4040
// MARK: - OptimizelyConfig
4141

Sources/Data Model/ProjectConfig.swift

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,9 @@
1717
import Foundation
1818

1919
class ProjectConfig {
20-
private var isUpdating = false // Flag to prevent recursion
21-
2220
var project: Project! {
2321
didSet {
24-
if !isUpdating {
25-
updateProjectDependentProps()
26-
}
22+
updateProjectDependentProps()
2723
}
2824
}
2925

@@ -45,6 +41,7 @@ class ProjectConfig {
4541
var flagVariationsMap = [String: [Variation]]()
4642
var allSegments = [String]()
4743
var holdoutIdMap = [String: Holdout]()
44+
var flagHoldoutsMap: [String: [String]] = [:]
4845

4946
// MARK: - Init
5047

@@ -71,21 +68,18 @@ class ProjectConfig {
7168
init() {}
7269

7370
func updateProjectDependentProps() {
74-
isUpdating = true
75-
defer { isUpdating = false }
7671

7772
self.allExperiments = project.experiments + project.groups.map { $0.experiments }.flatMap { $0 }
7873

74+
// Reset flag holdouts mapping with the change of datafile
75+
flagHoldoutsMap = [:]
76+
7977
holdoutIdMap = {
8078
var map = [String: Holdout]()
8179
project.holdouts.forEach { map[$0.id] = $0 }
8280
return map
8381
}()
8482

85-
if !project.holdouts.isEmpty {
86-
assignHoldoutIdsToFeatureFlags()
87-
}
88-
8983
self.experimentKeyMap = {
9084
var map = [String: Experiment]()
9185
allExperiments.forEach { exp in
@@ -173,32 +167,40 @@ class ProjectConfig {
173167

174168
}
175169

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) {
183193
holdoutIds.append(holdout.id)
184194
}
185-
} else if !holdout.excludedFlags.isEmpty {
186-
if !holdout.excludedFlags.contains(flag.id) {
195+
196+
case (_, false):
197+
if !holdout.excludedFlags.contains(id) {
187198
holdoutIds.append(holdout.id)
188199
}
189-
} else {
190-
// Global holdout
191-
holdoutIds.append(holdout.id)
192-
}
193200
}
194-
195-
/// Update holdoutIds for the flag
196-
updatedFlag.holdoutIds = holdoutIds
197-
return updatedFlag
198201
}
199202

200-
// Update project featureFlags after mapping with holdoutIds
201-
project.featureFlags = flagsWithHoldoutIds
203+
flagHoldoutsMap[id] = holdoutIds
202204
}
203205

204206
func getAllRulesForFlag(_ flag: FeatureFlag) -> [Experiment] {

Tests/OptimizelyTests-DataModel/ProjectConfigTests.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,15 @@ class ProjectConfigTests: XCTestCase {
160160

161161
let featureFlagKeyMap = projectConfig.featureFlagKeyMap
162162

163-
/// Test Global holdout + included
164-
XCTAssertEqual(featureFlagKeyMap["key_2000"]?.holdoutIds, ["3000", "3001", "3002", "3003", "3004"])
165-
XCTAssertEqual(featureFlagKeyMap["key_2002"]?.holdoutIds, ["3000", "3001", "3002", "3003", "3004"])
166-
167-
/// Test Global holdout - excluded
168-
XCTAssertEqual(featureFlagKeyMap["key_2001"]?.holdoutIds, ["3000", "3001", "3002"])
169-
170-
/// Test Global holdout
171-
XCTAssertEqual(featureFlagKeyMap["key_2003"]?.holdoutIds, ["3000", "3001", "3002", "3004"])
163+
// /// Test Global holdout + included
164+
// XCTAssertEqual(featureFlagKeyMap["key_2000"]?.holdoutIds, ["3000", "3001", "3002", "3003", "3004"])
165+
// XCTAssertEqual(featureFlagKeyMap["key_2002"]?.holdoutIds, ["3000", "3001", "3002", "3003", "3004"])
166+
//
167+
// /// Test Global holdout - excluded
168+
// XCTAssertEqual(featureFlagKeyMap["key_2001"]?.holdoutIds, ["3000", "3001", "3002"])
169+
//
170+
// /// Test Global holdout
171+
// XCTAssertEqual(featureFlagKeyMap["key_2003"]?.holdoutIds, ["3000", "3001", "3002", "3004"])
172172
}
173173

174174
func testFlagVariations() {

0 commit comments

Comments
 (0)