Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds ou to meta when DE ou [DHIS2-18884] #19764

Merged
merged 11 commits into from
Jan 27, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
package org.hisp.dhis.util;

import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT_CHILDREN;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT_GRANDCHILDREN;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -54,22 +56,22 @@ public static List<AnalyticsMetaDataKey> getAnalyticsMetaDataKeys(
String userOrganisationUnitsCriteria) {
List<AnalyticsMetaDataKey> keys = new ArrayList<>();

if (userOrganisationUnitsCriteria == null
|| !userOrganisationUnitsCriteria.contains(ORGUNIT_DIM_ID + ":")) {
return keys;
// Order matters, don't change unless you know what you're doing.
AnalyticsMetaDataKey[] analyticsMetaDataKeys = {
USER_ORGUNIT_CHILDREN, USER_ORGUNIT_GRANDCHILDREN, USER_ORGUNIT
};
for (AnalyticsMetaDataKey key : analyticsMetaDataKeys) {
if (StringUtils.trimToEmpty(userOrganisationUnitsCriteria).contains(key.getKey())) {
keys.add(key);
// We need this hack, and the analyticsMetaDataKeys order, because otherwise it would match
// USER_ORGUNIT_CHILDREN even if we only get USER_ORGUNIT, since the latter contains the
// former.
userOrganisationUnitsCriteria =
userOrganisationUnitsCriteria.replace(key.getKey(), StringUtils.EMPTY);
}
}

userOrganisationUnitsCriteria =
userOrganisationUnitsCriteria.replace(ORGUNIT_DIM_ID + ":", StringUtils.EMPTY);
List<String> criteria = Arrays.stream(userOrganisationUnitsCriteria.split(";")).toList();
return criteria.stream()
.filter(
c ->
c.equalsIgnoreCase(AnalyticsMetaDataKey.USER_ORGUNIT.getKey())
|| c.equalsIgnoreCase(AnalyticsMetaDataKey.USER_ORGUNIT_CHILDREN.getKey())
|| c.equalsIgnoreCase(AnalyticsMetaDataKey.USER_ORGUNIT_GRANDCHILDREN.getKey()))
.map(AnalyticsMetaDataKey::valueOf)
.toList();
return keys;
}

/**
Expand All @@ -82,8 +84,16 @@ public static List<AnalyticsMetaDataKey> getAnalyticsMetaDataKeys(
public static String getAnalyticsQueryCriteria(Set<String> dimensions) {
return isNotEmpty(dimensions)
? dimensions.stream()
.filter(d -> d.contains(ORGUNIT_DIM_ID))
.filter(OrganisationUnitCriteriaUtils::containsAnyUserOrgUnitKeyword)
.collect(Collectors.joining(","))
: StringUtils.EMPTY;
}

private static boolean containsAnyUserOrgUnitKeyword(String dimension) {
return Stream.of(
USER_ORGUNIT.getKey(),
AnalyticsMetaDataKey.USER_ORGUNIT_CHILDREN.getKey(),
AnalyticsMetaDataKey.USER_ORGUNIT_GRANDCHILDREN.getKey())
.anyMatch(dimension::contains);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
*/
package org.hisp.dhis.util;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT_CHILDREN;
import static org.hisp.dhis.analytics.AnalyticsMetaDataKey.USER_ORGUNIT_GRANDCHILDREN;
Expand All @@ -36,7 +38,6 @@

import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.hisp.dhis.analytics.AnalyticsMetaDataKey;
import org.hisp.dhis.common.AggregateAnalyticsQueryCriteria;
import org.hisp.dhis.common.EnrollmentAnalyticsQueryCriteria;
Expand All @@ -46,116 +47,127 @@
class OrganisationUnitCriteriaUtilsTest {
private static final String validOuDimensions =
"ou:USER_ORGUNIT;USER_ORGUNIT_CHILDREN;USER_ORGUNIT_GRANDCHILDREN";
private static final String invalidOuDimensions =
"USER_ORGUNIT;USER_ORGUNIT_CHILDREN;USER_ORGUNIT_GRANDCHILDREN";

@Test
void testGetAnalyticsMetaDataKeys_All() {
void testGetAnalyticsMetaDataKeys_Empty() {
// given
// when
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys(validOuDimensions);
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys("");
// then
assertEquals(3, keys.size());
assertEquals(USER_ORGUNIT.getKey(), keys.get(0).getKey());
assertEquals(USER_ORGUNIT_CHILDREN.getKey(), keys.get(1).getKey());
assertEquals(USER_ORGUNIT_GRANDCHILDREN.getKey(), keys.get(2).getKey());
assertEquals(0, keys.size());
}

@Test
void testGetAnalyticsMetaDataKeys_Unsupported() {
void testGetAnalyticsMetaDataKeys_Invalid() {
// given
// when
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys(invalidOuDimensions);

List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys("invalid");
// then
assertEquals(0, keys.size());
}

@Test
void testGetAnalyticsQueryCriteria_Enrollment() {
void testGetAnalyticsMetaDataKeys_USER_ORGUNIT_Only() {
// given
EnrollmentAnalyticsQueryCriteria enrollmentAnalyticsQueryCriteria =
new EnrollmentAnalyticsQueryCriteria();
enrollmentAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));

// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(enrollmentAnalyticsQueryCriteria.getDimension());

List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys("ou:USER_ORGUNIT");
// then
assertEquals(validOuDimensions, analyticsQueryCriteria);
assertEquals(1, keys.size());
assertThat(keys, hasItems(USER_ORGUNIT));
}

@Test
void testGetAnalyticsQueryCriteria_Event() {
void testGetAnalyticsMetaDataKeys_USER_ORGUNIT_CHILDREN_Only() {
// given
EventsAnalyticsQueryCriteria eventsAnalyticsQueryCriteria = new EventsAnalyticsQueryCriteria();
eventsAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));

// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(eventsAnalyticsQueryCriteria.getDimension());
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys("ou:USER_ORGUNIT_CHILDREN");
// then
assertEquals(1, keys.size());
}

@Test
void testGetAnalyticsMetaDataKeys_USER_ORGUNIT_GRANDCHILDREN_Only() {
// given
// when
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys("ou:USER_ORGUNIT_GRANDCHILDREN");
// then
assertEquals(validOuDimensions, analyticsQueryCriteria);
assertEquals(1, keys.size());
assertThat(keys, hasItems(USER_ORGUNIT_GRANDCHILDREN));
}

@Test
void testGetAnalyticsQueryCriteria_Aggregate() {
void testGetAnalyticsMetaDataKeys_USER_ORGUNIT_And_USER_ORGUNIT_CHILDREN() {
// given
AggregateAnalyticsQueryCriteria aggregateAnalyticsQueryCriteria =
new AggregateAnalyticsQueryCriteria();
aggregateAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));
// when
List<AnalyticsMetaDataKey> keys =
getAnalyticsMetaDataKeys("ou:USER_ORGUNIT;USER_ORGUNIT_CHILDREN");
// then
assertEquals(2, keys.size());
assertThat(keys, hasItems(USER_ORGUNIT, USER_ORGUNIT_CHILDREN));
}

@Test
void testGetAnalyticsMetaDataKeys_USER_ORGUNIT_And_USER_ORGUNIT_GRANDCHILDREN() {
// given
// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(aggregateAnalyticsQueryCriteria.getDimension());
List<AnalyticsMetaDataKey> keys =
getAnalyticsMetaDataKeys("ou:USER_ORGUNIT;USER_ORGUNIT_GRANDCHILDREN");
// then
assertEquals(2, keys.size());
assertThat(keys, hasItems(USER_ORGUNIT, USER_ORGUNIT_GRANDCHILDREN));
}

@Test
void testGetAnalyticsMetaDataKeys_All() {
// given
// when
List<AnalyticsMetaDataKey> keys = getAnalyticsMetaDataKeys(validOuDimensions);
// then
assertEquals(validOuDimensions, analyticsQueryCriteria);
assertEquals(3, keys.size());
assertThat(keys, hasItems(USER_ORGUNIT, USER_ORGUNIT_CHILDREN, USER_ORGUNIT_GRANDCHILDREN));
}

maikelarabori marked this conversation as resolved.
Show resolved Hide resolved
@Test
void testGetAnalyticsQueryCriteria_Enrollment_No_Dimension() {
void testGetAnalyticsQueryCriteria_Enrollment() {
// given
EnrollmentAnalyticsQueryCriteria enrollmentAnalyticsQueryCriteria =
new EnrollmentAnalyticsQueryCriteria();
enrollmentAnalyticsQueryCriteria.setDimension(Set.of(invalidOuDimensions));
enrollmentAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));

// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(enrollmentAnalyticsQueryCriteria.getDimension());

// then
assertEquals(StringUtils.EMPTY, analyticsQueryCriteria);
assertEquals(validOuDimensions, analyticsQueryCriteria);
}

@Test
void testGetAnalyticsQueryCriteria_Event_No_Dimension() {
void testGetAnalyticsQueryCriteria_Event() {
// given
EventsAnalyticsQueryCriteria eventsAnalyticsQueryCriteria = new EventsAnalyticsQueryCriteria();
eventsAnalyticsQueryCriteria.setDimension(Set.of(invalidOuDimensions));
eventsAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));

// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(eventsAnalyticsQueryCriteria.getDimension());

// then
assertEquals(StringUtils.EMPTY, analyticsQueryCriteria);
assertEquals(validOuDimensions, analyticsQueryCriteria);
}

@Test
void testGetAnalyticsQueryCriteria_Aggregate_No_Dimension() {
void testGetAnalyticsQueryCriteria_Aggregate() {
// given
AggregateAnalyticsQueryCriteria aggregateAnalyticsQueryCriteria =
new AggregateAnalyticsQueryCriteria();
aggregateAnalyticsQueryCriteria.setDimension(Set.of(invalidOuDimensions));
aggregateAnalyticsQueryCriteria.setDimension(Set.of(validOuDimensions));

// when
String analyticsQueryCriteria =
getAnalyticsQueryCriteria(aggregateAnalyticsQueryCriteria.getDimension());

// then
assertEquals(StringUtils.EMPTY, analyticsQueryCriteria);
assertEquals(validOuDimensions, analyticsQueryCriteria);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ public class EventQueryParams extends DataQueryParams {

@Getter protected boolean multipleQueries = false;

@Getter protected List<OrganisationUnit> userOrgUnits = new ArrayList<>();

// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -305,6 +307,7 @@ protected EventQueryParams instance() {
params.rowContext = this.rowContext;
params.multipleQueries = this.multipleQueries;
params.userOrganisationUnitsCriteria = this.userOrganisationUnitsCriteria;
params.userOrgUnits = this.userOrgUnits;
return params;
}

Expand Down Expand Up @@ -1360,5 +1363,10 @@ public Builder withMultipleQueries(boolean multipleQueries) {
this.params.multipleQueries = multipleQueries;
return this;
}

public Builder withUserOrgUnits(List<OrganisationUnit> userOrgUnits) {
this.params.userOrgUnits = userOrgUnits;
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ public abstract class AbstractJdbcEventAnalyticsManager {

private final DhisConfigurationProvider config;

private final OrganisationUnitResolver organisationUnitResolver;

/**
* Returns a SQL paging clause.
*
Expand Down Expand Up @@ -1277,9 +1279,14 @@ public String toSql(QueryItem item, QueryFilter filter, EventQueryParams params)
? getSelectSql(filter, item, params)
: getSelectSql(filter, item, params.getEarliestStartDate(), params.getLatestEndDate());

String filterString =
item.getValueType() == ValueType.ORGANISATION_UNIT
? organisationUnitResolver.resolveOrgUnits(filter, params.getUserOrgUnits())
: filter.getFilter();

if (IN.equals(filter.getOperator())) {
InQueryFilter inQueryFilter =
new InQueryFilter(field, sqlBuilder.escape(filter.getFilter()), !item.isNumeric());
new InQueryFilter(field, sqlBuilder.escape(filterString), !item.isNumeric());

return inQueryFilter.getSqlFilter();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,13 @@
import static org.hisp.dhis.analytics.util.AnalyticsUtils.illegalQueryExSupplier;
import static org.hisp.dhis.analytics.util.AnalyticsUtils.throwIllegalQueryEx;
import static org.hisp.dhis.common.DimensionalObject.DIMENSION_NAME_SEP;
import static org.hisp.dhis.common.DimensionalObject.OPTION_SEP;
import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID;
import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionFromParam;
import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionItemsFromParam;
import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionalItemIds;
import static org.hisp.dhis.common.ValueType.ORGANISATION_UNIT;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
Expand All @@ -57,7 +54,6 @@
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.hisp.dhis.analytics.AnalyticsAggregationType;
import org.hisp.dhis.analytics.DataQueryParams;
Expand Down Expand Up @@ -206,7 +202,8 @@ public EventQueryParams getFromRequest(EventDataQueryRequest request, boolean an
.withEndpointItem(request.getEndpointItem())
.withEndpointAction(request.getEndpointAction())
.withUserOrganisationUnitsCriteria(request.getUserOrganisationUnitCriteria())
.withRowContext(request.isRowContext());
.withRowContext(request.isRowContext())
.withUserOrgUnits(userOrgUnits);

if (analyzeOnly) {
builder = builder.withSkipData(true).withAnalyzeOrderId();
Expand Down Expand Up @@ -322,7 +319,7 @@ private void addDimensionsToParams(
if (groupableItem != null) {
params.addDimension((DimensionalObject) groupableItem);
} else {
groupableItem = getQueryItem(dim, pr, request.getOutputType(), userOrgUnits);
groupableItem = getQueryItem(dim, pr, request.getOutputType());
params.addItem((QueryItem) groupableItem);
}

Expand Down Expand Up @@ -515,14 +512,6 @@ private QueryItem getQueryItem(

@Override
public QueryItem getQueryItem(String dimensionString, Program program, EventOutputType type) {
return getQueryItem(dimensionString, program, type, Collections.emptyList());
}

private QueryItem getQueryItem(
String dimensionString,
Program program,
EventOutputType type,
List<OrganisationUnit> userOrgUnits) {
String[] split = dimensionString.split(DIMENSION_NAME_SEP);

if (split.length % 2 != 1) {
Expand All @@ -548,25 +537,13 @@ private QueryItem getQueryItem(
// FE uses HH.MM time format instead of HH:MM. This is not
// compatible with db table/cell values
modifyFilterWhenTimeQueryItem(queryItem, filter);
resolveOrgUnitDimensionIfNecessary(queryItem, filter, userOrgUnits);
queryItem.addFilter(filter);
}
}

return queryItem;
}

@SneakyThrows
private void resolveOrgUnitDimensionIfNecessary(
QueryItem queryItem, QueryFilter queryFilter, List<OrganisationUnit> userOrgUnits) {
if (queryItem.getValueType().equals(ORGANISATION_UNIT)) {
List<String> filterItem = QueryFilter.getFilterItems(queryFilter.getFilter());
List<String> orgUnitDimensionUid =
dataQueryService.getOrgUnitDimensionUid(filterItem, userOrgUnits);
queryFilter.setFilter(String.join(OPTION_SEP, orgUnitDimensionUid));
}
}

private static void modifyFilterWhenTimeQueryItem(QueryItem queryItem, QueryFilter filter) {
if (queryItem.getItem() instanceof DataElement
&& ((DataElement) queryItem.getItem()).getValueType() == ValueType.TIME) {
Expand Down
Loading
Loading