Skip to content

Commit

Permalink
feat: Support option set in DV object [DHIS2-18370] (#19492)
Browse files Browse the repository at this point in the history
* feat: Support option set in DV object [DHIS2-18370]

* feat: DRAFT commit for option set in DV [DHIS2-18370]

* fix: Logic, clean-up + tests [DHIS2-18370]

* chore: Clean-up [DHIS2-18370]

* chore: Clean-up [DHIS2-18370]

* fix: Failing unit test [DHIS2-18370]

* fix: Sonar issues [DHIS2-18370]
  • Loading branch information
maikelarabori authored Dec 17, 2024
1 parent 059689a commit 94998b5
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
// -------------------------------------------------------------------------
Expand All @@ -112,7 +134,6 @@ public DataDimensionItem() {}

public static List<DataDimensionItem> createWithDependencies(
DimensionalItemObject object, List<DataDimensionItem> items) {

if (DataElement.class.isAssignableFrom(object.getClass())) {
DataDimensionItem dimension = new DataDimensionItem();
DataElement dataElement = (DataElement) object;
Expand Down Expand Up @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public enum DimensionType {
ORGANISATION_UNIT_GROUP,
CATEGORY,
OPTION_GROUP_SET,
OPTION_SET,
VALIDATION_RULE,
STATIC,
ORGANISATION_UNIT_LEVEL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public interface DimensionalItemObject extends NameableObject {
/** Gets the legend sets. */
List<LegendSet> 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> options = new LinkedHashSet<>();

/** The aggregation for this option item. */
private Aggregation aggregation;

@JsonProperty
@JacksonXmlProperty(namespace = DXF_2_0)
public Set<String> getOptions() {
return options;
}

public void setOptions(Set<String> options) {
this.options = options;
}

@JsonProperty
@JacksonXmlProperty(namespace = DXF_2_0)
public Aggregation getAggregation() {
return aggregation;
}

public void setAggregation(Aggregation aggregation) {
this.aggregation = aggregation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -532,13 +534,16 @@ private void mergeDimensionalObjects(
List<String> 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)) {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<component name="dataElementOperand" class="org.hisp.dhis.dataelement.DataElementOperand">
<many-to-one name="dataElement" class="org.hisp.dhis.dataelement.DataElement"
column="dataelementoperand_dataelementid" foreign-key="fk_datadimensionitem_dataelementoperand_dataelementid" />

<many-to-one name="categoryOptionCombo" class="org.hisp.dhis.category.CategoryOptionCombo"
column="dataelementoperand_categoryoptioncomboid" foreign-key="fk_datadimensionitem_dataelementoperand_categoryoptioncomboid" />
</component>
Expand All @@ -43,7 +43,7 @@
column="programindicatorid" foreign-key="fk_datadimensionitem_programindicatorid" />

<component name="programDataElement" class="org.hisp.dhis.program.ProgramDataElementDimensionItem">
<many-to-one name="program" class="org.hisp.dhis.program.Program"
<many-to-one name="program" class="org.hisp.dhis.program.Program"
column="programdataelement_programid" foreign-key="fk_datadimensionitem_programdataelement_programid" />

<many-to-one name="dataElement" class="org.hisp.dhis.dataelement.DataElement"
Expand All @@ -56,11 +56,13 @@

<many-to-one name="attribute" class="org.hisp.dhis.trackedentity.TrackedEntityAttribute"
column="programattribute_attributeid" foreign-key="fk_datadimensionitem_programattribute_attributeid" />

</component>

<many-to-one name="expressionDimensionItem" class="org.hisp.dhis.expressiondimensionitem.ExpressionDimensionItem"
column="expressiondimensionitemid" foreign-key="fk_datadimensionitem_expressiondimensionitemid" />
column="expressiondimensionitemid" foreign-key="fk_datadimensionitem_expressiondimensionitemid" />

<component name="attributes">
<property name="optionSetItem" type="jbOptionSetItem"/>
</component>
</class>
</hibernate-mapping>
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<param name="clazz">org.hisp.dhis.visualization.VisualizationFontStyle</param>
</typedef>

<typedef class="org.hisp.dhis.hibernate.jsonb.type.JsonBinaryType" name="jbOptionSetItem">
<param name="clazz">org.hisp.dhis.common.OptionSetItem</param>
</typedef>

<typedef class="org.hisp.dhis.hibernate.jsonb.type.JsonListBinaryType" name="jbAxes">
<param name="clazz">org.hisp.dhis.visualization.AxisV2</param>
</typedef>
Expand Down
Loading

0 comments on commit 94998b5

Please sign in to comment.