// since final results are generated from group by table
groupByRecords.add(groupByRecord(record));
// step 2 : evaluate all aggregation functions
for (AggregationEvaluator e : aggregationEvaluators) {
Aggregator agg = lookupAggregator(record, e);
if (agg == null) {
// new aggregator
agg = e.getType().newAggregator();
// push back to context
putAggregator(record, e, agg);
}
e.aggregate(record, agg);
}
} else { // write result to output
final Map<String, EvaluationResult> resultRow = newLinkedHashMap();
for (Evaluator e : selectItems) {
resultRow.put(e.getText(), e.evaluate(record));
}
output.addRecord(new ProcessDataRecord() {
Map<String, EvaluationResult> expandedRow = expandSelectAllAndResolveDuplicateName(resultRow);
@Override
public EvaluationResult lookup(String name) {
return expandedRow.get(name);
}
@Override
public Iterable<EvaluationResult> asIterable() {
return expandedRow.values();
}
@Override
public FileDownloadPath lookupFileReference(Integer index) {
throw new IllegalArgumentException();
}
});
}
}
// last batch finished, append group by clause
if (context.getStatus() == ResultStatus.FINISHED) {
// if a statement is finished, then append all group by results
for (final Map<String, Object> rowKey : this.groupByRecords) {
ProcessDataRecord record = new ProcessDataRecord() {
@Override
public EvaluationResult lookup(String name) {
// must resolve aggregators first, because count(1) is a valid property name in appengine
Map<AggregationEvaluator, Aggregator> aggMap = groupByTable.row(rowKey);
for (AggregationEvaluator e : aggMap.keySet()) {
if (e.getText().equals(name)) {
Aggregator agg = aggMap.get(e);
if (agg == null) {
// for aggregation ONLY query
// when there is no record, the empty group by function is still trying to resolve aggregator
return new EvaluationResult(null).withTitle(e.getText());
} else {
return new EvaluationResult(agg.getResult()).withTitle(e.getText());
}
}
}
// fallback with other evaluators