diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java index 1f446d1d52f..95499fcb207 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/dstu3/BaseDstu3Config.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.TransactionProcessor; import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3; import ca.uhn.fhir.jpa.provider.GraphQLProvider; -import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3; import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorDstu3; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryDstu3; @@ -21,6 +20,7 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3; import ca.uhn.fhir.validation.IValidatorModule; import org.apache.commons.lang3.time.DateUtils; +import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; import org.hl7.fhir.dstu3.hapi.validation.CachingValidationSupport; import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator; @@ -99,6 +99,11 @@ public class BaseDstu3Config extends BaseConfig { return val; } + @Bean + public DefaultProfileValidationSupport defaultProfileValidationSupport() { + return new DefaultProfileValidationSupport(); + } + @Bean public JpaValidationSupportChainDstu3 jpaValidationSupportChain() { return new JpaValidationSupportChainDstu3(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java index 2bb9f1e81d3..9c5cfd5d17b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/BaseR4Config.java @@ -8,7 +8,7 @@ import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.TransactionProcessor; import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4; -import ca.uhn.fhir.jpa.graphql.JpaStorageServices; +import ca.uhn.fhir.jpa.provider.GraphQLProvider; import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR4; @@ -20,14 +20,12 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4; import ca.uhn.fhir.validation.IValidatorModule; import org.apache.commons.lang3.time.DateUtils; +import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; -import ca.uhn.fhir.jpa.provider.GraphQLProvider; import org.hl7.fhir.r4.hapi.validation.CachingValidationSupport; import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.utils.GraphQLEngine; import org.hl7.fhir.r5.utils.IResourceValidator; -import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -102,6 +100,11 @@ public class BaseR4Config extends BaseConfig { return val; } + @Bean + public DefaultProfileValidationSupport defaultProfileValidationSupport() { + return new DefaultProfileValidationSupport(); + } + @Bean public JpaValidationSupportChainR4 jpaValidationSupportChain() { return new JpaValidationSupportChainR4(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r5/BaseR5Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r5/BaseR5Config.java index 0edd674017f..3bce313f662 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r5/BaseR5Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r5/BaseR5Config.java @@ -20,6 +20,7 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5; import ca.uhn.fhir.validation.IValidatorModule; import org.apache.commons.lang3.time.DateUtils; +import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport; import org.hl7.fhir.r5.hapi.ctx.IValidationSupport; import org.hl7.fhir.r5.hapi.validation.CachingValidationSupport; import org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator; @@ -99,6 +100,11 @@ public class BaseR5Config extends BaseConfig { return val; } + @Bean + public DefaultProfileValidationSupport defaultProfileValidationSupport() { + return new DefaultProfileValidationSupport(); + } + @Bean public JpaValidationSupportChainR5 jpaValidationSupportChain() { return new JpaValidationSupportChainR5(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index 52d6eaf5812..255275ff131 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -112,7 +112,7 @@ import static org.apache.commons.lang3.StringUtils.*; @SuppressWarnings("WeakerAccess") @Repository -public abstract class BaseHapiFhirDao implements IDao, ApplicationContextAware { +public abstract class BaseHapiFhirDao implements IDao, IJpaDao, ApplicationContextAware { public static final long INDEX_STATUS_INDEXED = 1L; public static final long INDEX_STATUS_INDEXING_FAILED = 2L; @@ -1017,7 +1017,8 @@ public abstract class BaseHapiFhirDao implements IDao, } @SuppressWarnings("unchecked") - protected ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable + @Override + public ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { Validate.notNull(theEntity); @@ -1256,6 +1257,7 @@ public abstract class BaseHapiFhirDao implements IDao, return theEntity; } + @Override public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index 32a8f556bb9..1b8c00a7f3e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -149,21 +149,29 @@ public class DaoConfig { private boolean myFilterParameterEnabled = false; private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID; /** - * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}! + * Do not change default of {@code true}! + * + * @since 4.1.0 */ - private boolean myPreExpandValueSetsExperimental = false; + private boolean myPreExpandValueSets = true; /** - * EXPERIMENTAL - Do not use in production! Do not change default of {@code 0}! + * Do not change default of {@code 0}! + * + * @since 4.1.0 */ - private int myPreExpandValueSetsDefaultOffsetExperimental = 0; + private int myPreExpandValueSetsDefaultOffset = 0; /** - * EXPERIMENTAL - Do not use in production! Do not change default of {@code 1000}! + * Do not change default of {@code 1000}! + * + * @since 4.1.0 */ - private int myPreExpandValueSetsDefaultCountExperimental = 1000; + private int myPreExpandValueSetsDefaultCount = 1000; /** - * EXPERIMENTAL - Do not use in production! Do not change default of {@code 1000}! + * Do not change default of {@code 1000}! + * + * @since 4.1.0 */ - private int myPreExpandValueSetsMaxCountExperimental = 1000; + private int myPreExpandValueSetsMaxCount = 1000; /** * Constructor @@ -920,7 +928,7 @@ public class DaoConfig { *

* Default is {@literal true} beginning in HAPI FHIR 2.4, since this * feature is now specified in the FHIR specification. (Previously it - * was an experimental/rpposed feature) + * was an experimental/proposed feature) *

* * @since 1.5 @@ -1621,34 +1629,6 @@ public class DaoConfig { myModelConfig.setWebsocketContextPath(theWebsocketContextPath); } - /** - * EXPERIMENTAL - Do not use in production! - *

- * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate - * future optimization of the $expand operation on large ValueSets. - *

- *

- * The default value for this setting is {@code false}. - *

- */ - public boolean isPreExpandValueSetsExperimental() { - return myPreExpandValueSetsExperimental; - } - - /** - * EXPERIMENTAL - Do not use in production! - *

- * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate - * future optimization of the $expand operation on large ValueSets. - *

- *

- * The default value for this setting is {@code false}. - *

- */ - public void setPreExpandValueSetsExperimental(boolean thePreExpandValueSetsExperimental) { - myPreExpandValueSetsExperimental = thePreExpandValueSetsExperimental; - } - /** * If set to true the _filter search parameter will be enabled on this server. Note that _filter * is very powerful, but also potentially dangerous as it can allow a user to create a query for which there @@ -1720,83 +1700,118 @@ public class DaoConfig { } /** - * EXPERIMENTAL - Do not use in production! + *

+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate + * optimization of the $expand operation on large ValueSets. + *

+ *

+ * The default value for this setting is {@code true}. + *

+ * + * @since 4.1.0 + */ + public boolean isPreExpandValueSets() { + return myPreExpandValueSets; + } + + /** + *

+ * If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate + * optimization of the $expand operation on large ValueSets. + *

+ *

+ * The default value for this setting is {@code true}. + *

+ * + * @since 4.1.0 + */ + public void setPreExpandValueSets(boolean thePreExpandValueSets) { + myPreExpandValueSets = thePreExpandValueSets; + } + + /** *

* This is the default value of {@code offset} parameter for the ValueSet {@code $expand} operation when - * {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}. + * {@link DaoConfig#isPreExpandValueSets()} returns {@code true}. *

*

* The default value for this setting is {@code 0}. *

+ * + * @since 4.1.0 */ - public int getPreExpandValueSetsDefaultOffsetExperimental() { - return myPreExpandValueSetsDefaultOffsetExperimental; + public int getPreExpandValueSetsDefaultOffset() { + return myPreExpandValueSetsDefaultOffset; } /** - * EXPERIMENTAL - Do not use in production! *

* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when - * {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}. + * {@link DaoConfig#isPreExpandValueSets()} returns {@code true}. *

*

* The default value for this setting is {@code 1000}. *

+ * + * @since 4.1.0 */ - public int getPreExpandValueSetsDefaultCountExperimental() { - return myPreExpandValueSetsDefaultCountExperimental; + public int getPreExpandValueSetsDefaultCount() { + return myPreExpandValueSetsDefaultCount; } /** - * EXPERIMENTAL - Do not use in production! *

* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when - * {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}. + * {@link DaoConfig#isPreExpandValueSets()} returns {@code true}. *

*

- * If {@code thePreExpandValueSetsDefaultCountExperimental} is greater than - * {@link DaoConfig#getPreExpandValueSetsMaxCountExperimental()}, the lesser value is used. + * If {@code thePreExpandValueSetsDefaultCount} is greater than + * {@link DaoConfig#getPreExpandValueSetsMaxCount()}, the lesser value is used. *

*

* The default value for this setting is {@code 1000}. *

+ * + * @since 4.1.0 */ - public void setPreExpandValueSetsDefaultCountExperimental(int thePreExpandValueSetsDefaultCountExperimental) { - myPreExpandValueSetsDefaultCountExperimental = Math.min(thePreExpandValueSetsDefaultCountExperimental, getPreExpandValueSetsMaxCountExperimental()); + public void setPreExpandValueSetsDefaultCount(int thePreExpandValueSetsDefaultCount) { + myPreExpandValueSetsDefaultCount = Math.min(thePreExpandValueSetsDefaultCount, getPreExpandValueSetsMaxCount()); } /** - * EXPERIMENTAL - Do not use in production! *

* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when - * {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}. + * {@link DaoConfig#isPreExpandValueSets()} returns {@code true}. *

*

* The default value for this setting is {@code 1000}. *

+ * + * @since 4.1.0 */ - public int getPreExpandValueSetsMaxCountExperimental() { - return myPreExpandValueSetsMaxCountExperimental; + public int getPreExpandValueSetsMaxCount() { + return myPreExpandValueSetsMaxCount; } /** - * EXPERIMENTAL - Do not use in production! *

* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when - * {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}. + * {@link DaoConfig#isPreExpandValueSets()} returns {@code true}. *

*

- * If {@code thePreExpandValueSetsMaxCountExperimental} is lesser than - * {@link DaoConfig#getPreExpandValueSetsDefaultCountExperimental()}, the default {@code count} is lowered to the + * If {@code thePreExpandValueSetsMaxCount} is lesser than + * {@link DaoConfig#getPreExpandValueSetsDefaultCount()}, the default {@code count} is lowered to the * new max {@code count}. *

*

* The default value for this setting is {@code 1000}. *

+ * + * @since 4.1.0 */ - public void setPreExpandValueSetsMaxCountExperimental(int thePreExpandValueSetsMaxCountExperimental) { - myPreExpandValueSetsMaxCountExperimental = thePreExpandValueSetsMaxCountExperimental; - setPreExpandValueSetsDefaultCountExperimental(Math.min(getPreExpandValueSetsDefaultCountExperimental(), getPreExpandValueSetsMaxCountExperimental())); + public void setPreExpandValueSetsMaxCount(int thePreExpandValueSetsMaxCount) { + myPreExpandValueSetsMaxCount = thePreExpandValueSetsMaxCount; + setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount())); } public enum IndexEnabledEnum { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java index 6ce3e00419a..ddf27ce58e8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java @@ -73,8 +73,8 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2 { + @SuppressWarnings("unchecked") + ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable + theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry); + + ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, + ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource); +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/TransactionProcessor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/TransactionProcessor.java index 5dcdd2e90eb..c0a5274fe8c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/TransactionProcessor.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/TransactionProcessor.java @@ -909,10 +909,13 @@ public class TransactionProcessor { IPrimitiveType deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource); Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null; + IFhirResourceDao dao = myDaoRegistry.getResourceDao(nextResource.getClass()); + IJpaDao jpaDao = (IJpaDao) dao; + if (updatedEntities.contains(nextOutcome.getEntity())) { - myDao.updateInternal(theRequest, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource()); + jpaDao.updateInternal(theRequest, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource()); } else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) { - myDao.updateEntity(theRequest, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true); + jpaDao.updateEntity(theRequest, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java index b8acd0d8f0d..6759858c732 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCodeSystemDstu3.java @@ -125,8 +125,8 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3 @Autowired private IHapiTerminologySvc myHapiTerminologySvc; + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; + @Autowired @Qualifier("myJpaValidationSupportChainDstu3") private IValidationSupport myValidationSupport; + @Autowired private IFhirResourceDaoCodeSystem myCodeSystemDao; @@ -310,12 +315,18 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false; ValueSet vs = null; + boolean isBuiltInValueSet = false; if (theId != null) { vs = read(theId, theRequestDetails); } else if (haveIdentifierParam) { - vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue()); + vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); if (vs == null) { - throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); + if (vs == null) { + throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + } + } else { + isBuiltInValueSet = true; } } else { if (theCode == null || theCode.isEmpty()) { @@ -332,7 +343,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { + if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); @@ -395,11 +406,11 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 } @Override - protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (retVal.getDeleted() == null) { try { ValueSet valueSet = (ValueSet) theResource; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoCodeSystemR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoCodeSystemR4.java index 7fc850e4a8b..bc9768ca162 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoCodeSystemR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoCodeSystemR4.java @@ -128,8 +128,8 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4 i } @Override - protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); CodeSystem cs = (CodeSystem) theResource; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoConceptMapR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoConceptMapR4.java index baedded13f4..b553e42baa6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoConceptMapR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoConceptMapR4.java @@ -158,8 +158,8 @@ public class FhirResourceDaoConceptMapR4 extends FhirResourceDaoR4 i } @Override - protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); if (retVal.getDeleted() == null) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSubscriptionR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSubscriptionR4.java index 1455ef2191d..286e456dc76 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSubscriptionR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoSubscriptionR4.java @@ -75,8 +75,8 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4 imple @Autowired private IHapiTerminologySvc myHapiTerminologySvc; + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; + @Autowired @Qualifier("myJpaValidationSupportChainR4") private IValidationSupport myValidationSupport; @@ -306,12 +310,18 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple boolean haveIdentifierParam = theValueSetIdentifier != null && !theValueSetIdentifier.isEmpty(); ValueSet vs = null; + boolean isBuiltInValueSet = false; if (theId != null) { vs = read(theId, theRequestDetails); } else if (haveIdentifierParam) { - vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue()); + vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); if (vs == null) { - throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); + if (vs == null) { + throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + } + } else { + isBuiltInValueSet = true; } } else { if (theCode == null || theCode.isEmpty()) { @@ -328,7 +338,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { + if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); @@ -391,11 +401,11 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple } @Override - protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (retVal.getDeleted() == null) { ValueSet valueSet = (ValueSet) theResource; myHapiTerminologySvc.storeTermValueSet(retVal, valueSet); @@ -407,4 +417,5 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple return retVal; } + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoCodeSystemR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoCodeSystemR5.java index bb8d651839f..515355bc044 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoCodeSystemR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoCodeSystemR5.java @@ -128,8 +128,8 @@ public class FhirResourceDaoCodeSystemR5 extends FhirResourceDaoR5 i } @Override - protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); CodeSystem cs = (CodeSystem) theResource; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoConceptMapR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoConceptMapR5.java index 467dae02d64..dab3f9c764d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoConceptMapR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoConceptMapR5.java @@ -157,7 +157,7 @@ public class FhirResourceDaoConceptMapR5 extends FhirResourceDaoR5 i } @Override - protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoSubscriptionR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoSubscriptionR5.java index 535e6a49d35..da052fbba12 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoSubscriptionR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoSubscriptionR5.java @@ -73,8 +73,8 @@ public class FhirResourceDaoSubscriptionR5 extends FhirResourceDaoR5 imple @Autowired private IHapiTerminologySvc myHapiTerminologySvc; + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; + @Autowired @Qualifier("myJpaValidationSupportChainR5") private IValidationSupport myValidationSupport; @@ -312,12 +316,18 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5 imple boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false; ValueSet vs = null; + boolean isBuiltInValueSet = false; if (theId != null) { vs = read(theId, theRequestDetails); } else if (haveIdentifierParam) { - vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue()); + vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); if (vs == null) { - throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue()); + if (vs == null) { + throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue()); + } + } else { + isBuiltInValueSet = true; } } else { if (theCode == null || theCode.isEmpty()) { @@ -334,7 +344,7 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5 imple if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { + if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); @@ -397,11 +407,11 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5 imple } @Override - protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, - boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, + boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (retVal.getDeleted() == null) { ValueSet valueSet = (ValueSet) theResource; myHapiTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet)); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderValueSetDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderValueSetDstu3.java index 884941f053c..0d28d7ecf73 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderValueSetDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderValueSetDstu3.java @@ -68,7 +68,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options."); } - int offset = myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(); + int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset(); if (theOffset != null && theOffset.hasValue()) { if (theOffset.getValue() >= 0) { offset = theOffset.getValue(); @@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst } } - int count = myDaoConfig.getPreExpandValueSetsDefaultCountExperimental(); + int count = myDaoConfig.getPreExpandValueSetsDefaultCount(); if (theCount != null && theCount.hasValue()) { if (theCount.getValue() >= 0) { count = theCount.getValue(); @@ -85,7 +85,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue()); } } - int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental(); + int countMax = myDaoConfig.getPreExpandValueSetsMaxCount(); if (count > countMax) { ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax); count = countMax; @@ -94,7 +94,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst startRequest(theServletRequest); try { IFhirResourceDaoValueSet dao = (IFhirResourceDaoValueSet) getDao(); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (haveId) { return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderValueSetR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderValueSetR4.java index 5828b3f1356..f7f9f8c2a33 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderValueSetR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderValueSetR4.java @@ -60,7 +60,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4= 0) { offset = theOffset.getValue(); @@ -69,7 +69,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4= 0) { count = theCount.getValue(); @@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4= 0 when specified. count: " + theCount.getValue()); } } - int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental(); + int countMax = myDaoConfig.getPreExpandValueSetsMaxCount(); if (count > countMax) { ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax); count = countMax; @@ -86,7 +86,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4 dao = (IFhirResourceDaoValueSet) getDao(); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (haveId) { return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderValueSetR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderValueSetR5.java index f05a8f4cdaa..6ef5a0fd6ae 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderValueSetR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderValueSetR5.java @@ -60,7 +60,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5= 0) { offset = theOffset.getValue(); @@ -69,7 +69,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5= 0) { count = theCount.getValue(); @@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5= 0 when specified. count: " + theCount.getValue()); } } - int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental(); + int countMax = myDaoConfig.getPreExpandValueSetsMaxCount(); if (count > countMax) { ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax); count = countMax; @@ -86,7 +86,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5 dao = (IFhirResourceDaoValueSet) getDao(); - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSets()) { if (haveId) { return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails); } else if (haveIdentifier) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index d66593320bc..d4b8e0f40e9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java @@ -63,9 +63,9 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.r4.model.*; +import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; import org.quartz.Job; import org.quartz.JobExecutionContext; -import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -204,22 +204,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } - private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { - bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery()); - } - - private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { - Query textQuery = qb - .phrase() - .withSlop(2) - .onField("myDisplay").boostedTo(4.0f) - .andField("myDisplayEdgeNGram").boostedTo(2.0f) - // .andField("myDisplayNGram").boostedTo(1.0f) - // .andField("myDisplayPhonetic").boostedTo(0.5f) - .sentence(nextFilter.getValue().toLowerCase()).createQuery(); - bool.must(textQuery); - } - private boolean addToSet(Set theSetToPopulate, TermConcept theConcept) { boolean retVal = theSetToPopulate.add(theConcept); if (retVal) { @@ -888,18 +872,20 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, break; case "parent": case "child": - if (isCodeSystemLoinc(theSystem)) { - handleFilterLoincParentChild(theQb, theBool, theFilter); - } else { - throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem); - } + isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); + handleFilterLoincParentChild(theQb, theBool, theFilter); + break; + case "ancestor": + isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); + handleFilterLoincAncestor(theSystem, theQb, theBool, theFilter); + break; + case "descendant": + isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); + handleFilterLoincDescendant(theSystem, theQb, theBool, theFilter); break; case "copyright": - if (isCodeSystemLoinc(theSystem)) { - handleFilterLoincCopyright(theQb, theBool, theFilter); - } else { - throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem); - } + isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty()); + handleFilterLoincCopyright(theQb, theBool, theFilter); break; default: handleFilterRegex(theBool, theFilter); @@ -907,6 +893,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } + private boolean isCodeSystemLoingOrThrowInvalidRequestException(String theSystem, String theProperty) { + if (!isCodeSystemLoinc(theSystem)) { + throw new InvalidRequestException("Invalid filter, property " + theProperty + " is LOINC-specific and cannot be used with system: " + theSystem); + } + return true; + } + private boolean isCodeSystemLoinc(String theSystem) { return IHapiTerminologyLoaderSvc.LOINC_URI.equals(theSystem); } @@ -923,6 +916,22 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } + private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { + bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery()); + } + + private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction bool, ValueSet.ConceptSetFilterComponent nextFilter) { + Query textQuery = qb + .phrase() + .withSlop(2) + .onField("myDisplay").boostedTo(4.0f) + .andField("myDisplayEdgeNGram").boostedTo(2.0f) + // .andField("myDisplayNGram").boostedTo(1.0f) + // .andField("myDisplayPhonetic").boostedTo(0.5f) + .sentence(nextFilter.getValue().toLowerCase()).createQuery(); + bool.must(textQuery); + } + private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { TermConcept code = findCode(theSystem, theFilter.getValue()) .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue())); @@ -936,12 +945,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } private void handleFilterLoincParentChild(QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { - if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) { - addLoincFilterParentChildEqual(theBool, theFilter.getProperty(), theFilter.getValue()); - } else if (theFilter.getOp() == ValueSet.FilterOperator.IN) { - addLoincFilterParentChildIn(theBool, theFilter); - } else { - throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); + switch (theFilter.getOp()) { + case EQUAL: + addLoincFilterParentChildEqual(theBool, theFilter.getProperty(), theFilter.getValue()); + break; + case IN: + addLoincFilterParentChildIn(theBool, theFilter); + break; + default: + throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); } } @@ -964,6 +976,83 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, return new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theProperty, theValue); } + private void handleFilterLoincAncestor(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + switch (theFilter.getOp()) { + case EQUAL: + addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter); + break; + case IN: + addLoincFilterAncestorIn(theSystem, theQb, theBool, theFilter); + break; + default: + throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); + } + } + + private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + TermConcept code = findCode(theSystem, theFilter.getValue()) + .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue())); + + logFilteringValueOnProperty(theFilter.getValue(), theFilter.getProperty()); + theBool.must(theQb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery()); + } + + private void addLoincFilterAncestorIn(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + throw new UnsupportedOperationException(); + // FIXME: DM 2019-09-25 - Filter with op=IN on ancestor; see #1512 in GitHub. + // FIXME: DM 2019-09-26 - Once implemented, fix changelog entry for #1454 in changes.xml +// String[] values = theFilter.getValue().split(","); +// for (String value : values) { +// logFilteringValueOnProperty(value, theFilter.getProperty()); +// } + } + + private void handleFilterLoincDescendant(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + switch (theFilter.getOp()) { + case EQUAL: + addLoincFilterDescendantEqual(theSystem, theBool, theFilter); + break; + case IN: + addLoincFilterDescendantIn(theSystem, theQb, theBool, theFilter); + break; + default: + 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) { + addLoincFilterDescendantEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue()); + } + + private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction theBool, String theProperty, String theValue) { + List terms = getDescendantTerms(theSystem, theProperty, theValue); + theBool.must(new TermsQuery(terms)); + } + + private void addLoincFilterDescendantIn(String theSystem, QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { + String[] values = theFilter.getValue().split(","); + List terms = new ArrayList<>(); + for (String value : values) { + terms.addAll(getDescendantTerms(theSystem, theFilter.getProperty(), value)); + } + theBool.must(new TermsQuery(terms)); + } + + private List getDescendantTerms(String theSystem, String theProperty, String theValue) { + List retVal = new ArrayList<>(); + + TermConcept code = findCode(theSystem, theValue) + .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theValue)); + + String[] parentPids = code.getParentPidsAsString().split(" "); + for (String parentPid : parentPids) { + retVal.add(new Term("myId", parentPid)); + } + logFilteringValueOnProperty(theValue, theProperty); + + return retVal; + } + private void handleFilterLoincCopyright(QueryBuilder theQb, BooleanJunction theBool, ValueSet.ConceptSetFilterComponent theFilter) { if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) { @@ -1870,7 +1959,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override @Transactional public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) { - ourLog.info("Storing TermConceptMap {}", theConceptMap.getIdElement().getValue()); + ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url"); @@ -1981,7 +2070,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, throw new UnprocessableEntityException(msg); } - ourLog.info("Done storing TermConceptMap[{}]", termConceptMap.getId()); + ourLog.info("Done storing TermConceptMap[{}] for {}", termConceptMap.getId(), theConceptMap.getIdElement().toVersionless().getValueAsString()); } @Override @@ -2077,7 +2166,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override @Transactional public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) { - ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue()); + ourLog.info("Storing TermValueSet for {}", theValueSet.getIdElement().toVersionless().getValueAsString()); ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url"); @@ -2111,7 +2200,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, throw new UnprocessableEntityException(msg); } - ourLog.info("Done storing TermValueSet[{}]", termValueSet.getId()); + ourLog.info("Done storing TermValueSet[{}] for {}", termValueSet.getId(), theValueSet.getIdElement().toVersionless().getValueAsString()); } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java index 4ccaaf9391b..57898fdc4f9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/loinc/LoincPartRelatedCodeMappingHandler.java @@ -42,8 +42,8 @@ public class LoincPartRelatedCodeMappingHandler extends BaseLoincHandler impleme public static final String LOINC_SCT_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct"; private static final String LOINC_SCT_PART_MAP_NAME = "LOINC Part Map to SNOMED CT"; - public static final String LOINC_TERM_TO_RPID_PART_MAP_ID = "loinc-term-to-rpids"; - public static final String LOINC_TERM_TO_RPID_PART_MAP_URI = "http://loinc.org/cm/loinc-term-to-rpids"; + public static final String LOINC_TERM_TO_RPID_PART_MAP_ID = "loinc-to-rpids"; + public static final String LOINC_TERM_TO_RPID_PART_MAP_URI = "http://loinc.org/cm/loinc-to-rpids"; public static final String LOINC_TERM_TO_RPID_PART_MAP_NAME = "LOINC Terms to RadLex RPIDs"; public static final String LOINC_PART_TO_RID_PART_MAP_ID = "loinc-part-to-rids"; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainDstu3.java index 27f8239d779..312841e0f26 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainDstu3.java @@ -38,7 +38,8 @@ public class JpaValidationSupportChainDstu3 extends ValidationSupportChain { @Autowired @Qualifier("myJpaValidationSupportDstu3") public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 myJpaValidationSupportDstu3; - private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport(); + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; @Autowired private IHapiTerminologySvcDstu3 myTerminologyService; @Autowired diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR4.java index d92babe1fd6..710650ac6b1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR4.java @@ -20,10 +20,8 @@ package ca.uhn.fhir.jpa.validation; * #L% */ -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; import org.hl7.fhir.r4.hapi.validation.SnapshotGeneratingValidationSupport; @@ -32,11 +30,13 @@ import org.hl7.fhir.r4.model.StructureDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; public class JpaValidationSupportChainR4 extends ValidationSupportChain { - private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport(); + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; @Autowired private FhirContext myFhirContext; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR5.java index 5e7ad25d99f..8101855809a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChainR5.java @@ -35,7 +35,8 @@ import javax.annotation.PreDestroy; public class JpaValidationSupportChainR5 extends ValidationSupportChain { - private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport(); + @Autowired + private DefaultProfileValidationSupport myDefaultProfileValidationSupport; @Autowired private FhirContext myFhirContext; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java index 441de7433ee..45b9d107d25 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchNoFtTest.java @@ -537,6 +537,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { @Test public void testIndexNoDuplicatesUri() { ValueSet res = new ValueSet(); + res.setUrl("http://www.example.org/vs"); res.getCompose().addInclude().setSystem("http://foo"); res.getCompose().addInclude().setSystem("http://bar"); res.getCompose().addInclude().setSystem("http://foo"); @@ -549,7 +550,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { Class type = ResourceIndexedSearchParamUri.class; List results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList(); ourLog.info(toStringMultiline(results)); - assertEquals(2, results.size()); + assertEquals(3, results.size()); List actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo")))); assertThat(actual, contains(id)); @@ -2161,13 +2162,14 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test { } @Test - public void testSearchUriWrongParam() throws Exception { + public void testSearchUriWrongParam() { ValueSet v1 = new ValueSet(); v1.getUrlElement().setValue("http://foo"); String id1 = myValueSetDao.create(v1).getId().toUnqualifiedVersionless().getValue(); ValueSet v2 = new ValueSet(); v2.getExpansion().getIdentifierElement().setValue("http://foo"); + v2.getUrlElement().setValue("http://www.example.org/vs"); String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue(); { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValueSetTest.java index a3c2e1dec11..0180911b8b2 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValueSetTest.java @@ -229,7 +229,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test { } @Test - public void testValiedateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() { + public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() { IPrimitiveType display = null; Coding coding = null; CodeableConcept codeableConcept = null; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java index 11f460d3154..9ed8b44ff27 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoFtTest.java @@ -914,6 +914,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { @Test public void testIndexNoDuplicatesUri() { ValueSet res = new ValueSet(); + res.setUrl("http://www.example.org/vs"); res.getCompose().addInclude().setSystem("http://foo"); res.getCompose().addInclude().setSystem("http://bar"); res.getCompose().addInclude().setSystem("http://foo"); @@ -927,7 +928,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { Class type = ResourceIndexedSearchParamUri.class; List results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList(); ourLog.info(toStringMultiline(results)); - assertEquals(2, results.size()); + assertEquals(3, results.size()); }); List actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo")))); @@ -2951,6 +2952,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test { ValueSet v2 = new ValueSet(); v2.getExpansion().getIdentifierElement().setValue("http://foo"); + v2.getUrlElement().setValue("http://www.example.org/vs"); String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue(); { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoHashesTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoHashesTest.java index d38c66269b5..638c19de59e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoHashesTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchNoHashesTest.java @@ -772,6 +772,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test { @Test public void testIndexNoDuplicatesUri() { ValueSet res = new ValueSet(); + res.setUrl("http://www.example.org/vs"); res.getCompose().addInclude().setSystem("http://foo"); res.getCompose().addInclude().setSystem("http://bar"); res.getCompose().addInclude().setSystem("http://foo"); @@ -785,7 +786,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test { Class type = ResourceIndexedSearchParamUri.class; List results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList(); ourLog.info(toStringMultiline(results)); - assertEquals(2, results.size()); + assertEquals(3, results.size()); }); List actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo")))); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java index 10c0949f03d..0f1baea4010 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValueSetTest.java @@ -22,7 +22,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { @After public void after() { - myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); + myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets()); } @AfterClass @@ -128,7 +128,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { @Test public void testValidateCodeOperationByResourceIdAndCodeableConceptWithExistingValueSetAndPreExpansionEnabled() { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); UriType valueSetIdentifier = null; IIdType id = myExtensionalVsId; @@ -169,7 +169,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { @Test public void testValidateCodeOperationByResourceIdAndCodeAndSystemWithExistingValueSetAndPreExpansionEnabled() { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); UriType valueSetIdentifier = null; IIdType id = myExtensionalVsId; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetTest.java index 43a56659ca6..4adc61472fb 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetTest.java @@ -140,7 +140,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 createLocalVsWithUnknownCode(codeSystem); } - private void createLocalCsAndVs() { + private void createLocalCs() { CodeSystem codeSystem = new CodeSystem(); codeSystem.setUrl(URL_MY_CODE_SYSTEM); codeSystem.setContent(CodeSystemContentMode.COMPLETE); @@ -155,8 +155,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 .addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA")) .addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB")); myCodeSystemDao.create(codeSystem, mySrd); - - createLocalVs(codeSystem); } @@ -242,6 +240,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 // Include vs = new ValueSet(); + vs.setUrl("http://www.example.org/vs"); vs.getCompose() .addInclude() .setSystem(CS_URL); @@ -282,6 +281,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 // Include vs = new ValueSet(); + vs.setUrl("http://www.example.org/vs"); vs.getCompose() .addInclude() .setSystem(CS_URL); @@ -329,7 +329,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 @Test public void testExpandByIdWithPreExpansion() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -445,7 +445,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 @Test public void testExpandByUrlWithPreExpansion() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -468,7 +468,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 @Test public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -746,7 +746,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException { loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); - createLocalCsAndVs(); + createLocalCs(); createLocalVsWithIncludeConcept(); String url = ourServerBase + @@ -789,7 +789,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 * Technically this is the wrong param name */ @Test - public void testValiedateCodeAgainstBuiltInSystem() throws Exception { + public void testValidateCodeAgainstBuiltInSystem() throws Exception { loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); Parameters respParam = ourClient @@ -819,7 +819,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 * Technically this is the right param name */ @Test - public void testValiedateCodeAgainstBuiltInSystemByUrl() throws Exception { + public void testValidateCodeAgainstBuiltInSystemByUrl() throws Exception { loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); Parameters respParam = ourClient @@ -847,7 +847,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3 @After public void afterResetPreExpansionDefault() { - myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); + myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets()); } @AfterClass diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java index 2dddbe66a89..b569dd546e3 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java @@ -70,6 +70,7 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; +import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast; import static ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.hamcrest.Matchers.*; @@ -846,7 +847,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } @Override - public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stu + public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stub } }); @@ -3900,10 +3901,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute(); - /* - * First, make sure that we don't reuse a search if - * it's not marked with an expiry - */ + { myDaoConfig.setReuseCachedSearchResultsForMillis(10L); Bundle result1 = ourClient @@ -3912,7 +3910,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { .returnBundle(Bundle.class) .execute(); final String uuid1 = toSearchUuidFromLinkNext(result1); - sleepOneClick(); + sleepAtLeast(11L); Bundle result2 = ourClient .search() .forResource("Organization") @@ -3922,10 +3920,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { assertNotEquals(uuid1, uuid2); } - /* - * Now try one but mark it with an expiry time - * in the future - */ { myDaoConfig.setReuseCachedSearchResultsForMillis(1000L); Bundle result1 = ourClient @@ -3946,7 +3940,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { .returnBundle(Bundle.class) .execute(); - // Expiry doesn't affect reusablility final String uuid2 = toSearchUuidFromLinkNext(result2); assertEquals(uuid1, uuid2); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java index 967eac53868..038b06e4a15 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java @@ -3,8 +3,7 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; -import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; -import ca.uhn.fhir.jpa.entity.TermConcept; +import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; @@ -36,6 +35,7 @@ import org.springframework.transaction.support.TransactionTemplate; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Optional; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET; @@ -57,12 +57,28 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { loadAndPersistValueSet(theVerb); } + private void loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSet(theVerb); + } + + private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSetWithExclude(theVerb); + } + private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException { CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); codeSystem.setId("CodeSystem/cs"); persistCodeSystem(codeSystem, theVerb); } + private void loadAndPersistCodeSystemWithDesignations(HttpVerb theVerb) throws IOException { + CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs-with-designations.xml"); + codeSystem.setId("CodeSystem/cs"); + persistCodeSystem(codeSystem, theVerb); + } + private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) { switch (theVerb) { case POST: @@ -93,6 +109,12 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { persistValueSet(valueSet, theVerb); } + private void loadAndPersistValueSetWithExclude(HttpVerb theVerb) throws IOException { + ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml"); + valueSet.setId("ValueSet/vs"); + persistValueSet(valueSet, theVerb); + } + private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) { switch (theVerb) { case POST: @@ -222,7 +244,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @Test public void testExpandByIdWithPreExpansion() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -274,7 +296,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @Test public void testExpandByIdWithFilterWithPreExpansion() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -333,7 +355,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @Test public void testExpandByUrlWithPreExpansion() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -356,7 +378,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @Test public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -398,7 +420,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @Test public void testExpandByValueSetWithPreExpansion() throws IOException { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystem(HttpVerb.POST); myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); @@ -687,6 +709,168 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { } } + @Test + public void testUpdateValueSetTriggersAnotherPreExpansion() throws Exception { + myDaoConfig.setPreExpandValueSets(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); + + CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); + ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + String initialValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(initialValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem); + + ValueSet updatedValueSet = valueSet; + updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED")); + persistValueSet(updatedValueSet, HttpVerb.PUT); + updatedValueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet)); + + String updatedValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(updatedValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem); + } + + @Test + public void testUpdateValueSetTriggersAnotherPreExpansionUsingTransactionBundle() throws Exception { + myDaoConfig.setPreExpandValueSets(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); + + CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); + ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + String initialValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(initialValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem); + + ValueSet updatedValueSet = valueSet; + updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED")); + + String url = ourClient.getServerBase().concat("/").concat(myExtensionalVsId.getValueAsString()); + Bundle bundle = new Bundle(); + bundle.setType(Bundle.BundleType.TRANSACTION); + bundle + .addEntry() + .setFullUrl(url) + .setResource(updatedValueSet) + .getRequest() + .setMethod(Bundle.HTTPVerb.PUT) + .setUrl(url); + ourLog.info("Transaction Bundle:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + ourClient.transaction().withBundle(bundle).execute(); + + updatedValueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet)); + + String updatedValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(updatedValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem); + } + + private void validateTermValueSetNotExpanded(String theValueSetName) { + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); + assertTrue(optionalValueSetByResourcePid.isPresent()); + + Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); + assertTrue(optionalValueSetByUrl.isPresent()); + + TermValueSet termValueSet = optionalValueSetByUrl.get(); + assertSame(optionalValueSetByResourcePid.get(), termValueSet); + ourLog.info("ValueSet:\n" + termValueSet.toString()); + assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl()); + assertEquals(theValueSetName, termValueSet.getName()); + assertEquals(0, termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); + }); + } + + private void validateTermValueSetExpandedAndChildren(String theValueSetName, CodeSystem theCodeSystem) { + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); + assertTrue(optionalValueSetByResourcePid.isPresent()); + + Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); + assertTrue(optionalValueSetByUrl.isPresent()); + + TermValueSet termValueSet = optionalValueSetByUrl.get(); + assertSame(optionalValueSetByResourcePid.get(), termValueSet); + ourLog.info("ValueSet:\n" + termValueSet.toString()); + assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl()); + assertEquals(theValueSetName, termValueSet.getName()); + assertEquals(theCodeSystem.getConcept().size(), termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); + + TermValueSetConcept concept = termValueSet.getConcepts().get(0); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8450-9", concept.getCode()); + assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); + assertEquals(2, concept.getDesignations().size()); + assertEquals(0, concept.getOrder()); + + TermValueSetConceptDesignation designation = concept.getDesignations().get(0); + assertEquals("nl", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designation.getValue()); + + designation = concept.getDesignations().get(1); + assertEquals("sv", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); + + concept = termValueSet.getConcepts().get(1); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("11378-7", concept.getCode()); + assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + assertEquals(1, concept.getOrder()); + + // ... + + concept = termValueSet.getConcepts().get(22); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8491-3", concept.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); + assertEquals(1, concept.getDesignations().size()); + assertEquals(22, concept.getOrder()); + + designation = concept.getDesignations().get(0); + assertEquals("nl", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); + + concept = termValueSet.getConcepts().get(23); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8492-1", concept.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + assertEquals(23, concept.getOrder()); + }); + } + @Test public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception { loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); @@ -767,7 +951,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { } @Test - public void testValiedateCodeAgainstBuiltInSystem() { + public void testValidateCodeAgainstBuiltInSystem() { Parameters respParam = ourClient .operation() .onType(ValueSet.class) @@ -839,7 +1023,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { @After public void afterResetPreExpansionDefault() { - myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); + myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets()); } @AfterClass diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java index 3dd95a3e799..e2153aa4e63 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplDstu3Test.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermConcept; +import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; @@ -17,9 +18,8 @@ import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.ValueSet; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Test; +import org.junit.*; +import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.TransactionStatus; @@ -38,6 +38,9 @@ import static org.junit.Assert.*; public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplDstu3Test.class); + @Rule + public final ExpectedException expectedException = ExpectedException.none(); + private static final String CS_URL = "http://example.com/my_code_system"; private static final String CS_URL_2 = "http://example.com/my_code_system2"; @@ -145,6 +148,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { LOINC_URI, code2.getCode(), code2.getDisplay()); + code1.addChild(code2, TermConceptParentChildLink.RelationshipTypeEnum.ISA); cs.getConcepts().add(code1); code2.addPropertyString("SYSTEM", "Ser"); @@ -159,11 +163,13 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { LOINC_URI, code3.getCode(), code3.getDisplay()); + code2.addChild(code3, TermConceptParentChildLink.RelationshipTypeEnum.ISA); code2.addPropertyCoding( "child", LOINC_URI, code4.getCode(), code4.getDisplay()); + code2.addChild(code4, TermConceptParentChildLink.RelationshipTypeEnum.ISA); cs.getConcepts().add(code2); code3.addPropertyString("SYSTEM", "Ser"); @@ -306,7 +312,6 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { outcome = myTermSvc.expandValueSet(vs); codes = toCodesContains(outcome.getExpansion().getContains()); assertThat(codes, empty()); - } @Test @@ -485,12 +490,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("copyright") .setOp(ValueSet.FilterOperator.ISA) .setValue("LOINC"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Don't know how to handle op=ISA on property copyright", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle op=ISA on property copyright"); + myTermSvc.expandValueSet(vs); } @Test @@ -504,18 +507,16 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { // Include vs = new ValueSet(); include = vs.getCompose().addInclude(); - include.setSystem(LOINC_URI); + include.setSystem(CS_URL); include .addFilter() .setProperty("copyright") .setOp(ValueSet.FilterOperator.EQUAL) .setValue("LOINC"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Invalid filter, property copyright is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Invalid filter, property copyright is LOINC-specific and cannot be used with system: http://example.com/my_code_system"); + myTermSvc.expandValueSet(vs); } @Test @@ -534,12 +535,245 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("copyright") .setOp(ValueSet.FilterOperator.EQUAL) .setValue("bogus"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Don't know how to handle value=bogus on property copyright", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle value=bogus on property copyright"); + myTermSvc.expandValueSet(vs); + } + + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithExcludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent exclude; + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-3"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-4"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9")); + } + + @Ignore("Not yet implemented; see #1512 in GitHub.") + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithExcludeAndIn() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent exclude; + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.IN) + .setValue("50015-7,43343-3,43343-4,47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithIncludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-3"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-4"); + outcome = myTermSvc.expandValueSet(vs); + assertEquals(0, outcome.getExpansion().getContains().size()); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("47239-9"); + outcome = myTermSvc.expandValueSet(vs); + assertEquals(0, outcome.getExpansion().getContains().size()); + } + + @Ignore("Not yet implemented; see #1512 in GitHub.") + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithIncludeAndIn() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.IN) + .setValue("50015-7,43343-3,43343-4,47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithUnsupportedOp() { + createLoincSystemWithSomeCodes(); + + ValueSet vs; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.ISA) + .setValue("50015-7"); + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle op=ISA on property ancestor"); + myTermSvc.expandValueSet(vs); + } + + @Test + public void testExpandValueSetPropertyFilterLoincAncestorWithUnsupportedSystem() { + createCodeSystem(); + createLoincSystemWithSomeCodes(); + + ValueSet vs; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(CS_URL); + include + .addFilter() + .setProperty("ancestor") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Invalid filter, property ancestor is LOINC-specific and cannot be used with system: http://example.com/my_code_system"); + myTermSvc.expandValueSet(vs); } @Test @@ -747,12 +981,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("child") .setOp(ValueSet.FilterOperator.ISA) .setValue("50015-7"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Don't know how to handle op=ISA on property child", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle op=ISA on property child"); + myTermSvc.expandValueSet(vs); } @Test @@ -772,12 +1004,244 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("child") .setOp(ValueSet.FilterOperator.EQUAL) .setValue("50015-7"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Invalid filter, property child is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Invalid filter, property child is LOINC-specific and cannot be used with system: http://example.com/my_code_system"); + myTermSvc.expandValueSet(vs); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithExcludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent exclude; + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-3"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-4"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-4", "47239-9")); + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-4", "47239-9")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithExcludeAndIn() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent exclude; + + // Include + vs = new ValueSet(); + vs.getCompose() + .addInclude() + .setSystem(LOINC_URI); + // Exclude + exclude = vs.getCompose().addExclude(); + exclude.setSystem(LOINC_URI); + exclude + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.IN) + .setValue("50015-7,43343-3,43343-4,47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("43343-4", "47239-9")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithIncludeAndEqual() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + outcome = myTermSvc.expandValueSet(vs); + assertEquals(0, outcome.getExpansion().getContains().size()); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-3"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7")); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("43343-4"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3")); + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithIncludeAndIn() { + createLoincSystemWithSomeCodes(); + + List codes; + ValueSet vs; + ValueSet outcome; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.IN) + .setValue("50015-7,43343-3,43343-4,47239-9"); + outcome = myTermSvc.expandValueSet(vs); + codes = toCodesContains(outcome.getExpansion().getContains()); + assertThat(codes, containsInAnyOrder("50015-7", "43343-3")); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithUnsupportedOp() { + createLoincSystemWithSomeCodes(); + + ValueSet vs; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(LOINC_URI); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.ISA) + .setValue("50015-7"); + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle op=ISA on property descendant"); + myTermSvc.expandValueSet(vs); + } + + @Test + public void testExpandValueSetPropertyFilterLoincDescendantWithUnsupportedSystem() { + createCodeSystem(); + createLoincSystemWithSomeCodes(); + + ValueSet vs; + ValueSet.ConceptSetComponent include; + + // Include + vs = new ValueSet(); + include = vs.getCompose().addInclude(); + include.setSystem(CS_URL); + include + .addFilter() + .setProperty("descendant") + .setOp(ValueSet.FilterOperator.EQUAL) + .setValue("50015-7"); + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Invalid filter, property descendant is LOINC-specific and cannot be used with system: http://example.com/my_code_system"); + myTermSvc.expandValueSet(vs); } @Test @@ -984,12 +1448,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("parent") .setOp(ValueSet.FilterOperator.ISA) .setValue("50015-7"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Don't know how to handle op=ISA on property parent", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Don't know how to handle op=ISA on property parent"); + myTermSvc.expandValueSet(vs); } @Test @@ -1009,12 +1471,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { .setProperty("parent") .setOp(ValueSet.FilterOperator.EQUAL) .setValue("50015-7"); - try { - myTermSvc.expandValueSet(vs); - } catch (InvalidRequestException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("Invalid filter, property parent is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage()); - } + + expectedException.expect(InvalidRequestException.class); + expectedException.expectMessage("Invalid filter, property parent is LOINC-specific and cannot be used with system: http://example.com/my_code_system"); + myTermSvc.expandValueSet(vs); } @Test diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java index da2f2c27963..e4a99c064fa 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java @@ -65,7 +65,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @After public void after() { myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences()); - myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); + myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets()); } private IIdType createCodeSystem() { @@ -629,7 +629,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testDeleteValueSet() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -641,7 +641,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get(); @@ -666,7 +666,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testDeleteValueSetWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -678,7 +678,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get(); @@ -723,7 +723,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testDuplicateValueSetUrls() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail. loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); @@ -736,7 +736,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildren() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -750,7 +750,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myCaptureQueriesListener.clear(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); myCaptureQueriesListener.logSelectQueriesForCurrentThread(); @@ -760,7 +760,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty()); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -821,7 +821,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testExpandExistingValueSetNotPreExpanded() throws Exception { loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -829,11 +829,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(0, expandedValueSet.getExpansion().getParameter().size()); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); @@ -885,11 +885,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); assertFalse(containsComponent.hasDesignation()); - expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(0, expandedValueSet.getExpansion().getParameter().size()); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); @@ -944,7 +944,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -956,11 +956,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -1019,7 +1019,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithCount() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -1031,11 +1031,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 23); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 23); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -1088,7 +1088,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithCountWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -1100,11 +1100,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 23); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 23); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -1157,7 +1157,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithCountOfZero() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -1169,11 +1169,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 0); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 0); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -1185,7 +1185,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithCountOfZeroWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -1197,11 +1197,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 0); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 0); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); - assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset()); + assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset()); assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); @@ -1213,7 +1213,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithOffset() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -1225,7 +1225,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); @@ -1274,7 +1274,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithOffsetWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -1286,7 +1286,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); - ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCount()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); @@ -1335,7 +1335,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithOffsetAndCount() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -1390,7 +1390,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testExpandTermValueSetAndChildrenWithOffsetAndCountWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -2046,7 +2046,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermValueSetAndChildren() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -2148,7 +2148,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermValueSetAndChildrenWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); @@ -2250,7 +2250,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermValueSetAndChildrenWithExclude() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.POST); @@ -2352,7 +2352,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermValueSetAndChildrenWithExcludeWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.PUT); @@ -3600,7 +3600,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testValidateCodeIsInPreExpandedValueSet() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); @@ -3650,7 +3650,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testValidateCodeIsInPreExpandedValueSetWithClientAssignedId() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); + myDaoConfig.setPreExpandValueSets(true); loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0beec66cdf9..816f7f06dea 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -43,7 +43,7 @@ Improovement: + Improvement: A significant performance improvement was made to the parsers (particularly the Json Parser) when serializing resources. This work yields improvements of 20-50% in raw encode speed when encoding large resources. Thanks to David Maplesden for the pull request! @@ -91,11 +91,11 @@ The informational message returned in an OperationOutcome when a delete failed due to cascades not being enabled contained an incorrect example. This has been corrected. - - In some cases, deleting a CodeSystem resource would fail because the underlying - codes were not correctly deleted from the terminology service tables. This is - fixed. - + + In some cases, deleting a CodeSystem resource would fail because the underlying + codes were not correctly deleted from the terminology service tables. This is + fixed. + Two foreign keys have been dropped from the HFJ_SEARCH_RESULT table used by the FHIR search query cache. These constraints did not add value and caused unneccessary contention when used under high load. @@ -115,7 +115,7 @@ leaving the Bundle.entry.request.method blank in DSTU3 transactions and setting the request payload as a Binary resource containing a valid patch. - + The HAPI FHIR CLI server now uses H2 as its database platform instead of Derby. Note that this means that data in any existing installations will need to be re-uploaded to the new database platform. @@ -219,6 +219,36 @@ handled by method implementations that did not have any @IncludeParam]]> defined. This is now corrected. Thanks to Tuomo Ala-Vannesluoma for reporting and providing a test case! + + The ValueSet operation $expand]]> has been optimized for large ValueSets. ValueSets are + now persistence-backed by the terminology tables, which are populated by a scheduled pre-expansion process. + A ValueSet previously stored in an existing FHIR repository will need to be re-created or updated to make + it a candidate for pre-expansion. ValueSets that have yet to be pre-expanded will continue to be expanded + in-memory. + + + The ValueSet operation $validate-code]]> has been optimized for large ValueSets. + Codes in ValueSets that have yet to be pre-expanded will continue to be validated in-memory. + + + LOINC filenames for terminology upload are now configurable using the + loincupload.properties]]> file. + + + Support for the LOINC EXTERNAL_COPYRIGHT_NOTICE]]> property and + copyright]]> filter has been added. + + + Support for the LOINC parent]]> and child]]> filters has been + added. Both filters can be used with either of the =]]> or + in]]> operators. + + + Support for the LOINC ancestor]]> and descendant]]> filters has + been added. The descendant]]> filter can be used with either of the + =]]> or in]]> operators. At present, the + ancestor]]> filter can only be used with the =]]> operator. + The JPA server failed to find codes defined in not-present codesystems in some cases, and reported that the CodeSystem did not exist. This has been corrected.