Skip to content

Commit

Permalink
FM2-347:Add support for _has and _has:...:not for ServiceRequest and …
Browse files Browse the repository at this point in the history
…Observation
  • Loading branch information
gitcliff committed Mar 29, 2021
1 parent 976880c commit 453e3cd
Show file tree
Hide file tree
Showing 25 changed files with 475 additions and 243 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class FhirConstants {
+ "/condition-ver-status";

public static final String CLINICAL_FINDINGS_SYSTEM_URI = HL7_FHIR_CODE_SYSTEM_PREFIX + "/clinical-findings";

public static final String TASK_STATUS_VALUE_SET_URI = "http://hl7.org/fhir/task-status";

public static final String OBSERVATION_REFERENCE_RANGE_SYSTEM_URI = HL7_FHIR_CODE_SYSTEM_PREFIX
Expand Down Expand Up @@ -255,6 +255,8 @@ public class FhirConstants {

public static final String COMMON_SEARCH_HANDLER = "common.search.handler";

public static final String HAS_PROPERTY = "_has";

public static final String ID_PROPERTY = "_id.property";

public static final String LAST_UPDATED_PROPERTY = "_lastUpdated.property";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public interface FhirObservationService extends FhirService<Observation> {
Observation get(@Nonnull String uuid);

IBundleProvider searchForObservations(ReferenceAndListParam encounterReference, ReferenceAndListParam patientReference,
ReferenceAndListParam hasMemberReference, TokenAndListParam valueConcept, DateRangeParam valueDateParam,
QuantityAndListParam valueQuantityParam, StringAndListParam valueStringParam, DateRangeParam date,
TokenAndListParam code, TokenAndListParam category, TokenAndListParam id, DateRangeParam lastUpdated,
SortSpec sort, HashSet<Include> includes, HashSet<Include> revIncludes);
ReferenceAndListParam hasMemberReference, ReferenceAndListParam basedOnReference, TokenAndListParam valueConcept,
DateRangeParam valueDateParam, QuantityAndListParam valueQuantityParam, StringAndListParam valueStringParam,
DateRangeParam date, TokenAndListParam code, TokenAndListParam category, TokenAndListParam id,
DateRangeParam lastUpdated, SortSpec sort, HashSet<Include> includes, HashSet<Include> revIncludes);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import org.hl7.fhir.r4.model.ServiceRequest;
Expand All @@ -22,5 +23,5 @@ public interface FhirServiceRequestService extends FhirService<ServiceRequest> {

IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, DateRangeParam lastUpdated, HashSet<Include> includes);
TokenAndListParam uuid, DateRangeParam lastUpdated, HasAndListParam has, HashSet<Include> includes);
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,17 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.HasParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.param.QuantityParam;
Expand All @@ -82,6 +86,7 @@
import org.hibernate.internal.CriteriaImpl;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.Location;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Practitioner;
import org.hl7.fhir.r4.model.codesystems.AdministrativeGender;
Expand All @@ -90,6 +95,7 @@
import org.openmrs.module.fhir2.api.util.LocalDateTimeFactory;
import org.openmrs.module.fhir2.model.FhirConceptSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
* <p>
Expand Down Expand Up @@ -171,6 +177,10 @@ public abstract class BaseDao {
@Autowired
private LocalDateTimeFactory localDateTimeFactory;

@Autowired
@Qualifier("fhirR4")
private FhirContext fhirContext;

/**
* Converts an {@link Iterable} to a {@link Stream}
*
Expand Down Expand Up @@ -443,6 +453,49 @@ protected Optional<Criterion> handleDate(String propertyName, DateParam datePara
return Optional.empty();
}

/**
* A handler for a {@link HasParam}
*
* @param propertyName the name of the property in the query to use
* @param hasParam the {@link HasParam} to handle
* @return a {@link Criterion} to be added to the query for the indicate has param
*/
protected Optional<Criterion> handleHas(String propertyName, HasParam hasParam) {
if (hasParam == null) {
return Optional.empty();
}
ArrayList<IQueryParameterType> orValues = new ArrayList<>();
String targetResourceType = null;
String paramReference = null;
String parameterName = null;

String paramName = null;
targetResourceType = hasParam.getTargetResourceType();

if (targetResourceType.getClass().equals(Observation.class)) {
paramReference = hasParam.getReferenceFieldName();
parameterName = hasParam.getParameterName();
paramName = parameterName.replaceAll("\\..*", "");
hasParam = new HasParam(targetResourceType, paramReference, parameterName, hasParam.getParameterValue());
orValues.add(hasParam);
orValues.add(
(IQueryParameterType) QualifiedParamList.singleton(null, hasParam.getValueAsQueryToken(fhirContext)));
}
String qualifier = paramName.substring(4);
hasParam.setValueAsQueryToken(fhirContext, FhirConstants.HAS_PROPERTY, qualifier,
hasParam.getValueAsQueryToken(fhirContext));
orValues.add(hasParam);
return Optional.of(eq(propertyName, orValues));
}

protected Optional<Criterion> handleHasParam(@Nonnull String propertyName, HasAndListParam hasAndListParam) {
if (hasAndListParam == null) {
return Optional.empty();
}

return handleAndListParam(hasAndListParam, hasParam -> handleHas(propertyName, hasParam));
}

protected Optional<Criterion> handleQuantity(String propertyName, QuantityParam quantityParam) {
if (quantityParam == null) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@
*/
package org.openmrs.module.fhir2.api.dao.impl;

import static org.hibernate.criterion.Restrictions.and;
import static org.hibernate.criterion.Restrictions.eq;

import javax.annotation.Nonnull;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
Expand Down Expand Up @@ -59,6 +63,10 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
entry.getValue()
.forEach(category -> handleConceptClass(criteria, (TokenAndListParam) category.getParam()));
break;
case FhirConstants.BASED_ON_REFERENCE_SEARCH_HANDLER:
entry.getValue().forEach(param -> handleReference(criteria, (ReferenceAndListParam) param.getParam(),
"basedOnReferences", "bo"));
break;
case FhirConstants.VALUE_CODED_SEARCH_HANDLER:
entry.getValue().forEach(
valueCoded -> handleValueCodedConcept(criteria, (TokenAndListParam) valueCoded.getParam()));
Expand All @@ -71,6 +79,7 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
entry.getValue().forEach(hasMemberReference -> handleHasMemberReference(criteria,
(ReferenceAndListParam) hasMemberReference.getParam()));
break;

case FhirConstants.QUANTITY_SEARCH_HANDLER:
entry.getValue().forEach(
quantity -> handleQuantity(quantity.getPropertyName(), (QuantityAndListParam) quantity.getParam())
Expand Down Expand Up @@ -160,6 +169,27 @@ private void handleValueCodedConcept(Criteria criteria, TokenAndListParam valueC
}
}

private Boolean validReferenceParam(ReferenceParam ref) {
return (ref != null && ref.getIdPart() != null && ref.getResourceType() != null);
}

private void handleReference(Criteria criteria, ReferenceAndListParam reference, String property, String alias) {
handleAndListParam(reference, param -> {
if (validReferenceParam(param)) {
if (lacksAlias(criteria, alias)) {
criteria.createAlias(property, alias);
}

List<Optional<Criterion>> criterionList = new ArrayList<>();
criterionList.add(Optional.of(eq(String.format("%s.reference", alias), param.getIdPart())));
criterionList.add(Optional.of(eq(String.format("%s.type", alias), param.getResourceType())));
return Optional.of(and(toCriteriaArray(criterionList)));
}

return Optional.empty();
}).ifPresent(criteria::add);
}

@Override
protected String paramToProp(@Nonnull String paramName) {
if (Observation.SP_DATE.equals(paramName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import java.util.Optional;
import java.util.stream.Stream;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import lombok.AccessLevel;
Expand All @@ -26,12 +28,18 @@
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.api.dao.FhirServiceRequestDao;
import org.openmrs.module.fhir2.api.search.param.SearchParameterMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Setter(AccessLevel.PACKAGE)
public class FhirServiceRequestDaoImpl extends BaseFhirDao<TestOrder> implements FhirServiceRequestDao<TestOrder> {

@Autowired
@Qualifier("fhirR4")
private FhirContext fhirContext;

@Override
protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams) {
theParams.getParameters().forEach(entry -> {
Expand All @@ -51,6 +59,10 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
entry.getValue().forEach(participantReference -> handleProviderReference(criteria,
(ReferenceAndListParam) participantReference.getParam()));
break;
case FhirConstants.HAS_PROPERTY:
entry.getValue().forEach(hasParameter -> handleHasParam(hasParameter.getPropertyName(),
(HasAndListParam) hasParameter.getParam()).ifPresent(criteria::add));
break;
case FhirConstants.DATE_RANGE_SEARCH_HANDLER:
entry.getValue().forEach(dateRangeParam -> handleDateRange((DateRangeParam) dateRangeParam.getParam())
.ifPresent(criteria::add));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ public class FhirObservationServiceImpl extends BaseFhirService<Observation, org
@Override
@Transactional(readOnly = true)
public IBundleProvider searchForObservations(ReferenceAndListParam encounterReference,
ReferenceAndListParam patientReference, ReferenceAndListParam hasMemberReference, TokenAndListParam valueConcept,
DateRangeParam valueDateParam, QuantityAndListParam valueQuantityParam, StringAndListParam valueStringParam,
DateRangeParam date, TokenAndListParam code, TokenAndListParam category, TokenAndListParam id,
DateRangeParam lastUpdated, SortSpec sort, HashSet<Include> includes, HashSet<Include> revIncludes) {
ReferenceAndListParam patientReference, ReferenceAndListParam hasMemberReference,
ReferenceAndListParam basedOnReference, TokenAndListParam valueConcept, DateRangeParam valueDateParam,
QuantityAndListParam valueQuantityParam, StringAndListParam valueStringParam, DateRangeParam date,
TokenAndListParam code, TokenAndListParam category, TokenAndListParam id, DateRangeParam lastUpdated,
SortSpec sort, HashSet<Include> includes, HashSet<Include> revIncludes) {

SearchParameterMap theParams = new SearchParameterMap()
.addParameter(FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER, encounterReference)
Expand All @@ -68,6 +69,7 @@ public IBundleProvider searchForObservations(ReferenceAndListParam encounterRefe
.addParameter(FhirConstants.CATEGORY_SEARCH_HANDLER, category)
.addParameter(FhirConstants.VALUE_CODED_SEARCH_HANDLER, valueConcept)
.addParameter(FhirConstants.HAS_MEMBER_SEARCH_HANDLER, hasMemberReference)
.addParameter(FhirConstants.BASED_ON_REFERENCE_SEARCH_HANDLER, basedOnReference)
.addParameter(FhirConstants.VALUE_STRING_SEARCH_HANDLER, "valueText", valueStringParam)
.addParameter(FhirConstants.QUANTITY_SEARCH_HANDLER, "valueNumeric", valueQuantityParam)
.addParameter(FhirConstants.DATE_RANGE_SEARCH_HANDLER, "obsDatetime", date)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import lombok.AccessLevel;
Expand Down Expand Up @@ -53,11 +54,12 @@ public class FhirServiceRequestServiceImpl extends BaseFhirService<ServiceReques
@Override
public IBundleProvider searchForServiceRequests(ReferenceAndListParam patientReference, TokenAndListParam code,
ReferenceAndListParam encounterReference, ReferenceAndListParam participantReference, DateRangeParam occurrence,
TokenAndListParam uuid, DateRangeParam lastUpdated, HashSet<Include> includes) {
TokenAndListParam uuid, DateRangeParam lastUpdated, HasAndListParam has, HashSet<Include> includes) {

SearchParameterMap theParams = new SearchParameterMap()
.addParameter(FhirConstants.PATIENT_REFERENCE_SEARCH_HANDLER, patientReference)
.addParameter(FhirConstants.CODED_SEARCH_HANDLER, code)
.addParameter(FhirConstants.CODED_SEARCH_HANDLER, code)
.addParameter(FhirConstants.HAS_PROPERTY, has)
.addParameter(FhirConstants.ENCOUNTER_REFERENCE_SEARCH_HANDLER, encounterReference)
.addParameter(FhirConstants.PARTICIPANT_REFERENCE_SEARCH_HANDLER, participantReference)
.addParameter(FhirConstants.DATE_RANGE_SEARCH_HANDLER, occurrence)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private IBundleProvider handleObservationReverseInclude(ReferenceAndListParam pa
switch (targetType) {
case FhirConstants.OBSERVATION:
return observationService.searchForObservations(null, null, params, null, null, null, null, null, null, null,
null, null, null, null, null);
null, null, null, null, null, null);
case FhirConstants.DIAGNOSTIC_REPORT:
return diagnosticReportService.searchForDiagnosticReports(null, null, null, null, params, null, null, null,
null);
Expand All @@ -228,7 +228,8 @@ private IBundleProvider handlePractitionerReverseInclude(ReferenceAndListParam p
null);
case FhirConstants.PROCEDURE_REQUEST:
case FhirConstants.SERVICE_REQUEST:
return serviceRequestService.searchForServiceRequests(null, null, null, params, null, null, null, null);
return serviceRequestService.searchForServiceRequests(null, null, null, params, null, null, null, null,
null);
}

return null;
Expand All @@ -238,7 +239,7 @@ private IBundleProvider handleEncounterReverseInclude(ReferenceAndListParam para
switch (targetType) {
case FhirConstants.OBSERVATION:
return observationService.searchForObservations(params, null, null, null, null, null, null, null, null, null,
null, null, null, null, null);
null, null, null, null, null, null);
case FhirConstants.DIAGNOSTIC_REPORT:
return diagnosticReportService.searchForDiagnosticReports(params, null, null, null, null, null, null, null,
null);
Expand All @@ -247,7 +248,8 @@ private IBundleProvider handleEncounterReverseInclude(ReferenceAndListParam para
null);
case FhirConstants.PROCEDURE_REQUEST:
case FhirConstants.SERVICE_REQUEST:
return serviceRequestService.searchForServiceRequests(null, null, params, null, null, null, null, null);
return serviceRequestService.searchForServiceRequests(null, null, params, null, null, null, null, null,
null);
}

return null;
Expand All @@ -267,7 +269,7 @@ private IBundleProvider handlePatientReverseInclude(ReferenceAndListParam params
switch (targetType) {
case FhirConstants.OBSERVATION:
return observationService.searchForObservations(null, params, null, null, null, null, null, null, null, null,
null, null, null, null, null);
null, null, null, null, null, null);
case FhirConstants.DIAGNOSTIC_REPORT:
return diagnosticReportService.searchForDiagnosticReports(null, params, null, null, null, null, null, null,
null);
Expand All @@ -281,7 +283,8 @@ private IBundleProvider handlePatientReverseInclude(ReferenceAndListParam params
null);
case FhirConstants.SERVICE_REQUEST:
case FhirConstants.PROCEDURE_REQUEST:
return serviceRequestService.searchForServiceRequests(params, null, null, null, null, null, null, null);
return serviceRequestService.searchForServiceRequests(params, null, null, null, null, null, null, null,
null);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.ServiceRequest;
import org.openmrs.module.fhir2.api.FhirObservationService;
import org.openmrs.module.fhir2.api.search.SearchQueryBundleProviderR3Wrapper;
import org.openmrs.module.fhir2.providers.util.FhirProviderUtils;
Expand Down Expand Up @@ -112,6 +113,8 @@ public IBundleProvider searchObservations(
Patient.SP_FAMILY, Patient.SP_NAME }, targetTypes = Patient.class) ReferenceAndListParam patientParam,
@OptionalParam(name = Observation.SP_RELATED_TYPE, chainWhitelist = { "",
Observation.SP_CODE }, targetTypes = Observation.class) ReferenceAndListParam hasMemberReference,
@OptionalParam(name = Observation.SP_BASED_ON, chainWhitelist = { "",
ServiceRequest.SP_IDENTIFIER }, targetTypes = ServiceRequest.class) ReferenceAndListParam basedOnReference,
@OptionalParam(name = Observation.SP_VALUE_CONCEPT) TokenAndListParam valueConcept,
@OptionalParam(name = Observation.SP_VALUE_DATE) DateRangeParam valueDateParam,
@OptionalParam(name = Observation.SP_VALUE_QUANTITY) QuantityAndListParam valueQuantityParam,
Expand All @@ -138,8 +141,8 @@ public IBundleProvider searchObservations(
}

return new SearchQueryBundleProviderR3Wrapper(observationService.searchForObservations(encounterReference,
patientReference, hasMemberReference, valueConcept, valueDateParam, valueQuantityParam, valueStringParam, date,
code, category, id, lastUpdated, sort, includes, revIncludes));
patientReference, basedOnReference, hasMemberReference, valueConcept, valueDateParam, valueQuantityParam,
valueStringParam, date, code, category, id, lastUpdated, sort, includes, revIncludes));
}

}
Loading

0 comments on commit 453e3cd

Please sign in to comment.