Skip to content

Commit 3a2f511

Browse files
author
jianggang
authored
feat: server api support number/datetime/semver condition (#16)
feat: server api support number/datetime/semver condition
1 parent 999264e commit 3a2f511

16 files changed

Lines changed: 297 additions & 56 deletions

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@
8585
<version>2.11.0</version>
8686
</dependency>
8787
<dependency>
88-
<groupId>com.github.featureprobe</groupId>
88+
<groupId>com.featureprobe</groupId>
8989
<artifactId>server-sdk-java</artifactId>
90-
<version>1.1.1</version>
90+
<version>1.2.0</version>
9191
<exclusions>
9292
<exclusion>
9393
<groupId>org.codehaus.groovy</groupId>

src/main/java/com/featureprobe/api/dto/TargetingVersionRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@
44

55
@Data
66
public class TargetingVersionRequest extends PaginationRequest{
7+
8+
private Long version;
9+
710
}

src/main/java/com/featureprobe/api/model/AccessEventPoint.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ public class AccessEventPoint {
1111

1212
String name;
1313
List<VariationAccessCounter> values;
14+
Long lastChangeVersion;
1415
}

src/main/java/com/featureprobe/api/model/ConditionValue.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import org.apache.commons.lang3.StringUtils;
88

99
import java.util.List;
10-
import java.util.stream.Collectors;
1110

1211
@Data
1312
public class ConditionValue {
@@ -28,6 +27,19 @@ public Condition toCondition() {
2827
}
2928

3029
public boolean isSegmentType() {
31-
return StringUtils.equals(ConditionType.SEGMENT.toValue(), getType());
30+
return StringUtils.equals(ConditionType.SEGMENT.toValue(), type);
3231
}
32+
33+
public boolean isNumberType() {
34+
return StringUtils.equals(ConditionType.NUMBER.toValue(), type);
35+
}
36+
37+
public boolean isDatetimeType() {
38+
return StringUtils.equals(ConditionType.DATETIME.toValue(), type);
39+
}
40+
41+
public boolean isSemVerType() {
42+
return StringUtils.equals(ConditionType.SEMVER.toValue(), type);
43+
}
44+
3345
}

src/main/java/com/featureprobe/api/model/ServerSegmentBuilder.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package com.featureprobe.api.model;
22

33
import com.featureprobe.api.mapper.JsonMapper;
4+
import com.featureprobe.api.util.DateTimeTranslateUtil;
5+
import com.featureprobe.sdk.server.model.Condition;
46
import com.featureprobe.sdk.server.model.ConditionType;
57
import com.featureprobe.sdk.server.model.Segment;
68
import com.featureprobe.sdk.server.model.SegmentRule;
79
import org.apache.commons.collections4.CollectionUtils;
8-
import org.apache.commons.lang3.StringUtils;
910

1011
import java.util.Collections;
1112
import java.util.List;
1213
import java.util.stream.Collectors;
1314

1415
public class ServerSegmentBuilder {
1516

17+
private static final String DATETIME_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
18+
1619
private Segment segment;
1720

1821
private List<SegmentRuleModel> segmentRuleModels;
@@ -49,8 +52,17 @@ private void setRules() {
4952
}
5053
List<SegmentRule> rules = segmentRuleModels.stream().map(segmentRuleModel ->
5154
segmentRuleModel.toSegmentRule()).collect(Collectors.toList());
55+
rules.forEach(rule -> rule.getConditions().forEach(condition -> {
56+
if (condition.getType() == ConditionType.DATETIME){
57+
convertDatetimeToUnix(condition);
58+
}
59+
}));
5260
segment.setRules(rules);
5361
}
5462

63+
private void convertDatetimeToUnix(Condition condition) {
64+
condition.setObjects(condition.getObjects().stream().map(datetime ->
65+
DateTimeTranslateUtil.translateUnix(datetime, DATETIME_FORMAT_PATTERN)).collect(Collectors.toList()));
66+
}
5567

5668
}

src/main/java/com/featureprobe/api/model/ServerToggleBuilder.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,28 @@
33
import com.featureprobe.api.base.exception.ServerToggleBuildException;
44
import com.featureprobe.api.entity.Segment;
55
import com.featureprobe.api.mapper.JsonMapper;
6+
import com.featureprobe.api.util.DateTimeTranslateUtil;
67
import com.featureprobe.sdk.server.model.Condition;
78
import com.featureprobe.sdk.server.model.ConditionType;
89
import com.featureprobe.sdk.server.model.Rule;
910
import com.featureprobe.sdk.server.model.Toggle;
1011
import com.google.common.collect.Maps;
1112
import org.apache.commons.collections4.CollectionUtils;
1213
import org.apache.commons.lang3.BooleanUtils;
14+
import org.apache.commons.lang3.time.DateUtils;
1315

1416
import java.math.BigDecimal;
17+
import java.text.ParseException;
1518
import java.util.Collections;
19+
import java.util.Date;
1620
import java.util.List;
1721
import java.util.Map;
1822
import java.util.stream.Collectors;
1923

2024
public class ServerToggleBuilder {
2125

26+
private static final String DATETIME_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
27+
2228
private Toggle toggle;
2329
private Variation.ValueConverter variationValueConverter;
2430
private TargetingContent targetingContent;
@@ -120,6 +126,7 @@ private void setVariations() {
120126
toggle.setVariations(variations);
121127
}
122128

129+
123130
private void setRules() {
124131
if (CollectionUtils.isEmpty(targetingContent.getRules())) {
125132
toggle.setRules(Collections.emptyList());
@@ -128,12 +135,20 @@ private void setRules() {
128135
List<Rule> rules = targetingContent.getRules().stream().map(rule ->
129136
rule.toRule()).collect(Collectors.toList());
130137
rules.forEach(rule -> rule.getConditions().forEach(condition -> {
131-
if (condition.getType() != ConditionType.SEGMENT) return;
132-
replaceSegmentKeyToUniqueKey(condition);
138+
if (condition.getType() == ConditionType.SEGMENT){
139+
replaceSegmentKeyToUniqueKey(condition);
140+
} else if (condition.getType() == ConditionType.DATETIME) {
141+
convertDatetimeToUnix(condition);
142+
}
133143
}));
134144
toggle.setRules(rules);
135145
}
136146

147+
private void convertDatetimeToUnix(Condition condition) {
148+
condition.setObjects(condition.getObjects().stream().map(datetime ->
149+
DateTimeTranslateUtil.translateUnix(datetime, DATETIME_FORMAT_PATTERN)).collect(Collectors.toList()));
150+
}
151+
137152
private void replaceSegmentKeyToUniqueKey(Condition condition) {
138153
condition.setObjects(condition.getObjects().stream().map(segmentKey ->
139154
segments.get(segmentKey).getUniqueKey()).collect(Collectors.toList()));

src/main/java/com/featureprobe/api/repository/TargetingVersionRepository.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,17 @@
77
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
88
import org.springframework.stereotype.Repository;
99

10+
import java.util.Date;
11+
import java.util.List;
12+
1013
@Repository
1114
public interface TargetingVersionRepository extends JpaRepository<TargetingVersion, Long>,
1215
JpaSpecificationExecutor<TargetingVersion> {
1316

1417
Page<TargetingVersion> findAllByProjectKeyAndEnvironmentKey(String projectKey, String environmentKey,
15-
Pageable pageable);
18+
Pageable pageable);
19+
20+
List<TargetingVersion>
21+
findAllByTargetingIdAndCreatedTimeGreaterThanEqualAndCreatedTimeLessThanEqualOrderByCreatedTimeDesc(
22+
Long targetingId, Date startDate, Date endDate);
1623
}

src/main/java/com/featureprobe/api/service/MetricService.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.featureprobe.api.entity.Environment;
66
import com.featureprobe.api.entity.Event;
77
import com.featureprobe.api.entity.Targeting;
8+
import com.featureprobe.api.entity.TargetingVersion;
89
import com.featureprobe.api.entity.VariationHistory;
910
import com.featureprobe.api.mapper.TargetingVersionMapper;
1011
import com.featureprobe.api.model.AccessEventPoint;
@@ -14,6 +15,7 @@
1415
import com.featureprobe.api.repository.EnvironmentRepository;
1516
import com.featureprobe.api.repository.EventRepository;
1617
import com.featureprobe.api.repository.TargetingRepository;
18+
import com.featureprobe.api.repository.TargetingVersionRepository;
1719
import com.featureprobe.api.repository.VariationHistoryRepository;
1820
import com.google.common.collect.Lists;
1921
import lombok.AllArgsConstructor;
@@ -40,6 +42,7 @@ public class MetricService {
4042
private EnvironmentRepository environmentRepository;
4143
private EventRepository eventRepository;
4244
private VariationHistoryRepository variationHistoryRepository;
45+
private TargetingVersionRepository targetingVersionRepository;
4346
private TargetingRepository targetingRepository;
4447

4548
private static final int MAX_QUERY_HOURS = 12 * 24;
@@ -50,10 +53,11 @@ public MetricResponse query(String projectKey, String environmentKey, String tog
5053
int lastHours) {
5154
int queryLastHours = Math.min(lastHours, MAX_QUERY_HOURS);
5255
String serverSdkKey = queryEnvironmentServerSdkKey(projectKey, environmentKey);
53-
56+
Long targetingId = queryTargetingId(projectKey, environmentKey, toggleKey);
5457
Map<String, VariationHistory> variationVersionMap = buildVariationVersionMap(projectKey,
5558
environmentKey, toggleKey);
56-
List<AccessEventPoint> accessEventPoints = queryAccessEventPoints(serverSdkKey, toggleKey, queryLastHours);
59+
List<AccessEventPoint> accessEventPoints = queryAccessEventPoints(serverSdkKey, toggleKey, targetingId,
60+
queryLastHours);
5761
List<AccessEventPoint> aggregatedAccessEventPoints = aggregatePointByMetricType(variationVersionMap,
5862
accessEventPoints, metricType);
5963

@@ -100,7 +104,8 @@ protected List<AccessEventPoint> aggregatePointByMetricType(Map<String, Variatio
100104
return accessEventPoints;
101105
}
102106

103-
protected List<AccessEventPoint> queryAccessEventPoints(String serverSdkKey, String toggleKey, int lastHours) {
107+
private List<AccessEventPoint> queryAccessEventPoints(String serverSdkKey, String toggleKey,
108+
Long targetId, int lastHours) {
104109
int pointIntervalCount = getPointIntervalCount(lastHours);
105110
int pointCount = lastHours / pointIntervalCount;
106111

@@ -110,8 +115,8 @@ protected List<AccessEventPoint> queryAccessEventPoints(String serverSdkKey, Str
110115
List<AccessEventPoint> accessEventPoints = Lists.newArrayList();
111116
for (int i = 0; i < pointCount; i++) {
112117
LocalDateTime pointEndTime = pointStartTime.plusHours(pointIntervalCount);
113-
AccessEventPoint accessEventPoint = queryAccessEventPoint(serverSdkKey, toggleKey, pointNameFormat,
114-
pointStartTime, pointEndTime);
118+
AccessEventPoint accessEventPoint = queryAccessEventPoint(serverSdkKey, toggleKey, targetId,
119+
pointNameFormat, pointStartTime, pointEndTime);
115120

116121
accessEventPoints.add(accessEventPoint);
117122
pointStartTime = pointEndTime;
@@ -129,14 +134,25 @@ protected int getPointIntervalCount(int lastHours) {
129134
return pointIntervalCount;
130135
}
131136

132-
protected AccessEventPoint queryAccessEventPoint(String serverSdkKey, String toggleKey, String pointNameFormat,
137+
protected AccessEventPoint queryAccessEventPoint(String serverSdkKey, String toggleKey, Long targetingId,
138+
String pointNameFormat,
133139
LocalDateTime pointStartTime,
134140
LocalDateTime pointEndTime) {
135141
List<VariationAccessCounter> accessEvents = queryAccessEvents(serverSdkKey,
136142
toggleKey, pointStartTime, pointEndTime);
137143
String pointName = String.format("%s", pointEndTime.format(DateTimeFormatter.ofPattern(pointNameFormat)));
144+
Long lastTargetingVersion = queryLastTargetingVersion(targetingId, pointStartTime, pointEndTime);
145+
return new AccessEventPoint(pointName, accessEvents, lastTargetingVersion);
146+
}
138147

139-
return new AccessEventPoint(pointName, accessEvents);
148+
private Long queryLastTargetingVersion(Long targetingId, LocalDateTime pointStartTime, LocalDateTime pointEndTime) {
149+
List<TargetingVersion> targetingVersions = targetingVersionRepository
150+
.findAllByTargetingIdAndCreatedTimeGreaterThanEqualAndCreatedTimeLessThanEqualOrderByCreatedTimeDesc(
151+
targetingId, toDate(pointStartTime), toDate(pointEndTime));
152+
if (CollectionUtils.isNotEmpty(targetingVersions)) {
153+
return targetingVersions.get(0).getVersion();
154+
}
155+
return null;
140156
}
141157

142158
private List<VariationAccessCounter> queryAccessEvents(String serverSdkKey,
@@ -250,6 +266,12 @@ private String queryEnvironmentServerSdkKey(String projectKey, String environmen
250266
return environment.getServerSdkKey();
251267
}
252268

269+
private Long queryTargetingId(String projectKey, String environmentKey, String toggleKey) {
270+
Targeting targeting = targetingRepository.findByProjectKeyAndEnvironmentKeyAndToggleKey(projectKey,
271+
environmentKey, toggleKey).get();
272+
return targeting.getId();
273+
}
274+
253275
protected boolean isGroupByDay(int queryLastHours) {
254276
return queryLastHours > GROUP_BY_DAY_HOURS;
255277
}

0 commit comments

Comments
 (0)