From 7ee46a5fc18184acbcd6c9cbe7d38dbc402f540f Mon Sep 17 00:00:00 2001 From: Martina Duemcke Date: Thu, 24 May 2018 11:11:24 +0200 Subject: [PATCH] [BAH-460][Roni/Martina] Add api for search similar patient using PersonService and Lucene --- .../patient/PatientSearchParameters.java | 10 +++ .../patient/mapper/PatientResponseMapper.java | 13 ++-- .../module/bahmnicore/dao/PatientDao.java | 2 + .../bahmnicore/dao/impl/OrderDaoImpl.java | 5 +- .../bahmnicore/dao/impl/PatientDaoImpl.java | 72 +++++++++++++++---- .../matcher/EncounterSessionMatcher.java | 7 +- .../service/BahmniPatientService.java | 4 ++ .../impl/BahmniDiagnosisServiceImpl.java | 12 ++-- .../service/impl/BahmniObsServiceImpl.java | 35 ++++++--- .../impl/BahmniPatientServiceImpl.java | 9 +++ .../impl/DiseaseTemplateServiceImpl.java | 7 +- .../impl/PatientDocumentServiceImpl.java | 9 +-- .../impl/BahmniPatientDaoImplLuceneIT.java | 37 +++++++++- .../impl/BahmniPatientServiceImplTest.java | 24 ++++++- .../module/bahmnicore/util/PatientMother.java | 13 ++-- .../search/BahmniPatientSearchController.java | 22 ++++++ 16 files changed, 228 insertions(+), 53 deletions(-) diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/PatientSearchParameters.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/PatientSearchParameters.java index 496dc54c4c..222bc955cf 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/PatientSearchParameters.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/PatientSearchParameters.java @@ -9,6 +9,7 @@ public class PatientSearchParameters { private Boolean filterPatientsByLocation; private String identifier; private String name; + private String gender; private String addressFieldName; private String addressFieldValue; private Integer start; @@ -43,6 +44,7 @@ public PatientSearchParameters(RequestContext context) { } else { this.setAddressFieldName("city_village"); } + this.setGender(context.getParameter("gender")); this.setAddressFieldValue(context.getParameter("addressFieldValue")); Map parameterMap = context.getRequest().getParameterMap(); this.setAddressSearchResultFields((String[]) parameterMap.get("addressSearchResultsConfig")); @@ -71,6 +73,14 @@ public void setName(String name) { this.name = name; } + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + public String getAddressFieldName() { return addressFieldName; } diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/mapper/PatientResponseMapper.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/mapper/PatientResponseMapper.java index b5a24f279c..245fc625b4 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/mapper/PatientResponseMapper.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/contract/patient/mapper/PatientResponseMapper.java @@ -1,6 +1,5 @@ package org.bahmni.module.bahmnicore.contract.patient.mapper; -import java.util.Objects; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang3.StringUtils; import org.bahmni.module.bahmnicore.contract.patient.response.PatientResponse; @@ -17,11 +16,13 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import static java.util.Arrays.asList; + public class PatientResponseMapper { private PatientResponse patientResponse; private VisitService visitService; @@ -34,8 +35,8 @@ public PatientResponseMapper(VisitService visitService, BahmniVisitLocationServi } public PatientResponse map(Patient patient, String loginLocationUuid, String[] searchResultFields, String[] addressResultFields, Object programAttributeValue) { - List patientSearchResultFields = searchResultFields != null ? Arrays.asList(searchResultFields) : new ArrayList<>(); - List addressSearchResultFields = addressResultFields != null ? Arrays.asList(addressResultFields) : new ArrayList<>(); + List patientSearchResultFields = searchResultFields != null ? asList(searchResultFields) : new ArrayList<>(); + List addressSearchResultFields = addressResultFields != null ? asList(addressResultFields) : new ArrayList<>(); Integer visitLocationId = bahmniVisitLocationService.getVisitLocation(loginLocationUuid).getLocationId(); List activeVisitsByPatient = visitService.getActiveVisitsByPatient(patient); @@ -51,7 +52,9 @@ public PatientResponse map(Patient patient, String loginLocationUuid, String[] s patientResponse.setFamilyName(patient.getFamilyName()); patientResponse.setGender(patient.getGender()); PatientIdentifier primaryIdentifier = patient.getPatientIdentifier(); - patientResponse.setIdentifier(primaryIdentifier.getIdentifier()); + if(primaryIdentifier != null) { + patientResponse.setIdentifier(primaryIdentifier.getIdentifier()); + } patientResponse.setPatientProgramAttributeValue(programAttributeValue); mapExtraIdentifiers(patient, primaryIdentifier); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java index 0516349ff7..eca503486b 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/PatientDao.java @@ -19,6 +19,8 @@ List getPatientsUsingLuceneSearch(String identifier, String nam String programAttributeFieldName, String[] addressSearchResultFields, String[] patientSearchResultFields, String loginLocationUuid, Boolean filterPatientsByLocation, Boolean filterOnAllIdentifiers); + List getSimilarPatientsUsingLuceneSearch(String name, String gender, String loginLocationUuid, Integer length); + public Patient getPatient(String identifier); public List getPatients(String partialIdentifier, boolean shouldMatchExactPatientId); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/OrderDaoImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/OrderDaoImpl.java index 459f65d68f..d8aabaf148 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/OrderDaoImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/OrderDaoImpl.java @@ -31,7 +31,6 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -39,6 +38,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Arrays.asList; + @Component public class OrderDaoImpl implements OrderDao { private static final String ORDER_TEMPLATES_DIRECTORY = "ordertemplates"; @@ -364,7 +365,7 @@ public List getAllOrders(Patient patientByUuid, OrderType drugOrderTypeUu return getAllOrders(patientByUuid, drugOrderTypeUuid, null, null, encounters); } - return getAllOrders(patientByUuid, Arrays.asList(drugOrderTypeUuid), offset, limit); + return getAllOrders(patientByUuid, asList(drugOrderTypeUuid), offset, limit); } @Override diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java index f147768b4c..4b0dc4000c 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/PatientDaoImpl.java @@ -22,20 +22,26 @@ import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; +import org.openmrs.Person; +import org.openmrs.PersonName; import org.openmrs.RelationshipType; import org.openmrs.api.context.Context; +import org.openmrs.api.db.hibernate.HibernatePatientDAO; +import org.openmrs.api.db.hibernate.PersonLuceneQuery; +import org.openmrs.api.db.hibernate.search.LuceneQuery; import org.openmrs.module.bahmniemrapi.visitlocation.BahmniVisitLocationServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; + import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import static java.util.stream.Collectors.reducing; +import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; @Repository @@ -88,18 +94,60 @@ public List getPatientsUsingLuceneSearch(String identifier, Str List patientResponses = patientIdentifiers.stream() .map(patientIdentifier -> { Patient patient = patientIdentifier.getPatient(); - if(!uniquePatientIds.contains(patient.getPatientId())) { - PatientResponse patientResponse = patientResponseMapper.map(patient, loginLocationUuid, patientSearchResultFields, addressSearchResultFields, - programAttributes.get(patient.getPatientId())); - uniquePatientIds.add(patient.getPatientId()); - return patientResponse; - }else - return null; + return toPatientResponse(patientResponseMapper, patient, loginLocationUuid, addressSearchResultFields, patientSearchResultFields, programAttributes, uniquePatientIds); }).filter(Objects::nonNull) .collect(toList()); return patientResponses; } + @Override + public List getSimilarPatientsUsingLuceneSearch(String name, String gender, String loginLocationUuid, Integer length) { + PatientResponseMapper patientResponseMapper = new PatientResponseMapper(Context.getVisitService(),new BahmniVisitLocationServiceImpl(Context.getLocationService())); + List patients = getPatientsByNameAndGender(name, gender, length); + List patientResponses = patients.stream() + .map(patient -> {return patientResponseMapper.map(patient, loginLocationUuid, null, null,null);}).filter(Objects::nonNull) + .collect(toList()); + return patientResponses; + } + + private PatientResponse toPatientResponse(PatientResponseMapper patientResponseMapper, Patient patient, String loginLocationUuid, String[] addressSearchResultFields, String[] patientSearchResultFields, Map programAttributes, Set uniquePatientIds) { + if(!uniquePatientIds.contains(patient.getPatientId())) { + PatientResponse patientResponse = patientResponseMapper.map(patient, loginLocationUuid, patientSearchResultFields, addressSearchResultFields, + programAttributes.get(patient.getPatientId())); + uniquePatientIds.add(patient.getPatientId()); + return patientResponse; + } else { + return null; + } + } + + private List getPatientsByNameAndGender(String name, String gender, Integer length) { + HibernatePatientDAO patientDAO = new HibernatePatientDAO(); + patientDAO.setSessionFactory(sessionFactory); + List patients = new ArrayList(); + String query = LuceneQuery.escapeQuery(name); + PersonLuceneQuery personLuceneQuery = new PersonLuceneQuery(sessionFactory); + LuceneQuery nameQuery = personLuceneQuery.getPatientNameQueryWithOrParser(query, false); + List persons = nameQuery.list().stream() + .filter( + personName -> + personName.getPreferred() + && checkGender(personName.getPerson(), gender) + ).collect(toList()); + persons = persons.subList(0, Math.min(length, persons.size())); + persons.forEach(person -> patients.add(new Patient(person.getPerson()))); + return patients; + } + + + private Boolean checkGender(Person person, String gender) { + if(gender != null && !gender.isEmpty()){ + return gender.equals(person.getGender()); + } else { + return true; + } + } + private List getPatientIdentifiers(String identifier, Boolean filterOnAllIdentifiers, Integer offset, Integer length) { FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession()); QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(PatientIdentifier.class).get(); @@ -179,7 +227,7 @@ private boolean isValidAddressField(String addressFieldName) { "LOWER (TABLE_NAME) ='person_address' and LOWER(COLUMN_NAME) IN " + "( :personAddressField)"; Query queryToGetAddressFields = sessionFactory.getCurrentSession().createSQLQuery(query); - queryToGetAddressFields.setParameterList("personAddressField", Arrays.asList(addressFieldName.toLowerCase())); + queryToGetAddressFields.setParameterList("personAddressField", asList(addressFieldName.toLowerCase())); List list = queryToGetAddressFields.list(); return list.size() > 0; } @@ -201,7 +249,7 @@ private List getPersonAttributeIds(String[] patientAttributes) { String query = "select person_attribute_type_id from person_attribute_type where name in " + "( :personAttributeTypeNames)"; Query queryToGetAttributeIds = sessionFactory.getCurrentSession().createSQLQuery(query); - queryToGetAttributeIds.setParameterList("personAttributeTypeNames", Arrays.asList(patientAttributes)); + queryToGetAttributeIds.setParameterList("personAttributeTypeNames", asList(patientAttributes)); List list = queryToGetAttributeIds.list(); return (List) list; } @@ -229,7 +277,7 @@ public List getPatients(String patientIdentifier, boolean shouldMatchEx } Patient patient = getPatient(patientIdentifier); - List result = (patient == null ? new ArrayList() : Arrays.asList(patient)); + List result = (patient == null ? new ArrayList() : asList(patient)); return result; } diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/matcher/EncounterSessionMatcher.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/matcher/EncounterSessionMatcher.java index d35653526a..64c90167ed 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/matcher/EncounterSessionMatcher.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/matcher/EncounterSessionMatcher.java @@ -22,13 +22,14 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; +import static java.util.Arrays.asList; + @Component public class EncounterSessionMatcher implements BaseEncounterMatcher { @@ -79,7 +80,7 @@ private Encounter findMatchingEncounter(Visit visit, EncounterParameters encount if (visit.getId() == null) { // To handle new Visit scenario where visit will not be persisted in DB and we get a visit obj (Called from emr-api). return null; } - visits = Arrays.asList(visit); + visits = asList(visit); } if (null == encounterParameters.getEncounterDateTime()) { @@ -90,7 +91,7 @@ private Encounter findMatchingEncounter(Visit visit, EncounterParameters encount Collection encounters = this.encounterService.getEncounters(encounterParameters.getPatient(), null, getSearchStartDate(encounterParameters.getEncounterDateTime()), encounterParameters.getEncounterDateTime(), new ArrayList
(), - Arrays.asList(encounterParameters.getEncounterType()), + asList(encounterParameters.getEncounterType()), encounterParameters.getProviders(), null, visits, false); Map context = encounterParameters.getContext(); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java index 5a3905ba5f..eb598e582b 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/BahmniPatientService.java @@ -1,9 +1,11 @@ package org.bahmni.module.bahmnicore.service; import org.bahmni.module.bahmnicore.contract.patient.PatientSearchParameters; +import org.bahmni.module.bahmnicore.contract.patient.mapper.PatientResponseMapper; import org.bahmni.module.bahmnicore.contract.patient.response.PatientConfigResponse; import org.bahmni.module.bahmnicore.contract.patient.response.PatientResponse; import org.openmrs.Patient; +import org.openmrs.Person; import org.openmrs.RelationshipType; import java.util.List; @@ -15,6 +17,8 @@ public interface BahmniPatientService { List luceneSearch(PatientSearchParameters searchParameters); + List searchSimilarPatients(PatientSearchParameters searchParameters); + public List get(String partialIdentifier, boolean shouldMatchExactPatientId); public List getByAIsToB(String aIsToB); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniDiagnosisServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniDiagnosisServiceImpl.java index 6028d3ebbf..82edbd7efd 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniDiagnosisServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniDiagnosisServiceImpl.java @@ -31,6 +31,8 @@ import java.util.Iterator; import java.util.List; +import static java.util.Arrays.*; + @Component public class BahmniDiagnosisServiceImpl implements BahmniDiagnosisService { private EncounterService encounterService; @@ -80,8 +82,8 @@ private void voidAllDiagnosisWithSameInitialDiagnosis(String initialVisitDiagnos private List getDiagnosisByPatient(Patient patient, Visit visit) { List diagnoses = new ArrayList(); - List observations = obsService.getObservations(Arrays.asList((Person) patient), new ArrayList<>(visit.getEncounters()), - Arrays.asList(bahmniDiagnosisMetadata.getDiagnosisSetConcept()), null, null, null, Arrays.asList("obsDatetime"), + List observations = obsService.getObservations(asList((Person) patient), new ArrayList<>(visit.getEncounters()), + asList(bahmniDiagnosisMetadata.getDiagnosisSetConcept()), null, null, null, asList("obsDatetime"), null, null, null, null, false); Collection nonDiagnosisConcepts = emrApiProperties.getSuppressedDiagnosisConcepts(); @@ -150,9 +152,9 @@ public List getBahmniDiagnosisByPatientAndVisit(String p private Obs getLatestObsGroupBasedOnAnyDiagnosis(Diagnosis diagnosis, Concept bahmniDiagnosisRevised) { String initialDiagnosisUuid = bahmniDiagnosisMetadata.findInitialDiagnosisUuid(diagnosis.getExistingObs()); - List observations = obsService.getObservations(Arrays.asList(diagnosis.getExistingObs().getPerson()), null, - Arrays.asList(bahmniDiagnosisRevised), - Arrays.asList(conceptService.getFalseConcept()), null, null, null, + List observations = obsService.getObservations(asList(diagnosis.getExistingObs().getPerson()), null, + asList(bahmniDiagnosisRevised), + asList(conceptService.getFalseConcept()), null, null, null, null, null, null, null, false); for (Obs obs : observations) { diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java index f96519f607..8f9e08697d 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java @@ -23,7 +23,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import static java.util.Arrays.asList; @Service public class BahmniObsServiceImpl implements BahmniObsService { @@ -146,7 +159,7 @@ public Collection getLatest(String patientUuid, Collection(); for (Concept concept : concepts) { - List observations = obsDao.getObsByPatientAndVisit(patientUuid, Arrays.asList(concept.getName().getName()), + List observations = obsDao.getObsByPatientAndVisit(patientUuid, asList(concept.getName().getName()), visitDao.getVisitIdsFor(patientUuid, numberOfVisits), -1, ObsDaoImpl.OrderBy.DESC, obsIgnoreList, filterOutOrderObs, order, null, null); if (CollectionUtils.isNotEmpty(observations)) { latestObs.addAll(filterIgnoredObs(obsIgnoreList, getAllLatestObsForAConcept(observations))); @@ -160,8 +173,8 @@ public Collection getLatest(String patientUuid, Collection getLatestObsByVisit(Visit visit, Collection concepts, List obsIgnoreList, Boolean filterOutOrderObs) { List latestObs = new ArrayList<>(); for (Concept concept : concepts) { - latestObs.addAll(obsDao.getObsByPatientAndVisit(visit.getPatient().getUuid(), Arrays.asList(concept.getName().getName()), - Arrays.asList(visit.getVisitId()), 1, ObsDaoImpl.OrderBy.DESC, obsIgnoreList, filterOutOrderObs, null, null, null)); + latestObs.addAll(obsDao.getObsByPatientAndVisit(visit.getPatient().getUuid(), asList(concept.getName().getName()), + asList(visit.getVisitId()), 1, ObsDaoImpl.OrderBy.DESC, obsIgnoreList, filterOutOrderObs, null, null, null)); } return omrsObsToBahmniObsMapper.map(filterIgnoredObs(obsIgnoreList,latestObs), concepts); @@ -172,7 +185,7 @@ public Collection getInitial(String patientUuid, Collection obsIgnoreList, Boolean filterOutOrderObs, Order order) { List latestObs = new ArrayList<>(); for (Concept concept : conceptNames) { - latestObs.addAll(obsDao.getObsByPatientAndVisit(patientUuid, Arrays.asList(concept.getName().getName()), + latestObs.addAll(obsDao.getObsByPatientAndVisit(patientUuid, asList(concept.getName().getName()), visitDao.getVisitIdsFor(patientUuid, numberOfVisits), 1, ObsDaoImpl.OrderBy.ASC, obsIgnoreList, filterOutOrderObs, order, null, null)); } @@ -183,8 +196,8 @@ public Collection getInitial(String patientUuid, Collection getInitialObsByVisit(Visit visit, List concepts, List obsIgnoreList, Boolean filterObsWithOrders) { List latestObs = new ArrayList<>(); for (Concept concept : concepts) { - latestObs.addAll(obsDao.getObsByPatientAndVisit(visit.getPatient().getUuid(), Arrays.asList(concept.getName().getName()), - Arrays.asList(visit.getVisitId()), 1, ObsDaoImpl.OrderBy.ASC, obsIgnoreList, filterObsWithOrders, null, null, null)); + latestObs.addAll(obsDao.getObsByPatientAndVisit(visit.getPatient().getUuid(), asList(concept.getName().getName()), + asList(visit.getVisitId()), 1, ObsDaoImpl.OrderBy.ASC, obsIgnoreList, filterObsWithOrders, null, null, null)); } Collection map = omrsObsToBahmniObsMapper.map(filterIgnoredObs(obsIgnoreList,latestObs), concepts); @@ -199,7 +212,7 @@ public List getNumericConceptsForPerson(String personUUID) { @Override public Collection getLatestObsForConceptSetByVisit(String patientUuid, String conceptName, Integer visitId) { List obs = withUniqueConcepts(filterByRootConcept(obsDao.getLatestObsForConceptSetByVisit(patientUuid, conceptName, visitId), conceptName)); - return omrsObsToBahmniObsMapper.map(obs, Arrays.asList(getConceptByName(conceptName))); + return omrsObsToBahmniObsMapper.map(obs, asList(getConceptByName(conceptName))); } @Override @@ -225,7 +238,7 @@ public Collection getObservationsForPatientProgram(String pat if (conceptNames == null) return new ArrayList<>(); for (String conceptName : conceptNames) { - observations.addAll(obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, Arrays.asList(conceptName), null, ObsDaoImpl.OrderBy.DESC, null, null)); + observations.addAll(obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, asList(conceptName), null, ObsDaoImpl.OrderBy.DESC, null, null)); } return omrsObsToBahmniObsMapper.map(filterIgnoredObs(obsIgnoreList,observations), getConceptsByName(conceptNames)); @@ -237,7 +250,7 @@ public Collection getLatestObservationsForPatientProgram(Stri if (conceptNames == null) return new ArrayList<>(); for (String conceptName : conceptNames) { - List obsByPatientProgramUuidAndConceptName = obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, Arrays.asList(conceptName), null, OrderBy.DESC, null, null); + List obsByPatientProgramUuidAndConceptName = obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, asList(conceptName), null, OrderBy.DESC, null, null); List obsList = getAllLatestObsForAConcept(obsByPatientProgramUuidAndConceptName); if (CollectionUtils.isNotEmpty(obsList)) { observations.addAll(obsList); @@ -253,7 +266,7 @@ public Collection getInitialObservationsForPatientProgram(Str if (conceptNames == null) return new ArrayList<>(); for (String conceptName : conceptNames) { - observations.addAll(obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, Arrays.asList(conceptName), 1, ObsDaoImpl.OrderBy.ASC, null, null)); + observations.addAll(obsDao.getObsByPatientProgramUuidAndConceptNames(patientProgramUuid, asList(conceptName), 1, ObsDaoImpl.OrderBy.ASC, null, null)); } return omrsObsToBahmniObsMapper.map(filterIgnoredObs(obsIgnoreList,observations), getConceptsByName(conceptNames)); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java index 0c50fae0a8..2256f31fda 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImpl.java @@ -20,6 +20,7 @@ @Service @Lazy //to get rid of cyclic dependencies public class BahmniPatientServiceImpl implements BahmniPatientService { + private static final int SIMILAR_PATIENT_RESULT_LENGTH = 5; private PersonService personService; private ConceptService conceptService; private PatientDao patientDao; @@ -83,6 +84,14 @@ public List luceneSearch(PatientSearchParameters searchParamete searchParameters.getFilterPatientsByLocation(), searchParameters.getFilterOnAllIdentifiers()); } + @Override + public List searchSimilarPatients(PatientSearchParameters searchParameters) { + return patientDao.getSimilarPatientsUsingLuceneSearch(searchParameters.getName(), + searchParameters.getGender(), + searchParameters.getLoginLocationUuid(), + SIMILAR_PATIENT_RESULT_LENGTH); + } + @Override public List get(String partialIdentifier, boolean shouldMatchExactPatientId) { return patientDao.getPatients(partialIdentifier, shouldMatchExactPatientId); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/DiseaseTemplateServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/DiseaseTemplateServiceImpl.java index 3d8cbcf405..60de992d06 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/DiseaseTemplateServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/DiseaseTemplateServiceImpl.java @@ -27,12 +27,13 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; +import static java.util.Arrays.asList; + @Service public class DiseaseTemplateServiceImpl implements DiseaseTemplateService { @@ -98,7 +99,7 @@ public DiseaseTemplate diseaseTemplateFor(DiseaseTemplatesConfig diseaseTemplate List observationTemplateConcepts = diseaseTemplateConcept.getSetMembers(); for (Concept concept : observationTemplateConcepts) { Collection observations = bahmniObsService.observationsFor(diseaseTemplatesConfig.getPatientUuid(), - Arrays.asList(concept), null, null, false, null, diseaseTemplatesConfig.getStartDate(), diseaseTemplatesConfig.getEndDate()); + asList(concept), null, null, false, null, diseaseTemplatesConfig.getStartDate(), diseaseTemplatesConfig.getEndDate()); List observationTemplates = observationTemplateMapper.map(observations, concept); diseaseTemplate.addObservationTemplates(observationTemplates); } @@ -179,7 +180,7 @@ private List createObservationTemplates(String patientUuid, if (null != diseaseTemplateConcept && CollectionUtils.isNotEmpty(diseaseTemplateConcept.getSetMembers())) { for (Concept concept : diseaseTemplateConcept.getSetMembers()) { if (concept.getConceptClass().getName().equals(CASE_INTAKE_CONCEPT_CLASS) && CollectionUtils.isNotEmpty(visits)) { - Collection observations = bahmniObsService.observationsFor(patientUuid, Arrays.asList(concept), null, null, false, null, startDate, endDate); + Collection observations = bahmniObsService.observationsFor(patientUuid, asList(concept), null, null, false, null, startDate, endDate); observationTemplates.addAll(observationTemplateMapper.map(observations, concept)); } else { Visit latestVisit = bahmniVisitService.getLatestVisit(patientUuid, concept.getName().getName()); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/PatientDocumentServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/PatientDocumentServiceImpl.java index f4e2cf53a8..5600778966 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/PatientDocumentServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/PatientDocumentServiceImpl.java @@ -12,8 +12,6 @@ import org.bahmni.module.bahmnicore.service.PatientDocumentService; import org.bahmni.module.bahmnicore.service.ThumbnailGenerator; import org.imgscalr.Scalr; -import org.jcodec.common.model.Picture; -import org.jcodec.scale.AWTUtil; import org.openmrs.module.webservices.rest.web.RestUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -24,9 +22,12 @@ import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java index c02cfc7bc0..29dc45426d 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/dao/impl/BahmniPatientDaoImplLuceneIT.java @@ -7,7 +7,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.openmrs.Patient; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; @@ -213,4 +212,40 @@ public void shouldNotReturnDuplicatePatientsEvenIfTwoIdentifiersMatches() { assertTrue(patient.getExtraIdentifiers().contains("200006")); } + @Test + public void shouldSearchSimilarPatientByPatientName() { + List patients = patientDao.getSimilarPatientsUsingLuceneSearch("Peet", "", "c36006e5-9fbb-4f20-866b-0ece245615a1", 5); + assertEquals(2, patients.size()); + + PatientResponse patient1 = patients.get(0); + PatientResponse patient2 = patients.get(1); + assertEquals(patient1.getGivenName(), "Horatio"); + assertEquals(patient1.getMiddleName(), "Peeter"); + assertEquals(patient1.getFamilyName(), "Sinha"); + assertEquals(patient2.getGivenName(), "John"); + assertEquals(patient2.getMiddleName(), "Peeter"); + assertEquals(patient2.getFamilyName(), "Sinha"); + } + + @Test + public void shouldSearchSimilarPatientByPatientNameAndUseLimitResult() { + List patients = patientDao.getSimilarPatientsUsingLuceneSearch("Peet", "", "c36006e5-9fbb-4f20-866b-0ece245615a1", 1); + assertEquals("Should limit number of results",1, patients.size()); + PatientResponse patient1 = patients.get(0); + + assertEquals(patient1.getGivenName(), "Horatio"); + assertEquals(patient1.getMiddleName(), "Peeter"); + assertEquals(patient1.getFamilyName(), "Sinha"); + } + + @Test + public void shouldSearchSimilarPatientByPatientNameAndGender() { + List patients = patientDao.getSimilarPatientsUsingLuceneSearch("Peet", "F", "c36006e5-9fbb-4f20-866b-0ece245615a1", 5); + PatientResponse patient1 = patients.get(0); + + assertEquals(1, patients.size()); + assertEquals(patient1.getGivenName(), "John"); + assertEquals(patient1.getMiddleName(), "Peeter"); + assertEquals(patient1.getFamilyName(), "Sinha"); + } } diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java index 5c77844fdb..3bff7677c5 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniPatientServiceImplTest.java @@ -1,5 +1,6 @@ package org.bahmni.module.bahmnicore.service.impl; +import org.bahmni.module.bahmnicore.contract.patient.PatientSearchParameters; import org.bahmni.module.bahmnicore.contract.patient.response.PatientConfigResponse; import org.bahmni.module.bahmnicore.dao.PatientDao; import org.junit.Before; @@ -9,12 +10,16 @@ import org.openmrs.PersonAttributeType; import org.openmrs.api.ConceptService; import org.openmrs.api.PersonService; +import org.openmrs.module.webservices.rest.web.RequestContext; +import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static junit.framework.Assert.assertEquals; -import static org.mockito.Mockito.anyInt; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -25,6 +30,8 @@ public class BahmniPatientServiceImplTest { @Mock private ConceptService conceptService; @Mock + RequestContext requestContext; + @Mock private PatientDao patientDao; private BahmniPatientServiceImpl bahmniPatientService; @@ -67,4 +74,19 @@ public void shouldGetPatientByPartialIdentifier() throws Exception { bahmniPatientService.get("partial_identifier", shouldMatchExactPatientId); verify(patientDao).getPatients("partial_identifier", shouldMatchExactPatientId); } + + @Test + public void shouldCallgetSimilarPatientsUsingLuceneSearch() { + HttpServletRequest request = mock(HttpServletRequest.class); + when(requestContext.getRequest()).thenReturn(request); + when(request.getParameterMap()).thenReturn(new HashMap<>()); + + PatientSearchParameters patientSearchParameters = new PatientSearchParameters(requestContext); + patientSearchParameters.setName("John"); + patientSearchParameters.setGender("M"); + patientSearchParameters.setLoginLocationUuid("someUUid"); + + bahmniPatientService.searchSimilarPatients(patientSearchParameters); + verify(patientDao).getSimilarPatientsUsingLuceneSearch("John", "M", "someUUid", 5); + } } diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/util/PatientMother.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/util/PatientMother.java index 1c84b09cb3..a0ee4c5946 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/util/PatientMother.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/util/PatientMother.java @@ -9,10 +9,11 @@ import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Date; import java.util.HashSet; +import static java.util.Arrays.asList; + public class PatientMother { private String patientIdentifier; @@ -50,10 +51,10 @@ public Patient build() { patient.addIdentifier(new PatientIdentifier(patientIdentifier, null, null)); patient.addName(nameMother.build()); patient.setPersonDateCreated(this.dateCreated); - patient.setAddresses(new HashSet<>(Arrays.asList(addressMother.build()))); + patient.setAddresses(new HashSet<>(asList(addressMother.build()))); PersonAttributeType personAttributeType = new PersonAttributeType(); personAttributeType.setName("healthCenter"); - patient.setAttributes(new HashSet<>(Arrays.asList(new PersonAttribute(personAttributeType, "Ganiyari")))); + patient.setAttributes(new HashSet<>(asList(new PersonAttribute(personAttributeType, "Ganiyari")))); return patient; } @@ -62,12 +63,12 @@ public SimpleObject buildSimpleObject() { SimpleObject simpleObject = new SimpleObject().add("birthdate", "01-01-2012") .add("age", new SimpleObject().add("years", 21).add("months", 1).add("days", 3)) .add("gender", "M") - .add("attributes", Arrays.asList(new SimpleObject() + .add("attributes", asList(new SimpleObject() .add("attributeType", "b3b6d540-a32e-44c7-91b3-292d97667518") .add("value", "someCaste"))) - .add("addresses", Arrays.asList(addressMother.getSimpleObjectForAddress())) + .add("addresses", asList(addressMother.getSimpleObjectForAddress())) .add("centerID", "Ganiyari") - .add("names", Arrays.asList(nameMother.getSimpleObjectForName())) + .add("names", asList(nameMother.getSimpleObjectForName())) .add("dateOfRegistration", dateCreatedString) .add("identifier", patientIdentifier); if (balance != null) { diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java index a3d71c703a..6e5b0ba76f 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/search/BahmniPatientSearchController.java @@ -1,8 +1,14 @@ package org.bahmni.module.bahmnicore.web.v1_0.controller.search; import org.bahmni.module.bahmnicore.contract.patient.PatientSearchParameters; +import org.bahmni.module.bahmnicore.contract.patient.mapper.PatientResponseMapper; import org.bahmni.module.bahmnicore.contract.patient.response.PatientResponse; import org.bahmni.module.bahmnicore.service.BahmniPatientService; +import org.openmrs.Patient; +import org.openmrs.PatientIdentifier; +import org.openmrs.Person; +import org.openmrs.api.context.Context; +import org.openmrs.module.bahmniemrapi.visitlocation.BahmniVisitLocationServiceImpl; import org.openmrs.module.webservices.rest.web.RequestContext; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.RestUtil; @@ -15,6 +21,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; @@ -66,4 +73,19 @@ public ResponseEntity> luceneSearch(HttpServletReq return new ResponseEntity(RestUtil.wrapErrorResponse(e, e.getMessage()), HttpStatus.BAD_REQUEST); } } + + @RequestMapping(value="similar", method = RequestMethod.GET) + @ResponseBody + public ResponseEntity> searchSimilarPerson(HttpServletRequest request, + HttpServletResponse response) throws ResponseException{ + RequestContext requestContext = RestUtil.getRequestContext(request, response); + PatientSearchParameters searchParameters = new PatientSearchParameters(requestContext); + try { + List patients = bahmniPatientService.searchSimilarPatients(searchParameters); + AlreadyPaged alreadyPaged = new AlreadyPaged(requestContext, patients, false); + return new ResponseEntity(alreadyPaged, HttpStatus.OK); + }catch (IllegalArgumentException e){ + return new ResponseEntity(RestUtil.wrapErrorResponse(e, e.getMessage()), HttpStatus.BAD_REQUEST); + } + } }