Skip to content

Commit

Permalink
fix: /events?dataElementIdScheme!=UID for shared data elements DHIS2-…
Browse files Browse the repository at this point in the history
…14968 (#19291)

* debug

* fix: /events?dataElementIdScheme!=UID for shared data elements
  • Loading branch information
teleivo authored Nov 26, 2024
1 parent 56a870d commit 7306b5b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ private List<Event> fetchEvents(EventQueryParams queryParams, PageParams pagePar
mapSqlParameterSource,
resultSet -> {
Set<String> notes = new HashSet<>();
Set<String> dataElementUids = new HashSet<>();
// data elements per event
Map<String, Set<String>> dataElementUids = new HashMap<>();

while (resultSet.next()) {
if (resultSet.getString(COLUMN_EVENT_UID) == null) {
Expand All @@ -305,6 +306,7 @@ private List<Event> fetchEvents(EventQueryParams queryParams, PageParams pagePar
event.setId(resultSet.getLong(COLUMN_EVENT_ID));
event.setUid(eventUid);
eventsByUid.put(eventUid, event);
dataElementUids.put(eventUid, new HashSet<>());

TrackedEntity te = new TrackedEntity();
te.setUid(resultSet.getString(COLUMN_TRACKEDENTITY_UID));
Expand Down Expand Up @@ -437,11 +439,11 @@ private List<Event> fetchEvents(EventQueryParams queryParams, PageParams pagePar
// data value per data element. The same data element can be in the result set
// multiple times if the event also has notes.
String dataElementUid = resultSet.getString("de_uid");
if (!dataElementUids.contains(dataElementUid)) {
if (!dataElementUids.get(eventUid).contains(dataElementUid)) {
EventDataValue eventDataValue = parseEventDataValue(dataElementIdScheme, resultSet);
if (eventDataValue != null) {
event.getEventDataValues().add(eventDataValue);
dataElementUids.add(dataElementUid);
dataElementUids.get(eventUid).add(dataElementUid);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,27 @@ private Assertions() {
* @param actual the actual collection.
*/
public static <E> void assertContainsOnly(Collection<E> expected, Collection<E> actual) {
assertContainsOnly(expected, actual, "assertContainsOnly found mismatch");
}

/**
* Asserts that the given collection contains exactly the given items in any order.
*
* @param <E> the type.
* @param expected the expected items.
* @param actual the actual collection.
* @param heading the assertAll heading
*/
public static <E> void assertContainsOnly(
Collection<E> expected, Collection<E> actual, String heading) {
assertNotNull(
actual,
() -> String.format("Expected collection to contain %s, got null instead", expected));

List<E> missing = CollectionUtils.difference(expected, actual);
List<E> extra = CollectionUtils.difference(actual, expected);
assertAll(
"assertContainsOnly found mismatch",
heading,
() ->
assertTrue(
missing.isEmpty(), () -> String.format("Expected %s to be in %s", missing, actual)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,18 @@
import org.hisp.dhis.attribute.Attribute;
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.common.IdentifiableObjectManager;
import org.hisp.dhis.common.collection.CollectionUtils;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleMode;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleParams;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleService;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleValidationService;
import org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleValidationReport;
import org.hisp.dhis.eventdatavalue.EventDataValue;
import org.hisp.dhis.http.HttpStatus;
import org.hisp.dhis.importexport.ImportStrategy;
import org.hisp.dhis.jsontree.JsonList;
import org.hisp.dhis.jsontree.JsonObject;
import org.hisp.dhis.program.Event;
import org.hisp.dhis.render.RenderFormat;
Expand Down Expand Up @@ -282,6 +285,35 @@ void shouldExportEventUsingNonUIDDataElementIdSchemeEvenIfItHasNoDataValues() {
assertEquals("jxgFyJEMUPf", actual.getEvent());
}

@Test
void shouldExportEventsUsingNonUIDDataElementIdScheme() {
Event event1 = get(Event.class, "QRYjLTiJTrA");
Event event2 = get(Event.class, "kWjSezkXHVp");
assertNotEmpty(
CollectionUtils.intersection(
event1.getEventDataValues().stream()
.map(EventDataValue::getDataElement)
.collect(Collectors.toSet()),
event2.getEventDataValues().stream()
.map(EventDataValue::getDataElement)
.collect(Collectors.toSet())),
"test expects both events to have at least one data value for the same data element");

JsonList<JsonEvent> jsonEvents =
GET("/tracker/events?events=QRYjLTiJTrA,kWjSezkXHVp&fields=event,dataValues&dataElementIdScheme=NAME")
.content(HttpStatus.OK)
.getList("events", JsonEvent.class);

Map<String, JsonEvent> events =
jsonEvents.stream().collect(Collectors.toMap(JsonEvent::getEvent, Function.identity()));
assertContainsOnly(List.of(event1.getUid(), event2.getUid()), events.keySet());

TrackerIdSchemeParam idSchemeParam = TrackerIdSchemeParam.NAME;
assertAll(
() -> assertDataValues(events.get("QRYjLTiJTrA"), event1, idSchemeParam),
() -> assertDataValues(events.get("kWjSezkXHVp"), event2, idSchemeParam));
}

@ParameterizedTest
@ValueSource(strings = {"/{id}?", "?events={id}&paging=true&", "?events={id}&paging=false&"})
void shouldReportMetadataWhichDoesNotHaveAnIdentifierForGivenIdScheme(String urlPortion) {
Expand Down Expand Up @@ -350,6 +382,35 @@ private static void assertIdScheme(
field, idSchemeParam));
}

private void assertDataValues(
JsonEvent actual, Event expected, TrackerIdSchemeParam idSchemeParam) {
String field = "dataValues";
List<String> expectedDataElement =
expected.getEventDataValues().stream()
.map(dv -> idSchemeParam.getIdentifier(get(DataElement.class, dv.getDataElement())))
.toList();
assertNotEmpty(
expectedDataElement,
String.format(
"metadata corresponding to field \"%s\" has no value in test data for"
+ " idScheme '%s'",
field, idSchemeParam));
assertTrue(
actual.has(field),
() ->
String.format(
"field \"%s\" is not in response %s for idScheme '%s'",
field, actual, idSchemeParam));
List<String> actualDataElement =
actual
.getList(field, JsonObject.class)
.toList(el -> el.getString("dataElement").string(""));
assertContainsOnly(
expectedDataElement,
actualDataElement,
"mismatch in data elements of event " + expected.getUid());
}

private <T extends IdentifiableObject> T get(Class<T> type, String uid) {
T t = manager.get(type, uid);
assertNotNull(
Expand Down

0 comments on commit 7306b5b

Please sign in to comment.