diff --git a/api-2.6/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationDispenseDaoImpl_2_6.java b/api-2.6/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationDispenseDaoImpl_2_6.java index 37bff51aa..a5f9da79b 100644 --- a/api-2.6/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationDispenseDaoImpl_2_6.java +++ b/api-2.6/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationDispenseDaoImpl_2_6.java @@ -74,8 +74,8 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams .forEach(param -> handlePatientReference(criteria, (ReferenceAndListParam) param.getParam())); break; case FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER: - entry.getValue().forEach(e -> handleEncounterReference("e", (ReferenceAndListParam) e.getParam()) - .ifPresent(c -> createAlias(criteria, "encounter", "e").add(c))); + entry.getValue() + .forEach(e -> handleEncounterReference(criteria, (ReferenceAndListParam) e.getParam(), "e")); break; case FhirConstants.MEDICATION_REQUEST_REFERENCE_SEARCH_HANDLER: entry.getValue() diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/BaseDao.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/BaseDao.java index 36ad36b72..8bff33d9c 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/BaseDao.java +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/BaseDao.java @@ -80,6 +80,7 @@ import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.internal.CriteriaImpl; +import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.Location; import org.hl7.fhir.r4.model.Patient; @@ -493,14 +494,36 @@ protected Optional handleQuantity(@Nonnull String propertyName, Quant return handleAndListParam(quantityAndListParam, quantityParam -> handleQuantity(propertyName, quantityParam)); } - protected Optional handleEncounterReference(@Nonnull String encounterAlias, - ReferenceAndListParam encounterReference) { + protected void handleEncounterReference(Criteria criteria, ReferenceAndListParam encounterReference, + @Nonnull String encounterAlias) { + handleEncounterReference(criteria, encounterReference, encounterAlias, "encounter"); + } + + protected void handleEncounterReference(Criteria criteria, ReferenceAndListParam encounterReference, + @Nonnull String encounterAlias, @Nonnull String associationPath) { if (encounterReference == null) { - return Optional.empty(); + return; } - return handleAndListParam(encounterReference, - token -> Optional.of(eq(String.format("%s.uuid", encounterAlias), token.getIdPart()))); + if (lacksAlias(criteria, encounterAlias)) { + criteria.createAlias(associationPath, encounterAlias); + } + + handleAndListParam(encounterReference, token -> { + if (token.getChain() != null) { + switch (token.getChain()) { + case Encounter.SP_TYPE: + if (lacksAlias(criteria, "et")) { + criteria.createAlias(String.format("%s.encounterType", encounterAlias), "et"); + } + return propertyLike("et.uuid", new StringParam(token.getValue(), true)); + } + } else { + return Optional.of(eq(String.format("%s.uuid", encounterAlias), token.getIdPart())); + } + + return Optional.empty(); + }).ifPresent(criteria::add); } protected Optional handleGender(@Nonnull String propertyName, TokenAndListParam gender) { diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirDiagnosticReportDaoImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirDiagnosticReportDaoImpl.java index cf41da205..77c83967d 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirDiagnosticReportDaoImpl.java +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirDiagnosticReportDaoImpl.java @@ -37,8 +37,8 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams theParams.getParameters().forEach(entry -> { switch (entry.getKey()) { case FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER: - entry.getValue().forEach(param -> handleEncounterReference("e", (ReferenceAndListParam) param.getParam()) - .ifPresent(c -> criteria.createAlias("encounter", "e").add(c))); + entry.getValue().forEach( + param -> handleEncounterReference(criteria, (ReferenceAndListParam) param.getParam(), "e")); break; case FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER: entry.getValue().forEach( diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationRequestDaoImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationRequestDaoImpl.java index 576aceceb..2b3af0661 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationRequestDaoImpl.java +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirMedicationRequestDaoImpl.java @@ -29,8 +29,8 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams theParams.getParameters().forEach(entry -> { switch (entry.getKey()) { case FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER: - entry.getValue().forEach(e -> handleEncounterReference("e", (ReferenceAndListParam) e.getParam()) - .ifPresent(c -> criteria.createAlias("encounter", "e").add(c))); + entry.getValue() + .forEach(e -> handleEncounterReference(criteria, (ReferenceAndListParam) e.getParam(), "e")); break; case FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER: entry.getValue().forEach(patientReference -> handlePatientReference(criteria, diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirObservationDaoImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirObservationDaoImpl.java index e33d0a656..3085b9e98 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirObservationDaoImpl.java +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirObservationDaoImpl.java @@ -60,7 +60,6 @@ public class FhirObservationDaoImpl extends BaseFhirDao implements FhirObse @Override public List getSearchResultUuids(@Nonnull SearchParameterMap theParams) { if (!theParams.getParameters(FhirConstants.LASTN_OBSERVATION_SEARCH_HANDLER).isEmpty()) { - Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(typeToken.getRawType()); setupSearchParams(criteria, theParams); @@ -99,8 +98,8 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams theParams.getParameters().forEach(entry -> { switch (entry.getKey()) { case FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER: - entry.getValue().forEach(p -> handleEncounterReference("e", (ReferenceAndListParam) p.getParam()) - .ifPresent(c -> criteria.createAlias("encounter", "e").add(c))); + entry.getValue() + .forEach(p -> handleEncounterReference(criteria, (ReferenceAndListParam) p.getParam(), "e")); break; case FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER: entry.getValue().forEach(patientReference -> handlePatientReference(criteria, diff --git a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirServiceRequestDaoImpl.java b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirServiceRequestDaoImpl.java index 8a0fca699..a31d80610 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirServiceRequestDaoImpl.java +++ b/api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirServiceRequestDaoImpl.java @@ -37,8 +37,8 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams theParams.getParameters().forEach(entry -> { switch (entry.getKey()) { case FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER: - entry.getValue().forEach(param -> handleEncounterReference("e", (ReferenceAndListParam) param.getParam()) - .ifPresent(c -> criteria.createAlias("encounter", "e").add(c))); + entry.getValue().forEach( + param -> handleEncounterReference(criteria, (ReferenceAndListParam) param.getParam(), "e")); break; case FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER: entry.getValue().forEach(patientReference -> handlePatientReference(criteria, diff --git a/api/src/main/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProvider.java b/api/src/main/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProvider.java index 5134eb4e0..c5044fc50 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProvider.java +++ b/api/src/main/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProvider.java @@ -43,6 +43,7 @@ import org.apache.commons.collections.CollectionUtils; import org.hl7.fhir.convertors.conv30_40.Observation30_40; import org.hl7.fhir.dstu3.model.DiagnosticReport; +import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.OperationOutcome; @@ -94,7 +95,8 @@ public OperationOutcome deleteObservationResource(@IdParam @Nonnull IdType id) { @Search public IBundleProvider searchObservations( - @OptionalParam(name = Observation.SP_ENCOUNTER) ReferenceAndListParam encounterReference, + @OptionalParam(name = Observation.SP_ENCOUNTER, chainWhitelist = { "", + Encounter.SP_TYPE }, targetTypes = Encounter.class) ReferenceAndListParam encounterReference, @OptionalParam(name = Observation.SP_SUBJECT, chainWhitelist = { "", Patient.SP_IDENTIFIER, Patient.SP_GIVEN, Patient.SP_FAMILY, Patient.SP_NAME }, targetTypes = Patient.class) ReferenceAndListParam patientReference, diff --git a/api/src/main/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProvider.java b/api/src/main/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProvider.java index aca373da6..80fbe8aa6 100644 --- a/api/src/main/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProvider.java +++ b/api/src/main/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProvider.java @@ -91,8 +91,8 @@ public OperationOutcome deleteObservationResource(@IdParam @Nonnull IdType id) { @Search public IBundleProvider searchObservations( - @OptionalParam(name = Observation.SP_ENCOUNTER, chainWhitelist = { - "" }, targetTypes = Encounter.class) ReferenceAndListParam encounterReference, + @OptionalParam(name = Observation.SP_ENCOUNTER, chainWhitelist = { "", + Encounter.SP_TYPE }, targetTypes = Encounter.class) ReferenceAndListParam encounterReference, @OptionalParam(name = Observation.SP_SUBJECT, chainWhitelist = { "", Patient.SP_IDENTIFIER, Patient.SP_GIVEN, Patient.SP_FAMILY, Patient.SP_NAME }, targetTypes = Patient.class) ReferenceAndListParam patientReference, diff --git a/api/src/test/java/org/openmrs/module/fhir2/api/search/ObservationSearchQueryTest.java b/api/src/test/java/org/openmrs/module/fhir2/api/search/ObservationSearchQueryTest.java index 0081263f8..f89655355 100644 --- a/api/src/test/java/org/openmrs/module/fhir2/api/search/ObservationSearchQueryTest.java +++ b/api/src/test/java/org/openmrs/module/fhir2/api/search/ObservationSearchQueryTest.java @@ -131,6 +131,8 @@ public class ObservationSearchQueryTest extends BaseModuleContextSensitiveTest { private static final String ENCOUNTER_UUID_TWO = "6519d653-393b-4118-9c83-a3715b82d4ac"; + private static final String ENCOUNTER_TYPE_UUID = "07000be2-26b6-4cce-8b40-866d8435b613"; + private static final String MEMBER_UUID = "744b91f8-bdbc-4950-833b-002244e9fa2b"; private static final String OBS_SNOMED_CODE = "2332523"; @@ -667,6 +669,25 @@ public void searchForObs_shouldReturnObsByEncounter() { assertThat(resultList.size(), equalTo(10)); } + @Test + public void searchForObs_shouldReturnObsByEncounterType() { + ReferenceAndListParam encounterReference = new ReferenceAndListParam() + .addAnd(new ReferenceOrListParam().add(new ReferenceParam().setValue(ENCOUNTER_TYPE_UUID).setChain("type"))); + + SearchParameterMap theParams = new SearchParameterMap(); + theParams.addParameter(FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER, encounterReference); + + IBundleProvider results = search(theParams); + + assertThat(results, notNullValue()); + assertThat(results.size(), equalTo(14)); + + List resultList = get(results); + + assertThat(resultList, notNullValue()); + assertThat(resultList.size(), equalTo(10)); + } + @Test public void searchForObs_shouldReturnObsByCategory() { TokenAndListParam categories = new TokenAndListParam().addAnd(new TokenParam().setValue("laboratory")); diff --git a/api/src/test/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProviderTest.java b/api/src/test/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProviderTest.java index bf87582cc..5003ed4d5 100644 --- a/api/src/test/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProviderTest.java +++ b/api/src/test/java/org/openmrs/module/fhir2/providers/r3/ObservationFhirResourceProviderTest.java @@ -52,6 +52,7 @@ import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.DiagnosticReport; +import org.hl7.fhir.r4.model.Encounter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -175,6 +176,26 @@ public void searchObservations_shouldReturnMatchingObservationsWhenPatientParamI assertThat(resultList.get(0).getIdElement().getIdPart(), equalTo(OBSERVATION_UUID)); } + @Test + public void searchObservations_shouldReturnMatchingObservationsWhenEncounterParamIsSpecified() { + when(observationService.searchForObservations(any())) + .thenReturn(new MockIBundleProvider<>(Collections.singletonList(observation), 10, 1)); + + ReferenceAndListParam encounterParam = new ReferenceAndListParam(); + encounterParam.addValue(new ReferenceOrListParam().add(new ReferenceParam().setChain(Encounter.SP_TYPE))); + + IBundleProvider results = resourceProvider.searchObservations(encounterParam, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null); + + List resultList = get(results, 1, 5); + + assertThat(results, notNullValue()); + assertThat(resultList, hasSize(equalTo(1))); + assertThat(resultList.get(0), notNullValue()); + assertThat(resultList.get(0).fhirType(), equalTo(FhirConstants.OBSERVATION)); + assertThat(resultList.get(0).getIdElement().getIdPart(), equalTo(OBSERVATION_UUID)); + } + @Test public void searchObservations_shouldAddRelatedResourcesWhenIncluded() { HashSet includes = new HashSet<>(); diff --git a/api/src/test/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProviderTest.java b/api/src/test/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProviderTest.java index 920d3ea36..72d87a671 100644 --- a/api/src/test/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProviderTest.java +++ b/api/src/test/java/org/openmrs/module/fhir2/providers/r4/ObservationFhirResourceProviderTest.java @@ -38,6 +38,7 @@ import lombok.Getter; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.DiagnosticReport; +import org.hl7.fhir.r4.model.Encounter; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.OperationOutcome; @@ -170,6 +171,26 @@ public void searchObservations_shouldReturnMatchingObservationsWhenPatientParamI assertThat(resultList.get(0).getIdElement().getIdPart(), equalTo(OBSERVATION_UUID)); } + @Test + public void searchObservations_shouldReturnMatchingObservationsWhenEncounterParamIsSpecified() { + when(observationService.searchForObservations(any())) + .thenReturn(new MockIBundleProvider<>(Collections.singletonList(observation), 10, 1)); + + ReferenceAndListParam encounterParam = new ReferenceAndListParam(); + encounterParam.addValue(new ReferenceOrListParam().add(new ReferenceParam().setChain(Encounter.SP_TYPE))); + + IBundleProvider results = resourceProvider.searchObservations(encounterParam, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null); + + List resultList = get(results); + + assertThat(results, notNullValue()); + assertThat(resultList, hasSize(equalTo(1))); + assertThat(resultList.get(0), notNullValue()); + assertThat(resultList.get(0).fhirType(), equalTo(FhirConstants.OBSERVATION)); + assertThat(resultList.get(0).getIdElement().getIdPart(), equalTo(OBSERVATION_UUID)); + } + @Test public void searchObservations_shouldAddRelatedResourcesWhenIncluded() { HashSet includes = new HashSet<>();