Skip to content

Commit

Permalink
feat(analytics): add analytics rules and events support (#72)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tharropoulos authored Nov 4, 2024
1 parent 27123b1 commit fe13de1
Show file tree
Hide file tree
Showing 9 changed files with 415 additions and 18 deletions.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,62 @@ client.collections("Countries").delete();
client.collections("Countries").documents().export();
```

### Create an analytics rule
```java
AnalyticsRuleSchema analyticsRule = new AnalyticsRuleSchema();
analyticsRule.setName("popular-queries");
analyticsRule.setType(AnalyticsRuleSchema.TypeEnum.POPULAR_QUERIES);
analyticsRule.setParams(new AnalyticsRuleParameters()
.source(new AnalyticsRuleParametersSource()
.collections(Arrays.asList("Countries")))
.destination(new AnalyticsRuleParametersDestination()
.collection("top_searches")));

client.analytics().rules().create(analyticsRule);
```

### Upsert an analytics rule
```java
AnalyticsRuleUpsertSchema analyticsRule = new AnalyticsRuleUpsertSchema()
.type(AnalyticsRuleUpsertSchema.TypeEnum.NOHITS_QUERIES)
.params(new AnalyticsRuleParameters()
.source(new AnalyticsRuleParametersSource()
.collections(Arrays.asList("Countries")))
.destination(new AnalyticsRuleParametersDestination()
.collection("failed_searches")));

client.analytics().rules().upsert("failed-searches", analyticsRule);
```

### Retrieve all analytics rules
```java
AnalyticsRulesRetrieveSchema rules = client.analytics().rules().retrieve();
```

### Retrieve a single analytics rule
```java
AnalyticsRuleSchema rule = client.analytics().rules("failed-searches").retrieve();
```

### Delete an analytics rule
```java
client.analytics().rules("failed-searches").delete();
```

#### Create an analytics event
```java
AnalyticsEventCreateSchema analyticsEvent = new AnalyticsEventCreateSchema()
.type("conversion")
.name("purchase_made")
.data(Map.of(
"product_id", "123",
"user_id", "user_456",
"amount", "99.99"
));

client.analytics().events().create(analyticsEvent);
```

### Create an API key
```java
ApiKeySchema apiKeySchema = new ApiKeySchema();
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/org/typesense/api/Analytics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.typesense.api;

import java.util.HashMap;
import java.util.Map;

public class Analytics {
private final ApiCall apiCall;
private final AnalyticsRules rules;
private final Map<String, AnalyticsRule> individualRules;
private final AnalyticsEvents events;

public Analytics(ApiCall apiCall) {
this.apiCall = apiCall;
this.rules = new AnalyticsRules(this.apiCall);
this.individualRules = new HashMap<>();
this.events = new AnalyticsEvents(this.apiCall);
}

public AnalyticsRules rules() {
return this.rules;
}

public AnalyticsRule rules(String ruleId) {
AnalyticsRule retVal;

if (!this.individualRules.containsKey(ruleId)) {
this.individualRules.put(ruleId, new AnalyticsRule(ruleId, apiCall));
}

retVal = this.individualRules.get(ruleId);
return retVal;
}

public AnalyticsEvents events() {
return this.events;
}
}
18 changes: 18 additions & 0 deletions src/main/java/org/typesense/api/AnalyticsEvents.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.typesense.api;

import org.typesense.model.AnalyticsEventCreateResponse;
import org.typesense.model.AnalyticsEventCreateSchema;


public class AnalyticsEvents {
private final ApiCall apiCall;
public final static String RESOURCE_PATH = "/analytics/events";

public AnalyticsEvents(ApiCall apiCall) {
this.apiCall = apiCall;
}

public AnalyticsEventCreateResponse create(AnalyticsEventCreateSchema event) throws Exception {
return this.apiCall.post(RESOURCE_PATH, event, null, AnalyticsEventCreateResponse.class);
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/typesense/api/AnalyticsRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.typesense.api;

import org.typesense.api.utils.URLEncoding;
import org.typesense.model.AnalyticsRuleDeleteResponse;
import org.typesense.model.AnalyticsRuleSchema;

public class AnalyticsRule {
private final ApiCall apiCall;
private final String ruleId;

public AnalyticsRule(String ruleId, ApiCall apiCall) {
this.apiCall = apiCall;
this.ruleId = ruleId;
}


public AnalyticsRuleSchema retrieve() throws Exception {
return this.apiCall.get(this.getEndpoint(), null, AnalyticsRuleSchema.class);
}

public AnalyticsRuleDeleteResponse delete() throws Exception {
return this.apiCall.delete(this.getEndpoint(), null, AnalyticsRuleDeleteResponse.class);
}

private String getEndpoint() {
return AnalyticsRules.RESOURCE_PATH + "/" + URLEncoding.encodeURIComponent(ruleId);
}

}
30 changes: 30 additions & 0 deletions src/main/java/org/typesense/api/AnalyticsRules.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.typesense.api;

import org.typesense.api.utils.URLEncoding;
import org.typesense.model.AnalyticsRuleSchema;
import org.typesense.model.AnalyticsRuleUpsertSchema;
import org.typesense.model.AnalyticsRulesRetrieveSchema;

public class AnalyticsRules {

private final ApiCall apiCall;
public final static String RESOURCE_PATH = "/analytics/rules";

public AnalyticsRules(ApiCall apiCall) {
this.apiCall = apiCall;
}

public AnalyticsRuleSchema create(AnalyticsRuleSchema rule) throws Exception {
return this.apiCall.post(RESOURCE_PATH, rule, null, AnalyticsRuleSchema.class);
}

public AnalyticsRuleSchema upsert(String name, AnalyticsRuleUpsertSchema rule) throws Exception {
return this.apiCall.put(RESOURCE_PATH + "/" + URLEncoding.encodeURIComponent(name), rule, null,
AnalyticsRuleSchema.class);
}

public AnalyticsRulesRetrieveSchema retrieve() throws Exception {
return this.apiCall.get(RESOURCE_PATH, null, AnalyticsRulesRetrieveSchema.class);
}

}
9 changes: 9 additions & 0 deletions src/main/java/org/typesense/api/Client.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.typesense.api;


import java.util.HashMap;
import java.util.Map;

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


private Analytics analytics;

public Health health;
public Operations operations;
public Metrics metrics;
Expand All @@ -37,6 +41,7 @@ public Client(Configuration configuration){
this.metrics = new Metrics(this.apiCall);
this.debug = new Debug(this.apiCall);
this.multiSearch = new MultiSearch(this.apiCall);
this.analytics = new Analytics(this.apiCall);
}

public Collection collections(String name){
Expand Down Expand Up @@ -85,4 +90,8 @@ public Key keys(Long id){
retVal = this.individualKeys.get(id);
return retVal;
}

public Analytics analytics(){
return this.analytics;
}
}
48 changes: 48 additions & 0 deletions src/test/java/org/typesense/api/AnalyticsEventsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.typesense.api;

import java.util.HashMap;

import org.junit.jupiter.api.AfterEach;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.typesense.model.AnalyticsEventCreateResponse;
import org.typesense.model.AnalyticsEventCreateSchema;

public class AnalyticsEventsTest {

private Client client;
private Helper helper;

@BeforeEach
void setUp() throws Exception {
helper = new Helper();
client = helper.getClient();
helper.teardown();
helper.createTestCollection();
helper.createTestQueryCollection();
helper.createTestAnalyticsRule();
}

@AfterEach
void tearDown() throws Exception {
helper.teardown();
}

@Test
void testCreate() throws Exception {
HashMap<String, Object> eventData = new HashMap<>();
eventData.put("q", "running shoes");
eventData.put("user_id", "1234");
AnalyticsEventCreateSchema analyticsEvent = new AnalyticsEventCreateSchema()
.type("search")
.name("products_search_event")
.data(eventData);

AnalyticsEventCreateResponse result = this.client.analytics().events().create(analyticsEvent);
assertNotNull(result);
assertEquals(true, result.isOk());

}
}
131 changes: 131 additions & 0 deletions src/test/java/org/typesense/api/AnalyticsRulesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package org.typesense.api;

import java.util.Arrays;

import org.junit.jupiter.api.AfterEach;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.typesense.model.AnalyticsRuleDeleteResponse;
import org.typesense.model.AnalyticsRuleParameters;
import org.typesense.model.AnalyticsRuleParametersDestination;
import org.typesense.model.AnalyticsRuleParametersSource;
import org.typesense.model.AnalyticsRuleSchema;
import org.typesense.model.AnalyticsRuleUpsertSchema;
import org.typesense.model.AnalyticsRulesRetrieveSchema;

public class AnalyticsRulesTest {

private Client client;
private Helper helper;

@BeforeEach
void setUp() throws Exception {
helper = new Helper();
client = helper.getClient();
helper.teardown();
helper.createTestCollection();
helper.createTestQueryCollection();
}

@AfterEach
void tearDown() throws Exception {
helper.teardown();
}

@Test
void testCreate() throws Exception {
AnalyticsRuleSchema analyticsRuleSchema = new AnalyticsRuleSchema();
analyticsRuleSchema.setName("nohits-queries");
analyticsRuleSchema.setType(AnalyticsRuleSchema.TypeEnum.NOHITS_QUERIES);
analyticsRuleSchema.setParams(new AnalyticsRuleParameters()
.source(new AnalyticsRuleParametersSource()
.collections(Arrays.asList("books")))
.destination(new AnalyticsRuleParametersDestination()
.collection("queries")));

AnalyticsRuleSchema result = this.client.analytics().rules().create(analyticsRuleSchema);
assertNotNull(result);
assertEquals("nohits-queries", result.getName());

AnalyticsRuleParameters params = result.getParams();
assertNotNull(params);

assertNotNull(params.getSource());
assertEquals(Arrays.asList("books"), params.getSource().getCollections());

assertNotNull(params.getDestination());
assertEquals("queries", params.getDestination().getCollection());
}

@Test
void testUpsert() throws Exception {
AnalyticsRuleUpsertSchema analyticsRuleSchema = new AnalyticsRuleUpsertSchema()
.type(AnalyticsRuleUpsertSchema.TypeEnum.NOHITS_QUERIES)
.params(new AnalyticsRuleParameters()
.source(new AnalyticsRuleParametersSource()
.collections(Arrays.asList("books")))
.destination(new AnalyticsRuleParametersDestination()
.collection("queries")));

AnalyticsRuleSchema result = this.client.analytics().rules().upsert("nohits-queries", analyticsRuleSchema);
assertNotNull(result);
assertEquals("nohits-queries", result.getName());

AnalyticsRuleParameters params = result.getParams();
assertNotNull(params);

assertNotNull(params.getSource());
assertEquals(Arrays.asList("books"), params.getSource().getCollections());

assertNotNull(params.getDestination());
assertEquals("queries", params.getDestination().getCollection());
}

@Test
void testRetrieve() throws Exception {
helper.createTestAnalyticsRule();
AnalyticsRuleSchema result = this.client.analytics().rules("analytics-rule").retrieve();

assertNotNull(result);
assertEquals("analytics-rule", result.getName());

AnalyticsRuleParameters params = result.getParams();
assertNotNull(params);

assertNotNull(params.getSource());
assertEquals(Arrays.asList("books"), params.getSource().getCollections());

assertNotNull(params.getDestination());
assertEquals("queries", params.getDestination().getCollection());
}

@Test
void testRetrieveAll() throws Exception {
helper.createTestAnalyticsRule();
AnalyticsRulesRetrieveSchema result = this.client.analytics().rules().retrieve();

assertNotNull(result);
assertEquals("analytics-rule", result.getRules().get(0).getName());
assertEquals(1, result.getRules().size());

AnalyticsRuleParameters params = result.getRules().get(0).getParams();
assertNotNull(params);

assertNotNull(params.getSource());
assertEquals(Arrays.asList("books"), params.getSource().getCollections());

assertNotNull(params.getDestination());
assertEquals("queries", params.getDestination().getCollection());
}

@Test
void testDelete() throws Exception {
helper.createTestAnalyticsRule();
AnalyticsRuleDeleteResponse result = this.client.analytics().rules("analytics-rule").delete();

assertNotNull(result);
assertEquals("analytics-rule", result.getName());
}
}
Loading

0 comments on commit fe13de1

Please sign in to comment.