package org.rakam.plugin;
import com.facebook.presto.sql.parser.ParsingException;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.Query;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.rakam.server.http.annotations.ApiParam;
import org.rakam.util.RakamException;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
public class ContinuousQuery
{
@JsonIgnore
private final static SqlParser SQL_PARSER = new SqlParser();
public final String query;
public final String name;
@JsonIgnore
public Query queryStatement;
public final String tableName;
public final List<String> partitionKeys;
public final Map<String, Object> options;
private final Optional<Duration> windowDuration;
@JsonCreator
public ContinuousQuery(@ApiParam(value = "table_name", description = "The table name of the continuous query that can be used when querying") String tableName,
@ApiParam(value = "name", description = "Name") String name,
@ApiParam(value = "query", description = "The sql query that will be executed and materialized") String query,
@ApiParam(value = "partition_keys", description = "Partition columns of the table", required = false) List<String> partitionKeys,
@ApiParam(value = "options", description = "Additional information about the continuous query", required = false) Map<String, Object> options,
@ApiParam(value = "windowDuration", required = false) Duration windowDuration)
throws ParsingException, IllegalArgumentException
{
this.name = checkNotNull(name, "name is required");
this.tableName = checkNotNull(tableName, "table_name is required");
this.options = options == null ? ImmutableMap.of() : options;
this.partitionKeys = partitionKeys == null ? ImmutableList.of() : partitionKeys;
this.query = query;
this.windowDuration = Optional.ofNullable(windowDuration);
if(windowDuration != null && this.partitionKeys.size() > 0) {
throw new IllegalArgumentException("Window duration cannot be used with partition keys");
}
}
public ContinuousQuery(
String tableName,
String name,
String query,
List<String> partitionKeys,
Map<String, Object> options)
throws ParsingException, IllegalArgumentException
{
this(tableName, name, query, partitionKeys, options, null);
}
@JsonIgnore
public synchronized Query getQuery()
{
if (queryStatement == null) {
try {
queryStatement = (Query) SQL_PARSER.createStatement(checkNotNull(query, "query is required"));
}
catch (Exception e) {
throw new RakamException("Unable to parse continuous query: " + e.getMessage(),
HttpResponseStatus.BAD_REQUEST);
}
}
return queryStatement;
}
@JsonProperty("table_name")
public String getTableName()
{
return tableName;
}
@JsonProperty("partition_keys")
public List<String> getPartitionKeys()
{
return partitionKeys;
}
@JsonProperty("options")
public Map<String, Object> getOptions()
{
return options;
}
@JsonProperty("name")
public String getName()
{
return name;
}
@JsonProperty("windowDuration")
public Duration getWindowDuration()
{
return windowDuration.orElse(null);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (!(o instanceof ContinuousQuery)) {
return false;
}
ContinuousQuery that = (ContinuousQuery) o;
if (!query.equals(that.query)) {
return false;
}
if (!tableName.equals(that.tableName)) {
return false;
}
if (partitionKeys != null ? !partitionKeys.equals(that.partitionKeys) : that.partitionKeys != null) {
return false;
}
return !(options != null ? !options.equals(that.options) : that.options != null);
}
@Override
public int hashCode()
{
int result = query.hashCode();
result = 31 * result + tableName.hashCode();
result = 31 * result + (partitionKeys != null ? partitionKeys.hashCode() : 0);
result = 31 * result + (options != null ? options.hashCode() : 0);
return result;
}
}