Skip to content

Commit fe13de1

Browse files
authored
feat(analytics): add analytics rules and events support (#72)
* feat(analytics): add Analytics rules API support Initial implementation of Analytics rules API for the Typesense Java client. Includes CRUD operations for analytics rules and corresponding test coverage. The changes include: - New Analytics, AnalyticsRule, and AnalyticsRules classes - Analytics rules integration in Client class - Comprehensive test coverage for analytics operations - Documentation updates showcasing how to use the new feature feat(analytics): implement Analytics class feat(analytics): add AnalyticsRule class for individual rule operations feat(analytics): add AnalyticsRules class for bulk operations test(analytics): add comprehensive test coverage for analytics rules refactor(client): integrate analytics support docs(analytics): add documenation on proper analytics rules usage * feat(analytics): add Analytics events API support Implements analytics events tracking capabilities to complement existing rules functionality. Adds ability to create custom analytics events with type, name and data fields. Changes include: - New AnalyticsEvents class for event operations - Integration with Analytics class - Test coverage with sample search event creation - Helper updates for events in analytics rules - Documentation updates on how to use new feature feat(analytics): add AnalyticsEvents class test(analytics): add AnalyticsEventsTest feat(analytics): integrate events into Analytics class refactor(helper): update createTestAnalyticsRule for events docs(analytics): add documenation on proper analytics rules usage * fix: use regular hashmap on analytics test for older java versions
1 parent 27123b1 commit fe13de1

File tree

9 files changed

+415
-18
lines changed

9 files changed

+415
-18
lines changed

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,62 @@ client.collections("Countries").delete();
150150
client.collections("Countries").documents().export();
151151
```
152152

153+
### Create an analytics rule
154+
```java
155+
AnalyticsRuleSchema analyticsRule = new AnalyticsRuleSchema();
156+
analyticsRule.setName("popular-queries");
157+
analyticsRule.setType(AnalyticsRuleSchema.TypeEnum.POPULAR_QUERIES);
158+
analyticsRule.setParams(new AnalyticsRuleParameters()
159+
.source(new AnalyticsRuleParametersSource()
160+
.collections(Arrays.asList("Countries")))
161+
.destination(new AnalyticsRuleParametersDestination()
162+
.collection("top_searches")));
163+
164+
client.analytics().rules().create(analyticsRule);
165+
```
166+
167+
### Upsert an analytics rule
168+
```java
169+
AnalyticsRuleUpsertSchema analyticsRule = new AnalyticsRuleUpsertSchema()
170+
.type(AnalyticsRuleUpsertSchema.TypeEnum.NOHITS_QUERIES)
171+
.params(new AnalyticsRuleParameters()
172+
.source(new AnalyticsRuleParametersSource()
173+
.collections(Arrays.asList("Countries")))
174+
.destination(new AnalyticsRuleParametersDestination()
175+
.collection("failed_searches")));
176+
177+
client.analytics().rules().upsert("failed-searches", analyticsRule);
178+
```
179+
180+
### Retrieve all analytics rules
181+
```java
182+
AnalyticsRulesRetrieveSchema rules = client.analytics().rules().retrieve();
183+
```
184+
185+
### Retrieve a single analytics rule
186+
```java
187+
AnalyticsRuleSchema rule = client.analytics().rules("failed-searches").retrieve();
188+
```
189+
190+
### Delete an analytics rule
191+
```java
192+
client.analytics().rules("failed-searches").delete();
193+
```
194+
195+
#### Create an analytics event
196+
```java
197+
AnalyticsEventCreateSchema analyticsEvent = new AnalyticsEventCreateSchema()
198+
.type("conversion")
199+
.name("purchase_made")
200+
.data(Map.of(
201+
"product_id", "123",
202+
"user_id", "user_456",
203+
"amount", "99.99"
204+
));
205+
206+
client.analytics().events().create(analyticsEvent);
207+
```
208+
153209
### Create an API key
154210
```java
155211
ApiKeySchema apiKeySchema = new ApiKeySchema();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.typesense.api;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
public class Analytics {
7+
private final ApiCall apiCall;
8+
private final AnalyticsRules rules;
9+
private final Map<String, AnalyticsRule> individualRules;
10+
private final AnalyticsEvents events;
11+
12+
public Analytics(ApiCall apiCall) {
13+
this.apiCall = apiCall;
14+
this.rules = new AnalyticsRules(this.apiCall);
15+
this.individualRules = new HashMap<>();
16+
this.events = new AnalyticsEvents(this.apiCall);
17+
}
18+
19+
public AnalyticsRules rules() {
20+
return this.rules;
21+
}
22+
23+
public AnalyticsRule rules(String ruleId) {
24+
AnalyticsRule retVal;
25+
26+
if (!this.individualRules.containsKey(ruleId)) {
27+
this.individualRules.put(ruleId, new AnalyticsRule(ruleId, apiCall));
28+
}
29+
30+
retVal = this.individualRules.get(ruleId);
31+
return retVal;
32+
}
33+
34+
public AnalyticsEvents events() {
35+
return this.events;
36+
}
37+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.typesense.api;
2+
3+
import org.typesense.model.AnalyticsEventCreateResponse;
4+
import org.typesense.model.AnalyticsEventCreateSchema;
5+
6+
7+
public class AnalyticsEvents {
8+
private final ApiCall apiCall;
9+
public final static String RESOURCE_PATH = "/analytics/events";
10+
11+
public AnalyticsEvents(ApiCall apiCall) {
12+
this.apiCall = apiCall;
13+
}
14+
15+
public AnalyticsEventCreateResponse create(AnalyticsEventCreateSchema event) throws Exception {
16+
return this.apiCall.post(RESOURCE_PATH, event, null, AnalyticsEventCreateResponse.class);
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.typesense.api;
2+
3+
import org.typesense.api.utils.URLEncoding;
4+
import org.typesense.model.AnalyticsRuleDeleteResponse;
5+
import org.typesense.model.AnalyticsRuleSchema;
6+
7+
public class AnalyticsRule {
8+
private final ApiCall apiCall;
9+
private final String ruleId;
10+
11+
public AnalyticsRule(String ruleId, ApiCall apiCall) {
12+
this.apiCall = apiCall;
13+
this.ruleId = ruleId;
14+
}
15+
16+
17+
public AnalyticsRuleSchema retrieve() throws Exception {
18+
return this.apiCall.get(this.getEndpoint(), null, AnalyticsRuleSchema.class);
19+
}
20+
21+
public AnalyticsRuleDeleteResponse delete() throws Exception {
22+
return this.apiCall.delete(this.getEndpoint(), null, AnalyticsRuleDeleteResponse.class);
23+
}
24+
25+
private String getEndpoint() {
26+
return AnalyticsRules.RESOURCE_PATH + "/" + URLEncoding.encodeURIComponent(ruleId);
27+
}
28+
29+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.typesense.api;
2+
3+
import org.typesense.api.utils.URLEncoding;
4+
import org.typesense.model.AnalyticsRuleSchema;
5+
import org.typesense.model.AnalyticsRuleUpsertSchema;
6+
import org.typesense.model.AnalyticsRulesRetrieveSchema;
7+
8+
public class AnalyticsRules {
9+
10+
private final ApiCall apiCall;
11+
public final static String RESOURCE_PATH = "/analytics/rules";
12+
13+
public AnalyticsRules(ApiCall apiCall) {
14+
this.apiCall = apiCall;
15+
}
16+
17+
public AnalyticsRuleSchema create(AnalyticsRuleSchema rule) throws Exception {
18+
return this.apiCall.post(RESOURCE_PATH, rule, null, AnalyticsRuleSchema.class);
19+
}
20+
21+
public AnalyticsRuleSchema upsert(String name, AnalyticsRuleUpsertSchema rule) throws Exception {
22+
return this.apiCall.put(RESOURCE_PATH + "/" + URLEncoding.encodeURIComponent(name), rule, null,
23+
AnalyticsRuleSchema.class);
24+
}
25+
26+
public AnalyticsRulesRetrieveSchema retrieve() throws Exception {
27+
return this.apiCall.get(RESOURCE_PATH, null, AnalyticsRulesRetrieveSchema.class);
28+
}
29+
30+
}

src/main/java/org/typesense/api/Client.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.typesense.api;
22

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

@@ -17,6 +18,9 @@ public class Client {
1718
private Keys keys;
1819
private Map<Long, Key> individualKeys;
1920

21+
22+
private Analytics analytics;
23+
2024
public Health health;
2125
public Operations operations;
2226
public Metrics metrics;
@@ -37,6 +41,7 @@ public Client(Configuration configuration){
3741
this.metrics = new Metrics(this.apiCall);
3842
this.debug = new Debug(this.apiCall);
3943
this.multiSearch = new MultiSearch(this.apiCall);
44+
this.analytics = new Analytics(this.apiCall);
4045
}
4146

4247
public Collection collections(String name){
@@ -85,4 +90,8 @@ public Key keys(Long id){
8590
retVal = this.individualKeys.get(id);
8691
return retVal;
8792
}
93+
94+
public Analytics analytics(){
95+
return this.analytics;
96+
}
8897
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.typesense.api;
2+
3+
import java.util.HashMap;
4+
5+
import org.junit.jupiter.api.AfterEach;
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
import static org.junit.jupiter.api.Assertions.assertNotNull;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.typesense.model.AnalyticsEventCreateResponse;
11+
import org.typesense.model.AnalyticsEventCreateSchema;
12+
13+
public class AnalyticsEventsTest {
14+
15+
private Client client;
16+
private Helper helper;
17+
18+
@BeforeEach
19+
void setUp() throws Exception {
20+
helper = new Helper();
21+
client = helper.getClient();
22+
helper.teardown();
23+
helper.createTestCollection();
24+
helper.createTestQueryCollection();
25+
helper.createTestAnalyticsRule();
26+
}
27+
28+
@AfterEach
29+
void tearDown() throws Exception {
30+
helper.teardown();
31+
}
32+
33+
@Test
34+
void testCreate() throws Exception {
35+
HashMap<String, Object> eventData = new HashMap<>();
36+
eventData.put("q", "running shoes");
37+
eventData.put("user_id", "1234");
38+
AnalyticsEventCreateSchema analyticsEvent = new AnalyticsEventCreateSchema()
39+
.type("search")
40+
.name("products_search_event")
41+
.data(eventData);
42+
43+
AnalyticsEventCreateResponse result = this.client.analytics().events().create(analyticsEvent);
44+
assertNotNull(result);
45+
assertEquals(true, result.isOk());
46+
47+
}
48+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package org.typesense.api;
2+
3+
import java.util.Arrays;
4+
5+
import org.junit.jupiter.api.AfterEach;
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
import static org.junit.jupiter.api.Assertions.assertNotNull;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.typesense.model.AnalyticsRuleDeleteResponse;
11+
import org.typesense.model.AnalyticsRuleParameters;
12+
import org.typesense.model.AnalyticsRuleParametersDestination;
13+
import org.typesense.model.AnalyticsRuleParametersSource;
14+
import org.typesense.model.AnalyticsRuleSchema;
15+
import org.typesense.model.AnalyticsRuleUpsertSchema;
16+
import org.typesense.model.AnalyticsRulesRetrieveSchema;
17+
18+
public class AnalyticsRulesTest {
19+
20+
private Client client;
21+
private Helper helper;
22+
23+
@BeforeEach
24+
void setUp() throws Exception {
25+
helper = new Helper();
26+
client = helper.getClient();
27+
helper.teardown();
28+
helper.createTestCollection();
29+
helper.createTestQueryCollection();
30+
}
31+
32+
@AfterEach
33+
void tearDown() throws Exception {
34+
helper.teardown();
35+
}
36+
37+
@Test
38+
void testCreate() throws Exception {
39+
AnalyticsRuleSchema analyticsRuleSchema = new AnalyticsRuleSchema();
40+
analyticsRuleSchema.setName("nohits-queries");
41+
analyticsRuleSchema.setType(AnalyticsRuleSchema.TypeEnum.NOHITS_QUERIES);
42+
analyticsRuleSchema.setParams(new AnalyticsRuleParameters()
43+
.source(new AnalyticsRuleParametersSource()
44+
.collections(Arrays.asList("books")))
45+
.destination(new AnalyticsRuleParametersDestination()
46+
.collection("queries")));
47+
48+
AnalyticsRuleSchema result = this.client.analytics().rules().create(analyticsRuleSchema);
49+
assertNotNull(result);
50+
assertEquals("nohits-queries", result.getName());
51+
52+
AnalyticsRuleParameters params = result.getParams();
53+
assertNotNull(params);
54+
55+
assertNotNull(params.getSource());
56+
assertEquals(Arrays.asList("books"), params.getSource().getCollections());
57+
58+
assertNotNull(params.getDestination());
59+
assertEquals("queries", params.getDestination().getCollection());
60+
}
61+
62+
@Test
63+
void testUpsert() throws Exception {
64+
AnalyticsRuleUpsertSchema analyticsRuleSchema = new AnalyticsRuleUpsertSchema()
65+
.type(AnalyticsRuleUpsertSchema.TypeEnum.NOHITS_QUERIES)
66+
.params(new AnalyticsRuleParameters()
67+
.source(new AnalyticsRuleParametersSource()
68+
.collections(Arrays.asList("books")))
69+
.destination(new AnalyticsRuleParametersDestination()
70+
.collection("queries")));
71+
72+
AnalyticsRuleSchema result = this.client.analytics().rules().upsert("nohits-queries", analyticsRuleSchema);
73+
assertNotNull(result);
74+
assertEquals("nohits-queries", result.getName());
75+
76+
AnalyticsRuleParameters params = result.getParams();
77+
assertNotNull(params);
78+
79+
assertNotNull(params.getSource());
80+
assertEquals(Arrays.asList("books"), params.getSource().getCollections());
81+
82+
assertNotNull(params.getDestination());
83+
assertEquals("queries", params.getDestination().getCollection());
84+
}
85+
86+
@Test
87+
void testRetrieve() throws Exception {
88+
helper.createTestAnalyticsRule();
89+
AnalyticsRuleSchema result = this.client.analytics().rules("analytics-rule").retrieve();
90+
91+
assertNotNull(result);
92+
assertEquals("analytics-rule", result.getName());
93+
94+
AnalyticsRuleParameters params = result.getParams();
95+
assertNotNull(params);
96+
97+
assertNotNull(params.getSource());
98+
assertEquals(Arrays.asList("books"), params.getSource().getCollections());
99+
100+
assertNotNull(params.getDestination());
101+
assertEquals("queries", params.getDestination().getCollection());
102+
}
103+
104+
@Test
105+
void testRetrieveAll() throws Exception {
106+
helper.createTestAnalyticsRule();
107+
AnalyticsRulesRetrieveSchema result = this.client.analytics().rules().retrieve();
108+
109+
assertNotNull(result);
110+
assertEquals("analytics-rule", result.getRules().get(0).getName());
111+
assertEquals(1, result.getRules().size());
112+
113+
AnalyticsRuleParameters params = result.getRules().get(0).getParams();
114+
assertNotNull(params);
115+
116+
assertNotNull(params.getSource());
117+
assertEquals(Arrays.asList("books"), params.getSource().getCollections());
118+
119+
assertNotNull(params.getDestination());
120+
assertEquals("queries", params.getDestination().getCollection());
121+
}
122+
123+
@Test
124+
void testDelete() throws Exception {
125+
helper.createTestAnalyticsRule();
126+
AnalyticsRuleDeleteResponse result = this.client.analytics().rules("analytics-rule").delete();
127+
128+
assertNotNull(result);
129+
assertEquals("analytics-rule", result.getName());
130+
}
131+
}

0 commit comments

Comments
 (0)