Skip to content

Commit 259ece0

Browse files
arafay-folio3mikeproeng37
authored andcommitted
feat(api): Accepting all types for attributes values (#309)
1 parent ce6676c commit 259ece0

22 files changed

+288
-117
lines changed

OptimizelySDKCore/OptimizelySDKCore/OPTLYAudience.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ - (void)setConditionsWithNSString:(NSString *)string {
4646
}
4747
}
4848

49-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)attributes {
49+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes {
5050
for (NSObject<OPTLYCondition> *condition in self.conditions) {
5151
if ([condition evaluateConditionsWithAttributes:attributes]) {
5252
// if user satisfies any conditions, return true.

OptimizelySDKCore/OptimizelySDKCore/OPTLYBaseCondition.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
/// Condition type
3232
@property (nonatomic, strong) NSString *type;
3333
/// Condition value
34-
@property (nonatomic, strong) NSString *value;
34+
@property (nonatomic, strong) NSObject *value;
3535

3636
+(BOOL)isBaseConditionJSON:(NSData *)jsonData;
3737

OptimizelySDKCore/OptimizelySDKCore/OPTLYBaseCondition.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ + (BOOL) isBaseConditionJSON:(NSData *)jsonData {
3535
}
3636
}
3737

38-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)attributes {
38+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes {
3939
if (attributes == nil) {
4040
// if the user did not pass in attributes, return false
4141
return false;
4242
}
4343
else {
44-
// check user attribute value for the condition against our condition value
45-
return [self.value isEqualToString:attributes[self.name]];
44+
// check user attribute value for the condition against our condition value
45+
return [self.value isEqual:attributes[self.name]];
4646
}
4747
}
4848

OptimizelySDKCore/OptimizelySDKCore/OPTLYCondition.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
/**
2222
* Evaluate the condition against the user attributes.
2323
*/
24-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSString *> *)attributes;
24+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes;
2525

2626
@end
2727

OptimizelySDKCore/OptimizelySDKCore/OPTLYCondition.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ @implementation OPTLYCondition
115115

116116
@implementation OPTLYAndCondition
117117

118-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)attributes {
118+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes {
119119
for (NSObject<OPTLYCondition> *condition in self.subConditions) {
120120
// if any of our sub conditions are false
121121
if (![condition evaluateConditionsWithAttributes:attributes]) {
@@ -131,7 +131,7 @@ - (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)
131131

132132
@implementation OPTLYOrCondition
133133

134-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)attributes {
134+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes {
135135
for (NSObject<OPTLYCondition> *condition in self.subConditions) {
136136
// if any of our sub conditions are true
137137
if ([condition evaluateConditionsWithAttributes:attributes]) {
@@ -147,7 +147,7 @@ - (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)
147147

148148
@implementation OPTLYNotCondition
149149

150-
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *,NSString *> *)attributes {
150+
- (BOOL)evaluateConditionsWithAttributes:(NSDictionary<NSString *, NSObject *> *)attributes {
151151
// return the negative of the subcondition
152152
return ![self.subCondition evaluateConditionsWithAttributes:attributes];
153153
}

OptimizelySDKCore/OptimizelySDKCore/OPTLYDecisionService.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
*/
5555
- (nullable OPTLYVariation *)getVariation:(nonnull NSString *)userId
5656
experiment:(nonnull OPTLYExperiment *)experiment
57-
attributes:(nullable NSDictionary *)attributes;
57+
attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes;
5858

5959
/**
6060
* Get a variation the user is bucketed into for the given FeatureFlag
@@ -65,6 +65,6 @@
6565
*/
6666
- (nullable OPTLYFeatureDecision *)getVariationForFeature:(nonnull OPTLYFeatureFlag *)featureFlag
6767
userId:(nonnull NSString *)userId
68-
attributes:(nullable NSDictionary *)attributes;
68+
attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes;
6969

7070
@end

OptimizelySDKCore/OptimizelySDKCore/OPTLYDecisionService.m

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ - (instancetype) initWithProjectConfig:(OPTLYProjectConfig *)config
5252

5353
- (OPTLYVariation *)getVariation:(NSString *)userId
5454
experiment:(OPTLYExperiment *)experiment
55-
attributes:(NSDictionary *)attributes
55+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes
5656
{
5757
NSDictionary *userProfileDict = nil;
5858
OPTLYVariation *bucketedVariation = nil;
@@ -125,7 +125,7 @@ - (OPTLYVariation *)getVariation:(NSString *)userId
125125

126126
- (OPTLYFeatureDecision *)getVariationForFeature:(OPTLYFeatureFlag *)featureFlag
127127
userId:(NSString *)userId
128-
attributes:(NSDictionary *)attributes {
128+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
129129

130130
//Evaluate in this order:
131131

@@ -157,7 +157,7 @@ - (OPTLYFeatureDecision *)getVariationForFeature:(OPTLYFeatureFlag *)featureFlag
157157
# pragma mark - Helper Methods
158158

159159
- (NSString *)getBucketingId:(NSString *)userId
160-
attributes:(NSDictionary *)attributes {
160+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
161161

162162
// By default, the bucketing ID should be the user ID .
163163
NSString *bucketingId = userId;
@@ -189,7 +189,7 @@ - (OPTLYExperiment *)getExperimentInGroup:(OPTLYGroup *)group bucketingId:(NSStr
189189
- (OPTLYFeatureDecision *)getVariationForFeatureGroup:(OPTLYFeatureFlag *)featureFlag
190190
groupId:(NSString *)groupId
191191
userId:(NSString *)userId
192-
attributes:(NSDictionary *)attributes {
192+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
193193

194194
OPTLYFeatureDecision *decision = nil;
195195
NSString *logMessage = nil;
@@ -225,7 +225,7 @@ - (OPTLYFeatureDecision *)getVariationForFeatureGroup:(OPTLYFeatureFlag *)featur
225225

226226
- (OPTLYFeatureDecision *)getVariationForFeatureExperiment:(OPTLYFeatureFlag *)featureFlag
227227
userId:(NSString *)userId
228-
attributes:(NSDictionary *)attributes {
228+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
229229

230230
NSString *featureFlagKey = featureFlag.key;
231231
NSArray *experimentIds = featureFlag.experimentIds;
@@ -261,7 +261,7 @@ - (OPTLYFeatureDecision *)getVariationForFeatureExperiment:(OPTLYFeatureFlag *)f
261261

262262
- (OPTLYFeatureDecision *)getVariationForFeatureRollout:(OPTLYFeatureFlag *)featureFlag
263263
userId:(NSString *)userId
264-
attributes:(NSDictionary *)attributes {
264+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
265265

266266
NSString *bucketing_id = [self getBucketingId:userId attributes:attributes];
267267
NSString *featureFlagKey = featureFlag.key;
@@ -447,7 +447,7 @@ - (NSString *)getVariationIdFromUserProfile:(NSDictionary *)userProfileDict
447447
- (BOOL)userPassesTargeting:(OPTLYProjectConfig *)config
448448
experiment:(OPTLYExperiment *)experiment
449449
userId:(NSString *)userId
450-
attributes:(NSDictionary *)attributes
450+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes
451451
{
452452
// check if the user is in the experiment
453453
BOOL isUserInExperiment = [self isUserInExperiment:config experiment:experiment attributes:attributes];
@@ -476,7 +476,7 @@ - (BOOL)isExperimentActive:(OPTLYProjectConfig *)config
476476

477477
- (BOOL)isUserInExperiment:(OPTLYProjectConfig *)config
478478
experiment:(OPTLYExperiment *)experiment
479-
attributes:(NSDictionary *)attributes
479+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes
480480
{
481481
NSArray *audiences = experiment.audienceIds;
482482

OptimizelySDKCore/OptimizelySDKCore/OPTLYEventBuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_END
4343
- (nullable NSDictionary *)buildImpressionEventForUser:(nonnull NSString *)userId
4444
experiment:(nonnull OPTLYExperiment *)experiment
4545
variation:(nonnull OPTLYVariation *)variation
46-
attributes:(nullable NSDictionary<NSString *, NSString *> *)attributes;
46+
attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes;
4747

4848
/**
4949
* Create the parameters for a conversion event.
@@ -59,7 +59,7 @@ NS_ASSUME_NONNULL_END
5959
event:(nonnull OPTLYEvent *)event
6060
decisions:(nonnull NSArray<NSDictionary *> *)decisions
6161
eventTags:(nullable NSDictionary *)eventTags
62-
attributes:(nullable NSDictionary<NSString *, NSString *> *)attributes;
62+
attributes:(nullable NSDictionary<NSString *, NSObject *> *)attributes;
6363
@end
6464

6565
@interface OPTLYEventBuilderDefault : NSObject<OPTLYEventBuilder>

OptimizelySDKCore/OptimizelySDKCore/OPTLYEventBuilder.m

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ -(instancetype)initWithConfig:(OPTLYProjectConfig *)config {
5555
-(NSDictionary *)buildImpressionEventForUser:(NSString *)userId
5656
experiment:(OPTLYExperiment *)experiment
5757
variation:(OPTLYVariation *)variation
58-
attributes:(NSDictionary<NSString *,NSString *> *)attributes {
58+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
5959
if (!self.config) {
6060
return nil;
6161
}
@@ -71,7 +71,7 @@ -(NSDictionary *)buildConversionEventForUser:(NSString *)userId
7171
event:(OPTLYEvent *)event
7272
decisions:(NSArray<NSDictionary *> *)decisions
7373
eventTags:(NSDictionary *)eventTags
74-
attributes:(NSDictionary<NSString *,NSString *> *)attributes {
74+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
7575

7676
if (!self.config) {
7777
return nil;
@@ -87,7 +87,7 @@ -(NSDictionary *)buildConversionEventForUser:(NSString *)userId
8787
}
8888

8989
- (NSDictionary *)createCommonParamsForUser:(NSString *)userId
90-
attributes:(NSDictionary<NSString *, NSString *> *)attributes {
90+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
9191
NSMutableDictionary *commonParams = [NSMutableDictionary new];
9292

9393
NSMutableDictionary *visitor = [NSMutableDictionary new];
@@ -199,15 +199,15 @@ - (NSDictionary *)filterEventTags:(NSDictionary *)eventTags {
199199
}
200200

201201
- (NSArray *)createUserFeatures:(OPTLYProjectConfig *)config
202-
attributes:(NSDictionary *)attributes {
202+
attributes:(NSDictionary<NSString *, NSObject *> *)attributes {
203203

204204
NSNumber *botFiltering = config.botFiltering;
205205
NSMutableArray *features = [NSMutableArray new];
206206
NSArray *attributeKeys = [attributes allKeys];
207207

208208
for (NSString *attributeKey in attributeKeys) {
209-
NSString *attributeValue = attributes[attributeKey];
210-
if ([OPTLYEventBuilderDefault isEmptyString:attributeValue]) {
209+
NSObject *attributeValue = attributes[attributeKey];
210+
if (![OPTLYEventBuilderDefault isValidAttributeValue:attributeValue]) {
211211
NSString *logMessage = [NSString stringWithFormat:OPTLYLoggerMessagesAttributeValueInvalidFormat, attributeKey];
212212
[config.logger logMessage:logMessage withLevel:OptimizelyLogLevelDebug];
213213
continue;
@@ -252,10 +252,43 @@ + (NSString *)stringOrEmpty:(NSString *)str {
252252
return string;
253253
}
254254

255-
+ (BOOL)isEmptyString:(NSString*)str {
256-
return (str == nil
257-
|| [str isKindOfClass:[NSNull class]]
258-
|| [str length] == 0);
255+
+ (BOOL)isEmptyString:(NSObject *)str {
256+
return (!str
257+
|| ![str isKindOfClass:[NSString class]]
258+
|| [(NSString *)str isEqualToString:@""]);
259+
}
260+
261+
+ (BOOL)isValidAttributeValue:(NSObject *)value {
262+
// check value is NSObject
263+
if (!value || [value isEqual:[NSNull null]]) {
264+
return false;
265+
}
266+
// check value is NSString
267+
if ([value isKindOfClass:[NSString class]]) {
268+
return true;
269+
}
270+
NSNumber *number = (NSNumber *)value;
271+
// check value is NSNumber
272+
if (number && [number isKindOfClass:[NSNumber class]]) {
273+
const char *objCType = [number objCType];
274+
// check NSNumber is of type int, double, bool
275+
return (strcmp(objCType, @encode(short)) == 0)
276+
|| (strcmp(objCType, @encode(unsigned short)) == 0)
277+
|| (strcmp(objCType, @encode(int)) == 0)
278+
|| (strcmp(objCType, @encode(unsigned int)) == 0)
279+
|| (strcmp(objCType, @encode(long)) == 0)
280+
|| (strcmp(objCType, @encode(unsigned long)) == 0)
281+
|| (strcmp(objCType, @encode(long long)) == 0)
282+
|| (strcmp(objCType, @encode(unsigned long long)) == 0)
283+
|| (strcmp(objCType, @encode(float)) == 0)
284+
|| (strcmp(objCType, @encode(double)) == 0)
285+
|| (strcmp(objCType, @encode(char)) == 0)
286+
|| (strcmp(objCType, @encode(unsigned char)) == 0)
287+
|| (strcmp(objCType, @encode(bool)) == 0)
288+
|| [number isEqual:@YES]
289+
|| [number isEqual:@NO];
290+
}
291+
return false;
259292
}
260293

261294
@end

OptimizelySDKCore/OptimizelySDKCore/OPTLYNotificationCenter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ typedef NS_ENUM(NSUInteger, OPTLYNotificationType) {
2626

2727
typedef void (^ActivateListener)(OPTLYExperiment * _Nonnull experiment,
2828
NSString * _Nonnull userId,
29-
NSDictionary<NSString *,NSString *> * _Nonnull attributes,
29+
NSDictionary<NSString *, NSObject *> * _Nonnull attributes,
3030
OPTLYVariation * _Nonnull variation,
3131
NSDictionary<NSString *,NSObject *> * _Nonnull event);
3232

3333
typedef void (^TrackListener)(NSString * _Nonnull eventKey,
3434
NSString * _Nonnull userId,
35-
NSDictionary<NSString *,NSString *> * _Nonnull attributes,
35+
NSDictionary<NSString *, NSObject *> * _Nonnull attributes,
3636
NSDictionary * _Nonnull eventTags,
3737
NSDictionary<NSString *,NSObject *> * _Nonnull event);
3838

0 commit comments

Comments
 (0)