Changes to support multi-versioning in ValueSet $expand operation.

This commit is contained in:
ianmarshall 2020-09-20 22:01:21 -04:00
parent b2b63cbb02
commit 302bbca8fd
32 changed files with 2583 additions and 231 deletions

View File

@ -28,6 +28,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
public class VersionIndependentConcept implements Comparable<VersionIndependentConcept> { public class VersionIndependentConcept implements Comparable<VersionIndependentConcept> {
private final String mySystem; private final String mySystem;
private final String mySystemVersion;
private final String myCode; private final String myCode;
private final String myDisplay; private final String myDisplay;
private int myHashCode; private int myHashCode;
@ -40,7 +41,12 @@ public class VersionIndependentConcept implements Comparable<VersionIndependentC
} }
public VersionIndependentConcept(String theSystem, String theCode, String theDisplay) { public VersionIndependentConcept(String theSystem, String theCode, String theDisplay) {
this(theSystem, theCode, theDisplay, null);
}
public VersionIndependentConcept(String theSystem, String theCode, String theDisplay, String theSystemVersion) {
mySystem = theSystem; mySystem = theSystem;
mySystemVersion = theSystemVersion;
myCode = theCode; myCode = theCode;
myDisplay = theDisplay; myDisplay = theDisplay;
myHashCode = new HashCodeBuilder(17, 37) myHashCode = new HashCodeBuilder(17, 37)
@ -57,6 +63,9 @@ public class VersionIndependentConcept implements Comparable<VersionIndependentC
return mySystem; return mySystem;
} }
public String getSystemVersion() {
return mySystemVersion;
}
public String getCode() { public String getCode() {
return myCode; return myCode;

View File

@ -142,7 +142,6 @@ ca.uhn.fhir.jpa.binstore.BinaryAccessProvider.unknownType=Content in resource of
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateCodeSystemUrl=Can not create multiple CodeSystem resources with CodeSystem.url "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateCodeSystemUrl=Can not create multiple CodeSystem resources with CodeSystem.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateCodeSystemUrlAndVersion=Can not create multiple CodeSystem resources with CodeSystem.url "{0}" and CodeSystem.version "{1}", already have one with resource ID: {2} ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateCodeSystemUrlAndVersion=Can not create multiple CodeSystem resources with CodeSystem.url "{0}" and CodeSystem.version "{1}", already have one with resource ID: {2}
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotUpdateUrlOrVersionForCodeSystemResource=Cannot update URL or version for CodeSystem resource. Existing CodeSystem resource with resource ID {0} found with CodeSystem.url "{1}" and CodeSystem.version "{2}"
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted! ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!

View File

@ -38,8 +38,12 @@ public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> exten
T expandByIdentifier(String theUri, String theFilter); T expandByIdentifier(String theUri, String theFilter);
T expandByIdentifier(String theUri, String theValueSetVersion, String theFilter);
T expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount); T expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount);
T expandByIdentifier(String theUri, String theValueSetVersion, String theFilter, int theOffset, int theCount);
void purgeCaches(); void purgeCaches();
IValidationSupport.CodeValidationResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CD theCoding, CC theCodeableConcept, RequestDetails theRequestDetails); IValidationSupport.CodeValidationResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, CD theCoding, CC theCodeableConcept, RequestDetails theRequestDetails);

View File

@ -174,11 +174,21 @@ public class FhirResourceDaoValueSetDstu2 extends BaseHapiFhirResourceDao<ValueS
return expand(source, theFilter); return expand(source, theFilter);
} }
@Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter) {
throw new UnsupportedOperationException();
}
@Override @Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) { public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter, int theOffset, int theCount) {
throw new UnsupportedOperationException();
}
@Override @Override
public List<IIdType> findCodeSystemIdsContainingSystemAndCode(String theCode, String theSystem, RequestDetails theRequest) { public List<IIdType> findCodeSystemIdsContainingSystemAndCode(String theCode, String theSystem, RequestDetails theRequest) {
if (theSystem != null && theSystem.startsWith("http://hl7.org/fhir/")) { if (theSystem != null && theSystem.startsWith("http://hl7.org/fhir/")) {

View File

@ -25,8 +25,11 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.param.UriParam;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
@ -121,18 +124,25 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri)); params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
search = myDaoRegistry.getResourceDao("ValueSet").search(params); search = myDaoRegistry.getResourceDao(resourceName).search(params);
if (search.size() == 0) { if (search.size() == 0) {
params = new SearchParameterMap(); params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
params.add(ValueSet.SP_URL, new UriParam(theUri)); params.add(ValueSet.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("ValueSet").search(params); search = myDaoRegistry.getResourceDao(resourceName).search(params);
} }
} else { } else {
int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
params.add(ValueSet.SP_URL, new UriParam(theUri)); if (versionSeparator != -1) {
search = myDaoRegistry.getResourceDao("ValueSet").search(params); params.add(ValueSet.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
params.add(ValueSet.SP_URL, new UriParam(theUri.substring(0,versionSeparator)));
} else {
params.add(ValueSet.SP_URL, new UriParam(theUri));
}
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
} }
} else if ("StructureDefinition".equals(resourceName)) { } else if ("StructureDefinition".equals(resourceName)) {
// Don't allow the core FHIR definitions to be overwritten // Don't allow the core FHIR definitions to be overwritten
@ -156,9 +166,16 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
} }
search = myDaoRegistry.getResourceDao("Questionnaire").search(params); search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
} else if ("CodeSystem".equals(resourceName)) { } else if ("CodeSystem".equals(resourceName)) {
int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
params.add(CodeSystem.SP_URL, new UriParam(theUri)); if (versionSeparator != -1) {
params.add(CodeSystem.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
params.add(CodeSystem.SP_URL, new UriParam(theUri.substring(0,versionSeparator)));
} else {
params.add(CodeSystem.SP_URL, new UriParam(theUri));
}
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params); search = myDaoRegistry.getResourceDao(resourceName).search(params);
} else if ("ImplementationGuide".equals(resourceName)) { } else if ("ImplementationGuide".equals(resourceName)) {
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();

View File

@ -49,7 +49,7 @@ public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemV
TermCodeSystemVersion findByCodeSystemPidVersionIsNull(@Param("codesystem_pid") Long theCodeSystemPid); TermCodeSystemVersion findByCodeSystemPidVersionIsNull(@Param("codesystem_pid") Long theCodeSystemPid);
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResourcePid = :resource_id") @Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResourcePid = :resource_id")
TermCodeSystemVersion findByCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid); List<TermCodeSystemVersion> findByCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid);
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemHavingThisVersionAsCurrentVersionIfAny.myResource.myId = :resource_id") @Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemHavingThisVersionAsCurrentVersionIfAny.myResource.myId = :resource_id")
TermCodeSystemVersion findCurrentVersionForCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid); TermCodeSystemVersion findCurrentVersionForCodeSystemResourcePid(@Param("resource_id") Long theCodeSystemResourcePid);

View File

@ -36,6 +36,7 @@ public interface ITermValueSetDao extends JpaRepository<TermValueSet, Long> {
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid") @Query("SELECT vs FROM TermValueSet vs WHERE vs.myResourcePid = :resource_pid")
Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid); Optional<TermValueSet> findByResourcePid(@Param("resource_pid") Long theResourcePid);
@Deprecated
@Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url") @Query("SELECT vs FROM TermValueSet vs WHERE vs.myUrl = :url")
Optional<TermValueSet> findByUrl(@Param("url") String theUrl); Optional<TermValueSet> findByUrl(@Param("url") String theUrl);

View File

@ -21,22 +21,18 @@ package ca.uhn.fhir.jpa.dao.dstu3;
*/ */
import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.ElementUtil;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeableConcept; import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IntegerType; import org.hl7.fhir.dstu3.model.IntegerType;
@ -49,9 +45,6 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -63,16 +56,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet; import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet;
public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> { public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class);
@Autowired
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
private IValidationSupport myValidationSupport; private IValidationSupport myValidationSupport;
@Autowired
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
@Override @Override
public void start() { public void start() {
super.start(); super.start();
@ -127,21 +113,7 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueS
throw new InvalidRequestException("URI must not be blank or missing"); throw new InvalidRequestException("URI must not be blank or missing");
} }
ValueSet source = new ValueSet(); return doExpand(createSourceValueSet(theUri, null, theFilter));
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri);
if (isNotBlank(theFilter)) {
ConceptSetComponent include = source.getCompose().addInclude();
ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(FilterOperator.EQUAL);
filter.setValue(theFilter);
}
ValueSet retVal = doExpand(source);
return retVal;
// if (defaultValueSet != null) { // if (defaultValueSet != null) {
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet)); // source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
@ -157,15 +129,27 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueS
} }
@Override @Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) { public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, 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");
} }
return doExpand(createSourceValueSet(theUri, theValueSetVersion, theFilter));
}
private ValueSet createSourceValueSet(String theUri, String theValueSetVersion, String theFilter) {
ValueSet source = new ValueSet(); ValueSet source = new ValueSet();
source.setUrl(theUri); source.setUrl(theUri);
if (theValueSetVersion != null) {
source.setVersion(theValueSetVersion);
}
source.getCompose().addInclude().addValueSet(theUri); if (theValueSetVersion != null) {
source.getCompose().addInclude().addValueSet(theUri + "|" +theValueSetVersion);
} else {
source.getCompose().addInclude().addValueSet(theUri);
}
if (isNotBlank(theFilter)) { if (isNotBlank(theFilter)) {
ConceptSetComponent include = source.getCompose().addInclude(); ConceptSetComponent include = source.getCompose().addInclude();
@ -174,9 +158,25 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueS
filter.setOp(FilterOperator.EQUAL); filter.setOp(FilterOperator.EQUAL);
filter.setValue(theFilter); filter.setValue(theFilter);
} }
return source;
}
ValueSet retVal = doExpand(source, theOffset, theCount); @Override
return retVal; public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
return doExpand(createSourceValueSet(theUri, null, theFilter), theOffset, theCount);
}
@Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter, int theOffset, int theCount) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
return doExpand(createSourceValueSet(theUri, theValueSetVersion, theFilter), theOffset, theCount);
} }
@Override @Override
@ -214,6 +214,9 @@ public class FhirResourceDaoValueSetDstu3 extends BaseHapiFhirResourceDao<ValueS
ValueSet toExpand = new ValueSet(); ValueSet toExpand = new ValueSet();
toExpand.setId(theSource.getId()); toExpand.setId(theSource.getId());
toExpand.setUrl(theSource.getUrl()); toExpand.setUrl(theSource.getUrl());
if (theSource.getVersion() != null) {
toExpand.setVersion(theSource.getVersion());
}
for (ConceptSetComponent next : theSource.getCompose().getInclude()) { for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
toExpand.getCompose().addInclude(next); toExpand.getCompose().addInclude(next);

View File

@ -20,35 +20,28 @@ package ca.uhn.fhir.jpa.dao.r4;
* #L% * #L%
*/ */
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.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.ElementUtil;
import org.apache.commons.codec.binary.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator; import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -60,12 +53,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> { public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Autowired
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
private IValidationSupport myValidationSupport; private IValidationSupport myValidationSupport;
@Autowired
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
@Override @Override
public void start() { public void start() {
@ -107,21 +95,7 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
throw new InvalidRequestException("URI must not be blank or missing"); throw new InvalidRequestException("URI must not be blank or missing");
} }
ValueSet source = new ValueSet(); return doExpand(createSourceValueSet(theUri, null, theFilter));
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri);
if (isNotBlank(theFilter)) {
ConceptSetComponent include = source.getCompose().addInclude();
ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(FilterOperator.EQUAL);
filter.setValue(theFilter);
}
ValueSet retVal = doExpand(source);
return retVal;
// if (defaultValueSet != null) { // if (defaultValueSet != null) {
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet)); // source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
@ -136,27 +110,54 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
// return expand(defaultValueSet, theFilter); // return expand(defaultValueSet, theFilter);
} }
@Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
return doExpand(createSourceValueSet(theUri, theValueSetVersion, theFilter));
}
private ValueSet createSourceValueSet(String theUri, String theValueSetVersion, String theFilter) {
ValueSet source = new ValueSet();
source.setUrl(theUri);
if (theValueSetVersion != null) {
source.setVersion(theValueSetVersion);
}
if (theValueSetVersion != null) {
source.getCompose().addInclude().addValueSet(theUri + "|" +theValueSetVersion);
} else {
source.getCompose().addInclude().addValueSet(theUri);
}
if (isNotBlank(theFilter)) {
ValueSet.ConceptSetComponent include = source.getCompose().addInclude();
ValueSet.ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(ValueSet.FilterOperator.EQUAL);
filter.setValue(theFilter);
}
return source;
}
@Override @Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) { public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
if (isBlank(theUri)) { if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing"); throw new InvalidRequestException("URI must not be blank or missing");
} }
ValueSet source = new ValueSet(); return doExpand(createSourceValueSet(theUri,null,theFilter), theOffset, theCount);
source.setUrl(theUri); }
source.getCompose().addInclude().addValueSet(theUri); @Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter, int theOffset, int theCount) {
if (isNotBlank(theFilter)) { if (isBlank(theUri)) {
ConceptSetComponent include = source.getCompose().addInclude(); throw new InvalidRequestException("URI must not be blank or missing");
ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(FilterOperator.EQUAL);
filter.setValue(theFilter);
} }
ValueSet retVal = doExpand(source, theOffset, theCount); return doExpand(createSourceValueSet(theUri,theValueSetVersion,theFilter), theOffset, theCount);
return retVal;
} }
@Override @Override
@ -194,6 +195,9 @@ public class FhirResourceDaoValueSetR4 extends BaseHapiFhirResourceDao<ValueSet>
ValueSet toExpand = new ValueSet(); ValueSet toExpand = new ValueSet();
toExpand.setId(theSource.getId()); toExpand.setId(theSource.getId());
toExpand.setUrl(theSource.getUrl()); toExpand.setUrl(theSource.getUrl());
if (theSource.getVersion() != null) {
toExpand.setVersion(theSource.getVersion());
}
for (ConceptSetComponent next : theSource.getCompose().getInclude()) { for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
toExpand.getCompose().addInclude(next); toExpand.getCompose().addInclude(next);

View File

@ -20,39 +20,28 @@ package ca.uhn.fhir.jpa.dao.r5;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
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 ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.ElementUtil;
import org.apache.commons.codec.binary.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Enumerations; import org.hl7.fhir.r5.model.Enumerations;
import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -64,15 +53,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> { public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
@Autowired
@Qualifier("myDefaultProfileValidationSupport")
private IValidationSupport myDefaultProfileValidationSupport;
private IValidationSupport myValidationSupport; private IValidationSupport myValidationSupport;
@Autowired
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
@Override @Override
public void start() { public void start() {
super.start(); super.start();
@ -113,21 +95,7 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
throw new InvalidRequestException("URI must not be blank or missing"); throw new InvalidRequestException("URI must not be blank or missing");
} }
ValueSet source = new ValueSet(); return doExpand(createSourceValueSet(theUri, null, theFilter));
source.setUrl(theUri);
source.getCompose().addInclude().addValueSet(theUri);
if (isNotBlank(theFilter)) {
ConceptSetComponent include = source.getCompose().addInclude();
ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(Enumerations.FilterOperator.EQUAL);
filter.setValue(theFilter);
}
ValueSet retVal = doExpand(source);
return retVal;
// if (defaultValueSet != null) { // if (defaultValueSet != null) {
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet)); // source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
@ -142,27 +110,55 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
// return expand(defaultValueSet, theFilter); // return expand(defaultValueSet, theFilter);
} }
@Override
public ValueSet expandByIdentifier(String theUri, String theValueSetUri, String theFilter) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
return doExpand(createSourceValueSet(theUri, theValueSetUri, theFilter));
}
private ValueSet createSourceValueSet(String theUri, String theValueSetVersion, String theFilter) {
ValueSet source = new ValueSet();
source.setUrl(theUri);
if (theValueSetVersion != null) {
source.setVersion(theValueSetVersion);
}
if (theValueSetVersion != null) {
source.getCompose().addInclude().addValueSet(theUri + "|" +theValueSetVersion);
} else {
source.getCompose().addInclude().addValueSet(theUri);
}
if (isNotBlank(theFilter)) {
ValueSet.ConceptSetComponent include = source.getCompose().addInclude();
ValueSet.ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(Enumerations.FilterOperator.EQUAL);
filter.setValue(theFilter);
}
return source;
}
@Override @Override
public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) { public ValueSet expandByIdentifier(String theUri, String theFilter, int theOffset, int theCount) {
if (isBlank(theUri)) { if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing"); throw new InvalidRequestException("URI must not be blank or missing");
} }
ValueSet source = new ValueSet(); return doExpand(createSourceValueSet(theUri, null, theFilter), theOffset, theCount);
source.setUrl(theUri); }
source.getCompose().addInclude().addValueSet(theUri); @Override
public ValueSet expandByIdentifier(String theUri, String theValueSetVersion, String theFilter, int theOffset, int theCount) {
if (isNotBlank(theFilter)) { if (isBlank(theUri)) {
ConceptSetComponent include = source.getCompose().addInclude(); throw new InvalidRequestException("URI must not be blank or missing");
ConceptSetFilterComponent filter = include.addFilter();
filter.setProperty("display");
filter.setOp(Enumerations.FilterOperator.EQUAL);
filter.setValue(theFilter);
} }
ValueSet retVal = doExpand(source, theOffset, theCount); return doExpand(createSourceValueSet(theUri, theValueSetVersion, theFilter), theOffset, theCount);
return retVal;
} }
@Override @Override
@ -200,6 +196,9 @@ public class FhirResourceDaoValueSetR5 extends BaseHapiFhirResourceDao<ValueSet>
ValueSet toExpand = new ValueSet(); ValueSet toExpand = new ValueSet();
toExpand.setId(theSource.getId()); toExpand.setId(theSource.getId());
toExpand.setUrl(theSource.getUrl()); toExpand.setUrl(theSource.getUrl());
if (theSource.getVersion() != null) {
toExpand.setVersion(theSource.getVersion());
}
for (ConceptSetComponent next : theSource.getCompose().getInclude()) { for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
toExpand.getCompose().addInclude(next); toExpand.getCompose().addInclude(next);

View File

@ -46,6 +46,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
// Note: url is correct and identifier is not, but identifier was only added as // Note: url is correct and identifier is not, but identifier was only added as
// of 3.1.0 so we'll leave url for now. See: https://groups.google.com/d/msgid/hapi-fhir/CAN2Cfy8kW%2BAOkgC6VjPsU3gRCpExCNZBmJdi-k5R_TWeyWH4tA%40mail.gmail.com?utm_medium=email&utm_source=footer // of 3.1.0 so we'll leave url for now. See: https://groups.google.com/d/msgid/hapi-fhir/CAN2Cfy8kW%2BAOkgC6VjPsU3gRCpExCNZBmJdi-k5R_TWeyWH4tA%40mail.gmail.com?utm_medium=email&utm_source=footer
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) org.hl7.fhir.r4.model.StringType theValueSetVersion,
@OperationParam(name = "identifier", min = 0, max = 1) UriType theIdentifier, @OperationParam(name = "identifier", min = 0, max = 1) UriType theIdentifier,
@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,
@ -60,6 +61,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
boolean haveIdentifier = url != null && isNotBlank(url.getValue()); boolean haveIdentifier = url != null && isNotBlank(url.getValue());
boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty(); boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty();
boolean haveValueSetVersion = theValueSetVersion != null && !theValueSetVersion.isEmpty();
if (!haveId && !haveIdentifier && !haveValueSet) { if (!haveId && !haveIdentifier && !haveValueSet) {
throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request."); throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request.");
@ -99,7 +101,11 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter), offset, count); if (haveValueSetVersion) {
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.expand(theValueSet, toFilterString(theFilter), offset, count);
} }
@ -107,7 +113,11 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails); return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter)); if (haveValueSetVersion) {
return dao.expandByIdentifier(url.getValue(), theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(url.getValue(), toFilterString(theFilter));
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter)); return dao.expand(theValueSet, toFilterString(theFilter));
} }

View File

@ -44,6 +44,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet, @OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet,
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@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,
@ -52,6 +53,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
boolean haveId = theId != null && theId.hasIdPart(); boolean haveId = theId != null && theId.hasIdPart();
boolean haveIdentifier = theUrl != null && isNotBlank(theUrl.getValue()); boolean haveIdentifier = theUrl != null && isNotBlank(theUrl.getValue());
boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty(); boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty();
boolean haveValueSetVersion = theValueSetVersion != null && !theValueSetVersion.isEmpty();
if (!haveId && !haveIdentifier && !haveValueSet) { if (!haveId && !haveIdentifier && !haveValueSet) {
throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires a url or a valueSet as a part of the request."); throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires a url or a valueSet as a part of the request.");
@ -91,7 +93,11 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count); if (haveValueSetVersion) {
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.expand(theValueSet, toFilterString(theFilter), offset, count);
} }
@ -99,7 +105,11 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails); return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter)); if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue(), theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter));
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter)); return dao.expand(theValueSet, toFilterString(theFilter));
} }

View File

@ -44,6 +44,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
@IdParam(optional = true) IdType theId, @IdParam(optional = true) IdType theId,
@OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet, @OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet,
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl, @OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) org.hl7.fhir.r4.model.StringType theValueSetVersion,
@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,
@ -52,6 +53,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
boolean haveId = theId != null && theId.hasIdPart(); boolean haveId = theId != null && theId.hasIdPart();
boolean haveIdentifier = theUrl != null && isNotBlank(theUrl.getValue()); boolean haveIdentifier = theUrl != null && isNotBlank(theUrl.getValue());
boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty(); boolean haveValueSet = theValueSet != null && !theValueSet.isEmpty();
boolean haveValueSetVersion = theValueSetVersion != null && !theValueSetVersion.isEmpty();
if (!haveId && !haveIdentifier && !haveValueSet) { if (!haveId && !haveIdentifier && !haveValueSet) {
throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires a url or a valueSet as a part of the request."); throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires a url or a valueSet as a part of the request.");
@ -91,7 +93,11 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter), offset, count); if (haveValueSetVersion) {
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.expand(theValueSet, toFilterString(theFilter), offset, count);
} }
@ -99,7 +105,11 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
if (haveId) { if (haveId) {
return dao.expand(theId, toFilterString(theFilter), theRequestDetails); return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
} else if (haveIdentifier) { } else if (haveIdentifier) {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter)); if (haveValueSetVersion) {
return dao.expandByIdentifier(theUrl.getValue(), theValueSetVersion.getValue(), toFilterString(theFilter));
} else {
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter));
}
} else { } else {
return dao.expand(theValueSet, toFilterString(theFilter)); return dao.expand(theValueSet, toFilterString(theFilter));
} }

View File

@ -170,6 +170,7 @@ import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNoneBlank; import static org.apache.commons.lang3.StringUtils.isNoneBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -245,10 +246,25 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) { private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri(); String codeSystem = theConcept.getCodeSystemVersion().getCodeSystem().getCodeSystemUri();
String codeSystemVersion = theConcept.getCodeSystemVersion().getCodeSystemVersionId();
String code = theConcept.getCode(); String code = theConcept.getCode();
String display = theConcept.getDisplay(); String display = theConcept.getDisplay();
Collection<TermConceptDesignation> designations = theConcept.getDesignations(); Collection<TermConceptDesignation> designations = theConcept.getDesignations();
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, code, display); addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, designations, theAdd, theCodeCounter, codeSystem, codeSystemVersion, code, display);
}
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCodeSystemVersion, String theCode, String theDisplay) {
if (isNoneBlank(theCodeSystem, theCode)) {
if (theAdd && theAddedCodes.add(theCodeSystem + "|" + theCode + "|" + theCodeSystemVersion)) {
theValueSetCodeAccumulator.includeConceptWithDesignations(theCodeSystem, theCodeSystemVersion, theCode, theDisplay, theDesignations);
theCodeCounter.incrementAndGet();
}
if (!theAdd && theAddedCodes.remove(theCodeSystem + "|" + theCode + "|" + theCodeSystemVersion)) {
theValueSetCodeAccumulator.excludeConcept(theCodeSystem, theCodeSystemVersion, theCode);
theCodeCounter.decrementAndGet();
}
}
} }
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) { private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, Collection<TermConceptDesignation> theDesignations, boolean theAdd, AtomicInteger theCodeCounter, String theCodeSystem, String theCode, String theDisplay) {
@ -609,7 +625,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
ArrayList<VersionIndependentConcept> retVal = new ArrayList<>(); ArrayList<VersionIndependentConcept> retVal = new ArrayList<>();
for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent nextContains : expandedR4.getContains()) { for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent nextContains : expandedR4.getContains()) {
retVal.add(new VersionIndependentConcept(nextContains.getSystem(), nextContains.getCode(), nextContains.getDisplay())); retVal.add(new VersionIndependentConcept(nextContains.getSystem(), nextContains.getCode(), nextContains.getDisplay(), nextContains.getVersion()));
} }
return retVal; return retVal;
} }
@ -740,8 +756,14 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
TermCodeSystem codeSystem = uriToCodeSystem.get(nextConcept.getSystem()); TermCodeSystem codeSystem = uriToCodeSystem.get(nextConcept.getSystem());
if (codeSystem != null) { if (codeSystem != null) {
TermCodeSystemVersion termCodeSystemVersion;
if (nextConcept.getSystemVersion() != null) {
termCodeSystemVersion = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(codeSystem.getPid(), nextConcept.getSystemVersion());
} else {
termCodeSystemVersion = codeSystem.getCurrentVersion();
}
myConceptDao myConceptDao
.findByCodeSystemAndCode(codeSystem.getCurrentVersion(), nextConcept.getCode()) .findByCodeSystemAndCode(termCodeSystemVersion, nextConcept.getCode())
.ifPresent(concept -> .ifPresent(concept ->
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter) addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter)
); );
@ -770,7 +792,13 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Nonnull @Nonnull
private Boolean expandValueSetHandleIncludeOrExcludeUsingDatabase(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull, String theSystem, TermCodeSystem theCs) { private Boolean expandValueSetHandleIncludeOrExcludeUsingDatabase(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull, String theSystem, TermCodeSystem theCs) {
TermCodeSystemVersion csv = theCs.getCurrentVersion(); String codeSystemVersion = theIncludeOrExclude.getVersion();
TermCodeSystemVersion csv;
if (isEmpty(codeSystemVersion)) {
csv = theCs.getCurrentVersion();
} else {
csv = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(theCs.getPid(), codeSystemVersion);
}
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager); FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
/* /*
@ -797,7 +825,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
/* /*
* Filters * Filters
*/ */
handleFilters(bool, theSystem, qb, theIncludeOrExclude); handleFilters(bool, theSystem, codeSystemVersion, qb, theIncludeOrExclude);
Query luceneQuery = bool.createQuery(); Query luceneQuery = bool.createQuery();
@ -906,15 +934,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} }
private void handleFilters(BooleanJunction<?> theBool, String theSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) { private void handleFilters(BooleanJunction<?> theBool, String theSystem, String theSystemVersion, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
if (theIncludeOrExclude.getFilter().size() > 0) { if (theIncludeOrExclude.getFilter().size() > 0) {
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) { for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
handleFilter(theSystem, theQb, theBool, nextFilter); handleFilter(theSystem, theSystemVersion, theQb, theBool, nextFilter);
} }
} }
} }
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void handleFilter(String theSystem, String theSystemVersion, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) { if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
return; return;
} }
@ -930,7 +958,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
break; break;
case "concept": case "concept":
case "code": case "code":
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter); handleFilterConceptAndCode(theSystem, theSystemVersion, theQb, theBool, theFilter);
break; break;
case "parent": case "parent":
case "child": case "child":
@ -939,11 +967,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
break; break;
case "ancestor": case "ancestor":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
handleFilterLoincAncestor(theSystem, theBool, theFilter); handleFilterLoincAncestor(theSystem, theSystemVersion, theBool, theFilter);
break; break;
case "descendant": case "descendant":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
handleFilterLoincDescendant(theSystem, theBool, theFilter); handleFilterLoincDescendant(theSystem, theSystemVersion, theBool, theFilter);
break; break;
case "copyright": case "copyright":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
@ -993,8 +1021,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
bool.must(textQuery); bool.must(textQuery);
} }
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void handleFilterConceptAndCode(String theSystem, String theSystemVersion, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
TermConcept code = findCode(theSystem, theFilter.getValue()) TermConcept code = findCode(theSystem, theFilter.getValue(), theSystemVersion)
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theFilter.getValue())); .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theFilter.getValue()));
if (theFilter.getOp() == ValueSet.FilterOperator.ISA) { if (theFilter.getOp() == ValueSet.FilterOperator.ISA) {
@ -1039,41 +1067,41 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@SuppressWarnings("EnumSwitchStatementWhichMissesCases") @SuppressWarnings("EnumSwitchStatementWhichMissesCases")
private void handleFilterLoincAncestor(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void handleFilterLoincAncestor(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
switch (theFilter.getOp()) { switch (theFilter.getOp()) {
case EQUAL: case EQUAL:
addLoincFilterAncestorEqual(theSystem, theBool, theFilter); addLoincFilterAncestorEqual(theSystem, theSystemVersion, theBool, theFilter);
break; break;
case IN: case IN:
addLoincFilterAncestorIn(theSystem, theBool, theFilter); addLoincFilterAncestorIn(theSystem, theSystemVersion, theBool, theFilter);
break; break;
default: default:
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
} }
} }
private void addLoincFilterAncestorEqual(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void addLoincFilterAncestorEqual(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
addLoincFilterAncestorEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue()); addLoincFilterAncestorEqual(theSystem, theSystemVersion, theBool, theFilter.getProperty(), theFilter.getValue());
} }
private void addLoincFilterAncestorEqual(String theSystem, BooleanJunction<?> theBool, String theProperty, String theValue) { private void addLoincFilterAncestorEqual(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, String theProperty, String theValue) {
List<Term> terms = getAncestorTerms(theSystem, theProperty, theValue); List<Term> terms = getAncestorTerms(theSystem, theSystemVersion, theProperty, theValue);
theBool.must(new TermsQuery(terms)); theBool.must(new TermsQuery(terms));
} }
private void addLoincFilterAncestorIn(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void addLoincFilterAncestorIn(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
String[] values = theFilter.getValue().split(","); String[] values = theFilter.getValue().split(",");
List<Term> terms = new ArrayList<>(); List<Term> terms = new ArrayList<>();
for (String value : values) { for (String value : values) {
terms.addAll(getAncestorTerms(theSystem, theFilter.getProperty(), value)); terms.addAll(getAncestorTerms(theSystem, theSystemVersion, theFilter.getProperty(), value));
} }
theBool.must(new TermsQuery(terms)); theBool.must(new TermsQuery(terms));
} }
private List<Term> getAncestorTerms(String theSystem, String theProperty, String theValue) { private List<Term> getAncestorTerms(String theSystem, String theSystemVersion, String theProperty, String theValue) {
List<Term> retVal = new ArrayList<>(); List<Term> retVal = new ArrayList<>();
TermConcept code = findCode(theSystem, theValue) TermConcept code = findCode(theSystem, theValue, theSystemVersion)
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue)); .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
retVal.add(new Term("myParentPids", "" + code.getId())); retVal.add(new Term("myParentPids", "" + code.getId()));
@ -1083,41 +1111,41 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@SuppressWarnings("EnumSwitchStatementWhichMissesCases") @SuppressWarnings("EnumSwitchStatementWhichMissesCases")
private void handleFilterLoincDescendant(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void handleFilterLoincDescendant(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
switch (theFilter.getOp()) { switch (theFilter.getOp()) {
case EQUAL: case EQUAL:
addLoincFilterDescendantEqual(theSystem, theBool, theFilter); addLoincFilterDescendantEqual(theSystem, theSystemVersion, theBool, theFilter);
break; break;
case IN: case IN:
addLoincFilterDescendantIn(theSystem, theBool, theFilter); addLoincFilterDescendantIn(theSystem, theSystemVersion, theBool, theFilter);
break; break;
default: default:
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
} }
} }
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void addLoincFilterDescendantEqual(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
addLoincFilterDescendantEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue()); addLoincFilterDescendantEqual(theSystem, theSystemVersion, theBool, theFilter.getProperty(), theFilter.getValue());
} }
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, String theProperty, String theValue) { private void addLoincFilterDescendantEqual(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, String theProperty, String theValue) {
List<Term> terms = getDescendantTerms(theSystem, theProperty, theValue); List<Term> terms = getDescendantTerms(theSystem, theSystemVersion, theProperty, theValue);
theBool.must(new TermsQuery(terms)); theBool.must(new TermsQuery(terms));
} }
private void addLoincFilterDescendantIn(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) { private void addLoincFilterDescendantIn(String theSystem, String theSystemVersion, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
String[] values = theFilter.getValue().split(","); String[] values = theFilter.getValue().split(",");
List<Term> terms = new ArrayList<>(); List<Term> terms = new ArrayList<>();
for (String value : values) { for (String value : values) {
terms.addAll(getDescendantTerms(theSystem, theFilter.getProperty(), value)); terms.addAll(getDescendantTerms(theSystem, theSystemVersion, theFilter.getProperty(), value));
} }
theBool.must(new TermsQuery(terms)); theBool.must(new TermsQuery(terms));
} }
private List<Term> getDescendantTerms(String theSystem, String theProperty, String theValue) { private List<Term> getDescendantTerms(String theSystem, String theSystemVersion, String theProperty, String theValue) {
List<Term> retVal = new ArrayList<>(); List<Term> retVal = new ArrayList<>();
TermConcept code = findCode(theSystem, theValue) TermConcept code = findCode(theSystem, theValue, theSystemVersion)
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue)); .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + Constants.codeSystemWithDefaultDescription(theSystem) + "}" + theValue));
String[] parentPids = code.getParentPidsAsString().split(" "); String[] parentPids = code.getParentPidsAsString().split(" ");
@ -1391,7 +1419,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri, String theVersion) { private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri, String theVersion) {
StringBuilder key = new StringBuilder(theUri); StringBuilder key = new StringBuilder(theUri);
if (theVersion != null) { if (theVersion != null) {
key.append("_").append(theVersion); key.append("|").append(theVersion);
} }
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), t -> myTxTemplate.execute(tx -> { TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), t -> myTxTemplate.execute(tx -> {
TermCodeSystemVersion csv = null; TermCodeSystemVersion csv = null;
@ -1842,21 +1870,21 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Override @Override
@Transactional @Transactional
public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB, IPrimitiveType<String> theSystemVersion, String theCodingAVersion, String theCodingBVersion) { public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB, IPrimitiveType<String> theSystemVersion, String theCodingAVersion, String theCodingBVersion) {
VersionIndependentConceptWithSystemVersion conceptA = toConcept(theCodeA, theSystem, theCodingA, theSystemVersion, theCodingAVersion); VersionIndependentConcept conceptA = toConcept(theCodeA, theSystem, theCodingA, theSystemVersion, theCodingAVersion);
VersionIndependentConceptWithSystemVersion conceptB = toConcept(theCodeB, theSystem, theCodingB, theSystemVersion, theCodingBVersion); VersionIndependentConcept conceptB = toConcept(theCodeB, theSystem, theCodingB, theSystemVersion, theCodingBVersion);
if (!StringUtils.equals(conceptA.getSystem(), conceptB.getSystem())) { if (!StringUtils.equals(conceptA.getSystem(), conceptB.getSystem())) {
throw new InvalidRequestException("Unable to test subsumption across different code systems"); throw new InvalidRequestException("Unable to test subsumption across different code systems");
} }
if (!StringUtils.equals(conceptA.getCodeSystemVersion(), conceptB.getCodeSystemVersion())) { if (!StringUtils.equals(conceptA.getSystemVersion(), conceptB.getSystemVersion())) {
throw new InvalidRequestException("Unable to test subsumption across different code system versions"); throw new InvalidRequestException("Unable to test subsumption across different code system versions");
} }
TermConcept codeA = findCode(conceptA.getSystem(), conceptA.getCode(), conceptA.getCodeSystemVersion()) TermConcept codeA = findCode(conceptA.getSystem(), conceptA.getCode(), conceptA.getSystemVersion())
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA)); .orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA));
TermConcept codeB = findCode(conceptB.getSystem(), conceptB.getCode(), conceptB.getCodeSystemVersion()) TermConcept codeB = findCode(conceptB.getSystem(), conceptB.getCode(), conceptB.getSystemVersion())
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptB)); .orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptB));
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager); FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
@ -2214,7 +2242,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@Override @Override
public CodeSystem fetchCanonicalCodeSystemFromCompleteContext(String theSystem) { public CodeSystem fetchCanonicalCodeSystemFromCompleteContext(String theSystem) {
IValidationSupport validationSupport = provideValidationSupport(); IValidationSupport validationSupport = provideValidationSupport();
IBaseResource codeSystem = validationSupport.fetchCodeSystem(theSystem); IBaseResource codeSystem = validationSupport.fetchCodeSystem(theSystem);
if (codeSystem != null) { if (codeSystem != null) {
@ -2423,7 +2451,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
@NotNull @NotNull
private VersionIndependentConceptWithSystemVersion toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theSystemType, IBaseCoding theCodingType, IPrimitiveType<String> theSystemVersionType, String theCodingVersionType) { private VersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theSystemType, IBaseCoding theCodingType, IPrimitiveType<String> theSystemVersionType, String theCodingVersionType) {
String code = theCodeType != null ? theCodeType.getValueAsString() : null; String code = theCodeType != null ? theCodeType.getValueAsString() : null;
String system = theSystemType != null ? theSystemType.getValueAsString() : null; String system = theSystemType != null ? theSystemType.getValueAsString() : null;
String systemVersion = theSystemVersionType != null ? theSystemVersionType.getValueAsString() : null; String systemVersion = theSystemVersionType != null ? theSystemVersionType.getValueAsString() : null;
@ -2432,10 +2460,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
system = theCodingType.getSystem(); system = theCodingType.getSystem();
systemVersion = theCodingVersionType; systemVersion = theCodingVersionType;
} }
return new VersionIndependentConceptWithSystemVersion(system, code, systemVersion); return new VersionIndependentConcept(system, code, null, systemVersion);
} }
private static class VersionIndependentConceptWithSystemVersion extends VersionIndependentConcept { /* private static class VersionIndependentConceptWithSystemVersion extends VersionIndependentConcept {
String myCodeSystemVersion; String myCodeSystemVersion;
@ -2449,7 +2477,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} }
} }
*/
/** /**
* This method is present only for unit tests, do not call from client code * This method is present only for unit tests, do not call from client code
*/ */

View File

@ -33,8 +33,12 @@ public interface IValueSetConceptAccumulator {
void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations); void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations);
void includeConceptWithDesignations(String theSystem, String theSystemVersion, String theCode, String theDisplay, @Nullable Collection<TermConceptDesignation> theDesignations);
void excludeConcept(String theSystem, String theCode); void excludeConcept(String theSystem, String theCode);
void excludeConcept(String theSystem, String theSystemVersion, String theCode);
@Nullable @Nullable
default Integer getCapacityRemaining() { default Integer getCapacityRemaining() {
return null; return null;

View File

@ -351,32 +351,23 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied"); ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied");
// Grab the existing version so we can delete it // Grab the existing version so we can delete it
TermCodeSystem existingCodeSystem = myCodeSystemDao.findByCodeSystemUri(theSystemUri); List<TermCodeSystemVersion> existing = myCodeSystemVersionDao.findByCodeSystemResourcePid(theCodeSystemResourcePid.getIdAsLong());
TermCodeSystemVersion existing = null;
if (existingCodeSystem != null) {
existing = getExistingTermCodeSystemVersion(existingCodeSystem.getPid(), theSystemVersionId);
}
/*
* Get CodeSystem and validate CodeSystemVersion
*/
TermCodeSystem codeSystem = getOrCreateDistinctTermCodeSystem(theCodeSystemResourcePid, theSystemUri, theSystemName, theSystemVersionId, theCodeSystemResourceTable);
/* /*
* Delete version being replaced. * Delete version being replaced.
*/ */
if(existing != null) { for (TermCodeSystemVersion next : existing) {
ourLog.info("Deleting old code system version {}", existing.getPid()); ourLog.info("Deleting old code system version {}", next.getPid());
Long codeSystemVersionPid = existing.getPid(); Long codeSystemVersionPid = next.getPid();
deleteCodeSystemVersion(codeSystemVersionPid); deleteCodeSystemVersion(codeSystemVersionPid);
} }
/* /*
* Do the upload * Do the upload
*/ */
TermCodeSystem codeSystem = getOrCreateDistinctTermCodeSystem(theCodeSystemResourcePid, theSystemUri, theSystemName, theSystemVersionId, theCodeSystemResourceTable);
theCodeSystemVersion.setCodeSystem(codeSystem); theCodeSystemVersion.setCodeSystem(codeSystem);
theCodeSystemVersion.setCodeSystemDisplayName(theSystemName); theCodeSystemVersion.setCodeSystemDisplayName(theSystemName);
@ -687,13 +678,14 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
if (codeSystem == null) { if (codeSystem == null) {
codeSystem = new TermCodeSystem(); codeSystem = new TermCodeSystem();
} }
} else {
checkForCodeSystemVersionDuplicate(codeSystem, theSystemUri, theSystemVersionId, theCodeSystemResourceTable);
} }
codeSystem.setResource(theCodeSystemResourceTable); codeSystem.setResource(theCodeSystemResourceTable);
codeSystem.setCodeSystemUri(theSystemUri); codeSystem.setCodeSystemUri(theSystemUri);
codeSystem.setName(theSystemName); codeSystem.setName(theSystemName);
codeSystem = myCodeSystemDao.save(codeSystem); codeSystem = myCodeSystemDao.save(codeSystem);
checkForCodeSystemVersionDuplicate(codeSystem,theSystemUri, theSystemVersionId, theCodeSystemResourceTable);
return codeSystem; return codeSystem;
} }
@ -711,13 +703,6 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
codeSystemVersionEntity = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(theCodeSystem.getPid(), theSystemVersionId); codeSystemVersionEntity = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(theCodeSystem.getPid(), theSystemVersionId);
if (codeSystemVersionEntity != null) { if (codeSystemVersionEntity != null) {
msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "cannotCreateDuplicateCodeSystemUrlAndVersion", theSystemUri, theSystemVersionId, codeSystemVersionEntity.getResource().getIdDt().toUnqualifiedVersionless().getValue()); msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "cannotCreateDuplicateCodeSystemUrlAndVersion", theSystemUri, theSystemVersionId, codeSystemVersionEntity.getResource().getIdDt().toUnqualifiedVersionless().getValue());
} else {
// Check if a TermCodeSystemVersion entity already exists for this CodeSystem resource (i.e. with a different version or URL)
codeSystemVersionEntity = myCodeSystemVersionDao.findByCodeSystemResourcePid(theCodeSystemResourceTable.getId());
if (codeSystemVersionEntity != null) {
msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "cannotUpdateUrlOrVersionForCodeSystemResource", codeSystemVersionEntity.getResource().getIdDt().toUnqualifiedVersionless().getValue(), theSystemUri, theSystemVersionId);
throw new UnprocessableEntityException(msg);
}
} }
} }
// Throw exception if the TermCodeSystemVersion is being duplicated. // Throw exception if the TermCodeSystemVersion is being duplicated.

View File

@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.term;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
@ -69,14 +68,12 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
@Autowired @Autowired
protected PlatformTransactionManager myTransactionMgr; protected PlatformTransactionManager myTransactionMgr;
private boolean myProcessDeferred = true; private boolean myProcessDeferred = true;
private List<TermCodeSystem> myDefferedCodeSystemsDeletions = Collections.synchronizedList(new ArrayList<>()); final private List<TermCodeSystem> myDefferedCodeSystemsDeletions = Collections.synchronizedList(new ArrayList<>());
private List<TermCodeSystemVersion> myDefferedCodeSystemVersionsDeletions = Collections.synchronizedList(new ArrayList<>()); final private List<TermCodeSystemVersion> myDefferedCodeSystemVersionsDeletions = Collections.synchronizedList(new ArrayList<>());
private List<TermConcept> myDeferredConcepts = Collections.synchronizedList(new ArrayList<>()); final private List<TermConcept> myDeferredConcepts = Collections.synchronizedList(new ArrayList<>());
private List<ValueSet> myDeferredValueSets = Collections.synchronizedList(new ArrayList<>()); final private List<ValueSet> myDeferredValueSets = Collections.synchronizedList(new ArrayList<>());
private List<ConceptMap> myDeferredConceptMaps = Collections.synchronizedList(new ArrayList<>()); final private List<ConceptMap> myDeferredConceptMaps = Collections.synchronizedList(new ArrayList<>());
private List<TermConceptParentChildLink> myConceptLinksToSaveLater = Collections.synchronizedList(new ArrayList<>()); final private List<TermConceptParentChildLink> myConceptLinksToSaveLater = Collections.synchronizedList(new ArrayList<>());
@Autowired
private DaoConfig myDaoConfig;
@Autowired @Autowired
private ITermConceptParentChildLinkDao myConceptParentChildLinkDao; private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
@Autowired @Autowired
@ -121,9 +118,11 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
@Override @Override
@Transactional @Transactional
public void deleteCodeSystemForResource(ResourceTable theCodeSystemToDelete) { public void deleteCodeSystemForResource(ResourceTable theCodeSystemToDelete) {
TermCodeSystemVersion codeSystemVersionToDelete = myCodeSystemVersionDao.findByCodeSystemResourcePid(theCodeSystemToDelete.getResourceId()); List<TermCodeSystemVersion> codeSystemVersionsToDelete = myCodeSystemVersionDao.findByCodeSystemResourcePid(theCodeSystemToDelete.getResourceId());
if (codeSystemVersionToDelete != null) { for (TermCodeSystemVersion codeSystemVersionToDelete : codeSystemVersionsToDelete){
myDefferedCodeSystemVersionsDeletions.add(codeSystemVersionToDelete); if (codeSystemVersionToDelete != null) {
myDefferedCodeSystemVersionsDeletions.add(codeSystemVersionToDelete);
}
} }
TermCodeSystem codeSystemToDelete = myCodeSystemDao.findByResourcePid(theCodeSystemToDelete.getResourceId()); TermCodeSystem codeSystemToDelete = myCodeSystemDao.findByResourcePid(theCodeSystemToDelete.getResourceId());
if (codeSystemToDelete != null) { if (codeSystemToDelete != null) {
@ -297,8 +296,7 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
@Override @Override
public boolean isStorageQueueEmpty() { public boolean isStorageQueueEmpty() {
boolean retVal = true; boolean retVal = !isProcessDeferredPaused();
retVal &= !isProcessDeferredPaused();
retVal &= !isDeferredConcepts(); retVal &= !isDeferredConcepts();
retVal &= !isConceptLinksToSaveLater(); retVal &= !isConceptLinksToSaveLater();
retVal &= !isDeferredValueSets(); retVal &= !isDeferredValueSets();
@ -368,11 +366,6 @@ public class TermDeferredStorageSvcImpl implements ITermDeferredStorageSvc {
myTransactionMgr = theTxManager; myTransactionMgr = theTxManager;
} }
@VisibleForTesting
void setDaoConfigForUnitTest(DaoConfig theDaoConfig) {
myDaoConfig = theDaoConfig;
}
@VisibleForTesting @VisibleForTesting
void setCodeSystemStorageSvcForUnitTest(ITermCodeSystemStorageSvc theCodeSystemStorageSvc) { void setCodeSystemStorageSvcForUnitTest(ITermCodeSystemStorageSvc theCodeSystemStorageSvc) {
myCodeSystemStorageSvc = theCodeSystemStorageSvc; myCodeSystemStorageSvc = theCodeSystemStorageSvc;

View File

@ -71,7 +71,7 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
} }
@Override @Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) { public void includeConceptWithDesignations(String theSystem, String theSystemVersion, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay); TermValueSetConcept concept = saveConcept(theSystem, theCode, theDisplay);
if (theDesignations != null) { if (theDesignations != null) {
for (TermConceptDesignation designation : theDesignations) { for (TermConceptDesignation designation : theDesignations) {
@ -80,8 +80,18 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator {
} }
} }
@Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
includeConceptWithDesignations(theSystem, null, theCode, theDisplay, theDesignations);
}
@Override @Override
public void excludeConcept(String theSystem, String theCode) { public void excludeConcept(String theSystem, String theCode) {
excludeConcept(theSystem, null, theCode);
}
@Override
public void excludeConcept(String theSystem, String theSystemVersion, String theCode) {
if (isAnyBlank(theSystem, theCode)) { if (isAnyBlank(theSystem, theCode)) {
return; return;
} }

View File

@ -73,12 +73,15 @@ 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 theSystemVersion, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
incrementConceptsCount(); incrementConceptsCount();
ValueSet.ValueSetExpansionContainsComponent contains = this.addContains(); ValueSet.ValueSetExpansionContainsComponent contains = this.addContains();
contains.setSystem(theSystem); contains.setSystem(theSystem);
contains.setCode(theCode); contains.setCode(theCode);
contains.setDisplay(theDisplay); contains.setDisplay(theDisplay);
if (theSystemVersion != null) {
contains.setVersion(theSystemVersion);
}
if (theDesignations != null) { if (theDesignations != null) {
for (TermConceptDesignation termConceptDesignation : theDesignations) { for (TermConceptDesignation termConceptDesignation : theDesignations) {
contains contains
@ -93,6 +96,21 @@ public class ValueSetExpansionComponentWithConceptAccumulator extends ValueSet.V
} }
} }
@Override
public void includeConceptWithDesignations(String theSystem, String theCode, String theDisplay, Collection<TermConceptDesignation> theDesignations) {
this.includeConceptWithDesignations(theSystem, null, theCode, theDisplay, theDesignations);
}
@Override
public void excludeConcept(String theSystem, String theSystemVersion, String theCode) {
this
.getContains()
.removeIf(t ->
theSystem.equals(t.getSystem()) &&
theCode.equals(t.getCode()) &&
theSystemVersion.equals(t.getVersion()));
}
@Override @Override
public void excludeConcept(String theSystem, String theCode) { public void excludeConcept(String theSystem, String theCode) {
this this

View File

@ -0,0 +1,222 @@
package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoDstu3ValueSetMultiVersionTest extends BaseJpaDstu3Test {
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
private enum ValueSetVersions { NULL, V1, V2 }
@Autowired
protected ITermValueSetConceptDao myTermValueSetConceptDao;
private DaoMethodOutcome createLocalCsAndVs(String theVersion, Set<String> theCodeSystemCodes) {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion(theVersion);
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
for (String codeSystemCode : theCodeSystemCodes) {
codeSystem.addConcept().setCode(codeSystemCode);
}
myCodeSystemDao.create(codeSystem, mySrd);
return createLocalVs(codeSystem, theVersion);
}
private DaoMethodOutcome createLocalVs(CodeSystem theCodeSystem, String theVersion) {
ValueSet valueSet = new ValueSet();
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.setVersion(theVersion);
if (theVersion == null) {
valueSet.setName("ValueSet_noVersion");
} else {
valueSet.setName("ValueSet_"+theVersion);
}
valueSet.getCompose().addInclude().setSystem(theCodeSystem.getUrl());
return myValueSetDao.create(valueSet, mySrd);
}
private Map<ValueSetVersions, DaoMethodOutcome> createVersionedValueSets() {
HashMap<ValueSetVersions, DaoMethodOutcome> valueSets = new HashMap<>();
Set<String> valueSetConcepts_noVersion = new HashSet<>();
valueSetConcepts_noVersion.add("hello");
valueSetConcepts_noVersion.add("goodbye");
valueSets.put(ValueSetVersions.NULL, createLocalCsAndVs(null, valueSetConcepts_noVersion));
Set<String> valueSetConcepts_v1 = new HashSet<>(valueSetConcepts_noVersion);
valueSetConcepts_v1.add("hi");
valueSets.put(ValueSetVersions.V1, createLocalCsAndVs("v1", valueSetConcepts_v1));
Set<String> valueSetConcepts_v2 = new HashSet<>(valueSetConcepts_v1);
valueSetConcepts_v2.add("so-long");
valueSets.put(ValueSetVersions.V2, createLocalCsAndVs("v2", valueSetConcepts_v2));
return valueSets;
}
@Test
public void testCreateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
assertTrue(optionalTermValueSet.isPresent());
Long nullVersion_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.NULL).getEntity()).getId();
assertNotNull(nullVersion_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(nullVersion_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_noVersion", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
assertTrue(optionalTermValueSet.isPresent());
Long v1Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V1).getEntity()).getId();
assertNotNull(v1Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v1Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v1", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
assertTrue(optionalTermValueSet.isPresent());
Long v2Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V2).getEntity()).getId();
assertNotNull(v2Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v2Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v2", optionalTermValueSet.get().getName());
}
@Test
public void testUpdateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Update ValueSets
ValueSet updated = (ValueSet)myValueSets.get(ValueSetVersions.NULL).getResource();
updated.setName("ValueSet_noVersion_updated");
DaoMethodOutcome nullVersion_update_outcome = myValueSetDao.update(updated);
Long nullVersion_resid = ((ResourceTable)nullVersion_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V1).getResource();
updated.setName("ValueSet_v1_updated");
DaoMethodOutcome v1Version_update_outcome = myValueSetDao.update(updated);
Long v1Version_resid = ((ResourceTable)v1Version_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V2).getResource();
updated.setName("ValueSet_v2_updated");
DaoMethodOutcome v2Version_update_outcome = myValueSetDao.update(updated);
Long v2Version_resid = ((ResourceTable)v2Version_update_outcome.getEntity()).getId();
// Verify that ValueSets were updated.
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertNotNull(nullVersion_resid);
assertNotNull(termValueSet.getResource());
assertEquals(nullVersion_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_noVersion_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertNotNull(v1Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v1Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v1_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertNotNull(v2Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v2Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v2_updated", termValueSet.getName());
}
@Test
public void testDeleteVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Delete ValueSets
myValueSetDao.delete(myValueSets.get(ValueSetVersions.NULL).getResource().getIdElement());
assertEquals(2, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V1).getResource().getIdElement());
assertEquals(1, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V2).getResource().getIdElement());
assertEquals(0, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
if (optionalTermValueSet.isPresent()) {
fail();
}
}
}

View File

@ -235,6 +235,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
@Test @Test
public void testCodeSystemCreateDuplicateFails() { public void testCodeSystemCreateDuplicateFails() {
// No version.
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setContent(CodeSystemContentMode.COMPLETE); codeSystem.setContent(CodeSystemContentMode.COMPLETE);
@ -249,6 +250,25 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
} catch (UnprocessableEntityException e) { } catch (UnprocessableEntityException e) {
assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage()); assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
} }
// With version.
codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion("1");
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion("1");
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
try {
myCodeSystemDao.create(codeSystem, mySrd);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Can not create multiple CodeSystem resources with CodeSystem.url \"http://example.com/my_code_system\" and CodeSystem.version \"1\", already have one with resource ID: CodeSystem/" + id.getIdPart(), e.getMessage());
}
} }
@Test @Test

View File

@ -0,0 +1,222 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoR4ValueSetMultiVersionTest extends BaseJpaR4Test {
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
private enum ValueSetVersions { NULL, V1, V2 }
@Autowired
protected ITermValueSetConceptDao myTermValueSetConceptDao;
private DaoMethodOutcome createLocalCsAndVs(String theVersion, Set<String> theCodeSystemCodes) {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion(theVersion);
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
for (String codeSystemCode : theCodeSystemCodes) {
codeSystem.addConcept().setCode(codeSystemCode);
}
myCodeSystemDao.create(codeSystem, mySrd);
return createLocalVs(codeSystem, theVersion);
}
private DaoMethodOutcome createLocalVs(CodeSystem theCodeSystem, String theVersion) {
ValueSet valueSet = new ValueSet();
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.setVersion(theVersion);
if (theVersion == null) {
valueSet.setName("ValueSet_noVersion");
} else {
valueSet.setName("ValueSet_"+theVersion);
}
valueSet.getCompose().addInclude().setSystem(theCodeSystem.getUrl());
return myValueSetDao.create(valueSet, mySrd);
}
private Map<ValueSetVersions, DaoMethodOutcome> createVersionedValueSets() {
HashMap<ValueSetVersions, DaoMethodOutcome> valueSets = new HashMap<>();
Set<String> valueSetConcepts_noVersion = new HashSet<>();
valueSetConcepts_noVersion.add("hello");
valueSetConcepts_noVersion.add("goodbye");
valueSets.put(ValueSetVersions.NULL, createLocalCsAndVs(null, valueSetConcepts_noVersion));
Set<String> valueSetConcepts_v1 = new HashSet<>(valueSetConcepts_noVersion);
valueSetConcepts_v1.add("hi");
valueSets.put(ValueSetVersions.V1, createLocalCsAndVs("v1", valueSetConcepts_v1));
Set<String> valueSetConcepts_v2 = new HashSet<>(valueSetConcepts_v1);
valueSetConcepts_v2.add("so-long");
valueSets.put(ValueSetVersions.V2, createLocalCsAndVs("v2", valueSetConcepts_v2));
return valueSets;
}
@Test
public void testCreateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
assertTrue(optionalTermValueSet.isPresent());
Long nullVersion_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.NULL).getEntity()).getId();
assertNotNull(nullVersion_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(nullVersion_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_noVersion", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
assertTrue(optionalTermValueSet.isPresent());
Long v1Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V1).getEntity()).getId();
assertNotNull(v1Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v1Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v1", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
assertTrue(optionalTermValueSet.isPresent());
Long v2Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V2).getEntity()).getId();
assertNotNull(v2Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v2Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v2", optionalTermValueSet.get().getName());
}
@Test
public void testUpdateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Update ValueSets
ValueSet updated = (ValueSet)myValueSets.get(ValueSetVersions.NULL).getResource();
updated.setName("ValueSet_noVersion_updated");
DaoMethodOutcome nullVersion_update_outcome = myValueSetDao.update(updated);
Long nullVersion_resid = ((ResourceTable)nullVersion_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V1).getResource();
updated.setName("ValueSet_v1_updated");
DaoMethodOutcome v1Version_update_outcome = myValueSetDao.update(updated);
Long v1Version_resid = ((ResourceTable)v1Version_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V2).getResource();
updated.setName("ValueSet_v2_updated");
DaoMethodOutcome v2Version_update_outcome = myValueSetDao.update(updated);
Long v2Version_resid = ((ResourceTable)v2Version_update_outcome.getEntity()).getId();
// Verify that ValueSets were updated.
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertNotNull(nullVersion_resid);
assertNotNull(termValueSet.getResource());
assertEquals(nullVersion_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_noVersion_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertNotNull(v1Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v1Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v1_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertNotNull(v2Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v2Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v2_updated", termValueSet.getName());
}
@Test
public void testDeleteVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Delete ValueSets
myValueSetDao.delete(myValueSets.get(ValueSetVersions.NULL).getResource().getIdElement());
assertEquals(2, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V1).getResource().getIdElement());
assertEquals(1, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V2).getResource().getIdElement());
assertEquals(0, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
if (optionalTermValueSet.isPresent()) {
fail();
}
}
}

View File

@ -0,0 +1,222 @@
package ca.uhn.fhir.jpa.dao.r5;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ValueSet;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class FhirResourceDaoR5ValueSetMultiVersionTest extends BaseJpaR5Test {
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
private enum ValueSetVersions { NULL, V1, V2 }
@Autowired
protected ITermValueSetConceptDao myTermValueSetConceptDao;
private DaoMethodOutcome createLocalCsAndVs(String theVersion, Set<String> theCodeSystemCodes) {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion(theVersion);
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
for (String codeSystemCode : theCodeSystemCodes) {
codeSystem.addConcept().setCode(codeSystemCode);
}
myCodeSystemDao.create(codeSystem, mySrd);
return createLocalVs(codeSystem, theVersion);
}
private DaoMethodOutcome createLocalVs(CodeSystem theCodeSystem, String theVersion) {
ValueSet valueSet = new ValueSet();
valueSet.setUrl(URL_MY_VALUE_SET);
valueSet.setVersion(theVersion);
if (theVersion == null) {
valueSet.setName("ValueSet_noVersion");
} else {
valueSet.setName("ValueSet_"+theVersion);
}
valueSet.getCompose().addInclude().setSystem(theCodeSystem.getUrl());
return myValueSetDao.create(valueSet, mySrd);
}
private Map<ValueSetVersions, DaoMethodOutcome> createVersionedValueSets() {
HashMap<ValueSetVersions, DaoMethodOutcome> valueSets = new HashMap<>();
Set<String> valueSetConcepts_noVersion = new HashSet<>();
valueSetConcepts_noVersion.add("hello");
valueSetConcepts_noVersion.add("goodbye");
valueSets.put(ValueSetVersions.NULL, createLocalCsAndVs(null, valueSetConcepts_noVersion));
Set<String> valueSetConcepts_v1 = new HashSet<>(valueSetConcepts_noVersion);
valueSetConcepts_v1.add("hi");
valueSets.put(ValueSetVersions.V1, createLocalCsAndVs("v1", valueSetConcepts_v1));
Set<String> valueSetConcepts_v2 = new HashSet<>(valueSetConcepts_v1);
valueSetConcepts_v2.add("so-long");
valueSets.put(ValueSetVersions.V2, createLocalCsAndVs("v2", valueSetConcepts_v2));
return valueSets;
}
@Test
public void testCreateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
assertTrue(optionalTermValueSet.isPresent());
Long nullVersion_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.NULL).getEntity()).getId();
assertNotNull(nullVersion_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(nullVersion_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_noVersion", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
assertTrue(optionalTermValueSet.isPresent());
Long v1Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V1).getEntity()).getId();
assertNotNull(v1Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v1Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v1", optionalTermValueSet.get().getName());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
assertTrue(optionalTermValueSet.isPresent());
Long v2Version_resid = ((ResourceTable)myValueSets.get(ValueSetVersions.V2).getEntity()).getId();
assertNotNull(v2Version_resid);
assertNotNull(optionalTermValueSet.get().getResource());
assertEquals(v2Version_resid, optionalTermValueSet.get().getResource().getId());
assertEquals("ValueSet_v2", optionalTermValueSet.get().getName());
}
@Test
public void testUpdateVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Update ValueSets
ValueSet updated = (ValueSet)myValueSets.get(ValueSetVersions.NULL).getResource();
updated.setName("ValueSet_noVersion_updated");
DaoMethodOutcome nullVersion_update_outcome = myValueSetDao.update(updated);
Long nullVersion_resid = ((ResourceTable)nullVersion_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V1).getResource();
updated.setName("ValueSet_v1_updated");
DaoMethodOutcome v1Version_update_outcome = myValueSetDao.update(updated);
Long v1Version_resid = ((ResourceTable)v1Version_update_outcome.getEntity()).getId();
updated = (ValueSet)myValueSets.get(ValueSetVersions.V2).getResource();
updated.setName("ValueSet_v2_updated");
DaoMethodOutcome v2Version_update_outcome = myValueSetDao.update(updated);
Long v2Version_resid = ((ResourceTable)v2Version_update_outcome.getEntity()).getId();
// Verify that ValueSets were updated.
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertNotNull(nullVersion_resid);
assertNotNull(termValueSet.getResource());
assertEquals(nullVersion_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_noVersion_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertNotNull(v1Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v1Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v1_updated", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertNotNull(v2Version_resid);
assertNotNull(termValueSet.getResource());
assertEquals(v2Version_resid, termValueSet.getResource().getId());
assertEquals("ValueSet_v2_updated", termValueSet.getName());
}
@Test
public void testDeleteVersionedValueSets() {
Map<ValueSetVersions, DaoMethodOutcome> myValueSets = createVersionedValueSets();
assertEquals(3, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
TermValueSet termValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET).orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " with null version"));
assertEquals("ValueSet_noVersion", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
assertEquals("ValueSet_v1", termValueSet.getName());
termValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
assertEquals("ValueSet_v2", termValueSet.getName());
// Delete ValueSets
myValueSetDao.delete(myValueSets.get(ValueSetVersions.NULL).getResource().getIdElement());
assertEquals(2, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
Optional<TermValueSet> optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v1"));
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V1).getResource().getIdElement());
assertEquals(1, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2").orElseThrow(() -> new IllegalArgumentException("No TerValueSet found for " + URL_MY_VALUE_SET + " version v2"));
myValueSetDao.delete(myValueSets.get(ValueSetVersions.V2).getResource().getIdElement());
assertEquals(0, myTermValueSetDao.findTermValueSetByUrl(PageRequest.of(0, 10), URL_MY_VALUE_SET).size());
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndNullVersion(URL_MY_VALUE_SET);
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v1");
if (optionalTermValueSet.isPresent()) {
fail();
}
optionalTermValueSet = myTermValueSetDao.findTermValueSetByUrlAndVersion(URL_MY_VALUE_SET, "v2");
if (optionalTermValueSet.isPresent()) {
fail();
}
}
}

View File

@ -1,9 +1,16 @@
package ca.uhn.fhir.jpa.provider.r4; package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest; import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -18,6 +25,7 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
private static final String SYSTEM_PARENTCHILD = "http://parentchild"; private static final String SYSTEM_PARENTCHILD = "http://parentchild";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemTest.class);
private Long parentChildCsId;
@BeforeEach @BeforeEach
@Transactional @Transactional
@ -27,6 +35,7 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
CodeSystem parentChildCs = new CodeSystem(); CodeSystem parentChildCs = new CodeSystem();
parentChildCs.setUrl(SYSTEM_PARENTCHILD); parentChildCs.setUrl(SYSTEM_PARENTCHILD);
parentChildCs.setName("Parent Child CodeSystem");
parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE); parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE);
parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
parentChildCs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA); parentChildCs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
@ -35,7 +44,8 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
parentA.addConcept().setCode("ChildAA").setDisplay("Child AA"); parentA.addConcept().setCode("ChildAA").setDisplay("Child AA");
parentChildCs.addConcept().setCode("ParentB").setDisplay("Parent B"); parentChildCs.addConcept().setCode("ParentB").setDisplay("Parent B");
myCodeSystemDao.create(parentChildCs); DaoMethodOutcome parentChildCsOutcome = myCodeSystemDao.create(parentChildCs);
parentChildCsId = ((ResourceTable)parentChildCsOutcome.getEntity()).getId();
} }
@ -416,5 +426,25 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test
assertEquals(ConceptSubsumptionOutcome.NOTSUBSUMED.toCode(), ((CodeType) respParam.getParameter().get(0).getValue()).getValue()); assertEquals(ConceptSubsumptionOutcome.NOTSUBSUMED.toCode(), ((CodeType) respParam.getParameter().get(0).getValue()).getValue());
} }
@Test
public void testUpdateCodeSystemName() throws IOException {
CodeSystem initialCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCsId).execute();
assertEquals("Parent Child CodeSystem", initialCodeSystem.getName());
initialCodeSystem.setName("Updated Parent Child CodeSystem");
String encoded = myFhirCtx.newJsonParser().encodeResourceToString(initialCodeSystem);
HttpPut putRequest = new HttpPut(ourServerBase + "/CodeSystem/" + parentChildCsId);
putRequest.setEntity(new StringEntity(encoded, ContentType.parse("application/json+fhir")));
CloseableHttpResponse resp = ourHttpClient.execute(putRequest);
try {
assertEquals(200, resp.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(resp);
}
CodeSystem updatedCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCsId).execute();
assertEquals("Updated Parent Child CodeSystem", updatedCodeSystem.getName());
}
} }

View File

@ -1,9 +1,16 @@
package ca.uhn.fhir.jpa.provider.r4; package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest; import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
@ -12,7 +19,6 @@ import org.hl7.fhir.r4.model.Enumerations;
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.ValueSet;
import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -27,6 +33,8 @@ public class ResourceProviderR4CodeSystemVersionedTest extends BaseResourceProvi
private static final String SYSTEM_PARENTCHILD = "http://parentchild"; private static final String SYSTEM_PARENTCHILD = "http://parentchild";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemVersionedTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemVersionedTest.class);
private long parentChildCs1Id;
private long parentChildCs2Id;
@BeforeEach @BeforeEach
@Transactional @Transactional
@ -48,6 +56,7 @@ public class ResourceProviderR4CodeSystemVersionedTest extends BaseResourceProvi
CodeSystem parentChildCs = new CodeSystem(); CodeSystem parentChildCs = new CodeSystem();
parentChildCs.setUrl(SYSTEM_PARENTCHILD); parentChildCs.setUrl(SYSTEM_PARENTCHILD);
parentChildCs.setVersion("1"); parentChildCs.setVersion("1");
parentChildCs.setName("Parent Child CodeSystem 1");
parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE); parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE);
parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
parentChildCs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA); parentChildCs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
@ -57,10 +66,12 @@ public class ResourceProviderR4CodeSystemVersionedTest extends BaseResourceProvi
parentA.addConcept().setCode("ParentC").setDisplay("Parent C"); parentA.addConcept().setCode("ParentC").setDisplay("Parent C");
parentChildCs.addConcept().setCode("ParentB").setDisplay("Parent B"); parentChildCs.addConcept().setCode("ParentB").setDisplay("Parent B");
myCodeSystemDao.create(parentChildCs); DaoMethodOutcome parentChildCsOutcome = myCodeSystemDao.create(parentChildCs);
parentChildCs1Id = ((ResourceTable)parentChildCsOutcome.getEntity()).getId();
parentChildCs = new CodeSystem(); parentChildCs = new CodeSystem();
parentChildCs.setVersion("2"); parentChildCs.setVersion("2");
parentChildCs.setName("Parent Child CodeSystem 2");
parentChildCs.setUrl(SYSTEM_PARENTCHILD); parentChildCs.setUrl(SYSTEM_PARENTCHILD);
parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE); parentChildCs.setStatus(Enumerations.PublicationStatus.ACTIVE);
parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE); parentChildCs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
@ -71,7 +82,8 @@ public class ResourceProviderR4CodeSystemVersionedTest extends BaseResourceProvi
parentA.addConcept().setCode("ParentB").setDisplay("Parent B v2"); parentA.addConcept().setCode("ParentB").setDisplay("Parent B v2");
parentChildCs.addConcept().setCode("ParentC").setDisplay("Parent C v2"); parentChildCs.addConcept().setCode("ParentC").setDisplay("Parent C v2");
myCodeSystemDao.create(parentChildCs); parentChildCsOutcome = myCodeSystemDao.create(parentChildCs);
parentChildCs2Id = ((ResourceTable)parentChildCsOutcome.getEntity()).getId();
} }
@ -770,5 +782,41 @@ public class ResourceProviderR4CodeSystemVersionedTest extends BaseResourceProvi
} }
@Test
public void testUpdateCodeSystemName() throws IOException {
CodeSystem initialCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCs1Id).execute();
assertEquals("Parent Child CodeSystem 1", initialCodeSystem.getName());
initialCodeSystem.setName("Updated Parent Child CodeSystem 1");
String encoded = myFhirCtx.newJsonParser().encodeResourceToString(initialCodeSystem);
HttpPut putRequest = new HttpPut(ourServerBase + "/CodeSystem/" + parentChildCs1Id);
putRequest.setEntity(new StringEntity(encoded, ContentType.parse("application/json+fhir")));
CloseableHttpResponse resp = ourHttpClient.execute(putRequest);
try {
assertEquals(200, resp.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(resp);
}
CodeSystem updatedCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCs1Id).execute();
assertEquals("Updated Parent Child CodeSystem 1", updatedCodeSystem.getName());
initialCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCs2Id).execute();
assertEquals("Parent Child CodeSystem 2", initialCodeSystem.getName());
initialCodeSystem.setName("Updated Parent Child CodeSystem 2");
encoded = myFhirCtx.newJsonParser().encodeResourceToString(initialCodeSystem);
putRequest = new HttpPut(ourServerBase + "/CodeSystem/" + parentChildCs2Id);
putRequest.setEntity(new StringEntity(encoded, ContentType.parse("application/json+fhir")));
resp = ourHttpClient.execute(putRequest);
try {
assertEquals(200, resp.getStatusLine().getStatusCode());
} finally {
IOUtils.closeQuietly(resp);
}
updatedCodeSystem = myClient.read().resource(CodeSystem.class).withId(parentChildCs2Id).execute();
assertEquals("Updated Parent Child CodeSystem 2", updatedCodeSystem.getName());
}
} }

View File

@ -43,6 +43,8 @@ import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
import org.hl7.fhir.r4.model.codesystems.HttpVerb; import org.hl7.fhir.r4.model.codesystems.HttpVerb;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@ -245,6 +247,8 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Slice<TermValueSet> page = myTermValueSetDao.findByExpansionStatus(PageRequest.of(0, 10), TermValueSetPreExpansionStatusEnum.EXPANDED);
assertEquals(1, page.getContent().size());
Parameters respParam = myClient Parameters respParam = myClient
.operation() .operation()
@ -297,6 +301,8 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Slice<TermValueSet> page = myTermValueSetDao.findByExpansionStatus(PageRequest.of(0, 10), TermValueSetPreExpansionStatusEnum.EXPANDED);
assertEquals(1, page.getContent().size());
Parameters respParam = myClient Parameters respParam = myClient
.operation() .operation()
@ -356,6 +362,8 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
loadAndPersistCodeSystemAndValueSet(); loadAndPersistCodeSystemAndValueSet();
myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
Slice<TermValueSet> page = myTermValueSetDao.findByExpansionStatus(PageRequest.of(0, 10), TermValueSetPreExpansionStatusEnum.EXPANDED);
assertEquals(1, page.getContent().size());
Parameters respParam = myClient Parameters respParam = myClient
.operation() .operation()
@ -1093,7 +1101,6 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
public static CodeSystem createExternalCs(IFhirResourceDao<CodeSystem> theCodeSystemDao, IResourceTableDao theResourceTableDao, ITermCodeSystemStorageSvc theTermCodeSystemStorageSvc, ServletRequestDetails theRequestDetails, String theCodeSystemVersion) { public static CodeSystem createExternalCs(IFhirResourceDao<CodeSystem> theCodeSystemDao, IResourceTableDao theResourceTableDao, ITermCodeSystemStorageSvc theTermCodeSystemStorageSvc, ServletRequestDetails theRequestDetails, String theCodeSystemVersion) {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setUrl(URL_MY_CODE_SYSTEM);
codeSystem.setVersion("SYSTEM VERSION");
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT); codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
codeSystem.setVersion(theCodeSystemVersion); codeSystem.setVersion(theCodeSystemVersion);
IIdType id = theCodeSystemDao.create(codeSystem, theRequestDetails).getId().toUnqualified(); IIdType id = theCodeSystemDao.create(codeSystem, theRequestDetails).getId().toUnqualified();

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
@ -54,7 +53,6 @@ public class TermDeferredStorageSvcImplTest {
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl(); TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
svc.setTransactionManagerForUnitTest(myTxManager); svc.setTransactionManagerForUnitTest(myTxManager);
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc); svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
svc.setDaoConfigForUnitTest(new DaoConfig());
when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.of(myTermCodeSystemVersion)); when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.of(myTermCodeSystemVersion));
svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao); svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao);
@ -78,7 +76,6 @@ public class TermDeferredStorageSvcImplTest {
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl(); TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
svc.setTransactionManagerForUnitTest(myTxManager); svc.setTransactionManagerForUnitTest(myTxManager);
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc); svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
svc.setDaoConfigForUnitTest(new DaoConfig());
when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.empty()); when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.empty());
svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao); svc.setCodeSystemVersionDaoForUnitTest(myTermCodeSystemVersionDao);
@ -104,7 +101,6 @@ public class TermDeferredStorageSvcImplTest {
TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl(); TermDeferredStorageSvcImpl svc = new TermDeferredStorageSvcImpl();
svc.setTransactionManagerForUnitTest(myTxManager); svc.setTransactionManagerForUnitTest(myTxManager);
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc); svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
svc.setDaoConfigForUnitTest(new DaoConfig());
// Simulate the case where an exception is thrown despite a valid code system version. // Simulate the case where an exception is thrown despite a valid code system version.
when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.of(myTermCodeSystemVersion)); when(myTermCodeSystemVersionDao.findById(anyLong())).thenReturn(Optional.of(myTermCodeSystemVersion));
@ -129,7 +125,6 @@ public class TermDeferredStorageSvcImplTest {
svc.setTransactionManagerForUnitTest(myTxManager); svc.setTransactionManagerForUnitTest(myTxManager);
svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc); svc.setCodeSystemStorageSvcForUnitTest(myTermConceptStorageSvc);
svc.setConceptDaoForUnitTest(myConceptDao); svc.setConceptDaoForUnitTest(myConceptDao);
svc.setDaoConfigForUnitTest(new DaoConfig());
svc.setProcessDeferred(true); svc.setProcessDeferred(true);
svc.addConceptLinkToStorageQueue(conceptLink); svc.addConceptLinkToStorageQueue(conceptLink);
svc.saveDeferred(); svc.saveDeferred();

View File

@ -1942,6 +1942,58 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test {
}); });
} }
@Test
public void testUpdateCodeSystemUrlAndVersion() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(CS_URL);
codeSystem.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
codeSystem
.addConcept().setCode("A").setDisplay("Code A");
codeSystem
.addConcept().setCode("B").setDisplay("Code A");
codeSystem.setVersion("1");
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
Set<TermConcept> codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "A");
assertThat(toCodes(codes), containsInAnyOrder("A"));
codes = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "B");
assertThat(toCodes(codes), containsInAnyOrder("B"));
runInTransaction(() -> {
List<TermCodeSystemVersion> termCodeSystemVersions = myTermCodeSystemVersionDao.findAll();
assertEquals(termCodeSystemVersions.size(), 1);
TermCodeSystemVersion termCodeSystemVersion_1 = termCodeSystemVersions.get(0);
assertEquals(termCodeSystemVersion_1.getConcepts().size(), 2);
Set<TermConcept> termConcepts = new HashSet<>(termCodeSystemVersion_1.getConcepts());
assertThat(toCodes(termConcepts), containsInAnyOrder("A", "B"));
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id.getIdPartAsLong());
assertEquals("1", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
});
codeSystem.setVersion("2");
codeSystem.setUrl(CS_URL_2);
IIdType id_v2 = myCodeSystemDao.update(codeSystem, mySrd).getId().toUnqualified();
runInTransaction(() -> {
List<TermCodeSystemVersion> termCodeSystemVersions_updated = myTermCodeSystemVersionDao.findAll();
assertEquals(termCodeSystemVersions_updated.size(), 1);
TermCodeSystemVersion termCodeSystemVersion_2 = termCodeSystemVersions_updated.get(0);
assertEquals(termCodeSystemVersion_2.getConcepts().size(), 2);
Set<TermConcept> termConcepts_updated = new HashSet<>(termCodeSystemVersion_2.getConcepts());
assertThat(toCodes(termConcepts_updated), containsInAnyOrder("A", "B"));
TermCodeSystem termCodeSystem = myTermCodeSystemDao.findByResourcePid(id_v2.getIdPartAsLong());
assertEquals("2", termCodeSystem.getCurrentVersion().getCodeSystemVersionId());
assertEquals(CS_URL_2, termCodeSystem.getCodeSystemUri());
});
}
@Test @Test
public void testUpdateCodeSystemContentModeNotPresent() { public void testUpdateCodeSystemContentModeNotPresent() {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();

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(), anyString(), nullable(String.class), anyCollection());
} }

View File

@ -904,7 +904,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(), anyString(), nullable(String.class), anyCollection());
} }
@Test @Test

View File

@ -141,6 +141,11 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
//EMPI Target Type //EMPI Target Type
empiLink.addColumn("20200727.1","TARGET_TYPE").nullable().type(ColumnTypeEnum.STRING, EmpiLink.TARGET_TYPE_LENGTH); empiLink.addColumn("20200727.1","TARGET_TYPE").nullable().type(ColumnTypeEnum.STRING, EmpiLink.TARGET_TYPE_LENGTH);
//Term CodeSystem Version
Builder.BuilderWithTableName trmCodeSystemVer = version.onTable("TRM_CODESYSTEM_VER");
trmCodeSystemVer.addIndex("20200916.1", "IDX_CODESYSTEM_AND_VER").unique(true).withColumns("CODESYSTEM_PID", "CS_VERSION_ID");
} }
protected void init510_20200725() { protected void init510_20200725() {