diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/analytics/Aggregation.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/analytics/Aggregation.java new file mode 100644 index 000000000000..6a17f7a9554c --- /dev/null +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/analytics/Aggregation.java @@ -0,0 +1,33 @@ +/* + * 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; + +public enum Aggregation { + AGGREGATED, + DISAGGREGATED +} diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseDimensionalItemObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseDimensionalItemObject.java index 494ec44d4d22..aefcea136b2a 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseDimensionalItemObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseDimensionalItemObject.java @@ -51,6 +51,9 @@ public class BaseDimensionalItemObject extends BaseNameableObject implements Dim /** The aggregation type for this dimension. */ protected AggregationType aggregationType; + /** The client's OptionSet for this dimension item. */ + protected OptionSetItem optionSetItem; + /** Query modifiers for this object. */ protected transient QueryModifiers queryMods; @@ -92,6 +95,17 @@ public AggregationType getAggregationType() { : aggregationType; } + @Override + @JsonProperty + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) + public OptionSetItem getOptionSetItem() { + return optionSetItem; + } + + public void setOptionSetItem(OptionSetItem optionSetItem) { + this.optionSetItem = optionSetItem; + } + // ------------------------------------------------------------------------- // DimensionalItemObject // ------------------------------------------------------------------------- diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DataDimensionItem.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DataDimensionItem.java index 623259605851..87a1317a19fd 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DataDimensionItem.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DataDimensionItem.java @@ -33,10 +33,13 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import com.google.common.collect.Lists; +import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataelement.DataElementOperand; import org.hisp.dhis.expressiondimensionitem.ExpressionDimensionItem; @@ -104,6 +107,25 @@ public class DataDimensionItem { private SubexpressionDimensionItem subexpressionDimensionItem; + private Attributes attributes; + + @NoArgsConstructor + @AllArgsConstructor + public static class Attributes implements Serializable { + /** The option item for this dimension item. * */ + private OptionSetItem optionItem; + + @JsonProperty + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) + public OptionSetItem getOptionSetItem() { + return optionItem; + } + + public void setOptionSetItem(OptionSetItem optionItem) { + this.optionItem = optionItem; + } + } + // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- @@ -112,7 +134,6 @@ public DataDimensionItem() {} public static List createWithDependencies( DimensionalItemObject object, List items) { - if (DataElement.class.isAssignableFrom(object.getClass())) { DataDimensionItem dimension = new DataDimensionItem(); DataElement dataElement = (DataElement) object; @@ -187,6 +208,7 @@ public DimensionalItemObject getDimensionalItemObject() { if (indicator != null) { return indicator; } else if (dataElement != null) { + loadAttributes(dataElement); return dataElement; } else if (dataElementOperand != null) { return dataElementOperand; @@ -195,18 +217,31 @@ public DimensionalItemObject getDimensionalItemObject() { } else if (programIndicator != null) { return programIndicator; } else if (programDataElement != null) { + loadAttributes(programDataElement); return programDataElement; } else if (programAttribute != null) { + loadAttributes(programAttribute); return programAttribute; } else if (expressionDimensionItem != null) { return expressionDimensionItem; } else if (subexpressionDimensionItem != null) { - return expressionDimensionItem; + return subexpressionDimensionItem; } return null; } + /** + * Simply loads the internal attributes into the given item object. + * + * @param itemObject the {@link BaseDimensionalItemObject}. + */ + private void loadAttributes(BaseDimensionalItemObject itemObject) { + if (attributes != null) { + itemObject.setOptionSetItem(attributes.getOptionSetItem()); + } + } + @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public DataDimensionItemType getDataDimensionItemType() { @@ -287,6 +322,14 @@ public void setId(int id) { this.id = id; } + public Attributes getAttributes() { + return attributes; + } + + public void setAttributes(Attributes attributes) { + this.attributes = attributes; + } + @JsonProperty @JsonSerialize(as = BaseNameableObject.class) @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @@ -298,9 +341,6 @@ public void setIndicator(Indicator indicator) { this.indicator = indicator; } - @JsonProperty - @JsonSerialize(as = BaseNameableObject.class) - @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public DataElement getDataElement() { return dataElement; } diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionType.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionType.java index d286175a1571..a98438b87b68 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionType.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionType.java @@ -46,6 +46,7 @@ public enum DimensionType { ORGANISATION_UNIT_GROUP, CATEGORY, OPTION_GROUP_SET, + OPTION_SET, VALIDATION_RULE, STATIC, ORGANISATION_UNIT_LEVEL; diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalItemObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalItemObject.java index c12c4e954df7..ed5448291384 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalItemObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalItemObject.java @@ -54,6 +54,9 @@ public interface DimensionalItemObject extends NameableObject { /** Gets the legend sets. */ List getLegendSets(); + /** Option set saved for client usage. */ + OptionSetItem getOptionSetItem(); + /** * Gets the first legend set in the legend set list. This field is derived from {@link * DimensionalObject#getLegendSet()} and is not persisted. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/OptionSetItem.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/OptionSetItem.java new file mode 100644 index 000000000000..2a15915de4c1 --- /dev/null +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/OptionSetItem.java @@ -0,0 +1,74 @@ +/* + * 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.common; + +import static org.hisp.dhis.common.DxfNamespaces.DXF_2_0; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.io.Serializable; +import java.util.LinkedHashSet; +import java.util.Set; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.hisp.dhis.analytics.Aggregation; + +/** Encapsulates {@link org.hisp.dhis.option.Option}s uids and the {@link Aggregation} type. */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@JacksonXmlRootElement(localName = "optionSetItem", namespace = DXF_2_0) +public class OptionSetItem implements Serializable { + /** The uids of the options. */ + private Set options = new LinkedHashSet<>(); + + /** The aggregation for this option item. */ + private Aggregation aggregation; + + @JsonProperty + @JacksonXmlProperty(namespace = DXF_2_0) + public Set getOptions() { + return options; + } + + public void setOptions(Set options) { + this.options = options; + } + + @JsonProperty + @JacksonXmlProperty(namespace = DXF_2_0) + public Aggregation getAggregation() { + return aggregation; + } + + public void setAggregation(Aggregation aggregation) { + this.aggregation = aggregation; + } +} diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dimension/DefaultDimensionService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dimension/DefaultDimensionService.java index b7f120d82a13..8d37336eda60 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dimension/DefaultDimensionService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dimension/DefaultDimensionService.java @@ -41,6 +41,7 @@ import static org.hisp.dhis.common.DimensionType.PROGRAM_DATA_ELEMENT; import static org.hisp.dhis.common.DimensionType.PROGRAM_INDICATOR; import static org.hisp.dhis.common.DimensionalObjectUtils.COMPOSITE_DIM_OBJECT_ESCAPED_SEP; +import static org.hisp.dhis.common.IdScheme.UID; import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids; import static org.hisp.dhis.commons.util.TextUtils.splitSafe; import static org.hisp.dhis.eventvisualization.Attribute.COLUMN; @@ -74,6 +75,7 @@ import org.hisp.dhis.common.BaseDimensionalObject; import org.hisp.dhis.common.CodeGenerator; import org.hisp.dhis.common.DataDimensionItem; +import org.hisp.dhis.common.DataDimensionItem.Attributes; import org.hisp.dhis.common.DimensionService; import org.hisp.dhis.common.DimensionType; import org.hisp.dhis.common.DimensionalItemId; @@ -338,7 +340,7 @@ public DimensionalObject getDimensionalObjectCopy(String uid, boolean filterCanR @Override @Transactional(readOnly = true) public DimensionalItemObject getDataDimensionalItemObject(String dimensionItem) { - return getDataDimensionalItemObject(IdScheme.UID, dimensionItem); + return getDataDimensionalItemObject(UID, dimensionItem); } @Override @@ -532,13 +534,16 @@ private void mergeDimensionalObjects( List uids = getUids(items); if (DATA_X.equals(type)) { - for (String uid : uids) { - DimensionalItemObject dimItemObject = getDataDimensionalItemObject(IdScheme.UID, uid); + for (DimensionalItemObject item : items) { + DimensionalItemObject dimItemObject = getDataDimensionalItemObject(UID, item.getUid()); if (dimItemObject != null) { - DataDimensionItem item = DataDimensionItem.create(dimItemObject); + DataDimensionItem dataItem = DataDimensionItem.create(dimItemObject); - object.getDataDimensionItems().add(item); + // Adds attributes to the current data item object. + dataItem.setAttributes(new Attributes(item.getOptionSetItem())); + + object.getDataDimensionItems().add(dataItem); } } } else if (PERIOD.equals(type)) { @@ -560,7 +565,6 @@ private void mergeDimensionalObjects( } object.setRawRelativePeriods(new ArrayList<>(relativePeriods)); - // object.setRelatives(new RelativePeriods().setRelativePeriodsFromEnums(enums)); object.setPeriods(periodService.reloadPeriods(new ArrayList<>(periods))); } else if (ORGANISATION_UNIT.equals(type)) { for (String ou : uids) { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/common.hibernate/DataDimensionItem.hbm.xml b/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/common.hibernate/DataDimensionItem.hbm.xml index 8a0f55132cfd..b138afe6a9e5 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/common.hibernate/DataDimensionItem.hbm.xml +++ b/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/common.hibernate/DataDimensionItem.hbm.xml @@ -21,7 +21,7 @@ - + @@ -43,7 +43,7 @@ column="programindicatorid" foreign-key="fk_datadimensionitem_programindicatorid" /> - - + column="expressiondimensionitemid" foreign-key="fk_datadimensionitem_expressiondimensionitemid" /> + + + diff --git a/dhis-2/dhis-support/dhis-support-db-migration/src/main/resources/org/hisp/dhis/db/migration/2.42/V2_42_27__Add_optionsets_column_to_datadimensionitem.sql b/dhis-2/dhis-support/dhis-support-db-migration/src/main/resources/org/hisp/dhis/db/migration/2.42/V2_42_27__Add_optionsets_column_to_datadimensionitem.sql new file mode 100644 index 000000000000..8b7db765fb80 --- /dev/null +++ b/dhis-2/dhis-support/dhis-support-db-migration/src/main/resources/org/hisp/dhis/db/migration/2.42/V2_42_27__Add_optionsets_column_to_datadimensionitem.sql @@ -0,0 +1,5 @@ + +-- DHIS2-18370 - Visualization API: Support saving and loading "optionSet" in "items" + +-- Add new json column for array of option sets. +alter table datadimensionitem add column if not exists optionsetitem jsonb; diff --git a/dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/org/hisp/dhis/usertype/UserTypes.hbm.xml b/dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/org/hisp/dhis/usertype/UserTypes.hbm.xml index 5ffc6ca8c9fb..641cdd8628b1 100644 --- a/dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/org/hisp/dhis/usertype/UserTypes.hbm.xml +++ b/dhis-2/dhis-support/dhis-support-hibernate/src/main/resources/org/hisp/dhis/usertype/UserTypes.hbm.xml @@ -33,6 +33,10 @@ org.hisp.dhis.visualization.VisualizationFontStyle + + org.hisp.dhis.common.OptionSetItem + + org.hisp.dhis.visualization.AxisV2 diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/VisualizationControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/VisualizationControllerTest.java index b6d1c41a690b..0c17eeb5c6f7 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/VisualizationControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/VisualizationControllerTest.java @@ -30,6 +30,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; +import static org.hisp.dhis.analytics.AggregationType.SUM; +import static org.hisp.dhis.common.ValueType.TEXT; import static org.hisp.dhis.http.HttpAssertions.assertStatus; import static org.hisp.dhis.http.HttpStatus.CONFLICT; import static org.hisp.dhis.http.HttpStatus.CREATED; @@ -39,6 +41,7 @@ import java.nio.file.Path; import org.hisp.dhis.common.IdentifiableObjectManager; +import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.http.HttpStatus; import org.hisp.dhis.indicator.Indicator; import org.hisp.dhis.indicator.IndicatorType; @@ -47,8 +50,10 @@ import org.hisp.dhis.jsontree.JsonNode; import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramTrackedEntityAttribute; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; import org.hisp.dhis.test.webapi.json.domain.JsonImportSummary; +import org.hisp.dhis.trackedentity.TrackedEntityAttribute; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -313,4 +318,122 @@ void testRelativePeriods() { assertTrue( visualization.getObject("relativePeriods").getBoolean("last12Months").booleanValue()); } + + @Test + void testPostOptionSetItemInProgramAttribute() { + // Given + TrackedEntityAttribute trackedEntityAttribute = + new TrackedEntityAttribute("tea", "tea-desc", TEXT, false, false); + trackedEntityAttribute.setShortName("tea-shortName"); + trackedEntityAttribute.setAggregationType(SUM); + manager.save(trackedEntityAttribute); + + ProgramTrackedEntityAttribute programTrackedEntityAttribute = + new ProgramTrackedEntityAttribute(mockProgram, trackedEntityAttribute); + manager.save(programTrackedEntityAttribute); + + String programUid = programTrackedEntityAttribute.getProgram().getUid(); + String attributeUid = programTrackedEntityAttribute.getAttribute().getUid(); + String jsonBody = + """ +{ + "type": "PIVOT_TABLE", + "columns": [ + { + "dimension": "dx", + "items": [ + { + "id": "${program}.${attribute}", + "name": "Program Attribute - OptionSet", + "dimensionItemType": "PROGRAM_ATTRIBUTE", + "optionSetItem": { + "aggregation": "DISAGGREGATED", + "options": [ + "BFhv3jQZ8Cw" + ] + } + } + ] + } + ], + "name": "OptionSetItem - Test" +} +""" + .replace("${program}", programUid) + .replace("${attribute}", attributeUid); + + // When + String uid = assertStatus(CREATED, POST("/visualizations/", jsonBody)); + + // Then + String getParams = + "?fields=dataDimensionItems[programAttribute[attribute[optionSet[options[:all]]]]],attributeValues[:all,attribute[id,name,displayName]],columns[:all,items[:all,optionSetItem[options,aggregation]]"; + JsonObject response = GET("/visualizations/" + uid + getParams).content(); + + JsonNode columnNode = response.get("columns").node().element(0); + JsonNode itemsNode = columnNode.get("items").elementOrNull(0); + + assertEquals("DATA_X", columnNode.get("dimensionType").value()); + assertTrue((boolean) columnNode.get("dataDimension").value()); + assertEquals("PROGRAM_ATTRIBUTE", itemsNode.get("dimensionItemType").value()); + assertEquals("SUM", itemsNode.get("aggregationType").value()); + assertEquals(programUid + "." + attributeUid, itemsNode.get("dimensionItem").value()); + assertEquals("DISAGGREGATED", itemsNode.get("optionSetItem").get("aggregation").value()); + assertEquals( + "[\"BFhv3jQZ8Cw\"]", itemsNode.get("optionSetItem").get("options").value().toString()); + } + + @Test + void testPostOptionSetItemInDataElement() { + // Given + DataElement dataElement = createDataElement('A'); + manager.save(dataElement); + + String dataElementUid = dataElement.getUid(); + String jsonBody = + """ +{ + "type": "PIE", + "columns": [ + { + "dimension": "dx", + "items": [ + { + "id": "${dataElement}", + "name": "Data Element - OptionSet", + "dimensionItemType": "DATA_ELEMENT", + "optionSetItem": { + "aggregation": "AGGREGATED", + "options": [ + "BFhv3jQZ8Cw" + ] + } + } + ] + } + ], + "name": "OptionSetItem - Test" +} +""" + .replace("${dataElement}", dataElementUid); + + // When + String uid = assertStatus(CREATED, POST("/visualizations/", jsonBody)); + + // Then + String getParams = "?fields=columns[:all,items[:all,optionSetItem[options,aggregation]]"; + JsonObject response = GET("/visualizations/" + uid + getParams).content(); + + JsonNode columnNode = response.get("columns").node().element(0); + JsonNode itemsNode = columnNode.get("items").elementOrNull(0); + + assertEquals("DATA_X", columnNode.get("dimensionType").value()); + assertTrue((boolean) columnNode.get("dataDimension").value()); + assertEquals("DATA_ELEMENT", itemsNode.get("dimensionItemType").value()); + assertEquals("SUM", itemsNode.get("aggregationType").value()); + assertEquals(dataElementUid, itemsNode.get("dimensionItem").value()); + assertEquals("AGGREGATED", itemsNode.get("optionSetItem").get("aggregation").value()); + assertEquals( + "[\"BFhv3jQZ8Cw\"]", itemsNode.get("optionSetItem").get("options").value().toString()); + } }