AggregationOperation (common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/aggregate/AggregationOperation.scala) has no test coverage today. It is the type that backs every aggregate operator's runtime: result-column typing, type-validation, and the per-kind DistributedAggregation (init/iterate/merge/finalAgg) all live here.
Add a AggregationOperationSpec that pins:
getAggregationAttribute per kind: SUM/MIN/MAX preserve the input type, COUNT → INTEGER, AVERAGE → DOUBLE, CONCAT → STRING; null aggFunction throws.
getAggFunc validation: SUM/MIN/MAX throw UnsupportedOperationException for non-numeric types; null aggFunction throws.
getAggFunc semantics for SUM, COUNT, AVERAGE, CONCAT: init values, iterate accumulation (including null/null-attribute differences for COUNT), merge of partials, and finalAgg projection (including the "average of zero values is null" rule).
getFinal: COUNT → SUM over the result column; non-COUNT aggregations keep their kind but rebind attribute → resultAttribute.
AggregationOperation(common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/aggregate/AggregationOperation.scala) has no test coverage today. It is the type that backs every aggregate operator's runtime: result-column typing, type-validation, and the per-kindDistributedAggregation(init/iterate/merge/finalAgg) all live here.Add a
AggregationOperationSpecthat pins:getAggregationAttributeper kind: SUM/MIN/MAX preserve the input type, COUNT → INTEGER, AVERAGE → DOUBLE, CONCAT → STRING; null aggFunction throws.getAggFuncvalidation: SUM/MIN/MAX throwUnsupportedOperationExceptionfor non-numeric types; null aggFunction throws.getAggFuncsemantics for SUM, COUNT, AVERAGE, CONCAT: init values, iterate accumulation (including null/null-attribute differences for COUNT), merge of partials, and finalAgg projection (including the "average of zero values is null" rule).getFinal: COUNT → SUM over the result column; non-COUNT aggregations keep their kind but rebind attribute → resultAttribute.