diff --git a/README.md b/README.md index 5524147..c917dd4 100644 --- a/README.md +++ b/README.md @@ -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(); diff --git a/src/main/java/org/typesense/api/Analytics.java b/src/main/java/org/typesense/api/Analytics.java new file mode 100644 index 0000000..4503160 --- /dev/null +++ b/src/main/java/org/typesense/api/Analytics.java @@ -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 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; + } +} diff --git a/src/main/java/org/typesense/api/AnalyticsEvents.java b/src/main/java/org/typesense/api/AnalyticsEvents.java new file mode 100644 index 0000000..4889aa3 --- /dev/null +++ b/src/main/java/org/typesense/api/AnalyticsEvents.java @@ -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); + } +} diff --git a/src/main/java/org/typesense/api/AnalyticsRule.java b/src/main/java/org/typesense/api/AnalyticsRule.java new file mode 100644 index 0000000..2ed2f28 --- /dev/null +++ b/src/main/java/org/typesense/api/AnalyticsRule.java @@ -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); + } + +} diff --git a/src/main/java/org/typesense/api/AnalyticsRules.java b/src/main/java/org/typesense/api/AnalyticsRules.java new file mode 100644 index 0000000..f910b05 --- /dev/null +++ b/src/main/java/org/typesense/api/AnalyticsRules.java @@ -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); + } + +} diff --git a/src/main/java/org/typesense/api/Client.java b/src/main/java/org/typesense/api/Client.java index 6f69a60..6177674 100644 --- a/src/main/java/org/typesense/api/Client.java +++ b/src/main/java/org/typesense/api/Client.java @@ -1,5 +1,6 @@ package org.typesense.api; + import java.util.HashMap; import java.util.Map; @@ -17,6 +18,9 @@ public class Client { private Keys keys; private Map individualKeys; + + private Analytics analytics; + public Health health; public Operations operations; public Metrics metrics; @@ -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){ @@ -85,4 +90,8 @@ public Key keys(Long id){ retVal = this.individualKeys.get(id); return retVal; } + + public Analytics analytics(){ + return this.analytics; + } } diff --git a/src/test/java/org/typesense/api/AnalyticsEventsTest.java b/src/test/java/org/typesense/api/AnalyticsEventsTest.java new file mode 100644 index 0000000..2f88002 --- /dev/null +++ b/src/test/java/org/typesense/api/AnalyticsEventsTest.java @@ -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 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()); + + } +} diff --git a/src/test/java/org/typesense/api/AnalyticsRulesTest.java b/src/test/java/org/typesense/api/AnalyticsRulesTest.java new file mode 100644 index 0000000..34f5dd2 --- /dev/null +++ b/src/test/java/org/typesense/api/AnalyticsRulesTest.java @@ -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()); + } +} diff --git a/src/test/java/org/typesense/api/Helper.java b/src/test/java/org/typesense/api/Helper.java index b9b943f..33781ea 100644 --- a/src/test/java/org/typesense/api/Helper.java +++ b/src/test/java/org/typesense/api/Helper.java @@ -1,5 +1,17 @@ package org.typesense.api; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.typesense.model.AnalyticsRuleParameters; +import org.typesense.model.AnalyticsRuleParametersDestination; +import org.typesense.model.AnalyticsRuleParametersSource; +import org.typesense.model.AnalyticsRuleParametersSourceEvents; +import org.typesense.model.AnalyticsRuleSchema; +import org.typesense.model.AnalyticsRuleUpsertSchema; import org.typesense.model.ApiKey; import org.typesense.model.ApiKeySchema; import org.typesense.model.ApiKeysResponse; @@ -15,19 +27,14 @@ import org.typesense.model.SearchSynonymSchema; import org.typesense.resources.Node; -import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - public class Helper { private final Client client; Helper() { List nodes = new ArrayList<>(); - nodes.add(new Node("http","localhost","8108")); + nodes.add(new Node("http", "localhost", "8108")); - Configuration configuration = new Configuration(nodes, Duration.ofSeconds(3),"xyz"); + Configuration configuration = new Configuration(nodes, Duration.ofSeconds(3), "xyz"); this.client = new Client(configuration); } @@ -42,15 +49,26 @@ public void createTestCollection() throws Exception { client.collections().create(collectionSchema); } + public void createTestQueryCollection() throws Exception { + List fields = new ArrayList<>(); + fields.add(new Field().name("q").type((FieldTypes.STRING))); + fields.add(new Field().name("count").type((FieldTypes.INT32))); + + CollectionSchema collectionSchema = new CollectionSchema(); + collectionSchema.name("queries").fields(fields); + + client.collections().create(collectionSchema); + } + public void createTestDocument() throws Exception { - String[] authors = {"shakspeare","william"}; + String[] authors = { "shakspeare", "william" }; HashMap hmap = new HashMap<>(); - hmap.put("title","Romeo and juliet"); - hmap.put("authors",authors); - hmap.put("publication_year",1666); - hmap.put("ratings_count",124); - hmap.put("average_rating",3.2); - hmap.put("id","1"); + hmap.put("title", "Romeo and juliet"); + hmap.put("authors", authors); + hmap.put("publication_year", 1666); + hmap.put("ratings_count", 124); + hmap.put("average_rating", 3.2); + hmap.put("id", "1"); client.collections("books").documents().create(hmap); } @@ -88,22 +106,43 @@ public void createTestSynonym() throws Exception { SearchSynonymSchema synonym = new SearchSynonymSchema(); synonym.addSynonymsItem("blazer").addSynonymsItem("coat").addSynonymsItem("jacket"); - client.collections("books").synonyms().upsert("coat-synonyms",synonym); + client.collections("books").synonyms().upsert("coat-synonyms", synonym); + } + + public void createTestAnalyticsRule() throws Exception { + AnalyticsRuleUpsertSchema analyticsRuleSchema = new AnalyticsRuleUpsertSchema() + .type(AnalyticsRuleUpsertSchema.TypeEnum.NOHITS_QUERIES) + .params(new AnalyticsRuleParameters() + .source(new AnalyticsRuleParametersSource() + .collections(Arrays.asList("books")) + .events(Arrays.asList( + new AnalyticsRuleParametersSourceEvents() + .type("search") + .name("products_search_event")))) + .destination(new AnalyticsRuleParametersDestination() + .collection("queries"))); + + client.analytics().rules().upsert("analytics-rule", analyticsRuleSchema); } public void teardown() throws Exception { CollectionResponse[] collectionResponses = client.collections().retrieve(); - for(CollectionResponse c:collectionResponses) { + for (CollectionResponse c : collectionResponses) { client.collections(c.getName()).delete(); } CollectionAliasesResponse collectionAliasesResponse = client.aliases().retrieve(); - for(CollectionAlias a:collectionAliasesResponse.getAliases()) { + for (CollectionAlias a : collectionAliasesResponse.getAliases()) { client.aliases(a.getName()).delete(); } + AnalyticsRules analyticsRules = client.analytics().rules(); + for (AnalyticsRuleSchema r : analyticsRules.retrieve().getRules()) { + client.analytics().rules(r.getName()).delete(); + } + ApiKeysResponse apiKeysResponse = client.keys().retrieve(); - for (ApiKey k: apiKeysResponse.getKeys()) { + for (ApiKey k : apiKeysResponse.getKeys()) { client.keys(k.getId()).delete(); } }