Skip to content

Commit

Permalink
(feat) _has parameter added for patients
Browse files Browse the repository at this point in the history
  • Loading branch information
icrc-jofrancisco committed Jul 19, 2024
1 parent 5866889 commit fa21503
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 104 deletions.
5 changes: 5 additions & 0 deletions api/src/main/java/org/openmrs/module/fhir2/FhirConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ private FhirConstants() {

public static final String MEDICATION = "Medication";

public static final String GROUP = "Group";

public static final String MEDICATION_DISPENSE = "MedicationDispense";

public static final String MEDICATION_REQUEST = "MedicationRequest";
Expand Down Expand Up @@ -356,4 +358,7 @@ private FhirConstants() {
public static final String EXACT_TOTAL_SEARCH_PARAMETER = "_exactTotal";

public static final String COUNT_QUERY_CACHE = "countQueryCache";

public static final String INCLUDE_MEMBER_PARAM = "member";

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
Expand All @@ -33,17 +38,24 @@
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.sql.JoinType;
import org.openmrs.Cohort;
import org.openmrs.CohortMembership;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifierType;
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.api.dao.FhirGroupDao;
import org.openmrs.module.fhir2.api.dao.FhirPatientDao;
import org.openmrs.module.fhir2.api.search.param.SearchParameterMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Setter(AccessLevel.PACKAGE)
public class FhirPatientDaoImpl extends BasePersonDao<Patient> implements FhirPatientDao {

@Autowired
private FhirGroupDao groupDao;

@Override
public Patient getPatientById(@Nonnull Integer id) {
return (Patient) getSessionFactory().getCurrentSession().createCriteria(Patient.class).add(eq("patientId", id))
Expand Down Expand Up @@ -111,10 +123,55 @@ protected void setupSearchParams(Criteria criteria, SearchParameterMap theParams
case FhirConstants.COMMON_SEARCH_HANDLER:
handleCommonSearchParameters(entry.getValue()).ifPresent(criteria::add);
break;
case FhirConstants.HAS_SEARCH_HANDLER:
entry.getValue().forEach(param -> handleHasAndListParam(criteria, (HasAndListParam) param.getParam()));

Check warning on line 127 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L127

Added line #L127 was not covered by tests
break;
}
});
}

protected void handleHasAndListParam(Criteria criteria, HasAndListParam hasAndListParam) {
if (hasAndListParam != null) {
List<String> groupIds = new ArrayList<>();
hasAndListParam.getValuesAsQueryTokens().forEach(hasOrListParam -> {
hasOrListParam.getValuesAsQueryTokens().forEach(hasParam -> {

Check warning on line 137 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L135-L137

Added lines #L135 - L137 were not covered by tests
if (hasParam != null) {
String paramValue = hasParam.getParameterValue();

Check warning on line 139 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L139

Added line #L139 was not covered by tests
switch (hasParam.getTargetResourceType()) {
case FhirConstants.GROUP:
switch (hasParam.getReferenceFieldName()) {
case FhirConstants.INCLUDE_MEMBER_PARAM:
groupIds.add(paramValue);

Check warning on line 144 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L144

Added line #L144 was not covered by tests
break;
}
break;
}
}
});
});

Check warning on line 151 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L150-L151

Added lines #L150 - L151 were not covered by tests

if (!groupIds.isEmpty()) {
verifyPatientInGroups(criteria, groupIds);

Check warning on line 154 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L154

Added line #L154 was not covered by tests
}
}
}

Check warning on line 157 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L157

Added line #L157 was not covered by tests

private void verifyPatientInGroups(Criteria criteria, List<String> groupIds) {
Set<Integer> patientIds = new HashSet<>();
groupIds.forEach(groupId -> patientIds.addAll(getGroupMemberIds(groupId)));

Check warning on line 161 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L160-L161

Added lines #L160 - L161 were not covered by tests

criteria.add(in("patientId", patientIds.isEmpty() ? Collections.emptyList() : patientIds));
}

Check warning on line 164 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L164

Added line #L164 was not covered by tests

private List<Integer> getGroupMemberIds(String groupId) {
Cohort cohort = groupDao.get(groupId);

Check warning on line 167 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L167

Added line #L167 was not covered by tests
if (cohort != null) {
return cohort.getMemberships().stream().map(CohortMembership::getPatientId).collect(Collectors.toList());

Check warning on line 169 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L169

Added line #L169 was not covered by tests
} else {
return Collections.emptyList();

Check warning on line 171 in api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/openmrs/module/fhir2/api/dao/impl/FhirPatientDaoImpl.java#L171

Added line #L171 was not covered by tests
}
}

private void handlePatientQuery(Criteria criteria, @Nonnull StringAndListParam query) {
if (query == null) {
return;
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.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import lombok.Builder;
Expand Down Expand Up @@ -45,11 +46,13 @@ public class OpenmrsPatientSearchParams extends BaseResourceSearchParams {

private StringAndListParam country;

private HasAndListParam hasAndListParam;

@Builder
public OpenmrsPatientSearchParams(StringAndListParam query, TokenAndListParam gender, DateRangeParam birthDate,
DateRangeParam deathDate, TokenAndListParam deceased, StringAndListParam city, StringAndListParam state,
StringAndListParam postalCode, StringAndListParam country, TokenAndListParam id, DateRangeParam lastUpdated,
SortSpec sort, HashSet<Include> revIncludes) {
StringAndListParam postalCode, StringAndListParam country, TokenAndListParam id, HasAndListParam hasAndListParam,
DateRangeParam lastUpdated, SortSpec sort, HashSet<Include> revIncludes) {

super(id, lastUpdated, sort, null, revIncludes);

Expand All @@ -62,6 +65,7 @@ public OpenmrsPatientSearchParams(StringAndListParam query, TokenAndListParam ge
this.state = state;
this.postalCode = postalCode;
this.country = country;
this.hasAndListParam = hasAndListParam;
}

@Override
Expand All @@ -74,6 +78,7 @@ public SearchParameterMap toSearchParameterMap() {
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.CITY_PROPERTY, getCity())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.STATE_PROPERTY, getState())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.POSTAL_CODE_PROPERTY, getPostalCode())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.COUNTRY_PROPERTY, getCountry());
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.COUNTRY_PROPERTY, getCountry())
.addParameter(FhirConstants.HAS_SEARCH_HANDLER, getHasAndListParam());
}
}
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.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import lombok.Builder;
Expand Down Expand Up @@ -51,12 +52,14 @@ public class PatientSearchParams extends BaseResourceSearchParams {

private StringAndListParam country;

private HasAndListParam hasAndListParam;

@Builder
public PatientSearchParams(StringAndListParam name, StringAndListParam given, StringAndListParam family,
TokenAndListParam identifier, TokenAndListParam gender, DateRangeParam birthDate, DateRangeParam deathDate,
TokenAndListParam deceased, StringAndListParam city, StringAndListParam state, StringAndListParam postalCode,
StringAndListParam country, TokenAndListParam id, DateRangeParam lastUpdated, SortSpec sort,
HashSet<Include> revIncludes) {
StringAndListParam country, TokenAndListParam id, HasAndListParam hasAndListParam, DateRangeParam lastUpdated,
SortSpec sort, HashSet<Include> revIncludes) {

super(id, lastUpdated, sort, null, revIncludes);

Expand All @@ -72,6 +75,7 @@ public PatientSearchParams(StringAndListParam name, StringAndListParam given, St
this.state = state;
this.postalCode = postalCode;
this.country = country;
this.hasAndListParam = hasAndListParam;
}

@Override
Expand All @@ -88,6 +92,7 @@ public SearchParameterMap toSearchParameterMap() {
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.CITY_PROPERTY, getCity())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.STATE_PROPERTY, getState())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.POSTAL_CODE_PROPERTY, getPostalCode())
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.COUNTRY_PROPERTY, getCountry());
.addParameter(FhirConstants.ADDRESS_SEARCH_HANDLER, FhirConstants.COUNTRY_PROPERTY, getCountry())
.addParameter(FhirConstants.HAS_SEARCH_HANDLER, getHasAndListParam());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import ca.uhn.fhir.rest.api.SortSpec;
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.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
Expand All @@ -53,6 +54,7 @@
import org.hl7.fhir.dstu3.model.ProcedureRequest;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.ServiceRequest;
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.api.FhirPatientService;
import org.openmrs.module.fhir2.api.annotations.R3Provider;
import org.openmrs.module.fhir2.api.search.SearchQueryBundleProviderR3Wrapper;
Expand Down Expand Up @@ -128,6 +130,7 @@ public IBundleProvider searchPatients(@OptionalParam(name = Patient.SP_NAME) Str
@OptionalParam(name = Patient.SP_ADDRESS_POSTALCODE) StringAndListParam postalCode,
@OptionalParam(name = Patient.SP_ADDRESS_COUNTRY) StringAndListParam country,
@OptionalParam(name = Patient.SP_RES_ID) TokenAndListParam id,
@OptionalParam(name = FhirConstants.HAS_SEARCH_HANDLER) HasAndListParam hasAndListParam,
@OptionalParam(name = "_lastUpdated") DateRangeParam lastUpdated, @Sort SortSpec sort,
@IncludeParam(reverse = true, allow = { "Observation:" + Observation.SP_PATIENT,
"AllergyIntolerance:" + AllergyIntolerance.SP_PATIENT, "DiagnosticReport:" + DiagnosticReport.SP_PATIENT,
Expand All @@ -138,9 +141,9 @@ public IBundleProvider searchPatients(@OptionalParam(name = Patient.SP_NAME) Str
revIncludes = null;
}

return new SearchQueryBundleProviderR3Wrapper(
patientService.searchForPatients(new PatientSearchParams(name, given, family, identifier, gender, birthDate,
deathDate, deceased, city, state, postalCode, country, id, lastUpdated, sort, revIncludes)));
return new SearchQueryBundleProviderR3Wrapper(patientService
.searchForPatients(new PatientSearchParams(name, given, family, identifier, gender, birthDate, deathDate,
deceased, city, state, postalCode, country, id, hasAndListParam, lastUpdated, sort, revIncludes)));
}

@Search(queryName = "openmrsPatients")
Expand All @@ -155,6 +158,7 @@ public IBundleProvider searchOpenmrsPatients(@OptionalParam(name = "q") StringAn
@OptionalParam(name = org.hl7.fhir.r4.model.Patient.SP_ADDRESS_POSTALCODE) StringAndListParam postalCode,
@OptionalParam(name = org.hl7.fhir.r4.model.Patient.SP_ADDRESS_COUNTRY) StringAndListParam country,
@OptionalParam(name = org.hl7.fhir.r4.model.Patient.SP_RES_ID) TokenAndListParam id,
@OptionalParam(name = FhirConstants.HAS_SEARCH_HANDLER) HasAndListParam hasAndListParam,
@OptionalParam(name = "_lastUpdated") DateRangeParam lastUpdated, @Sort SortSpec sort,
@IncludeParam(reverse = true, allow = { "Observation:" + org.hl7.fhir.r4.model.Observation.SP_PATIENT,
"AllergyIntolerance:" + org.hl7.fhir.r4.model.AllergyIntolerance.SP_PATIENT,
Expand All @@ -169,7 +173,7 @@ public IBundleProvider searchOpenmrsPatients(@OptionalParam(name = "q") StringAn

return new SearchQueryBundleProviderR3Wrapper(
patientService.searchForPatients(new OpenmrsPatientSearchParams(query, gender, birthDate, deathDate,
deceased, city, state, postalCode, country, id, lastUpdated, sort, revIncludes)));
deceased, city, state, postalCode, country, id, hasAndListParam, lastUpdated, sort, revIncludes)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenParam;
Expand All @@ -54,6 +55,7 @@
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.ServiceRequest;
import org.openmrs.module.fhir2.FhirConstants;
import org.openmrs.module.fhir2.api.FhirPatientService;
import org.openmrs.module.fhir2.api.annotations.R4Provider;
import org.openmrs.module.fhir2.api.search.param.OpenmrsPatientSearchParams;
Expand Down Expand Up @@ -136,6 +138,7 @@ public IBundleProvider searchPatients(@OptionalParam(name = Patient.SP_NAME) Str
@OptionalParam(name = Patient.SP_ADDRESS_POSTALCODE) StringAndListParam postalCode,
@OptionalParam(name = Patient.SP_ADDRESS_COUNTRY) StringAndListParam country,
@OptionalParam(name = Patient.SP_RES_ID) TokenAndListParam id,
@OptionalParam(name = FhirConstants.HAS_SEARCH_HANDLER) HasAndListParam hasAndListParam,
@OptionalParam(name = "_lastUpdated") DateRangeParam lastUpdated, @Sort SortSpec sort,
@IncludeParam(reverse = true, allow = { "Observation:" + Observation.SP_PATIENT,
"AllergyIntolerance:" + AllergyIntolerance.SP_PATIENT, "DiagnosticReport:" + DiagnosticReport.SP_PATIENT,
Expand All @@ -147,7 +150,7 @@ public IBundleProvider searchPatients(@OptionalParam(name = Patient.SP_NAME) Str
}

return patientService.searchForPatients(new PatientSearchParams(name, given, family, identifier, gender, birthDate,
deathDate, deceased, city, state, postalCode, country, id, lastUpdated, sort, revIncludes));
deathDate, deceased, city, state, postalCode, country, id, hasAndListParam, lastUpdated, sort, revIncludes));
}

@Search(queryName = "openmrsPatients")
Expand All @@ -162,6 +165,7 @@ public IBundleProvider searchOpenmrsPatients(@OptionalParam(name = "q") StringAn
@OptionalParam(name = Patient.SP_ADDRESS_POSTALCODE) StringAndListParam postalCode,
@OptionalParam(name = Patient.SP_ADDRESS_COUNTRY) StringAndListParam country,
@OptionalParam(name = Patient.SP_RES_ID) TokenAndListParam id,
@OptionalParam(name = FhirConstants.HAS_SEARCH_HANDLER) HasAndListParam hasAndListParam,
@OptionalParam(name = "_lastUpdated") DateRangeParam lastUpdated, @Sort SortSpec sort,
@IncludeParam(reverse = true, allow = { "Observation:" + Observation.SP_PATIENT,
"AllergyIntolerance:" + AllergyIntolerance.SP_PATIENT, "DiagnosticReport:" + DiagnosticReport.SP_PATIENT,
Expand All @@ -173,7 +177,7 @@ public IBundleProvider searchOpenmrsPatients(@OptionalParam(name = "q") StringAn
}

return patientService.searchForPatients(new OpenmrsPatientSearchParams(query, gender, birthDate, deathDate, deceased,
city, state, postalCode, country, id, lastUpdated, sort, revIncludes));
city, state, postalCode, country, id, hasAndListParam, lastUpdated, sort, revIncludes));
}

/**
Expand Down
Loading

0 comments on commit fa21503

Please sign in to comment.