1616
1717import Foundation
1818
19- struct Audience : Codable , Equatable {
19+ struct Audience : Codable , Equatable , OptimizelyAudience {
2020 var id : String
2121 var name : String
22- var conditions : ConditionHolder
23-
22+ var conditionHolder : ConditionHolder
23+ var conditions : String // string representation for OptimizelyConfig
24+
2425 enum CodingKeys : String , CodingKey {
2526 case id
2627 case name
@@ -32,38 +33,45 @@ struct Audience: Codable, Equatable {
3233
3334 self . id = try container. decode ( String . self, forKey: . id)
3435 self . name = try container. decode ( String . self, forKey: . name)
36+
37+ let hint = " id: \( self . id) , name: \( self . name) "
38+ let decodeError = DecodingError . dataCorrupted (
39+ DecodingError . Context ( codingPath: container. codingPath,
40+ debugDescription: " Failed to decode Audience Condition ( \( hint) ) " ) )
3541
3642 if let value = try ? container. decode ( String . self, forKey: . conditions) {
37-
3843 // legacy stringified conditions
3944 // - "[\"or\",{\"value\":30,\"type\":\"custom_attribute\",\"match\":\"exact\",\"name\":\"geo\"}]"
4045 // decode it to recover to formatted CondtionHolder type
4146
42- let data = value. data ( using: . utf8)
43- self . conditions = try JSONDecoder ( ) . decode ( ConditionHolder . self, from: data!)
44-
45- } else if let value = try ? container. decode ( ConditionHolder . self, forKey: . conditions) {
46-
47- // typedAudience formats
48- // [TODO] Tom: check if this is correct
49- // NOTE: UserAttribute (not in array) at the top-level is allowed
50-
47+ guard let data = value. data ( using: . utf8) else { throw decodeError }
48+
49+ self . conditionHolder = try JSONDecoder ( ) . decode ( ConditionHolder . self, from: data)
5150 self . conditions = value
52-
51+ } else if let value = try ? container. decode ( ConditionHolder . self, forKey: . conditions) {
52+ self . conditionHolder = value
53+
54+ // sort by keys to compare strings in tests
55+ let sortEncoder = JSONEncoder ( )
56+ if #available( iOS 11 . 0 , tvOS 11 . 0 , watchOS 4 . 0 , * ) {
57+ sortEncoder. outputFormatting = . sortedKeys
58+ }
59+ let data = try sortEncoder. encode ( value)
60+ self . conditions = String ( bytes: data, encoding: . utf8) ?? " "
5361 } else {
54- let hint = " id: \( self . id) , name: \( self . name) "
55- throw DecodingError . dataCorrupted ( DecodingError . Context ( codingPath: container. codingPath, debugDescription: " Failed to decode Audience Condition ( \( hint) ) " ) )
62+ throw decodeError
5663 }
5764 }
5865
5966 func encode( to encoder: Encoder ) throws {
6067 var container = encoder. container ( keyedBy: CodingKeys . self)
6168 try container. encode ( id, forKey: . id)
6269 try container. encode ( name, forKey: . name)
63- try container. encode ( conditions , forKey: . conditions)
70+ try container. encode ( conditionHolder , forKey: . conditions)
6471 }
6572
6673 func evaluate( project: ProjectProtocol ? , attributes: OptimizelyAttributes ? ) throws -> Bool {
67- return try conditions . evaluate ( project: project, attributes: attributes)
74+ return try conditionHolder . evaluate ( project: project, attributes: attributes)
6875 }
76+
6977}
0 commit comments