io.keen.client.java.KeenQueryClient Maven / Gradle / Ivy
package io.keen.client.java;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import io.keen.client.java.exceptions.KeenQueryClientException;
import io.keen.client.java.exceptions.ServerException;
import io.keen.client.java.http.HttpHandler;
import io.keen.client.java.http.OutputSource;
import io.keen.client.java.http.Request;
import io.keen.client.java.http.Response;
import io.keen.client.java.http.UrlConnectionHttpHandler;
import io.keen.client.java.result.DoubleResult;
import io.keen.client.java.result.Group;
import io.keen.client.java.result.GroupByResult;
import io.keen.client.java.result.IntervalResult;
import io.keen.client.java.result.ListResult;
import io.keen.client.java.result.LongResult;
import io.keen.client.java.result.QueryResult;
import io.keen.client.java.result.StringResult;
/**
*
* KeenQueryClient provides all of the functionality required to execute the basic queries
* supported by the Data Analysis API: https://keen.io/docs/data-analysis/
*
This include Count, Count Unique, Sum, Average, Maxiumum, Minimum, Median,
* Percentile, and Select Unique. It does not include Extractions, Multi-Analysis, and Funnels.
*
* @author claireyoung
* @since 1.0.0
*/
public class KeenQueryClient {
private static final String ENCODING = "UTF-8";
private final KeenJsonHandler jsonHandler;
private final String baseUrl;
private final KeenProject project;
private final HttpHandler httpHandler;
/**
* Gets the default project that this {@link KeenQueryClient} is using.
*
* @return The {@link KeenProject}.
*/
public KeenProject getProject() {
return this.project;
}
/**
* Count query with only the required arguments.
* Query API info here: https://keen.io/docs/api/#count
*
* @param eventCollection The name of the event collection you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return the count query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public long count(String eventCollection, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.COUNT)
.withEventCollection(eventCollection)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToLong(result);
}
/**
* Count Unique query with only the required arguments.
* Query API info here: https://keen.io/docs/api/#count-unique
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The count unique query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public long countUnique(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.COUNT_UNIQUE)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToLong(result);
}
/**
* Minimum query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#minimum-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The minimum query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double minimum(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.MINIMUM)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Maximum query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#maximum-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The response from the server in the "result" map.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double maximum(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.MAXIMUM)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Average query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#average-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The average query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double average(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.AVERAGE)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Median query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#median-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The median query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double median(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.MEDIAN)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Percentile query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#percentile-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param percentile The percentile.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The percentile query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double percentile(String eventCollection, String targetProperty, Double percentile, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.PERCENTILE)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withPercentile(percentile)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Sum query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#sum-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The sum response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public double sum(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.SUM)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return queryResultToDouble(result);
}
/**
* Select Unique query with only the required arguments.
* Query API info here: https://keen.io/docs/api/reference/#select-unique-resource
*
* @param eventCollection The name of the event collection you are analyzing.
* @param targetProperty The name of the property you are analyzing.
* @param timeframe The {@link RelativeTimeframe} or {@link AbsoluteTimeframe}.
* @return The select unique query response.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public QueryResult selectUnique(String eventCollection, String targetProperty, Timeframe timeframe) throws IOException {
Query queryParams = new Query.Builder(QueryType.SELECT_UNIQUE)
.withEventCollection(eventCollection)
.withTargetProperty(targetProperty)
.withTimeframe(timeframe)
.build();
QueryResult result = execute(queryParams);
return result;
}
/**
* This is the most flexible way to run a query. Use {@link Builder} to
* build all the query arguments to run the query.
*
* @param params The {@link Query} information, including {@link QueryType}, required args, and any optional args.
* @return The {@link QueryResult} result.
* @throws IOException If there was an error communicating with the server or
* an error message received from the server.
*/
public QueryResult execute(Query params) throws IOException {
// check parameters are valid
if (false == params.areParamsValid()) {
throw new IllegalArgumentException("Keen Query parameters are insufficient. Please check Query API docs for required arguments.");
}
// Construct Query parameter args and URL string.
Map allQueryArgs = params.constructQueryArgs();
String urlString = formatBaseURL(params.getQueryType().toString());
URL url = new URL(urlString);
// post request and construct QueryResult.
Object postResult = postRequest(project, url, allQueryArgs);
QueryResult result = constructQueryResult(postResult, params.hasGroupBy(), params.hasInterval());
return result;
}
private static QueryResult constructQueryResult(Object input, boolean isGroupBy, boolean isInterval) {
QueryResult result = null;
// below code determines what type of object QueryResult holds.
if (input instanceof Integer) {
Integer intValue = (Integer) input;
result = new LongResult(intValue.longValue());
} else if (input instanceof Long) {
result = new LongResult((Long) input);
} else if (input instanceof Double) {
result = new DoubleResult((Double) input);
} else if (input instanceof String) {
result = new StringResult((String) input);
} else if (input instanceof List) {
// recursively construct the children of this...
List