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;
|
myFailOnMissingCodeSystem = theFailOnMissingCodeSystem;
|
||||||
return this;
|
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")
|
@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);
|
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);
|
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.ConceptValidationOptions;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
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.context.support.ValueSetExpansionOptions;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
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.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import org.hl7.fhir.convertors.conv30_40.ValueSet30_40;
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
|
||||||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||||
import org.hl7.fhir.dstu3.model.Coding;
|
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;
|
||||||
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.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
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;
|
import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet;
|
||||||
|
|
||||||
public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||||
|
|
||||||
private IValidationSupport myValidationSupport;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||||
super.start();
|
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
|
||||||
myValidationSupport = getApplicationContext().getBean(IValidationSupport.class, "myJpaValidationSupportChain");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
|
||||||
ValueSet source = read(theId, theRequestDetails);
|
|
||||||
return expand(source, theFilter);
|
return expand(source, theFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
|
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
|
||||||
ValueSet source = read(theId, theRequestDetails);
|
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
|
||||||
return expand(source, theFilter, theOffset, theCount);
|
return expand(source, theFilter, theOffset, theCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueSet doExpand(ValueSet theSource) {
|
@Override
|
||||||
validateIncludes("include", theSource.getCompose().getInclude());
|
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||||
validateIncludes("exclude", theSource.getCompose().getExclude());
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||||
|
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||||
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
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||||
if (isBlank(theUri)) {
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
throw new InvalidRequestException("URI must not be blank or missing");
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||||
}
|
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter) {
|
||||||
if (isBlank(theUri)) {
|
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
|
||||||
throw new InvalidRequestException("URI must not be blank or missing");
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
|
||||||
}
|
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||||
ValueSet toExpand = new ValueSet();
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
|
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
|
||||||
// for (UriType next : theSource.getCompose().getInclude()) {
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
|
||||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
return ValueSet30_40.convertValueSet(canonicalOutput);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -205,7 +205,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (modifier == TokenParamModifier.IN) {
|
if (modifier == TokenParamModifier.IN) {
|
||||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
codes.addAll(myTerminologySvc.expandValueSetIntoConceptList(null, code));
|
||||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||||
|
@ -273,7 +273,7 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu
|
||||||
String valueSet = valueSetUris.iterator().next();
|
String valueSet = valueSetUris.iterator().next();
|
||||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||||
.setFailOnMissingCodeSystem(false);
|
.setFailOnMissingCodeSystem(false);
|
||||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(options, valueSet);
|
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSetIntoConceptList(options, valueSet);
|
||||||
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
||||||
if (nextCandidate.getCode().equals(code)) {
|
if (nextCandidate.getCode().equals(code)) {
|
||||||
retVal = nextCandidate.getSystem();
|
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.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
|
||||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
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.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.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.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
import org.hl7.fhir.r4.model.IntegerType;
|
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
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.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
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.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> {
|
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
|
@Override
|
||||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||||
ValueSet source = read(theId, theRequestDetails);
|
ValueSet source = read(theId, theRequestDetails);
|
||||||
|
@ -75,156 +55,26 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
|
||||||
return expand(source, theFilter, theOffset, theCount);
|
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
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||||
if (isBlank(theUri)) {
|
return myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||||
if (isBlank(theUri)) {
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
throw new InvalidRequestException("URI must not be blank or missing");
|
return myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
public ValueSet expand(ValueSet theSource, String theFilter) {
|
||||||
ValueSet toExpand = new ValueSet();
|
return myTerminologySvc.expandValueSet(null, theSource, theFilter);
|
||||||
|
|
||||||
// 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
|
@Override
|
||||||
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||||
ValueSet toExpand = new ValueSet();
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
toExpand.setId(theSource.getId());
|
return myTerminologySvc.expandValueSet(options, theSource, theFilter);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
|
||||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
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.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
import org.hl7.fhir.convertors.conv40_50.ValueSet40_50;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||||
import org.hl7.fhir.r5.model.Coding;
|
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;
|
||||||
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.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
|
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.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> {
|
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
|
@Override
|
||||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||||
ValueSet source = read(theId, theRequestDetails);
|
ValueSet source = read(theId, theRequestDetails);
|
||||||
|
@ -74,157 +55,32 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
|
||||||
return expand(source, theFilter, theOffset, theCount);
|
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
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||||
if (isBlank(theUri)) {
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
|
||||||
throw new InvalidRequestException("URI must not be blank or missing");
|
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
|
||||||
if (isBlank(theUri)) {
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
throw new InvalidRequestException("URI must not be blank or missing");
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
|
||||||
}
|
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet expand(ValueSet theSource, String theFilter) {
|
public ValueSet expand(ValueSet theSource, String theFilter) {
|
||||||
ValueSet toExpand = new ValueSet();
|
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
|
||||||
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
|
||||||
// for (UriType next : theSource.getCompose().getInclude()) {
|
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||||
// 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
|
@Override
|
||||||
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
|
||||||
ValueSet toExpand = new ValueSet();
|
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
|
||||||
toExpand.setId(theSource.getId());
|
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
|
||||||
toExpand.setUrl(theSource.getUrl());
|
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
|
||||||
if (theSource.getVersion() != null) {
|
return ValueSet40_50.convertValueSet(canonicalOutput);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (modifier == TokenParamModifier.IN) {
|
if (modifier == TokenParamModifier.IN) {
|
||||||
codes.addAll(myTerminologySvc.expandValueSet(null, code));
|
codes.addAll(myTerminologySvc.expandValueSetIntoConceptList(null, code));
|
||||||
} else if (modifier == TokenParamModifier.ABOVE) {
|
} else if (modifier == TokenParamModifier.ABOVE) {
|
||||||
system = determineSystemIfMissing(theSearchParam, code, system);
|
system = determineSystemIfMissing(theSearchParam, code, system);
|
||||||
validateHaveSystemAndCodeForToken(paramName, code, system);
|
validateHaveSystemAndCodeForToken(paramName, code, system);
|
||||||
|
@ -228,7 +228,7 @@ public class TokenPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||||
String valueSet = valueSetUris.iterator().next();
|
String valueSet = valueSetUris.iterator().next();
|
||||||
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
ValueSetExpansionOptions options = new ValueSetExpansionOptions()
|
||||||
.setFailOnMissingCodeSystem(false);
|
.setFailOnMissingCodeSystem(false);
|
||||||
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(options, valueSet);
|
List<FhirVersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSetIntoConceptList(options, valueSet);
|
||||||
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
for (FhirVersionIndependentConcept nextCandidate : candidateCodes) {
|
||||||
if (nextCandidate.getCode().equals(code)) {
|
if (nextCandidate.getCode().equals(code)) {
|
||||||
retVal = nextCandidate.getSystem();
|
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.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
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.ITermCodeSystemStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
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.isEmpty;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
|
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.lowerCase;
|
||||||
|
|
||||||
public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
public static final int DEFAULT_FETCH_SIZE = 250;
|
public static final int DEFAULT_FETCH_SIZE = 250;
|
||||||
|
@ -394,25 +396,44 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FhirVersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet) {
|
@Transactional
|
||||||
ExpansionFilter expansionFilter = ExpansionFilter.NO_FILTER;
|
public List<FhirVersionIndependentConcept> expandValueSetIntoConceptList(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl) {
|
||||||
return expandValueSet(theExpansionOptions, theValueSet, expansionFilter);
|
String expansionFilter = null;
|
||||||
}
|
|
||||||
|
|
||||||
private List<FhirVersionIndependentConcept> expandValueSet(ValueSetExpansionOptions theExpansionOptions, String theValueSet, ExpansionFilter theExpansionFilter) {
|
|
||||||
// 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.
|
// 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) {
|
if (valueSet == null) {
|
||||||
throwInvalidValueSet(theValueSet);
|
throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetCanonicalUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
return expandValueSetAndReturnVersionIndependentConcepts(theExpansionOptions, valueSet, theExpansionFilter);
|
return expandValueSet(theExpansionOptions, valueSet, theExpansionFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@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");
|
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSetToExpand, "ValueSet to expand can not be null");
|
||||||
|
|
||||||
ValueSetExpansionOptions expansionOptions = provideExpansionOptions(theExpansionOptions);
|
ValueSetExpansionOptions expansionOptions = provideExpansionOptions(theExpansionOptions);
|
||||||
|
@ -431,9 +452,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
accumulator.addParameter().setName("count").setValue(new IntegerType(count));
|
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) {
|
if (accumulator.getTotalConcepts() != null) {
|
||||||
accumulator.setTotal(accumulator.getTotalConcepts());
|
accumulator.setTotal(accumulator.getTotalConcepts());
|
||||||
|
@ -449,7 +469,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
|
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
|
||||||
.setValue(new StringType(next));
|
.setValue(new StringType(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
return valueSet;
|
return valueSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,6 +532,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
boolean wasFilteredResult = false;
|
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) {
|
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("%", "[%]") + "%";
|
String displayValue = theFilter.getFilters().get(0).getValue().replace("%", "[%]") + "%";
|
||||||
|
displayValue = lowerCase(displayValue);
|
||||||
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
|
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
|
||||||
wasFilteredResult = true;
|
wasFilteredResult = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -675,7 +695,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
return theAction.get();
|
return theAction.get();
|
||||||
}
|
}
|
||||||
return myTxTemplate.execute(t->theAction.get());
|
return myTxTemplate.execute(t -> theAction.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getValueSetInfo(ValueSet theValueSet) {
|
private String getValueSetInfo(ValueSet theValueSet) {
|
||||||
|
@ -702,18 +722,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
return sb.toString();
|
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.
|
* @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
|
* 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.
|
* 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();
|
StopWatch sw = new StopWatch();
|
||||||
AtomicInteger count = new AtomicInteger(0);
|
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
|
* 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()) {
|
if (!concepts.isEmpty()) {
|
||||||
|
@ -1424,7 +1432,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
int versionIndex = theSystem.indexOf("|");
|
int versionIndex = theSystem.indexOf("|");
|
||||||
if (versionIndex >= 0) {
|
if (versionIndex >= 0) {
|
||||||
String systemUrl = theSystem.substring(0, versionIndex);
|
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);
|
optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCodeWithVersion(theResourcePid.getIdAsLong(), systemUrl, systemVersion, theCode);
|
||||||
} else {
|
} else {
|
||||||
optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCode(theResourcePid.getIdAsLong(), theSystem, theCode);
|
optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCode(theResourcePid.getIdAsLong(), theSystem, theCode);
|
||||||
|
@ -1526,7 +1534,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
private String getUrlFromIdentifier(String theUri) {
|
private String getUrlFromIdentifier(String theUri) {
|
||||||
String retVal = theUri;
|
String retVal = theUri;
|
||||||
if (StringUtils.isNotEmpty((theUri))){
|
if (StringUtils.isNotEmpty((theUri))) {
|
||||||
int versionSeparator = theUri.lastIndexOf('|');
|
int versionSeparator = theUri.lastIndexOf('|');
|
||||||
if (versionSeparator != -1) {
|
if (versionSeparator != -1) {
|
||||||
retVal = theUri.substring(0, versionSeparator);
|
retVal = theUri.substring(0, versionSeparator);
|
||||||
|
@ -1781,9 +1789,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
} else {
|
} else {
|
||||||
String msg = myContext.getLocalizer().getMessage(
|
String msg = myContext.getLocalizer().getMessage(
|
||||||
BaseTermReadSvcImpl.class,
|
BaseTermReadSvcImpl.class,
|
||||||
"cannotCreateDuplicateConceptMapUrlAndVersion",
|
"cannotCreateDuplicateConceptMapUrlAndVersion",
|
||||||
conceptMapUrl, conceptMapVersion,
|
conceptMapUrl, conceptMapVersion,
|
||||||
existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||||
throw new UnprocessableEntityException(msg);
|
throw new UnprocessableEntityException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1818,7 +1826,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
// We have a ValueSet to pre-expand.
|
// We have a ValueSet to pre-expand.
|
||||||
try {
|
try {
|
||||||
ValueSet valueSet = txTemplate.execute(t -> {
|
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());
|
return getValueSetFromResourceTable(refreshedValueSetToExpand.getResource());
|
||||||
});
|
});
|
||||||
assert valueSet != null;
|
assert valueSet != null;
|
||||||
|
@ -1988,7 +1996,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB,
|
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 conceptA = toConcept(theCodeA, theSystem, theCodingA);
|
||||||
FhirVersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB);
|
FhirVersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB);
|
||||||
|
|
||||||
|
@ -2002,7 +2010,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
String codeASystemIdentifier;
|
String codeASystemIdentifier;
|
||||||
if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) {
|
if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) {
|
||||||
codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
|
codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
|
||||||
} else {
|
} else {
|
||||||
codeASystemIdentifier = conceptA.getSystem();
|
codeASystemIdentifier = conceptA.getSystem();
|
||||||
}
|
}
|
||||||
|
@ -2342,7 +2350,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
|
|
||||||
Pageable page = PageRequest.of(0, 1);
|
Pageable page = PageRequest.of(0, 1);
|
||||||
List<TermConceptMap> theConceptMapList = myConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page,
|
List<TermConceptMap> theConceptMapList = myConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page,
|
||||||
theTranslationRequest.getUrl().asStringValue());
|
theTranslationRequest.getUrl().asStringValue());
|
||||||
if (!theConceptMapList.isEmpty()) {
|
if (!theConceptMapList.isEmpty()) {
|
||||||
return theConceptMapList.get(0).getVersion();
|
return theConceptMapList.get(0).getVersion();
|
||||||
}
|
}
|
||||||
|
@ -2553,6 +2561,136 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept);
|
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 {
|
public static class Job implements HapiJob {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITermReadSvc myTerminologySvc;
|
private ITermReadSvc myTerminologySvc;
|
||||||
|
@ -2640,21 +2778,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
return termConcept;
|
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
|
* 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() {
|
static boolean isOurLastResultsFromTranslationWithReverseCache() {
|
||||||
return ourLastResultsFromTranslationWithReverseCache;
|
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%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.util.FhirVersionIndependentConcept;
|
import ca.uhn.fhir.util.FhirVersionIndependentConcept;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
@ -29,6 +30,7 @@ import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
class ExpansionFilter {
|
class ExpansionFilter {
|
||||||
|
@ -95,4 +97,19 @@ class ExpansionFilter {
|
||||||
public Integer getMaxCount() {
|
public Integer getMaxCount() {
|
||||||
return myMaxCount;
|
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.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
|
||||||
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
|
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
|
||||||
import ca.uhn.fhir.model.api.annotation.Block;
|
import ca.uhn.fhir.model.api.annotation.Block;
|
||||||
|
@ -45,6 +46,15 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
|
||||||
private int myAddedConcepts;
|
private int myAddedConcepts;
|
||||||
private Integer myTotalConcepts;
|
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
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -56,7 +66,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Integer getCapacityRemaining() {
|
public Integer getCapacityRemaining() {
|
||||||
return (myMaxCapacity - myAddedConcepts) + mySkipCountRemaining;
|
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.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -57,7 +58,11 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public interface ITermReadSvc extends IValidationSupport {
|
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);
|
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);
|
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);
|
Optional<TermConcept> findCode(String theCodeSystem, String theCode);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.config;
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||||
import net.ttddyy.dsproxy.ExecutionInfo;
|
import net.ttddyy.dsproxy.ExecutionInfo;
|
||||||
import net.ttddyy.dsproxy.QueryInfo;
|
import net.ttddyy.dsproxy.QueryInfo;
|
||||||
import net.ttddyy.dsproxy.proxy.ParameterSetOperation;
|
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_CODE_SYSTEM;
|
||||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_VALUE_SET;
|
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_VALUE_SET;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
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.hamcrest.Matchers.stringContainsInOrder;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@ -343,14 +345,14 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, Matchers.containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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)
|
.onType(ValueSet.class)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
.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();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
|
|
|
@ -385,28 +385,28 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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
|
// Verify ValueSet v2
|
||||||
respParam = ourClient
|
respParam = ourClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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
|
// Validate ValueSet v2
|
||||||
respParam = ourClient
|
respParam = ourClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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)
|
.onType(ValueSet.class)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
.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();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
|
|
|
@ -261,14 +261,14 @@ public class ResourceProviderR4ValueSetVerCSNoVerTest extends BaseResourceProvid
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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;
|
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.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
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.TermValueSetConceptDesignation;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
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.ITermCodeSystemStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
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.api.server.storage.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
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.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
|
@ -44,7 +49,9 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
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_CODE_SYSTEM;
|
||||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
||||||
|
@ -331,28 +338,28 @@ public class ResourceProviderR4ValueSetVerCSVerTest extends BaseResourceProvider
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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
|
// Verify ValueSet v2
|
||||||
respParam = myClient
|
respParam = myClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
|
||||||
|
|
||||||
// Validate ValueSet v2
|
// Validate ValueSet v2
|
||||||
respParam = myClient
|
respParam = myClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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 myExtensionalCsId;
|
||||||
private IIdType myExtensionalVsId;
|
private IIdType myExtensionalVsId;
|
||||||
private IIdType myLocalValueSetId;
|
private IIdType myLocalValueSetId;
|
||||||
private Long myExtensionalCsIdOnResourceTable;
|
|
||||||
private Long myExtensionalVsIdOnResourceTable;
|
private Long myExtensionalVsIdOnResourceTable;
|
||||||
private ValueSet myLocalVs;
|
private ValueSet myLocalVs;
|
||||||
|
|
||||||
|
@ -84,11 +83,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
||||||
loadAndPersistValueSet(theVerb);
|
loadAndPersistValueSet(theVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HTTPVerb theVerb) throws IOException {
|
|
||||||
loadAndPersistCodeSystemWithDesignations(theVerb);
|
|
||||||
loadAndPersistValueSetWithExclude(theVerb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadAndPersistCodeSystem(HTTPVerb theVerb) throws IOException {
|
private void loadAndPersistCodeSystem(HTTPVerb theVerb) throws IOException {
|
||||||
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||||
codeSystem.setId("CodeSystem/cs");
|
codeSystem.setId("CodeSystem/cs");
|
||||||
|
@ -123,7 +117,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
|
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
|
||||||
}
|
}
|
||||||
myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAndPersistValueSet(HTTPVerb theVerb) throws IOException {
|
private void loadAndPersistValueSet(HTTPVerb theVerb) throws IOException {
|
||||||
|
@ -132,12 +125,6 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
||||||
persistValueSet(valueSet, theVerb);
|
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")
|
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||||
private void persistValueSet(ValueSet theValueSet, HTTPVerb theVerb) {
|
private void persistValueSet(ValueSet theValueSet, HTTPVerb theVerb) {
|
||||||
switch (theVerb) {
|
switch (theVerb) {
|
||||||
|
@ -404,14 +391,14 @@ public class ResourceProviderR5ValueSetTest extends BaseResourceProviderR5Test {
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId)
|
.onInstance(myExtensionalVsId)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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)
|
.onType(ValueSet.class)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
.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();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
|
|
|
@ -368,28 +368,28 @@ public class ResourceProviderR5ValueSetVersionedTest extends BaseResourceProvide
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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
|
// Verify ValueSet v2
|
||||||
respParam = myClient
|
respParam = myClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v1)
|
.onInstance(myExtensionalVsId_v1)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
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
|
// Validate ValueSet v2
|
||||||
respParam = myClient
|
respParam = myClient
|
||||||
.operation()
|
.operation()
|
||||||
.onInstance(myExtensionalVsId_v2)
|
.onInstance(myExtensionalVsId_v2)
|
||||||
.named("expand")
|
.named("expand")
|
||||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
.withParameter(Parameters.class, "filter", new StringType("systolic"))
|
||||||
.execute();
|
.execute();
|
||||||
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter v2\"/>"));
|
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.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
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.term.custom.CustomTerminologySet;
|
||||||
import ca.uhn.fhir.jpa.util.SqlQuery;
|
import ca.uhn.fhir.jpa.util.SqlQuery;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
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.Extension;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.hl7.fhir.r4.model.codesystems.HttpVerb;
|
import org.hl7.fhir.r4.model.codesystems.HttpVerb;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
@ -60,6 +63,11 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
||||||
@Mock
|
@Mock
|
||||||
private IValueSetConceptAccumulator myValueSetCodeAccumulator;
|
private IValueSetConceptAccumulator myValueSetCodeAccumulator;
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterEach() {
|
||||||
|
SearchBuilder.setMaxPageSize50ForTest(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletePreExpandedValueSet() throws IOException {
|
public void testDeletePreExpandedValueSet() throws IOException {
|
||||||
myDaoConfig.setPreExpandValueSets(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
@ -181,7 +189,53 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
||||||
// Make sure we used the pre-expanded version
|
// Make sure we used the pre-expanded version
|
||||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
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
|
// Make sure we used the pre-expanded version
|
||||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
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
|
@Test
|
||||||
public void testExpandInline_IncludePreExpandedValueSetByUri_ExcludeCodes_FilterOnDisplay_LeftMatch_SelectAll() {
|
public void testExpandInline_IncludePreExpandedValueSetByUri_ExcludeCodes_FilterOnDisplay_LeftMatch_SelectAll() {
|
||||||
myDaoConfig.setPreExpandValueSets(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
@ -254,7 +335,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
||||||
// Make sure we used the pre-expanded version
|
// Make sure we used the pre-expanded version
|
||||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
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() {
|
public void create100ConceptsCodeSystemAndValueSet() {
|
||||||
|
createConceptsCodeSystemAndValueSet(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IIdType createConceptsCodeSystemAndValueSet(int theCount) {
|
||||||
CodeSystem cs = new CodeSystem();
|
CodeSystem cs = new CodeSystem();
|
||||||
cs.setUrl("http://foo/cs");
|
cs.setUrl("http://foo/cs");
|
||||||
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||||
myCodeSystemDao.create(cs);
|
myCodeSystemDao.create(cs);
|
||||||
|
|
||||||
CustomTerminologySet additions = new CustomTerminologySet();
|
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);
|
additions.addRootConcept("code" + i, "display value " + i);
|
||||||
}
|
}
|
||||||
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", additions);
|
myTermCodeSystemStorageSvc.applyDeltaCodeSystemsAdd("http://foo/cs", additions);
|
||||||
|
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
||||||
|
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
vs.setUrl("http://foo/vs");
|
vs.setUrl("http://foo/vs");
|
||||||
vs.getCompose().addInclude().setSystem("http://foo/cs");
|
vs.getCompose().addInclude().setSystem("http://foo/cs");
|
||||||
myValueSetDao.create(vs);
|
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
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
|
@Test
|
||||||
|
@ -339,7 +434,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
|
||||||
// Make sure we used the pre-expanded version
|
// Make sure we used the pre-expanded version
|
||||||
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
|
||||||
String lastSelectQuery = selectQueries.get(selectQueries.size() - 1).getSql(true, true).toLowerCase();
|
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
|
@Nonnull
|
||||||
|
|
|
@ -89,12 +89,12 @@
|
||||||
<code value="8490-5" />
|
<code value="8490-5" />
|
||||||
<display value="Systolic blood pressure 24 hour mean" />
|
<display value="Systolic blood pressure 24 hour mean" />
|
||||||
</concept>
|
</concept>
|
||||||
<concept>
|
|
||||||
<code value="8491-3" />
|
|
||||||
<display value="Systolic blood pressure 1 hour minimum" />
|
|
||||||
</concept>
|
|
||||||
<concept>
|
<concept>
|
||||||
<code value="8492-1" />
|
<code value="8492-1" />
|
||||||
<display value="Systolic blood pressure 8 hour minimum" />
|
<display value="Systolic blood pressure 8 hour minimum" />
|
||||||
</concept>
|
</concept>
|
||||||
|
<concept>
|
||||||
|
<code value="9999-9" />
|
||||||
|
<display value="Foo Code" />
|
||||||
|
</concept>
|
||||||
</CodeSystem>
|
</CodeSystem>
|
||||||
|
|
Loading…
Reference in New Issue