diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/handler/DataHandler.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/handler/DataHandler.java
index 91973503f301..a8a6eb5c7f19 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/handler/DataHandler.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/handler/DataHandler.java
@@ -129,8 +129,8 @@
import org.hisp.dhis.analytics.QueryPlannerParams;
import org.hisp.dhis.analytics.RawAnalyticsManager;
import org.hisp.dhis.analytics.analyze.ExecutionPlanStore;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.data.EventAggregateService;
import org.hisp.dhis.analytics.resolver.ExpressionResolver;
import org.hisp.dhis.analytics.resolver.ExpressionResolvers;
import org.hisp.dhis.analytics.util.PeriodOffsetUtils;
@@ -171,7 +171,7 @@ public class DataHandler {
private static final int PERCENT = 100;
- private final EventAnalyticsService eventAnalyticsService;
+ private final EventAggregateService eventAggregatedService;
private final RawAnalyticsManager rawAnalyticsManager;
@@ -428,7 +428,7 @@ public void addProgramDataElementAttributeIndicatorValues(DataQueryParams params
.withSkipMeta(true)
.build();
- Grid eventGrid = eventAnalyticsService.getAggregatedEventData(eventQueryParams);
+ Grid eventGrid = eventAggregatedService.getAggregatedData(eventQueryParams);
grid.addRows(eventGrid);
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EnrollmentAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EnrollmentAnalyticsService.java
deleted file mode 100644
index 0190f1eb97be..000000000000
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EnrollmentAnalyticsService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2004-2022, University of Oslo
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * Neither the name of the HISP project nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.hisp.dhis.analytics.event;
-
-import org.hisp.dhis.common.Grid;
-
-/**
- * This interface is responsible for retrieving aggregated event data. Data will be returned in a
- * grid object or as a dimensional key-value mapping.
- *
- * @author Markus Bekken
- */
-public interface EnrollmentAnalyticsService {
-
- /**
- * Returns a list of enrollments matching the given query.
- *
- * @param params the envent query parameters.
- * @return enrollments with event data as a Grid object.
- */
- Grid getEnrollments(EventQueryParams params);
-}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java
deleted file mode 100644
index 3f4794718a15..000000000000
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2004-2022, University of Oslo
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * Neither the name of the HISP project nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.hisp.dhis.analytics.event;
-
-import java.util.List;
-import org.hisp.dhis.analytics.AnalyticsMetaDataKey;
-import org.hisp.dhis.analytics.Rectangle;
-import org.hisp.dhis.common.AnalyticalObject;
-import org.hisp.dhis.common.Grid;
-
-/**
- * This interface is responsible for retrieving aggregated event data. Data will be returned in a
- * grid object or as a dimensional key-value mapping.
- *
- * @author Lars Helge Overland
- */
-public interface EventAnalyticsService {
-
- /**
- * Generates aggregated event data for the given query.
- *
- * @param params the event query parameters.
- * @return aggregated event data as a Grid object.
- */
- Grid getAggregatedEventData(EventQueryParams params);
-
- /**
- * Generates an aggregated value grid for the given query. The grid will represent a table with
- * dimensions used as columns and rows as specified in columns and rows dimension arguments. If
- * columns and rows are null or empty, the normalized table will be returned.
- *
- *
If meta data is included in the query, the meta data map of the grid will contain keys
- * described in {@link AnalyticsMetaDataKey}.
- *
- * @param params the event query parameters.
- * @param columns the identifiers of the dimensions to use as columns.
- * @param rows the identifiers of the dimensions to use as rows.
- * @return aggregated data as a Grid object.
- */
- Grid getAggregatedEventData(EventQueryParams params, List columns, List rows)
- throws Exception;
-
- /**
- * Generates aggregated event data for the given analytical object.
- *
- * @param params the event query parameters.
- * @return aggregated event data as a Grid object.
- */
- Grid getAggregatedEventData(AnalyticalObject params);
-
- /**
- * Returns a list of events matching the given query.
- *
- * @param params the event query parameters.
- * @return events as a Grid object.
- */
- Grid getEvents(EventQueryParams params);
-
- /**
- * Returns a list of event clusters matching the given query.
- *
- * @param params the event query parameters.
- * @return event clusters as a Grid object.
- */
- Grid getEventClusters(EventQueryParams params);
-
- /**
- * Returns a Rectangle with information about event count and extent of the spatial rectangle for
- * the given query.
- *
- * @param params the event query parameters.
- * @return event clusters as a Grid object.
- */
- Rectangle getRectangle(EventQueryParams params);
-}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java
deleted file mode 100644
index 0f1588971b61..000000000000
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
- * Copyright (c) 2004-2022, University of Oslo
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * Neither the name of the HISP project nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.hisp.dhis.analytics.event.data;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.DIMENSIONS;
-import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.ITEMS;
-import static org.hisp.dhis.analytics.DataQueryParams.DENOMINATOR_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.DENOMINATOR_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.DIVISOR_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.DIVISOR_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.FACTOR_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.FACTOR_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.MULTIPLIER_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.MULTIPLIER_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.NUMERATOR_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.NUMERATOR_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.VALUE_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID;
-import static org.hisp.dhis.analytics.common.ColumnHeader.CREATED_BY_DISPLAY_NAME;
-import static org.hisp.dhis.analytics.common.ColumnHeader.ENROLLMENT_DATE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT;
-import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT_DATE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT_STATUS;
-import static org.hisp.dhis.analytics.common.ColumnHeader.GEOMETRY;
-import static org.hisp.dhis.analytics.common.ColumnHeader.INCIDENT_DATE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.LAST_UPDATED;
-import static org.hisp.dhis.analytics.common.ColumnHeader.LAST_UPDATED_BY_DISPLAY_NAME;
-import static org.hisp.dhis.analytics.common.ColumnHeader.LATITUDE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.LONGITUDE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_CODE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_NAME;
-import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_NAME_HIERARCHY;
-import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_INSTANCE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_STAGE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_STATUS;
-import static org.hisp.dhis.analytics.common.ColumnHeader.SCHEDULED_DATE;
-import static org.hisp.dhis.analytics.common.ColumnHeader.STORED_BY;
-import static org.hisp.dhis.analytics.common.ColumnHeader.TRACKED_ENTITY;
-import static org.hisp.dhis.analytics.event.LabelMapper.getEnrollmentDateLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getEventDateLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getEventLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getIncidentDateLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getOrgUnitLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getProgramStageLabel;
-import static org.hisp.dhis.analytics.event.LabelMapper.getScheduledDateLabel;
-import static org.hisp.dhis.analytics.util.AnalyticsUtils.throwIllegalQueryEx;
-import static org.hisp.dhis.common.DimensionalObject.CATEGORYOPTIONCOMBO_DIM_ID;
-import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID;
-import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID;
-import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID;
-import static org.hisp.dhis.common.ValueType.BOOLEAN;
-import static org.hisp.dhis.common.ValueType.DATETIME;
-import static org.hisp.dhis.common.ValueType.NUMBER;
-import static org.hisp.dhis.common.ValueType.TEXT;
-
-import com.google.common.base.Preconditions;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.lang3.StringUtils;
-import org.hisp.dhis.analytics.AnalyticsSecurityManager;
-import org.hisp.dhis.analytics.DataQueryParams;
-import org.hisp.dhis.analytics.EventAnalyticsDimensionalItem;
-import org.hisp.dhis.analytics.Rectangle;
-import org.hisp.dhis.analytics.cache.AnalyticsCache;
-import org.hisp.dhis.analytics.common.ColumnHeader;
-import org.hisp.dhis.analytics.common.scheme.SchemeInfo;
-import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
-import org.hisp.dhis.analytics.event.EventAnalyticsManager;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
-import org.hisp.dhis.analytics.event.EventAnalyticsUtils;
-import org.hisp.dhis.analytics.event.EventDataQueryService;
-import org.hisp.dhis.analytics.event.EventQueryParams;
-import org.hisp.dhis.analytics.event.EventQueryPlanner;
-import org.hisp.dhis.analytics.event.EventQueryValidator;
-import org.hisp.dhis.analytics.util.AnalyticsUtils;
-import org.hisp.dhis.common.AnalyticalObject;
-import org.hisp.dhis.common.DimensionalObject;
-import org.hisp.dhis.common.EventAnalyticalObject;
-import org.hisp.dhis.common.Grid;
-import org.hisp.dhis.common.GridHeader;
-import org.hisp.dhis.common.IdentifiableObjectUtils;
-import org.hisp.dhis.common.MetadataItem;
-import org.hisp.dhis.common.QueryItem;
-import org.hisp.dhis.common.ValueType;
-import org.hisp.dhis.common.ValueTypedDimensionalItemObject;
-import org.hisp.dhis.commons.collection.ListUtils;
-import org.hisp.dhis.dataelement.DataElementService;
-import org.hisp.dhis.feedback.ErrorCode;
-import org.hisp.dhis.legend.Legend;
-import org.hisp.dhis.option.Option;
-import org.hisp.dhis.system.database.DatabaseInfoProvider;
-import org.hisp.dhis.system.grid.ListGrid;
-import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;
-import org.hisp.dhis.user.UserService;
-import org.hisp.dhis.util.Timer;
-import org.springframework.stereotype.Service;
-
-/**
- * @author Lars Helge Overland
- */
-@Service("org.hisp.dhis.analytics.event.EventAnalyticsService")
-public class DefaultEventAnalyticsService extends AbstractAnalyticsService
- implements EventAnalyticsService {
- private static final String DASH_PRETTY_SEPARATOR = " - ";
-
- private static final String SPACE = " ";
-
- private static final String TOTAL_COLUMN_PRETTY_NAME = "Total";
-
- private static final Map COLUMN_NAMES =
- Map.of(
- DATA_X_DIM_ID, "data",
- CATEGORYOPTIONCOMBO_DIM_ID, "categoryoptioncombo",
- PERIOD_DIM_ID, "period",
- ORGUNIT_DIM_ID, "organisationunit");
-
- private static final Option OPT_TRUE = new Option("Yes", "1");
-
- private static final Option OPT_FALSE = new Option("No", "0");
-
- private final DataElementService dataElementService;
-
- private final TrackedEntityAttributeService trackedEntityAttributeService;
-
- private final EventAnalyticsManager eventAnalyticsManager;
-
- private final EnrollmentAnalyticsManager enrollmentAnalyticsManager;
-
- private final EventDataQueryService eventDataQueryService;
-
- private final EventQueryPlanner queryPlanner;
-
- private final boolean spatialSupport;
-
- private final AnalyticsCache analyticsCache;
-
- public DefaultEventAnalyticsService(
- DataElementService dataElementService,
- TrackedEntityAttributeService trackedEntityAttributeService,
- EventAnalyticsManager eventAnalyticsManager,
- EventDataQueryService eventDataQueryService,
- AnalyticsSecurityManager securityManager,
- EventQueryPlanner queryPlanner,
- EventQueryValidator queryValidator,
- DatabaseInfoProvider databaseInfoProvider,
- AnalyticsCache analyticsCache,
- EnrollmentAnalyticsManager enrollmentAnalyticsManager,
- SchemeIdResponseMapper schemeIdResponseMapper,
- UserService userService) {
- super(securityManager, queryValidator, schemeIdResponseMapper, userService);
-
- checkNotNull(dataElementService);
- checkNotNull(trackedEntityAttributeService);
- checkNotNull(eventAnalyticsManager);
- checkNotNull(eventDataQueryService);
- checkNotNull(queryPlanner);
- checkNotNull(databaseInfoProvider);
- checkNotNull(analyticsCache);
- checkNotNull(schemeIdResponseMapper);
-
- this.dataElementService = dataElementService;
- this.trackedEntityAttributeService = trackedEntityAttributeService;
- this.eventAnalyticsManager = eventAnalyticsManager;
- this.eventDataQueryService = eventDataQueryService;
- this.queryPlanner = queryPlanner;
- this.spatialSupport = databaseInfoProvider.getDatabaseInfo().isSpatialSupport();
- this.analyticsCache = analyticsCache;
- this.enrollmentAnalyticsManager = enrollmentAnalyticsManager;
- }
-
- // -------------------------------------------------------------------------
- // EventAnalyticsService implementation
- // -------------------------------------------------------------------------
-
- // TODO Use [longitude/latitude] format for event points
- // TODO Order event analytics tables on execution date to avoid default sort
- // TODO Sorting in queries
-
- @Override
- public Grid getAggregatedEventData(
- EventQueryParams params, List columns, List rows) {
- return AnalyticsUtils.isTableLayout(columns, rows)
- ? getAggregatedEventDataTableLayout(params, columns, rows)
- : getAggregatedEventData(params);
- }
-
- @Override
- public Grid getAggregatedEventData(AnalyticalObject object) {
- EventQueryParams params =
- eventDataQueryService.getFromAnalyticalObject((EventAnalyticalObject) object);
-
- return getAggregatedEventData(params);
- }
-
- @Override
- public Grid getAggregatedEventData(EventQueryParams params) {
- securityManager.decideAccessEventQuery(params);
- params = securityManager.withUserConstraints(params);
-
- queryValidator.validate(params);
-
- if (analyticsCache.isEnabled() && !params.analyzeOnly()) {
- EventQueryParams immutableParams = new EventQueryParams.Builder(params).build();
- return analyticsCache.getOrFetch(params, p -> getAggregatedEventDataGrid(immutableParams));
- }
-
- return getAggregatedEventDataGrid(params);
- }
-
- /**
- * Creates a grid with table layout for downloading event reports. The grid is dynamically made
- * from rows and columns input, which refers to the dimensions requested.
- *
- * For event reports each option for a dimension will be an {@link
- * EventAnalyticsDimensionalItem} and all permutations will be added to the grid.
- *
- * @param params the {@link EventQueryParams}.
- * @param columns the identifiers of the dimensions to use as columns.
- * @param rows the identifiers of the dimensions to use as rows.
- * @return aggregated data as a Grid object.
- */
- private Grid getAggregatedEventDataTableLayout(
- EventQueryParams params, List columns, List rows) {
- params.removeProgramIndicatorItems();
-
- Grid grid = getAggregatedEventData(params);
-
- ListUtils.removeEmptys(columns);
- ListUtils.removeEmptys(rows);
-
- Map> tableColumns = new LinkedHashMap<>();
-
- if (columns != null) {
- for (String dimension : columns) {
- addEventDataObjects(grid, params, tableColumns, dimension);
- }
- }
-
- Map> tableRows = new LinkedHashMap<>();
- List rowDimensions = new ArrayList<>();
-
- if (rows != null) {
- for (String dimension : rows) {
- rowDimensions.add(dimension);
- addEventDataObjects(grid, params, tableRows, dimension);
- }
- }
-
- List> rowPermutations =
- EventAnalyticsUtils.generateEventDataPermutations(tableRows);
-
- List> columnPermutations =
- EventAnalyticsUtils.generateEventDataPermutations(tableColumns);
-
- return generateOutputGrid(grid, params, rowPermutations, columnPermutations, rowDimensions);
- }
-
- /**
- * Generates an output grid for event analytics download based on input parameters.
- *
- * @param grid the result grid.
- * @param params the {@link EventQueryParams}.
- * @param rowPermutations the row permutations
- * @param columnPermutations the column permutations.
- * @param rowDimensions the row dimensions.
- * @return grid with table layout.
- */
- @SuppressWarnings("unchecked")
- private Grid generateOutputGrid(
- Grid grid,
- EventQueryParams params,
- List> rowPermutations,
- List> columnPermutations,
- List rowDimensions) {
- Grid outputGrid = new ListGrid();
- outputGrid.setTitle(IdentifiableObjectUtils.join(params.getFilterItems()));
-
- for (String row : rowDimensions) {
- MetadataItem metadataItem =
- (MetadataItem) ((Map) grid.getMetaData().get(ITEMS.getKey())).get(row);
-
- String name = StringUtils.defaultIfEmpty(metadataItem.getName(), row);
- String col = StringUtils.defaultIfEmpty(COLUMN_NAMES.get(row), row);
-
- outputGrid.addHeader(new GridHeader(name, col, ValueType.TEXT, false, true));
- }
-
- columnPermutations.forEach(
- permutation -> {
- StringBuilder builder = new StringBuilder();
-
- permutation.forEach(
- (key, value) -> {
- if (!key.equals(ORGUNIT_DIM_ID) && !key.equals(PERIOD_DIM_ID)) {
- builder.append(key).append(SPACE);
- }
- builder
- .append(value.getDisplayProperty(params.getDisplayProperty()))
- .append(DASH_PRETTY_SEPARATOR);
- });
-
- String display =
- builder.length() > 0
- ? builder.substring(0, builder.lastIndexOf(DASH_PRETTY_SEPARATOR))
- : TOTAL_COLUMN_PRETTY_NAME;
-
- outputGrid.addHeader(new GridHeader(display, display, ValueType.NUMBER, false, false));
- });
-
- for (Map rowCombination : rowPermutations) {
- outputGrid.addRow();
- List> ids = new ArrayList<>();
- Map displayObjects = new HashMap<>();
-
- boolean fillDisplayList = true;
-
- for (Map columnCombination : columnPermutations) {
- List idList = new ArrayList<>();
-
- boolean finalFillDisplayList = fillDisplayList;
- rowCombination.forEach(
- (key, value) -> {
- idList.add(value.toString());
-
- if (finalFillDisplayList) {
- displayObjects.put(value.getParentUid(), value);
- }
- });
-
- columnCombination.forEach((key, value) -> idList.add(value.toString()));
-
- ids.add(idList);
- fillDisplayList = false;
- }
-
- addValuesInOutputGrid(rowDimensions, outputGrid, displayObjects, params);
-
- EventAnalyticsUtils.addValues(ids, grid, outputGrid);
- }
-
- return getGridWithRows(grid, outputGrid);
- }
-
- /**
- * Returns a valid grid.
- *
- * @param grid the {@link Grid}.
- * @param outputGrid the output {@link Grid}.
- */
- private static Grid getGridWithRows(Grid grid, Grid outputGrid) {
- return outputGrid.getRows().isEmpty() ? grid : outputGrid;
- }
-
- /**
- * Adds values to the given output grid. Display objects are not empty if columns and rows are not
- * empty.
- *
- * @param rowDimensions the list of row dimensions.
- * @param grid the {@link Grid}.
- * @param displayObjects the map of display objects.
- * @param params the {@link EventQueryParams}.
- */
- private static void addValuesInOutputGrid(
- List rowDimensions,
- Grid grid,
- Map displayObjects,
- EventQueryParams params) {
- if (!displayObjects.isEmpty()) {
- rowDimensions.forEach(
- dimension ->
- grid.addValue(
- displayObjects.get(dimension).getDisplayProperty(params.getDisplayProperty())));
- }
- }
-
- /**
- * Puts elements into the mapping table. The elements are fetched from the query parameters.
- *
- * @param grid the {@link Grid}.
- * @param params the {@link EventQueryParams}.
- * @param table the map to add elements to.
- * @param dimension the dimension identifier.
- */
- private void addEventDataObjects(
- Grid grid,
- EventQueryParams params,
- Map> table,
- String dimension) {
- List objects =
- params.getEventReportDimensionalItemArrayExploded(dimension);
-
- if (objects.isEmpty()) {
- ValueTypedDimensionalItemObject eventDimensionalItemObject =
- dataElementService.getDataElement(dimension);
-
- if (eventDimensionalItemObject == null) {
- eventDimensionalItemObject =
- trackedEntityAttributeService.getTrackedEntityAttribute(dimension);
- }
-
- addEventReportDimensionalItems(eventDimensionalItemObject, objects, grid, dimension);
-
- table.put(
- eventDimensionalItemObject.getDisplayProperty(params.getDisplayProperty()), objects);
- } else {
- table.put(dimension, objects);
- }
- }
-
- /**
- * Adds dimensional items to the given list of objects. Send in a list of {@link
- * EventAnalyticsDimensionalItem} and add properties from {@link ValueTypedDimensionalItemObject}
- * parameter.
- *
- * @param eventDimensionalItemObject the {@link ValueTypedDimensionalItemObject} object to get
- * properties from.
- * @param objects the list of {@link EventAnalyticsDimensionalItem} objects.
- * @param grid the {@link Grid} from the event analytics request.
- * @param dimension the dimension identifier.
- */
- @SuppressWarnings("unchecked")
- private void addEventReportDimensionalItems(
- ValueTypedDimensionalItemObject eventDimensionalItemObject,
- List objects,
- Grid grid,
- String dimension) {
- Preconditions.checkNotNull(
- eventDimensionalItemObject, String.format("Data dimension '%s' is invalid", dimension));
-
- String parentUid = eventDimensionalItemObject.getUid();
-
- if (eventDimensionalItemObject.getValueType() == BOOLEAN) {
- objects.add(new EventAnalyticsDimensionalItem(OPT_TRUE, parentUid));
- objects.add(new EventAnalyticsDimensionalItem(OPT_FALSE, parentUid));
- }
-
- if (eventDimensionalItemObject.hasOptionSet()) {
- for (Option option : eventDimensionalItemObject.getOptionSet().getOptions()) {
- objects.add(new EventAnalyticsDimensionalItem(option, parentUid));
- }
- } else if (eventDimensionalItemObject.hasLegendSet()) {
- List legendOptions =
- (List)
- ((Map) grid.getMetaData().get(DIMENSIONS.getKey())).get(dimension);
-
- if (legendOptions.isEmpty()) {
- List legends = eventDimensionalItemObject.getLegendSet().getSortedLegends();
-
- for (Legend legend : legends) {
- for (int i = legend.getStartValue().intValue();
- i < legend.getEndValue().intValue();
- i++) {
- objects.add(
- new EventAnalyticsDimensionalItem(
- new Option(String.valueOf(i), String.valueOf(i)), parentUid));
- }
- }
- } else {
- for (String legend : legendOptions) {
- MetadataItem metadataItem =
- (MetadataItem)
- ((Map) grid.getMetaData().get(ITEMS.getKey())).get(legend);
-
- objects.add(
- new EventAnalyticsDimensionalItem(
- new Option(metadataItem.getName(), legend), parentUid));
- }
- }
- }
- }
-
- private Grid getAggregatedEventDataGrid(EventQueryParams params) {
- params.removeProgramIndicatorItems();
-
- Grid grid = new ListGrid();
-
- int maxLimit = queryValidator.getMaxLimit();
-
- // ---------------------------------------------------------------------
- // Headers and data
- // ---------------------------------------------------------------------
-
- if (!params.isSkipData() || params.analyzeOnly()) {
- // -----------------------------------------------------------------
- // Headers
- // -----------------------------------------------------------------
-
- if (params.isCollapseDataDimensions() || params.isAggregateData()) {
- grid.addHeader(
- new GridHeader(
- DimensionalObject.DATA_COLLAPSED_DIM_ID,
- DataQueryParams.DISPLAY_NAME_DATA_X,
- ValueType.TEXT,
- false,
- true));
- } else {
- for (QueryItem item : params.getItems()) {
- String displayProperty = item.getItem().getDisplayProperty(params.getDisplayProperty());
-
- grid.addHeader(
- new GridHeader(
- item.getItem().getUid(),
- displayProperty,
- item.getValueType(),
- false,
- true,
- item.getOptionSet(),
- item.getLegendSet()));
- }
- }
-
- for (DimensionalObject dimension : params.getDimensions()) {
- String displayProperty = dimension.getDisplayProperty(params.getDisplayProperty());
-
- grid.addHeader(
- new GridHeader(dimension.getDimension(), displayProperty, TEXT, false, true));
- }
-
- grid.addHeader(new GridHeader(VALUE_ID, VALUE_HEADER_NAME, NUMBER, false, false));
-
- if (params.isIncludeNumDen()) {
- grid.addHeader(new GridHeader(NUMERATOR_ID, NUMERATOR_HEADER_NAME, NUMBER, false, false))
- .addHeader(
- new GridHeader(DENOMINATOR_ID, DENOMINATOR_HEADER_NAME, NUMBER, false, false))
- .addHeader(new GridHeader(FACTOR_ID, FACTOR_HEADER_NAME, NUMBER, false, false))
- .addHeader(new GridHeader(MULTIPLIER_ID, MULTIPLIER_HEADER_NAME, NUMBER, false, false))
- .addHeader(new GridHeader(DIVISOR_ID, DIVISOR_HEADER_NAME, NUMBER, false, false));
- }
-
- // -----------------------------------------------------------------
- // Data
- // -----------------------------------------------------------------
-
- Timer timer = new Timer().start().disablePrint();
-
- List queries = queryPlanner.planAggregateQuery(params);
-
- timer.getSplitTime("Planned event query, got partitions: " + params.getPartitions());
-
- for (EventQueryParams query : queries) {
- // Query might be either an enrollment or event indicator
-
- if (query.hasEnrollmentProgramIndicatorDimension()) {
- enrollmentAnalyticsManager.getAggregatedEventData(query, grid, maxLimit);
- } else {
- eventAnalyticsManager.getAggregatedEventData(query, grid, maxLimit);
- }
- }
-
- timer.getTime("Got aggregated events");
-
- if (maxLimit > 0 && grid.getHeight() > maxLimit) {
- throwIllegalQueryEx(ErrorCode.E7128, maxLimit);
- }
-
- // -----------------------------------------------------------------
- // Limit and sort, done again due to potential multiple partitions
- // -----------------------------------------------------------------
-
- if (params.hasSortOrder() && grid.getHeight() > 0) {
- grid.sortGrid(1, params.getSortOrderAsInt());
- }
-
- if (params.hasLimit() && grid.getHeight() > params.getLimit()) {
- grid.limitGrid(params.getLimit());
- }
- }
-
- if (!params.isSkipMeta()) {
- SchemeInfo schemeInfo = new SchemeInfo(schemeSettings(params), schemeData(params));
- schemeIdResponseMapper.applyCustomIdScheme(schemeInfo, grid);
- }
-
- // ---------------------------------------------------------------------
- // Meta-ata
- // ---------------------------------------------------------------------
-
- addMetadata(params, grid);
-
- return grid;
- }
-
- // -------------------------------------------------------------------------
- // Query
- // -------------------------------------------------------------------------
-
- @Override
- public Grid getEvents(EventQueryParams params) {
- return getGrid(params);
- }
-
- @Override
- public Grid getEventClusters(EventQueryParams params) {
- if (!spatialSupport) {
- throwIllegalQueryEx(ErrorCode.E7218);
- }
-
- params =
- new EventQueryParams.Builder(params)
- .withGeometryOnly(true)
- .withStartEndDatesForPeriods()
- .build();
-
- securityManager.decideAccessEventQuery(params);
-
- queryValidator.validate(params);
-
- Grid grid = new ListGrid();
-
- // ---------------------------------------------------------------------
- // Headers
- // ---------------------------------------------------------------------
-
- grid.addHeader(
- new GridHeader(
- ColumnHeader.COUNT.getItem(), ColumnHeader.COUNT.getName(), NUMBER, false, false))
- .addHeader(
- new GridHeader(
- ColumnHeader.CENTER.getItem(), ColumnHeader.CENTER.getName(), TEXT, false, false))
- .addHeader(
- new GridHeader(
- ColumnHeader.EXTENT.getItem(), ColumnHeader.EXTENT.getName(), TEXT, false, false))
- .addHeader(
- new GridHeader(
- ColumnHeader.POINTS.getItem(), ColumnHeader.POINTS.getName(), TEXT, false, false));
-
- // ---------------------------------------------------------------------
- // Data
- // ---------------------------------------------------------------------
-
- params = queryPlanner.planEventQuery(params);
-
- eventAnalyticsManager.getEventClusters(params, grid, queryValidator.getMaxLimit());
-
- return grid;
- }
-
- @Override
- public Rectangle getRectangle(EventQueryParams params) {
- if (!spatialSupport) {
- throwIllegalQueryEx(ErrorCode.E7218);
- }
-
- params =
- new EventQueryParams.Builder(params)
- .withGeometryOnly(true)
- .withStartEndDatesForPeriods()
- .build();
-
- securityManager.decideAccessEventQuery(params);
-
- queryValidator.validate(params);
-
- params = queryPlanner.planEventQuery(params);
-
- return eventAnalyticsManager.getRectangle(params);
- }
-
- /**
- * Creates a grid with headers.
- *
- * @param params the {@link EventQueryParams}.
- */
- @Override
- protected Grid createGridWithHeaders(EventQueryParams params) {
- Grid grid = new ListGrid();
-
- grid.addHeader(
- new GridHeader(
- EVENT.getItem(),
- getEventLabel(params.getProgramStage(), EVENT.getName()),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(
- PROGRAM_STAGE.getItem(),
- getProgramStageLabel(params.getProgramStage(), PROGRAM_STAGE.getName()),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(
- EVENT_DATE.getItem(),
- getEventDateLabel(params.getProgramStage(), EVENT_DATE.getName()),
- DATETIME,
- false,
- true))
- .addHeader(new GridHeader(STORED_BY.getItem(), STORED_BY.getName(), TEXT, false, true))
- .addHeader(
- new GridHeader(
- CREATED_BY_DISPLAY_NAME.getItem(),
- CREATED_BY_DISPLAY_NAME.getName(),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(
- LAST_UPDATED_BY_DISPLAY_NAME.getItem(),
- LAST_UPDATED_BY_DISPLAY_NAME.getName(),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(LAST_UPDATED.getItem(), LAST_UPDATED.getName(), DATETIME, false, true))
- .addHeader(
- new GridHeader(
- SCHEDULED_DATE.getItem(),
- getScheduledDateLabel(params.getProgramStage(), SCHEDULED_DATE.getName()),
- DATETIME,
- false,
- true));
-
- if (params.getProgram().isRegistration()) {
- grid.addHeader(
- new GridHeader(
- ENROLLMENT_DATE.getItem(),
- getEnrollmentDateLabel(params.getProgram(), ENROLLMENT_DATE.getName()),
- DATETIME,
- false,
- true))
- .addHeader(
- new GridHeader(
- INCIDENT_DATE.getItem(),
- getIncidentDateLabel(params.getProgram(), INCIDENT_DATE.getName()),
- DATETIME,
- false,
- true))
- .addHeader(
- new GridHeader(TRACKED_ENTITY.getItem(), TRACKED_ENTITY.getName(), TEXT, false, true))
- .addHeader(
- new GridHeader(
- PROGRAM_INSTANCE.getItem(), PROGRAM_INSTANCE.getName(), TEXT, false, true));
- }
-
- grid.addHeader(new GridHeader(GEOMETRY.getItem(), GEOMETRY.getName(), TEXT, false, true))
- .addHeader(new GridHeader(LONGITUDE.getItem(), LONGITUDE.getName(), NUMBER, false, true))
- .addHeader(new GridHeader(LATITUDE.getItem(), LATITUDE.getName(), NUMBER, false, true))
- .addHeader(
- new GridHeader(
- ORG_UNIT_NAME.getItem(),
- getOrgUnitLabel(params.getProgram(), ORG_UNIT_NAME.getName()),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(
- ORG_UNIT_NAME_HIERARCHY.getItem(),
- ORG_UNIT_NAME_HIERARCHY.getName(),
- TEXT,
- false,
- true))
- .addHeader(
- new GridHeader(ORG_UNIT_CODE.getItem(), ORG_UNIT_CODE.getName(), TEXT, false, true))
- .addHeader(
- new GridHeader(PROGRAM_STATUS.getItem(), PROGRAM_STATUS.getName(), TEXT, false, true))
- .addHeader(
- new GridHeader(EVENT_STATUS.getItem(), EVENT_STATUS.getName(), TEXT, false, true));
-
- return grid;
- }
-
- /**
- * Adds event data to the given grid. Returns the number of events matching the given event query.
- *
- * @param grid the {@link Grid}.
- * @param params the {@link EventQueryParams}.
- * @return the count of events.
- */
- @Override
- protected long addData(Grid grid, EventQueryParams params) {
- Timer timer = new Timer().start().disablePrint();
-
- params = queryPlanner.planEventQuery(params);
-
- timer.getSplitTime("Planned event query, got partitions: " + params.getPartitions());
-
- long count = 0;
- EventQueryParams immutableParams = new EventQueryParams.Builder(params).build();
-
- if (params.getPartitions().hasAny() || params.isSkipPartitioning()) {
-
- eventAnalyticsManager.getEvents(immutableParams, grid, queryValidator.getMaxLimit());
-
- if (params.isPaging() && params.isTotalPages()) {
- count = eventAnalyticsManager.getEventCount(immutableParams);
- }
-
- timer.getTime("Got events " + grid.getHeight());
- }
-
- return count;
- }
-}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateService.java
new file mode 100644
index 000000000000..cf08987e7753
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateService.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2004-2022, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.event.data;
+
+import static org.hisp.dhis.analytics.DataQueryParams.VALUE_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID;
+import static org.hisp.dhis.analytics.tracker.HeaderHelper.addCommonHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.UNLIMITED_PAGING;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.addPaging;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.applyHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getDimensionsKeywords;
+import static org.hisp.dhis.common.DimensionType.PERIOD;
+import static org.hisp.dhis.common.ValueType.NUMBER;
+import static org.hisp.dhis.commons.util.TextUtils.EMPTY;
+
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.hisp.dhis.analytics.AnalyticsSecurityManager;
+import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.EventQueryPlanner;
+import org.hisp.dhis.analytics.event.EventQueryValidator;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
+import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
+import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.common.GridHeader;
+import org.hisp.dhis.system.grid.ListGrid;
+import org.hisp.dhis.util.Timer;
+import org.springframework.stereotype.Service;
+
+/** This service is responsible for retrieving aggregated enrollments data. */
+@Service
+@RequiredArgsConstructor
+public class EnrollmentAggregateService {
+
+ private final EnrollmentAnalyticsManager enrollmentAnalyticsManager;
+
+ private final EventQueryPlanner queryPlanner;
+
+ private final AnalyticsSecurityManager securityManager;
+
+ private final EventQueryValidator queryValidator;
+
+ private final MetadataItemsHandler metadataHandler;
+
+ private final SchemeIdHandler schemeIdHandler;
+
+ /**
+ * Returns the aggregated data related to enrollments, that matches the given query.
+ *
+ * @param params the {@link EventQueryParams} parameters.
+ * @return enrollments data as a {@link Grid} object.
+ */
+ public Grid getEnrollments(EventQueryParams params) {
+ // Check access/constraints.
+ securityManager.decideAccessEventQuery(params);
+ params = securityManager.withUserConstraints(params);
+
+ // Validate request.
+ queryValidator.validate(params);
+
+ List keywords = getDimensionsKeywords(params);
+ List periods = getPeriods(params);
+
+ // Set periods.
+ params = new EventQueryParams.Builder(params).withStartEndDatesForPeriods().build();
+
+ // Populate headers.
+ Grid grid = createGridWithHeaders();
+ addCommonHeaders(grid, params, periods);
+
+ // Add data.
+ if (!params.isSkipData() || params.analyzeOnly()) {
+ if (!periods.isEmpty()) {
+ params =
+ new EventQueryParams.Builder(params)
+ .withPeriods(periods.stream().flatMap(p -> p.getItems().stream()).toList(), EMPTY)
+ .build();
+ }
+
+ addData(grid, params);
+ }
+
+ // Set response info.
+ metadataHandler.addMetadata(grid, params, keywords);
+ schemeIdHandler.applyScheme(grid, params);
+
+ addPaging(params, UNLIMITED_PAGING, grid);
+ applyHeaders(grid, params);
+
+ return grid;
+ }
+
+ /**
+ * Creates a {@link Grid} object with default headers.
+ *
+ * @return the {@link Grid} with initial headers.
+ */
+ private Grid createGridWithHeaders() {
+ return new ListGrid()
+ .addHeader(new GridHeader(VALUE_ID, VALUE_HEADER_NAME, NUMBER, false, false));
+ }
+
+ /**
+ * Adds data into the given grid, based on the given params.
+ *
+ * @param grid {@link Grid}.
+ * @param params the {@link EventQueryParams}. @@param maxLimit the max number of records to
+ * retrieve.
+ */
+ private void addData(Grid grid, EventQueryParams params) {
+ Timer timer = new Timer().start().disablePrint();
+
+ List paramsList = queryPlanner.planAggregateQuery(params);
+
+ for (EventQueryParams queryParams : paramsList) {
+ timer.getSplitTime(
+ "Planned enrollment query, got partitions: " + queryParams.getPartitions());
+
+ int maxLimit =
+ params.isAggregatedEnrollments() ? UNLIMITED_PAGING : queryValidator.getMaxLimit();
+
+ enrollmentAnalyticsManager.getEnrollments(queryParams, grid, maxLimit);
+
+ timer.getTime("Got enrollments " + grid.getHeight());
+ }
+ }
+
+ private List getPeriods(EventQueryParams params) {
+ return params.getDimensions().stream().filter(d -> d.getDimensionType() == PERIOD).toList();
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentQueryService.java
similarity index 67%
rename from dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java
rename to dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentQueryService.java
index 6c786f54268c..376ff813652c 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EnrollmentQueryService.java
@@ -27,9 +27,6 @@
*/
package org.hisp.dhis.analytics.event.data;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.hisp.dhis.analytics.DataQueryParams.VALUE_HEADER_NAME;
-import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID;
import static org.hisp.dhis.analytics.common.ColumnHeader.CREATED_BY_DISPLAY_NAME;
import static org.hisp.dhis.analytics.common.ColumnHeader.ENROLLMENT;
import static org.hisp.dhis.analytics.common.ColumnHeader.ENROLLMENT_DATE;
@@ -49,72 +46,97 @@
import static org.hisp.dhis.analytics.event.LabelMapper.getEnrollmentLabel;
import static org.hisp.dhis.analytics.event.LabelMapper.getIncidentDateLabel;
import static org.hisp.dhis.analytics.event.LabelMapper.getOrgUnitLabel;
+import static org.hisp.dhis.analytics.tracker.HeaderHelper.addCommonHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.UNLIMITED_PAGING;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.addPaging;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.applyHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getDimensionsKeywords;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.setRowContextColumns;
import static org.hisp.dhis.common.ValueType.DATETIME;
import static org.hisp.dhis.common.ValueType.NUMBER;
import static org.hisp.dhis.common.ValueType.TEXT;
import java.util.List;
+import lombok.RequiredArgsConstructor;
import org.hisp.dhis.analytics.AnalyticsSecurityManager;
-import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsService;
import org.hisp.dhis.analytics.event.EventQueryParams;
import org.hisp.dhis.analytics.event.EventQueryPlanner;
import org.hisp.dhis.analytics.event.EventQueryValidator;
-import org.hisp.dhis.common.DimensionType;
-import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
+import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
import org.hisp.dhis.common.Grid;
import org.hisp.dhis.common.GridHeader;
-import org.hisp.dhis.common.RequestTypeAware;
import org.hisp.dhis.system.grid.ListGrid;
-import org.hisp.dhis.user.UserService;
import org.hisp.dhis.util.Timer;
import org.springframework.stereotype.Service;
-/**
- * @author Markus Bekken
- */
-@Service("org.hisp.dhis.analytics.event.EnrollmentAnalyticsService")
-public class DefaultEnrollmentAnalyticsService extends AbstractAnalyticsService
- implements EnrollmentAnalyticsService {
+/** This service is responsible for querying enrollments. */
+@Service
+@RequiredArgsConstructor
+public class EnrollmentQueryService {
private final EnrollmentAnalyticsManager enrollmentAnalyticsManager;
private final EventQueryPlanner queryPlanner;
- public DefaultEnrollmentAnalyticsService(
- EnrollmentAnalyticsManager enrollmentAnalyticsManager,
- AnalyticsSecurityManager securityManager,
- EventQueryPlanner queryPlanner,
- EventQueryValidator queryValidator,
- SchemeIdResponseMapper schemeIdResponseMapper,
- UserService userService) {
- super(securityManager, queryValidator, schemeIdResponseMapper, userService);
-
- checkNotNull(enrollmentAnalyticsManager);
- checkNotNull(queryPlanner);
- checkNotNull(schemeIdResponseMapper);
-
- this.enrollmentAnalyticsManager = enrollmentAnalyticsManager;
- this.queryPlanner = queryPlanner;
- }
+ private final AnalyticsSecurityManager securityManager;
+
+ private final EventQueryValidator queryValidator;
- // -------------------------------------------------------------------------
- // EventAnalyticsService implementation
- // -------------------------------------------------------------------------
+ private final MetadataItemsHandler metadataHandler;
- @Override
+ private final SchemeIdHandler schemeIdHandler;
+
+ /**
+ * Returns a list of enrollments matching the given query.
+ *
+ * @param params the {@link EventQueryParams} parameters.
+ * @return enrollments data as a {@link Grid} object.
+ */
public Grid getEnrollments(EventQueryParams params) {
- return getGrid(params);
- }
+ // Check access/constraints.
+ securityManager.decideAccessEventQuery(params);
+ params = securityManager.withUserConstraints(params);
+
+ // Validate request.
+ queryValidator.validate(params);
- @Override
- protected Grid createGridWithHeaders(EventQueryParams params) {
- if (params.getEndpointAction() == RequestTypeAware.EndpointAction.AGGREGATE) {
- return new ListGrid()
- .addHeader(new GridHeader(VALUE_ID, VALUE_HEADER_NAME, NUMBER, false, false));
+ List keywords = getDimensionsKeywords(params);
+
+ // Set periods.
+ params = new EventQueryParams.Builder(params).withStartEndDatesForPeriods().build();
+
+ // Populate headers.
+ Grid grid = createGridWithHeaders(params);
+ addCommonHeaders(grid, params, List.of());
+
+ // Add data.
+ long count = 0;
+
+ if (!params.isSkipData() || params.analyzeOnly()) {
+ count = addData(grid, params);
}
+ // Set response info.
+ metadataHandler.addMetadata(grid, params, keywords);
+ schemeIdHandler.applyScheme(grid, params);
+
+ addPaging(params, count, grid);
+ applyHeaders(grid, params);
+ setRowContextColumns(grid);
+
+ return grid;
+ }
+
+ /**
+ * Creates a {@link Grid} object with default headers.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @return the {@link Grid} with initial headers.
+ */
+ private Grid createGridWithHeaders(EventQueryParams params) {
return new ListGrid()
.addHeader(
new GridHeader(
@@ -179,45 +201,33 @@ protected Grid createGridWithHeaders(EventQueryParams params) {
new GridHeader(PROGRAM_STATUS.getItem(), PROGRAM_STATUS.getName(), TEXT, false, true));
}
- @Override
- protected long addData(Grid grid, EventQueryParams params) {
+ /**
+ * Adds data into the given grid, based on the given params.
+ *
+ * @param grid {@link Grid}.
+ * @param params the {@link EventQueryParams}. @@param maxLimit the max number of records to
+ * retrieve.
+ */
+ private long addData(Grid grid, EventQueryParams params) {
Timer timer = new Timer().start().disablePrint();
- List paramsList;
-
- if (params.getEndpointAction() == RequestTypeAware.EndpointAction.AGGREGATE) {
- paramsList = queryPlanner.planAggregateQuery(params);
- } else {
- paramsList = List.of(queryPlanner.planEnrollmentQuery(params));
- }
+ EventQueryParams queryParams = queryPlanner.planEnrollmentQuery(params);
long count = 0;
- for (EventQueryParams queryParams : paramsList) {
- timer.getSplitTime("Planned event query, got partitions: " + queryParams.getPartitions());
- if (queryParams.isTotalPages() && !params.isAggregatedEnrollments()) {
- count += enrollmentAnalyticsManager.getEnrollmentCount(queryParams);
- }
-
- // maxLimit == 0 means unlimited paging
- int maxLimit = params.isAggregatedEnrollments() ? 0 : queryValidator.getMaxLimit();
- enrollmentAnalyticsManager.getEnrollments(queryParams, grid, maxLimit);
+ timer.getSplitTime("Planned enrollment query, got partitions: " + queryParams.getPartitions());
- timer.getTime("Got enrollments " + grid.getHeight());
+ if (queryParams.isTotalPages()) {
+ count += enrollmentAnalyticsManager.getEnrollmentCount(queryParams);
}
- return count;
- }
+ int maxLimit =
+ params.isAggregatedEnrollments() ? UNLIMITED_PAGING : queryValidator.getMaxLimit();
- @Override
- protected List getPeriods(EventQueryParams params) {
- // for aggregated enrollments only
- if (!params.isAggregatedEnrollments()) {
- return List.of();
- }
+ enrollmentAnalyticsManager.getEnrollments(queryParams, grid, maxLimit);
- return params.getDimensions().stream()
- .filter(d -> d.getDimensionType() == DimensionType.PERIOD)
- .toList();
+ timer.getTime("Got enrollments " + grid.getHeight());
+
+ return count;
}
}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventAggregateService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventAggregateService.java
new file mode 100644
index 000000000000..39ba417dfbaf
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventAggregateService.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2004-2024, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.event.data;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
+import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.DIMENSIONS;
+import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.ITEMS;
+import static org.hisp.dhis.analytics.DataQueryParams.DENOMINATOR_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.DENOMINATOR_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_DATA_X;
+import static org.hisp.dhis.analytics.DataQueryParams.DIVISOR_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.DIVISOR_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.FACTOR_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.FACTOR_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.MULTIPLIER_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.MULTIPLIER_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.NUMERATOR_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.NUMERATOR_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.VALUE_HEADER_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID;
+import static org.hisp.dhis.analytics.event.EventAnalyticsUtils.addValues;
+import static org.hisp.dhis.analytics.event.EventAnalyticsUtils.generateEventDataPermutations;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.UNLIMITED_PAGING;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.addPaging;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getDimensionsKeywords;
+import static org.hisp.dhis.analytics.util.AnalyticsUtils.isTableLayout;
+import static org.hisp.dhis.analytics.util.AnalyticsUtils.throwIllegalQueryEx;
+import static org.hisp.dhis.common.DimensionalObject.CATEGORYOPTIONCOMBO_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.DATA_COLLAPSED_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID;
+import static org.hisp.dhis.common.IdentifiableObjectUtils.join;
+import static org.hisp.dhis.common.ValueType.BOOLEAN;
+import static org.hisp.dhis.common.ValueType.NUMBER;
+import static org.hisp.dhis.common.ValueType.TEXT;
+import static org.hisp.dhis.commons.collection.ListUtils.removeEmptys;
+import static org.hisp.dhis.feedback.ErrorCode.E7128;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.hisp.dhis.analytics.AnalyticsSecurityManager;
+import org.hisp.dhis.analytics.EventAnalyticsDimensionalItem;
+import org.hisp.dhis.analytics.cache.AnalyticsCache;
+import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
+import org.hisp.dhis.analytics.event.EventAnalyticsManager;
+import org.hisp.dhis.analytics.event.EventDataQueryService;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.EventQueryPlanner;
+import org.hisp.dhis.analytics.event.EventQueryValidator;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
+import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
+import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.common.EventAnalyticalObject;
+import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.common.GridHeader;
+import org.hisp.dhis.common.MetadataItem;
+import org.hisp.dhis.common.QueryItem;
+import org.hisp.dhis.common.ValueTypedDimensionalItemObject;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.legend.Legend;
+import org.hisp.dhis.option.Option;
+import org.hisp.dhis.system.grid.ListGrid;
+import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;
+import org.hisp.dhis.util.Timer;
+import org.springframework.stereotype.Service;
+
+/** This service is responsible for retrieving aggregated event data. */
+@Service
+@RequiredArgsConstructor
+public class EventAggregateService {
+
+ private static final String DASH_PRETTY_SEPARATOR = " - ";
+
+ private static final String SPACE = " ";
+
+ private static final String TOTAL_COLUMN_PRETTY_NAME = "Total";
+
+ private static final Map COLUMN_NAMES =
+ Map.of(
+ DATA_X_DIM_ID, "data",
+ CATEGORYOPTIONCOMBO_DIM_ID, "categoryoptioncombo",
+ PERIOD_DIM_ID, "period",
+ ORGUNIT_DIM_ID, "organisationunit");
+
+ private static final Option OPT_TRUE = new Option("Yes", "1");
+
+ private static final Option OPT_FALSE = new Option("No", "0");
+
+ private final DataElementService dataElementService;
+
+ private final TrackedEntityAttributeService trackedEntityAttributeService;
+
+ private final EventAnalyticsManager eventAnalyticsManager;
+
+ private final EnrollmentAnalyticsManager enrollmentAnalyticsManager;
+
+ private final EventDataQueryService eventDataQueryService;
+
+ private final EventQueryPlanner queryPlanner;
+
+ private final AnalyticsCache analyticsCache;
+
+ private final AnalyticsSecurityManager securityManager;
+
+ private final EventQueryValidator queryValidator;
+
+ private final MetadataItemsHandler metadataHandler;
+
+ private final SchemeIdHandler schemeIdHandler;
+
+ /**
+ * Generates an aggregated for the given query. The grid will represent a table with dimensions
+ * used as columns and rows as specified in columns and rows dimension arguments. If columns and
+ * rows are null or empty, the normalized table will be returned.
+ *
+ * If metadata is included in the query, the metadata map of the grid will contain keys
+ * described in {@link AnalyticsMetaDataKey}.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @param columns the identifiers of the dimensions to use as columns.
+ * @param rows the identifiers of the dimensions to use as rows.
+ * @return aggregated data as a {@link Grid} object.
+ */
+ public Grid getAggregatedData(EventQueryParams params, List columns, List rows) {
+ return isTableLayout(columns, rows)
+ ? getAggregatedDataTableLayout(params, columns, rows)
+ : getAggregatedData(params);
+ }
+
+ /**
+ * Generates aggregated event data for the given analytical object.
+ *
+ * @param object the {@link EventAnalyticalObject}.
+ * @return aggregated event data as a {@link Grid} object.
+ */
+ public Grid getAggregatedData(EventAnalyticalObject object) {
+ EventQueryParams params = eventDataQueryService.getFromAnalyticalObject(object);
+
+ return getAggregatedData(params);
+ }
+
+ /**
+ * Generates aggregated event data for the given query, along with required validation.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @return aggregated event data as a {@link Grid} object.
+ */
+ public Grid getAggregatedData(EventQueryParams params) {
+ securityManager.decideAccessEventQuery(params);
+ params = securityManager.withUserConstraints(params);
+
+ queryValidator.validate(params);
+
+ if (analyticsCache.isEnabled() && !params.analyzeOnly()) {
+ EventQueryParams immutableParams = new EventQueryParams.Builder(params).build();
+ return analyticsCache.getOrFetch(params, p -> getAggregatedDataGrid(immutableParams));
+ }
+
+ return getAggregatedDataGrid(params);
+ }
+
+ /**
+ * Fetches aggregated event data for the given query and creates a grid containing headers and
+ * metadata if applicable.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @return aggregated event data as a {@link Grid} object.
+ */
+ private Grid getAggregatedDataGrid(EventQueryParams params) {
+ params.removeProgramIndicatorItems();
+
+ Grid grid = new ListGrid();
+ int maxLimit = queryValidator.getMaxLimit();
+ List keywords = getDimensionsKeywords(params);
+
+ if (!params.isSkipData() || params.analyzeOnly()) {
+ addHeaders(params, grid);
+ addData(grid, params, maxLimit);
+
+ // Sort, done again due to potential multiple partitions.
+ if (params.hasSortOrder() && grid.getHeight() > 0) {
+ grid.sortGrid(1, params.getSortOrderAsInt());
+ }
+
+ // Limit the grid, if asked for.
+ if (params.hasLimit() && grid.getHeight() > params.getLimit()) {
+ grid.limitGrid(params.getLimit());
+ }
+ }
+
+ addPaging(params, UNLIMITED_PAGING, grid);
+ schemeIdHandler.applyScheme(grid, params);
+ metadataHandler.addMetadata(grid, params, keywords);
+
+ return grid;
+ }
+
+ /**
+ * Adds data into the given grid, based on the given params.
+ *
+ * @param grid {@link Grid}.
+ * @param params the {@link EventQueryParams}. @@param maxLimit the max number of records to
+ * retrieve.
+ */
+ private void addData(Grid grid, EventQueryParams params, int maxLimit) {
+ Timer timer = new Timer().start().disablePrint();
+
+ List queries = queryPlanner.planAggregateQuery(params);
+
+ timer.getSplitTime("Planned event query, got partitions: " + params.getPartitions());
+
+ for (EventQueryParams query : queries) {
+ if (query.hasEnrollmentProgramIndicatorDimension()) {
+ enrollmentAnalyticsManager.getAggregatedEventData(query, grid, maxLimit);
+ } else {
+ eventAnalyticsManager.getAggregatedEventData(query, grid, maxLimit);
+ }
+ }
+
+ timer.getTime("Got aggregated events");
+
+ if (maxLimit > 0 && grid.getHeight() > maxLimit) {
+ throwIllegalQueryEx(E7128, maxLimit);
+ }
+ }
+
+ /**
+ * Add headers into the given {@link Grid}.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @return the {@link Grid} with initial headers.
+ */
+ private void addHeaders(EventQueryParams params, Grid grid) {
+ if (params.isCollapseDataDimensions() || params.isAggregateData()) {
+ grid.addHeader(new GridHeader(DATA_COLLAPSED_DIM_ID, DISPLAY_NAME_DATA_X, TEXT, false, true));
+ } else {
+ for (QueryItem item : params.getItems()) {
+ String displayProperty = item.getItem().getDisplayProperty(params.getDisplayProperty());
+
+ grid.addHeader(
+ new GridHeader(
+ item.getItem().getUid(),
+ displayProperty,
+ item.getValueType(),
+ false,
+ true,
+ item.getOptionSet(),
+ item.getLegendSet()));
+ }
+ }
+
+ for (DimensionalObject dimension : params.getDimensions()) {
+ String displayProperty = dimension.getDisplayProperty(params.getDisplayProperty());
+
+ grid.addHeader(new GridHeader(dimension.getDimension(), displayProperty, TEXT, false, true));
+ }
+
+ grid.addHeader(new GridHeader(VALUE_ID, VALUE_HEADER_NAME, NUMBER, false, false));
+
+ if (params.isIncludeNumDen()) {
+ grid.addHeader(new GridHeader(NUMERATOR_ID, NUMERATOR_HEADER_NAME, NUMBER, false, false))
+ .addHeader(new GridHeader(DENOMINATOR_ID, DENOMINATOR_HEADER_NAME, NUMBER, false, false))
+ .addHeader(new GridHeader(FACTOR_ID, FACTOR_HEADER_NAME, NUMBER, false, false))
+ .addHeader(new GridHeader(MULTIPLIER_ID, MULTIPLIER_HEADER_NAME, NUMBER, false, false))
+ .addHeader(new GridHeader(DIVISOR_ID, DIVISOR_HEADER_NAME, NUMBER, false, false));
+ }
+ }
+
+ /**
+ * Puts elements into the mapping table. The elements are fetched from the query parameters.
+ *
+ * @param grid the {@link Grid}.
+ * @param params the {@link EventQueryParams}.
+ * @param table the map to add elements to.
+ * @param dimension the dimension identifier.
+ */
+ private void addEventDataObjects(
+ Grid grid,
+ EventQueryParams params,
+ Map> table,
+ String dimension) {
+ List objects =
+ params.getEventReportDimensionalItemArrayExploded(dimension);
+
+ if (objects.isEmpty()) {
+ ValueTypedDimensionalItemObject eventDimensionalItemObject =
+ dataElementService.getDataElement(dimension);
+
+ if (eventDimensionalItemObject == null) {
+ eventDimensionalItemObject =
+ trackedEntityAttributeService.getTrackedEntityAttribute(dimension);
+ }
+
+ addEventReportDimensionalItems(eventDimensionalItemObject, objects, grid, dimension);
+
+ table.put(
+ eventDimensionalItemObject.getDisplayProperty(params.getDisplayProperty()), objects);
+ } else {
+ table.put(dimension, objects);
+ }
+ }
+
+ /**
+ * Adds dimensional items to the given list of objects. Send in a list of {@link
+ * EventAnalyticsDimensionalItem} and add properties from {@link ValueTypedDimensionalItemObject}
+ * parameter.
+ *
+ * @param eventDimensionalItemObject the {@link ValueTypedDimensionalItemObject} object to get
+ * properties from.
+ * @param dimensionalItems the list of {@link EventAnalyticsDimensionalItem} objects.
+ * @param grid the {@link Grid} from the event analytics request.
+ * @param dimension the dimension identifier.
+ */
+ @SuppressWarnings("unchecked")
+ private void addEventReportDimensionalItems(
+ ValueTypedDimensionalItemObject eventDimensionalItemObject,
+ List dimensionalItems,
+ Grid grid,
+ String dimension) {
+ checkNotNull(
+ eventDimensionalItemObject, String.format("Data dimension '%s' is invalid", dimension));
+
+ String parentUid = eventDimensionalItemObject.getUid();
+
+ if (eventDimensionalItemObject.getValueType() == BOOLEAN) {
+ dimensionalItems.add(new EventAnalyticsDimensionalItem(OPT_TRUE, parentUid));
+ dimensionalItems.add(new EventAnalyticsDimensionalItem(OPT_FALSE, parentUid));
+ }
+
+ if (eventDimensionalItemObject.hasOptionSet()) {
+ for (Option option : eventDimensionalItemObject.getOptionSet().getOptions()) {
+ dimensionalItems.add(new EventAnalyticsDimensionalItem(option, parentUid));
+ }
+ } else if (eventDimensionalItemObject.hasLegendSet()) {
+ List legendOptions =
+ (List)
+ ((Map) grid.getMetaData().get(DIMENSIONS.getKey())).get(dimension);
+
+ if (legendOptions.isEmpty()) {
+ List legends = eventDimensionalItemObject.getLegendSet().getSortedLegends();
+ addLegends(dimensionalItems, parentUid, legends);
+ } else {
+ addLegendOptions(dimensionalItems, grid, parentUid, legendOptions);
+ }
+ }
+ }
+
+ /**
+ * Adds the given legends into the list of dimensionalItems.
+ *
+ * @param dimensionalItems
+ * @param parentUid
+ * @param legends
+ */
+ private static void addLegends(
+ List dimensionalItems,
+ String parentUid,
+ List legends) {
+ for (Legend legend : legends) {
+ for (int i = legend.getStartValue().intValue(); i < legend.getEndValue().intValue(); i++) {
+ dimensionalItems.add(
+ new EventAnalyticsDimensionalItem(
+ new Option(String.valueOf(i), String.valueOf(i)), parentUid));
+ }
+ }
+ }
+
+ /**
+ * Adds the given legendOptions into the list of dimensionalItems.
+ *
+ * @param dimensionalItems
+ * @param grid
+ * @param parentUid
+ * @param legendOptions
+ */
+ private static void addLegendOptions(
+ List dimensionalItems,
+ Grid grid,
+ String parentUid,
+ List legendOptions) {
+ for (String legend : legendOptions) {
+ MetadataItem metadataItem =
+ (MetadataItem) ((Map) grid.getMetaData().get(ITEMS.getKey())).get(legend);
+
+ dimensionalItems.add(
+ new EventAnalyticsDimensionalItem(new Option(metadataItem.getName(), legend), parentUid));
+ }
+ }
+
+ /**
+ * Creates a grid with table layout for downloading event reports. The grid is dynamically made
+ * from rows and columns input, which refers to the dimensions requested.
+ *
+ * For event reports each option for a dimension will be an {@link
+ * EventAnalyticsDimensionalItem} and all permutations will be added to the grid.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @param columns the identifiers of the dimensions to use as columns.
+ * @param rows the identifiers of the dimensions to use as rows.
+ * @return aggregated data as a Grid object.
+ */
+ private Grid getAggregatedDataTableLayout(
+ EventQueryParams params, List columns, List rows) {
+ params.removeProgramIndicatorItems();
+
+ Grid grid = getAggregatedData(params);
+
+ removeEmptys(columns);
+ removeEmptys(rows);
+
+ Map> tableColumns = new LinkedHashMap<>();
+
+ if (columns != null) {
+ for (String dimension : columns) {
+ addEventDataObjects(grid, params, tableColumns, dimension);
+ }
+ }
+
+ Map> tableRows = new LinkedHashMap<>();
+ List rowDimensions = new ArrayList<>();
+
+ if (rows != null) {
+ for (String dimension : rows) {
+ rowDimensions.add(dimension);
+ addEventDataObjects(grid, params, tableRows, dimension);
+ }
+ }
+
+ List> rowPermutations =
+ generateEventDataPermutations(tableRows);
+
+ List> columnPermutations =
+ generateEventDataPermutations(tableColumns);
+
+ return generateOutputGrid(grid, params, rowPermutations, columnPermutations, rowDimensions);
+ }
+
+ /**
+ * Generates an output grid for event analytics download based on input parameters.
+ *
+ * @param grid the result grid.
+ * @param params the {@link EventQueryParams}.
+ * @param rowPermutations the row permutations
+ * @param columnPermutations the column permutations.
+ * @param rowDimensions the row dimensions.
+ * @return grid with table layout.
+ */
+ @SuppressWarnings("unchecked")
+ private Grid generateOutputGrid(
+ Grid grid,
+ EventQueryParams params,
+ List> rowPermutations,
+ List> columnPermutations,
+ List rowDimensions) {
+ Grid outputGrid = new ListGrid();
+ outputGrid.setTitle(join(params.getFilterItems()));
+
+ for (String row : rowDimensions) {
+ MetadataItem metadataItem =
+ (MetadataItem) ((Map) grid.getMetaData().get(ITEMS.getKey())).get(row);
+
+ String name = defaultIfEmpty(metadataItem.getName(), row);
+ String col = defaultIfEmpty(COLUMN_NAMES.get(row), row);
+
+ outputGrid.addHeader(new GridHeader(name, col, TEXT, false, true));
+ }
+
+ columnPermutations.forEach(
+ permutation -> {
+ StringBuilder builder = new StringBuilder();
+
+ permutation.forEach(
+ (key, value) -> {
+ if (!key.equals(ORGUNIT_DIM_ID) && !key.equals(PERIOD_DIM_ID)) {
+ builder.append(key).append(SPACE);
+ }
+ builder
+ .append(value.getDisplayProperty(params.getDisplayProperty()))
+ .append(DASH_PRETTY_SEPARATOR);
+ });
+
+ String display =
+ builder.length() > 0
+ ? builder.substring(0, builder.lastIndexOf(DASH_PRETTY_SEPARATOR))
+ : TOTAL_COLUMN_PRETTY_NAME;
+
+ outputGrid.addHeader(new GridHeader(display, display, NUMBER, false, false));
+ });
+
+ for (Map rowCombination : rowPermutations) {
+ outputGrid.addRow();
+ List> ids = new ArrayList<>();
+ Map displayObjects = new HashMap<>();
+
+ boolean fillDisplayList = true;
+
+ for (Map columnCombination : columnPermutations) {
+ List idList = new ArrayList<>();
+
+ boolean finalFillDisplayList = fillDisplayList;
+ rowCombination.forEach(
+ (key, value) -> {
+ idList.add(value.toString());
+
+ if (finalFillDisplayList) {
+ displayObjects.put(value.getParentUid(), value);
+ }
+ });
+
+ columnCombination.forEach((key, value) -> idList.add(value.toString()));
+
+ ids.add(idList);
+ fillDisplayList = false;
+ }
+
+ addValuesInOutputGrid(rowDimensions, outputGrid, displayObjects, params);
+ addValues(ids, grid, outputGrid);
+ }
+
+ return getGridWithRows(grid, outputGrid);
+ }
+
+ /**
+ * Returns a valid grid.
+ *
+ * @param grid the {@link Grid}.
+ * @param outputGrid the output {@link Grid}.
+ */
+ private static Grid getGridWithRows(Grid grid, Grid outputGrid) {
+ return outputGrid.getRows().isEmpty() ? grid : outputGrid;
+ }
+
+ /**
+ * Adds values to the given output grid. Display objects are not empty if columns and rows are not
+ * empty.
+ *
+ * @param rowDimensions the list of row dimensions.
+ * @param grid the {@link Grid}.
+ * @param displayObjects the map of display objects.
+ * @param params the {@link EventQueryParams}.
+ */
+ private static void addValuesInOutputGrid(
+ List rowDimensions,
+ Grid grid,
+ Map displayObjects,
+ EventQueryParams params) {
+ if (!displayObjects.isEmpty()) {
+ rowDimensions.forEach(
+ dimension ->
+ grid.addValue(
+ displayObjects.get(dimension).getDisplayProperty(params.getDisplayProperty())));
+ }
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryService.java
new file mode 100644
index 000000000000..24f4741250d9
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryService.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2004-2024, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.event.data;
+
+import static org.hisp.dhis.analytics.common.ColumnHeader.CENTER;
+import static org.hisp.dhis.analytics.common.ColumnHeader.COUNT;
+import static org.hisp.dhis.analytics.common.ColumnHeader.CREATED_BY_DISPLAY_NAME;
+import static org.hisp.dhis.analytics.common.ColumnHeader.ENROLLMENT_DATE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT;
+import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT_DATE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.EVENT_STATUS;
+import static org.hisp.dhis.analytics.common.ColumnHeader.EXTENT;
+import static org.hisp.dhis.analytics.common.ColumnHeader.GEOMETRY;
+import static org.hisp.dhis.analytics.common.ColumnHeader.INCIDENT_DATE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.LAST_UPDATED;
+import static org.hisp.dhis.analytics.common.ColumnHeader.LAST_UPDATED_BY_DISPLAY_NAME;
+import static org.hisp.dhis.analytics.common.ColumnHeader.LATITUDE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.LONGITUDE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_CODE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_NAME;
+import static org.hisp.dhis.analytics.common.ColumnHeader.ORG_UNIT_NAME_HIERARCHY;
+import static org.hisp.dhis.analytics.common.ColumnHeader.POINTS;
+import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_INSTANCE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_STAGE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.PROGRAM_STATUS;
+import static org.hisp.dhis.analytics.common.ColumnHeader.SCHEDULED_DATE;
+import static org.hisp.dhis.analytics.common.ColumnHeader.STORED_BY;
+import static org.hisp.dhis.analytics.common.ColumnHeader.TRACKED_ENTITY;
+import static org.hisp.dhis.analytics.event.LabelMapper.getEnrollmentDateLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getEventDateLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getEventLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getIncidentDateLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getOrgUnitLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getProgramStageLabel;
+import static org.hisp.dhis.analytics.event.LabelMapper.getScheduledDateLabel;
+import static org.hisp.dhis.analytics.tracker.HeaderHelper.addCommonHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.addPaging;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.applyHeaders;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getDimensionsKeywords;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.setRowContextColumns;
+import static org.hisp.dhis.analytics.util.AnalyticsUtils.throwIllegalQueryEx;
+import static org.hisp.dhis.common.ValueType.DATETIME;
+import static org.hisp.dhis.common.ValueType.NUMBER;
+import static org.hisp.dhis.common.ValueType.TEXT;
+import static org.hisp.dhis.feedback.ErrorCode.E7218;
+
+import java.util.List;
+import javax.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import org.hisp.dhis.analytics.AnalyticsSecurityManager;
+import org.hisp.dhis.analytics.Rectangle;
+import org.hisp.dhis.analytics.event.EventAnalyticsManager;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.EventQueryPlanner;
+import org.hisp.dhis.analytics.event.EventQueryValidator;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
+import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
+import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.common.GridHeader;
+import org.hisp.dhis.system.database.DatabaseInfoProvider;
+import org.hisp.dhis.system.grid.ListGrid;
+import org.hisp.dhis.util.Timer;
+import org.springframework.stereotype.Service;
+
+/** This service is responsible for querying events. */
+@Service
+@RequiredArgsConstructor
+public class EventQueryService {
+
+ private final AnalyticsSecurityManager securityManager;
+
+ private final EventQueryValidator queryValidator;
+
+ private final EventAnalyticsManager eventAnalyticsManager;
+
+ private final EventQueryPlanner queryPlanner;
+
+ private final DatabaseInfoProvider databaseInfoProvider;
+
+ private final MetadataItemsHandler metadataHandler;
+
+ private final SchemeIdHandler schemeIdHandler;
+
+ private boolean spatialSupport;
+
+ @PostConstruct
+ void init() {
+ this.spatialSupport = databaseInfoProvider.getDatabaseInfo().isSpatialSupport();
+ }
+
+ /**
+ * Returns a list of events matching the given query.
+ *
+ * @param params the event query parameters.
+ * @return events as a {@Grid} object.
+ */
+ public Grid getEvents(EventQueryParams params) {
+ // Check access/constraints.
+ securityManager.decideAccessEventQuery(params);
+ params = securityManager.withUserConstraints(params);
+
+ // Validate request.
+ queryValidator.validate(params);
+
+ List keywords = getDimensionsKeywords(params);
+
+ // Set periods.
+ params = new EventQueryParams.Builder(params).withStartEndDatesForPeriods().build();
+
+ // Populate headers.
+ Grid grid = createGridWithHeaders(params);
+ addCommonHeaders(grid, params, List.of());
+
+ // Add data.
+ long count = 0;
+
+ if (!params.isSkipData() || params.analyzeOnly()) {
+ count = addData(grid, params);
+ }
+
+ // Set response info.
+ metadataHandler.addMetadata(grid, params, keywords);
+ schemeIdHandler.applyScheme(grid, params);
+
+ addPaging(params, count, grid);
+ applyHeaders(grid, params);
+ setRowContextColumns(grid);
+
+ return grid;
+ }
+
+ /**
+ * Returns a list of event clusters matching the given query.
+ *
+ * @param params the event query parameters.
+ * @return event clusters as a {@link Grid} object.
+ */
+ public Grid getEventClusters(EventQueryParams params) {
+ if (!spatialSupport) {
+ throwIllegalQueryEx(E7218);
+ }
+
+ params =
+ new EventQueryParams.Builder(params)
+ .withGeometryOnly(true)
+ .withStartEndDatesForPeriods()
+ .build();
+
+ securityManager.decideAccessEventQuery(params);
+
+ queryValidator.validate(params);
+
+ Grid grid = new ListGrid();
+ grid.addHeader(new GridHeader(COUNT.getItem(), COUNT.getName(), NUMBER, false, false))
+ .addHeader(new GridHeader(CENTER.getItem(), CENTER.getName(), TEXT, false, false))
+ .addHeader(new GridHeader(EXTENT.getItem(), EXTENT.getName(), TEXT, false, false))
+ .addHeader(new GridHeader(POINTS.getItem(), POINTS.getName(), TEXT, false, false));
+
+ params = queryPlanner.planEventQuery(params);
+
+ eventAnalyticsManager.getEventClusters(params, grid, queryValidator.getMaxLimit());
+
+ return grid;
+ }
+
+ /**
+ * Returns a Rectangle with information about event count and extent of the spatial rectangle for
+ * the given query.
+ *
+ * @param params the event query parameters.
+ * @return event clusters as a {@link Grid} object.
+ */
+ public Rectangle getRectangle(EventQueryParams params) {
+ if (!spatialSupport) {
+ throwIllegalQueryEx(E7218);
+ }
+
+ params =
+ new EventQueryParams.Builder(params)
+ .withGeometryOnly(true)
+ .withStartEndDatesForPeriods()
+ .build();
+
+ securityManager.decideAccessEventQuery(params);
+
+ queryValidator.validate(params);
+
+ params = queryPlanner.planEventQuery(params);
+
+ return eventAnalyticsManager.getRectangle(params);
+ }
+
+ /**
+ * Creates a grid with headers.
+ *
+ * @param params the {@link EventQueryParams}.
+ */
+ private Grid createGridWithHeaders(EventQueryParams params) {
+ Grid grid = new ListGrid();
+
+ grid.addHeader(
+ new GridHeader(
+ EVENT.getItem(),
+ getEventLabel(params.getProgramStage(), EVENT.getName()),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(
+ PROGRAM_STAGE.getItem(),
+ getProgramStageLabel(params.getProgramStage(), PROGRAM_STAGE.getName()),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(
+ EVENT_DATE.getItem(),
+ getEventDateLabel(params.getProgramStage(), EVENT_DATE.getName()),
+ DATETIME,
+ false,
+ true))
+ .addHeader(new GridHeader(STORED_BY.getItem(), STORED_BY.getName(), TEXT, false, true))
+ .addHeader(
+ new GridHeader(
+ CREATED_BY_DISPLAY_NAME.getItem(),
+ CREATED_BY_DISPLAY_NAME.getName(),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(
+ LAST_UPDATED_BY_DISPLAY_NAME.getItem(),
+ LAST_UPDATED_BY_DISPLAY_NAME.getName(),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(LAST_UPDATED.getItem(), LAST_UPDATED.getName(), DATETIME, false, true))
+ .addHeader(
+ new GridHeader(
+ SCHEDULED_DATE.getItem(),
+ getScheduledDateLabel(params.getProgramStage(), SCHEDULED_DATE.getName()),
+ DATETIME,
+ false,
+ true));
+
+ if (params.getProgram().isRegistration()) {
+ grid.addHeader(
+ new GridHeader(
+ ENROLLMENT_DATE.getItem(),
+ getEnrollmentDateLabel(params.getProgram(), ENROLLMENT_DATE.getName()),
+ DATETIME,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(
+ INCIDENT_DATE.getItem(),
+ getIncidentDateLabel(params.getProgram(), INCIDENT_DATE.getName()),
+ DATETIME,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(TRACKED_ENTITY.getItem(), TRACKED_ENTITY.getName(), TEXT, false, true))
+ .addHeader(
+ new GridHeader(
+ PROGRAM_INSTANCE.getItem(), PROGRAM_INSTANCE.getName(), TEXT, false, true));
+ }
+
+ grid.addHeader(new GridHeader(GEOMETRY.getItem(), GEOMETRY.getName(), TEXT, false, true))
+ .addHeader(new GridHeader(LONGITUDE.getItem(), LONGITUDE.getName(), NUMBER, false, true))
+ .addHeader(new GridHeader(LATITUDE.getItem(), LATITUDE.getName(), NUMBER, false, true))
+ .addHeader(
+ new GridHeader(
+ ORG_UNIT_NAME.getItem(),
+ getOrgUnitLabel(params.getProgram(), ORG_UNIT_NAME.getName()),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(
+ ORG_UNIT_NAME_HIERARCHY.getItem(),
+ ORG_UNIT_NAME_HIERARCHY.getName(),
+ TEXT,
+ false,
+ true))
+ .addHeader(
+ new GridHeader(ORG_UNIT_CODE.getItem(), ORG_UNIT_CODE.getName(), TEXT, false, true))
+ .addHeader(
+ new GridHeader(PROGRAM_STATUS.getItem(), PROGRAM_STATUS.getName(), TEXT, false, true))
+ .addHeader(
+ new GridHeader(EVENT_STATUS.getItem(), EVENT_STATUS.getName(), TEXT, false, true));
+
+ return grid;
+ }
+
+ /**
+ * Adds event data to the given grid. Returns the number of events matching the given event query.
+ *
+ * @param grid the {@link Grid}.
+ * @param params the {@link EventQueryParams}.
+ * @return the count of events.
+ */
+ private long addData(Grid grid, EventQueryParams params) {
+ Timer timer = new Timer().start().disablePrint();
+
+ params = queryPlanner.planEventQuery(params);
+
+ timer.getSplitTime("Planned event query, got partitions: " + params.getPartitions());
+
+ long count = 0;
+ EventQueryParams immutableParams = new EventQueryParams.Builder(params).build();
+
+ if (params.getPartitions().hasAny() || params.isSkipPartitioning()) {
+ eventAnalyticsManager.getEvents(immutableParams, grid, queryValidator.getMaxLimit());
+
+ if (params.isPaging() && params.isTotalPages()) {
+ count = eventAnalyticsManager.getEventCount(immutableParams);
+ }
+
+ timer.getTime("Got events " + grid.getHeight());
+ }
+
+ return count;
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/HeaderHelper.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/HeaderHelper.java
new file mode 100644
index 000000000000..50e304ead549
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/HeaderHelper.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2004-2024, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.tracker;
+
+import static java.util.stream.Collectors.counting;
+import static java.util.stream.Collectors.groupingBy;
+import static lombok.AccessLevel.PRIVATE;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getItemUid;
+import static org.hisp.dhis.common.ValueType.COORDINATE;
+import static org.hisp.dhis.common.ValueType.ORGANISATION_UNIT;
+import static org.hisp.dhis.common.ValueType.REFERENCE;
+import static org.hisp.dhis.common.ValueType.TEXT;
+
+import java.util.List;
+import java.util.Map;
+import lombok.NoArgsConstructor;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.common.DisplayProperty;
+import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.common.GridHeader;
+import org.hisp.dhis.common.QueryItem;
+import org.hisp.dhis.common.RepeatableStageParams;
+
+@NoArgsConstructor(access = PRIVATE)
+public class HeaderHelper {
+ public static void addCommonHeaders(
+ Grid grid, EventQueryParams params, List periods) {
+
+ for (DimensionalObject dimension : params.getDimensions()) {
+ grid.addHeader(
+ new GridHeader(
+ dimension.getDimension(), dimension.getDimensionDisplayName(), TEXT, false, true));
+ }
+
+ for (DimensionalObject dimension : periods) {
+ grid.addHeader(
+ new GridHeader(
+ dimension.getDimension(), dimension.getDimensionDisplayName(), TEXT, false, true));
+ }
+
+ DisplayProperty displayProperty = params.getDisplayProperty();
+ Map repeatedNames =
+ params.getItems().stream()
+ .collect(groupingBy(s -> s.getItem().getDisplayProperty(displayProperty), counting()));
+
+ for (QueryItem item : params.getItems()) {
+ /**
+ * If the request contains an item of value type ORGANISATION_UNIT and the item UID is linked
+ * to coordinates (coordinateField), then create header of value type COORDINATE and type
+ * Point.
+ */
+ if (item.getValueType() == ORGANISATION_UNIT
+ && params.getCoordinateFields().stream()
+ .anyMatch(f -> f.equals(item.getItem().getUid()))) {
+ grid.addHeader(
+ new GridHeader(
+ item.getItem().getUid(),
+ item.getItem().getDisplayProperty(displayProperty),
+ COORDINATE,
+ false,
+ true,
+ item.getOptionSet(),
+ item.getLegendSet()));
+ } else if (item.hasNonDefaultRepeatableProgramStageOffset()) {
+ String column = item.getItem().getDisplayProperty(displayProperty);
+ String displayColumn = item.getColumnName(displayProperty, repeatedNames.get(column) > 1);
+
+ RepeatableStageParams repeatableStageParams = item.getRepeatableStageParams();
+
+ String name = repeatableStageParams.getDimension();
+
+ grid.addHeader(
+ new GridHeader(
+ name,
+ column,
+ displayColumn,
+ repeatableStageParams.simpleStageValueExpected() ? item.getValueType() : REFERENCE,
+ false,
+ true,
+ item.getOptionSet(),
+ item.getLegendSet(),
+ item.getProgramStage().getUid(),
+ item.getRepeatableStageParams()));
+ } else {
+ String uid = getItemUid(item);
+ String column = item.getItem().getDisplayProperty(displayProperty);
+ String displayColumn = item.getColumnName(displayProperty, repeatedNames.get(column) > 1);
+
+ grid.addHeader(
+ new GridHeader(
+ uid,
+ column,
+ displayColumn,
+ item.getValueType(),
+ false,
+ true,
+ item.getOptionSet(),
+ item.getLegendSet()));
+ }
+ }
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/MetadataItemsHandler.java
similarity index 54%
rename from dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java
rename to dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/MetadataItemsHandler.java
index 230fe44bcef6..86a3a2e78c5d 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/MetadataItemsHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2022, University of Oslo
+ * Copyright (c) 2004-2024, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,31 +25,25 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.hisp.dhis.analytics.event.data;
+package org.hisp.dhis.analytics.tracker;
import static java.util.Collections.emptyList;
import static java.util.Optional.empty;
-import static java.util.stream.Collectors.counting;
-import static java.util.stream.Collectors.groupingBy;
-import static java.util.stream.Collectors.toList;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
-import static org.apache.commons.lang3.StringUtils.EMPTY;
-import static org.apache.commons.lang3.StringUtils.joinWith;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.DIMENSIONS;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.ITEMS;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.ORG_UNIT_HIERARCHY;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.ORG_UNIT_NAME_HIERARCHY;
-import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.PAGER;
import static org.hisp.dhis.analytics.event.data.QueryItemHelper.getItemOptions;
import static org.hisp.dhis.analytics.event.data.QueryItemHelper.getItemOptionsAsFilter;
+import static org.hisp.dhis.analytics.tracker.ResponseHelper.getItemUid;
+import static org.hisp.dhis.analytics.util.AnalyticsOrganisationUnitUtils.getUserOrganisationUnitItems;
import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID;
import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID;
import static org.hisp.dhis.common.DimensionalObjectUtils.asTypedList;
import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionalItemIds;
-import static org.hisp.dhis.common.IdScheme.NAME;
import static org.hisp.dhis.common.IdentifiableObjectUtils.getLocalPeriodIdentifiers;
import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids;
-import static org.hisp.dhis.common.ValueType.COORDINATE;
import static org.hisp.dhis.organisationunit.OrganisationUnit.getParentGraphMap;
import static org.hisp.dhis.organisationunit.OrganisationUnit.getParentNameGraphMap;
@@ -62,395 +56,231 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.TreeMap;
import lombok.RequiredArgsConstructor;
import org.hisp.dhis.analytics.AnalyticsSecurityManager;
-import org.hisp.dhis.analytics.common.processing.MetadataItemsHandler;
-import org.hisp.dhis.analytics.common.scheme.SchemeInfo;
-import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Data;
-import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Settings;
-import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
import org.hisp.dhis.analytics.event.EventQueryParams;
-import org.hisp.dhis.analytics.event.EventQueryValidator;
import org.hisp.dhis.analytics.orgunit.OrgUnitHelper;
-import org.hisp.dhis.analytics.util.AnalyticsOrganisationUnitUtils;
import org.hisp.dhis.analytics.util.AnalyticsUtils;
import org.hisp.dhis.calendar.Calendar;
-import org.hisp.dhis.common.DimensionItemKeywords;
import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
import org.hisp.dhis.common.DimensionalItemObject;
import org.hisp.dhis.common.DimensionalObject;
import org.hisp.dhis.common.DisplayProperty;
import org.hisp.dhis.common.Grid;
-import org.hisp.dhis.common.GridHeader;
import org.hisp.dhis.common.IdentifiableObjectUtils;
import org.hisp.dhis.common.MetadataItem;
-import org.hisp.dhis.common.Pager;
import org.hisp.dhis.common.QueryItem;
-import org.hisp.dhis.common.RepeatableStageParams;
-import org.hisp.dhis.common.SlimPager;
-import org.hisp.dhis.common.ValueStatus;
-import org.hisp.dhis.common.ValueType;
import org.hisp.dhis.option.Option;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.period.PeriodType;
import org.hisp.dhis.user.CurrentUserUtil;
import org.hisp.dhis.user.User;
import org.hisp.dhis.user.UserService;
+import org.springframework.stereotype.Component;
-/**
- * @author Luciano Fiandesio
- */
+@Component
@RequiredArgsConstructor
-public abstract class AbstractAnalyticsService {
+public class MetadataItemsHandler {
protected final AnalyticsSecurityManager securityManager;
- protected final EventQueryValidator queryValidator;
-
- protected final SchemeIdResponseMapper schemeIdResponseMapper;
-
protected final UserService userService;
/**
- * Returns a grid based on the given query.
+ * Adds meta data values to the given grid based on the given data query parameters.
*
+ * @param grid the {@link Grid}.
* @param params the {@link EventQueryParams}.
- * @return a {@link Grid}.
+ * @param keywords the list of {@link Keyword}.
*/
- protected Grid getGrid(EventQueryParams params) {
- // ---------------------------------------------------------------------
- // Decide access, add constraints and validate
- // ---------------------------------------------------------------------
-
- securityManager.decideAccessEventQuery(params);
-
- params = securityManager.withUserConstraints(params);
-
- queryValidator.validate(params);
-
- // Keywords and periods are removed in the next step
-
- List periodKeywords =
- params.getDimensions().stream()
- .map(DimensionalObject::getDimensionItemKeywords)
- .filter(
- dimensionItemKeywords ->
- dimensionItemKeywords != null && !dimensionItemKeywords.isEmpty())
- .flatMap(dk -> dk.getKeywords().stream())
- .collect(toList());
-
- List periods = getPeriods(params);
-
- params = new EventQueryParams.Builder(params).withStartEndDatesForPeriods().build();
-
- // ---------------------------------------------------------------------
- // Headers
- // ---------------------------------------------------------------------
-
- Grid grid = createGridWithHeaders(params);
-
- for (DimensionalObject dimension : params.getDimensions()) {
- grid.addHeader(
- new GridHeader(
- dimension.getDimension(),
- dimension.getDimensionDisplayName(),
- ValueType.TEXT,
- false,
- true));
- }
-
- for (DimensionalObject dimension : periods) {
- grid.addHeader(
- new GridHeader(
- dimension.getDimension(),
- dimension.getDimensionDisplayName(),
- ValueType.TEXT,
- false,
- true));
- }
-
- final DisplayProperty displayProperty = params.getDisplayProperty();
- Map repeatedNames =
- params.getItems().stream()
- .collect(groupingBy(s -> s.getItem().getDisplayProperty(displayProperty), counting()));
+ public void addMetadata(Grid grid, EventQueryParams params, List keywords) {
+ if (!params.isSkipMeta()) {
+ Map metadata = new HashMap<>();
+ Map> optionsPresentInGrid = getItemOptions(grid, params.getItems());
+ Set optionItems = new LinkedHashSet<>();
+ boolean hasResults = isNotEmpty(grid.getRows());
- for (QueryItem item : params.getItems()) {
- /**
- * If the request contains an item of value type ORGANISATION_UNIT and the item UID is linked
- * to coordinates (coordinateField), then create header of value type COORDINATE and type
- * Point.
- */
- if (item.getValueType() == ValueType.ORGANISATION_UNIT
- && params.getCoordinateFields().stream()
- .anyMatch(f -> f.equals(item.getItem().getUid()))) {
- grid.addHeader(
- new GridHeader(
- item.getItem().getUid(),
- item.getItem().getDisplayProperty(displayProperty),
- COORDINATE,
- false,
- true,
- item.getOptionSet(),
- item.getLegendSet()));
- } else if (item.hasNonDefaultRepeatableProgramStageOffset()) {
- String column = item.getItem().getDisplayProperty(displayProperty);
- String displayColumn = item.getColumnName(displayProperty, repeatedNames.get(column) > 1);
-
- RepeatableStageParams repeatableStageParams = item.getRepeatableStageParams();
-
- String name = repeatableStageParams.getDimension();
-
- grid.addHeader(
- new GridHeader(
- name,
- column,
- displayColumn,
- repeatableStageParams.simpleStageValueExpected()
- ? item.getValueType()
- : ValueType.REFERENCE,
- false,
- true,
- item.getOptionSet(),
- item.getLegendSet(),
- item.getProgramStage().getUid(),
- item.getRepeatableStageParams()));
+ if (hasResults) {
+ optionItems.addAll(
+ optionsPresentInGrid.values().stream().flatMap(Collection::stream).distinct().toList());
} else {
- String uid = getItemUid(item);
- String column = item.getItem().getDisplayProperty(displayProperty);
- String displayColumn = item.getColumnName(displayProperty, repeatedNames.get(column) > 1);
-
- grid.addHeader(
- new GridHeader(
- uid,
- column,
- displayColumn,
- item.getValueType(),
- false,
- true,
- item.getOptionSet(),
- item.getLegendSet()));
+ optionItems.addAll(getItemOptionsAsFilter(params.getItemOptions(), params.getItems()));
}
- }
-
- // ---------------------------------------------------------------------
- // Data
- // ---------------------------------------------------------------------
- long count = 0;
+ Map items = new HashMap<>();
+ getUserOrganisationUnitItems(
+ userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()),
+ params.getUserOrganisationUnitsCriteria())
+ .forEach(items::putAll);
- if (!params.isSkipData() || params.analyzeOnly()) {
- if (!periods.isEmpty()) {
- params =
- new EventQueryParams.Builder(params)
- .withPeriods(periods.stream().flatMap(p -> p.getItems().stream()).toList(), EMPTY)
- .build();
+ if (params.isComingFromQuery()) {
+ items.putAll(getMetadataItems(params, keywords, optionItems, grid));
+ } else {
+ items.putAll(getMetadataItems(params));
}
- count = addData(grid, params);
- }
-
- // ---------------------------------------------------------------------
- // Metadata
- // ---------------------------------------------------------------------
- addMetadata(params, periodKeywords, grid);
+ metadata.put(ITEMS.getKey(), items);
- // ---------------------------------------------------------------------
- // ID scheme
- // ---------------------------------------------------------------------
+ if (params.isComingFromQuery()) {
+ metadata.put(
+ DIMENSIONS.getKey(), getDimensionItems(params, Optional.of(optionsPresentInGrid)));
+ } else {
+ metadata.put(DIMENSIONS.getKey(), getDimensionItems(params, empty()));
+ }
- if (params.hasDataIdScheme()) {
- schemeIdResponseMapper.applyOptionAndLegendSetMapping(NAME, grid);
- }
+ maybeAddOrgUnitHierarchyInfo(params, metadata, grid);
- if (!params.isSkipMeta()) {
- SchemeInfo schemeInfo = new SchemeInfo(schemeSettings(params), schemeData(params));
- schemeIdResponseMapper.applyCustomIdScheme(schemeInfo, grid);
+ grid.setMetaData(metadata);
}
-
- // ---------------------------------------------------------------------
- // Paging
- // ---------------------------------------------------------------------
-
- addPaging(params, count, grid);
-
- // ---------------------------------------------------------------------
- // Headers
- // ---------------------------------------------------------------------
-
- addHeaders(params, grid);
-
- // ---------------------------------------------------------------------
- // RowContext
- // ---------------------------------------------------------------------
-
- setRowContextColumns(grid);
-
- return grid;
- }
-
- protected Data schemeData(EventQueryParams params) {
- return Data.builder()
- .dataElements(params.getAllDataElements())
- .dimensionalItemObjects(new LinkedHashSet<>(params.getAllDimensionItems()))
- .dataElementOperands(params.getDataElementOperands())
- .options(params.getItemOptions())
- .organizationUnits(params.getOrganisationUnits())
- .program(params.getProgram())
- .programStage(params.getProgramStage())
- .indicators(params.getIndicators())
- .programIndicators(params.getProgramIndicators())
- .build();
- }
-
- protected Settings schemeSettings(EventQueryParams params) {
- return Settings.builder()
- .dataIdScheme(params.getDataIdScheme())
- .outputDataElementIdScheme(params.getOutputDataElementIdScheme())
- .outputDataItemIdScheme(params.getOutputDataItemIdScheme())
- .outputIdScheme(params.getOutputIdScheme())
- .outputOrgUnitIdScheme(params.getOutputOrgUnitIdScheme())
- .outputFormat(params.getOutputFormat())
- .build();
}
/**
- * Add information about row context. The row context is based on origin of repeatable stage
- * value. Please see the {@link ValueStatus}
+ * Adds the given item to the given metadata item map.
*
- * @param grid the {@link Grid}.
+ * @param metadataItemMap the metadata item map.
+ * @param item the {@link QueryItem}.
+ * @param includeDetails whether to include metadata details.
+ * @param displayProperty the {@link DisplayProperty}.
*/
- private void setRowContextColumns(Grid grid) {
- Map> oldRowContext = grid.getRowContext();
+ private void addItemToMetadata(
+ Map metadataItemMap,
+ QueryItem item,
+ boolean includeDetails,
+ DisplayProperty displayProperty) {
+ MetadataItem metadataItem =
+ new MetadataItem(
+ item.getItem().getDisplayProperty(displayProperty),
+ includeDetails ? item.getItem() : null);
- Map> newRowContext = new TreeMap<>();
+ metadataItemMap.put(getItemIdWithProgramStageIdPrefix(item), metadataItem);
- oldRowContext
- .keySet()
- .forEach(
- rowKey -> {
- Map newCols = new HashMap<>();
- Map cols = oldRowContext.get(rowKey);
- cols.keySet()
- .forEach(
- colKey ->
- newCols.put(
- Integer.toString(grid.getIndexOfHeader(colKey)), cols.get(colKey)));
- newRowContext.put(rowKey, newCols);
- });
-
- grid.setRowContext(newRowContext);
+ // Done for backwards compatibility.
+ metadataItemMap.put(item.getItemId(), metadataItem);
}
/**
- * Applies paging to the given grid if the given query specifies paging.
+ * Adds the given metadata items.
*
+ * @param metadataItemMap the metadata item map.
* @param params the {@link EventQueryParams}.
- * @param totalCount the total count.
- * @param grid the {@link Grid}.
+ * @param itemOptions the list of {@link Option}.
*/
- private void addPaging(EventQueryParams params, long totalCount, Grid grid) {
- if (params.isPaging()) {
- Pager pager =
- params.isTotalPages()
- ? new Pager(params.getPageWithDefault(), totalCount, params.getPageSizeWithDefault())
- : new SlimPager(
- params.getPageWithDefault(),
- params.getPageSizeWithDefault(),
- grid.hasLastDataRow());
-
- grid.getMetaData().put(PAGER.getKey(), pager);
- }
+ private void addMetadataItems(
+ Map metadataItemMap, EventQueryParams params, Set itemOptions) {
+ boolean includeDetails = params.isIncludeMetadataDetails();
+
+ itemOptions.forEach(
+ option ->
+ metadataItemMap.put(
+ option.getUid(),
+ new MetadataItem(
+ option.getDisplayProperty(params.getDisplayProperty()),
+ includeDetails ? option.getUid() : null,
+ option.getCode())));
+
+ new org.hisp.dhis.analytics.common.processing.MetadataItemsHandler()
+ .addOptionsSetIntoMap(metadataItemMap, itemOptions);
}
/**
- * Based on the given item this method returns the correct UID based on internal rules.
+ * Returns a map between dimension identifiers and lists of dimension item identifiers.
*
- * @param item the current QueryItem.
- * @return the correct UID based on the item type.
+ * @param params the {@link EventQueryParams}.
+ * @param itemOptions the item options to be added into dimension items.
+ * @return a {@link Map} of dimension items.
*/
- private String getItemUid(QueryItem item) {
- String uid = item.getItem().getUid();
+ private Map> getDimensionItems(
+ EventQueryParams params, Optional>> itemOptions) {
+ Calendar calendar = PeriodType.getCalendar();
- if (item.hasProgramStage()) {
- uid = joinWith(".", item.getProgramStage().getUid(), uid);
- }
+ List periodUids =
+ calendar.isIso8601()
+ ? getUids(params.getDimensionOrFilterItems(PERIOD_DIM_ID))
+ : getLocalPeriodIdentifiers(params.getDimensionOrFilterItems(PERIOD_DIM_ID), calendar);
- return uid;
- }
+ Map> dimensionItems = new HashMap<>();
- protected abstract Grid createGridWithHeaders(EventQueryParams params);
+ dimensionItems.put(PERIOD_DIM_ID, periodUids);
- protected abstract long addData(Grid grid, EventQueryParams params);
+ for (DimensionalObject dim : params.getDimensionsAndFilters()) {
+ dimensionItems.put(dim.getDimension(), getDimensionalItemIds(dim.getItems()));
+ }
- /**
- * Applies headers to the given if the given query specifies headers.
- *
- * @param params the {@link EventQueryParams}.
- * @param grid the {@link Grid}.
- */
- private void addHeaders(EventQueryParams params, Grid grid) {
- if (params.hasHeaders()) {
- grid.retainColumns(params.getHeaders());
+ for (QueryItem item : params.getItems()) {
+ String itemUid = getItemUid(item);
+
+ if (item.hasOptionSet()) {
+ if (itemOptions.isPresent()) {
+ Map> itemOptionsMap = itemOptions.get();
+
+ // The call itemOptions.get( itemUid ) can return null.
+ // The query item can't have both legends and options.
+ dimensionItems.put(
+ itemUid,
+ getDimensionItemUidsFrom(
+ itemOptionsMap.get(itemUid), item.getOptionSetFilterItemsOrAll()));
+ } else {
+ dimensionItems.put(item.getItemId(), item.getOptionSetFilterItemsOrAll());
+ }
+ } else if (item.hasLegendSet()) {
+ dimensionItems.put(itemUid, item.getLegendSetFilterItemsOrAll());
+ } else {
+ dimensionItems.put(itemUid, List.of());
+ }
}
- }
- /**
- * Adds meta data values to the given grid based on the given data query parameters.
- *
- * @param params the {@link EventQueryParams}.
- * @param grid the {@link Grid}.
- */
- protected void addMetadata(EventQueryParams params, Grid grid) {
- addMetadata(params, null, grid);
+ addItemFiltersToDimensionItems(params.getItemFilters(), dimensionItems);
+
+ return dimensionItems;
}
/**
- * Adds meta data values to the given grid based on the given data query parameters.
+ * Based on the given arguments, this method will extract a list of UIDs of {@link Option}. If
+ * itemOptions is null, it returns the default list of UIDs (defaultOptionUids). Otherwise, it
+ * will return the list of UIDs from itemOptions.
*
- * @param params the {@link EventQueryParams}.
- * @param periodKeywords the list of period keywords.
- * @param grid the {@link Grid}.
+ * @param itemOptions a list of {@link Option} objects
+ * @param defaultOptionUids a list of default {@link Option} UIDs.
+ * @return a list of UIDs.
*/
- protected void addMetadata(
- EventQueryParams params, List periodKeywords, Grid grid) {
- if (!params.isSkipMeta()) {
- Map metadata = new HashMap<>();
- Map> optionsPresentInGrid = getItemOptions(grid, params.getItems());
- Set optionItems = new LinkedHashSet<>();
- boolean hasResults = isNotEmpty(grid.getRows());
-
- if (hasResults) {
- optionItems.addAll(
- optionsPresentInGrid.values().stream().flatMap(Collection::stream).distinct().toList());
- } else {
- optionItems.addAll(getItemOptionsAsFilter(params.getItemOptions(), params.getItems()));
- }
-
- Map items = new HashMap<>();
- AnalyticsOrganisationUnitUtils.getUserOrganisationUnitItems(
- userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()),
- params.getUserOrganisationUnitsCriteria())
- .forEach(items::putAll);
+ private List getDimensionItemUidsFrom(
+ List itemOptions, List defaultOptionUids) {
+ List dimensionUids = new ArrayList<>();
- if (params.isComingFromQuery()) {
- items.putAll(getMetadataItems(params, periodKeywords, optionItems, grid));
- } else {
- items.putAll(getMetadataItems(params));
- }
+ if (itemOptions == null) {
+ dimensionUids.addAll(defaultOptionUids);
+ } else {
+ dimensionUids.addAll(IdentifiableObjectUtils.getUids(itemOptions));
+ }
- metadata.put(ITEMS.getKey(), items);
+ return dimensionUids;
+ }
- if (params.isComingFromQuery()) {
- metadata.put(
- DIMENSIONS.getKey(), getDimensionItems(params, Optional.of(optionsPresentInGrid)));
+ private static void addItemFiltersToDimensionItems(
+ List itemsFilter, Map> dimensionItems) {
+ for (QueryItem item : itemsFilter) {
+ if (item.hasOptionSet()) {
+ dimensionItems.put(item.getItemId(), item.getOptionSetFilterItemsOrAll());
+ } else if (item.hasLegendSet()) {
+ dimensionItems.put(item.getItemId(), item.getLegendSetFilterItemsOrAll());
} else {
- metadata.put(DIMENSIONS.getKey(), getDimensionItems(params, empty()));
+ dimensionItems.put(
+ item.getItemId(),
+ item.getFiltersAsString() != null ? List.of(item.getFiltersAsString()) : emptyList());
}
+ }
+ }
- maybeAddOrgUnitHierarchyInfo(params, metadata, grid);
-
- grid.setMetaData(metadata);
+ /**
+ * Returns the query item identifier, may have a program stage prefix.
+ *
+ * @param item {@link QueryItem}.
+ */
+ private String getItemIdWithProgramStageIdPrefix(QueryItem item) {
+ if (item.hasProgramStage()) {
+ return item.getProgramStage().getUid() + "." + item.getItemId();
}
+
+ return item.getItemId();
}
/**
@@ -543,16 +373,13 @@ private Map getMetadataItems(EventQueryParams params) {
* Returns a map of metadata item identifiers and {@link MetadataItem}.
*
* @param params the {@link EventQueryParams}.
- * @param periodKeywords the period keywords.
+ * @param keywords the dimension keywords.
* @param itemOptions the set of item {@link Option}.
* @param grid the grid instance {@link Grid}.
* @return a map.
*/
private Map getMetadataItems(
- EventQueryParams params,
- List periodKeywords,
- Set itemOptions,
- Grid grid) {
+ EventQueryParams params, List keywords, Set itemOptions, Grid grid) {
Map metadataItemMap =
AnalyticsUtils.getDimensionMetadataItemMap(params, grid);
@@ -588,8 +415,8 @@ private Map getMetadataItems(
addItemToMetadata(
metadataItemMap, item, includeDetails, params.getDisplayProperty()));
- if (hasPeriodKeywords(periodKeywords)) {
- for (DimensionItemKeywords.Keyword keyword : periodKeywords) {
+ if (isNotEmpty(keywords)) {
+ for (Keyword keyword : keywords) {
if (keyword.getMetadataItem() != null) {
metadataItemMap.put(
keyword.getKey(), new MetadataItem(keyword.getMetadataItem().getName()));
@@ -599,173 +426,4 @@ private Map getMetadataItems(
return metadataItemMap;
}
-
- /**
- * Adds the given item to the given metadata item map.
- *
- * @param metadataItemMap the metadata item map.
- * @param item the {@link QueryItem}.
- * @param includeDetails whether to include metadata details.
- * @param displayProperty the {@link DisplayProperty}.
- */
- private void addItemToMetadata(
- Map metadataItemMap,
- QueryItem item,
- boolean includeDetails,
- DisplayProperty displayProperty) {
- MetadataItem metadataItem =
- new MetadataItem(
- item.getItem().getDisplayProperty(displayProperty),
- includeDetails ? item.getItem() : null);
-
- metadataItemMap.put(getItemIdWithProgramStageIdPrefix(item), metadataItem);
-
- // Done for backwards compatibility
-
- metadataItemMap.put(item.getItemId(), metadataItem);
- }
-
- /**
- * Returns the query item identifier, may have a program stage prefix.
- *
- * @param item {@link QueryItem}.
- */
- private String getItemIdWithProgramStageIdPrefix(QueryItem item) {
- if (item.hasProgramStage()) {
- return item.getProgramStage().getUid() + "." + item.getItemId();
- }
-
- return item.getItemId();
- }
-
- /**
- * Indicates whether any keywords exist.
- *
- * @param keywords the list of {@link Keyword}.
- */
- private boolean hasPeriodKeywords(List keywords) {
- return keywords != null && !keywords.isEmpty();
- }
-
- /**
- * Adds the given metadata items.
- *
- * @param metadataItemMap the metadata item map.
- * @param params the {@link EventQueryParams}.
- * @param itemOptions the list of {@link Option}.
- */
- private void addMetadataItems(
- Map metadataItemMap, EventQueryParams params, Set itemOptions) {
- boolean includeDetails = params.isIncludeMetadataDetails();
-
- itemOptions.forEach(
- option ->
- metadataItemMap.put(
- option.getUid(),
- new MetadataItem(
- option.getDisplayProperty(params.getDisplayProperty()),
- includeDetails ? option.getUid() : null,
- option.getCode())));
-
- new MetadataItemsHandler().addOptionsSetIntoMap(metadataItemMap, itemOptions);
- }
-
- /**
- * Returns a map between dimension identifiers and lists of dimension item identifiers.
- *
- * @param params the {@link EventQueryParams}.
- * @param itemOptions the item options to be added into dimension items.
- * @return a {@link Map} of dimension items.
- */
- private Map> getDimensionItems(
- EventQueryParams params, Optional>> itemOptions) {
- Calendar calendar = PeriodType.getCalendar();
-
- List periodUids =
- calendar.isIso8601()
- ? getUids(params.getDimensionOrFilterItems(PERIOD_DIM_ID))
- : getLocalPeriodIdentifiers(params.getDimensionOrFilterItems(PERIOD_DIM_ID), calendar);
-
- Map> dimensionItems = new HashMap<>();
-
- dimensionItems.put(PERIOD_DIM_ID, periodUids);
-
- for (DimensionalObject dim : params.getDimensionsAndFilters()) {
- dimensionItems.put(dim.getDimension(), getDimensionalItemIds(dim.getItems()));
- }
-
- for (QueryItem item : params.getItems()) {
- String itemUid = getItemUid(item);
-
- if (item.hasOptionSet()) {
- if (itemOptions.isPresent()) {
- Map> itemOptionsMap = itemOptions.get();
-
- // The call itemOptions.get( itemUid ) can return null.
- // The query item can't have both legends and options.
- dimensionItems.put(
- itemUid,
- getDimensionItemUidsFrom(
- itemOptionsMap.get(itemUid), item.getOptionSetFilterItemsOrAll()));
- } else {
- dimensionItems.put(item.getItemId(), item.getOptionSetFilterItemsOrAll());
- }
- } else if (item.hasLegendSet()) {
- dimensionItems.put(itemUid, item.getLegendSetFilterItemsOrAll());
- } else {
- dimensionItems.put(itemUid, List.of());
- }
- }
-
- addItemFiltersToDimensionItems(params.getItemFilters(), dimensionItems);
-
- return dimensionItems;
- }
-
- private static void addItemFiltersToDimensionItems(
- List itemsFilter, Map> dimensionItems) {
- for (QueryItem item : itemsFilter) {
- if (item.hasOptionSet()) {
- dimensionItems.put(item.getItemId(), item.getOptionSetFilterItemsOrAll());
- } else if (item.hasLegendSet()) {
- dimensionItems.put(item.getItemId(), item.getLegendSetFilterItemsOrAll());
- } else {
- dimensionItems.put(
- item.getItemId(),
- item.getFiltersAsString() != null ? List.of(item.getFiltersAsString()) : emptyList());
- }
- }
- }
-
- /**
- * Based on the given arguments, this method will extract a list of UIDs of {@link Option}. If
- * itemOptions is null, it returns the default list of UIDs (defaultOptionUids). Otherwise, it
- * will return the list of UIDs from itemOptions.
- *
- * @param itemOptions a list of {@link Option} objects
- * @param defaultOptionUids a list of default {@link Option} UIDs.
- * @return a list of UIDs.
- */
- private List getDimensionItemUidsFrom(
- List itemOptions, List defaultOptionUids) {
- List dimensionUids = new ArrayList<>();
-
- if (itemOptions == null) {
- dimensionUids.addAll(defaultOptionUids);
- } else {
- dimensionUids.addAll(IdentifiableObjectUtils.getUids(itemOptions));
- }
-
- return dimensionUids;
- }
-
- /**
- * retrieve all periods as list of dimensional objects
- *
- * @param params
- * @return {@link EventQueryParams} object
- */
- protected List getPeriods(EventQueryParams params) {
- return List.of();
- }
}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/ResponseHelper.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/ResponseHelper.java
new file mode 100644
index 000000000000..5761736618c1
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/ResponseHelper.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2004-2024, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.tracker;
+
+import static lombok.AccessLevel.PRIVATE;
+import static org.apache.commons.lang3.StringUtils.joinWith;
+import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.PAGER;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import lombok.NoArgsConstructor;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.common.DimensionItemKeywords.Keyword;
+import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.common.Pager;
+import org.hisp.dhis.common.QueryItem;
+import org.hisp.dhis.common.SlimPager;
+import org.hisp.dhis.common.ValueStatus;
+
+@NoArgsConstructor(access = PRIVATE)
+public class ResponseHelper {
+
+ public static final int UNLIMITED_PAGING = 0;
+
+ /**
+ * Applies the headers to the given if the given query specifies headers.
+ *
+ * @param grid the {@link Grid}.
+ * @param params the {@link EventQueryParams}.
+ */
+ public static void applyHeaders(Grid grid, EventQueryParams params) {
+ if (params.hasHeaders()) {
+ grid.retainColumns(params.getHeaders());
+ }
+ }
+
+ /**
+ * Extracts a list of {@link Keyword} from the dimensions present in the given params.
+ *
+ * @param params where to extract the dimensions from.
+ * @return the list of keywords.
+ */
+ public static List getDimensionsKeywords(EventQueryParams params) {
+ return params.getDimensions().stream()
+ .map(DimensionalObject::getDimensionItemKeywords)
+ .filter(
+ dimensionItemKeywords ->
+ dimensionItemKeywords != null && !dimensionItemKeywords.isEmpty())
+ .flatMap(dk -> dk.getKeywords().stream())
+ .toList();
+ }
+
+ /**
+ * Add information about row context. The row context is based on the origin of the repeatable
+ * stage value. Please see the {@link ValueStatus}.
+ *
+ * @param grid the {@link Grid}.
+ */
+ public static void setRowContextColumns(Grid grid) {
+ Map> oldRowContext = grid.getRowContext();
+ Map> newRowContext = new TreeMap<>();
+
+ oldRowContext
+ .keySet()
+ .forEach(
+ rowKey -> {
+ Map newCols = new HashMap<>();
+ Map cols = oldRowContext.get(rowKey);
+ cols.keySet()
+ .forEach(
+ colKey ->
+ newCols.put(
+ Integer.toString(grid.getIndexOfHeader(colKey)), cols.get(colKey)));
+ newRowContext.put(rowKey, newCols);
+ });
+
+ grid.setRowContext(newRowContext);
+ }
+
+ /**
+ * Applies paging to the given grid if the given query specifies paging.
+ *
+ * @param params the {@link EventQueryParams}.
+ * @param totalCount the total count.
+ * @param grid the {@link Grid}.
+ */
+ public static void addPaging(EventQueryParams params, long totalCount, Grid grid) {
+ if (params.isPaging()) {
+ Pager pager =
+ params.isTotalPages()
+ ? new Pager(params.getPageWithDefault(), totalCount, params.getPageSizeWithDefault())
+ : new SlimPager(
+ params.getPageWithDefault(),
+ params.getPageSizeWithDefault(),
+ grid.hasLastDataRow());
+
+ grid.getMetaData().put(PAGER.getKey(), pager);
+ }
+ }
+
+ /**
+ * Based on the given item this method returns the correct UID based on internal rules.
+ *
+ * @param item the current QueryItem.
+ * @return the correct UID based on the item type.
+ */
+ public static String getItemUid(QueryItem item) {
+ String uid = item.getItem().getUid();
+
+ if (item.hasProgramStage()) {
+ uid = joinWith(".", item.getProgramStage().getUid(), uid);
+ }
+
+ return uid;
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/SchemeIdHandler.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/SchemeIdHandler.java
new file mode 100644
index 000000000000..43ea234712e6
--- /dev/null
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/tracker/SchemeIdHandler.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2004-2024, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.hisp.dhis.analytics.tracker;
+
+import static org.hisp.dhis.common.IdScheme.NAME;
+
+import java.util.LinkedHashSet;
+import lombok.RequiredArgsConstructor;
+import org.hisp.dhis.analytics.common.scheme.SchemeInfo;
+import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Data;
+import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Settings;
+import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
+import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.common.Grid;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class SchemeIdHandler {
+ private final SchemeIdResponseMapper schemeIdResponseMapper;
+
+ /**
+ * @param grid the {@link Grid}.
+ * @param params the {@link EventQueryParams}.
+ */
+ public void applyScheme(Grid grid, EventQueryParams params) {
+ if (params.hasDataIdScheme()) {
+ schemeIdResponseMapper.applyOptionAndLegendSetMapping(NAME, grid);
+ }
+
+ if (!params.isSkipMeta()) {
+ SchemeInfo schemeInfo = new SchemeInfo(schemeSettings(params), schemeData(params));
+ schemeIdResponseMapper.applyCustomIdScheme(schemeInfo, grid);
+ }
+ }
+
+ private Data schemeData(EventQueryParams params) {
+ return Data.builder()
+ .dataElements(params.getAllDataElements())
+ .dimensionalItemObjects(new LinkedHashSet<>(params.getAllDimensionItems()))
+ .dataElementOperands(params.getDataElementOperands())
+ .options(params.getItemOptions())
+ .organizationUnits(params.getOrganisationUnits())
+ .program(params.getProgram())
+ .programStage(params.getProgramStage())
+ .indicators(params.getIndicators())
+ .programIndicators(params.getProgramIndicators())
+ .build();
+ }
+
+ private Settings schemeSettings(EventQueryParams params) {
+ return Settings.builder()
+ .dataIdScheme(params.getDataIdScheme())
+ .outputDataElementIdScheme(params.getOutputDataElementIdScheme())
+ .outputDataItemIdScheme(params.getOutputDataItemIdScheme())
+ .outputIdScheme(params.getOutputIdScheme())
+ .outputOrgUnitIdScheme(params.getOutputOrgUnitIdScheme())
+ .outputFormat(params.getOutputFormat())
+ .build();
+ }
+}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceBaseTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceBaseTest.java
index fa28f4ab3e75..5a0969dba201 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceBaseTest.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceBaseTest.java
@@ -47,7 +47,7 @@
import org.hisp.dhis.analytics.data.handler.HeaderHandler;
import org.hisp.dhis.analytics.data.handler.MetadataHandler;
import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
+import org.hisp.dhis.analytics.event.data.EventAggregateService;
import org.hisp.dhis.analytics.resolver.ExpressionResolvers;
import org.hisp.dhis.expression.ExpressionService;
import org.hisp.dhis.external.conf.DhisConfigurationProvider;
@@ -82,7 +82,7 @@ abstract class AnalyticsServiceBaseTest {
@Mock private SystemSettingManager systemSettingManager;
- @Mock protected EventAnalyticsService eventAnalyticsService;
+ @Mock protected EventAggregateService eventAggregatedService;
@Mock private DataQueryService dataQueryService;
@@ -111,7 +111,7 @@ public void baseSetUp() {
new MetadataHandler(dataQueryService, schemeIdResponseMapper, userService);
DataHandler dataHandler =
new DataHandler(
- eventAnalyticsService,
+ eventAggregatedService,
rawAnalyticsManager,
resolvers,
expressionService,
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceProgramDataElementTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceProgramDataElementTest.java
index ddfe568a547a..f7c67f183558 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceProgramDataElementTest.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceProgramDataElementTest.java
@@ -100,12 +100,12 @@ void verifyProgramDataElementInQueryCallsEventsAnalytics() {
any(DataQueryParams.class), eq(AnalyticsTableType.DATA_VALUE), eq(0)))
.thenReturn(CompletableFuture.completedFuture(emptyData));
- when(eventAnalyticsService.getAggregatedEventData(any(EventQueryParams.class)))
+ when(eventAggregatedService.getAggregatedData(any(EventQueryParams.class)))
.thenReturn(new ListGrid());
target.getAggregatedDataValueGrid(params);
- verify(eventAnalyticsService).getAggregatedEventData(capturedParams.capture());
+ verify(eventAggregatedService).getAggregatedData(capturedParams.capture());
EventQueryParams data = capturedParams.getValue();
assertThat(data.hasValueDimension(), is(false));
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateServiceTest.java
similarity index 67%
rename from dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java
rename to dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateServiceTest.java
index fbd8d67144a5..3a9a90411c8c 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAggregateServiceTest.java
@@ -31,6 +31,14 @@
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
+import static org.hisp.dhis.analytics.AggregationType.COUNT;
+import static org.hisp.dhis.analytics.AggregationType.NONE;
+import static org.hisp.dhis.common.DimensionType.PERIOD;
+import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID;
+import static org.hisp.dhis.common.ValueType.COORDINATE;
+import static org.hisp.dhis.common.ValueType.NUMBER;
+import static org.hisp.dhis.common.ValueType.TEXT;
import static org.hisp.dhis.test.TestBase.createDataElement;
import static org.hisp.dhis.test.TestBase.createOrganisationUnit;
import static org.hisp.dhis.test.TestBase.injectSecurityContext;
@@ -38,11 +46,13 @@
import static org.mockito.Mockito.when;
import java.util.List;
-import org.hisp.dhis.analytics.AggregationType;
import org.hisp.dhis.analytics.AnalyticsSecurityManager;
-import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
+import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.EventQueryPlanner;
import org.hisp.dhis.analytics.event.EventQueryValidator;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
import org.hisp.dhis.common.BaseDimensionalObject;
import org.hisp.dhis.common.DhisApiVersion;
import org.hisp.dhis.common.DimensionType;
@@ -57,9 +67,7 @@
import org.hisp.dhis.period.Period;
import org.hisp.dhis.program.Program;
import org.hisp.dhis.program.ProgramStage;
-import org.hisp.dhis.system.grid.ListGrid;
import org.hisp.dhis.user.SystemUser;
-import org.hisp.dhis.user.UserService;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -69,32 +77,26 @@
import org.opengis.geometry.primitive.Point;
/**
- * This class only tests the "shared" code of AbstractAnalyticsService, which includes Grid header
- * generation and Grid Metadata
+ * Unit tests for {@link EnrollmentAggregateService}.
*
* @author Luciano Fiandesio
*/
@ExtendWith(MockitoExtension.class)
-class AbstractAnalyticsServiceTest {
- private Period peA;
+class EnrollmentAggregateServiceTest {
- private OrganisationUnit ouA;
+ private EnrollmentAggregateService dummyAnalyticsService;
- private DataElement deA;
-
- private DataElement deB;
-
- private DataElement deC;
+ @Mock private AnalyticsSecurityManager securityManager;
- private DummyAnalyticsService dummyAnalyticsService;
+ @Mock private EnrollmentAnalyticsManager enrollmentAnalyticsManager;
- @Mock private AnalyticsSecurityManager securityManager;
+ @Mock private EventQueryValidator queryValidator;
- @Mock private EventQueryValidator eventQueryValidator;
+ @Mock private EventQueryPlanner queryPlanner;
- @Mock private SchemeIdResponseMapper schemeIdResponseMapper;
+ @Mock private MetadataItemsHandler metadataHandler;
- @Mock private UserService userService;
+ @Mock private SchemeIdHandler schemeIdHandler;
@BeforeAll
static void setup() {
@@ -104,27 +106,27 @@ static void setup() {
@BeforeEach
public void setUp() {
dummyAnalyticsService =
- new DummyAnalyticsService(
- securityManager, eventQueryValidator, schemeIdResponseMapper, userService);
-
- peA = MonthlyPeriodType.getPeriodFromIsoString("201701");
- ouA = createOrganisationUnit('A');
- deA = createDataElement('A', ValueType.TEXT, AggregationType.NONE);
-
- deB = createDataElement('B', ValueType.ORGANISATION_UNIT, AggregationType.NONE);
- deC = createDataElement('C', ValueType.NUMBER, AggregationType.COUNT);
+ new EnrollmentAggregateService(
+ enrollmentAnalyticsManager,
+ queryPlanner,
+ securityManager,
+ queryValidator,
+ metadataHandler,
+ schemeIdHandler);
}
@Test
void verifyHeaderCreationBasedOnQueryItemsAndDimensions() {
- DimensionalObject periods =
- new BaseDimensionalObject(
- DimensionalObject.PERIOD_DIM_ID, DimensionType.PERIOD, List.of(peA));
-
+ // Given
+ Period peA = MonthlyPeriodType.getPeriodFromIsoString("201701");
+ OrganisationUnit ouA = createOrganisationUnit('A');
+ DataElement deA = createDataElement('A', TEXT, NONE);
+ DataElement deB = createDataElement('B', ValueType.ORGANISATION_UNIT, NONE);
+ DataElement deC = createDataElement('C', NUMBER, COUNT);
+ DimensionalObject periods = new BaseDimensionalObject(PERIOD_DIM_ID, PERIOD, List.of(peA));
DimensionalObject orgUnits =
new BaseDimensionalObject(
- DimensionalObject.ORGUNIT_DIM_ID, DimensionType.ORGANISATION_UNIT, "ouA", List.of(ouA));
-
+ ORGUNIT_DIM_ID, DimensionType.ORGANISATION_UNIT, "ouA", List.of(ouA));
QueryItem qiA = new QueryItem(deA, null, deA.getValueType(), deA.getAggregationType(), null);
QueryItem qiB = new QueryItem(deB, null, deB.getValueType(), deB.getAggregationType(), null);
QueryItem qiC = new QueryItem(deC, null, deC.getValueType(), deC.getAggregationType(), null);
@@ -142,47 +144,52 @@ void verifyHeaderCreationBasedOnQueryItemsAndDimensions() {
.withApiVersion(DhisApiVersion.V33)
.build();
+ // When
when(securityManager.withUserConstraints(any(EventQueryParams.class))).thenReturn(params);
+ Grid grid = dummyAnalyticsService.getEnrollments(params);
- Grid grid = dummyAnalyticsService.getGrid(params);
-
+ // Then
List headers = grid.getHeaders();
assertThat(headers, is(notNullValue()));
- assertThat(headers, hasSize(4));
+ assertThat(headers, hasSize(6));
- assertHeaderWithColumn(headers.get(0), "ou", "ouA", ValueType.TEXT, String.class.getName());
+ assertHeaderWithColumn(headers.get(0), "value", "Value", NUMBER, Double.class.getName());
+ assertHeaderWithColumn(headers.get(1), "ou", "ouA", TEXT, String.class.getName());
+ assertHeaderWithColumn(headers.get(2), "pe", null, TEXT, String.class.getName());
assertHeaderWithColumn(
- headers.get(1), deA.getUid(), deA.getName(), ValueType.TEXT, String.class.getName());
+ headers.get(3), deA.getUid(), deA.getName(), TEXT, String.class.getName());
assertHeaderWithColumn(
- headers.get(2), deB.getUid(), deB.getName(), ValueType.COORDINATE, Point.class.getName());
+ headers.get(4), deB.getUid(), deB.getName(), COORDINATE, Point.class.getName());
assertHeaderWithColumn(
- headers.get(3), deC.getUid(), deC.getName(), ValueType.NUMBER, Double.class.getName());
+ headers.get(5), deC.getUid(), deC.getName(), NUMBER, Double.class.getName());
}
@Test
void verifyHeaderCreationBasedOnQueryItemsAndDimensionsWithSameNamesMultiStage() {
+ // Given
+ Period peA = MonthlyPeriodType.getPeriodFromIsoString("201701");
+ OrganisationUnit ouA = createOrganisationUnit('A');
+
ProgramStage psA = new ProgramStage("ps", new Program());
psA.setUid("psA12345678");
ProgramStage psB = new ProgramStage("ps", new Program());
psB.setUid("psB12345678");
- DataElement deD = createDataElement('D', ValueType.NUMBER, AggregationType.COUNT);
+ DataElement deD = createDataElement('D', NUMBER, COUNT);
deD.setName("same");
- DataElement deE = createDataElement('E', ValueType.NUMBER, AggregationType.COUNT);
+ DataElement deE = createDataElement('E', NUMBER, COUNT);
deE.setName("same");
- DataElement deF = createDataElement('F', ValueType.NUMBER, AggregationType.COUNT);
+ DataElement deF = createDataElement('F', NUMBER, COUNT);
deF.setName("unique");
- DimensionalObject periods =
- new BaseDimensionalObject(
- DimensionalObject.PERIOD_DIM_ID, DimensionType.PERIOD, List.of(peA));
-
+ DataElement deB = createDataElement('B', ValueType.ORGANISATION_UNIT, NONE);
+ DimensionalObject periods = new BaseDimensionalObject(PERIOD_DIM_ID, PERIOD, List.of(peA));
DimensionalObject orgUnits =
new BaseDimensionalObject(
- DimensionalObject.ORGUNIT_DIM_ID, DimensionType.ORGANISATION_UNIT, "ouA", List.of(ouA));
+ ORGUNIT_DIM_ID, DimensionType.ORGANISATION_UNIT, "ouA", List.of(ouA));
QueryItem qiD = new QueryItem(deD, null, deD.getValueType(), deD.getAggregationType(), null);
qiD.setProgramStage(psA);
@@ -206,30 +213,33 @@ void verifyHeaderCreationBasedOnQueryItemsAndDimensionsWithSameNamesMultiStage()
.withApiVersion(DhisApiVersion.V33)
.build();
+ // When
when(securityManager.withUserConstraints(any(EventQueryParams.class))).thenReturn(params);
+ Grid grid = dummyAnalyticsService.getEnrollments(params);
- Grid grid = dummyAnalyticsService.getGrid(params);
-
+ // Then
List headers = grid.getHeaders();
assertThat(headers, is(notNullValue()));
- assertThat(headers, hasSize(4));
+ assertThat(headers, hasSize(6));
- assertHeaderWithColumn(headers.get(0), "ou", "ouA", ValueType.TEXT, String.class.getName());
+ assertHeaderWithColumn(headers.get(0), "value", "Value", NUMBER, Double.class.getName());
+ assertHeaderWithColumn(headers.get(1), "ou", "ouA", TEXT, String.class.getName());
+ assertHeaderWithColumn(headers.get(2), "pe", null, TEXT, String.class.getName());
// Same item names with different program stages.
assertHeaderWithDisplayColumn(
- headers.get(1),
+ headers.get(3),
psA.getUid() + "." + deD.getUid(),
deD.getName(),
deD.getName() + " - " + psA.getName(),
- ValueType.NUMBER,
+ NUMBER,
Double.class.getName());
assertHeaderWithDisplayColumn(
- headers.get(2),
+ headers.get(4),
psB.getUid() + "." + deE.getUid(),
deE.getName(),
deE.getName() + " - " + psB.getName(),
- ValueType.NUMBER,
+ NUMBER,
Double.class.getName());
}
@@ -256,23 +266,3 @@ private void assertHeaderWithDisplayColumn(
assertThat("Header type does not match", expected.getType(), is(type));
}
}
-
-class DummyAnalyticsService extends AbstractAnalyticsService {
- public DummyAnalyticsService(
- AnalyticsSecurityManager securityManager,
- EventQueryValidator queryValidator,
- SchemeIdResponseMapper schemeIdResponseMapper,
- UserService userService) {
- super(securityManager, queryValidator, schemeIdResponseMapper, userService);
- }
-
- @Override
- protected Grid createGridWithHeaders(EventQueryParams params) {
- return new ListGrid();
- }
-
- @Override
- protected long addData(Grid grid, EventQueryParams params) {
- return 0;
- }
-}
diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryServiceTest.java
similarity index 80%
rename from dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java
rename to dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryServiceTest.java
index b011982f349f..213106dc8284 100644
--- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java
+++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryServiceTest.java
@@ -41,27 +41,22 @@
import com.google.common.collect.Sets;
import org.hisp.dhis.analytics.AnalyticsSecurityManager;
-import org.hisp.dhis.analytics.cache.AnalyticsCache;
import org.hisp.dhis.analytics.common.scheme.SchemeInfo;
import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Data;
import org.hisp.dhis.analytics.common.scheme.SchemeInfo.Settings;
import org.hisp.dhis.analytics.data.handler.SchemeIdResponseMapper;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsManager;
import org.hisp.dhis.analytics.event.EventAnalyticsManager;
-import org.hisp.dhis.analytics.event.EventDataQueryService;
import org.hisp.dhis.analytics.event.EventQueryParams;
import org.hisp.dhis.analytics.event.EventQueryPlanner;
import org.hisp.dhis.analytics.event.EventQueryValidator;
import org.hisp.dhis.analytics.table.model.Partitions;
+import org.hisp.dhis.analytics.tracker.MetadataItemsHandler;
+import org.hisp.dhis.analytics.tracker.SchemeIdHandler;
import org.hisp.dhis.common.IdScheme;
-import org.hisp.dhis.dataelement.DataElementService;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.program.Program;
-import org.hisp.dhis.system.database.DatabaseInfo;
import org.hisp.dhis.system.database.DatabaseInfoProvider;
-import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;
import org.hisp.dhis.user.SystemUser;
-import org.hisp.dhis.user.UserService;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -75,33 +70,27 @@
* @author maikel arabori
*/
@ExtendWith(MockitoExtension.class)
-class DefaultEventAnalyticsServiceTest {
- private DefaultEventAnalyticsService defaultEventAnalyticsService;
+class EventQueryServiceTest {
+ @Mock private EventQueryService eventQueryService;
- @Mock private AnalyticsSecurityManager securityManager;
-
- @Mock private EventQueryValidator eventQueryValidator;
+ @Mock private EventQueryValidator queryValidator;
- @Mock private DataElementService dataElementService;
+ @Mock private MetadataItemsHandler metadataHandler;
- @Mock private TrackedEntityAttributeService trackedEntityAttributeService;
+ @Mock private SchemeIdHandler schemeIdHandler;
- @Mock private EventAnalyticsManager eventAnalyticsManager;
+ @Mock private AnalyticsSecurityManager securityManager;
- @Mock private EnrollmentAnalyticsManager enrollmentAnalyticsManager;
+ @Mock private EventQueryValidator eventQueryValidator;
- @Mock private EventDataQueryService eventDataQueryService;
+ @Mock private EventAnalyticsManager eventAnalyticsManager;
@Mock private EventQueryPlanner queryPlanner;
@Mock private DatabaseInfoProvider databaseInfoProvider;
- @Mock private AnalyticsCache analyticsCache;
-
@Mock private SchemeIdResponseMapper schemeIdResponseMapper;
- @Mock private UserService userService;
-
@BeforeAll
static void setup() {
injectSecurityContext(new SystemUser());
@@ -109,21 +98,15 @@ static void setup() {
@BeforeEach
public void setUp() {
- when(databaseInfoProvider.getDatabaseInfo()).thenReturn(DatabaseInfo.builder().build());
- defaultEventAnalyticsService =
- new DefaultEventAnalyticsService(
- dataElementService,
- trackedEntityAttributeService,
- eventAnalyticsManager,
- eventDataQueryService,
+ eventQueryService =
+ new EventQueryService(
securityManager,
+ queryValidator,
+ eventAnalyticsManager,
queryPlanner,
- eventQueryValidator,
databaseInfoProvider,
- analyticsCache,
- enrollmentAnalyticsManager,
- schemeIdResponseMapper,
- userService);
+ metadataHandler,
+ schemeIdHandler);
}
@Test
@@ -137,10 +120,9 @@ void testOutputSchemeWhenSchemeIsSet() {
doNothing().when(securityManager).decideAccessEventQuery(mockParams);
when(securityManager.withUserConstraints(mockParams)).thenReturn(mockParams);
- doNothing().when(eventQueryValidator).validate(mockParams);
when(queryPlanner.planEventQuery(any(EventQueryParams.class))).thenReturn(mockParams);
- defaultEventAnalyticsService.getEvents(mockParams);
+ eventQueryService.getEvents(mockParams);
verify(schemeIdResponseMapper, atMost(1)).getSchemeIdResponseMap(mockSchemeInfo);
}
@@ -156,10 +138,9 @@ void testOutputSchemeWhenNoSchemeIsSet() {
doNothing().when(securityManager).decideAccessEventQuery(mockParams);
when(securityManager.withUserConstraints(mockParams)).thenReturn(mockParams);
- doNothing().when(eventQueryValidator).validate(mockParams);
when(queryPlanner.planEventQuery(any(EventQueryParams.class))).thenReturn(mockParams);
- defaultEventAnalyticsService.getEvents(mockParams);
+ eventQueryService.getEvents(mockParams);
verify(schemeIdResponseMapper, never()).getSchemeIdResponseMap(mockSchemeInfo);
}
diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/chart/impl/DefaultChartService.java b/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/chart/impl/DefaultChartService.java
index 3fc980ff3fae..b9765a088bb9 100644
--- a/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/chart/impl/DefaultChartService.java
+++ b/dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/chart/impl/DefaultChartService.java
@@ -48,7 +48,7 @@
import org.apache.commons.math3.exception.MathRuntimeException;
import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.hisp.dhis.analytics.AnalyticsService;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
+import org.hisp.dhis.analytics.event.data.EventAggregateService;
import org.hisp.dhis.category.CategoryOptionCombo;
import org.hisp.dhis.common.AnalyticsType;
import org.hisp.dhis.common.DimensionalObject;
@@ -165,7 +165,7 @@ public class DefaultChartService implements ChartService {
private final AnalyticsService analyticsService;
- private final EventAnalyticsService eventAnalyticsService;
+ private final EventAggregateService eventAggregationService;
// -------------------------------------------------------------------------
// ChartService implementation
@@ -726,13 +726,13 @@ private CategoryDataset[] getCategoryDataSet(PlotData plotData) {
valueMap = analyticsService.getAggregatedDataValueMapping(plotData.getVisualization());
} else {
if (plotData.getEventChart() != null) {
- Grid grid = eventAnalyticsService.getAggregatedEventData(plotData.getEventChart());
+ Grid grid = eventAggregationService.getAggregatedData(plotData.getEventChart());
plotData.getEventChart().setDataItemGrid(grid);
valueMap = GridUtils.getMetaValueMapping(grid, (grid.getWidth() - 1));
} else {
- Grid grid = eventAnalyticsService.getAggregatedEventData(plotData.getEventVisualization());
+ Grid grid = eventAggregationService.getAggregatedData(plotData.getEventVisualization());
plotData.getEventVisualization().setDataItemGrid(grid);
diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceMetadataTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceMetadataTest.java
index ef10b536ff38..e06533dca7ff 100644
--- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceMetadataTest.java
+++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceMetadataTest.java
@@ -38,7 +38,6 @@
import java.util.Set;
import org.hisp.dhis.analytics.AggregationType;
import org.hisp.dhis.analytics.AnalyticsMetaDataKey;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
import org.hisp.dhis.analytics.event.EventQueryParams;
import org.hisp.dhis.common.BaseDimensionalObject;
import org.hisp.dhis.common.DhisApiVersion;
@@ -114,7 +113,7 @@ class EventAnalyticsServiceMetadataTest extends PostgresIntegrationTestBase {
private Program prA;
- @Autowired private EventAnalyticsService eventAnalyticsService;
+ @Autowired private EventAggregateService eventAggregateService;
@BeforeAll
void setUp() {
@@ -192,7 +191,7 @@ void testGetQueryItemDimensionMetadata() {
.withDisplayProperty(DisplayProperty.NAME)
.build();
- Grid grid = eventAnalyticsService.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
Map metadata = grid.getMetaData();
assertNotNull(metadata);
Map dimensionItems =
@@ -248,7 +247,7 @@ void testGetQueryItemMetadata() {
.withSkipMeta(false)
.withApiVersion(DhisApiVersion.V29)
.build();
- Grid grid = eventAnalyticsService.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
Map metadata = grid.getMetaData();
Map itemMap =
(Map) metadata.get(AnalyticsMetaDataKey.ITEMS.getKey());
diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java
index 826958ec71b1..c0015199f013 100644
--- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java
+++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java
@@ -75,8 +75,6 @@
import org.hisp.dhis.analytics.AnalyticsTableUpdateParams;
import org.hisp.dhis.analytics.EventOutputType;
import org.hisp.dhis.analytics.OrgUnitField;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsService;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
import org.hisp.dhis.analytics.event.EventQueryParams;
import org.hisp.dhis.category.Category;
import org.hisp.dhis.category.CategoryCombo;
@@ -143,9 +141,13 @@
@TestInstance(Lifecycle.PER_CLASS)
@Transactional
class EventAnalyticsServiceTest extends PostgresIntegrationTestBase {
- @Autowired private EventAnalyticsService eventTarget;
+ @Autowired private EventQueryService eventQueryTarget;
- @Autowired private EnrollmentAnalyticsService enrollmentTarget;
+ @Autowired private EventAggregateService eventAggregateService;
+
+ @Autowired private EnrollmentQueryService enrollmentQueryTarget;
+
+ @Autowired private EnrollmentAggregateService enrollmentAggregateService;
@Autowired private List analyticsTableServices;
@@ -630,7 +632,7 @@ void testDimensionRestrictionSuccessfully() {
.build();
// Then
- assertDoesNotThrow(() -> eventTarget.getAggregatedEventData(events_2017_params));
+ assertDoesNotThrow(() -> eventAggregateService.getAggregatedData(events_2017_params));
}
@Test
@@ -672,7 +674,7 @@ void testDimensionRestrictionWhenUserCannotReadCategoryOptions() {
Throwable exception =
assertThrows(
IllegalQueryException.class,
- () -> eventTarget.getAggregatedEventData(events_2017_params));
+ () -> eventAggregateService.getAggregatedData(events_2017_params));
assertThat(
exception.getMessage(),
@@ -684,7 +686,7 @@ void testDimensionRestrictionWhenUserCannotReadCategoryOptions() {
void testEnrollmentWithCategoryDimensionRestriction() {
injectSecurityContextUser(userA);
EventQueryParams params = getEnrollmentQueryBuilderA().build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -704,7 +706,7 @@ void testGetAggregatedEventDataWithRegistrationOrgUnit() {
EventQueryParams params =
getAggregatedQueryBuilderA().withOrgUnitField(new OrgUnitField("REGISTRATION")).build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -722,7 +724,7 @@ void testGetAggregatedEventDataWithEnrollmentOrgUnit() {
EventQueryParams params =
getAggregatedQueryBuilderA().withOrgUnitField(new OrgUnitField("ENROLLMENT")).build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -740,7 +742,7 @@ void testGetAggregatedEventDataWithOwnerAtStart() {
EventQueryParams params =
getAggregatedQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_START")).build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -758,7 +760,7 @@ void testGetAggregatedEventDataWithOwnerAtEnd() {
EventQueryParams params =
getAggregatedQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_END")).build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -775,7 +777,7 @@ void testGetAggregatedEventDataWithOwnerAtEnd() {
void testGetAggregatedEventDataWithDefaultEventOrgUnit() {
EventQueryParams params = getAggregatedQueryBuilderA().build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -793,7 +795,7 @@ void testGetAggregatedEventDataWithDataElementOrgUnit() {
EventQueryParams params =
getAggregatedQueryBuilderA().withOrgUnitField(new OrgUnitField(deU.getUid())).build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -815,7 +817,7 @@ void testGetEventsWithRegistrationOrgUnit() {
EventQueryParams params =
getEventQueryBuilderA().withOrgUnitField(new OrgUnitField("REGISTRATION")).build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
assertGridContains(
// Headers
@@ -833,7 +835,7 @@ void testGetEventsWithEnrollmentOrgUnit() {
EventQueryParams params =
getEventQueryBuilderA().withOrgUnitField(new OrgUnitField("ENROLLMENT")).build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
assertGridContains(
// Headers
@@ -851,7 +853,7 @@ void testGetEventsWithOwnerAtStart() {
EventQueryParams params =
getEventQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_START")).build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
// Note that owner at start does not change with each event because
// there is no monthly aggregation.
@@ -871,7 +873,7 @@ void testGetEventsWithOwnerAtEnd() {
EventQueryParams params =
getEventQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_END")).build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
// Note that owner at end does not change with each event because
// there is no monthly aggregation.
@@ -890,7 +892,7 @@ void testGetEventsWithOwnerAtEnd() {
void testGetEventsWithDefaultEventOrgUnit() {
EventQueryParams params = getEventQueryBuilderA().build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
assertGridContains(
// Headers
@@ -908,7 +910,7 @@ void testGetEventsWithDataElementOrgUnit() {
EventQueryParams params =
getEventQueryBuilderA().withOrgUnitField(new OrgUnitField(deU.getUid())).build();
- Grid grid = eventTarget.getEvents(params);
+ Grid grid = eventQueryTarget.getEvents(params);
assertGridContains(
// Headers
@@ -930,7 +932,7 @@ void testGetEnrollmentsWithRegistrationOrgUnit() {
EventQueryParams params =
getEnrollmentQueryBuilderA().withOrgUnitField(new OrgUnitField("REGISTRATION")).build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -946,7 +948,7 @@ void testGetEnrollmentsWithEnrollmentOrgUnit() {
EventQueryParams params =
getEnrollmentQueryBuilderA().withOrgUnitField(new OrgUnitField("ENROLLMENT")).build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -963,7 +965,7 @@ void testGetEnrollmentsWithOwnerAtStart() {
EventQueryParams params =
getEnrollmentQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_START")).build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -983,7 +985,7 @@ void testGetEnrollmentsWithOwnerAtEnd() {
EventQueryParams params =
getEnrollmentQueryBuilderA().withOrgUnitField(new OrgUnitField("OWNER_AT_END")).build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -998,7 +1000,7 @@ void testGetEnrollmentsWithOwnerAtEnd() {
void testGetEnrollmentsWithDefaultEnrollmentOrgUnit() {
EventQueryParams params = getEnrollmentQueryBuilderA().build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -1014,7 +1016,7 @@ void testGetEnrollmentsWithAttributeOrgUnit() {
EventQueryParams params =
getEnrollmentQueryBuilderA().withOrgUnitField(new OrgUnitField(atU.getUid())).build();
- Grid grid = enrollmentTarget.getEnrollments(params);
+ Grid grid = enrollmentQueryTarget.getEnrollments(params);
assertGridContains(
// Headers
@@ -1042,7 +1044,7 @@ void testEventProgramIndicatorWithNoOrgUnitField() {
.withOrganisationUnits(level3Ous)
.build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -1068,7 +1070,7 @@ void testEventProgramIndicatorWithOrgUnitFieldAtStart() {
.withOrganisationUnits(level3Ous)
.build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -1094,7 +1096,7 @@ void testEventProgramIndicatorWithOrgUnitFieldAtEnd() {
.withOrganisationUnits(level3Ous)
.build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -1125,7 +1127,7 @@ void testEnrollmentProgramIndicatorWithOrgUnitFieldAtStart() {
.withOrganisationUnits(level3Ous)
.build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -1156,7 +1158,7 @@ void testEnrollmentProgramIndicatorWithOrgUnitFieldAtEnd() {
.withOrganisationUnits(level3Ous)
.build();
- Grid grid = eventTarget.getAggregatedEventData(params);
+ Grid grid = eventAggregateService.getAggregatedData(params);
assertGridContains(
// Headers
@@ -1440,7 +1442,7 @@ private Grid getTestAggregatedGrid(String expression, AggregationType aggregatio
.withOrganisationUnits(List.of(ouA, ouI, ouJ))
.build();
- return eventTarget.getAggregatedEventData(params);
+ return eventAggregateService.getAggregatedData(params);
}
/** Creates program indicator for program A with orgUnitField. */
diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentAggregateAnalyticsController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentAggregateAnalyticsController.java
index 17d4cf0f8eba..80fff37c2664 100644
--- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentAggregateAnalyticsController.java
+++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentAggregateAnalyticsController.java
@@ -30,13 +30,19 @@
import static org.hisp.dhis.common.DhisApiVersion.ALL;
import static org.hisp.dhis.common.DhisApiVersion.DEFAULT;
import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.AGGREGATE;
-import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.QUERY;
+import static org.hisp.dhis.common.RequestTypeAware.EndpointItem.ENROLLMENT;
import static org.hisp.dhis.common.cache.CacheStrategy.RESPECT_SYSTEM_SETTING;
-import static org.hisp.dhis.period.PeriodDataProvider.DataSource.DATABASE;
-import static org.hisp.dhis.period.PeriodDataProvider.DataSource.SYSTEM_DEFINED;
import static org.hisp.dhis.security.Authorities.F_PERFORM_ANALYTICS_EXPLAIN;
import static org.hisp.dhis.setting.SettingKey.ANALYSIS_RELATIVE_PERIOD;
import static org.hisp.dhis.setting.SettingKey.ANALYTICS_MAX_LIMIT;
+import static org.hisp.dhis.system.grid.GridUtils.toCsv;
+import static org.hisp.dhis.system.grid.GridUtils.toHtml;
+import static org.hisp.dhis.system.grid.GridUtils.toHtmlCss;
+import static org.hisp.dhis.system.grid.GridUtils.toXls;
+import static org.hisp.dhis.system.grid.GridUtils.toXlsx;
+import static org.hisp.dhis.system.grid.GridUtils.toXml;
+import static org.hisp.dhis.util.PeriodCriteriaUtils.defineDefaultPeriodForCriteria;
+import static org.hisp.dhis.webapi.dimension.EnrollmentAnalyticsPrefixStrategy.INSTANCE;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_CSV;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_EXCEL;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_HTML;
@@ -53,29 +59,21 @@
import org.hisp.dhis.analytics.analyze.ExecutionPlanStore;
import org.hisp.dhis.analytics.dimensions.AnalyticsDimensionsPagingWrapper;
import org.hisp.dhis.analytics.event.EnrollmentAnalyticsDimensionsService;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsService;
import org.hisp.dhis.analytics.event.EventDataQueryService;
import org.hisp.dhis.analytics.event.EventQueryParams;
-import org.hisp.dhis.analytics.table.setting.AnalyticsTableSettings;
-import org.hisp.dhis.analytics.util.AnalyticsPeriodCriteriaUtils;
+import org.hisp.dhis.analytics.event.data.EnrollmentAggregateService;
import org.hisp.dhis.common.DhisApiVersion;
import org.hisp.dhis.common.DimensionsCriteria;
import org.hisp.dhis.common.EnrollmentAnalyticsQueryCriteria;
import org.hisp.dhis.common.EventDataQueryRequest;
import org.hisp.dhis.common.Grid;
import org.hisp.dhis.common.OpenApi;
-import org.hisp.dhis.common.RequestTypeAware;
-import org.hisp.dhis.common.RequestTypeAware.EndpointAction;
import org.hisp.dhis.datavalue.DataValue;
-import org.hisp.dhis.period.PeriodDataProvider;
import org.hisp.dhis.period.RelativePeriodEnum;
import org.hisp.dhis.security.RequiresAuthority;
import org.hisp.dhis.setting.SystemSettingManager;
-import org.hisp.dhis.system.grid.GridUtils;
-import org.hisp.dhis.util.PeriodCriteriaUtils;
import org.hisp.dhis.webapi.dimension.DimensionFilteringAndPagingService;
import org.hisp.dhis.webapi.dimension.DimensionMapperService;
-import org.hisp.dhis.webapi.dimension.EnrollmentAnalyticsPrefixStrategy;
import org.hisp.dhis.webapi.mvc.annotation.ApiVersion;
import org.hisp.dhis.webapi.utils.ContextUtils;
import org.springframework.stereotype.Controller;
@@ -85,9 +83,6 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
-/**
- * @author Markus Bekken
- */
@OpenApi.Document(domain = DataValue.class)
@Controller
@ApiVersion({DEFAULT, ALL})
@@ -96,7 +91,7 @@
public class EnrollmentAggregateAnalyticsController {
@Nonnull private final EventDataQueryService eventDataQueryService;
- @Nonnull private final EnrollmentAnalyticsService analyticsService;
+ @Nonnull private final EnrollmentAggregateService enrollmentAggregateService;
@Nonnull private final ContextUtils contextUtils;
@@ -110,10 +105,6 @@ public class EnrollmentAggregateAnalyticsController {
@Nonnull private final SystemSettingManager systemSettingManager;
- @Nonnull private final PeriodDataProvider periodDataProvider;
-
- @Nonnull private final AnalyticsTableSettings analyticsTableSettings;
-
@RequiresAuthority(anyOf = F_PERFORM_ANALYTICS_EXPLAIN)
@GetMapping(
value = "/{program}/explain",
@@ -123,9 +114,9 @@ public class EnrollmentAggregateAnalyticsController {
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, true, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, true);
- Grid grid = analyticsService.getEnrollments(params);
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
contextUtils.configureResponse(response, CONTENT_TYPE_JSON, RESPECT_SYSTEM_SETTING);
if (params.analyzeOnly()) {
@@ -144,11 +135,11 @@ public class EnrollmentAggregateAnalyticsController {
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(response, CONTENT_TYPE_JSON, RESPECT_SYSTEM_SETTING);
- return analyticsService.getEnrollments(params);
+ return enrollmentAggregateService.getEnrollments(params);
}
@SneakyThrows
@@ -158,12 +149,12 @@ public void getAggregateXml(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_XML, RESPECT_SYSTEM_SETTING, "enrollments.xml", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXml(grid, response.getOutputStream());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toXml(grid, response.getOutputStream());
}
@SneakyThrows
@@ -173,12 +164,12 @@ public void getAggregateXls(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_EXCEL, RESPECT_SYSTEM_SETTING, "enrollments.xls", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXls(grid, response.getOutputStream());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toXls(grid, response.getOutputStream());
}
@SneakyThrows
@@ -188,12 +179,12 @@ public void getAggregateXlsx(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_EXCEL, RESPECT_SYSTEM_SETTING, "enrollments.xlsx", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXlsx(grid, response.getOutputStream());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toXlsx(grid, response.getOutputStream());
}
@SneakyThrows
@@ -203,12 +194,12 @@ public void getAggregateCsv(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_CSV, RESPECT_SYSTEM_SETTING, "enrollments.csv", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toCsv(grid, response.getWriter());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toCsv(grid, response.getWriter());
}
@SneakyThrows
@@ -218,12 +209,12 @@ public void getAggregateHtml(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_HTML, RESPECT_SYSTEM_SETTING, "enrollments.html", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toHtml(grid, response.getWriter());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toHtml(grid, response.getWriter());
}
@SneakyThrows
@@ -233,12 +224,12 @@ public void getAggregateHtmlCss(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_HTML, RESPECT_SYSTEM_SETTING, "enrollments.html", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toHtmlCss(grid, response.getWriter());
+ Grid grid = enrollmentAggregateService.getEnrollments(params);
+ toHtmlCss(grid, response.getWriter());
}
@ResponseBody
@@ -252,7 +243,7 @@ public AnalyticsDimensionsPagingWrapper getAggregateDimensions(
return dimensionFilteringAndPagingService.pageAndFilter(
dimensionMapperService.toDimensionResponse(
enrollmentAnalyticsDimensionsService.getAggregateDimensionsByProgramStageId(programId),
- EnrollmentAnalyticsPrefixStrategy.INSTANCE),
+ INSTANCE),
dimensionsCriteria,
fields);
}
@@ -261,29 +252,18 @@ private EventQueryParams getEventQueryParams(
@PathVariable String program,
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
- boolean analyzeOnly,
- EndpointAction endpointAction) {
+ boolean analyzeOnly) {
criteria.definePageSize(systemSettingManager.getIntSetting(ANALYTICS_MAX_LIMIT));
- if (endpointAction == QUERY) {
- AnalyticsPeriodCriteriaUtils.defineDefaultPeriodForCriteria(
- criteria,
- periodDataProvider,
- analyticsTableSettings.getMaxPeriodYearsOffset() == null ? SYSTEM_DEFINED : DATABASE);
- } else {
- PeriodCriteriaUtils.defineDefaultPeriodForCriteria(
- criteria,
- systemSettingManager.getSystemSetting(
- ANALYSIS_RELATIVE_PERIOD, RelativePeriodEnum.class));
- }
+ defineDefaultPeriodForCriteria(
+ criteria,
+ systemSettingManager.getSystemSetting(ANALYSIS_RELATIVE_PERIOD, RelativePeriodEnum.class));
EventDataQueryRequest request =
EventDataQueryRequest.builder()
.fromCriteria(
(EnrollmentAnalyticsQueryCriteria)
- criteria
- .withEndpointAction(endpointAction)
- .withEndpointItem(RequestTypeAware.EndpointItem.ENROLLMENT))
+ criteria.withEndpointAction(AGGREGATE).withEndpointItem(ENROLLMENT))
.program(program)
.apiVersion(apiVersion)
.build();
diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentQueryAnalyticsController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentQueryAnalyticsController.java
index 4989dcc51702..c90b7ed5036c 100644
--- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentQueryAnalyticsController.java
+++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EnrollmentQueryAnalyticsController.java
@@ -30,12 +30,19 @@
import static org.hisp.dhis.common.DhisApiVersion.ALL;
import static org.hisp.dhis.common.DhisApiVersion.DEFAULT;
import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.QUERY;
+import static org.hisp.dhis.common.RequestTypeAware.EndpointItem.ENROLLMENT;
import static org.hisp.dhis.common.cache.CacheStrategy.RESPECT_SYSTEM_SETTING;
import static org.hisp.dhis.period.PeriodDataProvider.DataSource.DATABASE;
import static org.hisp.dhis.period.PeriodDataProvider.DataSource.SYSTEM_DEFINED;
import static org.hisp.dhis.security.Authorities.F_PERFORM_ANALYTICS_EXPLAIN;
-import static org.hisp.dhis.setting.SettingKey.ANALYSIS_RELATIVE_PERIOD;
import static org.hisp.dhis.setting.SettingKey.ANALYTICS_MAX_LIMIT;
+import static org.hisp.dhis.system.grid.GridUtils.toCsv;
+import static org.hisp.dhis.system.grid.GridUtils.toHtml;
+import static org.hisp.dhis.system.grid.GridUtils.toHtmlCss;
+import static org.hisp.dhis.system.grid.GridUtils.toXls;
+import static org.hisp.dhis.system.grid.GridUtils.toXlsx;
+import static org.hisp.dhis.system.grid.GridUtils.toXml;
+import static org.hisp.dhis.webapi.dimension.EnrollmentAnalyticsPrefixStrategy.INSTANCE;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_CSV;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_EXCEL;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_HTML;
@@ -52,9 +59,9 @@
import org.hisp.dhis.analytics.analyze.ExecutionPlanStore;
import org.hisp.dhis.analytics.dimensions.AnalyticsDimensionsPagingWrapper;
import org.hisp.dhis.analytics.event.EnrollmentAnalyticsDimensionsService;
-import org.hisp.dhis.analytics.event.EnrollmentAnalyticsService;
import org.hisp.dhis.analytics.event.EventDataQueryService;
import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.data.EnrollmentQueryService;
import org.hisp.dhis.analytics.table.setting.AnalyticsTableSettings;
import org.hisp.dhis.analytics.util.AnalyticsPeriodCriteriaUtils;
import org.hisp.dhis.common.DhisApiVersion;
@@ -63,18 +70,12 @@
import org.hisp.dhis.common.EventDataQueryRequest;
import org.hisp.dhis.common.Grid;
import org.hisp.dhis.common.OpenApi;
-import org.hisp.dhis.common.RequestTypeAware;
-import org.hisp.dhis.common.RequestTypeAware.EndpointAction;
import org.hisp.dhis.datavalue.DataValue;
import org.hisp.dhis.period.PeriodDataProvider;
-import org.hisp.dhis.period.RelativePeriodEnum;
import org.hisp.dhis.security.RequiresAuthority;
import org.hisp.dhis.setting.SystemSettingManager;
-import org.hisp.dhis.system.grid.GridUtils;
-import org.hisp.dhis.util.PeriodCriteriaUtils;
import org.hisp.dhis.webapi.dimension.DimensionFilteringAndPagingService;
import org.hisp.dhis.webapi.dimension.DimensionMapperService;
-import org.hisp.dhis.webapi.dimension.EnrollmentAnalyticsPrefixStrategy;
import org.hisp.dhis.webapi.mvc.annotation.ApiVersion;
import org.hisp.dhis.webapi.utils.ContextUtils;
import org.springframework.stereotype.Controller;
@@ -92,7 +93,7 @@
public class EnrollmentQueryAnalyticsController {
@Nonnull private final EventDataQueryService eventDataQueryService;
- @Nonnull private final EnrollmentAnalyticsService analyticsService;
+ @Nonnull private final EnrollmentQueryService enrollmentQueryService;
@Nonnull private final ContextUtils contextUtils;
@@ -119,9 +120,9 @@ public class EnrollmentQueryAnalyticsController {
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, true, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, true);
- Grid grid = analyticsService.getEnrollments(params);
+ Grid grid = enrollmentQueryService.getEnrollments(params);
contextUtils.configureResponse(response, CONTENT_TYPE_JSON, RESPECT_SYSTEM_SETTING);
if (params.analyzeOnly()) {
@@ -140,11 +141,11 @@ public class EnrollmentQueryAnalyticsController {
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(response, CONTENT_TYPE_JSON, RESPECT_SYSTEM_SETTING);
- return analyticsService.getEnrollments(params);
+ return enrollmentQueryService.getEnrollments(params);
}
@SneakyThrows
@@ -154,12 +155,12 @@ public void getQueryXml(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_XML, RESPECT_SYSTEM_SETTING, "enrollments.xml", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXml(grid, response.getOutputStream());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toXml(grid, response.getOutputStream());
}
@SneakyThrows
@@ -169,12 +170,12 @@ public void getQueryXls(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_EXCEL, RESPECT_SYSTEM_SETTING, "enrollments.xls", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXls(grid, response.getOutputStream());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toXls(grid, response.getOutputStream());
}
@SneakyThrows
@@ -184,12 +185,12 @@ public void getQueryXlsx(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_EXCEL, RESPECT_SYSTEM_SETTING, "enrollments.xlsx", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toXlsx(grid, response.getOutputStream());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toXlsx(grid, response.getOutputStream());
}
@SneakyThrows
@@ -199,12 +200,12 @@ public void getQueryCsv(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_CSV, RESPECT_SYSTEM_SETTING, "enrollments.csv", true);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toCsv(grid, response.getWriter());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toCsv(grid, response.getWriter());
}
@SneakyThrows
@@ -214,12 +215,12 @@ public void getQueryHtml(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_HTML, RESPECT_SYSTEM_SETTING, "enrollments.html", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toHtml(grid, response.getWriter());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toHtml(grid, response.getWriter());
}
@SneakyThrows
@@ -229,12 +230,12 @@ public void getQueryHtmlCss(
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
HttpServletResponse response) {
- EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, QUERY);
+ EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false);
contextUtils.configureResponse(
response, CONTENT_TYPE_HTML, RESPECT_SYSTEM_SETTING, "enrollments.html", false);
- Grid grid = analyticsService.getEnrollments(params);
- GridUtils.toHtmlCss(grid, response.getWriter());
+ Grid grid = enrollmentQueryService.getEnrollments(params);
+ toHtmlCss(grid, response.getWriter());
}
@ResponseBody
@@ -248,7 +249,7 @@ public AnalyticsDimensionsPagingWrapper getQueryDimensions(
return dimensionFilteringAndPagingService.pageAndFilter(
dimensionMapperService.toDimensionResponse(
enrollmentAnalyticsDimensionsService.getQueryDimensionsByProgramId(programId),
- EnrollmentAnalyticsPrefixStrategy.INSTANCE),
+ INSTANCE),
dimensionsCriteria,
fields);
}
@@ -257,29 +258,19 @@ private EventQueryParams getEventQueryParams(
@PathVariable String program,
EnrollmentAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
- boolean analyzeOnly,
- EndpointAction endpointAction) {
+ boolean analyzeOnly) {
criteria.definePageSize(systemSettingManager.getIntSetting(ANALYTICS_MAX_LIMIT));
- if (endpointAction == QUERY) {
- AnalyticsPeriodCriteriaUtils.defineDefaultPeriodForCriteria(
- criteria,
- periodDataProvider,
- analyticsTableSettings.getMaxPeriodYearsOffset() == null ? SYSTEM_DEFINED : DATABASE);
- } else {
- PeriodCriteriaUtils.defineDefaultPeriodForCriteria(
- criteria,
- systemSettingManager.getSystemSetting(
- ANALYSIS_RELATIVE_PERIOD, RelativePeriodEnum.class));
- }
+ AnalyticsPeriodCriteriaUtils.defineDefaultPeriodForCriteria(
+ criteria,
+ periodDataProvider,
+ analyticsTableSettings.getMaxPeriodYearsOffset() == null ? SYSTEM_DEFINED : DATABASE);
EventDataQueryRequest request =
EventDataQueryRequest.builder()
.fromCriteria(
(EnrollmentAnalyticsQueryCriteria)
- criteria
- .withEndpointAction(endpointAction)
- .withEndpointItem(RequestTypeAware.EndpointItem.ENROLLMENT))
+ criteria.withEndpointAction(QUERY).withEndpointItem(ENROLLMENT))
.program(program)
.apiVersion(apiVersion)
.build();
diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAggregateAnalyticsController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAggregateAnalyticsController.java
index 0eeec0f3dfa8..c651314147b0 100644
--- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAggregateAnalyticsController.java
+++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAggregateAnalyticsController.java
@@ -31,10 +31,17 @@
import static org.hisp.dhis.common.DhisApiVersion.DEFAULT;
import static org.hisp.dhis.common.DimensionalObjectUtils.getItemsFromParam;
import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.AGGREGATE;
+import static org.hisp.dhis.common.RequestTypeAware.EndpointItem.EVENT;
import static org.hisp.dhis.common.cache.CacheStrategy.RESPECT_SYSTEM_SETTING;
import static org.hisp.dhis.security.Authorities.F_PERFORM_ANALYTICS_EXPLAIN;
import static org.hisp.dhis.setting.SettingKey.ANALYSIS_RELATIVE_PERIOD;
import static org.hisp.dhis.setting.SettingKey.ANALYTICS_MAX_LIMIT;
+import static org.hisp.dhis.system.grid.GridUtils.toCsv;
+import static org.hisp.dhis.system.grid.GridUtils.toHtml;
+import static org.hisp.dhis.system.grid.GridUtils.toHtmlCss;
+import static org.hisp.dhis.system.grid.GridUtils.toXls;
+import static org.hisp.dhis.system.grid.GridUtils.toXlsx;
+import static org.hisp.dhis.system.grid.GridUtils.toXml;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_CSV;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_EXCEL;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_HTML;
@@ -50,9 +57,9 @@
import org.hisp.dhis.analytics.analyze.ExecutionPlanStore;
import org.hisp.dhis.analytics.dimensions.AnalyticsDimensionsPagingWrapper;
import org.hisp.dhis.analytics.event.EventAnalyticsDimensionsService;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
import org.hisp.dhis.analytics.event.EventDataQueryService;
import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.data.EventAggregateService;
import org.hisp.dhis.common.DhisApiVersion;
import org.hisp.dhis.common.DimensionsCriteria;
import org.hisp.dhis.common.EventDataQueryRequest;
@@ -60,13 +67,11 @@
import org.hisp.dhis.common.Grid;
import org.hisp.dhis.common.OpenApi;
import org.hisp.dhis.common.PrefixedDimension;
-import org.hisp.dhis.common.RequestTypeAware;
import org.hisp.dhis.common.RequestTypeAware.EndpointAction;
import org.hisp.dhis.datavalue.DataValue;
import org.hisp.dhis.period.RelativePeriodEnum;
import org.hisp.dhis.security.RequiresAuthority;
import org.hisp.dhis.setting.SystemSettingManager;
-import org.hisp.dhis.system.grid.GridUtils;
import org.hisp.dhis.util.PeriodCriteriaUtils;
import org.hisp.dhis.webapi.dimension.DimensionFilteringAndPagingService;
import org.hisp.dhis.webapi.dimension.DimensionMapperService;
@@ -81,9 +86,6 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
-/**
- * @author Lars Helge Overland
- */
@OpenApi.Document(domain = DataValue.class)
@Controller
@ApiVersion({DEFAULT, ALL})
@@ -93,7 +95,7 @@ public class EventAggregateAnalyticsController {
@Nonnull private final EventDataQueryService eventDataService;
- @Nonnull private final EventAnalyticsService analyticsService;
+ @Nonnull private final EventAggregateService eventAggregationService;
@Nonnull private final ContextUtils contextUtils;
@@ -115,14 +117,13 @@ public class EventAggregateAnalyticsController {
@PathVariable String program,
EventsAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
- HttpServletResponse response)
- throws Exception {
+ HttpServletResponse response) {
EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, true, AGGREGATE);
configResponseForJson(response);
Grid grid =
- analyticsService.getAggregatedEventData(
+ eventAggregationService.getAggregatedData(
params,
getItemsFromParam(criteria.getColumns()),
getItemsFromParam(criteria.getRows()));
@@ -141,13 +142,12 @@ public class EventAggregateAnalyticsController {
@PathVariable String program,
EventsAnalyticsQueryCriteria criteria,
DhisApiVersion apiVersion,
- HttpServletResponse response)
- throws Exception {
+ HttpServletResponse response) {
EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
configResponseForJson(response);
- return analyticsService.getAggregatedEventData(
+ return eventAggregationService.getAggregatedData(
params, getItemsFromParam(criteria.getColumns()), getItemsFromParam(criteria.getRows()));
}
@@ -158,7 +158,7 @@ public void getAggregateXml(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXml(
+ toXml(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_XML, "events.xml", response),
response.getOutputStream());
@@ -171,7 +171,7 @@ public void getAggregateXls(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXls(
+ toXls(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_EXCEL, "events.xls", response),
response.getOutputStream());
@@ -184,7 +184,7 @@ public void getAggregateXlsx(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXlsx(
+ toXlsx(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_EXCEL, "events.xlsx", response),
response.getOutputStream());
@@ -197,7 +197,7 @@ public void getAggregateCsv(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toCsv(
+ toCsv(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_CSV, "events.csv", response),
response.getWriter());
@@ -210,7 +210,7 @@ public void getAggregateHtml(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toHtml(
+ toHtml(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_HTML, "events.html", response),
response.getWriter());
@@ -223,7 +223,7 @@ public void getAggregateHtmlCss(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toHtmlCss(
+ toHtmlCss(
getAggregatedGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_HTML, "events.html", response),
response.getWriter());
@@ -257,13 +257,12 @@ private Grid getAggregatedGridWithAttachment(
DhisApiVersion apiVersion,
String contentType,
String file,
- HttpServletResponse response)
- throws Exception {
+ HttpServletResponse response) {
EventQueryParams params = getEventQueryParams(program, criteria, apiVersion, false, AGGREGATE);
contextUtils.configureResponse(response, contentType, RESPECT_SYSTEM_SETTING, file, false);
- return analyticsService.getAggregatedEventData(
+ return eventAggregationService.getAggregatedData(
params, getItemsFromParam(criteria.getColumns()), getItemsFromParam(criteria.getRows()));
}
@@ -283,9 +282,7 @@ private EventQueryParams getEventQueryParams(
EventDataQueryRequest.builder()
.fromCriteria(
(EventsAnalyticsQueryCriteria)
- criteria
- .withEndpointAction(endpointAction)
- .withEndpointItem(RequestTypeAware.EndpointItem.EVENT))
+ criteria.withEndpointAction(endpointAction).withEndpointItem(EVENT))
.program(program)
.apiVersion(apiVersion)
.build();
diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventQueryAnalyticsController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventQueryAnalyticsController.java
index 0fec12749a00..47296025f4ec 100644
--- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventQueryAnalyticsController.java
+++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventQueryAnalyticsController.java
@@ -27,14 +27,23 @@
*/
package org.hisp.dhis.webapi.controller;
+import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.hisp.dhis.common.DhisApiVersion.ALL;
import static org.hisp.dhis.common.DhisApiVersion.DEFAULT;
import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.OTHER;
import static org.hisp.dhis.common.RequestTypeAware.EndpointAction.QUERY;
+import static org.hisp.dhis.common.RequestTypeAware.EndpointItem.EVENT;
import static org.hisp.dhis.common.cache.CacheStrategy.RESPECT_SYSTEM_SETTING;
+import static org.hisp.dhis.feedback.ErrorCode.E7235;
import static org.hisp.dhis.security.Authorities.F_PERFORM_ANALYTICS_EXPLAIN;
import static org.hisp.dhis.setting.SettingKey.ANALYSIS_RELATIVE_PERIOD;
import static org.hisp.dhis.setting.SettingKey.ANALYTICS_MAX_LIMIT;
+import static org.hisp.dhis.system.grid.GridUtils.toCsv;
+import static org.hisp.dhis.system.grid.GridUtils.toHtml;
+import static org.hisp.dhis.system.grid.GridUtils.toHtmlCss;
+import static org.hisp.dhis.system.grid.GridUtils.toXls;
+import static org.hisp.dhis.system.grid.GridUtils.toXlsx;
+import static org.hisp.dhis.system.grid.GridUtils.toXml;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_CSV;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_EXCEL;
import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_HTML;
@@ -47,14 +56,13 @@
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
-import org.apache.commons.lang3.StringUtils;
import org.hisp.dhis.analytics.Rectangle;
import org.hisp.dhis.analytics.analyze.ExecutionPlanStore;
import org.hisp.dhis.analytics.dimensions.AnalyticsDimensionsPagingWrapper;
import org.hisp.dhis.analytics.event.EventAnalyticsDimensionsService;
-import org.hisp.dhis.analytics.event.EventAnalyticsService;
import org.hisp.dhis.analytics.event.EventDataQueryService;
import org.hisp.dhis.analytics.event.EventQueryParams;
+import org.hisp.dhis.analytics.event.data.EventQueryService;
import org.hisp.dhis.common.DhisApiVersion;
import org.hisp.dhis.common.DimensionsCriteria;
import org.hisp.dhis.common.EventDataQueryRequest;
@@ -63,15 +71,12 @@
import org.hisp.dhis.common.IllegalQueryException;
import org.hisp.dhis.common.OpenApi;
import org.hisp.dhis.common.PrefixedDimension;
-import org.hisp.dhis.common.RequestTypeAware;
import org.hisp.dhis.common.RequestTypeAware.EndpointAction;
import org.hisp.dhis.datavalue.DataValue;
-import org.hisp.dhis.feedback.ErrorCode;
import org.hisp.dhis.feedback.ErrorMessage;
import org.hisp.dhis.period.RelativePeriodEnum;
import org.hisp.dhis.security.RequiresAuthority;
import org.hisp.dhis.setting.SystemSettingManager;
-import org.hisp.dhis.system.grid.GridUtils;
import org.hisp.dhis.util.PeriodCriteriaUtils;
import org.hisp.dhis.webapi.dimension.DimensionFilteringAndPagingService;
import org.hisp.dhis.webapi.dimension.DimensionMapperService;
@@ -86,9 +91,6 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
-/**
- * @author Lars Helge Overland
- */
@OpenApi.Document(domain = DataValue.class)
@Controller
@ApiVersion({DEFAULT, ALL})
@@ -98,7 +100,7 @@ public class EventQueryAnalyticsController {
@Nonnull private final EventDataQueryService eventDataService;
- @Nonnull private final EventAnalyticsService analyticsService;
+ @Nonnull private final EventQueryService eventQueryService;
@Nonnull private final ContextUtils contextUtils;
@@ -124,7 +126,7 @@ public class EventQueryAnalyticsController {
configResponseForJson(response);
- return analyticsService.getRectangle(params);
+ return eventQueryService.getRectangle(params);
}
@GetMapping(
@@ -149,7 +151,7 @@ public class EventQueryAnalyticsController {
configResponseForJson(response);
- return analyticsService.getEventClusters(params);
+ return eventQueryService.getEventClusters(params);
}
@RequiresAuthority(anyOf = F_PERFORM_ANALYTICS_EXPLAIN)
@@ -165,7 +167,7 @@ public class EventQueryAnalyticsController {
configResponseForJson(response);
- Grid grid = analyticsService.getEvents(params);
+ Grid grid = eventQueryService.getEvents(params);
if (params.analyzeOnly()) {
grid.addPerformanceMetrics(executionPlanStore.getExecutionPlans(params.getExplainOrderId()));
@@ -186,7 +188,7 @@ public class EventQueryAnalyticsController {
configResponseForJson(response);
- return analyticsService.getEvents(params);
+ return eventQueryService.getEvents(params);
}
@GetMapping(value = "/query/{program}.xml")
@@ -196,7 +198,7 @@ public void getQueryXml(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXml(
+ toXml(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_XML, "events.xml", false, response),
response.getOutputStream());
@@ -209,7 +211,7 @@ public void getQueryXls(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXls(
+ toXls(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_EXCEL, "events.xls", true, response),
response.getOutputStream());
@@ -222,7 +224,7 @@ public void getQueryXlsx(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toXlsx(
+ toXlsx(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_EXCEL, "events.xlsx", true, response),
response.getOutputStream());
@@ -235,7 +237,7 @@ public void getQueryCsv(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toCsv(
+ toCsv(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_CSV, "events.csv", true, response),
response.getWriter());
@@ -248,7 +250,7 @@ public void getQueryHtml(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toHtml(
+ toHtml(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_HTML, "events.html", false, response),
response.getWriter());
@@ -261,7 +263,7 @@ public void getQueryHtmlCss(
DhisApiVersion apiVersion,
HttpServletResponse response)
throws Exception {
- GridUtils.toHtmlCss(
+ toHtmlCss(
getListGridWithAttachment(
criteria, program, apiVersion, CONTENT_TYPE_HTML, "events.html", false, response),
response.getWriter());
@@ -293,9 +295,10 @@ public AnalyticsDimensionsPagingWrapper getQueryDimensions(
dimResponse, dimensionsCriteria, fields);
}
- private void validateRequest(String programId, String programStageId) {
- if (StringUtils.isBlank(programId) && StringUtils.isBlank(programStageId)) {
- throw new IllegalQueryException(new ErrorMessage(ErrorCode.E7235));
+ private void validateRequest(String programId, String programStageId)
+ throws IllegalQueryException {
+ if (isBlank(programId) && isBlank(programStageId)) {
+ throw new IllegalQueryException(new ErrorMessage(E7235));
}
}
@@ -311,7 +314,7 @@ private Grid getListGridWithAttachment(
contextUtils.configureResponse(response, contentType, RESPECT_SYSTEM_SETTING, file, attachment);
- return analyticsService.getEvents(params);
+ return eventQueryService.getEvents(params);
}
private EventQueryParams getEventQueryParams(
@@ -330,9 +333,7 @@ private EventQueryParams getEventQueryParams(
EventDataQueryRequest.builder()
.fromCriteria(
(EventsAnalyticsQueryCriteria)
- criteria
- .withEndpointAction(endpointAction)
- .withEndpointItem(RequestTypeAware.EndpointItem.EVENT))
+ criteria.withEndpointAction(endpointAction).withEndpointItem(EVENT))
.program(program)
.apiVersion(apiVersion)
.build();