Skip to content

Commit b2a5de1

Browse files
authored
Added dynamic typed (#16)
* added dynamic typed * fixed import and scope of function * removed assignment test file from git * fixed test cases * fixed object type * also set the string value in case of JsonNode type * fixed numeric type and test cases
1 parent 09dab29 commit b2a5de1

File tree

13 files changed

+258
-52
lines changed

13 files changed

+258
-52
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
target/
33
out/
44
src/test/resources/assignment-v2
5-
src/test/resources/rac-experiments-v2.json
5+
src/test/resources/rac-experiments-v*.json

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ testDataDir := src/test/resources/
3434
test-data:
3535
rm -rf $(testDataDir)
3636
mkdir -p $(testDataDir)
37-
gsutil cp gs://sdk-test-data/rac-experiments-v2.json $(testDataDir)
37+
gsutil cp gs://sdk-test-data/rac-experiments-v3.json $(testDataDir)
3838
gsutil cp -r gs://sdk-test-data/assignment-v2 $(testDataDir)
3939

4040
.PHONY: test

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>cloud.eppo</groupId>
88
<artifactId>eppo-server-sdk</artifactId>
9-
<version>1.2.1</version>
9+
<version>2.0.0</version>
1010

1111
<name>${project.groupId}:${project.artifactId}</name>
1212
<description>Eppo Server-Side SDK for Java</description>

src/main/java/com/eppo/sdk/EppoClient.java

Lines changed: 119 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.eppo.sdk.dto.AssignmentLogData;
66
import com.eppo.sdk.dto.EppoClientConfig;
77
import com.eppo.sdk.dto.EppoValue;
8+
import com.eppo.sdk.dto.EppoValueType;
89
import com.eppo.sdk.dto.ExperimentConfiguration;
910
import com.eppo.sdk.dto.Rule;
1011
import com.eppo.sdk.dto.SubjectAttributes;
@@ -55,7 +56,7 @@ private EppoClient(ConfigurationStore configurationStore, Timer poller, EppoClie
5556
* @param subjectAttributes
5657
* @return
5758
*/
58-
public Optional<String> getAssignment(
59+
private Optional<EppoValue> getAssignment(
5960
String subjectKey,
6061
String flagKey,
6162
SubjectAttributes subjectAttributes
@@ -74,7 +75,7 @@ public Optional<String> getAssignment(
7475
// Check if subject has override variations
7576
EppoValue subjectVariationOverride = this.getSubjectVariationOverride(subjectKey, configuration);
7677
if (!subjectVariationOverride.isNull()) {
77-
return Optional.of(subjectVariationOverride.stringValue());
78+
return Optional.of(subjectVariationOverride);
7879
}
7980

8081
// Check if disabled
@@ -104,14 +105,14 @@ public Optional<String> getAssignment(
104105
this.eppoClientConfig.getAssignmentLogger()
105106
.logAssignment(new AssignmentLogData(
106107
flagKey,
107-
assignedVariation.getValue().stringValue(),
108+
assignedVariation.getTypedValue().stringValue(),
108109
subjectKey,
109110
subjectAttributes
110111
));
111112
} catch (Exception e){
112113
// Ignore Exception
113114
}
114-
return Optional.of(assignedVariation.getValue().stringValue());
115+
return Optional.of(assignedVariation.getTypedValue());
115116
}
116117

117118
/**
@@ -121,16 +122,125 @@ public Optional<String> getAssignment(
121122
* @param experimentKey
122123
* @return
123124
*/
124-
public Optional<String> getAssignment(String subjectKey, String experimentKey) {
125+
private Optional<EppoValue> getAssignment(String subjectKey, String experimentKey) {
125126
return this.getAssignment(subjectKey, experimentKey, new SubjectAttributes());
126127
}
127128

129+
/**
130+
* This function will return typed assignment value
131+
* @param subjectKey
132+
* @param experimentKey
133+
* @param type
134+
* @param subjectAttributes
135+
* @return
136+
*/
137+
private Optional<?> getTypedAssignment(String subjectKey, String experimentKey, EppoValueType type, SubjectAttributes subjectAttributes) {
138+
Optional<EppoValue> value = this.getAssignment(subjectKey, experimentKey, subjectAttributes);
139+
if (value.isEmpty()) {
140+
return Optional.empty();
141+
}
142+
143+
switch (type) {
144+
case BOOLEAN:
145+
return Optional.of(value.get().boolValue());
146+
case NUMBER:
147+
return Optional.of(value.get().doubleValue());
148+
default:
149+
return Optional.of(value.get().stringValue());
150+
}
151+
}
152+
153+
/**
154+
* This function will return string assignment value
155+
* @param subjectKey
156+
* @param experimentKey
157+
* @param subjectAttributes
158+
* @return
159+
*/
160+
public Optional<String> getStringAssignment(String subjectKey, String experimentKey, SubjectAttributes subjectAttributes) {
161+
return (Optional<String>) this.getTypedAssignment(subjectKey, experimentKey, EppoValueType.STRING, subjectAttributes);
162+
}
163+
164+
/**
165+
* This function will return string assignment value without passing subjectAttributes
166+
* @param subjectKey
167+
* @param experimentKey
168+
* @return
169+
*/
170+
public Optional<String> getStringAssignment(String subjectKey, String experimentKey) {
171+
return this.getStringAssignment(subjectKey, experimentKey, new SubjectAttributes());
172+
}
173+
174+
/**
175+
* This function will return boolean assignment value
176+
* @param subjectKey
177+
* @param experimentKey
178+
* @param subjectAttributes
179+
* @return
180+
*/
181+
public Optional<Boolean> getBooleanAssignment(String subjectKey, String experimentKey, SubjectAttributes subjectAttributes) {
182+
return (Optional<Boolean>) this.getTypedAssignment(subjectKey, experimentKey, EppoValueType.BOOLEAN, subjectAttributes);
183+
}
184+
185+
/**
186+
* This function will return boolean assignment value without passing subjectAttributes
187+
* @param subjectKey
188+
* @param experimentKey
189+
* @return
190+
*/
191+
public Optional<Boolean> getBooleanAssignment(String subjectKey, String experimentKey) {
192+
return this.getBooleanAssignment(subjectKey, experimentKey, new SubjectAttributes());
193+
}
194+
195+
/**
196+
* This function will return double assignment value
197+
* @param subjectKey
198+
* @param experimentKey
199+
* @param subjectAttributes
200+
* @return
201+
*/
202+
public Optional<Double> getDoubleAssignment(String subjectKey, String experimentKey, SubjectAttributes subjectAttributes) {
203+
return (Optional<Double>) this.getTypedAssignment(subjectKey, experimentKey, EppoValueType.NUMBER, subjectAttributes);
204+
}
205+
206+
/**
207+
* This function will return long assignment value without passing subjectAttributes
208+
* @param subjectKey
209+
* @param experimentKey
210+
* @return
211+
*/
212+
public Optional<Double> getDoubleAssignment(String subjectKey, String experimentKey) {
213+
return this.getDoubleAssignment(subjectKey, experimentKey, new SubjectAttributes());
214+
}
215+
216+
/**
217+
* This function will return json string assignment value
218+
* @param subjectKey
219+
* @param experimentKey
220+
* @param subjectAttributes
221+
* @return
222+
*/
223+
public Optional<String> getJSONAssignment(String subjectKey, String experimentKey, SubjectAttributes subjectAttributes) {
224+
return this.getStringAssignment(subjectKey, experimentKey, subjectAttributes);
225+
}
226+
227+
/**
228+
* This function will return json string assignment value without passing subjectAttributes
229+
* @param subjectKey
230+
* @param experimentKey
231+
* @return
232+
*/
233+
public Optional<String> getJSONAssignment(String subjectKey, String experimentKey) {
234+
return this.getJSONAssignment(subjectKey, experimentKey, new SubjectAttributes());
235+
}
236+
128237
/**
129238
* This function is used to check if the Experiment is in the same
130239
*
131240
* @param subjectKey
132241
* @param experimentKey
133-
* @param experimentConfiguration
242+
* @param subjectShards
243+
* @param percentageExposure
134244
* @return
135245
*/
136246
private boolean isInExperimentSample(
@@ -148,7 +258,8 @@ private boolean isInExperimentSample(
148258
*
149259
* @param subjectKey
150260
* @param experimentKey
151-
* @param experimentConfiguration
261+
* @param subjectShards
262+
* @param subjectShards
152263
* @return
153264
*/
154265
private Variation getAssignedVariation(
@@ -178,7 +289,7 @@ private EppoValue getSubjectVariationOverride(
178289
ExperimentConfiguration experimentConfiguration
179290
) {
180291
String hexedSubjectKey = Shard.getHex(subjectKey);
181-
return experimentConfiguration.getOverrides().getOrDefault(hexedSubjectKey, new EppoValue());
292+
return experimentConfiguration.getTypedOverrides().getOrDefault(hexedSubjectKey, new EppoValue());
182293
}
183294

184295
/***

src/main/java/com/eppo/sdk/deserializer/EppoValueDeserializer.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,16 @@ private EppoValue parseEppoValue(JsonNode node) {
7272
}
7373
return EppoValue.valueOf(array);
7474
case NUMBER:
75-
return EppoValue.valueOf(node.asLong());
75+
return EppoValue.valueOf(node.asDouble());
7676
case STRING:
7777
return EppoValue.valueOf(node.asText());
7878
case BOOLEAN:
7979
return EppoValue.valueOf(node.asBoolean());
80-
case NULL:
81-
return EppoValue.valueOf();
80+
case OBJECT:
81+
case POJO:
82+
return EppoValue.valueOf(node);
8283
default:
83-
throw new UnsupportedEppoValue("Unsupported Eppo Values");
84+
return EppoValue.valueOf();
8485
}
8586
}
8687
}

src/main/java/com/eppo/sdk/dto/EppoValue.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.eppo.sdk.dto;
22

33
import com.eppo.sdk.deserializer.EppoValueDeserializer;
4+
import com.fasterxml.jackson.databind.JsonNode;
45
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
56

67
import java.util.List;
@@ -11,10 +12,12 @@
1112
@JsonDeserialize(using = EppoValueDeserializer.class)
1213
public class EppoValue {
1314
private String value;
15+
private JsonNode node;
1416
private EppoValueType type = EppoValueType.NULL;
1517
private List<String> array;
1618

17-
public EppoValue() {}
19+
public EppoValue() {
20+
}
1821

1922
public EppoValue(String value, EppoValueType type) {
2023
this.value = value;
@@ -26,6 +29,12 @@ public EppoValue(List<String> array) {
2629
this.type = EppoValueType.ARRAY_OF_STRING;
2730
}
2831

32+
public EppoValue(JsonNode node) {
33+
this.node = node;
34+
this.value = node.toString();
35+
this.type = EppoValueType.JSON_NODE;
36+
}
37+
2938
public EppoValue(EppoValueType type) {
3039
this.type = type;
3140
}
@@ -34,32 +43,28 @@ public static EppoValue valueOf(String value) {
3443
return new EppoValue(value, EppoValueType.STRING);
3544
}
3645

37-
public static EppoValue valueOf(int value) {
38-
return new EppoValue(Integer.toString(value), EppoValueType.NUMBER);
39-
}
40-
41-
public static EppoValue valueOf(long value) {
42-
return new EppoValue(Long.toString(value), EppoValueType.NUMBER);
46+
public static EppoValue valueOf(double value) {
47+
return new EppoValue(Double.toString(value), EppoValueType.NUMBER);
4348
}
4449

4550
public static EppoValue valueOf(boolean value) {
4651
return new EppoValue(Boolean.toString(value), EppoValueType.BOOLEAN);
4752
}
4853

49-
public static EppoValue valueOf(List<String> value) {
50-
return new EppoValue(value);
54+
public static EppoValue valueOf(JsonNode node) {
55+
return new EppoValue(node);
5156
}
5257

53-
public static EppoValue valueOf() {
54-
return new EppoValue(EppoValueType.NULL);
58+
public static EppoValue valueOf(List<String> value) {
59+
return new EppoValue(value);
5560
}
5661

57-
public int intValue() {
58-
return Integer.parseInt(value, 10);
62+
public static EppoValue valueOf() {
63+
return new EppoValue(EppoValueType.NULL);
5964
}
6065

61-
public long longValue() {
62-
return Long.parseLong(value, 10);
66+
public double doubleValue() {
67+
return Double.parseDouble(value);
6368
}
6469

6570
public String stringValue() {
@@ -70,13 +75,17 @@ public boolean boolValue() {
7075
return Boolean.valueOf(value);
7176
}
7277

78+
public JsonNode jsonNodeValue() {
79+
return this.node;
80+
}
81+
7382
public List<String> arrayValue() {
74-
return array;
83+
return array;
7584
}
7685

7786
public boolean isNumeric() {
7887
try {
79-
Long.parseLong(value, 10);
88+
Double.parseDouble(value);
8089
return true;
8190
} catch (Exception e) {
8291
return false;
@@ -88,7 +97,7 @@ public boolean isArray() {
8897
}
8998

9099
public boolean isBool() {
91-
return type == EppoValueType.BOOLEAN;
100+
return type == EppoValueType.BOOLEAN;
92101
}
93102

94103
public boolean isNull() {
@@ -99,6 +108,8 @@ public boolean isNull() {
99108
public String toString() {
100109
if (this.isArray()) {
101110
return List.of(this.array).toString();
111+
} else if (this.type == EppoValueType.JSON_NODE) {
112+
return this.node.toString();
102113
}
103114
return this.value;
104115
}

src/main/java/com/eppo/sdk/dto/EppoValueType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ public enum EppoValueType {
88
STRING,
99
BOOLEAN,
1010
NULL,
11-
ARRAY_OF_STRING
11+
ARRAY_OF_STRING,
12+
JSON_NODE,
1213
}

src/main/java/com/eppo/sdk/dto/ExperimentConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.eppo.sdk.dto;
22

3+
import java.util.HashMap;
34
import java.util.List;
45
import java.util.Map;
56

@@ -13,7 +14,7 @@ public class ExperimentConfiguration {
1314
private String name;
1415
private boolean enabled;
1516
private int subjectShards;
16-
private Map<String, EppoValue> overrides;
17+
private Map<String, EppoValue> typedOverrides = new HashMap<>();
1718
private Map<String, Allocation> allocations;
1819
private List<Rule> rules;
1920

src/main/java/com/eppo/sdk/dto/Variation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
*/
88
@Data
99
public class Variation {
10-
private EppoValue value;
10+
private EppoValue typedValue;
1111
private ShardRange shardRange;
1212
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.eppo.sdk.helpers;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
public class Converter {
7+
public static List<Double> convertToDecimal(List<String> input) {
8+
return input.stream().map((value) -> Double.parseDouble(value)).collect(Collectors.toList());
9+
}
10+
11+
public static List<Boolean> convertToBoolean(List<String> input) {
12+
return input.stream().map((value) -> Boolean.parseBoolean(value)).collect(Collectors.toList());
13+
}
14+
}

0 commit comments

Comments
 (0)