=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java 2013-01-24 04:15:05 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java 2013-01-27 20:34:47 +0000 @@ -330,7 +330,7 @@ */ public PeriodType getPeriodType() { - return dataSets != null && dataSets.size() > 0 ? dataSets.iterator().next().getPeriodType() : null; + return dataSets != null && !dataSets.isEmpty() ? dataSets.iterator().next().getPeriodType() : null; } /** === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroup.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroup.java 2012-06-01 11:35:55 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroup.java 2013-01-27 20:34:47 +0000 @@ -40,6 +40,7 @@ import org.hisp.dhis.common.annotation.Scanned; import org.hisp.dhis.common.view.DetailedView; import org.hisp.dhis.common.view.ExportView; +import org.hisp.dhis.period.PeriodType; import java.util.HashSet; import java.util.Set; @@ -120,6 +121,33 @@ addDataElement( dataElement ); } } + + /** + * Returns the value type of the data elements in this group. Uses an arbitrary + * member to determine the value type. + */ + public String getValueType() + { + return members != null && !members.isEmpty() ? members.iterator().next().getType() : null; + } + + /** + * Returns the aggregation operator of the data elements in this group. Uses + * an arbitrary member to determine the aggregation operator. + */ + public String getAggregationOperator() + { + return members != null && !members.isEmpty() ? members.iterator().next().getAggregationOperator() : null; + } + + /** + * Returns the period type of the data elements in this group. Uses an + * arbitrary member to determine the period type. + */ + public PeriodType getPeriodType() + { + return members != null && !members.isEmpty() ? members.iterator().next().getPeriodType() : null; + } // ------------------------------------------------------------------------- // hashCode and equals === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2013-01-27 14:20:01 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2013-01-27 20:34:47 +0000 @@ -705,6 +705,26 @@ setDimensionOptions( ORGUNIT_DIM_ID, DimensionType.ORGANISATIONUNIT, organisationUnits ); } + public List getDataElementGroupSets() + { + List list = new ArrayList(); + + for ( Dimension dimension : dimensions ) + { + if ( DimensionType.DATAELEMENT_GROUPSET.equals( dimension.getType() ) ) + { + list.add( dimension ); + } + } + + return list; + } + + public void setDataElementGroupSet( Dimension dimension, List dataElementGroups ) + { + setDimensionOptions( dimension.getDimension(), DimensionType.DATAELEMENT_GROUPSET, dataElementGroups ); + } + // ------------------------------------------------------------------------- // Get and set helpers for filters // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2013-01-27 14:20:01 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2013-01-27 20:34:47 +0000 @@ -27,10 +27,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import static org.hisp.dhis.analytics.AggregationType.*; +import static org.hisp.dhis.analytics.AggregationType.AVERAGE_BOOL; +import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT_AGGREGATION; +import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT_DISAGGREGATION; +import static org.hisp.dhis.analytics.AggregationType.SUM; +import static org.hisp.dhis.analytics.DataQueryParams.ORGUNIT_DIM_ID; +import static org.hisp.dhis.analytics.DataQueryParams.PERIOD_DIM_ID; import static org.hisp.dhis.dataelement.DataElement.AGGREGATION_OPERATOR_AVERAGE; import static org.hisp.dhis.dataelement.DataElement.AGGREGATION_OPERATOR_SUM; -import static org.hisp.dhis.analytics.DataQueryParams.*; +import static org.hisp.dhis.dataelement.DataElement.VALUE_TYPE_BOOL; import java.util.ArrayList; import java.util.Collection; @@ -44,6 +49,7 @@ import org.hisp.dhis.analytics.table.PartitionUtils; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementGroup; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.period.Period; @@ -295,33 +301,58 @@ * higher or equal frequency than the aggregation period type. Average disaggregation * means that the data elements have the average aggregation operator and * that the period type of the data elements have lower frequency than the - * aggregation period type. + * aggregation period type. Average bool means that the data elements have the + * average aggregation operator and the bool value type. + * + * The query is grouped on data elements if any exists, then on data element + * group sets if any exists. In the case where multiple data element group + * sets exists, the query will be grouped on the data element groups of the + * first group set found. A constraint for data element groups is that they + * must contain data elements with equal aggregation type. Hence it is not + * meaningful to split on multiple data element group sets. */ private List groupByAggregationType( DataQueryParams params ) { List queries = new ArrayList(); - - if ( params.getDataElements() == null || params.getDataElements().isEmpty() ) - { - queries.add( new DataQueryParams( params ) ); - return queries; - } - PeriodType periodType = PeriodType.getPeriodTypeByName( params.getPeriodType() ); - - ListMap aggregationTypeDataElementMap = getAggregationTypeDataElementMap( params.getDataElements(), periodType ); - - for ( AggregationType aggregationType : aggregationTypeDataElementMap.keySet() ) - { - DataQueryParams query = new DataQueryParams( params ); - query.setDataElements( aggregationTypeDataElementMap.get( aggregationType ) ); - query.setAggregationType( aggregationType ); - queries.add( query ); + if ( params.getDataElements() != null && !params.getDataElements().isEmpty() ) + { + PeriodType periodType = PeriodType.getPeriodTypeByName( params.getPeriodType() ); + + ListMap aggregationTypeDataElementMap = getAggregationTypeDataElementMap( params.getDataElements(), periodType ); + + for ( AggregationType aggregationType : aggregationTypeDataElementMap.keySet() ) + { + DataQueryParams query = new DataQueryParams( params ); + query.setDataElements( aggregationTypeDataElementMap.get( aggregationType ) ); + query.setAggregationType( aggregationType ); + queries.add( query ); + } + } + else if ( params.getDataElementGroupSets() != null && !params.getDataElementGroupSets().isEmpty() ) + { + Dimension groupSet = params.getDataElementGroupSets().iterator().next(); + + PeriodType periodType = PeriodType.getPeriodTypeByName( params.getPeriodType() ); + + ListMap aggregationTypeDataElementGroupMap = getAggregationTypeDataElementGroupMap( groupSet.getOptions(), periodType ); + + for ( AggregationType aggregationType : aggregationTypeDataElementGroupMap.keySet() ) + { + DataQueryParams query = new DataQueryParams( params ); + query.setDataElementGroupSet( groupSet, aggregationTypeDataElementGroupMap.get( aggregationType ) ); + query.setAggregationType( aggregationType ); + queries.add( query ); + } + } + else + { + queries.add( new DataQueryParams( params ) ); } return queries; } - + /** * Groups the given query in sub queries based on the period type of its * data elements. Sets the data period type on each query. @@ -450,7 +481,7 @@ return map; } - + /** * Creates a mapping between the aggregation type and data element for the * given data elements and period type. @@ -462,34 +493,60 @@ for ( IdentifiableObject element : dataElements ) { DataElement dataElement = (DataElement) element; - - if ( AGGREGATION_OPERATOR_SUM.equals( dataElement.getAggregationOperator() ) ) + + putByAggregationType( map, dataElement.getType(), dataElement.getAggregationOperator(), dataElement, aggregationPeriodType, dataElement.getPeriodType() ); + } + + return map; + } + + /** + * Creates a mapping between the aggregation type and data element for the + * given data elements and period type. + */ + private ListMap getAggregationTypeDataElementGroupMap( Collection dataElementGroups, PeriodType aggregationPeriodType ) + { + ListMap map = new ListMap(); + + for ( IdentifiableObject element : dataElementGroups ) + { + DataElementGroup group = (DataElementGroup) element; + + putByAggregationType( map, group.getValueType(), group.getAggregationOperator(), group, aggregationPeriodType, group.getPeriodType() ); + } + + return map; + } + + /** + * Puts the given element into the map according to the value type, aggregation + * operator, aggregation period type and data period type. + */ + private void putByAggregationType( ListMap map, String valueType, String aggregationOperator, + IdentifiableObject element, PeriodType aggregationPeriodType, PeriodType dataPeriodType ) + { + if ( AGGREGATION_OPERATOR_SUM.equals( aggregationOperator ) ) + { + map.putValue( SUM, element ); + } + else if ( AGGREGATION_OPERATOR_AVERAGE.equals( aggregationOperator ) ) + { + if ( VALUE_TYPE_BOOL.equals( valueType ) ) { - map.putValue( SUM, element ); + map.putValue( AVERAGE_BOOL, element ); } - else if ( AGGREGATION_OPERATOR_AVERAGE.equals( dataElement.getAggregationOperator() ) ) + else { - if ( DataElement.VALUE_TYPE_BOOL.equals( dataElement.getType() ) ) + if ( dataPeriodType == null || aggregationPeriodType.getFrequencyOrder() >= dataPeriodType.getFrequencyOrder() ) { - map.putValue( AVERAGE_BOOL, element ); + map.putValue( AVERAGE_INT_AGGREGATION, element ); } else { - PeriodType dataPeriodType = dataElement.getPeriodType(); - - if ( dataPeriodType == null || aggregationPeriodType.getFrequencyOrder() >= dataPeriodType.getFrequencyOrder() ) - { - map.putValue( AVERAGE_INT_AGGREGATION, element ); - } - else - { - map.putValue( AVERAGE_INT_DISAGGREGATION, element ); - } + map.putValue( AVERAGE_INT_DISAGGREGATION, element ); } } } - - return map; } /**