Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 72de4f8

Browse files
author
Stefan Kock
committed
SORMAS-Foundation#3612: Count eventSummaries instead of eventCount subquery per contact
1 parent e37463f commit 72de4f8

5 files changed

Lines changed: 96 additions & 40 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactIndexDetailedDto.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import de.symeda.sormas.api.Disease;
66
import de.symeda.sormas.api.caze.CaseClassification;
7-
import de.symeda.sormas.api.location.LocationDto;
87
import de.symeda.sormas.api.person.ApproximateAgeType;
98
import de.symeda.sormas.api.person.Sex;
109
import de.symeda.sormas.api.person.SymptomJournalStatus;
@@ -67,7 +66,7 @@ public ContactIndexDetailedDto(String uuid, String personFirstName, String perso
6766
String caseHealthFacilityUuid, String casePointOfEntryUuid, Date changeDate, String externalID,
6867
Sex sex, Integer approximateAge, ApproximateAgeType approximateAgeType,
6968
String city, String street, String houseNumber, String additionalInformation, String postalCode, String phone,
70-
String reportingUserFirstName, String reportingUserLastName, int visitCount, long eventCount
69+
String reportingUserFirstName, String reportingUserLastName, int visitCount
7170
) {
7271
//@formatter:on
7372

@@ -87,7 +86,6 @@ public ContactIndexDetailedDto(String uuid, String personFirstName, String perso
8786
this.postalCode = postalCode;
8887
this.phone = phone;
8988
this.reportingUser = new UserReferenceDto(reportingUserUuid, reportingUserFirstName, reportingUserLastName, null);
90-
this.eventCount = eventCount;
9189
}
9290

9391
public Sex getSex() {
@@ -134,6 +132,10 @@ public Long getEventCount() {
134132
return eventCount;
135133
}
136134

135+
public void setEventCount(Long eventCount) {
136+
this.eventCount = eventCount;
137+
}
138+
137139
public String getLatestEventId() {
138140
return latestEventId;
139141
}

sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
*******************************************************************************/
1818
package de.symeda.sormas.backend.contact;
1919

20-
import static de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal;
2120
import static de.symeda.sormas.backend.visit.VisitLogic.getVisitResult;
2221
import static java.time.temporal.ChronoUnit.DAYS;
2322

@@ -133,6 +132,7 @@
133132
import de.symeda.sormas.backend.exposure.Exposure;
134133
import de.symeda.sormas.backend.externaljournal.ExternalJournalService;
135134
import de.symeda.sormas.backend.facility.Facility;
135+
import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal;
136136
import de.symeda.sormas.backend.location.Location;
137137
import de.symeda.sormas.backend.person.Person;
138138
import de.symeda.sormas.backend.person.PersonFacadeEjb;
@@ -911,15 +911,14 @@ public List<ContactIndexDetailedDto> getIndexDetailedList(
911911
dtos = em.createQuery(query).getResultList();
912912
}
913913

914-
// Load latest events info
915-
// Adding a second query here is not perfect, but selecting the last event with a criteria query
916-
// doesn't seem to be possible and using a native query is not an option because of user filters
914+
// Load event count and latest events info per contact
917915
List<ContactEventSummaryDetails> eventSummaries =
918916
eventService.getEventSummaryDetailsByContacts(dtos.stream().map(ContactIndexDetailedDto::getUuid).collect(Collectors.toList()));
917+
Map<String, Long> eventCounts =
918+
eventSummaries.stream().collect(Collectors.groupingBy(ContactEventSummaryDetails::getContactUuid, Collectors.counting()));
919919
for (ContactIndexDetailedDto contact : dtos) {
920-
if (contact.getEventCount() == 0) {
921-
continue;
922-
}
920+
921+
contact.setEventCount(eventCounts.getOrDefault(contact.getUuid(), 0L));
923922

924923
eventSummaries.stream()
925924
.filter(v -> v.getContactUuid().equals(contact.getUuid()))

sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactListCriteriaBuilder.java

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
import javax.persistence.criteria.CriteriaBuilder;
1717
import javax.persistence.criteria.CriteriaQuery;
1818
import javax.persistence.criteria.Expression;
19-
import javax.persistence.criteria.Join;
20-
import javax.persistence.criteria.JoinType;
2119
import javax.persistence.criteria.Order;
2220
import javax.persistence.criteria.Predicate;
2321
import javax.persistence.criteria.Root;
@@ -32,8 +30,6 @@
3230
import de.symeda.sormas.backend.caze.Case;
3331
import de.symeda.sormas.backend.common.AbstractAdoService;
3432
import de.symeda.sormas.backend.common.AbstractDomainObject;
35-
import de.symeda.sormas.backend.event.Event;
36-
import de.symeda.sormas.backend.event.EventParticipant;
3733
import de.symeda.sormas.backend.facility.Facility;
3834
import de.symeda.sormas.backend.infrastructure.PointOfEntry;
3935
import de.symeda.sormas.backend.location.Location;
@@ -60,8 +56,7 @@ public CriteriaQuery<ContactIndexDto> buildIndexCriteria(ContactCriteria contact
6056
this::getContactIndexSelections,
6157
contactCriteria,
6258
this::getIndexOrders,
63-
sortProperties,
64-
false);
59+
sortProperties);
6560
}
6661

6762
public CriteriaQuery<ContactIndexDetailedDto> buildIndexDetailedCriteria(ContactCriteria contactCriteria, List<SortProperty> sortProperties) {
@@ -71,8 +66,7 @@ public CriteriaQuery<ContactIndexDetailedDto> buildIndexDetailedCriteria(Contact
7166
this::getContactIndexDetailedSelections,
7267
contactCriteria,
7368
this::getIndexDetailOrders,
74-
sortProperties,
75-
true);
69+
sortProperties);
7670
}
7771

7872
public Stream<Selection<?>> getJurisdictionSelections(ContactJoins joins) {
@@ -217,8 +211,7 @@ private <T> CriteriaQuery<T> buildIndexCriteria(
217211
BiFunction<Root<Contact>, ContactJoins, List<Selection<?>>> selectionProvider,
218212
ContactCriteria contactCriteria,
219213
OrderExpressionProvider orderExpressionProvider,
220-
List<SortProperty> sortProperties,
221-
boolean withEventInfo) {
214+
List<SortProperty> sortProperties) {
222215

223216
CriteriaBuilder cb = em.getCriteriaBuilder();
224217
CriteriaQuery<T> cq = cb.createQuery(type);
@@ -240,23 +233,6 @@ private <T> CriteriaQuery<T> buildIndexCriteria(
240233
cq.where(filter);
241234
}
242235

243-
if (withEventInfo) {
244-
// Events count subquery
245-
Subquery<Long> eventCountSq = cq.subquery(Long.class);
246-
Root<EventParticipant> eventCountRoot = eventCountSq.from(EventParticipant.class);
247-
Join<EventParticipant, Event> eventJoin = eventCountRoot.join(EventParticipant.EVENT, JoinType.INNER);
248-
Join<Person, Contact> contactJoin = eventCountRoot.join(EventParticipant.PERSON, JoinType.INNER).join(Person.CONTACTS, JoinType.INNER);
249-
250-
eventCountSq.where(
251-
cb.and(
252-
cb.equal(contactJoin.get(Contact.UUID), contact.get(Contact.UUID)),
253-
cb.isFalse(eventJoin.get(Event.DELETED)),
254-
cb.isFalse(eventJoin.get(Event.ARCHIVED)),
255-
cb.isFalse(eventCountRoot.get(EventParticipant.DELETED))));
256-
eventCountSq.select(cb.countDistinct(eventJoin.get(Event.ID)));
257-
selections.add(eventCountSq);
258-
}
259-
260236
cq.multiselect(selections);
261237
cq.distinct(true);
262238

sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,11 @@ public VisitDto createVisit(
562562

563563
public EventDto createEvent(UserReferenceDto reportingUser) {
564564

565+
return createEvent(reportingUser, new Date());
566+
}
567+
568+
public EventDto createEvent(UserReferenceDto reportingUser, Date eventDate) {
569+
565570
return createEvent(
566571
EventStatus.SIGNAL,
567572
EventInvestigationStatus.PENDING,
@@ -571,7 +576,7 @@ public EventDto createEvent(UserReferenceDto reportingUser) {
571576
"LastName",
572577
null,
573578
null,
574-
new Date(),
579+
eventDate,
575580
new Date(),
576581
reportingUser,
577582
null,

sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,21 @@
5656
import de.symeda.sormas.api.contact.ContactDto;
5757
import de.symeda.sormas.api.contact.ContactExportDto;
5858
import de.symeda.sormas.api.contact.ContactFacade;
59+
import de.symeda.sormas.api.contact.ContactIndexDetailedDto;
5960
import de.symeda.sormas.api.contact.ContactIndexDto;
6061
import de.symeda.sormas.api.contact.ContactSimilarityCriteria;
6162
import de.symeda.sormas.api.contact.ContactStatus;
6263
import de.symeda.sormas.api.contact.MapContactDto;
6364
import de.symeda.sormas.api.contact.SimilarContactDto;
6465
import de.symeda.sormas.api.epidata.EpiDataDto;
6566
import de.symeda.sormas.api.epidata.EpiDataHelper;
66-
import de.symeda.sormas.api.exposure.ExposureDto;
67-
import de.symeda.sormas.api.exposure.ExposureType;
6867
import de.symeda.sormas.api.event.EventDto;
6968
import de.symeda.sormas.api.event.EventInvestigationStatus;
7069
import de.symeda.sormas.api.event.EventParticipantDto;
70+
import de.symeda.sormas.api.event.EventReferenceDto;
7171
import de.symeda.sormas.api.event.EventStatus;
72+
import de.symeda.sormas.api.exposure.ExposureDto;
73+
import de.symeda.sormas.api.exposure.ExposureType;
7274
import de.symeda.sormas.api.followup.FollowUpLogic;
7375
import de.symeda.sormas.api.i18n.I18nProperties;
7476
import de.symeda.sormas.api.person.PersonDto;
@@ -84,9 +86,11 @@
8486
import de.symeda.sormas.api.task.TaskStatus;
8587
import de.symeda.sormas.api.task.TaskType;
8688
import de.symeda.sormas.api.user.UserDto;
89+
import de.symeda.sormas.api.user.UserReferenceDto;
8790
import de.symeda.sormas.api.user.UserRole;
8891
import de.symeda.sormas.api.utils.DataHelper;
8992
import de.symeda.sormas.api.utils.DateHelper;
93+
import de.symeda.sormas.api.utils.SortProperty;
9094
import de.symeda.sormas.api.utils.YesNoUnknown;
9195
import de.symeda.sormas.api.visit.VisitDto;
9296
import de.symeda.sormas.api.visit.VisitStatus;
@@ -434,6 +438,76 @@ public void testGetIndexListByEventFreeText() {
434438
.size());
435439
}
436440

441+
@Test
442+
public void testGetIndexDetailedList() {
443+
444+
ContactCriteria contactCriteria = new ContactCriteria();
445+
contactCriteria.setIncludeContactsFromOtherJurisdictions(true);
446+
List<SortProperty> sortProperties = Collections.emptyList();
447+
List<ContactIndexDetailedDto> result;
448+
449+
// 0. No data: empty list
450+
result = getContactFacade().getIndexDetailedList(contactCriteria, null, null, sortProperties);
451+
assertThat(result, is(empty()));
452+
453+
// Create needed structural data
454+
RDCFEntities rdcf = creator.createRDCFEntities("Region", "District", "Community", "Facility");
455+
UserDto user = creator
456+
.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR);
457+
PersonDto cazePerson = creator.createPerson("Case", "Person");
458+
CaseDataDto caze = creator.createCase(
459+
user.toReference(),
460+
cazePerson.toReference(),
461+
Disease.EVD,
462+
CaseClassification.PROBABLE,
463+
InvestigationStatus.PENDING,
464+
new Date(),
465+
rdcf);
466+
467+
UserReferenceDto reportingUser = new UserReferenceDto(user.getUuid());
468+
EventDto event1 = creator.createEvent(reportingUser, DateHelper.subtractDays(new Date(), 1));
469+
EventDto event2 = creator.createEvent(reportingUser, new Date());
470+
471+
PersonDto contactPerson = creator.createPerson("Contact", "Person");
472+
ContactDto contact1 =
473+
creator.createContact(user.toReference(), user.toReference(), contactPerson.toReference(), caze, new Date(), new Date(), null);
474+
475+
// 1a. one Contact without Event
476+
result = getContactFacade().getIndexDetailedList(contactCriteria, null, null, sortProperties);
477+
assertThat(result, hasSize(1));
478+
{
479+
ContactIndexDetailedDto dto = result.get(0);
480+
assertThat(dto.getUuid(), equalTo(contact1.getUuid()));
481+
assertThat(dto.getEventCount(), equalTo(0L));
482+
assertNull(dto.getLatestEventId());
483+
assertNull(dto.getLatestEventTitle());
484+
}
485+
486+
// 1b. one Contact with one Event
487+
creator.createEventParticipant(new EventReferenceDto(event1.getUuid()), contactPerson, reportingUser);
488+
result = getContactFacade().getIndexDetailedList(contactCriteria, null, null, sortProperties);
489+
assertThat(result, hasSize(1));
490+
{
491+
ContactIndexDetailedDto dto = result.get(0);
492+
assertThat(dto.getUuid(), equalTo(contact1.getUuid()));
493+
assertThat(dto.getEventCount(), equalTo(1L));
494+
assertThat(dto.getLatestEventId(), equalTo(event1.getUuid()));
495+
assertThat(dto.getLatestEventTitle(), equalTo(event1.getEventTitle()));
496+
}
497+
498+
// 1c. one Contact with two Events, second is leading
499+
creator.createEventParticipant(new EventReferenceDto(event2.getUuid()), contactPerson, reportingUser);
500+
result = getContactFacade().getIndexDetailedList(contactCriteria, null, null, sortProperties);
501+
assertThat(result, hasSize(1));
502+
{
503+
ContactIndexDetailedDto dto = result.get(0);
504+
assertThat(dto.getUuid(), equalTo(contact1.getUuid()));
505+
assertThat(dto.getEventCount(), equalTo(2L));
506+
assertThat(dto.getLatestEventId(), equalTo(event2.getUuid()));
507+
assertThat(dto.getLatestEventTitle(), equalTo(event2.getEventTitle()));
508+
}
509+
}
510+
437511
@Test
438512
public void testGetContactCountsByCasesForDashboard() {
439513

0 commit comments

Comments
 (0)