Always apply vs filters correctly (#2195)
* Always apply valueset filters correctly * Test fix * Testfix * Test fix * Add changelog * Test fix
This commit is contained in:
parent
702cc7762d
commit
fb8658da70
|
@ -93,4 +93,10 @@ public class ValueSetExpansionOptions {
|
|||
myFailOnMissingCodeSystem = theFailOnMissingCodeSystem;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static ValueSetExpansionOptions forOffsetAndCount(int theOffset, int theCount) {
|
||||
return new ValueSetExpansionOptions()
|
||||
.setOffset(theOffset)
|
||||
.setCount(theCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2195
|
||||
title: "When performing a ValueSet expansion with a filter a large pre-expanded
|
||||
ValueSet (more than 1000 codes), the filter failed to find concepts appearing
|
||||
after the first thousand. This has been corrected."
|
|
@ -34,7 +34,7 @@ public interface ITermValueSetConceptViewDao extends JpaRepository<TermValueSetC
|
|||
@Query("SELECT v FROM TermValueSetConceptView v WHERE v.myConceptValueSetPid = :pid AND v.myConceptOrder >= :from AND v.myConceptOrder < :to ORDER BY v.myConceptOrder")
|
||||
List<TermValueSetConceptView> findByTermValueSetId(@Param("from") int theFrom, @Param("to") int theTo, @Param("pid") Long theValueSetId);
|
||||
|
||||
@Query("SELECT v FROM TermValueSetConceptView v WHERE v.myConceptValueSetPid = :pid AND v.myConceptDisplay LIKE :display ORDER BY v.myConceptOrder")
|
||||
@Query("SELECT v FROM TermValueSetConceptView v WHERE v.myConceptValueSetPid = :pid AND LOWER(v.myConceptDisplay) LIKE :display ORDER BY v.myConceptOrder")
|
||||
List<TermValueSetConceptView> findByTermValueSetId(@Param("pid") Long theValueSetId, @Param("display") String theDisplay);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
|
||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
|
@ -31,216 +30,60 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
|||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import org.hl7.fhir.convertors.conv30_40.ValueSet30_40;
|
||||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoValueSetR4.validateHaveExpansionOrThrowInternalErrorException;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet;
|
||||
|
||||
public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
myValidationSupport = getApplicationContext().getBean(IValidationSupport.class, "myJpaValidationSupportChain");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
ValueSet source = read(theId, theRequestDetails);
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
|
||||
return expand(source, theFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
|
||||
ValueSet source = read(theId, theRequestDetails);
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
|
||||
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
|
||||
return expand(source, theFilter, theOffset, theCount);
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource) {
|
||||
validateIncludes("include", theSource.getCompose().getInclude());
|
||||
validateIncludes("exclude", theSource.getCompose().getExclude());
|
||||
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource, int theOffset, int theCount) {
|
||||
validateIncludes("include", theSource.getCompose().getInclude());
|
||||
validateIncludes("exclude", theSource.getCompose().getExclude());
|
||||
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setOffset(theOffset)
|
||||
.setCount(theCount);
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), options, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
}
|
||||
|
||||
private void validateIncludes(String name, List<ConceptSetComponent> listToValidate) {
|
||||
for (ConceptSetComponent nextExclude : listToValidate) {
|
||||
if (isBlank(nextExclude.getSystem()) && nextExclude.getValueSet().isEmpty() && !ElementUtil.isEmpty(nextExclude.getConcept(), nextExclude.getFilter())) {
|
||||
throw new InvalidRequestException("ValueSet contains " + name + " criteria with no system defined");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
return doExpand(source);
|
||||
|
||||
// if (defaultValueSet != null) {
|
||||
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
|
||||
// } else {
|
||||
// IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri));
|
||||
// if (ids.size() == 0) {
|
||||
// throw new InvalidRequestException("Unknown ValueSet URI: " + theUri);
|
||||
// }
|
||||
// source = (ValueSet) ids.getResources(0, 1).get(0);
|
||||
// }
|
||||
//
|
||||
// return expand(defaultValueSet, theFilter);
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
return doExpand(source, theOffset, theCount);
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter) {
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
|
||||
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
|
||||
// for (UriType next : theSource.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
toExpand.setId(theSource.getId());
|
||||
toExpand.setUrl(theSource.getUrl());
|
||||
if (theSource.getVersion() != null) {
|
||||
toExpand.setVersion(theSource.getVersion());
|
||||
}
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand, theOffset, theCount);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void applyFilter(IntegerType theTotalElement, List<ValueSetExpansionContainsComponent> theContains, String theFilter) {
|
||||
|
||||
for (int idx = 0; idx < theContains.size(); idx++) {
|
||||
ValueSetExpansionContainsComponent next = theContains.get(idx);
|
||||
if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
|
||||
theContains.remove(idx);
|
||||
idx--;
|
||||
if (theTotalElement.getValue() != null) {
|
||||
theTotalElement.setValue(theTotalElement.getValue() - 1);
|
||||
}
|
||||
}
|
||||
applyFilter(theTotalElement, next.getContains(), theFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
|
||||
if (ElementUtil.isEmpty(include.getConcept())) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
|
||||
}
|
||||
}
|
||||
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
|
||||
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -205,7 +205,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
*/
|
||||
|
||||
if (modifier == TokenParamModifier.IN) {
|
||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
||||
codes.addAll(myTerminologySvc.expandValueSetIntoConceptList(null, code));
|
||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||
|
@ -273,7 +273,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
|||
String valueSet = valueSetUris.iterator().next();
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setFailOnMissingCodeSystem(false);
|
||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(options, valueSet);
|
||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSetIntoConceptList(options, valueSet);
|
||||
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
||||
if (nextCandidate.getCode().equals(code)) {
|
||||
retVal = nextCandidate.getSystem();
|
||||
|
|
|
@ -21,48 +21,28 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateCodeOptions;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
myValidationSupport = getApplicationContext().getBean(IValidationSupport.class, "myJpaValidationSupportChain");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
ValueSet source = read(theId, theRequestDetails);
|
||||
|
@ -75,156 +55,26 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
|
|||
return expand(source, theFilter, theOffset, theCount);
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource) {
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource, int theOffset, int theCount) {
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setOffset(theOffset)
|
||||
.setCount(theCount);
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), options, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
return doExpand(source);
|
||||
|
||||
// if (defaultValueSet != null) {
|
||||
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
|
||||
// } else {
|
||||
// IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri));
|
||||
// if (ids.size() == 0) {
|
||||
// throw new InvalidRequestException("Unknown ValueSet URI: " + theUri);
|
||||
// }
|
||||
// source = (ValueSet) ids.getResources(0, 1).get(0);
|
||||
// }
|
||||
//
|
||||
// return expand(defaultValueSet, theFilter);
|
||||
return myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
return doExpand(source, theOffset, theCount);
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
return myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
|
||||
// for (UriType next : theSource.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return myTerminologySvc.expandValueSet(null, theSource, theFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
toExpand.setId(theSource.getId());
|
||||
toExpand.setUrl(theSource.getUrl());
|
||||
if (theSource.getVersion() != null) {
|
||||
toExpand.setVersion(theSource.getVersion());
|
||||
}
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand, theOffset, theCount);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void applyFilter(IntegerType theTotalElement, List<ValueSetExpansionContainsComponent> theContains, String theFilter) {
|
||||
|
||||
for (int idx = 0; idx < theContains.size(); idx++) {
|
||||
ValueSetExpansionContainsComponent next = theContains.get(idx);
|
||||
if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
|
||||
theContains.remove(idx);
|
||||
idx--;
|
||||
if (theTotalElement.getValue() != null) {
|
||||
theTotalElement.setValue(theTotalElement.getValue() - 1);
|
||||
}
|
||||
}
|
||||
applyFilter(theTotalElement, next.getContains(), theFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
|
||||
if (ElementUtil.isEmpty(include.getConcept())) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty(JpaConstants.VALUESET_FILTER_DISPLAY).setOp(FilterOperator.EQUAL).setValue(theFilter);
|
||||
}
|
||||
}
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
return myTerminologySvc.expandValueSet(options, theSource, theFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,47 +21,28 @@ package ca.uhn.fhir.jpa.dao.r5;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import org.hl7.fhir.convertors.conv40_50.ValueSet40_50;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.Enumerations;
|
||||
import org.hl7.fhir.r5.model.IntegerType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateCodeOptions;
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoValueSetR4.validateHaveExpansionOrThrowInternalErrorException;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
myValidationSupport = getApplicationContext().getBean(IValidationSupport.class,"myJpaValidationSupportChain" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
ValueSet source = read(theId, theRequestDetails);
|
||||
|
@ -74,157 +55,32 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
|
|||
return expand(source, theFilter, theOffset, theCount);
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource) {
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource, int theOffset, int theCount) {
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setOffset(theOffset)
|
||||
.setCount(theCount);
|
||||
IValidationSupport.ValueSetExpansionOutcome retVal = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), options, theSource);
|
||||
validateHaveExpansionOrThrowInternalErrorException(retVal);
|
||||
return (ValueSet) retVal.getValueSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(Enumerations.FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
ValueSet retVal = doExpand(source);
|
||||
return retVal;
|
||||
|
||||
// if (defaultValueSet != null) {
|
||||
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
|
||||
// } else {
|
||||
// IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri));
|
||||
// if (ids.size() == 0) {
|
||||
// throw new InvalidRequestException("Unknown ValueSet URI: " + theUri);
|
||||
// }
|
||||
// source = (ValueSet) ids.getResources(0, 1).get(0);
|
||||
// }
|
||||
//
|
||||
// return expand(defaultValueSet, theFilter);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
source.setUrl(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetFilterComponent filter = source.getCompose().addInclude().addValueSet(theUri).addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(Enumerations.FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
} else {
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
}
|
||||
|
||||
return doExpand(source, theOffset, theCount);
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
|
||||
// for (UriType next : theSource.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
|
||||
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
toExpand.setId(theSource.getId());
|
||||
toExpand.setUrl(theSource.getUrl());
|
||||
if (theSource.getVersion() != null) {
|
||||
toExpand.setVersion(theSource.getVersion());
|
||||
}
|
||||
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(theSource.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand, theOffset, theCount);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void applyFilter(IntegerType theTotalElement, List<ValueSetExpansionContainsComponent> theContains, String theFilter) {
|
||||
|
||||
for (int idx = 0; idx < theContains.size(); idx++) {
|
||||
ValueSetExpansionContainsComponent next = theContains.get(idx);
|
||||
if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
|
||||
theContains.remove(idx);
|
||||
idx--;
|
||||
if (theTotalElement.getValue() != null) {
|
||||
theTotalElement.setValue(theTotalElement.getValue() - 1);
|
||||
}
|
||||
}
|
||||
applyFilter(theTotalElement, next.getContains(), theFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
|
||||
if (ElementUtil.isEmpty(include.getConcept())) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty("display").setOp(Enumerations.FilterOperator.EQUAL).setValue(theFilter);
|
||||
}
|
||||
}
|
||||
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
|
||||
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
|
||||
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -154,7 +154,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
|||
*/
|
||||
|
||||
if (modifier == TokenParamModifier.IN) {
|
||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
||||
codes.addAll(myTerminologySvc.expandValueSetIntoConceptList(null, code));
|
||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||
|
@ -228,7 +228,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
|||
String valueSet = valueSetUris.iterator().next();
|
||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||
.setFailOnMissingCodeSystem(false);
|
||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(options, valueSet);
|
||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSetIntoConceptList(options, valueSet);
|
||||
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
||||
if (nextCandidate.getCode().equals(code)) {
|
||||
retVal = nextCandidate.getSystem();
|
||||
|
|
|
@ -67,6 +67,7 @@ import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
|||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||
|
@ -183,6 +184,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.lowerCase;
|
||||
|
||||
public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||
public static final int DEFAULT_FETCH_SIZE = 250;
|
||||
|
@ -394,25 +396,44 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
|
||||
|
||||
@Override
|
||||
public List<FhirVersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet) {
|
||||
ExpansionFilter expansionFilter = ExpansionFilter.NO_FILTER;
|
||||
return expandValueSet(theExpansionOptions, theValueSet, expansionFilter);
|
||||
}
|
||||
|
||||
private List<FhirVersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet, ExpansionFilter theExpansionFilter) {
|
||||
@Transactional
|
||||
public List<FhirVersionIndependentConcept> expandValueSetIntoConceptList(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl) {
|
||||
String expansionFilter = null;
|
||||
// TODO: DM 2019-09-10 - This is problematic because an incorrect URL that matches ValueSet.id will not be found in the terminology tables but will yield a ValueSet here. Depending on the ValueSet, the expansion may time-out.
|
||||
|
||||
ValueSet valueSet = fetchCanonicalValueSetFromCompleteContext(theValueSet);
|
||||
ValueSet expanded = expandValueSet(theExpansionOptions, theValueSetCanonicalUrl, expansionFilter);
|
||||
|
||||
ArrayList<FhirVersionIndependentConcept> retVal = new ArrayList<>();
|
||||
for (ValueSet.ValueSetExpansionContainsComponent nextContains : expanded.getExpansion().getContains()) {
|
||||
retVal.add(new FhirVersionIndependentConcept(nextContains.getSystem(), nextContains.getCode(), nextContains.getDisplay(), nextContains.getVersion()));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl, @Nullable String theExpansionFilter) {
|
||||
ValueSet valueSet = fetchCanonicalValueSetFromCompleteContext(theValueSetCanonicalUrl);
|
||||
if (valueSet == null) {
|
||||
throwInvalidValueSet(theValueSet);
|
||||
throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetCanonicalUrl));
|
||||
}
|
||||
|
||||
return expandValueSetAndReturnVersionIndependentConcepts(theExpansionOptions, valueSet, theExpansionFilter);
|
||||
return expandValueSet(theExpansionOptions, valueSet, theExpansionFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public ValueSet expandValueSet(ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand) {
|
||||
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand) {
|
||||
return expandValueSet(theExpansionOptions, theValueSetToExpand, (String) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand, @Nullable String theFilter) {
|
||||
return expandValueSet(theExpansionOptions, theValueSetToExpand, ExpansionFilter.fromFilterString(theFilter));
|
||||
}
|
||||
|
||||
private ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, ExpansionFilter theFilter) {
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSetToExpand, "ValueSet to expand can not be null");
|
||||
|
||||
ValueSetExpansionOptions expansionOptions = provideExpansionOptions(theExpansionOptions);
|
||||
|
@ -431,9 +452,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
accumulator.addParameter().setName("count").setValue(new IntegerType(count));
|
||||
}
|
||||
|
||||
ExpansionFilter filter = ExpansionFilter.NO_FILTER;
|
||||
|
||||
expandValueSetIntoAccumulator(theValueSetToExpand, theExpansionOptions, accumulator, filter, true);
|
||||
expandValueSetIntoAccumulator(theValueSetToExpand, theExpansionOptions, accumulator, theFilter, true);
|
||||
|
||||
if (accumulator.getTotalConcepts() != null) {
|
||||
accumulator.setTotal(accumulator.getTotalConcepts());
|
||||
|
@ -449,7 +469,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
|
||||
.setValue(new StringType(next));
|
||||
}
|
||||
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
|
@ -513,6 +532,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
boolean wasFilteredResult = false;
|
||||
if (!theFilter.getFilters().isEmpty() && JpaConstants.VALUESET_FILTER_DISPLAY.equals(theFilter.getFilters().get(0).getProperty()) && theFilter.getFilters().get(0).getOp() == ValueSet.FilterOperator.EQUAL) {
|
||||
String displayValue = theFilter.getFilters().get(0).getValue().replace("%", "[%]") + "%";
|
||||
displayValue = lowerCase(displayValue);
|
||||
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
|
||||
wasFilteredResult = true;
|
||||
} else {
|
||||
|
@ -675,7 +695,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
return theAction.get();
|
||||
}
|
||||
return myTxTemplate.execute(t->theAction.get());
|
||||
return myTxTemplate.execute(t -> theAction.get());
|
||||
}
|
||||
|
||||
private String getValueSetInfo(ValueSet theValueSet) {
|
||||
|
@ -702,18 +722,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
protected List<FhirVersionIndependentConcept> expandValueSetAndReturnVersionIndependentConcepts(ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpandR4, @Nonnull ExpansionFilter theExpansionFilter) {
|
||||
int maxCapacity = myDaoConfig.getMaximumExpansionSize();
|
||||
ValueSetExpansionComponentWithConceptAccumulator accumulator = new ValueSetExpansionComponentWithConceptAccumulator(myContext, maxCapacity);
|
||||
expandValueSet(theExpansionOptions, theValueSetToExpandR4, accumulator, theExpansionFilter);
|
||||
|
||||
ArrayList<FhirVersionIndependentConcept> retVal = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent nextContains : accumulator.getContains()) {
|
||||
retVal.add(new FhirVersionIndependentConcept(nextContains.getSystem(), nextContains.getCode(), nextContains.getDisplay(), nextContains.getVersion()));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if there are potentially more results to process.
|
||||
*/
|
||||
|
@ -938,12 +946,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
* DM 2019-08-21 - Processing slows after any ValueSets with many codes explicitly identified. This might
|
||||
* be due to the dark arts that is memory management. Will monitor but not do anything about this right now.
|
||||
*/
|
||||
BooleanQuery.setMaxClauseCount(10000);
|
||||
BooleanQuery.setMaxClauseCount(SearchBuilder.getMaximumPageSize());
|
||||
|
||||
StopWatch sw = new StopWatch();
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
int maxResultsPerBatch = 10000;
|
||||
int maxResultsPerBatch = SearchBuilder.getMaximumPageSize();
|
||||
|
||||
/*
|
||||
* If the accumulator is bounded, we may reduce the size of the query to
|
||||
|
@ -1395,7 +1403,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
}
|
||||
}
|
||||
|
||||
return createFailureCodeValidationResult(theSystem, theCode, " - Concept Display \"" + theDisplay + "\" does not match expected \"" + concepts.get(0).getDisplay() + "\"").setDisplay(concepts.get(0).getDisplay());
|
||||
return createFailureCodeValidationResult(theSystem, theCode, " - Concept Display \"" + theDisplay + "\" does not match expected \"" + concepts.get(0).getDisplay() + "\"").setDisplay(concepts.get(0).getDisplay());
|
||||
}
|
||||
|
||||
if (!concepts.isEmpty()) {
|
||||
|
@ -1424,7 +1432,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
int versionIndex = theSystem.indexOf("|");
|
||||
if (versionIndex >= 0) {
|
||||
String systemUrl = theSystem.substring(0, versionIndex);
|
||||
String systemVersion = theSystem.substring(versionIndex+1);
|
||||
String systemVersion = theSystem.substring(versionIndex + 1);
|
||||
optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCodeWithVersion(theResourcePid.getIdAsLong(), systemUrl, systemVersion, theCode);
|
||||
} else {
|
||||
optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCode(theResourcePid.getIdAsLong(), theSystem, theCode);
|
||||
|
@ -1526,7 +1534,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
|
||||
private String getUrlFromIdentifier(String theUri) {
|
||||
String retVal = theUri;
|
||||
if (StringUtils.isNotEmpty((theUri))){
|
||||
if (StringUtils.isNotEmpty((theUri))) {
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
if (versionSeparator != -1) {
|
||||
retVal = theUri.substring(0, versionSeparator);
|
||||
|
@ -1781,9 +1789,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
} else {
|
||||
String msg = myContext.getLocalizer().getMessage(
|
||||
BaseTermReadSvcImpl.class,
|
||||
"cannotCreateDuplicateConceptMapUrlAndVersion",
|
||||
conceptMapUrl, conceptMapVersion,
|
||||
existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
"cannotCreateDuplicateConceptMapUrlAndVersion",
|
||||
conceptMapUrl, conceptMapVersion,
|
||||
existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
throw new UnprocessableEntityException(msg);
|
||||
}
|
||||
}
|
||||
|
@ -1818,7 +1826,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
// We have a ValueSet to pre-expand.
|
||||
try {
|
||||
ValueSet valueSet = txTemplate.execute(t -> {
|
||||
TermValueSet refreshedValueSetToExpand = myValueSetDao.findById(valueSetToExpand.getId()).orElseThrow(()->new IllegalStateException("Unknown VS ID: " + valueSetToExpand.getId()));
|
||||
TermValueSet refreshedValueSetToExpand = myValueSetDao.findById(valueSetToExpand.getId()).orElseThrow(() -> new IllegalStateException("Unknown VS ID: " + valueSetToExpand.getId()));
|
||||
return getValueSetFromResourceTable(refreshedValueSetToExpand.getResource());
|
||||
});
|
||||
assert valueSet != null;
|
||||
|
@ -1988,7 +1996,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
@Override
|
||||
@Transactional
|
||||
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB,
|
||||
IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
|
||||
IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB) {
|
||||
FhirVersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA);
|
||||
FhirVersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB);
|
||||
|
||||
|
@ -2002,7 +2010,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
|
||||
String codeASystemIdentifier;
|
||||
if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) {
|
||||
codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
|
||||
codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
|
||||
} else {
|
||||
codeASystemIdentifier = conceptA.getSystem();
|
||||
}
|
||||
|
@ -2342,7 +2350,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
|
||||
Pageable page = PageRequest.of(0, 1);
|
||||
List<TermConceptMap> theConceptMapList = myConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page,
|
||||
theTranslationRequest.getUrl().asStringValue());
|
||||
theTranslationRequest.getUrl().asStringValue());
|
||||
if (!theConceptMapList.isEmpty()) {
|
||||
return theConceptMapList.get(0).getVersion();
|
||||
}
|
||||
|
@ -2553,6 +2561,136 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
@Nullable
|
||||
protected abstract CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept);
|
||||
|
||||
@NotNull
|
||||
private FhirVersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theCodeSystemIdentifierType, IBaseCoding theCodingType) {
|
||||
String code = theCodeType != null ? theCodeType.getValueAsString() : null;
|
||||
String system = theCodeSystemIdentifierType != null ? getUrlFromIdentifier(theCodeSystemIdentifierType.getValueAsString()) : null;
|
||||
String systemVersion = theCodeSystemIdentifierType != null ? getVersionFromIdentifier(theCodeSystemIdentifierType.getValueAsString()) : null;
|
||||
if (theCodingType != null) {
|
||||
Coding canonicalizedCoding = toCanonicalCoding(theCodingType);
|
||||
assert canonicalizedCoding != null; // Shouldn't be null, since theCodingType isn't
|
||||
code = canonicalizedCoding.getCode();
|
||||
system = canonicalizedCoding.getSystem();
|
||||
systemVersion = canonicalizedCoding.getVersion();
|
||||
}
|
||||
return new FhirVersionIndependentConcept(system, code, null, systemVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CodeValidationResult codeSystemValidateCode(IIdType theCodeSystemId, String theCodeSystemUrl, String theVersion, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
|
||||
|
||||
CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConcept);
|
||||
boolean haveCodeableConcept = codeableConcept != null && codeableConcept.getCoding().size() > 0;
|
||||
|
||||
Coding coding = toCanonicalCoding(theCoding);
|
||||
boolean haveCoding = coding != null && coding.isEmpty() == false;
|
||||
|
||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||
|
||||
if (!haveCodeableConcept && !haveCoding && !haveCode) {
|
||||
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate.");
|
||||
}
|
||||
if (!LogicUtil.multiXor(haveCodeableConcept, haveCoding, haveCode)) {
|
||||
throw new InvalidRequestException("$validate-code can only validate (code) OR (coding) OR (codeableConcept)");
|
||||
}
|
||||
|
||||
boolean haveIdentifierParam = isNotBlank(theCodeSystemUrl);
|
||||
String codeSystemUrl;
|
||||
if (theCodeSystemId != null) {
|
||||
IBaseResource codeSystem = myDaoRegistry.getResourceDao("CodeSystem").read(theCodeSystemId);
|
||||
codeSystemUrl = CommonCodeSystemsTerminologyService.getCodeSystemUrl(codeSystem);
|
||||
} else if (haveIdentifierParam) {
|
||||
codeSystemUrl = theCodeSystemUrl;
|
||||
} else {
|
||||
throw new InvalidRequestException("Either CodeSystem ID or CodeSystem identifier must be provided. Unable to validate.");
|
||||
}
|
||||
|
||||
|
||||
String code = theCode;
|
||||
String display = theDisplay;
|
||||
|
||||
if (haveCodeableConcept) {
|
||||
for (int i = 0; i < codeableConcept.getCoding().size(); i++) {
|
||||
Coding nextCoding = codeableConcept.getCoding().get(i);
|
||||
if (nextCoding.hasSystem()) {
|
||||
if (!codeSystemUrl.equalsIgnoreCase(nextCoding.getSystem())) {
|
||||
throw new InvalidRequestException("Coding.system '" + nextCoding.getSystem() + "' does not equal with CodeSystem.url '" + theCodeSystemUrl + "'. Unable to validate.");
|
||||
}
|
||||
codeSystemUrl = nextCoding.getSystem();
|
||||
}
|
||||
code = nextCoding.getCode();
|
||||
display = nextCoding.getDisplay();
|
||||
CodeValidationResult nextValidation = codeSystemValidateCode(codeSystemUrl, theVersion, code, display);
|
||||
if (nextValidation.isOk() || i == codeableConcept.getCoding().size() - 1) {
|
||||
return nextValidation;
|
||||
}
|
||||
}
|
||||
} else if (haveCoding) {
|
||||
if (coding.hasSystem()) {
|
||||
if (!codeSystemUrl.equalsIgnoreCase(coding.getSystem())) {
|
||||
throw new InvalidRequestException("Coding.system '" + coding.getSystem() + "' does not equal with CodeSystem.url '" + theCodeSystemUrl + "'. Unable to validate.");
|
||||
}
|
||||
codeSystemUrl = coding.getSystem();
|
||||
}
|
||||
code = coding.getCode();
|
||||
display = coding.getDisplay();
|
||||
}
|
||||
|
||||
return codeSystemValidateCode(codeSystemUrl, theVersion, code, display);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CodeValidationResult codeSystemValidateCode(String theCodeSystemUrl, String theCodeSystemVersion, String theCode, String theDisplay) {
|
||||
|
||||
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<TermConcept> query = criteriaBuilder.createQuery(TermConcept.class);
|
||||
Root<TermConcept> root = query.from(TermConcept.class);
|
||||
|
||||
Fetch<TermCodeSystemVersion, TermConcept> systemVersionFetch = root.fetch("myCodeSystem", JoinType.INNER);
|
||||
Join<TermCodeSystemVersion, TermConcept> systemVersionJoin = (Join<TermCodeSystemVersion, TermConcept>) systemVersionFetch;
|
||||
Fetch<TermCodeSystem, TermCodeSystemVersion> systemFetch = systemVersionFetch.fetch("myCodeSystem", JoinType.INNER);
|
||||
Join<TermCodeSystem, TermCodeSystemVersion> systemJoin = (Join<TermCodeSystem, TermCodeSystemVersion>) systemFetch;
|
||||
|
||||
ArrayList<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
if (isNotBlank(theCode)) {
|
||||
predicates.add(criteriaBuilder.equal(root.get("myCode"), theCode));
|
||||
}
|
||||
|
||||
if (isNotBlank(theDisplay)) {
|
||||
predicates.add(criteriaBuilder.equal(root.get("myDisplay"), theDisplay));
|
||||
}
|
||||
|
||||
if (isNoneBlank(theCodeSystemUrl)) {
|
||||
predicates.add(criteriaBuilder.equal(systemJoin.get("myCodeSystemUri"), theCodeSystemUrl));
|
||||
}
|
||||
|
||||
if (isNoneBlank(theCodeSystemVersion)) {
|
||||
predicates.add(criteriaBuilder.equal(systemVersionJoin.get("myCodeSystemVersionId"), theCodeSystemVersion));
|
||||
} else {
|
||||
query.orderBy(criteriaBuilder.desc(root.get("myUpdated")));
|
||||
}
|
||||
|
||||
Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
query.where(outerPredicate);
|
||||
|
||||
final TypedQuery<TermConcept> typedQuery = myEntityManager.createQuery(query.select(root));
|
||||
org.hibernate.query.Query<TermConcept> hibernateQuery = (org.hibernate.query.Query<TermConcept>) typedQuery;
|
||||
hibernateQuery.setFetchSize(SINGLE_FETCH_SIZE);
|
||||
List<TermConcept> resultsList = hibernateQuery.getResultList();
|
||||
|
||||
if (!resultsList.isEmpty()) {
|
||||
TermConcept concept = resultsList.get(0);
|
||||
return new CodeValidationResult().setCode(concept.getCode()).setDisplay(concept.getDisplay());
|
||||
}
|
||||
|
||||
if (isBlank(theDisplay))
|
||||
return createFailureCodeValidationResult(theCodeSystemUrl, theCode);
|
||||
else
|
||||
return createFailureCodeValidationResult(theCodeSystemUrl, theCode, " - Concept Display : " + theDisplay);
|
||||
}
|
||||
|
||||
public static class Job implements HapiJob {
|
||||
@Autowired
|
||||
private ITermReadSvc myTerminologySvc;
|
||||
|
@ -2640,21 +2778,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
return termConcept;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private FhirVersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theCodeSystemIdentifierType, IBaseCoding theCodingType) {
|
||||
String code = theCodeType != null ? theCodeType.getValueAsString() : null;
|
||||
String system = theCodeSystemIdentifierType != null ? getUrlFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
|
||||
String systemVersion = theCodeSystemIdentifierType != null ? getVersionFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
|
||||
if (theCodingType != null) {
|
||||
Coding canonicalizedCoding = toCanonicalCoding(theCodingType);
|
||||
assert canonicalizedCoding != null; // Shouldn't be null, since theCodingType isn't
|
||||
code = canonicalizedCoding.getCode();
|
||||
system = canonicalizedCoding.getSystem();
|
||||
systemVersion = canonicalizedCoding.getVersion();
|
||||
}
|
||||
return new FhirVersionIndependentConcept(system, code, null, systemVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is present only for unit tests, do not call from client code
|
||||
*/
|
||||
|
@ -2686,120 +2809,4 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
static boolean isOurLastResultsFromTranslationWithReverseCache() {
|
||||
return ourLastResultsFromTranslationWithReverseCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CodeValidationResult codeSystemValidateCode(IIdType theCodeSystemId, String theCodeSystemUrl, String theVersion, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
|
||||
|
||||
CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConcept);
|
||||
boolean haveCodeableConcept = codeableConcept != null && codeableConcept.getCoding().size() > 0;
|
||||
|
||||
Coding coding = toCanonicalCoding(theCoding);
|
||||
boolean haveCoding = coding != null && coding.isEmpty() == false;
|
||||
|
||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||
|
||||
if (!haveCodeableConcept && !haveCoding && !haveCode) {
|
||||
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate.");
|
||||
}
|
||||
if (!LogicUtil.multiXor(haveCodeableConcept, haveCoding, haveCode)) {
|
||||
throw new InvalidRequestException("$validate-code can only validate (code) OR (coding) OR (codeableConcept)");
|
||||
}
|
||||
|
||||
boolean haveIdentifierParam = isNotBlank(theCodeSystemUrl);
|
||||
String codeSystemUrl;
|
||||
if (theCodeSystemId != null) {
|
||||
IBaseResource codeSystem = myDaoRegistry.getResourceDao("CodeSystem").read(theCodeSystemId);
|
||||
codeSystemUrl = CommonCodeSystemsTerminologyService.getCodeSystemUrl(codeSystem);
|
||||
} else if (haveIdentifierParam) {
|
||||
codeSystemUrl = theCodeSystemUrl;
|
||||
} else {
|
||||
throw new InvalidRequestException("Either CodeSystem ID or CodeSystem identifier must be provided. Unable to validate.");
|
||||
}
|
||||
|
||||
|
||||
String code = theCode;
|
||||
String display = theDisplay;
|
||||
|
||||
if (haveCodeableConcept) {
|
||||
for (int i = 0; i < codeableConcept.getCoding().size(); i++) {
|
||||
Coding nextCoding = codeableConcept.getCoding().get(i);
|
||||
if (nextCoding.hasSystem()) {
|
||||
if (!codeSystemUrl.equalsIgnoreCase(nextCoding.getSystem())) {
|
||||
throw new InvalidRequestException("Coding.system '" + nextCoding.getSystem() + "' does not equal with CodeSystem.url '" + theCodeSystemUrl + "'. Unable to validate.");
|
||||
}
|
||||
codeSystemUrl = nextCoding.getSystem();
|
||||
}
|
||||
code = nextCoding.getCode();
|
||||
display = nextCoding.getDisplay();
|
||||
CodeValidationResult nextValidation = codeSystemValidateCode(codeSystemUrl, theVersion, code, display);
|
||||
if (nextValidation.isOk() || i == codeableConcept.getCoding().size() - 1) {
|
||||
return nextValidation;
|
||||
}
|
||||
}
|
||||
} else if (haveCoding) {
|
||||
if (coding.hasSystem()) {
|
||||
if (!codeSystemUrl.equalsIgnoreCase(coding.getSystem())) {
|
||||
throw new InvalidRequestException("Coding.system '" + coding.getSystem() + "' does not equal with CodeSystem.url '" + theCodeSystemUrl + "'. Unable to validate.");
|
||||
}
|
||||
codeSystemUrl = coding.getSystem();
|
||||
}
|
||||
code = coding.getCode();
|
||||
display = coding.getDisplay();
|
||||
}
|
||||
|
||||
return codeSystemValidateCode(codeSystemUrl, theVersion, code, display);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CodeValidationResult codeSystemValidateCode(String theCodeSystemUrl, String theCodeSystemVersion, String theCode, String theDisplay) {
|
||||
|
||||
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<TermConcept> query = criteriaBuilder.createQuery(TermConcept.class);
|
||||
Root<TermConcept> root = query.from(TermConcept.class);
|
||||
|
||||
Fetch<TermCodeSystemVersion, TermConcept> systemVersionFetch = root.fetch("myCodeSystem", JoinType.INNER);
|
||||
Join<TermCodeSystemVersion, TermConcept> systemVersionJoin = (Join<TermCodeSystemVersion, TermConcept>)systemVersionFetch;
|
||||
Fetch<TermCodeSystem, TermCodeSystemVersion> systemFetch = systemVersionFetch.fetch("myCodeSystem", JoinType.INNER);
|
||||
Join<TermCodeSystem, TermCodeSystemVersion> systemJoin = (Join<TermCodeSystem, TermCodeSystemVersion>)systemFetch;
|
||||
|
||||
ArrayList<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
if (isNotBlank(theCode)) {
|
||||
predicates.add(criteriaBuilder.equal(root.get("myCode"), theCode));
|
||||
}
|
||||
|
||||
if (isNotBlank(theDisplay)) {
|
||||
predicates.add(criteriaBuilder.equal(root.get("myDisplay"), theDisplay));
|
||||
}
|
||||
|
||||
if (isNoneBlank(theCodeSystemUrl)) {
|
||||
predicates.add(criteriaBuilder.equal(systemJoin.get("myCodeSystemUri"), theCodeSystemUrl));
|
||||
}
|
||||
|
||||
if (isNoneBlank(theCodeSystemVersion)) {
|
||||
predicates.add(criteriaBuilder.equal(systemVersionJoin.get("myCodeSystemVersionId"), theCodeSystemVersion));
|
||||
} else {
|
||||
query.orderBy(criteriaBuilder.desc(root.get("myUpdated")));
|
||||
}
|
||||
|
||||
Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
query.where(outerPredicate);
|
||||
|
||||
final TypedQuery<TermConcept> typedQuery = myEntityManager.createQuery(query.select(root));
|
||||
org.hibernate.query.Query<TermConcept> hibernateQuery = (org.hibernate.query.Query<TermConcept>) typedQuery;
|
||||
hibernateQuery.setFetchSize(SINGLE_FETCH_SIZE);
|
||||
List<TermConcept> resultsList = hibernateQuery.getResultList();
|
||||
|
||||
if (!resultsList.isEmpty()) {
|
||||
TermConcept concept = resultsList.get(0);
|
||||
return new CodeValidationResult().setCode(concept.getCode()).setDisplay(concept.getDisplay());
|
||||
}
|
||||
|
||||
if (isBlank(theDisplay))
|
||||
return createFailureCodeValidationResult(theCodeSystemUrl, theCode);
|
||||
else
|
||||
return createFailureCodeValidationResult(theCodeSystemUrl, theCode, " - Concept Display : " + theDisplay);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.util.FhirVersionIndependentConcept;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
@ -29,6 +30,7 @@ import javax.annotation.Nullable;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
class ExpansionFilter {
|
||||
|
@ -95,4 +97,19 @@ class ExpansionFilter {
|
|||
public Integer getMaxCount() {
|
||||
return myMaxCount;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ExpansionFilter fromFilterString(@Nullable String theFilter) {
|
||||
ExpansionFilter filter;
|
||||
if (isNoneBlank(theFilter)) {
|
||||
List<ValueSet.ConceptSetFilterComponent> filters = Collections.singletonList(new ValueSet.ConceptSetFilterComponent()
|
||||
.setProperty(JpaConstants.VALUESET_FILTER_DISPLAY)
|
||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||
.setValue(theFilter));
|
||||
filter = new ExpansionFilter(null, null, filters, null);
|
||||
} else {
|
||||
filter = ExpansionFilter.NO_FILTER;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
|
||||
import ca.uhn.fhir.model.api.annotation.Block;
|
||||
|
@ -45,6 +46,15 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
|
|||
private int myAddedConcepts;
|
||||
private Integer myTotalConcepts;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theDaoConfig Will be used to determine the max capacity for this accumulator
|
||||
*/
|
||||
public ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, DaoConfig theDaoConfig) {
|
||||
this(theContext, theDaoConfig.getMaximumExpansionSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -56,7 +66,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
|
|||
myContext = theContext;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Nonnull
|
||||
@Override
|
||||
public Integer getCapacityRemaining() {
|
||||
return (myMaxCapacity - myAddedConcepts) + mySkipCountRemaining;
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.hl7.fhir.r4.model.CodeSystem;
|
|||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -57,7 +58,11 @@ import java.util.Set;
|
|||
*/
|
||||
public interface ITermReadSvc extends IValidationSupport {
|
||||
|
||||
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand);
|
||||
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl, @Nullable String theExpansionFilter);
|
||||
|
||||
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand);
|
||||
|
||||
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand, @Nullable String theFilter);
|
||||
|
||||
void expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||
|
||||
|
@ -68,7 +73,7 @@ public interface ITermReadSvc extends IValidationSupport {
|
|||
|
||||
void expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
|
||||
|
||||
List<FhirVersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet);
|
||||
List<FhirVersionIndependentConcept> expandValueSetIntoConceptList(ValueSetExpansionOptions theExpansionOptions, String theValueSetCanonicalUrl);
|
||||
|
||||
Optional<TermConcept> findCode(String theCodeSystem, String theCode);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||
import net.ttddyy.dsproxy.ExecutionInfo;
|
||||
import net.ttddyy.dsproxy.QueryInfo;
|
||||
import net.ttddyy.dsproxy.proxy.ParameterSetOperation;
|
||||
|
|
|
@ -50,6 +50,8 @@ import java.util.List;
|
|||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_CODE_SYSTEM;
|
||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_VALUE_SET;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
@ -343,14 +345,14 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, Matchers.containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, Matchers.not(Matchers.containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -866,7 +868,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.andParameter("filter", new StringType("first"))
|
||||
.andParameter("filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
|
|
|
@ -385,28 +385,28 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
// Verify ValueSet v2
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -425,28 +425,28 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
// Validate ValueSet v2
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -287,14 +287,14 @@ public class ResourceProviderR4ValueSetNoVerCSNoVerTest extends BaseResourceProv
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -312,14 +312,14 @@ public class ResourceProviderR4ValueSetNoVerCSNoVerTest extends BaseResourceProv
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -1203,7 +1203,7 @@ public class ResourceProviderR4ValueSetNoVerCSNoVerTest extends BaseResourceProv
|
|||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.andParameter("filter", new StringType("first"))
|
||||
.andParameter("filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
|
|
|
@ -261,14 +261,14 @@ public class ResourceProviderR4ValueSetVerCSNoVerTest extends BaseResourceProvid
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -286,14 +286,14 @@ public class ResourceProviderR4ValueSetVerCSNoVerTest extends BaseResourceProvid
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
|
@ -11,8 +12,11 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
|
|||
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
|
||||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
@ -37,6 +41,7 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
|
@ -44,7 +49,9 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
||||
|
@ -331,28 +338,28 @@ public class ResourceProviderR4ValueSetVerCSVerTest extends BaseResourceProvider
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
// Verify ValueSet v2
|
||||
respParam = myClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -372,28 +379,27 @@ public class ResourceProviderR4ValueSetVerCSVerTest extends BaseResourceProvider
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
|
||||
// Validate ValueSet v2
|
||||
respParam = myClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
private IIdType myExtensionalCsId;
|
||||
private IIdType myExtensionalVsId;
|
||||
private IIdType myLocalValueSetId;
|
||||
private Long myExtensionalCsIdOnResourceTable;
|
||||
private Long myExtensionalVsIdOnResourceTable;
|
||||
private ValueSet myLocalVs;
|
||||
|
||||
|
@ -84,11 +83,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
loadAndPersistValueSet(theVerb);
|
||||
}
|
||||
|
||||
private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HTTPVerb theVerb) throws IOException {
|
||||
loadAndPersistCodeSystemWithDesignations(theVerb);
|
||||
loadAndPersistValueSetWithExclude(theVerb);
|
||||
}
|
||||
|
||||
private void loadAndPersistCodeSystem(HTTPVerb theVerb) throws IOException {
|
||||
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||
codeSystem.setId("CodeSystem/cs");
|
||||
|
@ -123,7 +117,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
default:
|
||||
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
|
||||
}
|
||||
myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId();
|
||||
}
|
||||
|
||||
private void loadAndPersistValueSet(HTTPVerb theVerb) throws IOException {
|
||||
|
@ -132,12 +125,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
persistValueSet(valueSet, theVerb);
|
||||
}
|
||||
|
||||
private void loadAndPersistValueSetWithExclude(HTTPVerb theVerb) throws IOException {
|
||||
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml");
|
||||
valueSet.setId("ValueSet/vs");
|
||||
persistValueSet(valueSet, theVerb);
|
||||
}
|
||||
|
||||
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||
private void persistValueSet(ValueSet theValueSet, HTTPVerb theVerb) {
|
||||
switch (theVerb) {
|
||||
|
@ -404,14 +391,14 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -426,14 +413,14 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -1449,7 +1436,7 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
|||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.andParameter("filter", new StringType("first"))
|
||||
.andParameter("filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
|
|
|
@ -368,28 +368,28 @@ public class ResourceProviderR5ValueSetVersionedTest extends BaseResourceProvide
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
// Verify ValueSet v2
|
||||
respParam = myClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
@ -409,28 +409,28 @@ public class ResourceProviderR5ValueSetVersionedTest extends BaseResourceProvide
|
|||
.operation()
|
||||
.onInstance(myExtensionalVsId_v1)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
// Validate ValueSet v2
|
||||
respParam = myClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId_v2)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||
.execute();
|
||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration v2\"/>")));
|
||||
assertThat(resp, not(containsString("\"Foo Code\"")));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
|
|||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -22,10 +23,12 @@ import org.hl7.fhir.r4.model.CodeSystem;
|
|||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.codesystems.HttpVerb;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
@ -60,6 +63,11 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
@Mock
|
||||
private IValueSetConceptAccumulator myValueSetCodeAccumulator;
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
SearchBuilder.setMaxPageSize50ForTest(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletePreExpandedValueSet() throws IOException {
|
||||
myDaoConfig.setPreExpandValueSets(true);
|
||||
|
@ -181,7 +189,53 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
assertThat(lastSelectQuery, containsString("concept_display like 'display value 9%'"));
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 9%'"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandHugeValueSet_FilterOnDisplay_LeftMatch_SelectAll() {
|
||||
SearchBuilder.setMaxPageSize50ForTest(true);
|
||||
myDaoConfig.setPreExpandValueSets(true);
|
||||
IIdType vsId = createConceptsCodeSystemAndValueSet(1005);
|
||||
|
||||
// Inline ValueSet
|
||||
{
|
||||
ValueSet input = new ValueSet();
|
||||
input.getCompose()
|
||||
.addInclude()
|
||||
.addValueSet("http://foo/vs")
|
||||
.addFilter()
|
||||
.setProperty(JpaConstants.VALUESET_FILTER_DISPLAY)
|
||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||
.setValue("display value 100");
|
||||
|
||||
// Expansion should contain all codes
|
||||
myCaptureQueriesListener.clear();
|
||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(new ValueSetExpansionOptions(), input);
|
||||
List<String> codes = expandedValueSet.getExpansion().getContains().stream().map(t -> t.getCode()).collect(Collectors.toList());
|
||||
assertThat(codes.toString(), codes, contains("code100", "code1000", "code1001", "code1002", "code1003", "code1004"));
|
||||
|
||||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
ourLog.info("SQL: {}", lastSelectQuery);
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 100%'"));
|
||||
}
|
||||
|
||||
// ValueSet by ID
|
||||
{
|
||||
myCaptureQueriesListener.clear();
|
||||
ValueSet expandedValueSet = myValueSetDao.expand(vsId, "display value 100", 0, 1000, mySrd);
|
||||
List<String> codes = expandedValueSet.getExpansion().getContains().stream().map(t -> t.getCode()).collect(Collectors.toList());
|
||||
assertThat(codes.toString(), codes, contains("code100", "code1000", "code1001", "code1002", "code1003", "code1004"));
|
||||
|
||||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
ourLog.info("SQL: {}", lastSelectQuery);
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 100%'"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -215,11 +269,38 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
assertThat(lastSelectQuery, containsString("concept_display like 'display value 9%'"));
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 9%'"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandInline_IncludePreExpandedValueSetByUri_FilterOnDisplay_LeftMatchCaseInsensitive() {
|
||||
myDaoConfig.setPreExpandValueSets(true);
|
||||
create100ConceptsCodeSystemAndValueSet();
|
||||
|
||||
ValueSet input = new ValueSet();
|
||||
input.getCompose()
|
||||
.addInclude()
|
||||
.addValueSet("http://foo/vs")
|
||||
.addFilter()
|
||||
.setProperty(JpaConstants.VALUESET_FILTER_DISPLAY)
|
||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||
.setValue("dIsPlAy valuE 99");
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(null, input);
|
||||
ourLog.debug("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||
|
||||
assertThat(toCodes(expandedValueSet).toString(), toCodes(expandedValueSet), contains( "code99" ));
|
||||
|
||||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
assertThat(lastSelectQuery, containsString("like 'display value 99%'"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandInline_IncludePreExpandedValueSetByUri_ExcludeCodes_FilterOnDisplay_LeftMatch_SelectAll() {
|
||||
myDaoConfig.setPreExpandValueSets(true);
|
||||
|
@ -254,7 +335,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
assertThat(lastSelectQuery, containsString("concept_display like 'display value 90%'"));
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 90%'"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -292,24 +373,38 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void create100ConceptsCodeSystemAndValueSet() {
|
||||
createConceptsCodeSystemAndValueSet(100);
|
||||
}
|
||||
|
||||
public IIdType createConceptsCodeSystemAndValueSet(int theCount) {
|
||||
CodeSystem cs = new CodeSystem();
|
||||
cs.setUrl("http://foo/cs");
|
||||
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||
myCodeSystemDao.create(cs);
|
||||
|
||||
CustomTerminologySet additions = new CustomTerminologySet();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (int i = 0; i < theCount; i++) {
|
||||
additions.addRootConcept("code" + i, "display value " + i);
|
||||
}
|
||||
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", additions);
|
||||
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
vs.setUrl("http://foo/vs");
|
||||
vs.getCompose().addInclude().setSystem("http://foo/cs");
|
||||
myValueSetDao.create(vs);
|
||||
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
|
||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||
|
||||
// Confirm we pre-expanded successfully
|
||||
runInTransaction(() -> {
|
||||
Pageable page = Pageable.unpaged();
|
||||
List<TermValueSet> valueSets = myTermValueSetDao.findTermValueSetByUrl(page, "http://foo/vs");
|
||||
assertEquals(1, valueSets.size());
|
||||
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, valueSets.get(0).getExpansionStatus());
|
||||
});
|
||||
|
||||
return vsId;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -339,7 +434,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
|||
// Make sure we used the pre-expanded version
|
||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
||||
assertThat(lastSelectQuery, containsString("concept_display like 'display value 9%'"));
|
||||
assertThat(lastSelectQuery, containsString(" like 'display value 9%'"));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -89,12 +89,12 @@
|
|||
<code value="8490-5" />
|
||||
<display value="Systolic blood pressure 24 hour mean" />
|
||||
</concept>
|
||||
<concept>
|
||||
<code value="8491-3" />
|
||||
<display value="Systolic blood pressure 1 hour minimum" />
|
||||
</concept>
|
||||
<concept>
|
||||
<code value="8492-1" />
|
||||
<display value="Systolic blood pressure 8 hour minimum" />
|
||||
</concept>
|
||||
<concept>
|
||||
<code value="9999-9" />
|
||||
<display value="Foo Code" />
|
||||
</concept>
|
||||
</CodeSystem>
|
||||
|
|
Loading…
Reference in New Issue