package org.yaac.server.egql.evaluator;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Sets.newHashSet;
import java.util.Set;
import org.yaac.server.egql.EntityProperty;
import org.yaac.server.egql.evaluator.aggregator.Aggregator;
import org.yaac.server.egql.evaluator.aggregator.AvgAggregator;
import org.yaac.server.egql.evaluator.aggregator.CountAggregator;
import org.yaac.server.egql.evaluator.aggregator.MaxAggregator;
import org.yaac.server.egql.evaluator.aggregator.MinAggregator;
import org.yaac.server.egql.evaluator.aggregator.SumAggregator;
import org.yaac.server.egql.exception.EGQLE004Exception;
import org.yaac.server.egql.exception.EGQLException;
import org.yaac.server.egql.processor.ProcessData.ProcessDataRecord;
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
public class AggregationEvaluator extends Evaluator {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* aggregation types
*
* @author Max Zhu (thebbsky@gmail.com)
*
*/
public enum Type {
COUNT(CountAggregator.class),
SUM(SumAggregator.class),
AVG(AvgAggregator.class),
MAX(MaxAggregator.class),
MIN(MinAggregator.class);
Class<? extends Aggregator> clazz;
private Type(Class<? extends Aggregator> clazz) {
this.clazz = clazz;
}
public Aggregator newAggregator() {
try {
return this.clazz.newInstance();
} catch (InstantiationException e) {
// should not happen, as covered by test case
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
// should not happen, as covered by test case
e.printStackTrace();
return null;
}
}
}
private final Evaluator op;
private Type type;
public AggregationEvaluator(String type, Evaluator op) {
checkArgument(!isNullOrEmpty(type), "Aggregation name is mandatory");
for (Type t : Type.values()) {
if (t.toString().equals(type.toUpperCase())) {
this.type = t;
break;
}
}
checkNotNull(this.type, "Invalid aggregation name : " + type);
this.op = op;
}
public Type getType() {
return type;
}
@Override
public EvaluationResult evaluate(ProcessDataRecord record) {
return record.lookup(this.getText());
}
public void aggregate(ProcessDataRecord record, Aggregator agg) {
EvaluationResult result = op.evaluate(record);
agg.aggregate(result);
}
/**
* init new aggregator with emtpy value
*
* @param context
* @return
*/
@Deprecated
public Aggregator newAggregator() {
switch (this.type) {
case COUNT:
// COUNT will only count those records in which the field in the brackets is NOT NULL.
return new CountAggregator();
case MAX:
return new MaxAggregator();
case MIN:
return new MinAggregator();
case AVG:
return new AvgAggregator();
case SUM:
return new SumAggregator();
default:
throw new IllegalArgumentException("Unsupported aggregation aggregation type : " + this.type);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((op == null) ? 0 : op.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
AggregationEvaluator other = (AggregationEvaluator) obj;
if (op == null) {
if (other.op != null)
return false;
} else if (!op.equals(other.op))
return false;
if (type != other.type)
return false;
return true;
}
@Override
public String toString() {
return "AggregationEvaluator [op=" + op + ", type=" + type + "]";
}
@Override
public Set<AggregationEvaluator> aggregationChildren() {
// it is possible that aggregation function is nested
Set<AggregationEvaluator> result = newHashSet(op.aggregationChildren());
result.add(this);
return result;
}
@Override
public Set<EntityProperty> nonAggregationProperties() {
return newHashSet();
}
@Override
public void validate() throws EGQLException {
if (!op.aggregationChildren().isEmpty()) {
// at the moment Yaac does not support nested aggregation function
throw new EGQLE004Exception();
}
}
}