Skip to content

Commit

Permalink
Analytics API: Add support for Option in /analytics [DHIS2-18368] (#1…
Browse files Browse the repository at this point in the history
…9558)

* cherrypicking, resolve conflicts, part1

* cherrypicking, resolve conflicts, part2

* cherrypicking, resolve conflicts, part3

* cherrypicking, resolve conflicts, part3.1

* Revert "cherrypicking, resolve conflicts, part3.1"

This reverts commit 123bc05.

* cherrypicking, resolve conflicts, part3.2

* cherrypicking, resolve conflicts, part3.2

* cherrypicking, resolve conflicts, part3.2

* code cleaning

* code cleaning

* QA issues

* QA issues

* QA issues

* bugfix unit test

* bugfix unit test

* bugfix unit test

* code cleaning

* request caching

* fix: Small bugs and clean-up [DHIS2-18368]

* fix: prevent NPE [DHIS2-18368]

* fix: Group by issue [DHIS2-18368]

* fix: Regex/separator for options [DHIS2-18368]

* refactor: Extract common code [DHIS2-18368]

* chore: Replace dot by constat [DHIS2-18368]

* chore: Comment typo [DHIS2-18368]

* chore: Comment typo [DHIS2-18368]

* chore: Replace dot by constat [DHIS2-18368]

* chore: Code clean-up [DHIS2-18368]

* fix: Merge issue [DHIS2-18368]

* fix: Sonar issue [DHIS2-18368]

* fix: Bugs and missing features [DHIS2-18368]

* chore: Test regex

* fix: Logic for dx Option and clean-up [DHIS2-18368]

* chore: Remove unnecessary code [DHIS2-18368]

* fix: Missing program in filter [DHIS2-18368]

* chore: Remove test code [DHIS2-18368]

* chore:Code clean-up [DHIS2-18368]

* fix: Metada + clean-up [DHIS2-18368]

* fix: Sonar issue [DHIS2-18368]

* fix: Failing test [DHIS2-18368]

* chore: Remove unnecessary code [DHIS2-18368]

* test: add e2e tests [DHIS2-18368]

* chore: Missing annotation in constructor [DHIS2-18956]

---------

Co-authored-by: Maikel Arabori <[email protected]>
Co-authored-by: Maikel Arabori <[email protected]>
  • Loading branch information
3 people authored Feb 12, 2025
1 parent 0629c05 commit 1fc9f97
Show file tree
Hide file tree
Showing 23 changed files with 828 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,9 @@ public static List<String> getDimensionItemsFromParam(String param) {
}

if (param.split(DIMENSION_NAME_SEP).length > 1) {
// Extracts dimension items by removing dimension name and separator
// Extracts dimension items by removing dimension name and separator.
String dimensionItems = param.substring(param.indexOf(DIMENSION_NAME_SEP) + 1);

// Returns them as List<String>
return Arrays.asList(dimensionItems.split(OPTION_SEP));
}

Expand Down Expand Up @@ -522,20 +521,45 @@ public static boolean isCompositeDimensionalObject(String expression) {
* @param compositeItem the composite dimension object identifier.
* @return the first identifier, or null if not a valid composite identifier or no match.
*/
public static String getFirstIdentifer(String compositeItem) {
public static String getFirstIdentifier(String compositeItem) {
if (compositeItem == null) {
return null;
}

Matcher matcher = COMPOSITE_DIM_OBJECT_PATTERN.matcher(compositeItem);
return matcher.matches() ? matcher.group(1) : null;
return matcher.matches() ? matcher.group("id1") : null;
}

/**
* Returns the second identifier in a composite dimension object identifier.
*
* @param compositeItem the composite dimension object identifier.
* @return the second identifier, or null if not a valid composite identifier or no match.
* @return the second identifier, or null if thr composite identifier is not valid or do not
* match.
*/
public static String getSecondIdentifer(String compositeItem) {
public static String getSecondIdentifier(String compositeItem) {
if (compositeItem == null) {
return null;
}

Matcher matcher = COMPOSITE_DIM_OBJECT_PATTERN.matcher(compositeItem);
return matcher.matches() ? matcher.group(2) : null;
return matcher.matches() ? matcher.group("id2") : null;
}

/**
* Returns the third identifier in a composite dimension object identifier.
*
* @param compositeItem the composite dimension object identifier.
* @return the third identifier, or null if thr composite identifier is not valid or do not match.
*/
public static String getThirdIdentifier(String compositeItem) {
if (compositeItem == null) {
return null;
}

Matcher matcher = COMPOSITE_DIM_OBJECT_PATTERN.matcher(compositeItem);

return matcher.matches() ? matcher.group("id3") : null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.hisp.dhis.analytics.QueryKey;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.legend.LegendSet;
import org.hisp.dhis.option.Option;
import org.hisp.dhis.option.OptionSet;
import org.hisp.dhis.program.Program;
import org.hisp.dhis.program.ProgramStage;
Expand Down Expand Up @@ -71,6 +72,8 @@ public class QueryItem implements GroupableItem {

private OptionSet optionSet;

private Option option;

private Program program;

private ProgramStage programStage;
Expand Down Expand Up @@ -429,6 +432,7 @@ public boolean equals(Object object) {
final QueryItem other = (QueryItem) object;

return Objects.equals(item, other.getItem())
&& Objects.equals(option, other.getOption())
&& Objects.equals(program, other.getProgram())
&& Objects.equals(programStage, other.getProgramStage())
&& Objects.equals(repeatableStageParams, other.getRepeatableStageParams());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,6 @@ public boolean hasAllOptions(Collection<String> optionCodes) {
return true;
}

public List<String> getOptionValues() {
return options.stream()
.filter(Objects::nonNull)
.map(Option::getName)
.collect(Collectors.toList());
}

public List<String> getOptionCodes() {
return options.stream()
.filter(Objects::nonNull)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
package org.hisp.dhis.program;

import static com.google.common.base.MoreObjects.toStringHelper;
import static org.apache.commons.lang3.StringUtils.SPACE;
import static java.lang.String.format;
import static org.apache.commons.lang3.StringUtils.joinWith;
import static org.hisp.dhis.common.DimensionItemType.PROGRAM_DATA_ELEMENT_OPTION;
import static org.hisp.dhis.common.DimensionalObjectUtils.COMPOSITE_DIM_OBJECT_PLAIN_SEP;
Expand All @@ -43,6 +43,7 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.google.common.base.Objects;
import java.util.List;
import javax.annotation.Nonnull;
import lombok.NoArgsConstructor;
import org.hisp.dhis.analytics.AggregationType;
import org.hisp.dhis.common.BaseDimensionalItemObject;
Expand Down Expand Up @@ -73,25 +74,26 @@ public class ProgramDataElementOptionDimensionItem extends BaseDimensionalItemOb
private Option option;

public ProgramDataElementOptionDimensionItem(
Program program, DataElement dataElement, Option option) {
@Nonnull Program program, @Nonnull DataElement dataElement, @Nonnull Option option) {
this.program = program;
this.dataElement = dataElement;
this.option = option;
}

@Override
public String getName() {
return joinWith(
SPACE, program.getDisplayName(), dataElement.getDisplayName(), option.getDisplayName());
return format(
"%s (%s, %s)",
option.getDisplayName(), dataElement.getDisplayName(), program.getDisplayName());
}

@Override
public String getShortName() {
return joinWith(
SPACE,
program.getDisplayShortName(),
return format(
"%s (%s, %s)",
option.getDisplayShortName(),
dataElement.getDisplayShortName(),
option.getDisplayShortName());
program.getDisplayShortName());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
package org.hisp.dhis.program;

import static com.google.common.base.MoreObjects.toStringHelper;
import static org.apache.commons.lang3.StringUtils.SPACE;
import static java.lang.String.format;
import static org.apache.commons.lang3.StringUtils.joinWith;
import static org.hisp.dhis.common.DimensionItemType.PROGRAM_ATTRIBUTE_OPTION;
import static org.hisp.dhis.common.DimensionalObjectUtils.COMPOSITE_DIM_OBJECT_PLAIN_SEP;
Expand All @@ -43,6 +43,7 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.google.common.base.Objects;
import java.util.List;
import javax.annotation.Nonnull;
import lombok.NoArgsConstructor;
import org.hisp.dhis.analytics.AggregationType;
import org.hisp.dhis.common.BaseDimensionalItemObject;
Expand Down Expand Up @@ -70,25 +71,26 @@ public class ProgramTrackedEntityAttributeOptionDimensionItem extends BaseDimens
private Option option;

public ProgramTrackedEntityAttributeOptionDimensionItem(
Program program, TrackedEntityAttribute attribute, Option option) {
@Nonnull Program program, @Nonnull TrackedEntityAttribute attribute, @Nonnull Option option) {
this.program = program;
this.attribute = attribute;
this.option = option;
}

@Override
public String getName() {
return joinWith(
SPACE, program.getDisplayName(), attribute.getDisplayName(), option.getDisplayName());
return format(
"%s (%s, %s)",
option.getDisplayName(), attribute.getDisplayName(), program.getDisplayName());
}

@Override
public String getShortName() {
return joinWith(
SPACE,
program.getDisplayShortName(),
return format(
"%s (%s, %s)",
option.getDisplayShortName(),
attribute.getDisplayShortName(),
option.getDisplayShortName());
program.getDisplayShortName());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,15 @@ void testGetDataElementOperandIdSchemeCodeMap() {
@Test
void testGetFirstSecondIdentifier() {
assertEquals(
"A123456789A", DimensionalObjectUtils.getFirstIdentifer("A123456789A.P123456789A"));
assertNull(DimensionalObjectUtils.getFirstIdentifer("A123456789A"));
"A123456789A", DimensionalObjectUtils.getFirstIdentifier("A123456789A.P123456789A"));
assertNull(DimensionalObjectUtils.getFirstIdentifier("A123456789A"));
}

@Test
void testGetSecondIdentifier() {
assertEquals(
"P123456789A", DimensionalObjectUtils.getSecondIdentifer("A123456789A.P123456789A"));
assertNull(DimensionalObjectUtils.getSecondIdentifer("A123456789A"));
"P123456789A", DimensionalObjectUtils.getSecondIdentifier("A123456789A.P123456789A"));
assertNull(DimensionalObjectUtils.getSecondIdentifier("A123456789A"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,6 @@ public <T extends DataQueryParams> T copyTo(T params) {
params.orgUnitField = this.orgUnitField;
params.apiVersion = this.apiVersion;
params.locale = this.locale;

params.currentUser = this.currentUser;
params.partitions = new Partitions(this.partitions);
params.tableName = this.tableName;
Expand Down Expand Up @@ -2221,17 +2220,37 @@ public List<DimensionalItemObject> getAllProgramAttributes() {
ListUtils.union(getProgramAttributes(), getFilterProgramAttributes()));
}

/** Returns all program attribute options part of a dimension or filter. */
public List<DimensionalItemObject> getAllProgramAttributeOptions() {
return ImmutableList.copyOf(
ListUtils.union(getProgramAttributeOptions(), getFilterProgramAttributeOptions()));
}

/** Returns all program data elements part of a dimension or filter. */
public List<DimensionalItemObject> getAllProgramDataElements() {
return ImmutableList.copyOf(
ListUtils.union(getProgramDataElements(), getFilterProgramDataElements()));
}

/** Returns all program attributes part of a dimension or filter. */
/** Returns all program data element options part of a dimension or filter. */
public List<DimensionalItemObject> getAllProgramDataElementOptions() {
return ImmutableList.copyOf(
ListUtils.union(getProgramDataElementOptions(), getFilterProgramDataElementOptions()));
}

/** Returns all data element attributes part of a dimension or filter. */
public List<DimensionalItemObject> getAllProgramDataElementsAndAttributes() {
return ListUtils.union(getAllProgramAttributes(), getAllProgramDataElements());
}

/**
* Returns all options from program attributes and program data elements part of a dimension or
* filter.
*/
public List<DimensionalItemObject> getAllProgramDataElementsAndAttributesOptions() {
return ListUtils.union(getAllProgramAttributeOptions(), getAllProgramDataElementOptions());
}

/** Returns all validation results part of a dimension or filter. */
public List<DimensionalItemObject> getAllValidationResults() {
return ImmutableList.copyOf(
Expand Down Expand Up @@ -2348,6 +2367,13 @@ public List<DimensionalItemObject> getProgramDataElements() {
DataDimensionItemType.PROGRAM_DATA_ELEMENT, getDimensionOptions(DATA_X_DIM_ID)));
}

/** Returns all program data element options part of the data dimension. */
public List<DimensionalItemObject> getProgramDataElementOptions() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_DATA_ELEMENT_OPTION, getDimensionOptions(DATA_X_DIM_ID)));
}

/**
* Returns all data elements, data elements of of data element operands and data elements of
* program data elements part of the data dimension.
Expand All @@ -2370,13 +2396,20 @@ public List<DimensionalItemObject> getDataElementsOperandsProgramDataElements()
return ImmutableList.copyOf(dataElements);
}

/** Returns all indicators part of the data dimension. */
/** Returns all program attributes part of the data dimension. */
public List<DimensionalItemObject> getProgramAttributes() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_ATTRIBUTE, getDimensionOptions(DATA_X_DIM_ID)));
}

/** Returns all program attribute option part of the data dimension. */
public List<DimensionalItemObject> getProgramAttributeOptions() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_ATTRIBUTE_OPTION, getDimensionOptions(DATA_X_DIM_ID)));
}

/** Returns all expression dimension items part of the data dimension. */
public List<DimensionalItemObject> getExpressionDimensionItems() {
return ImmutableList.copyOf(
Expand Down Expand Up @@ -2496,13 +2529,27 @@ public List<DimensionalItemObject> getFilterProgramDataElements() {
DataDimensionItemType.PROGRAM_DATA_ELEMENT, getFilterOptions(DATA_X_DIM_ID)));
}

/** Returns all program data element options part of the data filter. */
public List<DimensionalItemObject> getFilterProgramDataElementOptions() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_DATA_ELEMENT_OPTION, getFilterOptions(DATA_X_DIM_ID)));
}

/** Returns all program attributes part of the data filter. */
public List<DimensionalItemObject> getFilterProgramAttributes() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_ATTRIBUTE, getFilterOptions(DATA_X_DIM_ID)));
}

/** Returns all program attribute options part of the data filter. */
public List<DimensionalItemObject> getFilterProgramAttributeOptions() {
return ImmutableList.copyOf(
AnalyticsUtils.getByDataDimensionItemType(
DataDimensionItemType.PROGRAM_ATTRIBUTE_OPTION, getFilterOptions(DATA_X_DIM_ID)));
}

/** Returns all expression dimension items part of the data filter. */
public List<DimensionalItemObject> getFilterExpressionDimensionItems() {
return ImmutableList.copyOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*/
package org.hisp.dhis.analytics.data;

import static java.util.Objects.requireNonNull;
import static org.apache.commons.collections4.CollectionUtils.addIgnoreNull;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
Expand Down Expand Up @@ -174,7 +175,7 @@ public DataQueryParams getFromRequest(DataQueryRequest request) {
@Override
@Transactional(readOnly = true)
public DataQueryParams getFromAnalyticalObject(AnalyticalObject object) {
Objects.requireNonNull(object);
requireNonNull(object);

DataQueryParams.Builder params = DataQueryParams.newBuilder();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP;
import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids;
import static org.hisp.dhis.common.collection.CollectionUtils.concat;
import static org.hisp.dhis.system.util.SqlUtils.quote;
import static org.hisp.dhis.util.DateUtils.toMediumDate;
import static org.hisp.dhis.util.SqlExceptionUtils.ERR_MSG_SILENT_FALLBACK;
import static org.hisp.dhis.util.SqlExceptionUtils.relationDoesNotExist;
Expand Down Expand Up @@ -371,10 +372,8 @@ protected String getValueClause(DataQueryParams params) {
* @return a SQL numeric value column.
*/
protected String getAggregateValueColumn(DataQueryParams params) {
String sql = null;

String sql;
AnalyticsAggregationType aggType = params.getAggregationType();

String valueColumn = params.getValueColumn();

if (aggType.isAggregationType(SUM)
Expand Down
Loading

0 comments on commit 1fc9f97

Please sign in to comment.