Add support for hierarchycal valueset expansion (#2525)

* Add support for hierarchycal valueset expansion

* Add changelog

* Add tests

* Cleanup

* Test fix

* Test fixes
This commit is contained in:
James Agnew 2021-04-06 17:36:54 -04:00 committed by GitHub
parent fcffb04c7b
commit a6cbf7eebd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 930 additions and 728 deletions

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -32,6 +32,17 @@ public class ValueSetExpansionOptions {
private boolean myFailOnMissingCodeSystem = true;
private int myCount = 1000;
private int myOffset = 0;
private boolean myIncludeHierarchy;
private String myFilter;
public String getFilter() {
return myFilter;
}
public ValueSetExpansionOptions setFilter(String theFilter) {
myFilter = theFilter;
return this;
}
/**
* The number of codes to return.
@ -94,6 +105,14 @@ public class ValueSetExpansionOptions {
return this;
}
public boolean isIncludeHierarchy() {
return myIncludeHierarchy;
}
public void setIncludeHierarchy(boolean theIncludeHierarchy) {
myIncludeHierarchy = theIncludeHierarchy;
}
public static ValueSetExpansionOptions forOffsetAndCount(int theOffset, int theCount) {
return new ValueSetExpansionOptions()
.setOffset(theOffset)

View File

@ -3,14 +3,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -78,13 +78,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-subscription</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -101,7 +101,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<classifier>classes</classifier>
</dependency>
<dependency>

View File

@ -0,0 +1,6 @@
---
type: add
issue: 2525
title: "A new optional parameter has been added to the `ValueSet/$expand` operation. When provided a value of `true`, the
operation will include the concept hierarchy in the expansion response."

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.api.dao;
*/
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -28,17 +29,11 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> extends IFhirResourceDao<T> {
T expand(IIdType theId, String theFilter, RequestDetails theRequestDetails);
T expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails);
T expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails);
T expand(T theSource, ValueSetExpansionOptions theOptions);
T expand(T theSource, String theFilter);
T expand(T theSource, String theFilter, int theOffset, int theCount);
T expandByIdentifier(String theUri, String theFilter);
T expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount);
T expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions);
void purgeCaches();

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -24,9 +24,9 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport.CodeValidationResult;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
@ -40,6 +40,7 @@ import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -51,20 +52,20 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
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.util.LogicUtil.multiXor;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueSet>
implements IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>, IFhirResourceDaoCodeSystem<ValueSet, CodingDt, CodeableConceptDt> {
implements IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>, IFhirResourceDaoCodeSystem<ValueSet, CodingDt, CodeableConceptDt> {
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
@ -104,31 +105,32 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
}
@Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequest) {
public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequest) {
ValueSet source = loadValueSetForExpansion(theId, theRequest);
return expand(source, theFilter);
return expand(source, theOptions);
}
@Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequest) {
throw new UnsupportedOperationException();
}
@Override
public ValueSet expand(ValueSet source, String theFilter) {
public ValueSet expand(ValueSet source, ValueSetExpansionOptions theOptions) {
ValueSet retVal = new ValueSet();
retVal.setDate(DateTimeDt.withCurrentTime());
String filter = null;
if (theOptions != null) {
filter = theOptions.getFilter();
}
/*
* Add composed concepts
*/
for (ComposeInclude nextInclude : source.getCompose().getInclude()) {
for (ComposeIncludeConcept next : nextInclude.getConcept()) {
if (isBlank(theFilter)) {
if (isBlank(filter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
} else {
String filter = theFilter.toLowerCase();
filter = filter.toLowerCase();
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
}
@ -141,19 +143,14 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
*/
for (CodeSystemConcept next : source.getCodeSystem().getConcept()) {
addCompose(theFilter, retVal, source, next);
addCompose(filter, retVal, source, next);
}
return retVal;
}
@Override
public ValueSet expand(ValueSet source, String theFilter, int theOffset, int theCount) {
throw new UnsupportedOperationException();
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter) {
public ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
@ -173,12 +170,7 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
source = (ValueSet) ids.getResources(0, 1).get(0);
}
return expand(source, theFilter);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
throw new UnsupportedOperationException();
return expand(source, theOptions);
}
@Override
@ -236,6 +228,7 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
return null;
}
@Nonnull
@Override
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, RequestDetails theRequest) {
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
@ -294,20 +287,20 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
// nothing
}
public static String toStringOrNull(IPrimitiveType<String> thePrimitive) {
return thePrimitive != null ? thePrimitive.getValue() : null;
}
@Override
public IValidationSupport.CodeValidationResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode,
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept, RequestDetails theRequest) {
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept, RequestDetails theRequest) {
return myTerminologySvc.validateCode(vsValidateCodeOptions(), theId, toStringOrNull(theValueSetIdentifier), toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
}
@Override
public CodeValidationResult validateCode(IIdType theCodeSystemId, IPrimitiveType<String> theCodeSystemUrl, IPrimitiveType<String> theVersion, IPrimitiveType<String> theCode,
IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept, RequestDetails theRequestDetails) {
IPrimitiveType<String> theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept, RequestDetails theRequestDetails) {
throw new UnsupportedOperationException();
}
public static String toStringOrNull(IPrimitiveType<String> thePrimitive) {
return thePrimitive != null ? thePrimitive.getValue() : null;
}
}

View File

@ -47,42 +47,21 @@ import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet;
public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails) {
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter);
return expand(source, theOptions);
}
@Override
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter, theOffset, theCount);
}
@Override
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter) {
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
return ValueSet30_40.convertValueSet(canonicalOutput);
}
@Override
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
return ValueSet30_40.convertValueSet(canonicalOutput);
}
@Override
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter) {
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, ValueSetExpansionOptions theOptions) {
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, canonicalInput);
return ValueSet30_40.convertValueSet(canonicalOutput);
}
@Override
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, theUri);
return ValueSet30_40.convertValueSet(canonicalOutput);
}

View File

@ -44,37 +44,20 @@ import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateC
public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter);
return expand(source, theOptions);
}
@Override
public ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
return myTerminologySvc.expandValueSet(theOptions, theUri);
}
@Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter, theOffset, theCount);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter) {
return myTerminologySvc.expandValueSet(null, theUri, theFilter);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
return myTerminologySvc.expandValueSet(options, theUri, theFilter);
}
@Override
public ValueSet expand(ValueSet theSource, String theFilter) {
return myTerminologySvc.expandValueSet(null, theSource, theFilter);
}
@Override
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
return myTerminologySvc.expandValueSet(options, theSource, theFilter);
public ValueSet expand(ValueSet theSource, ValueSetExpansionOptions theOptions) {
return myTerminologySvc.expandValueSet(theOptions, theSource);
}
@Override
@ -107,15 +90,5 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
return retVal;
}
public static void validateHaveExpansionOrThrowInternalErrorException(IValidationSupport.ValueSetExpansionOutcome theRetVal) {
if (theRetVal != null && theRetVal.getValueSet() == null) {
throw new InternalErrorException("Unable to expand ValueSet: " + theRetVal.getError());
}
if (theRetVal == null) {
throw new InternalErrorException("Unable to expand ValueSet");
}
}
}

View File

@ -44,42 +44,21 @@ import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateC
public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter);
return expand(source, theOptions);
}
@Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter, theOffset, theCount);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter) {
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, theUri, theFilter);
public ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, theUri);
return ValueSet40_50.convertValueSet(canonicalOutput);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, theUri, theFilter);
return ValueSet40_50.convertValueSet(canonicalOutput);
}
@Override
public ValueSet expand(ValueSet theSource, String theFilter) {
public ValueSet expand(ValueSet theSource, ValueSetExpansionOptions theOptions) {
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(null, canonicalInput, theFilter);
return ValueSet40_50.convertValueSet(canonicalOutput);
}
@Override
public ValueSet expand(ValueSet theSource, String theFilter, int theOffset, int theCount) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount);
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, canonicalInput);
return ValueSet40_50.convertValueSet(canonicalOutput);
}

View File

@ -0,0 +1,47 @@
package ca.uhn.fhir.jpa.entity;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ITermValueSetConceptView {
String getConceptSystemUrl();
String getConceptCode();
String getConceptDisplay();
Long getSourceConceptPid();
String getSourceConceptDirectParentPids();
Long getConceptPid();
Long getDesignationPid();
String getDesignationUseSystem();
String getDesignationUseCode();
String getDesignationUseDisplay();
String getDesignationVal();
String getDesignationLang();
}

View File

@ -388,7 +388,7 @@ public class TermConcept implements Serializable {
b.append("NONE");
}
myParentPids = b.toString();
setParentPids(b.toString());
}
public TermConcept setParentPids(String theParentPids) {

View File

@ -27,7 +27,21 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.annotation.Nonnull;
import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@ -60,6 +74,9 @@ public class TermValueSetConcept implements Serializable {
@Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false)
private Long myValueSetPid;
@Column(name = "INDEX_STATUS", nullable = true)
private Long myIndexStatus;
@Column(name = "VALUESET_ORDER", nullable = false)
private int myOrder;
@ -69,6 +86,13 @@ public class TermValueSetConcept implements Serializable {
@Transient
private String myValueSetName;
@Column(name = "SOURCE_PID", nullable = true)
private Long mySourceConceptPid;
@Lob
@Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true)
private String mySourceConceptDirectParentPids;
@Column(name = "SYSTEM_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem;
@ -87,6 +111,13 @@ public class TermValueSetConcept implements Serializable {
@Transient
private transient Integer myHashCode;
/**
* Constructor
*/
public TermValueSetConcept() {
super();
}
public Long getId() {
return myId;
}
@ -219,4 +250,20 @@ public class TermValueSetConcept implements Serializable {
.append(myDesignations != null ? ("myDesignations - size=" + myDesignations.size()) : ("myDesignations=(null)"))
.toString();
}
public Long getIndexStatus() {
return myIndexStatus;
}
public void setIndexStatus(Long theIndexStatus) {
myIndexStatus = theIndexStatus;
}
public void setSourceConceptPid(Long theSourceConceptPid) {
mySourceConceptPid = theSourceConceptPid;
}
public void setSourceConceptDirectParentPids(String theSourceConceptDirectParentPids) {
mySourceConceptDirectParentPids = theSourceConceptDirectParentPids;
}
}

View File

@ -20,16 +20,20 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.io.IOUtils;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.sql.Clob;
import java.sql.SQLException;
@Entity
@Immutable
@ -39,26 +43,28 @@ import java.io.Serializable;
* because hibernate won't allow the view the function without it, but
*/
"SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " +
" vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vscd.PID AS DESIGNATION_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
"FROM TRM_VALUESET_CONCEPT vsc " +
"LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID"
" vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vsc.SOURCE_PID AS SOURCE_PID, " +
" vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " +
" vscd.PID AS DESIGNATION_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
"FROM TRM_VALUESET_CONCEPT vsc " +
"LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID"
)
public class TermValueSetConceptView implements Serializable {
public class TermValueSetConceptView implements Serializable, ITermValueSetConceptView {
private static final long serialVersionUID = 1L;
@Id
@Column(name="PID", length = 1000 /* length only needed to satisfy JpaEntityTest, it's not used*/)
@Column(name = "PID", length = 1000 /* length only needed to satisfy JpaEntityTest, it's not used*/)
private String id; // still set automatically
@Column(name = "CONCEPT_PID")
@ -97,43 +103,76 @@ public class TermValueSetConceptView implements Serializable {
@Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH)
private String myDesignationVal;
@Column(name = "SOURCE_PID", nullable = true)
private Long mySourceConceptPid;
@Lob
@Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true)
private Clob mySourceConceptDirectParentPids;
@Override
public Long getSourceConceptPid() {
return mySourceConceptPid;
}
@Override
public String getSourceConceptDirectParentPids() {
if (mySourceConceptDirectParentPids != null) {
try (Reader characterStream = mySourceConceptDirectParentPids.getCharacterStream()) {
return IOUtils.toString(characterStream);
} catch (IOException | SQLException e) {
throw new InternalErrorException(e);
}
}
return null;
}
@Override
public Long getConceptPid() {
return myConceptPid;
}
@Override
public String getConceptSystemUrl() {
return myConceptSystemUrl;
}
@Override
public String getConceptCode() {
return myConceptCode;
}
@Override
public String getConceptDisplay() {
return myConceptDisplay;
}
@Override
public Long getDesignationPid() {
return myDesignationPid;
}
@Override
public String getDesignationLang() {
return myDesignationLang;
}
@Override
public String getDesignationUseSystem() {
return myDesignationUseSystem;
}
@Override
public String getDesignationUseCode() {
return myDesignationUseCode;
}
@Override
public String getDesignationUseDisplay() {
return myDesignationUseDisplay;
}
@Override
public String getDesignationVal() {
return myDesignationVal;
}

View File

@ -20,18 +20,20 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.io.IOUtils;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Lob;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.sql.Clob;
import java.sql.SQLException;
@Entity
@Immutable
@ -41,26 +43,28 @@ import java.io.Serializable;
* because hibernate won't allow the view the function without it, but
*/
"SELECT CONCAT(vsc.PID, CONCAT(' ', vscd.PID)) AS PID, " +
" vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vscd.PID AS DESIGNATION_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
" vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vsc.SOURCE_PID AS SOURCE_PID, " +
" vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " +
" vscd.PID AS DESIGNATION_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
"FROM TRM_VALUESET_CONCEPT vsc " +
"LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID"
)
public class TermValueSetConceptViewOracle implements Serializable {
public class TermValueSetConceptViewOracle implements Serializable, ITermValueSetConceptView {
private static final long serialVersionUID = 1L;
@Id
@Column(name="PID", length = 1000 /* length only needed to satisfy JpaEntityTest, it's not used*/)
@Column(name = "PID", length = 1000 /* length only needed to satisfy JpaEntityTest, it's not used*/)
private String id; // still set automatically
@Column(name = "CONCEPT_PID")
@ -99,43 +103,76 @@ public class TermValueSetConceptViewOracle implements Serializable {
@Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH)
private String myDesignationVal;
@Column(name = "SOURCE_PID", nullable = true)
private Long mySourceConceptPid;
@Lob
@Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true)
private Clob mySourceConceptDirectParentPids;
@Override
public Long getConceptPid() {
return myConceptPid;
}
@Override
public String getConceptSystemUrl() {
return myConceptSystemUrl;
}
@Override
public String getConceptCode() {
return myConceptCode;
}
@Override
public String getConceptDisplay() {
return myConceptDisplay;
}
@Override
public Long getSourceConceptPid() {
return mySourceConceptPid;
}
@Override
public String getSourceConceptDirectParentPids() {
if (mySourceConceptDirectParentPids != null) {
try (Reader characterStream = mySourceConceptDirectParentPids.getCharacterStream()) {
return IOUtils.toString(characterStream);
} catch (IOException | SQLException e) {
throw new InternalErrorException(e);
}
}
return null;
}
@Override
public Long getDesignationPid() {
return myDesignationPid;
}
@Override
public String getDesignationLang() {
return myDesignationLang;
}
@Override
public String getDesignationUseSystem() {
return myDesignationUseSystem;
}
@Override
public String getDesignationUseCode() {
return myDesignationUseCode;
}
@Override
public String getDesignationUseDisplay() {
return myDesignationUseDisplay;
}
@Override
public String getDesignationVal() {
return myDesignationVal;
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.provider;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
@ -87,8 +88,11 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
}
}
private String toFilterString(StringDt theFilter) {
return theFilter != null ? theFilter.getValue() : null;
private ValueSetExpansionOptions toFilterString(StringDt theFilter) {
if (theFilter != null) {
return ValueSetExpansionOptions.forOffsetAndCount(0, 1000).setFilter(theFilter.getValue());
}
return null;
}
@Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters = {

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.provider.dstu3;
*/
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2;
@ -29,14 +30,24 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.IntegerType;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import javax.servlet.http.HttpServletRequest;
import static ca.uhn.fhir.jpa.provider.r4.BaseJpaResourceProviderValueSetR4.createValueSetExpansionOptions;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDstu3<ValueSet> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaResourceProviderValueSetDstu3.class);
@Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true)
public ValueSet expand(
@ -51,6 +62,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount,
@OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, min = 0, max = 1, typeName = "boolean") IPrimitiveType<Boolean> theIncludeHierarchy,
RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart();
@ -71,56 +83,21 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.");
}
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
if (theOffset != null && theOffset.hasValue()) {
if (theOffset.getValue() >= 0) {
offset = theOffset.getValue();
} else {
throw new InvalidRequestException("offset parameter for $expand operation must be >= 0 when specified. offset: " + theOffset.getValue());
}
}
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
if (theCount != null && theCount.hasValue()) {
if (theCount.getValue() >= 0) {
count = theCount.getValue();
} else {
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
}
}
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
if (count > countMax) {
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
count = countMax;
}
ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(url.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter), offset, count);
}
if (haveId) {
return dao.expand(theId, options, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(url.getValue() + "|" + theValueSetVersion.getValue(), options);
} else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count);
return dao.expandByIdentifier(url.getValue(), options);
}
} else {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(url.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter));
}
} else {
return dao.expand(theValueSet, toFilterString(theFilter));
}
return dao.expand(theValueSet, options);
}
} finally {
endRequest(theServletRequest);
@ -128,11 +105,6 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
}
private String toFilterString(StringType theFilter) {
return theFilter != null ? theFilter.getValue() : null;
}
@Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class),

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.jpa.provider.r4;
*/
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2;
@ -29,7 +31,17 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import javax.servlet.http.HttpServletRequest;
@ -48,6 +60,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount,
@OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, min = 0, max = 1, typeName = "boolean") IPrimitiveType<Boolean> theIncludeHierarchy,
RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart();
@ -63,69 +76,28 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
}
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
if (theOffset != null && theOffset.hasValue()) {
if (theOffset.getValue() >= 0) {
offset = theOffset.getValue();
} else {
throw new InvalidRequestException("offset parameter for $expand operation must be >= 0 when specified. offset: " + theOffset.getValue());
}
}
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
if (theCount != null && theCount.hasValue()) {
if (theCount.getValue() >= 0) {
count = theCount.getValue();
} else {
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
}
}
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
if (count > countMax) {
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
count = countMax;
}
ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count);
}
if (haveId) {
return dao.expand(theId, options, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), options);
} else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count);
return dao.expandByIdentifier(theUrl.getValue(), options);
}
} else {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter));
}
} else {
return dao.expand(theValueSet, toFilterString(theFilter));
}
return dao.expand(theValueSet, options);
}
} finally {
endRequest(theServletRequest);
}
}
private String toFilterString(StringType theFilter) {
return theFilter != null ? theFilter.getValue() : null;
}
@SuppressWarnings("unchecked")
@Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class),
@ -167,6 +139,42 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
}
}
public static ValueSetExpansionOptions createValueSetExpansionOptions(DaoConfig theDaoConfig, IPrimitiveType<Integer> theOffset, IPrimitiveType<Integer> theCount, IPrimitiveType<Boolean> theIncludeHierarchy, IPrimitiveType<String> theFilter) {
int offset = theDaoConfig.getPreExpandValueSetsDefaultOffset();
if (theOffset != null && theOffset.hasValue()) {
if (theOffset.getValue() >= 0) {
offset = theOffset.getValue();
} else {
throw new InvalidRequestException("offset parameter for $expand operation must be >= 0 when specified. offset: " + theOffset.getValue());
}
}
int count = theDaoConfig.getPreExpandValueSetsDefaultCount();
if (theCount != null && theCount.hasValue()) {
if (theCount.getValue() >= 0) {
count = theCount.getValue();
} else {
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
}
}
int countMax = theDaoConfig.getPreExpandValueSetsMaxCount();
if (count > countMax) {
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
count = countMax;
}
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(offset, count);
if (theIncludeHierarchy != null && Boolean.TRUE.equals(theIncludeHierarchy.getValue())) {
options.setIncludeHierarchy(true);
}
if (theFilter != null) {
options.setFilter(theFilter.getValue());
}
return options;
}
private static boolean moreThanOneTrue(boolean... theBooleans) {
boolean haveOne = false;

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.provider.r5;
*/
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2;
@ -29,14 +30,24 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import javax.servlet.http.HttpServletRequest;
import static ca.uhn.fhir.jpa.provider.r4.BaseJpaResourceProviderValueSetR4.createValueSetExpansionOptions;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<ValueSet> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaResourceProviderValueSetR5.class);
@Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true)
public ValueSet expand(
@ -48,6 +59,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount,
@OperationParam(name = JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, min = 0, max = 1, typeName = "boolean") IPrimitiveType<Boolean> theIncludeHierarchy,
RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart();
@ -63,56 +75,21 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
}
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
if (theOffset != null && theOffset.hasValue()) {
if (theOffset.getValue() >= 0) {
offset = theOffset.getValue();
} else {
throw new InvalidRequestException("offset parameter for $expand operation must be >= 0 when specified. offset: " + theOffset.getValue());
}
}
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
if (theCount != null && theCount.hasValue()) {
if (theCount.getValue() >= 0) {
count = theCount.getValue();
} else {
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
}
}
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
if (count > countMax) {
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
count = countMax;
}
ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count);
}
if (haveId) {
return dao.expand(theId, options, theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), options);
} else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count);
return dao.expandByIdentifier(theUrl.getValue(), options);
}
} else {
if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) {
if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter));
}
} else {
return dao.expand(theValueSet, toFilterString(theFilter));
}
return dao.expand(theValueSet, options);
}
} finally {
endRequest(theServletRequest);
@ -120,12 +97,6 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
}
private String toFilterString(StringType theFilter) {
return theFilter != null ? theFilter.getValue() : null;
}
@SuppressWarnings("unchecked")
@Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class),

View File

@ -41,6 +41,7 @@ import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptViewDao;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptViewOracleDao;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetDao;
import ca.uhn.fhir.jpa.entity.ITermValueSetConceptView;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
@ -52,8 +53,6 @@ import ca.uhn.fhir.jpa.entity.TermConceptPropertyBinder;
import ca.uhn.fhir.jpa.entity.TermConceptPropertyTypeEnum;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptView;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptViewOracle;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.sched.HapiJob;
@ -153,6 +152,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@ -251,19 +251,27 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
String code = theConcept.getCode();
String display = theConcept.getDisplay();
Long sourceConceptPid = theConcept.getId();
String directParentPids = theConcept
.getParents()
.stream()
.map(t -> t.getParent().getId().toString())
.collect(Collectors.joining(" "));
Collection<TermConceptDesignation> designations = theConcept.getDesignations();
if (StringUtils.isNotEmpty(theValueSetIncludeVersion)) {
return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem + "|" + theValueSetIncludeVersion, code, display);
return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem + "|" + theValueSetIncludeVersion, code, display, sourceConceptPid, directParentPids);
} else {
return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem, code, display);
return addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, codeSystem, code, display, sourceConceptPid, directParentPids);
}
}
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, boolean theAdd, String theCodeSystem, String theCodeSystemVersion, String theCode, String theDisplay) {
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, boolean theAdd, String theCodeSystem, String theCodeSystemVersion, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
if (StringUtils.isNotEmpty(theCodeSystemVersion)) {
if (isNoneBlank(theCodeSystem, theCode)) {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem + "|" + theCodeSystemVersion, theCode, theDisplay, null);
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem + "|" + theCodeSystemVersion, theCode, theDisplay, null, theSourceConceptPid, theSourceConceptDirectParentPids);
}
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
@ -272,7 +280,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
} else {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, null);
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, null, theSourceConceptPid, theSourceConceptDirectParentPids);
}
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
@ -281,10 +289,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
private boolean addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, String theCodeSystem, String theCode, String theDisplay) {
private boolean addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, String theCodeSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
if (isNoneBlank(theCodeSystem, theCode)) {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations);
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations, theSourceConceptPid, theSourceConceptDirectParentPids);
return true;
}
@ -353,10 +361,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Override
@Transactional
public List<FhirVersionIndependentConcept> expandValueSetIntoConceptList(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl) {
String expansionFilter = null;
// TODO: DM 2019-09-10 - This is problematic because an incorrect URL that matches ValueSet.id will not be found in the terminology tables but will yield a ValueSet here. Depending on the ValueSet, the expansion may time-out.
ValueSet expanded = expandValueSet(theExpansionOptions, theValueSetCanonicalUrl, expansionFilter);
ValueSet expanded = expandValueSet(theExpansionOptions, theValueSetCanonicalUrl);
ArrayList<FhirVersionIndependentConcept> retVal = new ArrayList<>();
for (ValueSet.ValueSetExpansionContainsComponent nextContains : expanded.getExpansion().getContains()) {
@ -367,25 +374,23 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Override
@Transactional
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl, @Nullable String theExpansionFilter) {
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl) {
ValueSet valueSet = fetchCanonicalValueSetFromCompleteContext(theValueSetCanonicalUrl);
if (valueSet == null) {
throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetCanonicalUrl));
}
return expandValueSet(theExpansionOptions, valueSet, theExpansionFilter);
return expandValueSet(theExpansionOptions, valueSet);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
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));
String filter = null;
if (theExpansionOptions != null) {
filter = theExpansionOptions.getFilter();
}
return expandValueSet(theExpansionOptions, theValueSetToExpand, ExpansionFilter.fromFilterString(filter));
}
private ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, ExpansionFilter theFilter) {
@ -395,7 +400,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
int offset = expansionOptions.getOffset();
int count = expansionOptions.getCount();
ValueSetExpansionComponentWithConceptAccumulator accumulator = new ValueSetExpansionComponentWithConceptAccumulator(myContext, count);
ValueSetExpansionComponentWithConceptAccumulator accumulator = new ValueSetExpansionComponentWithConceptAccumulator(myContext, count, expansionOptions.isIncludeHierarchy());
accumulator.setHardExpansionMaximumSize(myDaoConfig.getMaximumExpansionSize());
accumulator.setSkipCountRemaining(offset);
accumulator.setIdentifier(UUID.randomUUID().toString());
@ -424,6 +429,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
.setValue(new StringType(next));
}
if (expansionOptions.isIncludeHierarchy()) {
accumulator.applyHierarchy();
}
return valueSet;
}
@ -469,124 +479,14 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
*/
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion");
theAccumulator.addMessage(msg);
if (isOracleDialect()) {
expandConceptsOracle(theAccumulator, termValueSet, theFilter, theAdd);
} else {
expandConcepts(theAccumulator, termValueSet, theFilter, theAdd);
}
expandConcepts(theAccumulator, termValueSet, theFilter, theAdd, isOracleDialect());
}
private boolean isOracleDialect() {
return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect;
}
private void expandConceptsOracle(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd) {
// Literal copy paste from expandConcepts but tailored for Oracle since we can't reliably extend the DAO and hibernate classes
Integer offset = theAccumulator.getSkipCountRemaining();
offset = ObjectUtils.defaultIfNull(offset, 0);
offset = Math.min(offset, theTermValueSet.getTotalConcepts().intValue());
Integer count = theAccumulator.getCapacityRemaining();
count = defaultIfNull(count, myDaoConfig.getMaximumExpansionSize());
int conceptsExpanded = 0;
int designationsExpanded = 0;
int toIndex = offset + count;
Collection<TermValueSetConceptViewOracle> conceptViews;
boolean wasFilteredResult = false;
String filterDisplayValue = null;
if (!theFilter.getFilters().isEmpty() && JpaConstants.VALUESET_FILTER_DISPLAY.equals(theFilter.getFilters().get(0).getProperty()) && theFilter.getFilters().get(0).getOp() == ValueSet.FilterOperator.EQUAL) {
filterDisplayValue = lowerCase(theFilter.getFilters().get(0).getValue().replace("%", "[%]"));
String displayValue = "%" + lowerCase(filterDisplayValue) + "%";
conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
wasFilteredResult = true;
} else {
// TODO JA HS: I'm pretty sure we are overfetching here. test says offset 3, count 4, but we are fetching index 3 -> 10 here, grabbing 7 concepts.
//Specifically this test testExpandInline_IncludePreExpandedValueSetByUri_FilterOnDisplay_LeftMatch_SelectRange
conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId(offset, toIndex, theTermValueSet.getId());
theAccumulator.consumeSkipCount(offset);
if (theAdd) {
theAccumulator.incrementOrDecrementTotalConcepts(true, theTermValueSet.getTotalConcepts().intValue());
}
}
if (conceptViews.isEmpty()) {
logConceptsExpanded("No concepts to expand. ", theTermValueSet, conceptsExpanded);
return;
}
Map<Long, FhirVersionIndependentConcept> pidToConcept = new LinkedHashMap<>();
ArrayListMultimap<Long, TermConceptDesignation> pidToDesignations = ArrayListMultimap.create();
for (TermValueSetConceptViewOracle conceptView : conceptViews) {
String system = conceptView.getConceptSystemUrl();
String code = conceptView.getConceptCode();
String display = conceptView.getConceptDisplay();
//-- this is quick solution, may need to revisit
if (!applyFilter(display, filterDisplayValue))
continue;
Long conceptPid = conceptView.getConceptPid();
if (!pidToConcept.containsKey(conceptPid)) {
FhirVersionIndependentConcept concept = new FhirVersionIndependentConcept(system, code, display);
pidToConcept.put(conceptPid, concept);
}
// TODO: DM 2019-08-17 - Implement includeDesignations parameter for $expand operation to designations optional.
if (conceptView.getDesignationPid() != null) {
TermConceptDesignation designation = new TermConceptDesignation();
designation.setUseSystem(conceptView.getDesignationUseSystem());
designation.setUseCode(conceptView.getDesignationUseCode());
designation.setUseDisplay(conceptView.getDesignationUseDisplay());
designation.setValue(conceptView.getDesignationVal());
designation.setLanguage(conceptView.getDesignationLang());
pidToDesignations.put(conceptPid, designation);
if (++designationsExpanded % 250 == 0) {
logDesignationsExpanded("Expansion of designations in progress. ", theTermValueSet, designationsExpanded);
}
}
if (++conceptsExpanded % 250 == 0) {
logConceptsExpanded("Expansion of concepts in progress. ", theTermValueSet, conceptsExpanded);
}
}
for (Long nextPid : pidToConcept.keySet()) {
FhirVersionIndependentConcept concept = pidToConcept.get(nextPid);
List<TermConceptDesignation> designations = pidToDesignations.get(nextPid);
String system = concept.getSystem();
String code = concept.getCode();
String display = concept.getDisplay();
if (theAdd) {
if (theAccumulator.getCapacityRemaining() != null) {
if (theAccumulator.getCapacityRemaining() == 0) {
break;
}
}
theAccumulator.includeConceptWithDesignations(system, code, display, designations);
} else {
boolean removed = theAccumulator.excludeConcept(system, code);
if (removed) {
theAccumulator.incrementOrDecrementTotalConcepts(false, 1);
}
}
}
if (wasFilteredResult && theAdd) {
theAccumulator.incrementOrDecrementTotalConcepts(true, pidToConcept.size());
}
logDesignationsExpanded("Finished expanding designations. ", theTermValueSet, designationsExpanded);
logConceptsExpanded("Finished expanding concepts. ", theTermValueSet, conceptsExpanded);
}
private void expandConcepts(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd) {
private void expandConcepts(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd, boolean theOracle) {
// NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its copy pasted sibling
Integer offset = theAccumulator.getSkipCountRemaining();
offset = ObjectUtils.defaultIfNull(offset, 0);
@ -599,19 +499,26 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
int designationsExpanded = 0;
int toIndex = offset + count;
Collection<TermValueSetConceptView> conceptViews;
Collection<TermValueSetConceptViewOracle> conceptViewsOracle;
Collection<? extends ITermValueSetConceptView> conceptViews;
boolean wasFilteredResult = false;
String filterDisplayValue = null;
if (!theFilter.getFilters().isEmpty() && JpaConstants.VALUESET_FILTER_DISPLAY.equals(theFilter.getFilters().get(0).getProperty()) && theFilter.getFilters().get(0).getOp() == ValueSet.FilterOperator.EQUAL) {
filterDisplayValue = lowerCase(theFilter.getFilters().get(0).getValue().replace("%", "[%]"));
String displayValue = "%" + lowerCase(filterDisplayValue) + "%";
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
if (theOracle) {
conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
} else {
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(theTermValueSet.getId(), displayValue);
}
wasFilteredResult = true;
} else {
// TODO JA HS: I'm pretty sure we are overfetching here. test says offset 3, count 4, but we are fetching index 3 -> 10 here, grabbing 7 concepts.
//Specifically this test testExpandInline_IncludePreExpandedValueSetByUri_FilterOnDisplay_LeftMatch_SelectRange
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(offset, toIndex, theTermValueSet.getId());
if (theOracle) {
conceptViews = myTermValueSetConceptViewOracleDao.findByTermValueSetId(offset, toIndex, theTermValueSet.getId());
} else {
conceptViews = myTermValueSetConceptViewDao.findByTermValueSetId(offset, toIndex, theTermValueSet.getId());
}
theAccumulator.consumeSkipCount(offset);
if (theAdd) {
theAccumulator.incrementOrDecrementTotalConcepts(true, theTermValueSet.getTotalConcepts().intValue());
@ -625,8 +532,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
Map<Long, FhirVersionIndependentConcept> pidToConcept = new LinkedHashMap<>();
ArrayListMultimap<Long, TermConceptDesignation> pidToDesignations = ArrayListMultimap.create();
Map<Long, Long> pidToSourcePid = new HashMap<>();
Map<Long, String> pidToSourceDirectParentPids = new HashMap<>();
for (TermValueSetConceptView conceptView : conceptViews) {
for (ITermValueSetConceptView conceptView : conceptViews) {
String system = conceptView.getConceptSystemUrl();
String code = conceptView.getConceptCode();
@ -657,6 +566,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
if (theAccumulator.isTrackingHierarchy()) {
pidToSourcePid.put(conceptPid, conceptView.getSourceConceptPid());
pidToSourceDirectParentPids.put(conceptPid, conceptView.getSourceConceptDirectParentPids());
}
if (++conceptsExpanded % 250 == 0) {
logConceptsExpanded("Expansion of concepts in progress. ", theTermValueSet, conceptsExpanded);
}
@ -676,7 +590,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
theAccumulator.includeConceptWithDesignations(system, code, display, designations);
Long sourceConceptPid = pidToSourcePid.get(nextPid);
String sourceConceptDirectParentPids = pidToSourceDirectParentPids.get(nextPid);
theAccumulator.includeConceptWithDesignations(system, code, display, designations, sourceConceptPid, sourceConceptDirectParentPids);
} else {
boolean removed = theAccumulator.excludeConcept(system, code);
if (removed) {
@ -1158,7 +1074,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
private void addOrRemoveCode(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, boolean theAdd, String theSystem, String theCode, String theDisplay) {
if (theAdd && theAddedCodes.add(theSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConcept(theSystem, theCode, theDisplay);
theValueSetCodeAccumulator.includeConcept(theSystem, theCode, theDisplay, null, null);
}
if (!theAdd && theAddedCodes.remove(theSystem + "|" + theCode)) {
theValueSetCodeAccumulator.excludeConcept(theSystem, theCode);
@ -1506,7 +1422,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
if (theInclude.getConcept().isEmpty()) {
for (TermConcept next : theVersion.getConcepts()) {
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, theAdd, theSystem, theInclude.getVersion(), next.getCode(), next.getDisplay());
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, theAdd, theSystem, theInclude.getVersion(), next.getCode(), next.getDisplay(), next.getId(), next.getParentPidsAsString());
}
}
@ -1514,7 +1430,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
if (!theSystem.equals(theInclude.getSystem()) && isNotBlank(theSystem)) {
continue;
}
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, theAdd, theSystem, theInclude.getVersion(), next.getCode(), next.getDisplay());
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, theAdd, theSystem, theInclude.getVersion(), next.getCode(), next.getDisplay(), null, null);
}

View File

@ -29,9 +29,9 @@ public interface IValueSetConceptAccumulator {
void addMessage(String theMessage);
void includeConcept(String theSystem, String theCode, String theDisplay);
void includeConcept(String theSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids);
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations);
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations, Long theSourceConceptPid, String theSourceConceptDirectParentPids);
/**
* @return Returns <code>true</code> if the code was actually present and was removed
@ -48,6 +48,10 @@ public interface IValueSetConceptAccumulator {
return null;
}
default boolean isTrackingHierarchy() {
return true;
}
@Nullable
default void consumeSkipCount(int theSkipCountToConsume) {
// nothing

View File

@ -66,13 +66,13 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
}
@Override
public void includeConcept(String theSystem, String theCode, String theDisplay) {
saveConcept(theSystem, theCode, theDisplay);
public void includeConcept(String theSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
saveConcept(theSystem, theCode, theDisplay, theSourceConceptPid, theSourceConceptDirectParentPids);
}
@Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay);
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay, theSourceConceptPid, theSourceConceptDirectParentPids);
if (theDesignations != null) {
for (TermConceptDesignation designation : theDesignations) {
saveConceptDesignation(concept, designation);
@ -117,7 +117,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
return false;
}
private TermValueSetConcept saveConcept(String theSystem, String theCode, String theDisplay) {
private TermValueSetConcept saveConcept(String theSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystem, "ValueSet contains a concept with no system value");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "ValueSet contains a concept with no code value");
@ -135,6 +135,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
if (isNotBlank(theDisplay)) {
concept.setDisplay(theDisplay);
}
concept.setSourceConceptPid(theSourceConceptPid);
concept.setSourceConceptDirectParentPids(theSourceConceptDirectParentPids);
myValueSetConceptDao.save(concept);
myValueSetDao.save(myTermValueSet.incrementTotalConcepts());

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.term;
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import ca.uhn.fhir.model.api.annotation.Block;
@ -32,9 +31,15 @@ import org.hl7.fhir.r4.model.ValueSet;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Block()
public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetConceptAccumulator {
@ -45,25 +50,21 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
private List<String> myMessages;
private int myAddedConcepts;
private Integer myTotalConcepts;
/**
* Constructor
*
* @param theDaoConfig Will be used to determine the max capacity for this accumulator
*/
public ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, DaoConfig theDaoConfig) {
this(theContext, theDaoConfig.getMaximumExpansionSize());
}
private Map<Long, ValueSet.ValueSetExpansionContainsComponent> mySourcePidToConcept = new HashMap<>();
private Map<ValueSet.ValueSetExpansionContainsComponent, String> myConceptToSourceDirectParentPids = new HashMap<>();
private boolean myTrackingHierarchy;
/**
* Constructor
*
* @param theMaxCapacity The maximum number of results this accumulator will accept before throwing
* an {@link InternalErrorException}
* @param theTrackingHierarchy
*/
ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, int theMaxCapacity) {
ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, int theMaxCapacity, boolean theTrackingHierarchy) {
myMaxCapacity = theMaxCapacity;
myContext = theContext;
myTrackingHierarchy = theTrackingHierarchy;
}
@Nonnull
@ -79,6 +80,11 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
return Collections.unmodifiableList(myMessages);
}
@Override
public boolean isTrackingHierarchy() {
return myTrackingHierarchy;
}
@Override
public void addMessage(String theMessage) {
if (myMessages == null) {
@ -88,7 +94,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
}
@Override
public void includeConcept(String theSystem, String theCode, String theDisplay) {
public void includeConcept(String theSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
if (mySkipCountRemaining > 0) {
mySkipCountRemaining--;
return;
@ -103,7 +109,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
}
@Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
if (mySkipCountRemaining > 0) {
mySkipCountRemaining--;
return;
@ -112,6 +118,14 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
incrementConceptsCount();
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
if (theSourceConceptPid != null) {
mySourcePidToConcept.put(theSourceConceptPid, contains);
}
if (theSourceConceptDirectParentPids != null) {
myConceptToSourceDirectParentPids.put(contains, theSourceConceptDirectParentPids);
}
setSystemAndVersion(theSystem, contains);
contains.setCode(theCode);
contains.setDisplay(theDisplay);
@ -215,4 +229,29 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
public void setHardExpansionMaximumSize(int theHardExpansionMaximumSize) {
myHardExpansionMaximumSize = theHardExpansionMaximumSize;
}
public void applyHierarchy() {
for (int i = 0; i < this.getContains().size(); i++) {
ValueSet.ValueSetExpansionContainsComponent nextContains = this.getContains().get(i);
String directParentPidsString = myConceptToSourceDirectParentPids.get(nextContains);
if (isNotBlank(directParentPidsString)) {
List<Long> directParentPids = Arrays.stream(directParentPidsString.split(" ")).map(t -> Long.parseLong(t)).collect(Collectors.toList());
boolean firstMatch = false;
for (Long next : directParentPids) {
ValueSet.ValueSetExpansionContainsComponent parentConcept = mySourcePidToConcept.get(next);
if (parentConcept != null) {
if (!firstMatch) {
firstMatch = true;
this.getContains().remove(i);
i--;
}
parentConcept.addContains(nextContains);
}
}
}
}
}
}

View File

@ -58,12 +58,10 @@ import java.util.Set;
*/
public interface ITermReadSvc extends IValidationSupport {
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl, @Nullable String theExpansionFilter);
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl);
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);
/**

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.dstu2;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
@ -180,7 +181,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -193,7 +194,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
* Filter with code
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("11378"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("11378"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -205,7 +206,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
@Test
public void testExpandByIdentifier() {
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", "11378");
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", new ValueSetExpansionOptions().setFilter("11378"));
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -220,7 +221,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
@Test
public void testExpandByValueSet() throws IOException {
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-2.xml");
ValueSet expanded = myValueSetDao.expand(toExpand, "11378");
ValueSet expanded = myValueSetDao.expand(toExpand, new ValueSetExpansionOptions().setFilter("11378"));
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -235,7 +236,7 @@ public class FhirResourceDaoValueSetDstu2Test extends BaseJpaDstu2Test {
@Test
public void testValidateCodeForCodeSystemOperationNotSupported() {
try {
((IFhirResourceDaoCodeSystem)myValueSetDao).validateCode(null, null, null, null, null, null, null, null);
((IFhirResourceDaoCodeSystem) myValueSetDao).validateCode(null, null, null, null, null, null, null, null);
fail();
} catch (UnsupportedOperationException theE) {
assertNotNull(theE);

View File

@ -1,16 +1,17 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -18,7 +19,6 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
@ -38,7 +38,6 @@ import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -48,21 +47,22 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.empty;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3TerminologyTest.class);
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3TerminologyTest.class);
@Autowired
private CachingValidationSupport myCachingValidationSupport;
@Autowired
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
@AfterEach
public void after() {
@ -138,7 +138,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.getConcepts().add(parentA);
for (int i = 0; i < 450; i++) {
TermConcept childI = new TermConcept(cs, "subCodeA"+i).setDisplay("Sub-code A"+i);
TermConcept childI = new TermConcept(cs, "subCodeA" + i).setDisplay("Sub-code A" + i);
parentA.addChild(childI, RelationshipTypeEnum.ISA);
}
@ -146,18 +146,15 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.getConcepts().add(parentB);
for (int i = 0; i < 450; i++) {
TermConcept childI = new TermConcept(cs, "subCodeB"+i).setDisplay("Sub-code B"+i);
TermConcept childI = new TermConcept(cs, "subCodeB" + i).setDisplay("Sub-code B" + i);
parentB.addChild(childI, RelationshipTypeEnum.ISA);
}
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), URL_MY_CODE_SYSTEM, "SYSTEM NAME", "SYSTEM VERSION" , cs, table);
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), URL_MY_CODE_SYSTEM, "SYSTEM NAME", "SYSTEM VERSION", cs, table);
myTermDeferredStorageSvc.saveAllDeferred();
}
@Autowired
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
private void createExternalCsAndLocalVs() {
CodeSystem codeSystem = createExternalCs();
@ -191,7 +188,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
dogs.addChild(beagle, RelationshipTypeEnum.ISA);
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), URL_MY_CODE_SYSTEM,"SYSTEM NAME", "SYSTEM VERSION" , cs, table);
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), URL_MY_CODE_SYSTEM, "SYSTEM NAME", "SYSTEM VERSION", cs, table);
return codeSystem;
}
@ -202,14 +199,14 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
)
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
)
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem
.addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on
myCodeSystemDao.create(codeSystem, mySrd);
@ -265,12 +262,12 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem
.addConcept().setCode("B").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code AB"));
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code AB"));
//@formatter:on
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
@ -306,20 +303,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result);
assertEquals(4, result.getExpansion().getTotal());
@ -334,7 +331,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
public void testExpandWithOpEquals() {
ValueSet result = myValueSetDao.expandByIdentifier("http://hl7.org/fhir/ValueSet/doc-typecodes", "");
ValueSet result = myValueSetDao.expandByIdentifier("http://hl7.org/fhir/ValueSet/doc-typecodes", new ValueSetExpansionOptions().setFilter(""));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result));
}
@ -347,20 +344,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -377,20 +374,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
.setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
.setSystem(codeSystem.getUrl())
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("dogs");
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "hel");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("hel"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -408,7 +405,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -524,7 +521,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myTerminologyDeferredStorageSvc.saveDeferred();
myTerminologyDeferredStorageSvc.saveDeferred();
IValidationSupport.LookupCodeResult lookupResults = myCodeSystemDao.lookupCode(new StringType("childAA"), new StringType(URL_MY_CODE_SYSTEM),null, mySrd);
IValidationSupport.LookupCodeResult lookupResults = myCodeSystemDao.lookupCode(new StringType("childAA"), new StringType(URL_MY_CODE_SYSTEM), null, mySrd);
assertEquals(true, lookupResults.isFound());
ValueSet vs = new ValueSet();
@ -628,9 +625,9 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose()
.addInclude()
.setSystem(codeSystem.getUrl());
.setSystem(codeSystem.getUrl());
ValueSet result = myValueSetDao.expand(valueSet, "");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result);
assertEquals(5, result.getExpansion().getTotal());
@ -711,7 +708,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.setResource(table);
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), "http://snomed.info/sct", "Snomed CT", "SYSTEM VERSION" , cs, table);
myTermCodeSystemStorageSvc.storeNewCodeSystemVersion(new ResourcePersistentId(table.getId()), "http://snomed.info/sct", "Snomed CT", "SYSTEM VERSION", cs, table);
StringType code = new StringType("ParentA");
StringType system = new StringType("http://snomed.info/sct");
@ -1130,7 +1127,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
try {
myObservationDao.search(params);
} catch(InvalidRequestException e) {
} catch (InvalidRequestException e) {
assertEquals("Unable to expand imported value set: Unable to find imported value set http://non_existant_VS", e.getMessage());
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -99,7 +100,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
private boolean clearDeferredStorageQueue() {
if(!myTerminologyDeferredStorageSvc.isStorageQueueEmpty()) {
if (!myTerminologyDeferredStorageSvc.isStorageQueueEmpty()) {
myTerminologyDeferredStorageSvc.saveAllDeferred();
return false;
} else {
@ -155,7 +156,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -169,7 +170,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
@Test
@Disabled
public void testExpandByIdentifier() {
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", "11378");
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", new ValueSetExpansionOptions().setFilter("11378"));
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
@ -188,7 +189,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
@Disabled
public void testExpandByValueSet() throws IOException {
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
ValueSet expanded = myValueSetDao.expand(toExpand, "11378");
ValueSet expanded = myValueSetDao.expand(toExpand, new ValueSetExpansionOptions().setFilter("11378"));
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -11,6 +11,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.test.utilities.docker.RequiresDocker;
import org.hamcrest.Matchers;
import org.hl7.fhir.instance.model.api.IIdType;
@ -169,7 +170,7 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
ValueSet result = myValueSetDao.expand(vs, "child");
ValueSet result = myValueSetDao.expand(vs, new ValueSetExpansionOptions().setFilter("child"));
logAndValidateValueSet(result);
@ -187,7 +188,7 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
ValueSet result = myValueSetDao.expand(vs, "chi");
ValueSet result = myValueSetDao.expand(vs, new ValueSetExpansionOptions().setFilter("chi"));
logAndValidateValueSet(result);
@ -205,7 +206,7 @@ public class FhirResourceDaoR4SearchWithElasticSearchIT extends BaseJpaTest {
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
ValueSet result = myValueSetDao.expand(vs, "hil");
ValueSet result = myValueSetDao.expand(vs, new ValueSetExpansionOptions().setFilter("hil"));
logAndValidateValueSet(result);

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
@ -344,7 +345,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result);
assertEquals(2, result.getExpansion().getTotal());
@ -379,7 +380,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result);
assertEquals(4, result.getExpansion().getTotal());
@ -409,7 +410,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "hel");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("hel"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -427,7 +428,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -457,7 +458,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal());
@ -677,7 +678,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
public void testExpandWithOpEquals() {
ValueSet result = myValueSetDao.expandByIdentifier("http://hl7.org/fhir/ValueSet/doc-typecodes", "");
ValueSet result = myValueSetDao.expandByIdentifier("http://hl7.org/fhir/ValueSet/doc-typecodes", new ValueSetExpansionOptions().setFilter(""));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result));
}
@ -795,7 +796,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
.addInclude()
.setSystem(codeSystem.getUrl());
ValueSet result = myValueSetDao.expand(valueSet, "");
ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result);
assertEquals(5, result.getExpansion().getTotal());

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
@ -258,8 +259,6 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
OperationOutcome oo;
// Valid code
obs.setValue(new Quantity().setSystem("http://cs").setCode("code1").setValue(123));
try {
@ -1702,7 +1701,8 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
myTermReadSvc.preExpandDeferredValueSetsToTerminologyTables();
ValueSet expansion = myValueSetDao.expand(id, null, 0, 10000, mySrd);
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(0, 10000);
ValueSet expansion = myValueSetDao.expand(id, options, mySrd);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertEquals(2, expansion.getExpansion().getContains().size());

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -221,7 +222,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r5;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
@ -226,7 +227,7 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off

View File

@ -1,21 +1,6 @@
package ca.uhn.fhir.jpa.provider;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
@ -24,12 +9,25 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2Test {
private IIdType myExtensionalVsId;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2ValueSetTest.class);
private IIdType myExtensionalVsId;
@BeforeEach
@Transactional
@ -181,18 +179,18 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
assertThat(resp,
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
"<expansion>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>",
"</contains>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"8450-9\"/>",
"<display value=\"Systolic blood pressure--expiration\"/>",
"</contains>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>",
"</contains>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"8450-9\"/>",
"<display value=\"Systolic blood pressure--expiration\"/>",
"</contains>",
"</expansion>"
));
));
/*
* Filter with display name
@ -206,12 +204,12 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
.execute();
expanded = (ValueSet) respParam.getParameter().get(0).getResource();
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
expanded = myValueSetDao.expand(myExtensionalVsId, new ValueSetExpansionOptions().setFilter("systolic"), mySrd);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
/*
* Filter with code
@ -227,8 +225,8 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
}
@Test
@ -245,8 +243,8 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
}
@ -267,8 +265,8 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
}

View File

@ -8,9 +8,9 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -38,6 +38,7 @@ import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.UrlType;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
@ -53,12 +54,16 @@ import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
import static ca.uhn.fhir.util.HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.is;
@ -1037,6 +1042,165 @@ public class ResourceProviderR4ValueSetNoVerCSNoVerTest extends BaseResourceProv
testValidateCodeOperationByCodeAndSystemInstanceOnInstance();
}
@Test
public void testExpandUsingHierarchy_PreStored_NotPreCalculated() {
createLocalCs();
createHierarchicalVs();
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
ValueSet expansion;
// Non-hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "url", new UrlType(URL_MY_VALUE_SET))
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A", "AA", "AB", "AAA"));
assertEquals(19, myCaptureQueriesListener.getSelectQueries().size());
assertEquals("ValueSet \"ValueSet.url[http://example.com/my_value_set]\" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: NOT_EXPANDED | The ValueSet is waiting to be picked up and pre-expanded by a scheduled task.", expansion.getMeta().getExtensionString(EXT_VALUESET_EXPANSION_MESSAGE));
// Hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "url", new UrlType(URL_MY_VALUE_SET))
.andParameter(JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, new BooleanType("true"))
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains()), containsInAnyOrder("AA", "AB"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains().stream().filter(t->t.getCode().equals("AA")).findFirst().orElseThrow(()->new IllegalArgumentException()).getContains()), containsInAnyOrder("AAA"));
assertEquals(16, myCaptureQueriesListener.getSelectQueries().size());
}
@Test
public void testExpandUsingHierarchy_NotPreStored() {
createLocalCs();
createHierarchicalVs();
myLocalVs.setUrl(null);
ValueSet expansion;
// Non-hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "valueSet", myLocalVs)
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A", "AA", "AB", "AAA"));
assertEquals(15, myCaptureQueriesListener.getSelectQueries().size());
assertEquals(null, expansion.getMeta().getExtensionString(EXT_VALUESET_EXPANSION_MESSAGE));
// Hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "valueSet", myLocalVs)
.andParameter(JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, new BooleanType("true"))
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains()), containsInAnyOrder("AA", "AB"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains().stream().filter(t->t.getCode().equals("AA")).findFirst().orElseThrow(()->new IllegalArgumentException()).getContains()), containsInAnyOrder("AAA"));
assertEquals(14, myCaptureQueriesListener.getSelectQueries().size());
}
@Test
public void testExpandUsingHierarchy_PreStored_PreCalculated() {
createLocalCs();
createHierarchicalVs();
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
ValueSet expansion;
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
// Do a warm-up pass to precache anything that can be pre-cached
myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "url", new UrlType(URL_MY_VALUE_SET))
.returnResourceType(ValueSet.class)
.execute();
// Non-hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "url", new UrlType(URL_MY_VALUE_SET))
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A", "AA", "AB", "AAA"));
assertEquals(3, myCaptureQueriesListener.getSelectQueries().size());
assertEquals("ValueSet was expanded using a pre-calculated expansion", expansion.getMeta().getExtensionString(EXT_VALUESET_EXPANSION_MESSAGE));
// Hierarchical
myCaptureQueriesListener.clear();
expansion = myClient
.operation()
.onType("ValueSet")
.named(JpaConstants.OPERATION_EXPAND)
.withParameter(Parameters.class, "url", new UrlType(URL_MY_VALUE_SET))
.andParameter(JpaConstants.OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY, new BooleanType("true"))
.returnResourceType(ValueSet.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion));
assertThat(toDirectCodes(expansion.getExpansion().getContains()), containsInAnyOrder("A"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains()), containsInAnyOrder("AA", "AB"));
assertThat(toDirectCodes(expansion.getExpansion().getContains().get(0).getContains().stream().filter(t->t.getCode().equals("AA")).findFirst().orElseThrow(()->new IllegalArgumentException()).getContains()), containsInAnyOrder("AAA"));
assertEquals(3, myCaptureQueriesListener.getSelectQueries().size());
}
private void createHierarchicalVs() {
myLocalVs = new ValueSet();
myLocalVs.setUrl(URL_MY_VALUE_SET);
myLocalVs
.getCompose()
.addInclude()
.setSystem(URL_MY_CODE_SYSTEM)
.addFilter()
.setProperty("concept")
.setOp(FilterOperator.ISA)
.setValue("A");
myLocalVs
.getCompose()
.addInclude()
.setSystem(URL_MY_CODE_SYSTEM)
.addConcept()
.setCode("A");
}
public List<String> toDirectCodes(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
List<String> collect = theContains.stream().map(t -> t.getCode()).collect(Collectors.toList());
ourLog.info("Codes: {}", collect);
return collect;
}
private void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId.getIdPart() + "/$validate-code?system=" +

View File

@ -42,7 +42,7 @@ public class ValueSetConceptAccumulatorTest {
@Test
public void testIncludeConcept() {
for (int i = 0; i < 1000; i++) {
myAccumulator.includeConcept("sys", "code", "display");
myAccumulator.includeConcept("sys", "code", "display", null, null);
}
verify(myValueSetConceptDao, times(1000)).save(any());
}

View File

@ -195,7 +195,7 @@ public class ValueSetExpansionR4ElasticsearchIT extends BaseJpaTest {
include.setSystem(CS_URL);
myTermSvc.expandValueSet(null, vs, myValueSetCodeAccumulator);
verify(myValueSetCodeAccumulator, times(9)).includeConceptWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection());
verify(myValueSetCodeAccumulator, times(9)).includeConceptWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection(), nullable(Long.class), nullable(String.class));
}

View File

@ -7,7 +7,6 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
@ -38,11 +37,10 @@ import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@ -228,7 +226,8 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
// ValueSet by ID
{
myCaptureQueriesListener.clear();
ValueSet expandedValueSet = myValueSetDao.expand(vsId, "display value 100", 0, 1000, mySrd);
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(0, 1000).setFilter("display value 100");
ValueSet expandedValueSet = myValueSetDao.expand(vsId, options, mySrd);
List<String> codes = expandedValueSet.getExpansion().getContains().stream().map(t -> t.getCode()).collect(Collectors.toList());
assertThat(codes.toString(), codes, containsInAnyOrder("code100", "code1000", "code1001", "code1002", "code1003", "code1004"));
@ -300,7 +299,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
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" ));
assertThat(toCodes(expandedValueSet).toString(), toCodes(expandedValueSet), contains("code99"));
// Make sure we used the pre-expanded version
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries();
@ -786,7 +785,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(codeSystem.getConcept().size() - expandedValueSet.getExpansion().getOffset(), expandedValueSet.getExpansion().getContains().size());
assertThat(toCodes(expandedValueSet), is(equalTo(expandedConcepts.subList(1,expandedConcepts.size()))));
assertThat(toCodes(expandedValueSet), is(equalTo(expandedConcepts.subList(1, expandedConcepts.size()))));
}
@Test
@ -818,7 +817,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(codeSystem.getConcept().size() - expandedValueSet.getExpansion().getOffset(), expandedValueSet.getExpansion().getContains().size());
assertThat(toCodes(expandedValueSet), is(equalTo(expandedConcepts.subList(1,expandedConcepts.size()))));
assertThat(toCodes(expandedValueSet), is(equalTo(expandedConcepts.subList(1, expandedConcepts.size()))));
}
@Test
@ -953,7 +952,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
include.setSystem(CS_URL);
myTermSvc.expandValueSet(null, vs, myValueSetCodeAccumulator);
verify(myValueSetCodeAccumulator, times(9)).includeConceptWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection());
verify(myValueSetCodeAccumulator, times(9)).includeConceptWithDesignations(anyString(), anyString(), nullable(String.class), anyCollection(), nullable(Long.class), nullable(String.class));
}
@Test
@ -1433,5 +1432,4 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
}
}

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -144,13 +144,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -55,13 +55,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test-utilities</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -87,6 +87,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
version.onTable("HFJ_FORCED_ID").addIndex("20210309.2", "IDX_FORCEID_FID")
.unique(false).withColumns("FORCED_ID");
//-- ValueSet Concept Fulltext Indexing
version.onTable("TRM_VALUESET_CONCEPT").addColumn("20210406.1", "INDEX_STATUS").nullable().type(ColumnTypeEnum.LONG);
version.onTable("TRM_VALUESET_CONCEPT").addColumn("20210406.2", "SOURCE_DIRECT_PARENT_PIDS").nullable().type(ColumnTypeEnum.CLOB);
version.onTable("TRM_VALUESET_CONCEPT").addColumn("20210406.3", "SOURCE_PID").nullable().type(ColumnTypeEnum.LONG);
}
private void init530() {

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -218,6 +218,11 @@ public class JpaConstants {
*/
public static final String DEFAULT_PARTITION_NAME = "DEFAULT";
/**
* Parameter for the $expand operation
*/
public static final String OPERATION_EXPAND_PARAM_INCLUDE_HIERARCHY = "includeHierarchy";
/**
* Non-instantiable
*/

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -164,7 +164,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-converter</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -58,37 +58,37 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r5</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<description>An open-source implementation of the FHIR specification in Java.</description>
<url>https://hapifhir.io</url>

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version>
<version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>