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> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>5.4.0-PRE4-SNAPSHOT</version> <version>5.4.0-PRE5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -32,6 +32,17 @@ public class ValueSetExpansionOptions {
private boolean myFailOnMissingCodeSystem = true; private boolean myFailOnMissingCodeSystem = true;
private int myCount = 1000; private int myCount = 1000;
private int myOffset = 0; 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. * The number of codes to return.
@ -94,6 +105,14 @@ public class ValueSetExpansionOptions {
return this; return this;
} }
public boolean isIncludeHierarchy() {
return myIncludeHierarchy;
}
public void setIncludeHierarchy(boolean theIncludeHierarchy) {
myIncludeHierarchy = theIncludeHierarchy;
}
public static ValueSetExpansionOptions forOffsetAndCount(int theOffset, int theCount) { public static ValueSetExpansionOptions forOffsetAndCount(int theOffset, int theCount) {
return new ValueSetExpansionOptions() return new ValueSetExpansionOptions()
.setOffset(theOffset) .setOffset(theOffset)

View File

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

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

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

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </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.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -28,17 +29,11 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> extends IFhirResourceDao<T> { 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 expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions);
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);
void purgeCaches(); void purgeCaches();

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </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.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport.CodeValidationResult; 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.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; 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.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; 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.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; 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.TokenParam;
import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; 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.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateCodeOptions;
import static ca.uhn.fhir.jpa.util.LogicUtil.multiXor; import static ca.uhn.fhir.jpa.util.LogicUtil.multiXor;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueSet> 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; private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
@ -104,31 +105,32 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
} }
@Override @Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequest) { public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequest) {
ValueSet source = loadValueSetForExpansion(theId, theRequest); ValueSet source = loadValueSetForExpansion(theId, theRequest);
return expand(source, theFilter); return expand(source, theOptions);
} }
@Override @Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequest) { public ValueSet expand(ValueSet source, ValueSetExpansionOptions theOptions) {
throw new UnsupportedOperationException();
}
@Override
public ValueSet expand(ValueSet source, String theFilter) {
ValueSet retVal = new ValueSet(); ValueSet retVal = new ValueSet();
retVal.setDate(DateTimeDt.withCurrentTime()); retVal.setDate(DateTimeDt.withCurrentTime());
String filter = null;
if (theOptions != null) {
filter = theOptions.getFilter();
}
/* /*
* Add composed concepts * Add composed concepts
*/ */
for (ComposeInclude nextInclude : source.getCompose().getInclude()) { for (ComposeInclude nextInclude : source.getCompose().getInclude()) {
for (ComposeIncludeConcept next : nextInclude.getConcept()) { for (ComposeIncludeConcept next : nextInclude.getConcept()) {
if (isBlank(theFilter)) { if (isBlank(filter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay()); addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
} else { } else {
String filter = theFilter.toLowerCase(); filter = filter.toLowerCase();
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) { if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay()); addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
} }
@ -141,19 +143,14 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
*/ */
for (CodeSystemConcept next : source.getCodeSystem().getConcept()) { for (CodeSystemConcept next : source.getCodeSystem().getConcept()) {
addCompose(theFilter, retVal, source, next); addCompose(filter, retVal, source, next);
} }
return retVal; return retVal;
} }
@Override @Override
public ValueSet expand(ValueSet source, String theFilter, int theOffset, int theCount) { public ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
throw new UnsupportedOperationException();
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter) {
if (isBlank(theUri)) { if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing"); 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); source = (ValueSet) ids.getResources(0, 1).get(0);
} }
return expand(source, theFilter); return expand(source, theOptions);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
throw new UnsupportedOperationException();
} }
@Override @Override
@ -236,6 +228,7 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
return null; return null;
} }
@Nonnull
@Override @Override
public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, RequestDetails theRequest) { public IValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, CodingDt theCoding, RequestDetails theRequest) {
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode()); boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
@ -294,20 +287,20 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
// nothing // nothing
} }
public static String toStringOrNull(IPrimitiveType<String> thePrimitive) {
return thePrimitive != null ? thePrimitive.getValue() : null;
}
@Override @Override
public IValidationSupport.CodeValidationResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, 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); return myTerminologySvc.validateCode(vsValidateCodeOptions(), theId, toStringOrNull(theValueSetIdentifier), toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
} }
@Override @Override
public CodeValidationResult validateCode(IIdType theCodeSystemId, IPrimitiveType<String> theCodeSystemUrl, IPrimitiveType<String> theVersion, IPrimitiveType<String> theCode, 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(); 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> { public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override @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); org.hl7.fhir.dstu3.model.ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter); return expand(source, theOptions);
} }
@Override @Override
public org.hl7.fhir.dstu3.model.ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) { public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, ValueSetExpansionOptions theOptions) {
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) {
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource); 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); return ValueSet30_40.convertValueSet(canonicalOutput);
} }
@Override @Override
public org.hl7.fhir.dstu3.model.ValueSet expand(org.hl7.fhir.dstu3.model.ValueSet theSource, String theFilter, int theOffset, int theCount) { public org.hl7.fhir.dstu3.model.ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
ValueSetExpansionOptions options = ValueSetExpansionOptions.forOffsetAndCount(theOffset, theCount); org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, theUri);
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet30_40.convertValueSet(theSource);
org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(options, canonicalInput, theFilter);
return ValueSet30_40.convertValueSet(canonicalOutput); 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> { public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override @Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) { public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails) {
ValueSet source = read(theId, 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 @Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) { public ValueSet expand(ValueSet theSource, ValueSetExpansionOptions theOptions) {
ValueSet source = read(theId, theRequestDetails); return myTerminologySvc.expandValueSet(theOptions, theSource);
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);
} }
@Override @Override
@ -107,15 +90,5 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
return retVal; 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> { public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Override @Override
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) { public ValueSet expand(IIdType theId, ValueSetExpansionOptions theOptions, RequestDetails theRequestDetails) {
ValueSet source = read(theId, theRequestDetails); ValueSet source = read(theId, theRequestDetails);
return expand(source, theFilter); return expand(source, theOptions);
} }
@Override @Override
public ValueSet expand(IIdType theId, String theFilter, int theOffset, int theCount, RequestDetails theRequestDetails) { public ValueSet expandByIdentifier(String theUri, ValueSetExpansionOptions theOptions) {
ValueSet source = read(theId, theRequestDetails); org.hl7.fhir.r4.model.ValueSet canonicalOutput = myTerminologySvc.expandValueSet(theOptions, theUri);
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);
return ValueSet40_50.convertValueSet(canonicalOutput); return ValueSet40_50.convertValueSet(canonicalOutput);
} }
@Override @Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) { public ValueSet expand(ValueSet theSource, ValueSetExpansionOptions theOptions) {
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) {
org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.convertValueSet(theSource); org.hl7.fhir.r4.model.ValueSet canonicalInput = ValueSet40_50.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 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);
return ValueSet40_50.convertValueSet(canonicalOutput); 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"); b.append("NONE");
} }
myParentPids = b.toString(); setParentPids(b.toString());
} }
public TermConcept setParentPids(String theParentPids) { 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 org.apache.commons.lang3.builder.ToStringStyle;
import javax.annotation.Nonnull; 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.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -60,6 +74,9 @@ public class TermValueSetConcept implements Serializable {
@Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false) @Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false)
private Long myValueSetPid; private Long myValueSetPid;
@Column(name = "INDEX_STATUS", nullable = true)
private Long myIndexStatus;
@Column(name = "VALUESET_ORDER", nullable = false) @Column(name = "VALUESET_ORDER", nullable = false)
private int myOrder; private int myOrder;
@ -69,6 +86,13 @@ public class TermValueSetConcept implements Serializable {
@Transient @Transient
private String myValueSetName; 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) @Column(name = "SYSTEM_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH)
private String mySystem; private String mySystem;
@ -87,6 +111,13 @@ public class TermValueSetConcept implements Serializable {
@Transient @Transient
private transient Integer myHashCode; private transient Integer myHashCode;
/**
* Constructor
*/
public TermValueSetConcept() {
super();
}
public Long getId() { public Long getId() {
return myId; return myId;
} }
@ -219,4 +250,20 @@ public class TermValueSetConcept implements Serializable {
.append(myDesignations != null ? ("myDesignations - size=" + myDesignations.size()) : ("myDesignations=(null)")) .append(myDesignations != null ? ("myDesignations - size=" + myDesignations.size()) : ("myDesignations=(null)"))
.toString(); .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% * #L%
*/ */
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.io.IOUtils;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect; import org.hibernate.annotations.Subselect;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Lob;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Clob;
import java.sql.SQLException;
@Entity @Entity
@Immutable @Immutable
@ -39,26 +43,28 @@ import java.io.Serializable;
* because hibernate won't allow the view the function without it, but * because hibernate won't allow the view the function without it, but
*/ */
"SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " + "SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " +
" vsc.PID AS CONCEPT_PID, " + " vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " + " vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " + " vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vscd.PID AS DESIGNATION_PID, " + " vsc.SOURCE_PID AS SOURCE_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + " vscd.PID AS DESIGNATION_PID, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " + " vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.VAL AS DESIGNATION_VAL " + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
"FROM TRM_VALUESET_CONCEPT vsc " + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
"LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID" " 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; private static final long serialVersionUID = 1L;
@Id @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 private String id; // still set automatically
@Column(name = "CONCEPT_PID") @Column(name = "CONCEPT_PID")
@ -97,43 +103,76 @@ public class TermValueSetConceptView implements Serializable {
@Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH) @Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH)
private String myDesignationVal; 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() { public Long getConceptPid() {
return myConceptPid; return myConceptPid;
} }
@Override
public String getConceptSystemUrl() { public String getConceptSystemUrl() {
return myConceptSystemUrl; return myConceptSystemUrl;
} }
@Override
public String getConceptCode() { public String getConceptCode() {
return myConceptCode; return myConceptCode;
} }
@Override
public String getConceptDisplay() { public String getConceptDisplay() {
return myConceptDisplay; return myConceptDisplay;
} }
@Override
public Long getDesignationPid() { public Long getDesignationPid() {
return myDesignationPid; return myDesignationPid;
} }
@Override
public String getDesignationLang() { public String getDesignationLang() {
return myDesignationLang; return myDesignationLang;
} }
@Override
public String getDesignationUseSystem() { public String getDesignationUseSystem() {
return myDesignationUseSystem; return myDesignationUseSystem;
} }
@Override
public String getDesignationUseCode() { public String getDesignationUseCode() {
return myDesignationUseCode; return myDesignationUseCode;
} }
@Override
public String getDesignationUseDisplay() { public String getDesignationUseDisplay() {
return myDesignationUseDisplay; return myDesignationUseDisplay;
} }
@Override
public String getDesignationVal() { public String getDesignationVal() {
return myDesignationVal; return myDesignationVal;
} }

View File

@ -20,18 +20,20 @@ package ca.uhn.fhir.jpa.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.io.IOUtils;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect; import org.hibernate.annotations.Subselect;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id; 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.io.Serializable;
import java.sql.Clob;
import java.sql.SQLException;
@Entity @Entity
@Immutable @Immutable
@ -41,26 +43,28 @@ import java.io.Serializable;
* because hibernate won't allow the view the function without it, but * because hibernate won't allow the view the function without it, but
*/ */
"SELECT CONCAT(vsc.PID, CONCAT(' ', vscd.PID)) AS PID, " + "SELECT CONCAT(vsc.PID, CONCAT(' ', vscd.PID)) AS PID, " +
" vsc.PID AS CONCEPT_PID, " + " vsc.PID AS CONCEPT_PID, " +
" vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " +
" vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " +
" vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " +
" vsc.CODEVAL AS CONCEPT_CODEVAL, " + " vsc.CODEVAL AS CONCEPT_CODEVAL, " +
" vsc.DISPLAY AS CONCEPT_DISPLAY, " + " vsc.DISPLAY AS CONCEPT_DISPLAY, " +
" vscd.PID AS DESIGNATION_PID, " + " vsc.SOURCE_PID AS SOURCE_PID, " +
" vscd.LANG AS DESIGNATION_LANG, " + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " +
" vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + " vscd.PID AS DESIGNATION_PID, " +
" vscd.USE_CODE AS DESIGNATION_USE_CODE, " + " vscd.LANG AS DESIGNATION_LANG, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " +
" vscd.VAL AS DESIGNATION_VAL " + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " +
" vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " +
" vscd.VAL AS DESIGNATION_VAL " +
"FROM TRM_VALUESET_CONCEPT vsc " + "FROM TRM_VALUESET_CONCEPT vsc " +
"LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID" "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; private static final long serialVersionUID = 1L;
@Id @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 private String id; // still set automatically
@Column(name = "CONCEPT_PID") @Column(name = "CONCEPT_PID")
@ -99,43 +103,76 @@ public class TermValueSetConceptViewOracle implements Serializable {
@Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH) @Column(name = "DESIGNATION_VAL", length = TermConceptDesignation.MAX_VAL_LENGTH)
private String myDesignationVal; 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() { public Long getConceptPid() {
return myConceptPid; return myConceptPid;
} }
@Override
public String getConceptSystemUrl() { public String getConceptSystemUrl() {
return myConceptSystemUrl; return myConceptSystemUrl;
} }
@Override
public String getConceptCode() { public String getConceptCode() {
return myConceptCode; return myConceptCode;
} }
@Override
public String getConceptDisplay() { public String getConceptDisplay() {
return myConceptDisplay; 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() { public Long getDesignationPid() {
return myDesignationPid; return myDesignationPid;
} }
@Override
public String getDesignationLang() { public String getDesignationLang() {
return myDesignationLang; return myDesignationLang;
} }
@Override
public String getDesignationUseSystem() { public String getDesignationUseSystem() {
return myDesignationUseSystem; return myDesignationUseSystem;
} }
@Override
public String getDesignationUseCode() { public String getDesignationUseCode() {
return myDesignationUseCode; return myDesignationUseCode;
} }
@Override
public String getDesignationUseDisplay() { public String getDesignationUseDisplay() {
return myDesignationUseDisplay; return myDesignationUseDisplay;
} }
@Override
public String getDesignationVal() { public String getDesignationVal() {
return myDesignationVal; 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.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport; 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.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
@ -87,8 +88,11 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
} }
} }
private String toFilterString(StringDt theFilter) { private ValueSetExpansionOptions toFilterString(StringDt theFilter) {
return theFilter != null ? theFilter.getValue() : null; if (theFilter != null) {
return ValueSetExpansionOptions.forOffsetAndCount(0, 1000).setFilter(theFilter.getValue());
}
return null;
} }
@Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters = { @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.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2; 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.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.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 javax.servlet.http.HttpServletRequest;
import static ca.uhn.fhir.jpa.provider.r4.BaseJpaResourceProviderValueSetR4.createValueSetExpansionOptions;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDstu3<ValueSet> { 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) @Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true)
public ValueSet expand( public ValueSet expand(
@ -51,6 +62,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter, @OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset, @OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount, @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) { RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart(); 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."); 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(); ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
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;
}
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) { if (haveId) {
if (haveId) { return dao.expand(theId, options, theRequestDetails);
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) {
} else if (haveIdentifier) { if (haveValueSetVersion) {
if (haveValueSetVersion) { return dao.expandByIdentifier(url.getValue() + "|" + theValueSetVersion.getValue(), options);
return dao.expandByIdentifier(url.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter), offset, count);
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count); return dao.expandByIdentifier(url.getValue(), options);
} }
} else { } else {
if (haveId) { return dao.expand(theValueSet, options);
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));
}
} }
} finally { } finally {
endRequest(theServletRequest); 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 = { @Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class), @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.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.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2; 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.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.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; 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 = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset, @OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount, @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) { RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart(); 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."); 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(); ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
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;
}
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) { if (haveId) {
if (haveId) { return dao.expand(theId, options, theRequestDetails);
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) {
} else if (haveIdentifier) { if (haveValueSetVersion) {
if (haveValueSetVersion) { return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), options);
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count);
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count); return dao.expandByIdentifier(theUrl.getValue(), options);
} }
} else { } else {
if (haveId) { return dao.expand(theValueSet, options);
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));
}
} }
} finally { } finally {
endRequest(theServletRequest); endRequest(theServletRequest);
} }
} }
private String toFilterString(StringType theFilter) {
return theFilter != null ? theFilter.getValue() : null;
}
@SuppressWarnings("unchecked")
@Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = { @Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class), @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) { private static boolean moreThanOneTrue(boolean... theBooleans) {
boolean haveOne = false; 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.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProviderValueSetDstu2; 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.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.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 javax.servlet.http.HttpServletRequest;
import static ca.uhn.fhir.jpa.provider.r4.BaseJpaResourceProviderValueSetR4.createValueSetExpansionOptions;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<ValueSet> { 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) @Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true)
public ValueSet expand( public ValueSet expand(
@ -48,6 +59,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter, @OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset, @OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount, @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) { RequestDetails theRequestDetails) {
boolean haveId = theId != null && theId.hasIdPart(); 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."); 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(); ValueSetExpansionOptions options = createValueSetExpansionOptions(myDaoConfig, theOffset, theCount, theIncludeHierarchy, theFilter);
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;
}
startRequest(theServletRequest); startRequest(theServletRequest);
try { try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao(); IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
if (myDaoConfig.isPreExpandValueSets()) { if (haveId) {
if (haveId) { return dao.expand(theId, options, theRequestDetails);
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) {
} else if (haveIdentifier) { if (haveValueSetVersion) {
if (haveValueSetVersion) { return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), options);
return dao.expandByIdentifier(theUrl.getValue() + "|" + theValueSetVersion.getValue(), toFilterString(theFilter), offset, count);
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count);
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter), offset, count); return dao.expandByIdentifier(theUrl.getValue(), options);
} }
} else { } else {
if (haveId) { return dao.expand(theValueSet, options);
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));
}
} }
} finally { } finally {
endRequest(theServletRequest); 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 = { @Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class), @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.ITermValueSetConceptViewDao;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptViewOracleDao; import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptViewOracleDao;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetDao; 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.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; 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.TermConceptPropertyTypeEnum;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; 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.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.sched.HapiJob; import ca.uhn.fhir.jpa.model.sched.HapiJob;
@ -153,6 +152,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -251,19 +251,27 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri(); String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
String code = theConcept.getCode(); String code = theConcept.getCode();
String display = theConcept.getDisplay(); 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(); Collection<TermConceptDesignation> designations = theConcept.getDesignations();
if (StringUtils.isNotEmpty(theValueSetIncludeVersion)) { 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 { } 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 (StringUtils.isNotEmpty(theCodeSystemVersion)) {
if (isNoneBlank(theCodeSystem, theCode)) { if (isNoneBlank(theCodeSystem, theCode)) {
if (theAdd && theAddedCodes.add(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)) { if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode)) {
@ -272,7 +280,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} else { } else {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) { 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)) { 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 (isNoneBlank(theCodeSystem, theCode)) {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) { if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations); theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCode, theDisplay, theDesignations, theSourceConceptPid, theSourceConceptDirectParentPids);
return true; return true;
} }
@ -353,10 +361,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Override @Override
@Transactional @Transactional
public List<FhirVersionIndependentConcept> expandValueSetIntoConceptList(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull String theValueSetCanonicalUrl) { 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. // 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<>(); ArrayList<FhirVersionIndependentConcept> retVal = new ArrayList<>();
for (ValueSet.ValueSetExpansionContainsComponent nextContains : expanded.getExpansion().getContains()) { for (ValueSet.ValueSetExpansionContainsComponent nextContains : expanded.getExpansion().getContains()) {
@ -367,25 +374,23 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Override @Override
@Transactional @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); ValueSet valueSet = fetchCanonicalValueSetFromCompleteContext(theValueSetCanonicalUrl);
if (valueSet == null) { if (valueSet == null) {
throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetCanonicalUrl)); throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetCanonicalUrl));
} }
return expandValueSet(theExpansionOptions, valueSet, theExpansionFilter); return expandValueSet(theExpansionOptions, valueSet);
} }
@Override @Override
@Transactional(propagation = Propagation.REQUIRED) @Transactional(propagation = Propagation.REQUIRED)
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand) { public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand) {
return expandValueSet(theExpansionOptions, theValueSetToExpand, (String) null); String filter = null;
} if (theExpansionOptions != null) {
filter = theExpansionOptions.getFilter();
@Override }
@Transactional(propagation = Propagation.REQUIRED) return expandValueSet(theExpansionOptions, theValueSetToExpand, ExpansionFilter.fromFilterString(filter));
public ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand, @Nullable String theFilter) {
return expandValueSet(theExpansionOptions, theValueSetToExpand, ExpansionFilter.fromFilterString(theFilter));
} }
private ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, ExpansionFilter theFilter) { 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 offset = expansionOptions.getOffset();
int count = expansionOptions.getCount(); int count = expansionOptions.getCount();
ValueSetExpansionComponentWithConceptAccumulator accumulator = new ValueSetExpansionComponentWithConceptAccumulator(myContext, count); ValueSetExpansionComponentWithConceptAccumulator accumulator = new ValueSetExpansionComponentWithConceptAccumulator(myContext, count, expansionOptions.isIncludeHierarchy());
accumulator.setHardExpansionMaximumSize(myDaoConfig.getMaximumExpansionSize()); accumulator.setHardExpansionMaximumSize(myDaoConfig.getMaximumExpansionSize());
accumulator.setSkipCountRemaining(offset); accumulator.setSkipCountRemaining(offset);
accumulator.setIdentifier(UUID.randomUUID().toString()); accumulator.setIdentifier(UUID.randomUUID().toString());
@ -424,6 +429,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
.setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE) .setUrl(HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE)
.setValue(new StringType(next)); .setValue(new StringType(next));
} }
if (expansionOptions.isIncludeHierarchy()) {
accumulator.applyHierarchy();
}
return valueSet; return valueSet;
} }
@ -469,124 +479,14 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
*/ */
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion"); String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "valueSetExpandedUsingPreExpansion");
theAccumulator.addMessage(msg); theAccumulator.addMessage(msg);
if (isOracleDialect()) { expandConcepts(theAccumulator, termValueSet, theFilter, theAdd, isOracleDialect());
expandConceptsOracle(theAccumulator, termValueSet, theFilter, theAdd);
} else {
expandConcepts(theAccumulator, termValueSet, theFilter, theAdd);
}
} }
private boolean isOracleDialect() { private boolean isOracleDialect() {
return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect; return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect;
} }
private void expandConceptsOracle(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd) { private void expandConcepts(IValueSetConceptAccumulator theAccumulator, TermValueSet theTermValueSet, ExpansionFilter theFilter, boolean theAdd, boolean theOracle) {
// 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) {
// NOTE: if you modifiy the logic here, look to `expandConceptsOracle` and see if your new code applies to its copy pasted sibling // 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(); Integer offset = theAccumulator.getSkipCountRemaining();
offset = ObjectUtils.defaultIfNull(offset, 0); offset = ObjectUtils.defaultIfNull(offset, 0);
@ -599,19 +499,26 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
int designationsExpanded = 0; int designationsExpanded = 0;
int toIndex = offset + count; int toIndex = offset + count;
Collection<TermValueSetConceptView> conceptViews; Collection<? extends ITermValueSetConceptView> conceptViews;
Collection<TermValueSetConceptViewOracle> conceptViewsOracle;
boolean wasFilteredResult = false; boolean wasFilteredResult = false;
String filterDisplayValue = null; 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) { 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("%", "[%]")); filterDisplayValue = lowerCase(theFilter.getFilters().get(0).getValue().replace("%", "[%]"));
String displayValue = "%" + lowerCase(filterDisplayValue) + "%"; 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; wasFilteredResult = true;
} else { } 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. // 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 //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); theAccumulator.consumeSkipCount(offset);
if (theAdd) { if (theAdd) {
theAccumulator.incrementOrDecrementTotalConcepts(true, theTermValueSet.getTotalConcepts().intValue()); theAccumulator.incrementOrDecrementTotalConcepts(true, theTermValueSet.getTotalConcepts().intValue());
@ -625,8 +532,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
Map<Long, FhirVersionIndependentConcept> pidToConcept = new LinkedHashMap<>(); Map<Long, FhirVersionIndependentConcept> pidToConcept = new LinkedHashMap<>();
ArrayListMultimap<Long, TermConceptDesignation> pidToDesignations = ArrayListMultimap.create(); 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 system = conceptView.getConceptSystemUrl();
String code = conceptView.getConceptCode(); 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) { if (++conceptsExpanded % 250 == 0) {
logConceptsExpanded("Expansion of concepts in progress. ", theTermValueSet, conceptsExpanded); 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 { } else {
boolean removed = theAccumulator.excludeConcept(system, code); boolean removed = theAccumulator.excludeConcept(system, code);
if (removed) { 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) { private void addOrRemoveCode(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, boolean theAdd, String theSystem, String theCode, String theDisplay) {
if (theAdd && theAddedCodes.add(theSystem + "|" + theCode)) { if (theAdd && theAddedCodes.add(theSystem + "|" + theCode)) {
theValueSetCodeAccumulator.includeConcept(theSystem, theCode, theDisplay); theValueSetCodeAccumulator.includeConcept(theSystem, theCode, theDisplay, null, null);
} }
if (!theAdd && theAddedCodes.remove(theSystem + "|" + theCode)) { if (!theAdd && theAddedCodes.remove(theSystem + "|" + theCode)) {
theValueSetCodeAccumulator.excludeConcept(theSystem, theCode); theValueSetCodeAccumulator.excludeConcept(theSystem, theCode);
@ -1506,7 +1422,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
if (theInclude.getConcept().isEmpty()) { if (theInclude.getConcept().isEmpty()) {
for (TermConcept next : theVersion.getConcepts()) { 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)) { if (!theSystem.equals(theInclude.getSystem()) && isNotBlank(theSystem)) {
continue; 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 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 * @return Returns <code>true</code> if the code was actually present and was removed
@ -48,6 +48,10 @@ public interface IValueSetConceptAccumulator {
return null; return null;
} }
default boolean isTrackingHierarchy() {
return true;
}
@Nullable @Nullable
default void consumeSkipCount(int theSkipCountToConsume) { default void consumeSkipCount(int theSkipCountToConsume) {
// nothing // nothing

View File

@ -66,13 +66,13 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
} }
@Override @Override
public void includeConcept(String theSystem, String theCode, String theDisplay) { public void includeConcept(String theSystem, String theCode, String theDisplay, Long theSourceConceptPid, String theSourceConceptDirectParentPids) {
saveConcept(theSystem, theCode, theDisplay); saveConcept(theSystem, theCode, theDisplay, theSourceConceptPid, theSourceConceptDirectParentPids);
} }
@Override @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) {
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay); TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay, theSourceConceptPid, theSourceConceptDirectParentPids);
if (theDesignations != null) { if (theDesignations != null) {
for (TermConceptDesignation designation : theDesignations) { for (TermConceptDesignation designation : theDesignations) {
saveConceptDesignation(concept, designation); saveConceptDesignation(concept, designation);
@ -117,7 +117,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
return false; 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(theSystem, "ValueSet contains a concept with no system value");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "ValueSet contains a concept with no code value"); ValidateUtil.isNotBlankOrThrowInvalidRequest(theCode, "ValueSet contains a concept with no code value");
@ -135,6 +135,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
if (isNotBlank(theDisplay)) { if (isNotBlank(theDisplay)) {
concept.setDisplay(theDisplay); concept.setDisplay(theDisplay);
} }
concept.setSourceConceptPid(theSourceConceptPid);
concept.setSourceConceptDirectParentPids(theSourceConceptDirectParentPids);
myValueSetConceptDao.save(concept); myValueSetConceptDao.save(concept);
myValueSetDao.save(myTermValueSet.incrementTotalConcepts()); 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.context.FhirContext;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation; import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException; import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import ca.uhn.fhir.model.api.annotation.Block; import ca.uhn.fhir.model.api.annotation.Block;
@ -32,9 +31,15 @@ import org.hl7.fhir.r4.model.ValueSet;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Block() @Block()
public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetConceptAccumulator { public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.ValueSetExpansionComponent implements IValueSetConceptAccumulator {
@ -45,25 +50,21 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
private List<String> myMessages; private List<String> myMessages;
private int myAddedConcepts; private int myAddedConcepts;
private Integer myTotalConcepts; private Integer myTotalConcepts;
private Map<Long, ValueSet.ValueSetExpansionContainsComponent> mySourcePidToConcept = new HashMap<>();
/** private Map<ValueSet.ValueSetExpansionContainsComponent, String> myConceptToSourceDirectParentPids = new HashMap<>();
* Constructor private boolean myTrackingHierarchy;
*
* @param theDaoConfig Will be used to determine the max capacity for this accumulator
*/
public ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, DaoConfig theDaoConfig) {
this(theContext, theDaoConfig.getMaximumExpansionSize());
}
/** /**
* Constructor * Constructor
* *
* @param theMaxCapacity The maximum number of results this accumulator will accept before throwing * @param theMaxCapacity The maximum number of results this accumulator will accept before throwing
* an {@link InternalErrorException} * an {@link InternalErrorException}
* @param theTrackingHierarchy
*/ */
ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, int theMaxCapacity) { ValueSetExpansionComponentWithConceptAccumulator(FhirContext theContext, int theMaxCapacity, boolean theTrackingHierarchy) {
myMaxCapacity = theMaxCapacity; myMaxCapacity = theMaxCapacity;
myContext = theContext; myContext = theContext;
myTrackingHierarchy = theTrackingHierarchy;
} }
@Nonnull @Nonnull
@ -79,6 +80,11 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
return Collections.unmodifiableList(myMessages); return Collections.unmodifiableList(myMessages);
} }
@Override
public boolean isTrackingHierarchy() {
return myTrackingHierarchy;
}
@Override @Override
public void addMessage(String theMessage) { public void addMessage(String theMessage) {
if (myMessages == null) { if (myMessages == null) {
@ -88,7 +94,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
} }
@Override @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) { if (mySkipCountRemaining > 0) {
mySkipCountRemaining--; mySkipCountRemaining--;
return; return;
@ -103,7 +109,7 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
} }
@Override @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) { if (mySkipCountRemaining > 0) {
mySkipCountRemaining--; mySkipCountRemaining--;
return; return;
@ -112,6 +118,14 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
incrementConceptsCount(); incrementConceptsCount();
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains(); ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
if (theSourceConceptPid != null) {
mySourcePidToConcept.put(theSourceConceptPid, contains);
}
if (theSourceConceptDirectParentPids != null) {
myConceptToSourceDirectParentPids.put(contains, theSourceConceptDirectParentPids);
}
setSystemAndVersion(theSystem, contains); setSystemAndVersion(theSystem, contains);
contains.setCode(theCode); contains.setCode(theCode);
contains.setDisplay(theDisplay); contains.setDisplay(theDisplay);
@ -215,4 +229,29 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
public void setHardExpansionMaximumSize(int theHardExpansionMaximumSize) { public void setHardExpansionMaximumSize(int theHardExpansionMaximumSize) {
myHardExpansionMaximumSize = 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 { 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);
ValueSet expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull ValueSet theValueSetToExpand, @Nullable String theFilter);
void expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator); void expandValueSet(@Nullable ValueSetExpansionOptions theExpansionOptions, ValueSet theValueSetToExpand, IValueSetConceptAccumulator theValueSetCodeAccumulator);
/** /**

View File

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

View File

@ -1,16 +1,17 @@
package ca.uhn.fhir.jpa.dao.dstu3; package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.context.support.IValidationSupport; 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.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; 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.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl; import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.parser.IParser; 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.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 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.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport; 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.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -48,21 +47,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsStringIgnoringCase; import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test { 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_CODE_SYSTEM = "http://example.com/my_code_system";
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set"; 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 @Autowired
private CachingValidationSupport myCachingValidationSupport; private CachingValidationSupport myCachingValidationSupport;
@Autowired
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
@AfterEach @AfterEach
public void after() { public void after() {
@ -138,7 +138,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.getConcepts().add(parentA); cs.getConcepts().add(parentA);
for (int i = 0; i < 450; i++) { 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); parentA.addChild(childI, RelationshipTypeEnum.ISA);
} }
@ -146,18 +146,15 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.getConcepts().add(parentB); cs.getConcepts().add(parentB);
for (int i = 0; i < 450; i++) { 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); 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(); myTermDeferredStorageSvc.saveAllDeferred();
} }
@Autowired
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
private void createExternalCsAndLocalVs() { private void createExternalCsAndLocalVs() {
CodeSystem codeSystem = createExternalCs(); CodeSystem codeSystem = createExternalCs();
@ -191,7 +188,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle"); TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
dogs.addChild(beagle, RelationshipTypeEnum.ISA); 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; return codeSystem;
} }
@ -202,14 +199,14 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
codeSystem.setContent(CodeSystemContentMode.COMPLETE); codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem codeSystem
.addConcept().setCode("A").setDisplay("Code A") .addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA") .addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA")) .addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
) )
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB")); .addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem codeSystem
.addConcept().setCode("B").setDisplay("Code B") .addConcept().setCode("B").setDisplay("Code B")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA")) .addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB")); .addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
//@formatter:on //@formatter:on
myCodeSystemDao.create(codeSystem, mySrd); myCodeSystemDao.create(codeSystem, mySrd);
@ -265,12 +262,12 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
codeSystem.setContent(CodeSystemContentMode.COMPLETE); codeSystem.setContent(CodeSystemContentMode.COMPLETE);
codeSystem codeSystem
.addConcept().setCode("A").setDisplay("Code A") .addConcept().setCode("A").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")) .addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB")); .addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
codeSystem codeSystem
.addConcept().setCode("B").setDisplay("Code A") .addConcept().setCode("B").setDisplay("Code A")
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code AA")) .addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code AA"))
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code AB")); .addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code AB"));
//@formatter:on //@formatter:on
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified(); IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
@ -306,20 +303,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello")) .addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye")); .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addFilter() .addFilter()
.setProperty("concept") .setProperty("concept")
.setOp(FilterOperator.ISA) .setOp(FilterOperator.ISA)
.setValue("dogs"); .setValue("dogs");
myValueSetDao.create(valueSet, mySrd); myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, ""); ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result); logAndValidateValueSet(result);
assertEquals(4, result.getExpansion().getTotal()); assertEquals(4, result.getExpansion().getTotal());
@ -334,7 +331,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
public void testExpandWithOpEquals() { 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)); ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result));
} }
@ -347,20 +344,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello")) .addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye")); .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addFilter() .addFilter()
.setProperty("concept") .setProperty("concept")
.setOp(FilterOperator.ISA) .setOp(FilterOperator.ISA)
.setValue("dogs"); .setValue("dogs");
myValueSetDao.create(valueSet, mySrd); myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab"); ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result); logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal()); assertEquals(1, result.getExpansion().getTotal());
@ -377,20 +374,20 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addConcept(new ConceptReferenceComponent().setCode("hello")) .addConcept(new ConceptReferenceComponent().setCode("hello"))
.addConcept(new ConceptReferenceComponent().setCode("goodbye")); .addConcept(new ConceptReferenceComponent().setCode("goodbye"));
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()) .setSystem(codeSystem.getUrl())
.addFilter() .addFilter()
.setProperty("concept") .setProperty("concept")
.setOp(FilterOperator.ISA) .setOp(FilterOperator.ISA)
.setValue("dogs"); .setValue("dogs");
myValueSetDao.create(valueSet, mySrd); myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "hel"); ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("hel"));
logAndValidateValueSet(result); logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal()); assertEquals(1, result.getExpansion().getTotal());
@ -408,7 +405,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl()); valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
myValueSetDao.create(valueSet, mySrd); myValueSetDao.create(valueSet, mySrd);
ValueSet result = myValueSetDao.expand(valueSet, "lab"); ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter("lab"));
logAndValidateValueSet(result); logAndValidateValueSet(result);
assertEquals(1, result.getExpansion().getTotal()); assertEquals(1, result.getExpansion().getTotal());
@ -524,7 +521,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myTerminologyDeferredStorageSvc.saveDeferred(); myTerminologyDeferredStorageSvc.saveDeferred();
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()); assertEquals(true, lookupResults.isFound());
ValueSet vs = new ValueSet(); ValueSet vs = new ValueSet();
@ -628,9 +625,9 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
valueSet.setUrl(URL_MY_VALUE_SET); valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.getCompose() valueSet.getCompose()
.addInclude() .addInclude()
.setSystem(codeSystem.getUrl()); .setSystem(codeSystem.getUrl());
ValueSet result = myValueSetDao.expand(valueSet, ""); ValueSet result = myValueSetDao.expand(valueSet, new ValueSetExpansionOptions().setFilter(""));
logAndValidateValueSet(result); logAndValidateValueSet(result);
assertEquals(5, result.getExpansion().getTotal()); assertEquals(5, result.getExpansion().getTotal());
@ -711,7 +708,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.setResource(table); cs.setResource(table);
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A"); TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA); 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 code = new StringType("ParentA");
StringType system = new StringType("http://snomed.info/sct"); 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)); params.add(Observation.SP_CODE, new TokenParam(null, URL_MY_VALUE_SET).setModifier(TokenParamModifier.IN));
try { try {
myObservationDao.search(params); 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()); 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; package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.context.support.IValidationSupport; 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.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum; import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -99,7 +100,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
private boolean clearDeferredStorageQueue() { private boolean clearDeferredStorageQueue() {
if(!myTerminologyDeferredStorageSvc.isStorageQueueEmpty()) { if (!myTerminologyDeferredStorageSvc.isStorageQueueEmpty()) {
myTerminologyDeferredStorageSvc.saveAllDeferred(); myTerminologyDeferredStorageSvc.saveAllDeferred();
return false; return false;
} else { } else {
@ -155,7 +156,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
* Filter with display name * 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); resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
//@formatter:off //@formatter:off
@ -169,7 +170,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
@Test @Test
@Disabled @Disabled
public void testExpandByIdentifier() { 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); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
//@formatter:off //@formatter:off
@ -188,7 +189,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
@Disabled @Disabled
public void testExpandByValueSet() throws IOException { public void testExpandByValueSet() throws IOException {
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); 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); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
//@formatter:off //@formatter:off

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,21 +1,6 @@
package ca.uhn.fhir.jpa.provider; package ca.uhn.fhir.jpa.provider;
import static org.hamcrest.Matchers.containsString; import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
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.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.resource.Parameters; import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.ValueSet; 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.StringDt;
import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 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 { public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2Test {
private IIdType myExtensionalVsId;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2ValueSetTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2ValueSetTest.class);
private IIdType myExtensionalVsId;
@BeforeEach @BeforeEach
@Transactional @Transactional
@ -181,18 +179,18 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
assertThat(resp, assertThat(resp,
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">", stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
"<expansion>", "<expansion>",
"<contains>", "<contains>",
"<system value=\"http://loinc.org\"/>", "<system value=\"http://loinc.org\"/>",
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>", "<display value=\"Systolic blood pressure at First encounter\"/>",
"</contains>", "</contains>",
"<contains>", "<contains>",
"<system value=\"http://loinc.org\"/>", "<system value=\"http://loinc.org\"/>",
"<code value=\"8450-9\"/>", "<code value=\"8450-9\"/>",
"<display value=\"Systolic blood pressure--expiration\"/>", "<display value=\"Systolic blood pressure--expiration\"/>",
"</contains>", "</contains>",
"</expansion>" "</expansion>"
)); ));
/* /*
* Filter with display name * Filter with display name
@ -206,12 +204,12 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
.execute(); .execute();
expanded = (ValueSet) respParam.getParameter().get(0).getResource(); 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); resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
assertThat(resp, stringContainsInOrder( assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>")); "<display value=\"Systolic blood pressure at First encounter\"/>"));
/* /*
* Filter with code * Filter with code
@ -227,8 +225,8 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
assertThat(resp, stringContainsInOrder( assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>")); "<display value=\"Systolic blood pressure at First encounter\"/>"));
} }
@Test @Test
@ -245,8 +243,8 @@ public class ResourceProviderDstu2ValueSetTest extends BaseResourceProviderDstu2
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
assertThat(resp, stringContainsInOrder( assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>")); "<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, not(containsString("<code value=\"8450-9\"/>"))); 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); String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp); ourLog.info(resp);
assertThat(resp, stringContainsInOrder( assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>", "<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>")); "<display value=\"Systolic blood pressure at First encounter\"/>"));
assertThat(resp, not(containsString("<code value=\"8450-9\"/>"))); 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.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; 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.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 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.Parameters;
import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType; 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;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator; import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
@ -53,12 +54,16 @@ import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
import static ca.uhn.fhir.util.HapiExtensions.EXT_VALUESET_EXPANSION_MESSAGE;
import static org.awaitility.Awaitility.await; import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.containsStringIgnoringCase; import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -1037,6 +1042,165 @@ public class ResourceProviderR4ValueSetNoVerCSNoVerTest extends BaseResourceProv
testValidateCodeOperationByCodeAndSystemInstanceOnInstance(); 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 { private void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
String url = ourServerBase + String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId.getIdPart() + "/$validate-code?system=" + "/ValueSet/" + myLocalValueSetId.getIdPart() + "/$validate-code?system=" +

View File

@ -42,7 +42,7 @@ public class ValueSetConceptAccumulatorTest {
@Test @Test
public void testIncludeConcept() { public void testIncludeConcept() {
for (int i = 0; i < 1000; i++) { 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()); verify(myValueSetConceptDao, times(1000)).save(any());
} }

View File

@ -195,7 +195,7 @@ public class ValueSetExpansionR4ElasticsearchIT extends BaseJpaTest {
include.setSystem(CS_URL); include.setSystem(CS_URL);
myTermSvc.expandValueSet(null, vs, myValueSetCodeAccumulator); 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.TermConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; 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.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
@ -38,11 +37,10 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
@ -228,7 +226,8 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
// ValueSet by ID // ValueSet by ID
{ {
myCaptureQueriesListener.clear(); 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()); 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")); 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); ValueSet expandedValueSet = myTermSvc.expandValueSet(null, input);
ourLog.debug("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); 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 // Make sure we used the pre-expanded version
List<SqlQuery> selectQueries = myCaptureQueriesListener.getSelectQueries(); 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(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(codeSystem.getConcept().size() - expandedValueSet.getExpansion().getOffset(), expandedValueSet.getExpansion().getContains().size()); 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 @Test
@ -818,7 +817,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue());
assertEquals(codeSystem.getConcept().size() - expandedValueSet.getExpansion().getOffset(), expandedValueSet.getExpansion().getContains().size()); 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 @Test
@ -953,7 +952,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
include.setSystem(CS_URL); include.setSystem(CS_URL);
myTermSvc.expandValueSet(null, vs, myValueSetCodeAccumulator); 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 @Test
@ -1433,5 +1432,4 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test {
} }
} }

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

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

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -87,6 +87,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
version.onTable("HFJ_FORCED_ID").addIndex("20210309.2", "IDX_FORCEID_FID") version.onTable("HFJ_FORCED_ID").addIndex("20210309.2", "IDX_FORCEID_FID")
.unique(false).withColumns("FORCED_ID"); .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() { private void init530() {

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -218,6 +218,11 @@ public class JpaConstants {
*/ */
public static final String DEFAULT_PARTITION_NAME = "DEFAULT"; 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 * Non-instantiable
*/ */

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId> <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> <relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent> </parent>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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