Skip to content

Commit 798320c

Browse files
pwargulakibacher
authored andcommitted
O3-4544: Improve FHIR Location endpoint performance openmrs#559
1 parent 3432289 commit 798320c

29 files changed

+390
-114
lines changed

api-2.6/src/test/java/org/openmrs/module/fhir2/api/impl/FhirMedicationDispenseServiceImpl_2_6Test.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.hamcrest.Matchers.not;
1919
import static org.junit.jupiter.api.Assertions.assertThrows;
2020
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.ArgumentMatchers.anyCollection;
2122
import static org.mockito.Mockito.when;
2223

2324
import java.util.Collections;
@@ -238,6 +239,7 @@ public void searchMedicationDispenses_shouldGetSearchResults() {
238239
new SearchQueryBundleProvider<>(theParams, dao, translator, globalPropertyService, searchQueryInclude));
239240
when(searchQueryInclude.getIncludedResources(any(), any())).thenReturn(Collections.emptySet());
240241
when(translator.toFhirResource(openmrsDispense)).thenReturn(fhirDispense);
242+
when(translator.toFhirResources(anyCollection())).thenCallRealMethod();
241243

242244
MedicationDispenseSearchParams params = new MedicationDispenseSearchParams();
243245
params.setId(idParam);

api/src/main/java/org/openmrs/module/fhir2/api/dao/FhirLocationDao.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
import javax.annotation.Nonnull;
1313

14+
import java.util.Collection;
1415
import java.util.List;
16+
import java.util.Map;
1517

1618
import org.openmrs.Location;
1719
import org.openmrs.LocationAttribute;
@@ -31,6 +33,9 @@ public interface FhirLocationDao extends FhirDao<Location> {
3133
List<LocationAttribute> getActiveAttributesByLocationAndAttributeTypeUuid(@Nonnull Location location,
3234
@Nonnull String locationAttributeTypeUuid);
3335

36+
Map<Location, List<LocationAttribute>> getActiveAttributesByLocationsAndAttributeTypeUuid(
37+
@Nonnull Collection<Location> location, @Nonnull String locationAttributeTypeUuid);
38+
3439
@Override
3540
@Authorized(PrivilegeConstants.MANAGE_LOCATIONS)
3641
Location createOrUpdate(@Nonnull Location newEntry);

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/BaseFhirDao.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import lombok.AccessLevel;
3434
import lombok.Getter;
3535
import lombok.Setter;
36+
import lombok.extern.slf4j.Slf4j;
3637
import org.hibernate.CacheMode;
3738
import org.hibernate.Criteria;
3839
import org.hibernate.Hibernate;
@@ -68,6 +69,7 @@
6869
* @param <T> the {@link OpenmrsObject} managed by this Dao
6970
*/
7071
@Transactional
72+
@Slf4j
7173
public abstract class BaseFhirDao<T extends OpenmrsObject & Auditable> extends BaseDao implements FhirDao<T> {
7274

7375
@SuppressWarnings("UnstableApiUsage")
@@ -249,6 +251,7 @@ public List<T> getSearchResults(@Nonnull SearchParameterMap theParams) {
249251

250252
results = idsCriteria.list();
251253
}
254+
252255
return results.stream().map(this::deproxyResult).collect(Collectors.toList());
253256
}
254257

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirLocationDaoImpl.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,21 @@
99
*/
1010
package org.openmrs.module.fhir2.api.dao.impl;
1111

12+
import static java.util.stream.Collectors.groupingBy;
13+
import static java.util.stream.Collectors.toList;
1214
import static org.hibernate.criterion.Restrictions.eq;
1315
import static org.hibernate.criterion.Restrictions.or;
1416

1517
import javax.annotation.Nonnull;
18+
import javax.persistence.criteria.CriteriaBuilder;
19+
import javax.persistence.criteria.CriteriaQuery;
20+
import javax.persistence.criteria.Predicate;
21+
import javax.persistence.criteria.Root;
1622

1723
import java.util.ArrayList;
24+
import java.util.Collection;
1825
import java.util.List;
26+
import java.util.Map;
1927
import java.util.Optional;
2028

2129
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
@@ -93,6 +101,25 @@ public List<LocationAttribute> getActiveAttributesByLocationAndAttributeTypeUuid
93101
.list();
94102
}
95103

104+
@Override
105+
public Map<Location, List<LocationAttribute>> getActiveAttributesByLocationsAndAttributeTypeUuid(
106+
@Nonnull Collection<Location> location, @Nonnull String locationAttributeTypeUuid) {
107+
final CriteriaBuilder criteriaBuilder = getSessionFactory().getCurrentSession().getCriteriaBuilder();
108+
final CriteriaQuery<LocationAttribute> criteria = criteriaBuilder.createQuery(LocationAttribute.class);
109+
final Root<LocationAttribute> locationAttributeRoot = criteria.from(LocationAttribute.class);
110+
111+
final Predicate byId = locationAttributeRoot.get("location").get("locationId")
112+
.in(location.stream().map(Location::getLocationId).collect(toList()));
113+
final Predicate byAttributeType = criteriaBuilder.equal(locationAttributeRoot.get("attributeType").get("uuid"),
114+
locationAttributeTypeUuid);
115+
final Predicate byVoided = criteriaBuilder.equal(locationAttributeRoot.get("voided"), false);
116+
117+
criteria.where(byId, byAttributeType, byVoided);
118+
119+
return getSessionFactory().getCurrentSession().createQuery(criteria).getResultList().stream()
120+
.collect(groupingBy(LocationAttribute::getLocation));
121+
}
122+
96123
private void handleName(Criteria criteria, StringAndListParam namePattern) {
97124
handleAndListParam(namePattern, (name) -> propertyLike("name", name)).ifPresent(criteria::add);
98125
}

api/src/main/java/org/openmrs/module/fhir2/api/search/SearchQuery.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import org.openmrs.module.fhir2.api.FhirGlobalPropertyService;
1919
import org.openmrs.module.fhir2.api.dao.FhirDao;
2020
import org.openmrs.module.fhir2.api.search.param.SearchParameterMap;
21-
import org.openmrs.module.fhir2.api.translators.ToFhirTranslator;
21+
import org.openmrs.module.fhir2.api.translators.OpenmrsFhirTranslator;
2222
import org.springframework.beans.factory.annotation.Autowired;
2323
import org.springframework.stereotype.Component;
2424

@@ -29,7 +29,7 @@
2929
* @param <T> FHIR generic translator Class
3030
*/
3131
@Component
32-
public class SearchQuery<T extends OpenmrsObject & Auditable, U extends IBaseResource, O extends FhirDao<T>, V extends ToFhirTranslator<T, U>, W extends SearchQueryInclude<U>> {
32+
public class SearchQuery<T extends OpenmrsObject & Auditable, U extends IBaseResource, O extends FhirDao<T>, V extends OpenmrsFhirTranslator<T, U>, W extends SearchQueryInclude<U>> {
3333

3434
@Autowired
3535
private FhirGlobalPropertyService globalPropertyService;

api/src/main/java/org/openmrs/module/fhir2/api/search/SearchQueryBundleProvider.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@
1616
import java.util.ArrayList;
1717
import java.util.Date;
1818
import java.util.List;
19-
import java.util.Objects;
2019
import java.util.Set;
21-
import java.util.stream.Collectors;
2220

2321
import ca.uhn.fhir.model.primitive.InstantDt;
2422
import ca.uhn.fhir.rest.api.server.IBundleProvider;
2523
import lombok.Getter;
24+
import lombok.extern.slf4j.Slf4j;
2625
import org.hl7.fhir.instance.model.api.IBaseResource;
2726
import org.hl7.fhir.instance.model.api.IPrimitiveType;
2827
import org.openmrs.Auditable;
@@ -31,10 +30,11 @@
3130
import org.openmrs.module.fhir2.api.FhirGlobalPropertyService;
3231
import org.openmrs.module.fhir2.api.dao.FhirDao;
3332
import org.openmrs.module.fhir2.api.search.param.SearchParameterMap;
34-
import org.openmrs.module.fhir2.api.translators.ToFhirTranslator;
33+
import org.openmrs.module.fhir2.api.translators.OpenmrsFhirTranslator;
3534
import org.openmrs.module.fhir2.api.util.FhirUtils;
3635
import org.springframework.transaction.annotation.Transactional;
3736

37+
@Slf4j
3838
public class SearchQueryBundleProvider<T extends OpenmrsObject & Auditable, U extends IBaseResource> implements IBundleProvider, Serializable {
3939

4040
private static final long serialVersionUID = 4L;
@@ -46,7 +46,7 @@ public class SearchQueryBundleProvider<T extends OpenmrsObject & Auditable, U ex
4646

4747
private final SearchParameterMap searchParameterMap;
4848

49-
private final ToFhirTranslator<T, U> translator;
49+
private final OpenmrsFhirTranslator<T, U> translator;
5050

5151
@Getter
5252
private final String uuid;
@@ -60,7 +60,7 @@ public class SearchQueryBundleProvider<T extends OpenmrsObject & Auditable, U ex
6060
private final SearchQueryInclude<U> searchQueryInclude;
6161

6262
public SearchQueryBundleProvider(SearchParameterMap searchParameterMap, FhirDao<T> dao,
63-
ToFhirTranslator<T, U> translator, FhirGlobalPropertyService globalPropertyService,
63+
OpenmrsFhirTranslator<T, U> translator, FhirGlobalPropertyService globalPropertyService,
6464
SearchQueryInclude<U> searchQueryInclude) {
6565
this.dao = dao;
6666
this.published = InstantDt.withCurrentTime();
@@ -78,13 +78,12 @@ public List<IBaseResource> getResources(int fromIndex, int toIndex) {
7878
searchParameterMap.setFromIndex(fromIndex);
7979
searchParameterMap.setToIndex(toIndex);
8080

81-
List<U> returnedResourceList = dao.getSearchResults(searchParameterMap).stream().map(translator::toFhirResource)
82-
.filter(Objects::nonNull).collect(Collectors.toList());
81+
List<U> resources = translator.toFhirResources(dao.getSearchResults(searchParameterMap));
8382

84-
Set<IBaseResource> includedResources = searchQueryInclude.getIncludedResources(returnedResourceList,
85-
this.searchParameterMap);
83+
Set<IBaseResource> includedResources = searchQueryInclude.getIncludedResources(resources, this.searchParameterMap);
8684

87-
List<IBaseResource> resultList = new ArrayList<>(returnedResourceList);
85+
List<IBaseResource> resultList = new ArrayList<>(resources.size() + includedResources.size());
86+
resultList.addAll(resources);
8887
resultList.addAll(includedResources);
8988

9089
return resultList;

api/src/main/java/org/openmrs/module/fhir2/api/translators/LocationTranslator.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
import javax.annotation.Nonnull;
1313

14+
import java.util.Collection;
15+
import java.util.List;
16+
1417
import org.hl7.fhir.r4.model.Location;
1518

1619
public interface LocationTranslator extends OpenmrsFhirUpdatableTranslator<org.openmrs.Location, Location> {
@@ -24,6 +27,15 @@ public interface LocationTranslator extends OpenmrsFhirUpdatableTranslator<org.o
2427
@Override
2528
Location toFhirResource(@Nonnull org.openmrs.Location openmrsLocation);
2629

30+
/**
31+
* Maps a collection of {@link org.openmrs.Location}s to a {@link org.hl7.fhir.r4.model.Location}
32+
*
33+
* @param openmrsLocations the collection of locations to translate
34+
* @return the mapping of OpenMRS location to corresponding FHIR location resource
35+
*/
36+
@Override
37+
List<Location> toFhirResources(Collection<org.openmrs.Location> openmrsLocations);
38+
2739
/**
2840
* Maps a {@link org.hl7.fhir.r4.model.Location} to an {@link org.openmrs.Location}
2941
*

api/src/main/java/org/openmrs/module/fhir2/api/translators/OpenmrsFhirTranslator.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,25 @@
99
*/
1010
package org.openmrs.module.fhir2.api.translators;
1111

12+
import java.util.Collection;
13+
import java.util.List;
14+
import java.util.stream.Collectors;
15+
1216
/**
1317
* Generic interface for a translator between OpenMRS data and FHIR resources
1418
*
1519
* @param <T> OpenMRS data type
1620
* @param <U> FHIR resource type
1721
*/
18-
public interface OpenmrsFhirTranslator<T, U> extends ToFhirTranslator<T, U>, ToOpenmrsTranslator<T, U> {}
22+
public interface OpenmrsFhirTranslator<T, U> extends ToFhirTranslator<T, U>, ToOpenmrsTranslator<T, U> {
23+
24+
/**
25+
* Maps OpenMRS data elements to FHIR resources.
26+
*
27+
* @param data the collection of OpenMRS data elements to translate
28+
* @return the mapping of OpenMRS data element to corresponding FHIR resource
29+
*/
30+
default List<U> toFhirResources(Collection<T> data) {
31+
return data.stream().distinct().map(this::toFhirResource).collect(Collectors.toList());
32+
}
33+
}

api/src/main/java/org/openmrs/module/fhir2/api/translators/ToFhirTranslator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ public interface ToFhirTranslator<T, U> extends FhirTranslator {
2626
* @return the corresponding FHIR resource
2727
*/
2828
U toFhirResource(@Nonnull T data);
29+
2930
}

0 commit comments

Comments
 (0)