Changes per code review.
This commit is contained in:
parent
5cc77b78d4
commit
a4811f1508
|
@ -29,6 +29,15 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public interface IFhirResourceDaoObservation<T extends IBaseResource> extends IFhirResourceDao<T> {
|
public interface IFhirResourceDaoObservation<T extends IBaseResource> extends IFhirResourceDao<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a BundleProvider which can be used to implement the $lastn operation.
|
||||||
|
* @param paramMap Parameters supported include Observation.subject, Observation.patient, Observation.code,
|
||||||
|
* Observation.category, and max (the maximum number of Observations to return per specified subjects/patients,
|
||||||
|
* codes, and/or categories.
|
||||||
|
* @param theRequestDetails
|
||||||
|
* @param theServletResponse
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
IBundleProvider observationsLastN(SearchParameterMap paramMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse);
|
IBundleProvider observationsLastN(SearchParameterMap paramMap, RequestDetails theRequestDetails, HttpServletResponse theServletResponse);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,25 +22,50 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoObservation;
|
||||||
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
import ca.uhn.fhir.rest.api.server.*;
|
import ca.uhn.fhir.rest.api.server.*;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
public abstract class BaseHapiFhirResourceDaoObservation<T extends IBaseResource> extends BaseHapiFhirResourceDao<T> implements IFhirResourceDaoObservation<T> {
|
public abstract class BaseHapiFhirResourceDaoObservation<T extends IBaseResource> extends BaseHapiFhirResourceDao<T> implements IFhirResourceDaoObservation<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ObservationLastNIndexPersistSvc myObservationLastNIndexPersistSvc;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
||||||
|
|
||||||
|
protected ResourceTable updateObservationEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity,
|
||||||
|
Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||||
|
TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion,
|
||||||
|
theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
|
if (!retVal.isUnchangedInCurrentOperation()) {
|
||||||
|
if (retVal.getDeleted() == null) {
|
||||||
|
// Update indexes here for LastN operation.
|
||||||
|
myObservationLastNIndexPersistSvc.indexObservation(theResource);
|
||||||
|
} else {
|
||||||
|
myObservationLastNIndexPersistSvc.deleteObservationIndex(theEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateSearchParamsForLastn(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails) {
|
protected void updateSearchParamsForLastn(SearchParameterMap theSearchParameterMap, RequestDetails theRequestDetails) {
|
||||||
if (!isPagingProviderDatabaseBacked(theRequestDetails)) {
|
if (!isPagingProviderDatabaseBacked(theRequestDetails)) {
|
||||||
theSearchParameterMap.setLoadSynchronous(true);
|
theSearchParameterMap.setLoadSynchronous(true);
|
||||||
|
|
|
@ -39,40 +39,46 @@ public class ObservationLastNIndexPersistSvc {
|
||||||
|
|
||||||
public void indexObservation(IBaseResource theResource) {
|
public void indexObservation(IBaseResource theResource) {
|
||||||
|
|
||||||
String subjectId = null;
|
|
||||||
List<IBase> subjectReferenceElement = mySearchParameterExtractor.extractValues("Observation.subject", theResource);
|
List<IBase> subjectReferenceElement = mySearchParameterExtractor.extractValues("Observation.subject", theResource);
|
||||||
if (subjectReferenceElement.size() == 1) {
|
String subjectId = subjectReferenceElement.stream()
|
||||||
PathAndRef subjectPathAndRef = mySearchParameterExtractor.extractReferenceLinkFromResource(subjectReferenceElement.get(0), "Observation.subject");
|
.map(refElement -> mySearchParameterExtractor.extractReferenceLinkFromResource(refElement, "Observation.subject"))
|
||||||
if (subjectPathAndRef != null) {
|
.filter(Objects::nonNull)
|
||||||
IBaseReference subjectReference = subjectPathAndRef.getRef();
|
.map(PathAndRef::getRef)
|
||||||
if (subjectReference != null) {
|
.filter(Objects::nonNull)
|
||||||
subjectId = subjectReference.getReferenceElement().getValue();
|
.map(subjectRef -> subjectRef.getReferenceElement().getValue())
|
||||||
}
|
.filter(Objects::nonNull)
|
||||||
}
|
.findFirst().orElse(null);
|
||||||
}
|
|
||||||
|
|
||||||
Date effectiveDtm = null;
|
Date effectiveDtm = null;
|
||||||
List<IBase> effectiveDateElement = mySearchParameterExtractor.extractValues("Observation.effective", theResource);
|
List<IBase> effectiveDateElement = mySearchParameterExtractor.extractValues("Observation.effective", theResource);
|
||||||
if (effectiveDateElement.size() == 1) {
|
if (effectiveDateElement.size() > 0) {
|
||||||
effectiveDtm = mySearchParameterExtractor.extractDateFromResource(effectiveDateElement.get(0), "Observation.effective");
|
effectiveDtm = mySearchParameterExtractor.extractDateFromResource(effectiveDateElement.get(0), "Observation.effective");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build CodeableConcept entity for Observation.Code.
|
|
||||||
List<IBase> observationCodeCodeableConcepts = mySearchParameterExtractor.extractValues("Observation.code", theResource);
|
List<IBase> observationCodeCodeableConcepts = mySearchParameterExtractor.extractValues("Observation.code", theResource);
|
||||||
|
|
||||||
|
// Only index for lastn if Observation has a code
|
||||||
// Only index for lastn if Observation has a subject, effective date/time and code
|
if (observationCodeCodeableConcepts.size() == 0) {
|
||||||
if (subjectId == null || effectiveDtm == null || observationCodeCodeableConcepts.size() == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<IBase> observationCategoryCodeableConcepts = mySearchParameterExtractor.extractValues("Observation.category", theResource);
|
||||||
|
|
||||||
String resourcePID = theResource.getIdElement().getIdPart();
|
String resourcePID = theResource.getIdElement().getIdPart();
|
||||||
|
|
||||||
|
createOrUpdateIndexedObservation(resourcePID, effectiveDtm, subjectId, observationCodeCodeableConcepts, observationCategoryCodeableConcepts);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createOrUpdateIndexedObservation(String resourcePID, Date theEffectiveDtm, String theSubjectId,
|
||||||
|
List<IBase> theObservationCodeCodeableConcepts,
|
||||||
|
List<IBase> theObservationCategoryCodeableConcepts) {
|
||||||
|
|
||||||
// Determine if an index already exists for Observation:
|
// Determine if an index already exists for Observation:
|
||||||
boolean observationIndexUpdate = false;
|
boolean observationIndexUpdate = false;
|
||||||
ObservationIndexedSearchParamLastNEntity indexedObservation = null;
|
ObservationIndexedSearchParamLastNEntity indexedObservation = null;
|
||||||
if (resourcePID != null) {
|
if (resourcePID != null) {
|
||||||
indexedObservation = myResourceIndexedObservationLastNDao.findForIdentifier(resourcePID);
|
indexedObservation = myResourceIndexedObservationLastNDao.findByIdentifier(resourcePID);
|
||||||
}
|
}
|
||||||
if (indexedObservation == null) {
|
if (indexedObservation == null) {
|
||||||
indexedObservation = new ObservationIndexedSearchParamLastNEntity();
|
indexedObservation = new ObservationIndexedSearchParamLastNEntity();
|
||||||
|
@ -80,27 +86,46 @@ public class ObservationLastNIndexPersistSvc {
|
||||||
observationIndexUpdate = true;
|
observationIndexUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexedObservation.setEffectiveDtm(effectiveDtm);
|
indexedObservation.setEffectiveDtm(theEffectiveDtm);
|
||||||
indexedObservation.setIdentifier(resourcePID);
|
indexedObservation.setIdentifier(resourcePID);
|
||||||
indexedObservation.setSubject(subjectId);
|
indexedObservation.setSubject(theSubjectId);
|
||||||
|
|
||||||
|
addCodeToObservationIndex(theObservationCodeCodeableConcepts, indexedObservation);
|
||||||
|
|
||||||
|
addCategoriesToObservationIndex(theObservationCategoryCodeableConcepts, indexedObservation);
|
||||||
|
|
||||||
|
if (observationIndexUpdate) {
|
||||||
|
myEntityManager.merge(indexedObservation);
|
||||||
|
} else {
|
||||||
|
myEntityManager.persist(indexedObservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCodeToObservationIndex(List<IBase> theObservationCodeCodeableConcepts,
|
||||||
|
ObservationIndexedSearchParamLastNEntity theIndexedObservation) {
|
||||||
// Determine if a Normalized ID was created previously for Observation Code
|
// Determine if a Normalized ID was created previously for Observation Code
|
||||||
boolean observationCodeUpdate = false;
|
Optional<String> existingObservationCodeNormalizedId = getCodeCodeableConceptIdIfExists(theObservationCodeCodeableConcepts.get(0));
|
||||||
String observationCodeNormalizedId = getCodeCodeableConceptIdIfExists(observationCodeCodeableConcepts.get(0));
|
|
||||||
if (observationCodeNormalizedId != null) {
|
|
||||||
observationCodeUpdate = true;
|
|
||||||
}
|
|
||||||
// Generate a new a normalized ID if necessary
|
|
||||||
if (observationCodeNormalizedId == null) {
|
|
||||||
observationCodeNormalizedId = UUID.randomUUID().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create/update normalized Observation Code index record
|
// Create/update normalized Observation Code index record
|
||||||
ObservationIndexedCodeCodeableConceptEntity codeableConceptField = getCodeCodeableConcept(observationCodeCodeableConcepts.get(0), observationCodeNormalizedId);
|
ObservationIndexedCodeCodeableConceptEntity codeableConceptField =
|
||||||
|
getCodeCodeableConcept(theObservationCodeCodeableConcepts.get(0),
|
||||||
|
existingObservationCodeNormalizedId.orElse(UUID.randomUUID().toString()));
|
||||||
|
|
||||||
|
if (existingObservationCodeNormalizedId.isPresent()) {
|
||||||
|
myEntityManager.merge(codeableConceptField);
|
||||||
|
} else {
|
||||||
|
myEntityManager.persist(codeableConceptField);
|
||||||
|
}
|
||||||
|
|
||||||
|
theIndexedObservation.setObservationCode(codeableConceptField);
|
||||||
|
theIndexedObservation.setCodeNormalizedId(codeableConceptField.getCodeableConceptId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCategoriesToObservationIndex(List<IBase> observationCategoryCodeableConcepts,
|
||||||
|
ObservationIndexedSearchParamLastNEntity indexedObservation) {
|
||||||
// Build CodeableConcept entities for Observation.Category
|
// Build CodeableConcept entities for Observation.Category
|
||||||
List<IBase> observationCategoryCodeableConcepts = mySearchParameterExtractor.extractValues("Observation.category", theResource);
|
|
||||||
Set<ObservationIndexedCategoryCodeableConceptEntity> categoryCodeableConceptEntities = new HashSet<>();
|
Set<ObservationIndexedCategoryCodeableConceptEntity> categoryCodeableConceptEntities = new HashSet<>();
|
||||||
for (IBase categoryCodeableConcept : observationCategoryCodeableConcepts) {
|
for (IBase categoryCodeableConcept : observationCategoryCodeableConcepts) {
|
||||||
// Build CodeableConcept entities for each category CodeableConcept
|
// Build CodeableConcept entities for each category CodeableConcept
|
||||||
|
@ -108,20 +133,6 @@ public class ObservationLastNIndexPersistSvc {
|
||||||
}
|
}
|
||||||
indexedObservation.setCategoryCodeableConcepts(categoryCodeableConceptEntities);
|
indexedObservation.setCategoryCodeableConcepts(categoryCodeableConceptEntities);
|
||||||
|
|
||||||
if (observationCodeUpdate) {
|
|
||||||
myEntityManager.merge(codeableConceptField);
|
|
||||||
} else {
|
|
||||||
myEntityManager.persist(codeableConceptField);
|
|
||||||
}
|
|
||||||
|
|
||||||
indexedObservation.setObservationCode(codeableConceptField);
|
|
||||||
indexedObservation.setCodeNormalizedId(observationCodeNormalizedId);
|
|
||||||
if (observationIndexUpdate) {
|
|
||||||
myEntityManager.merge(indexedObservation);
|
|
||||||
} else {
|
|
||||||
myEntityManager.persist(indexedObservation);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservationIndexedCategoryCodeableConceptEntity getCategoryCodeableConceptEntities(IBase theValue) {
|
private ObservationIndexedCategoryCodeableConceptEntity getCategoryCodeableConceptEntities(IBase theValue) {
|
||||||
|
@ -151,29 +162,32 @@ public class ObservationLastNIndexPersistSvc {
|
||||||
return codeCodeableConcept;
|
return codeCodeableConcept;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCodeCodeableConceptIdIfExists(IBase theValue) {
|
private Optional<String> getCodeCodeableConceptIdIfExists(IBase theValue) {
|
||||||
List<IBase> codings = mySearchParameterExtractor.getCodingsFromCodeableConcept(theValue);
|
List<IBase> codings = mySearchParameterExtractor.getCodingsFromCodeableConcept(theValue);
|
||||||
String codeCodeableConceptId = null;
|
String codeCodeableConceptId = null;
|
||||||
|
Optional<String> codeCodeableConceptIdOptional = Optional.empty();
|
||||||
|
|
||||||
for (IBase nextCoding : codings) {
|
for (IBase nextCoding : codings) {
|
||||||
ResourceIndexedSearchParamToken param = mySearchParameterExtractor.createSearchParamForCoding("Observation",
|
ResourceIndexedSearchParamToken param = mySearchParameterExtractor.createSearchParamForCoding("Observation",
|
||||||
new RuntimeSearchParam(null, null, "code", null, null, null, null, null, null, null),
|
new RuntimeSearchParam(null, null, "code", null, null, null,
|
||||||
|
null, null, null, null),
|
||||||
nextCoding);
|
nextCoding);
|
||||||
if (param != null) {
|
if (param != null) {
|
||||||
String system = param.getSystem();
|
String system = param.getSystem();
|
||||||
String code = param.getValue();
|
String code = param.getValue();
|
||||||
String text = mySearchParameterExtractor.getDisplayTextForCoding(nextCoding);
|
String text = mySearchParameterExtractor.getDisplayTextForCoding(nextCoding);
|
||||||
if (code != null && system != null) {
|
if (code != null && system != null) {
|
||||||
codeCodeableConceptId = myObservationIndexedCodeCodingSearchParamDao.findForCodeAndSystem(code, system);
|
codeCodeableConceptIdOptional = Optional.ofNullable(myObservationIndexedCodeCodingSearchParamDao.findByCodeAndSystem(code, system));
|
||||||
} else {
|
} else {
|
||||||
codeCodeableConceptId = myObservationIndexedCodeCodingSearchParamDao.findForDisplay(text);
|
codeCodeableConceptIdOptional = Optional.ofNullable(myObservationIndexedCodeCodingSearchParamDao.findByDisplay(text));
|
||||||
}
|
}
|
||||||
if (codeCodeableConceptId != null) {
|
if (codeCodeableConceptIdOptional.isPresent()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return codeCodeableConceptId;
|
return codeCodeableConceptIdOptional;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservationIndexedCategoryCodingEntity getCategoryCoding(IBase theValue) {
|
private ObservationIndexedCategoryCodingEntity getCategoryCoding(IBase theValue) {
|
||||||
|
@ -205,7 +219,7 @@ public class ObservationLastNIndexPersistSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteObservationIndex(IBasePersistedResource theEntity) {
|
public void deleteObservationIndex(IBasePersistedResource theEntity) {
|
||||||
ObservationIndexedSearchParamLastNEntity deletedObservationLastNEntity = myResourceIndexedObservationLastNDao.findForIdentifier(theEntity.getIdDt().getIdPart());
|
ObservationIndexedSearchParamLastNEntity deletedObservationLastNEntity = myResourceIndexedObservationLastNDao.findByIdentifier(theEntity.getIdDt().getIdPart());
|
||||||
if (deletedObservationLastNEntity != null) {
|
if (deletedObservationLastNEntity != null) {
|
||||||
myEntityManager.remove(deletedObservationLastNEntity);
|
myEntityManager.remove(deletedObservationLastNEntity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
// NB: keep public
|
// NB: keep public
|
||||||
public static final int MAXIMUM_PAGE_SIZE = 800;
|
public static final int MAXIMUM_PAGE_SIZE = 800;
|
||||||
public static final int MAXIMUM_PAGE_SIZE_FOR_TESTING = 50;
|
public static final int MAXIMUM_PAGE_SIZE_FOR_TESTING = 50;
|
||||||
public static boolean myIsTest = false;
|
public static boolean myUseMaxPageSize50ForTest = false;
|
||||||
|
|
||||||
private static final List<ResourcePersistentId> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<>());
|
private static final List<ResourcePersistentId> EMPTY_LONG_LIST = Collections.unmodifiableList(new ArrayList<>());
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilder.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilder.class);
|
||||||
|
@ -184,15 +184,15 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMaximumPageSize() {
|
public static int getMaximumPageSize() {
|
||||||
if (myIsTest) {
|
if (myUseMaxPageSize50ForTest) {
|
||||||
return MAXIMUM_PAGE_SIZE_FOR_TESTING;
|
return MAXIMUM_PAGE_SIZE_FOR_TESTING;
|
||||||
} else {
|
} else {
|
||||||
return MAXIMUM_PAGE_SIZE;
|
return MAXIMUM_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setIsTest(boolean theIsTest) {
|
public static void setMaxPageSize50ForTest(boolean theIsTest) {
|
||||||
myIsTest = theIsTest;
|
myUseMaxPageSize50ForTest = theIsTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -14,13 +14,13 @@ public interface IObservationIndexedCodeCodingSearchParamDao extends JpaReposito
|
||||||
"WHERE t.myCode = :code " +
|
"WHERE t.myCode = :code " +
|
||||||
"AND t.mySystem = :system " +
|
"AND t.mySystem = :system " +
|
||||||
"")
|
"")
|
||||||
String findForCodeAndSystem(@Param("code") String theCode, @Param("system") String theSystem);
|
String findByCodeAndSystem(@Param("code") String theCode, @Param("system") String theSystem);
|
||||||
|
|
||||||
|
|
||||||
@Query("" +
|
@Query("" +
|
||||||
"SELECT t.myCodeableConceptId FROM ObservationIndexedCodeCodingEntity t " +
|
"SELECT t.myCodeableConceptId FROM ObservationIndexedCodeCodingEntity t " +
|
||||||
"WHERE t.myDisplay = :display" +
|
"WHERE t.myDisplay = :display" +
|
||||||
"")
|
"")
|
||||||
String findForDisplay(@Param("display") String theDisplay);
|
String findByDisplay(@Param("display") String theDisplay);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,6 @@ public interface IObservationIndexedSearchParamLastNDao extends JpaRepository<Ob
|
||||||
"SELECT t FROM ObservationIndexedSearchParamLastNEntity t " +
|
"SELECT t FROM ObservationIndexedSearchParamLastNEntity t " +
|
||||||
"WHERE t.myIdentifier = :identifier" +
|
"WHERE t.myIdentifier = :identifier" +
|
||||||
"")
|
"")
|
||||||
ObservationIndexedSearchParamLastNEntity findForIdentifier(@Param("identifier") String theIdentifier);
|
ObservationIndexedSearchParamLastNEntity findByIdentifier(@Param("identifier") String theIdentifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,21 +71,11 @@ public class FhirResourceDaoObservationDstu3 extends BaseHapiFhirResourceDaoObse
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
return updateObservationEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull,
|
||||||
|
thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate,
|
||||||
if (!retVal.isUnchangedInCurrentOperation()) {
|
theCreateNewHistoryEntry);
|
||||||
if (retVal.getDeleted() == null) {
|
|
||||||
// Update indexes here for LastN operation.
|
|
||||||
Observation observation = (Observation) theResource;
|
|
||||||
myObservationLastNIndexPersistSvc.indexObservation(observation);
|
|
||||||
} else {
|
|
||||||
myObservationLastNIndexPersistSvc.deleteObservationIndex(theEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,21 +78,11 @@ public class FhirResourceDaoObservationR4 extends BaseHapiFhirResourceDaoObserva
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
return updateObservationEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull,
|
||||||
|
thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate,
|
||||||
if (!retVal.isUnchangedInCurrentOperation()) {
|
theCreateNewHistoryEntry);
|
||||||
if (retVal.getDeleted() == null) {
|
|
||||||
// Update indexes here for LastN operation.
|
|
||||||
Observation observation = (Observation) theResource;
|
|
||||||
myObservationLastNIndexPersistSvc.indexObservation(observation);
|
|
||||||
} else {
|
|
||||||
myObservationLastNIndexPersistSvc.deleteObservationIndex(retVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,21 +71,11 @@ public class FhirResourceDaoObservationR5 extends BaseHapiFhirResourceDaoObserva
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, TransactionDetails theTransactionDetails, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate, theCreateNewHistoryEntry);
|
return updateObservationEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull,
|
||||||
|
thePerformIndexing, theUpdateVersion, theTransactionDetails, theForceUpdate,
|
||||||
if (!retVal.isUnchangedInCurrentOperation()) {
|
theCreateNewHistoryEntry);
|
||||||
if (retVal.getDeleted() == null) {
|
|
||||||
// Update indexes here for LastN operation.
|
|
||||||
Observation observation = (Observation) theResource;
|
|
||||||
myObservationLastNIndexPersistSvc.indexObservation(observation);
|
|
||||||
} else {
|
|
||||||
myObservationLastNIndexPersistSvc.deleteObservationIndex(theEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
package ca.uhn.fhir.jpa.search.lastn;
|
package ca.uhn.fhir.jpa.search.lastn;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.model.util.CodeSystemHash;
|
||||||
|
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
||||||
|
import ca.uhn.fhir.jpa.search.lastn.json.ObservationJson;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.util.LastNParameterHelper;
|
import ca.uhn.fhir.jpa.searchparam.util.LastNParameterHelper;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
|
||||||
import ca.uhn.fhir.jpa.search.lastn.json.ObservationJson;
|
|
||||||
import ca.uhn.fhir.jpa.search.lastn.util.CodeSystemHash;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import org.shadehapi.elasticsearch.action.DocWriteResponse;
|
||||||
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||||
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
import org.shadehapi.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
||||||
import org.shadehapi.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
import org.shadehapi.elasticsearch.action.admin.indices.get.GetIndexRequest;
|
||||||
import org.shadehapi.elasticsearch.action.DocWriteResponse;
|
|
||||||
import org.shadehapi.elasticsearch.action.index.IndexRequest;
|
import org.shadehapi.elasticsearch.action.index.IndexRequest;
|
||||||
import org.shadehapi.elasticsearch.action.index.IndexResponse;
|
import org.shadehapi.elasticsearch.action.index.IndexResponse;
|
||||||
import org.shadehapi.elasticsearch.action.search.SearchRequest;
|
import org.shadehapi.elasticsearch.action.search.SearchRequest;
|
||||||
|
@ -33,7 +33,10 @@ import org.shadehapi.elasticsearch.search.aggregations.AggregationBuilder;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.AggregationBuilders;
|
import org.shadehapi.elasticsearch.search.aggregations.AggregationBuilders;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.Aggregations;
|
import org.shadehapi.elasticsearch.search.aggregations.Aggregations;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.BucketOrder;
|
import org.shadehapi.elasticsearch.search.aggregations.BucketOrder;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.bucket.composite.*;
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
|
||||||
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
|
||||||
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.composite.ParsedComposite;
|
||||||
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.composite.TermsValuesSourceBuilder;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.Terms;
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||||
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
import org.shadehapi.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
||||||
|
@ -42,7 +45,9 @@ import org.shadehapi.elasticsearch.search.aggregations.support.ValueType;
|
||||||
import org.shadehapi.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.shadehapi.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
import org.shadehapi.elasticsearch.search.sort.SortOrder;
|
import org.shadehapi.elasticsearch.search.sort.SortOrder;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -52,9 +57,11 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
|
|
||||||
public static final String OBSERVATION_INDEX = "observation_index";
|
public static final String OBSERVATION_INDEX = "observation_index";
|
||||||
public static final String CODE_INDEX = "code_index";
|
public static final String OBSERVATION_CODE_INDEX = "code_index";
|
||||||
public static final String OBSERVATION_DOCUMENT_TYPE = "ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity";
|
public static final String OBSERVATION_DOCUMENT_TYPE = "ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity";
|
||||||
public static final String CODE_DOCUMENT_TYPE = "ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity";
|
public static final String CODE_DOCUMENT_TYPE = "ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity";
|
||||||
|
public static final String OBSERVATION_INDEX_SCHEMA_FILE = "ObservationIndexSchema.json";
|
||||||
|
public static final String OBSERVATION_CODE_INDEX_SCHEMA_FILE = "ObservationCodeIndexSchema.json";
|
||||||
|
|
||||||
private final RestHighLevelClient myRestHighLevelClient;
|
private final RestHighLevelClient myRestHighLevelClient;
|
||||||
|
|
||||||
|
@ -63,6 +70,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
private final String GROUP_BY_SUBJECT = "group_by_subject";
|
private final String GROUP_BY_SUBJECT = "group_by_subject";
|
||||||
private final String GROUP_BY_SYSTEM = "group_by_system";
|
private final String GROUP_BY_SYSTEM = "group_by_system";
|
||||||
private final String GROUP_BY_CODE = "group_by_code";
|
private final String GROUP_BY_CODE = "group_by_code";
|
||||||
|
private final String OBSERVATION_IDENTIFIER_FIELD_NAME = "identifier";
|
||||||
|
|
||||||
|
|
||||||
public ElasticsearchSvcImpl(String theHostname, int thePort, String theUsername, String thePassword) {
|
public ElasticsearchSvcImpl(String theHostname, int thePort, String theUsername, String thePassword) {
|
||||||
|
@ -70,106 +78,41 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
createObservationIndexIfMissing();
|
createObservationIndexIfMissing();
|
||||||
createCodeIndexIfMissing();
|
createObservationCodeIndexIfMissing();
|
||||||
} catch (IOException theE) {
|
} catch (IOException theE) {
|
||||||
throw new RuntimeException("Failed to create document index", theE);
|
throw new RuntimeException("Failed to create document index", theE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getIndexSchema(String theSchemaFileName) throws IOException {
|
||||||
|
InputStreamReader input = new InputStreamReader(ElasticsearchSvcImpl.class.getResourceAsStream(theSchemaFileName));
|
||||||
|
BufferedReader reader = new BufferedReader(input);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String str;
|
||||||
|
while((str = reader.readLine())!= null){
|
||||||
|
sb.append(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private void createObservationIndexIfMissing() throws IOException {
|
private void createObservationIndexIfMissing() throws IOException {
|
||||||
if (indexExists(OBSERVATION_INDEX)) {
|
if (indexExists(OBSERVATION_INDEX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String observationMapping = "{\n" +
|
String observationMapping = getIndexSchema(OBSERVATION_INDEX_SCHEMA_FILE);
|
||||||
" \"mappings\" : {\n" +
|
|
||||||
" \"ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity\" : {\n" +
|
|
||||||
" \"properties\" : {\n" +
|
|
||||||
" \"codeconceptid\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\",\n" +
|
|
||||||
" \"norms\" : true\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codeconcepttext\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codeconceptcodingcode\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codeconceptcodingsystem\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codeconceptcodingcode_system_hash\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codeconceptcodingdisplay\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"categoryconcepttext\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"categoryconceptcodingcode\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"categoryconceptcodingsystem\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"categoryconceptcodingcode_system_hash\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"categoryconceptcodingdisplay\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"effectivedtm\" : {\n" +
|
|
||||||
" \"type\" : \"date\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"identifier\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\",\n" +
|
|
||||||
" \"store\" : true\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"subject\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n";
|
|
||||||
if (!createIndex(OBSERVATION_INDEX, observationMapping)) {
|
if (!createIndex(OBSERVATION_INDEX, observationMapping)) {
|
||||||
throw new RuntimeException("Failed to create observation index");
|
throw new RuntimeException("Failed to create observation index");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCodeIndexIfMissing() throws IOException {
|
private void createObservationCodeIndexIfMissing() throws IOException {
|
||||||
if (indexExists(CODE_INDEX)) {
|
if (indexExists(OBSERVATION_CODE_INDEX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String codeMapping = "{\n" +
|
String observationCodeMapping = getIndexSchema(OBSERVATION_CODE_INDEX_SCHEMA_FILE);
|
||||||
" \"mappings\" : {\n" +
|
if (!createIndex(OBSERVATION_CODE_INDEX, observationCodeMapping)) {
|
||||||
" \"ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity\" : {\n" +
|
throw new RuntimeException("Failed to create observation code index");
|
||||||
" \"properties\" : {\n" +
|
|
||||||
" \"codeable_concept_id\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\",\n" +
|
|
||||||
" \"store\" : true\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codingcode\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codingcode_system_hash\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codingdisplay\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"codingsystem\" : {\n" +
|
|
||||||
" \"type\" : \"keyword\"\n" +
|
|
||||||
" },\n" +
|
|
||||||
" \"text\" : {\n" +
|
|
||||||
" \"type\" : \"text\"\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n";
|
|
||||||
if (!createIndex(CODE_INDEX, codeMapping)) {
|
|
||||||
throw new RuntimeException("Failed to create code index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,7 +133,6 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> executeLastN(SearchParameterMap theSearchParameterMap, FhirContext theFhirContext, Integer theMaxResultsToFetch) {
|
public List<String> executeLastN(SearchParameterMap theSearchParameterMap, FhirContext theFhirContext, Integer theMaxResultsToFetch) {
|
||||||
String OBSERVATION_IDENTIFIER_FIELD_NAME = "identifier";
|
|
||||||
String[] topHitsInclude = {OBSERVATION_IDENTIFIER_FIELD_NAME};
|
String[] topHitsInclude = {OBSERVATION_IDENTIFIER_FIELD_NAME};
|
||||||
return buildAndExecuteSearch(theSearchParameterMap, theFhirContext, topHitsInclude,
|
return buildAndExecuteSearch(theSearchParameterMap, theFhirContext, topHitsInclude,
|
||||||
ObservationJson::getIdentifier, theMaxResultsToFetch);
|
ObservationJson::getIdentifier, theMaxResultsToFetch);
|
||||||
|
@ -557,7 +499,7 @@ public class ElasticsearchSvcImpl implements IElasticsearchSvc {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<CodeJson> queryAllIndexedObservationCodes() throws IOException {
|
List<CodeJson> queryAllIndexedObservationCodes() throws IOException {
|
||||||
SearchRequest codeSearchRequest = new SearchRequest(CODE_INDEX);
|
SearchRequest codeSearchRequest = new SearchRequest(OBSERVATION_CODE_INDEX);
|
||||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||||
// Query
|
// Query
|
||||||
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
|
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
|
||||||
|
|
|
@ -6,5 +6,13 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface IElasticsearchSvc {
|
public interface IElasticsearchSvc {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns identifiers for the last most recent N observations that meet the specified criteria.
|
||||||
|
* @param theSearchParameterMap SearchParameterMap containing search parameters used for filtering the last N observations. Supported parameters include Subject, Patient, Code, Category and Max (the parameter used to determine N).
|
||||||
|
* @param theFhirContext Current FhirContext.
|
||||||
|
* @param theMaxResultsToFetch The maximum number of results to return for the purpose of paging.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
List<String> executeLastN(SearchParameterMap theSearchParameterMap, FhirContext theFhirContext, Integer theMaxResultsToFetch);
|
List<String> executeLastN(SearchParameterMap theSearchParameterMap, FhirContext theFhirContext, Integer theMaxResultsToFetch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.search.lastn.json;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.search.lastn.util.CodeSystemHash;
|
import ca.uhn.fhir.jpa.model.util.CodeSystemHash;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.search.lastn.json;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.search.lastn.util.CodeSystemHash;
|
import ca.uhn.fhir.jpa.model.util.CodeSystemHash;
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
@ -25,148 +25,117 @@ import java.util.List;
|
||||||
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||||
public class ObservationJson {
|
public class ObservationJson {
|
||||||
|
|
||||||
@JsonProperty(value = "identifier", required = true)
|
@JsonProperty(value = "identifier", required = true)
|
||||||
private String myIdentifier;
|
private String myIdentifier;
|
||||||
|
|
||||||
@JsonProperty(value = "subject", required = true)
|
@JsonProperty(value = "subject", required = true)
|
||||||
private String mySubject;
|
private String mySubject;
|
||||||
|
|
||||||
@JsonProperty(value = "categoryconcepttext", required = false)
|
@JsonProperty(value = "categoryconcepttext", required = false)
|
||||||
private List<String> myCategory_concept_text = new ArrayList<>();
|
private List<String> myCategory_concept_text = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty(value = "categoryconceptcodingcode", required = false)
|
@JsonProperty(value = "categoryconceptcodingcode", required = false)
|
||||||
private List<List<String>> myCategory_coding_code = new ArrayList<>();
|
private List<List<String>> myCategory_coding_code = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty(value = "categoryconceptcodingcode_system_hash", required = false)
|
@JsonProperty(value = "categoryconceptcodingcode_system_hash", required = false)
|
||||||
private List<List<String>> myCategory_coding_code_system_hash = new ArrayList<>();
|
private List<List<String>> myCategory_coding_code_system_hash = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty(value = "categoryconceptcodingdisplay", required = false)
|
@JsonProperty(value = "categoryconceptcodingdisplay", required = false)
|
||||||
private List<List<String>> myCategory_coding_display = new ArrayList<>();
|
private List<List<String>> myCategory_coding_display = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty(value = "categoryconceptcodingsystem", required = false)
|
@JsonProperty(value = "categoryconceptcodingsystem", required = false)
|
||||||
private List<List<String>> myCategory_coding_system = new ArrayList<>();
|
private List<List<String>> myCategory_coding_system = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty(value = "codeconceptid", required = false)
|
@JsonProperty(value = "codeconceptid", required = false)
|
||||||
private String myCode_concept_id;
|
private String myCode_concept_id;
|
||||||
|
|
||||||
@JsonProperty(value = "codeconcepttext", required = false)
|
@JsonProperty(value = "codeconcepttext", required = false)
|
||||||
private String myCode_concept_text;
|
private String myCode_concept_text;
|
||||||
|
|
||||||
@JsonProperty(value = "codeconceptcodingcode", required = false)
|
@JsonProperty(value = "codeconceptcodingcode", required = false)
|
||||||
// TODO: Temporary change until sort out how to deal with multiple observation code codings
|
private String myCode_coding_code;
|
||||||
// private List<String> myCode_coding_code = new ArrayList<>();
|
|
||||||
private String myCode_coding_code;
|
|
||||||
|
|
||||||
@JsonProperty(value = "codeconceptcodingcode_system_hash", required = false)
|
@JsonProperty(value = "codeconceptcodingcode_system_hash", required = false)
|
||||||
// TODO: Temporary change until sort out how to deal with multiple observation code codings
|
private String myCode_coding_code_system_hash;
|
||||||
// private List<String> myCode_coding_code_system_hash = new ArrayList<>();
|
|
||||||
private String myCode_coding_code_system_hash;
|
|
||||||
|
|
||||||
@JsonProperty(value = "codeconceptcodingdisplay", required = false)
|
@JsonProperty(value = "codeconceptcodingdisplay", required = false)
|
||||||
// TODO: Temporary change until sort out how to deal with multiple observation code codings
|
private String myCode_coding_display;
|
||||||
// private List<String> myCode_coding_display = new ArrayList<>();
|
|
||||||
private String myCode_coding_display;
|
|
||||||
|
|
||||||
@JsonProperty(value = "codeconceptcodingsystem", required = false)
|
@JsonProperty(value = "codeconceptcodingsystem", required = false)
|
||||||
// TODO: Temporary change until sort out how to deal with multiple observation code codings
|
private String myCode_coding_system;
|
||||||
// private List<String> myCode_coding_system = new ArrayList<>();
|
|
||||||
private String myCode_coding_system;
|
|
||||||
|
|
||||||
@JsonProperty(value = "effectivedtm", required = true)
|
@JsonProperty(value = "effectivedtm", required = true)
|
||||||
private Date myEffectiveDtm;
|
private Date myEffectiveDtm;
|
||||||
|
|
||||||
public ObservationJson() {}
|
public ObservationJson() {
|
||||||
|
}
|
||||||
|
|
||||||
public void setIdentifier(String theIdentifier) {
|
public void setIdentifier(String theIdentifier) {
|
||||||
myIdentifier = theIdentifier;
|
myIdentifier = theIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSubject(String theSubject) {
|
public void setSubject(String theSubject) {
|
||||||
mySubject = theSubject;
|
mySubject = theSubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCategories(List<CodeableConcept> theCategories) {
|
public void setCategories(List<CodeableConcept> theCategories) {
|
||||||
for (CodeableConcept theConcept : theCategories) {
|
for (CodeableConcept theConcept : theCategories) {
|
||||||
myCategory_concept_text.add(theConcept.getText());
|
myCategory_concept_text.add(theConcept.getText());
|
||||||
List<String> coding_code_system_hashes = new ArrayList<>();
|
List<String> coding_code_system_hashes = new ArrayList<>();
|
||||||
List<String> coding_codes = new ArrayList<>();
|
List<String> coding_codes = new ArrayList<>();
|
||||||
List<String> coding_displays = new ArrayList<>();
|
List<String> coding_displays = new ArrayList<>();
|
||||||
List<String> coding_systems = new ArrayList<>();
|
List<String> coding_systems = new ArrayList<>();
|
||||||
for (Coding theCategoryCoding : theConcept.getCoding()) {
|
for (Coding theCategoryCoding : theConcept.getCoding()) {
|
||||||
coding_code_system_hashes.add(String.valueOf(CodeSystemHash.hashCodeSystem(theCategoryCoding.getSystem(), theCategoryCoding.getCode())));
|
coding_code_system_hashes.add(String.valueOf(CodeSystemHash.hashCodeSystem(theCategoryCoding.getSystem(), theCategoryCoding.getCode())));
|
||||||
coding_codes.add(theCategoryCoding.getCode());
|
coding_codes.add(theCategoryCoding.getCode());
|
||||||
coding_displays.add(theCategoryCoding.getDisplay());
|
coding_displays.add(theCategoryCoding.getDisplay());
|
||||||
coding_systems.add(theCategoryCoding.getSystem());
|
coding_systems.add(theCategoryCoding.getSystem());
|
||||||
}
|
}
|
||||||
myCategory_coding_code_system_hash.add(coding_code_system_hashes);
|
myCategory_coding_code_system_hash.add(coding_code_system_hashes);
|
||||||
myCategory_coding_code.add(coding_codes);
|
myCategory_coding_code.add(coding_codes);
|
||||||
myCategory_coding_display.add(coding_displays);
|
myCategory_coding_display.add(coding_displays);
|
||||||
myCategory_coding_system.add(coding_systems);
|
myCategory_coding_system.add(coding_systems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getCategory_concept_text() {
|
public List<String> getCategory_concept_text() {
|
||||||
return myCategory_concept_text;
|
return myCategory_concept_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<List<String>> getCategory_coding_code_system_hash() {
|
public List<List<String>> getCategory_coding_code_system_hash() {
|
||||||
return myCategory_coding_code_system_hash;
|
return myCategory_coding_code_system_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<List<String>> getCategory_coding_code() {
|
public List<List<String>> getCategory_coding_code() {
|
||||||
return myCategory_coding_code;
|
return myCategory_coding_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<List<String>> getCategory_coding_display() {
|
public List<List<String>> getCategory_coding_display() {
|
||||||
return myCategory_coding_display;
|
return myCategory_coding_display;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<List<String>> getCategory_coding_system() {
|
public List<List<String>> getCategory_coding_system() {
|
||||||
return myCategory_coding_system;
|
return myCategory_coding_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(CodeableConcept theCode) {
|
public void setCode(CodeableConcept theCode) {
|
||||||
myCode_concept_text = theCode.getText();
|
myCode_concept_text = theCode.getText();
|
||||||
for(Coding theCodeCoding : theCode.getCoding()) {
|
for (Coding theCodeCoding : theCode.getCoding()) {
|
||||||
// TODO: Temporary change until address how to manage multiple Observation Code codings.
|
myCode_coding_code_system_hash = String.valueOf(CodeSystemHash.hashCodeSystem(theCodeCoding.getSystem(), theCodeCoding.getCode()));
|
||||||
/* myCode_coding_code_system_hash.add(String.valueOf(CodeSystemHash.hashCodeSystem(theCodeCoding.getSystem(), theCodeCoding.getCode())));
|
myCode_coding_code = theCodeCoding.getCode();
|
||||||
myCode_coding_code.add(theCodeCoding.getCode());
|
myCode_coding_display = theCodeCoding.getDisplay();
|
||||||
myCode_coding_display.add(theCodeCoding.getDisplay());
|
myCode_coding_system = theCodeCoding.getSystem();
|
||||||
myCode_coding_system.add(theCodeCoding.getSystem());
|
}
|
||||||
*/
|
|
||||||
myCode_coding_code_system_hash = String.valueOf(CodeSystemHash.hashCodeSystem(theCodeCoding.getSystem(), theCodeCoding.getCode()));
|
|
||||||
myCode_coding_code = theCodeCoding.getCode();
|
|
||||||
myCode_coding_display = theCodeCoding.getDisplay();
|
|
||||||
myCode_coding_system = theCodeCoding.getSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCode_concept_text() {
|
public String getCode_concept_text() {
|
||||||
return myCode_concept_text;
|
return myCode_concept_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Temporary changes until resolve problem of how to manage Observation Code with multiple codings
|
public String getCode_coding_code_system_hash() {
|
||||||
/*
|
return myCode_coding_code_system_hash;
|
||||||
public List<String> getCode_coding_code_system_hash() {
|
}
|
||||||
return myCode_coding_code_system_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getCode_coding_code() {
|
|
||||||
return myCode_coding_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getCode_coding_display() {
|
|
||||||
return myCode_coding_display;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getCode_coding_system() {
|
|
||||||
return myCode_coding_system;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public String getCode_coding_code_system_hash() {
|
|
||||||
return myCode_coding_code_system_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode_coding_code() {
|
public String getCode_coding_code() {
|
||||||
return myCode_coding_code;
|
return myCode_coding_code;
|
||||||
|
@ -180,28 +149,28 @@ public class ObservationJson {
|
||||||
return myCode_coding_system;
|
return myCode_coding_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode_concept_id(String theCodeId) {
|
public void setCode_concept_id(String theCodeId) {
|
||||||
myCode_concept_id = theCodeId;
|
myCode_concept_id = theCodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCode_concept_id() {
|
public String getCode_concept_id() {
|
||||||
return myCode_concept_id;
|
return myCode_concept_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEffectiveDtm(Date theEffectiveDtm) {
|
public void setEffectiveDtm(Date theEffectiveDtm) {
|
||||||
myEffectiveDtm = theEffectiveDtm;
|
myEffectiveDtm = theEffectiveDtm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getEffectiveDtm() {
|
public Date getEffectiveDtm() {
|
||||||
return myEffectiveDtm;
|
return myEffectiveDtm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return mySubject;
|
return mySubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
return myIdentifier;
|
return myIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.search.lastn.util;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import com.google.common.hash.HashCode;
|
|
||||||
import com.google.common.hash.HashFunction;
|
|
||||||
import com.google.common.hash.Hasher;
|
|
||||||
import com.google.common.hash.Hashing;
|
|
||||||
|
|
||||||
public class CodeSystemHash {
|
|
||||||
private static final HashFunction HASH_FUNCTION = Hashing.murmur3_128(0);
|
|
||||||
private static final byte[] DELIMITER_BYTES = "|".getBytes(Charsets.UTF_8);
|
|
||||||
|
|
||||||
static public long hashCodeSystem( String system, String code ) {
|
|
||||||
Hasher hasher = HASH_FUNCTION.newHasher();
|
|
||||||
addStringToHasher(hasher, system);
|
|
||||||
addStringToHasher(hasher, code);
|
|
||||||
|
|
||||||
HashCode hashCode = hasher.hash();
|
|
||||||
return hashCode.asLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
static private void addStringToHasher(Hasher hasher, String next) {
|
|
||||||
if (next == null) {
|
|
||||||
hasher.putByte((byte) 0);
|
|
||||||
} else {
|
|
||||||
next = UrlUtil.escapeUrlParam(next);
|
|
||||||
byte[] bytes = next.getBytes(Charsets.UTF_8);
|
|
||||||
hasher.putBytes(bytes);
|
|
||||||
}
|
|
||||||
hasher.putBytes(DELIMITER_BYTES);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"mappings" : {
|
||||||
|
"ca.uhn.fhir.jpa.model.entity.ObservationIndexedCodeCodeableConceptEntity" : {
|
||||||
|
"properties" : {
|
||||||
|
"codeable_concept_id" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codingcode" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codingcode_system_hash" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codingdisplay" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codingsystem" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"text" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"mappings" : {
|
||||||
|
"ca.uhn.fhir.jpa.model.entity.ObservationIndexedSearchParamLastNEntity" : {
|
||||||
|
"properties" : {
|
||||||
|
"codeconceptid" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codeconcepttext" : {
|
||||||
|
"type" : "text"
|
||||||
|
},
|
||||||
|
"codeconceptcodingcode" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codeconceptcodingsystem" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codeconceptcodingcode_system_hash" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"codeconceptcodingdisplay" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"categoryconcepttext" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"categoryconceptcodingcode" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"categoryconceptcodingsystem" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"categoryconceptcodingcode_system_hash" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"categoryconceptcodingdisplay" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"effectivedtm" : {
|
||||||
|
"type" : "date"
|
||||||
|
},
|
||||||
|
"identifier" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
},
|
||||||
|
"subject" : {
|
||||||
|
"type" : "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,14 +52,14 @@ public class FhirResourceDaoR4SearchLastNAsyncIT extends BaseR4SearchLastN {
|
||||||
mySmallerPreFetchThresholds.add(-1);
|
mySmallerPreFetchThresholds.add(-1);
|
||||||
myDaoConfig.setSearchPreFetchThresholds(mySmallerPreFetchThresholds);
|
myDaoConfig.setSearchPreFetchThresholds(mySmallerPreFetchThresholds);
|
||||||
|
|
||||||
SearchBuilder.setIsTest(true);
|
SearchBuilder.setMaxPageSize50ForTest(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
myDaoConfig.setSearchPreFetchThresholds(originalPreFetchThresholds);
|
myDaoConfig.setSearchPreFetchThresholds(originalPreFetchThresholds);
|
||||||
SearchBuilder.setIsTest(false);
|
SearchBuilder.setMaxPageSize50ForTest(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -82,7 +82,7 @@ public class FhirResourceDaoR4SearchLastNAsyncIT extends BaseR4SearchLastN {
|
||||||
when(mySrd.getParameters()).thenReturn(requestParameters);
|
when(mySrd.getParameters()).thenReturn(requestParameters);
|
||||||
|
|
||||||
// Set chunk size to 50
|
// Set chunk size to 50
|
||||||
SearchBuilder.setIsTest(true);
|
SearchBuilder.setMaxPageSize50ForTest(true);
|
||||||
|
|
||||||
// Expand default fetch sizes to ensure all observations are returned in first page:
|
// Expand default fetch sizes to ensure all observations are returned in first page:
|
||||||
List<Integer> myBiggerPreFetchThresholds = new ArrayList<>();
|
List<Integer> myBiggerPreFetchThresholds = new ArrayList<>();
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseR4SearchLastN {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void resetMaximumPageSize() {
|
public void resetMaximumPageSize() {
|
||||||
SearchBuilder.setIsTest(false);
|
SearchBuilder.setMaxPageSize50ForTest(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -46,7 +46,7 @@ public class FhirResourceDaoR4SearchLastNIT extends BaseR4SearchLastN {
|
||||||
when(mySrd.getParameters()).thenReturn(requestParameters);
|
when(mySrd.getParameters()).thenReturn(requestParameters);
|
||||||
|
|
||||||
// Set chunk size to 50
|
// Set chunk size to 50
|
||||||
SearchBuilder.setIsTest(true);
|
SearchBuilder.setMaxPageSize50ForTest(true);
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
List<String> results = toUnqualifiedVersionlessIdValues(myObservationDao.observationsLastN(params, mockSrd(),null));
|
List<String> results = toUnqualifiedVersionlessIdValues(myObservationDao.observationsLastN(params, mockSrd(),null));
|
||||||
|
|
|
@ -130,7 +130,6 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
|
|
||||||
myObservation.setCode(getObservationCode());
|
myObservation.setCode(getObservationCode());
|
||||||
|
|
||||||
//myObservationLastNIndexPersistR4Svc.indexObservation(myObservation);
|
|
||||||
testObservationPersist.indexObservation(myObservation);
|
testObservationPersist.indexObservation(myObservation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,12 +138,12 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
// Add three CodeableConcepts for category
|
// Add three CodeableConcepts for category
|
||||||
List<CodeableConcept> categoryConcepts = new ArrayList<>();
|
List<CodeableConcept> categoryConcepts = new ArrayList<>();
|
||||||
// Create three codings and first category CodeableConcept
|
// Create three codings and first category CodeableConcept
|
||||||
List<Coding> category1 = new ArrayList<>();
|
List<Coding> category = new ArrayList<>();
|
||||||
CodeableConcept categoryCodeableConcept1 = new CodeableConcept().setText("Test Codeable Concept Field for first category");
|
CodeableConcept categoryCodeableConcept1 = new CodeableConcept().setText("Test Codeable Concept Field for first category");
|
||||||
category1.add(new Coding(CATEGORYFIRSTCODINGSYSTEM, FIRSTCATEGORYFIRSTCODINGCODE, "test-heart-rate display"));
|
category.add(new Coding(CATEGORYFIRSTCODINGSYSTEM, FIRSTCATEGORYFIRSTCODINGCODE, "test-heart-rate display"));
|
||||||
category1.add(new Coding("http://myalternatecodes.org/fhir/observation-category", "test-alt-heart-rate", "test-alt-heart-rate display"));
|
category.add(new Coding("http://myalternatecodes.org/fhir/observation-category", "test-alt-heart-rate", "test-alt-heart-rate display"));
|
||||||
category1.add(new Coding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-heart-rate", "test-2nd-alt-heart-rate display"));
|
category.add(new Coding("http://mysecondaltcodes.org/fhir/observation-category", "test-2nd-alt-heart-rate", "test-2nd-alt-heart-rate display"));
|
||||||
categoryCodeableConcept1.setCoding(category1);
|
categoryCodeableConcept1.setCoding(category);
|
||||||
categoryConcepts.add(categoryCodeableConcept1);
|
categoryConcepts.add(categoryCodeableConcept1);
|
||||||
// Create three codings and second category CodeableConcept
|
// Create three codings and second category CodeableConcept
|
||||||
List<Coding> category2 = new ArrayList<>();
|
List<Coding> category2 = new ArrayList<>();
|
||||||
|
@ -169,9 +168,6 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
// Create CodeableConcept for Code with three codings.
|
// Create CodeableConcept for Code with three codings.
|
||||||
CodeableConcept codeableConceptField = new CodeableConcept().setText(SINGLE_OBSERVATION_CODE_TEXT);
|
CodeableConcept codeableConceptField = new CodeableConcept().setText(SINGLE_OBSERVATION_CODE_TEXT);
|
||||||
codeableConceptField.addCoding(new Coding(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE, "test-code display"));
|
codeableConceptField.addCoding(new Coding(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE, "test-code display"));
|
||||||
// TODO: Temporarily limit this to a single Observation Code coding until we sort out how to manage multiple codings
|
|
||||||
// codeableConceptField.addCoding(new Coding("http://myalternatecodes.org/fhir/observation-code", "test-alt-code", "test-alt-code display"));
|
|
||||||
// codeableConceptField.addCoding(new Coding("http://mysecondaltcodes.org/fhir/observation-code", "test-second-alt-code", "test-second-alt-code display"));
|
|
||||||
return codeableConceptField;
|
return codeableConceptField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +259,6 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
Date effectiveDtm = observationDate.getTime();
|
Date effectiveDtm = observationDate.getTime();
|
||||||
observation.setEffective(new DateTimeType(effectiveDtm));
|
observation.setEffective(new DateTimeType(effectiveDtm));
|
||||||
|
|
||||||
// myObservationLastNIndexPersistR4Svc.indexObservation(observation);
|
|
||||||
|
|
||||||
testObservationPersist.indexObservation(observation);
|
testObservationPersist.indexObservation(observation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +273,7 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
indexMultipleObservations();
|
indexMultipleObservations();
|
||||||
assertEquals(100, myResourceIndexedObservationLastNDao.count());
|
assertEquals(100, myResourceIndexedObservationLastNDao.count());
|
||||||
// Check that fifth observation for fifth patient has been indexed.
|
// Check that fifth observation for fifth patient has been indexed.
|
||||||
ObservationIndexedSearchParamLastNEntity observation = myResourceIndexedObservationLastNDao.findForIdentifier("55");
|
ObservationIndexedSearchParamLastNEntity observation = myResourceIndexedObservationLastNDao.findByIdentifier("55");
|
||||||
assertNotNull(observation);
|
assertNotNull(observation);
|
||||||
|
|
||||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||||
|
@ -295,12 +289,11 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
entity.setResourceType("Observation");
|
entity.setResourceType("Observation");
|
||||||
entity.setVersion(0L);
|
entity.setVersion(0L);
|
||||||
|
|
||||||
// myObservationLastNIndexPersistR4Svc.deleteObservationIndex(entity);
|
|
||||||
testObservationPersist.deleteObservationIndex(entity);
|
testObservationPersist.deleteObservationIndex(entity);
|
||||||
|
|
||||||
// Confirm that observation was deleted.
|
// Confirm that observation was deleted.
|
||||||
assertEquals(99, myResourceIndexedObservationLastNDao.count());
|
assertEquals(99, myResourceIndexedObservationLastNDao.count());
|
||||||
observation = myResourceIndexedObservationLastNDao.findForIdentifier("55");
|
observation = myResourceIndexedObservationLastNDao.findByIdentifier("55");
|
||||||
assertNull(observation);
|
assertNull(observation);
|
||||||
|
|
||||||
observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, myFhirCtx, 200);
|
observationIdsOnly = elasticsearchSvc.executeLastN(searchParameterMap, myFhirCtx, 200);
|
||||||
|
@ -341,10 +334,9 @@ public class PersistObservationIndexedSearchParamLastNR4IT {
|
||||||
updatedObservation.setCategory(getCategoryCode());
|
updatedObservation.setCategory(getCategoryCode());
|
||||||
updatedObservation.setCode(getObservationCode());
|
updatedObservation.setCode(getObservationCode());
|
||||||
|
|
||||||
// myObservationLastNIndexPersistR4Svc.indexObservation(updatedObservation);
|
|
||||||
testObservationPersist.indexObservation(updatedObservation);
|
testObservationPersist.indexObservation(updatedObservation);
|
||||||
|
|
||||||
ObservationIndexedSearchParamLastNEntity updatedObservationEntity = myResourceIndexedObservationLastNDao.findForIdentifier(SINGLE_OBSERVATION_PID);
|
ObservationIndexedSearchParamLastNEntity updatedObservationEntity = myResourceIndexedObservationLastNDao.findByIdentifier(SINGLE_OBSERVATION_PID);
|
||||||
assertEquals("1234", updatedObservationEntity.getSubject());
|
assertEquals("1234", updatedObservationEntity.getSubject());
|
||||||
assertEquals(newEffectiveDtm.getValue(), updatedObservationEntity.getEffectiveDtm());
|
assertEquals(newEffectiveDtm.getValue(), updatedObservationEntity.getEffectiveDtm());
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
||||||
@After
|
@After
|
||||||
public void after() throws IOException {
|
public void after() throws IOException {
|
||||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.CODE_INDEX);
|
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -307,18 +307,12 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
||||||
String codeableConceptId1 = UUID.randomUUID().toString();
|
String codeableConceptId1 = UUID.randomUUID().toString();
|
||||||
CodeableConcept codeableConceptField1 = new CodeableConcept().setText("Test Codeable Concept Field for First Code");
|
CodeableConcept codeableConceptField1 = new CodeableConcept().setText("Test Codeable Concept Field for First Code");
|
||||||
codeableConceptField1.addCoding(new Coding("http://mycodes.org/fhir/observation-code", "test-code-1", "test-code-1 display"));
|
codeableConceptField1.addCoding(new Coding("http://mycodes.org/fhir/observation-code", "test-code-1", "test-code-1 display"));
|
||||||
// TODO: uncomment the following once there is a solution to supporting multiple codings for Observation Code
|
|
||||||
// codeableConceptField1.addCoding(new Coding("http://myalternatecodes.org/fhir/observation-code", "test-alt-code-1", "test-alt-code-1 display"));
|
|
||||||
// codeableConceptField1.addCoding(new Coding("http://mysecondaltcodes.org/fhir/observation-code", "test-second-alt-code-1", "test-second-alt-code-1 display"));
|
|
||||||
CodeJson codeJson1 = new CodeJson(codeableConceptField1, codeableConceptId1);
|
CodeJson codeJson1 = new CodeJson(codeableConceptField1, codeableConceptId1);
|
||||||
String codeJson1Document = ourMapperNonPrettyPrint.writeValueAsString(codeJson1);
|
String codeJson1Document = ourMapperNonPrettyPrint.writeValueAsString(codeJson1);
|
||||||
|
|
||||||
String codeableConceptId2 = UUID.randomUUID().toString();
|
String codeableConceptId2 = UUID.randomUUID().toString();
|
||||||
CodeableConcept codeableConceptField2 = new CodeableConcept().setText("Test Codeable Concept Field for Second Code");
|
CodeableConcept codeableConceptField2 = new CodeableConcept().setText("Test Codeable Concept Field for Second Code");
|
||||||
codeableConceptField2.addCoding(new Coding("http://mycodes.org/fhir/observation-code", "test-code-2", "test-code-2 display"));
|
codeableConceptField2.addCoding(new Coding("http://mycodes.org/fhir/observation-code", "test-code-2", "test-code-2 display"));
|
||||||
// TODO: uncomment the following once there is a solution to supporting multiple codings for Observation Code
|
|
||||||
// codeableConceptField2.addCoding(new Coding("http://myalternatecodes.org/fhir/observation-code", "test-alt-code-2", "test-alt-code-2 display"));
|
|
||||||
// codeableConceptField2.addCoding(new Coding("http://mysecondaltcodes.org/fhir/observation-code", "test-second-alt-code-2", "test-second-alt-code-2 display"));
|
|
||||||
CodeJson codeJson2 = new CodeJson(codeableConceptField2, codeableConceptId2);
|
CodeJson codeJson2 = new CodeJson(codeableConceptField2, codeableConceptId2);
|
||||||
String codeJson2Document = ourMapperNonPrettyPrint.writeValueAsString(codeJson2);
|
String codeJson2Document = ourMapperNonPrettyPrint.writeValueAsString(codeJson2);
|
||||||
|
|
||||||
|
@ -357,12 +351,12 @@ public class LastNElasticsearchSvcMultipleObservationsIT {
|
||||||
observationJson.setCategories(categoryConcepts1);
|
observationJson.setCategories(categoryConcepts1);
|
||||||
observationJson.setCode(codeableConceptField1);
|
observationJson.setCode(codeableConceptField1);
|
||||||
observationJson.setCode_concept_id(codeableConceptId1);
|
observationJson.setCode_concept_id(codeableConceptId1);
|
||||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.CODE_INDEX, codeableConceptId1, codeJson1Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX, codeableConceptId1, codeJson1Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
||||||
} else {
|
} else {
|
||||||
observationJson.setCategories(categoryConcepts2);
|
observationJson.setCategories(categoryConcepts2);
|
||||||
observationJson.setCode(codeableConceptField2);
|
observationJson.setCode(codeableConceptField2);
|
||||||
observationJson.setCode_concept_id(codeableConceptId2);
|
observationJson.setCode_concept_id(codeableConceptId2);
|
||||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.CODE_INDEX, codeableConceptId2, codeJson2Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX, codeableConceptId2, codeJson2Document, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
Calendar observationDate = new GregorianCalendar();
|
Calendar observationDate = new GregorianCalendar();
|
||||||
|
|
|
@ -1,27 +1,37 @@
|
||||||
package ca.uhn.fhir.jpa.search.lastn;
|
package ca.uhn.fhir.jpa.search.lastn;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.model.util.CodeSystemHash;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.config.TestElasticsearchConfig;
|
import ca.uhn.fhir.jpa.search.lastn.config.TestElasticsearchConfig;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
import ca.uhn.fhir.jpa.search.lastn.json.CodeJson;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.json.ObservationJson;
|
import ca.uhn.fhir.jpa.search.lastn.json.ObservationJson;
|
||||||
import ca.uhn.fhir.jpa.search.lastn.util.CodeSystemHash;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
import org.junit.*;
|
import org.junit.After;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -68,12 +78,6 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
final String CODEFIRSTCODINGSYSTEM = "http://mycodes.org/fhir/observation-code";
|
final String CODEFIRSTCODINGSYSTEM = "http://mycodes.org/fhir/observation-code";
|
||||||
final String CODEFIRSTCODINGCODE = "test-code";
|
final String CODEFIRSTCODINGCODE = "test-code";
|
||||||
final String CODEFIRSTCODINGDISPLAY = "test-code display";
|
final String CODEFIRSTCODINGDISPLAY = "test-code display";
|
||||||
// final String CODESECONDCODINGSYSTEM = "http://myalternatecodes.org/fhir/observation-code";
|
|
||||||
// final String CODESECONDCODINGCODE = "test-alt-code";
|
|
||||||
// final String CODESECONDCODINGDISPLAY = "test-alt-code display";
|
|
||||||
// final String CODETHIRDCODINGSYSTEM = "http://mysecondaltcodes.org/fhir/observation-code";
|
|
||||||
// final String CODETHIRDCODINGCODE = "test-second-alt-code";
|
|
||||||
// final String CODETHIRDCODINGDISPLAY = "test-second-alt-code display";
|
|
||||||
|
|
||||||
final FhirContext myFhirContext = FhirContext.forR4();
|
final FhirContext myFhirContext = FhirContext.forR4();
|
||||||
|
|
||||||
|
@ -89,7 +93,7 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
@After
|
@After
|
||||||
public void after() throws IOException {
|
public void after() throws IOException {
|
||||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_INDEX);
|
||||||
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.CODE_INDEX);
|
elasticsearchSvc.deleteAllDocuments(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -209,32 +213,6 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
String code_concept_text_values = observation.getCode_concept_text();
|
String code_concept_text_values = observation.getCode_concept_text();
|
||||||
assertEquals(OBSERVATIONCODETEXT, code_concept_text_values);
|
assertEquals(OBSERVATIONCODETEXT, code_concept_text_values);
|
||||||
|
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
/*
|
|
||||||
List<String> code_coding_systems = observation.getCode_coding_system();
|
|
||||||
assertEquals(3,code_coding_systems.size());
|
|
||||||
assertEquals(CODEFIRSTCODINGSYSTEM, code_coding_systems.get(0));
|
|
||||||
assertEquals(CODESECONDCODINGSYSTEM, code_coding_systems.get(1));
|
|
||||||
assertEquals(CODETHIRDCODINGSYSTEM, code_coding_systems.get(2));
|
|
||||||
|
|
||||||
List<String> code_coding_codes = observation.getCode_coding_code();
|
|
||||||
assertEquals(3, code_coding_codes.size());
|
|
||||||
assertEquals(CODEFIRSTCODINGCODE, code_coding_codes.get(0));
|
|
||||||
assertEquals(CODESECONDCODINGCODE, code_coding_codes.get(1));
|
|
||||||
assertEquals(CODETHIRDCODINGCODE, code_coding_codes.get(2));
|
|
||||||
|
|
||||||
List<String> code_coding_display = observation.getCode_coding_display();
|
|
||||||
assertEquals(3, code_coding_display.size());
|
|
||||||
assertEquals(CODEFIRSTCODINGDISPLAY, code_coding_display.get(0));
|
|
||||||
assertEquals(CODESECONDCODINGDISPLAY, code_coding_display.get(1));
|
|
||||||
assertEquals(CODETHIRDCODINGDISPLAY, code_coding_display.get(2));
|
|
||||||
|
|
||||||
List<String> code_coding_code_system_hash = observation.getCode_coding_code_system_hash();
|
|
||||||
assertEquals(3, code_coding_code_system_hash.size());
|
|
||||||
assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE)), code_coding_code_system_hash.get(0));
|
|
||||||
assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODESECONDCODINGSYSTEM, CODESECONDCODINGCODE)), code_coding_code_system_hash.get(1));
|
|
||||||
assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODETHIRDCODINGSYSTEM, CODETHIRDCODINGCODE)), code_coding_code_system_hash.get(2));
|
|
||||||
*/
|
|
||||||
String code_coding_systems = observation.getCode_coding_system();
|
String code_coding_systems = observation.getCode_coding_system();
|
||||||
assertEquals(CODEFIRSTCODINGSYSTEM, code_coding_systems);
|
assertEquals(CODEFIRSTCODINGSYSTEM, code_coding_systems);
|
||||||
|
|
||||||
|
@ -258,36 +236,20 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
assertEquals(OBSERVATIONCODETEXT, persistedCodeConceptText);
|
assertEquals(OBSERVATIONCODETEXT, persistedCodeConceptText);
|
||||||
|
|
||||||
List<String> persistedCodeCodingSystems = persistedObservationCode.getCoding_system();
|
List<String> persistedCodeCodingSystems = persistedObservationCode.getCoding_system();
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
// assertEquals(3,persistedCodeCodingSystems.size());
|
|
||||||
assertEquals(1, persistedCodeCodingSystems.size());
|
assertEquals(1, persistedCodeCodingSystems.size());
|
||||||
assertEquals(CODEFIRSTCODINGSYSTEM, persistedCodeCodingSystems.get(0));
|
assertEquals(CODEFIRSTCODINGSYSTEM, persistedCodeCodingSystems.get(0));
|
||||||
// assertEquals(CODESECONDCODINGSYSTEM, persistedCodeCodingSystems.get(1));
|
|
||||||
// assertEquals(CODETHIRDCODINGSYSTEM, persistedCodeCodingSystems.get(2));
|
|
||||||
|
|
||||||
List<String> persistedCodeCodingCodes = persistedObservationCode.getCoding_code();
|
List<String> persistedCodeCodingCodes = persistedObservationCode.getCoding_code();
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
// assertEquals(3, persistedCodeCodingCodes.size());
|
|
||||||
assertEquals(1, persistedCodeCodingCodes.size());
|
assertEquals(1, persistedCodeCodingCodes.size());
|
||||||
assertEquals(CODEFIRSTCODINGCODE, persistedCodeCodingCodes.get(0));
|
assertEquals(CODEFIRSTCODINGCODE, persistedCodeCodingCodes.get(0));
|
||||||
// assertEquals(CODESECONDCODINGCODE, persistedCodeCodingCodes.get(1));
|
|
||||||
// assertEquals(CODETHIRDCODINGCODE, persistedCodeCodingCodes.get(2));
|
|
||||||
|
|
||||||
List<String> persistedCodeCodingDisplays = persistedObservationCode.getCoding_display();
|
List<String> persistedCodeCodingDisplays = persistedObservationCode.getCoding_display();
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
// assertEquals(3, persistedCodeCodingDisplays.size());
|
|
||||||
assertEquals(1, persistedCodeCodingDisplays.size());
|
assertEquals(1, persistedCodeCodingDisplays.size());
|
||||||
assertEquals(CODEFIRSTCODINGDISPLAY, persistedCodeCodingDisplays.get(0));
|
assertEquals(CODEFIRSTCODINGDISPLAY, persistedCodeCodingDisplays.get(0));
|
||||||
// assertEquals(CODESECONDCODINGDISPLAY, persistedCodeCodingDisplays.get(1));
|
|
||||||
// assertEquals(CODETHIRDCODINGDISPLAY, persistedCodeCodingDisplays.get(2));
|
|
||||||
|
|
||||||
List<String> persistedCodeCodingCodeSystemHashes = persistedObservationCode.getCoding_code_system_hash();
|
List<String> persistedCodeCodingCodeSystemHashes = persistedObservationCode.getCoding_code_system_hash();
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
// assertEquals(3, persistedCodeCodingCodeSystemHashes.size());
|
|
||||||
assertEquals(1, persistedCodeCodingCodeSystemHashes.size());
|
assertEquals(1, persistedCodeCodingCodeSystemHashes.size());
|
||||||
assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE)), persistedCodeCodingCodeSystemHashes.get(0));
|
assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE)), persistedCodeCodingCodeSystemHashes.get(0));
|
||||||
// assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODESECONDCODINGSYSTEM, CODESECONDCODINGCODE)), persistedCodeCodingCodeSystemHashes.get(1));
|
|
||||||
// assertEquals(String.valueOf(CodeSystemHash.hashCodeSystem(CODETHIRDCODINGSYSTEM, CODETHIRDCODINGCODE)), persistedCodeCodingCodeSystemHashes.get(2));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -330,9 +292,6 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
indexedObservation.setCode_concept_id(OBSERVATIONSINGLECODEID);
|
indexedObservation.setCode_concept_id(OBSERVATIONSINGLECODEID);
|
||||||
CodeableConcept codeableConceptField = new CodeableConcept().setText(OBSERVATIONCODETEXT);
|
CodeableConcept codeableConceptField = new CodeableConcept().setText(OBSERVATIONCODETEXT);
|
||||||
codeableConceptField.addCoding(new Coding(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE, CODEFIRSTCODINGDISPLAY));
|
codeableConceptField.addCoding(new Coding(CODEFIRSTCODINGSYSTEM, CODEFIRSTCODINGCODE, CODEFIRSTCODINGDISPLAY));
|
||||||
// TODO: Temporary changes until find a solution for addressing Observation Code with multiple codings.
|
|
||||||
// codeableConceptField.addCoding(new Coding(CODESECONDCODINGSYSTEM, CODESECONDCODINGCODE, CODESECONDCODINGDISPLAY));
|
|
||||||
// codeableConceptField.addCoding(new Coding(CODETHIRDCODINGSYSTEM, CODETHIRDCODINGCODE, CODETHIRDCODINGDISPLAY));
|
|
||||||
indexedObservation.setCode(codeableConceptField);
|
indexedObservation.setCode(codeableConceptField);
|
||||||
|
|
||||||
String observationDocument = ourMapperNonPrettyPrint.writeValueAsString(indexedObservation);
|
String observationDocument = ourMapperNonPrettyPrint.writeValueAsString(indexedObservation);
|
||||||
|
@ -340,7 +299,7 @@ public class LastNElasticsearchSvcSingleObservationIT {
|
||||||
|
|
||||||
CodeJson observationCode = new CodeJson(codeableConceptField, OBSERVATIONSINGLECODEID);
|
CodeJson observationCode = new CodeJson(codeableConceptField, OBSERVATIONSINGLECODEID);
|
||||||
String codeDocument = ourMapperNonPrettyPrint.writeValueAsString(observationCode);
|
String codeDocument = ourMapperNonPrettyPrint.writeValueAsString(observationCode);
|
||||||
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.CODE_INDEX, OBSERVATIONSINGLECODEID, codeDocument, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
assertTrue(elasticsearchSvc.performIndex(ElasticsearchSvcImpl.OBSERVATION_CODE_INDEX, OBSERVATIONSINGLECODEID, codeDocument, ElasticsearchSvcImpl.CODE_DOCUMENT_TYPE));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000L);
|
Thread.sleep(1000L);
|
||||||
|
|
|
@ -47,9 +47,4 @@ public class TestElasticsearchConfig {
|
||||||
return embeddedElastic;
|
return embeddedElastic;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @PreDestroy
|
|
||||||
// public void stop() {
|
|
||||||
// embeddedElasticSearch().stop();
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,9 @@ public class ObservationIndexedCodeCodeableConceptEntity {
|
||||||
@Column(name = "CODEABLE_CONCEPT_TEXT", nullable = true, length = MAX_LENGTH)
|
@Column(name = "CODEABLE_CONCEPT_TEXT", nullable = true, length = MAX_LENGTH)
|
||||||
private String myCodeableConceptText;
|
private String myCodeableConceptText;
|
||||||
|
|
||||||
// TODO: Make coding a Collection. Need to first figure out how to maintain this over time.
|
|
||||||
@IndexedEmbedded(depth=2, prefix = "coding")
|
@IndexedEmbedded(depth=2, prefix = "coding")
|
||||||
// @OneToMany(mappedBy = "myCodeableConceptId", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
|
||||||
@JoinColumn(name = "CODEABLE_CONCEPT_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_CONCEPT_CODE"))
|
@JoinColumn(name = "CODEABLE_CONCEPT_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_CONCEPT_CODE"))
|
||||||
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||||
// private Set<ObservationIndexedCodeCodingEntity> myObservationIndexedCodeCodingEntitySet;
|
|
||||||
private ObservationIndexedCodeCodingEntity myObservationIndexedCodeCodingEntity;
|
private ObservationIndexedCodeCodingEntity myObservationIndexedCodeCodingEntity;
|
||||||
|
|
||||||
public ObservationIndexedCodeCodeableConceptEntity() {
|
public ObservationIndexedCodeCodeableConceptEntity() {
|
||||||
|
@ -42,10 +39,6 @@ public class ObservationIndexedCodeCodeableConceptEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCoding(ObservationIndexedCodeCodingEntity theObservationIndexedCodeCodingEntity) {
|
public void addCoding(ObservationIndexedCodeCodingEntity theObservationIndexedCodeCodingEntity) {
|
||||||
// if (myObservationIndexedCodeCodingEntitySet == null) {
|
|
||||||
// myObservationIndexedCodeCodingEntitySet = new HashSet<>();
|
|
||||||
// }
|
|
||||||
// myObservationIndexedCodeCodingEntitySet.add(theObservationIndexedCodeCodingEntity);
|
|
||||||
myObservationIndexedCodeCodingEntity = theObservationIndexedCodeCodingEntity;
|
myObservationIndexedCodeCodingEntity = theObservationIndexedCodeCodingEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +58,4 @@ public class ObservationIndexedCodeCodeableConceptEntity {
|
||||||
myCodeableConceptText = theCodeableConceptText;
|
myCodeableConceptText = theCodeableConceptText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,36 +13,31 @@ public class ObservationIndexedCodeCodingEntity {
|
||||||
|
|
||||||
public static final int MAX_LENGTH = 200;
|
public static final int MAX_LENGTH = 200;
|
||||||
|
|
||||||
// TODO: Fix this to allow multiple codings for observation code
|
|
||||||
// @Id
|
|
||||||
// @SequenceGenerator(name = "SEQ_CODING_FIELD", sequenceName = "SEQ_CODING_FIELD")
|
|
||||||
// @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODING_FIELD")
|
|
||||||
// private Long myId;
|
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="CODEABLE_CONCEPT_ID", length = MAX_LENGTH)
|
@Column(name = "CODEABLE_CONCEPT_ID", length = MAX_LENGTH)
|
||||||
private String myCodeableConceptId;
|
private String myCodeableConceptId;
|
||||||
|
|
||||||
@Field (name = "code", analyze = Analyze.NO)
|
@Field(name = "code", analyze = Analyze.NO)
|
||||||
private String myCode;
|
private String myCode;
|
||||||
|
|
||||||
@Field (name = "system", analyze = Analyze.NO)
|
@Field(name = "system", analyze = Analyze.NO)
|
||||||
private String mySystem;
|
private String mySystem;
|
||||||
|
|
||||||
@Field (name = "code_system_hash", analyze = Analyze.NO)
|
@Field(name = "code_system_hash", analyze = Analyze.NO)
|
||||||
private String myCodeSystemHash;
|
private String myCodeSystemHash;
|
||||||
|
|
||||||
@Field (name = "display")
|
@Field(name = "display")
|
||||||
private String myDisplay;
|
private String myDisplay;
|
||||||
|
|
||||||
public ObservationIndexedCodeCodingEntity() {}
|
public ObservationIndexedCodeCodingEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
public ObservationIndexedCodeCodingEntity(String theSystem, String theCode, String theDisplay, String theCodeableConceptId) {
|
public ObservationIndexedCodeCodingEntity(String theSystem, String theCode, String theDisplay, String theCodeableConceptId) {
|
||||||
myCode = theCode;
|
myCode = theCode;
|
||||||
mySystem = theSystem;
|
mySystem = theSystem;
|
||||||
myCodeSystemHash = String.valueOf(CodeSystemHash.hashCodeSystem(theSystem, theCode));
|
myCodeSystemHash = String.valueOf(CodeSystemHash.hashCodeSystem(theSystem, theCode));
|
||||||
myDisplay = theDisplay;
|
myDisplay = theDisplay;
|
||||||
myCodeableConceptId = theCodeableConceptId;
|
myCodeableConceptId = theCodeableConceptId;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,32 +10,47 @@ public class LastNParameterHelper {
|
||||||
if (theParamName == null) {
|
if (theParamName == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (theContext.getVersion().getVersion() == FhirVersionEnum.R5) {
|
|
||||||
if (theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_PATIENT)
|
FhirVersionEnum version = theContext.getVersion().getVersion();
|
||||||
|| theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_CODE)) {
|
|
||||||
return true;
|
if (isR5(version) && isLastNParameterR5(theParamName)) {
|
||||||
} else {
|
return true;
|
||||||
return false;
|
} else if (isR4(version) && isLastNParameterR4(theParamName)) {
|
||||||
}
|
return true;
|
||||||
} else if (theContext.getVersion().getVersion() == FhirVersionEnum.R4) {
|
} else if (isDstu3(version) && isLastNParameterDstu3(theParamName)) {
|
||||||
if (theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_PATIENT)
|
return true;
|
||||||
|| theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_CODE)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
|
|
||||||
if (theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_PATIENT)
|
|
||||||
|| theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_CODE)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidRequestException("$lastn operation is not implemented for FHIR Version " + theContext.getVersion().getVersion().getFhirVersionString());
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isDstu3(FhirVersionEnum theVersion) {
|
||||||
|
return (theVersion == FhirVersionEnum.DSTU3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isR4(FhirVersionEnum theVersion) {
|
||||||
|
return (theVersion == FhirVersionEnum.R4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isR5(FhirVersionEnum theVersion) {
|
||||||
|
return (theVersion == FhirVersionEnum.R5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isLastNParameterDstu3(String theParamName) {
|
||||||
|
return (theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_PATIENT)
|
||||||
|
|| theParamName.equals(org.hl7.fhir.dstu3.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_CODE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isLastNParameterR4(String theParamName) {
|
||||||
|
return (theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_PATIENT)
|
||||||
|
|| theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.r4.model.Observation.SP_CODE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isLastNParameterR5(String theParamName) {
|
||||||
|
return (theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_SUBJECT) || theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_PATIENT)
|
||||||
|
|| theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_CATEGORY) || theParamName.equals(org.hl7.fhir.r5.model.Observation.SP_CODE));
|
||||||
|
}
|
||||||
|
|
||||||
public static String getSubjectParamName(FhirContext theContext) {
|
public static String getSubjectParamName(FhirContext theContext) {
|
||||||
if (theContext.getVersion().getVersion() == FhirVersionEnum.R5) {
|
if (theContext.getVersion().getVersion() == FhirVersionEnum.R5) {
|
||||||
return org.hl7.fhir.r5.model.Observation.SP_SUBJECT;
|
return org.hl7.fhir.r5.model.Observation.SP_SUBJECT;
|
||||||
|
|
Loading…
Reference in New Issue