diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties index 8d9373ef09b..6a1223953a1 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties @@ -127,11 +127,5 @@ ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemU ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1} ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted! -ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.valueSetNotReadyForExpand=ValueSet is not ready for operation $expand; current status: {0} | {1} ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1} - -ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.notExpanded=The ValueSet is waiting to be picked up and pre-expanded by a scheduled task. -ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.expansionInProgress=The ValueSet has been picked up by a scheduled task and pre-expansion is in progress. -ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.expanded=The ValueSet has been picked up by a scheduled task and pre-expansion is complete. -ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.failedToExpand=The ValueSet has been picked up by a scheduled task and pre-expansion has failed. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetConceptDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetConceptDao.java index dca653b2058..826dda7e55f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetConceptDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ITermValueSetConceptDao.java @@ -47,8 +47,8 @@ public interface ITermValueSetConceptDao extends JpaRepository findByTermValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode); @Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.myCode = :codeval") - List findOneByValueSetIdAndCode(@Param("resource_pid") Long theValueSetId, @Param("codeval") String theCode); + List findByValueSetResourcePidAndCode(@Param("resource_pid") Long theValueSetId, @Param("codeval") String theCode); @Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval") - List findOneByValueSetIdSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode); + Optional findByValueSetResourcePidSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java index 3e5d9f89445..4a816fdc40f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoValueSetDstu3.java @@ -331,7 +331,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3 if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java index aa719557794..cb20e868505 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoValueSetR4.java @@ -327,7 +327,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4 imple if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoValueSetR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoValueSetR5.java index f0bb1ed9b12..d97e625f948 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoValueSetR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirResourceDaoValueSetR5.java @@ -333,7 +333,7 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5 imple if (vs != null) { ValidateCodeResult result; - if (myDaoConfig.isPreExpandValueSetsExperimental()) { + if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) { result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept); } else { ValueSet expansion = doExpand(vs); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnum.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnum.java index 83e1e0af62e..914be418ee2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnum.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnum.java @@ -29,26 +29,32 @@ import java.util.Map; * an expanded ValueSet has its included concepts stored in the terminology tables as well. */ public enum TermValueSetPreExpansionStatusEnum { - /** + /* * Sorting agnostic. */ - NOT_EXPANDED("notExpanded"), - EXPANSION_IN_PROGRESS("expansionInProgress"), - EXPANDED("expanded"), - FAILED_TO_EXPAND("failedToExpand"); + NOT_EXPANDED("notExpanded", "The ValueSet is waiting to be picked up and pre-expanded by a scheduled task."), + EXPANSION_IN_PROGRESS("expansionInProgress", "The ValueSet has been picked up by a scheduled task and pre-expansion is in progress."), + EXPANDED("expanded", "The ValueSet has been picked up by a scheduled task and pre-expansion is complete."), + FAILED_TO_EXPAND("failedToExpand", "The ValueSet has been picked up by a scheduled task and pre-expansion has failed."); private static Map ourValues; private String myCode; + private String myDescription; - TermValueSetPreExpansionStatusEnum(String theCode) { + TermValueSetPreExpansionStatusEnum(String theCode, String theDescription) { myCode = theCode; + myDescription = theDescription; } public String getCode() { return myCode; } + public String getDescription() { + return myDescription; + } + public static TermValueSetPreExpansionStatusEnum fromCode(String theCode) { if (ourValues == null) { HashMap values = new HashMap(); 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 2e3324b8719..23252a7d708 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 @@ -55,6 +55,7 @@ import org.hibernate.search.query.dsl.BooleanJunction; import org.hibernate.search.query.dsl.QueryBuilder; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseCoding; +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.*; @@ -145,6 +146,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Autowired private PlatformTransactionManager myTransactionMgr; private IFhirResourceDaoCodeSystem myCodeSystemResourceDao; + private IFhirResourceDaoValueSet myValueSetResourceDao; private Cache> myTranslationCache; private Cache> myTranslationWithReverseCache; private int myFetchSize = DEFAULT_FETCH_SIZE; @@ -486,7 +488,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, Optional optionalTermValueSet; if (theValueSetToExpand.hasId()) { - optionalTermValueSet = myValueSetDao.findByResourcePid(theValueSetToExpand.getIdElement().getIdPartAsLong()); + Long valueSetResourcePid = getValueSetResourcePid(theValueSetToExpand.getIdElement()); + optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); } else if (theValueSetToExpand.hasUrl()) { optionalTermValueSet = myValueSetDao.findByUrl(theValueSetToExpand.getUrl()); } else { @@ -494,12 +497,18 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } if (!optionalTermValueSet.isPresent()) { - throw new InvalidRequestException("ValueSet is not present in terminology tables: " + theValueSetToExpand.getUrl()); + ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory expansion without parameters. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSetToExpand)); + myDeferredValueSets.add(theValueSetToExpand); + return expandValueSet(theValueSetToExpand); // In-memory expansion. } TermValueSet termValueSet = optionalTermValueSet.get(); - validatePreExpansionStatusOfValueSetOrThrowException(termValueSet.getExpansionStatus()); + if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) { + ourLog.warn("{} is present in terminology tables but not ready for persistence-backed invocation of operation $expand. Will perform in-memory expansion without parameters. Current status: {} | {}", + getValueSetInfo(theValueSetToExpand), termValueSet.getExpansionStatus().name(), termValueSet.getExpansionStatus().getDescription()); + return expandValueSet(theValueSetToExpand); // In-memory expansion. + } ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent(); expansionComponent.setIdentifier(UUID.randomUUID().toString()); @@ -514,20 +523,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, return valueSet; } - private void validatePreExpansionStatusOfValueSetOrThrowException(TermValueSetPreExpansionStatusEnum thePreExpansionStatus) { - if (TermValueSetPreExpansionStatusEnum.EXPANDED != thePreExpansionStatus) { - String statusMsg = myContext.getLocalizer().getMessage( - TermValueSetPreExpansionStatusEnum.class, - thePreExpansionStatus.getCode()); - String msg = myContext.getLocalizer().getMessage( - BaseHapiTerminologySvcImpl.class, - "valueSetNotReadyForExpand", - thePreExpansionStatus.name(), - statusMsg); - throw new UnprocessableEntityException(msg); - } - } - private void populateExpansionComponent(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) { int total = myValueSetConceptDao.countByTermValueSetId(theTermValueSet.getId()); theExpansionComponent.setTotal(total); @@ -960,28 +955,49 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } + @Override + public boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet) { + Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement()); + Optional optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); + + if (!optionalTermValueSet.isPresent()) { + ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory code validation. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSet)); + myDeferredValueSets.add(theValueSet); + return false; + } + + TermValueSet termValueSet = optionalTermValueSet.get(); + + if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) { + ourLog.warn("{} is present in terminology tables but not ready for persistence-backed invocation of operation $validation-code. Will perform in-memory code validation. Current status: {} | {}", + getValueSetInfo(theValueSet), termValueSet.getExpansionStatus().name(), termValueSet.getExpansionStatus().getDescription()); + return false; + } + + return true; + } + protected ValidateCodeResult validateCodeIsInPreExpandedValueSet( ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) { ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet.hasId(), "ValueSet.id is required"); - - Long valueSetId = theValueSet.getIdElement().toUnqualifiedVersionless().getIdPartAsLong(); + Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement()); List concepts = new ArrayList<>(); if (isNotBlank(theCode)) { if (isNotBlank(theSystem)) { - concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theSystem, theCode); + concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, theSystem, theCode)); } else { - concepts = myValueSetConceptDao.findOneByValueSetIdAndCode(valueSetId, theCode); + concepts.addAll(myValueSetConceptDao.findByValueSetResourcePidAndCode(valueSetResourcePid, theCode)); } } else if (theCoding != null) { if (theCoding.hasSystem() && theCoding.hasCode()) { - concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theCoding.getSystem(), theCoding.getCode()); + concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, theCoding.getSystem(), theCoding.getCode())); } } else if (theCodeableConcept != null){ for (Coding coding : theCodeableConcept.getCoding()) { if (coding.hasSystem() && coding.hasCode()) { - concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, coding.getSystem(), coding.getCode()); + concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, coding.getSystem(), coding.getCode())); if (!concepts.isEmpty()) { break; } @@ -1002,6 +1018,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, return null; } + private List findByValueSetResourcePidSystemAndCode(Long theResourcePid, String theSystem, String theCode) { + List retVal = new ArrayList<>(); + Optional optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCode(theResourcePid, theSystem, theCode); + if (optionalTermValueSetConcept.isPresent()) { + retVal.add(optionalTermValueSetConcept.get()); + } + return retVal; + } + private void fetchChildren(TermConcept theConcept, Set theSetToPopulate) { for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) { TermConcept nextChild = nextChildLink.getChild(); @@ -1134,6 +1159,27 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, protected abstract CodeSystem getCodeSystemFromContext(String theSystem); + private Long getCodeSystemResourcePid(IIdType theIdType) { + return getCodeSystemResourcePid(theIdType, null); + } + + private Long getCodeSystemResourcePid(IIdType theIdType, RequestDetails theRequestDetails) { + return getResourcePid(myCodeSystemResourceDao, theIdType, theRequestDetails); + } + + private Long getValueSetResourcePid(IIdType theIdType) { + return getValueSetResourcePid(theIdType, null); + } + + private Long getValueSetResourcePid(IIdType theIdType, RequestDetails theRequestDetails) { + return getResourcePid(myValueSetResourceDao, theIdType, theRequestDetails); + } + + private Long getResourcePid(IFhirResourceDao theResourceDao, IIdType theIdType, RequestDetails theRequestDetails) { + ResourceTable resourceTable = (ResourceTable) theResourceDao.readEntity(theIdType, theRequestDetails); + return resourceTable.getId(); + } + private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap theConceptsStack, int theTotalConcepts) { if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) { return; @@ -1467,6 +1513,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @PostConstruct public void start() { myCodeSystemResourceDao = myApplicationContext.getBean(IFhirResourceDaoCodeSystem.class); + myValueSetResourceDao = myApplicationContext.getBean(IFhirResourceDaoValueSet.class); myTxTemplate = new TransactionTemplate(myTransactionManager); } @@ -1600,7 +1647,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.COMPLETE || theCodeSystem.getContent() == null || theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) { ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", theResourceEntity.getIdDt().getValue(), theCodeSystem.getContentElement().getValueAsString()); - Long codeSystemResourcePid = IDao.RESOURCE_PID.get(theCodeSystem); + Long codeSystemResourcePid = getCodeSystemResourcePid(theCodeSystem.getIdElement()); TermCodeSystemVersion persCs = myCodeSystemVersionDao.findCurrentVersionForCodeSystemResourcePid(codeSystemResourcePid); if (persCs != null) { ourLog.info("Code system version already exists in database"); @@ -1799,7 +1846,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Scheduled(fixedDelay = 600000) // 10 minutes. @Override - public synchronized void preExpandValueSetToTerminologyTables() { + public synchronized void preExpandDeferredValueSetsToTerminologyTables() { if (isNotSafeToPreExpandValueSets()) { ourLog.info("Skipping scheduled pre-expansion of ValueSets while deferred entities are being loaded."); return; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java index eb9b7c7e96e..1dc8a94b4a6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu2.java @@ -153,4 +153,9 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl { public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) { throw new UnsupportedOperationException(); } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + throw new UnsupportedOperationException(); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java index 09f17ea98bf..0070469c00f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java @@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.UrlUtil; +import ca.uhn.fhir.util.ValidateUtil; import org.hl7.fhir.convertors.VersionConvertor_30_40; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; import org.hl7.fhir.dstu3.model.*; @@ -364,24 +365,33 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen @Override public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) { + ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null"); ValueSet valueSet = (ValueSet) theValueSet; + org.hl7.fhir.r4.model.ValueSet valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet); + Coding coding = (Coding) theCoding; + org.hl7.fhir.r4.model.Coding codingR4 = null; + if (coding != null) { + codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay()); + } + CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept; - - try { - org.hl7.fhir.r4.model.ValueSet valueSetR4; - valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet); - - org.hl7.fhir.r4.model.Coding codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay()); - - org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept(); + org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = null; + if (codeableConcept != null) { + codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept(); for (Coding nestedCoding : codeableConcept.getCoding()) { codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay())); } - - return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); - } catch (FHIRException e) { - throw new InternalErrorException(e); } + + return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); + } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null"); + ValueSet valueSet = (ValueSet) theValueSet; + org.hl7.fhir.r4.model.ValueSet valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet); + return super.isValueSetPreExpandedForCodeValidation(valueSetR4); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java index a27afaccd49..a7e3d60e8e7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java @@ -284,4 +284,10 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept; return super.validateCodeIsInPreExpandedValueSet(valueSet, theSystem, theCode, theDisplay, coding, codeableConcept); } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + ValueSet valueSet = (ValueSet) theValueSet; + return super.isValueSetPreExpandedForCodeValidation(valueSet); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR5.java index b828627e94e..ede8dc78120 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR5.java @@ -7,11 +7,12 @@ import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.UrlUtil; +import ca.uhn.fhir.util.ValidateUtil; import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r5.model.*; import org.hl7.fhir.r5.hapi.ctx.IValidationSupport; +import org.hl7.fhir.r5.model.*; import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.terminologies.ValueSetExpander; @@ -291,17 +292,33 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements @Override public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) { - org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet((ValueSet) theValueSet); + ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null"); + ValueSet valueSet = (ValueSet) theValueSet; + org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet); Coding coding = (Coding) theCoding; - org.hl7.fhir.r4.model.Coding codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay()); + org.hl7.fhir.r4.model.Coding codingR4 = null; + if (coding != null) { + codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay()); + } CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept; - org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept(); - for (Coding nestedCoding : codeableConcept.getCoding()) { - codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay())); + org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = null; + if (codeableConcept != null) { + codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept(); + for (Coding nestedCoding : codeableConcept.getCoding()) { + codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay())); + } } return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null"); + ValueSet valueSet = (ValueSet) theValueSet; + org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet); + return super.isValueSetPreExpandedForCodeValidation(valueSetR4); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java index 8675d594205..f6b06b8b4e7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/IHapiTerminologySvc.java @@ -111,10 +111,17 @@ public interface IHapiTerminologySvc { AtomicInteger applyDeltaCodesystemsRemove(String theSystem, CodeSystem theDelta); - void preExpandValueSetToTerminologyTables(); + void preExpandDeferredValueSetsToTerminologyTables(); /** * Version independent */ ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept); + + boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet); + + /** + * Version independent + */ + boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet); } 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 cf3d7ce0bd6..10c0949f03d 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 @@ -1,14 +1,12 @@ package ca.uhn.fhir.jpa.dao.r4; +import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult; import ca.uhn.fhir.util.TestUtil; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.r4.model.*; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.*; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; @@ -22,6 +20,10 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { private IIdType myExtensionalVsId; + @After + public void after() { + myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental()); + } @AfterClass public static void afterClassClearContext() { @@ -124,6 +126,33 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); } + @Test + public void testValidateCodeOperationByResourceIdAndCodeableConceptWithExistingValueSetAndPreExpansionEnabled() { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + UriType valueSetIdentifier = null; + IIdType id = myExtensionalVsId; + CodeType code = null; + UriType system = null; + StringType display = null; + Coding coding = null; + CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding().setSystem("http://acme.org").setCode("11378-7"); + ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + myTermSvc.saveDeferred(); + result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + } + @Test public void testValidateCodeOperationByResourceIdAndCodeAndSystem() { UriType valueSetIdentifier = null; @@ -138,6 +167,32 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test { assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); } + @Test + public void testValidateCodeOperationByResourceIdAndCodeAndSystemWithExistingValueSetAndPreExpansionEnabled() { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + UriType valueSetIdentifier = null; + IIdType id = myExtensionalVsId; + CodeType code = new CodeType("11378-7"); + UriType system = new UriType("http://acme.org"); + StringType display = null; + Coding coding = null; + CodeableConcept codeableConcept = null; + ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + myTermSvc.saveDeferred(); + result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd); + assertTrue(result.isResult()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + } + @Test public void testExpandById() throws IOException { String resp; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnumTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnumTest.java deleted file mode 100644 index a9b8f365ca4..00000000000 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnumTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package ca.uhn.fhir.jpa.entity; - -import ca.uhn.fhir.i18n.HapiLocalizer; -import org.junit.Test; - -import static org.junit.Assert.fail; - -public class TermValueSetPreExpansionStatusEnumTest { - @Test - public void testHaveDescriptions() { - HapiLocalizer localizer = new HapiLocalizer(); - - for (TermValueSetPreExpansionStatusEnum next : TermValueSetPreExpansionStatusEnum.values()) { - String key = "ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum." + next.getCode(); - String msg = localizer.getMessage(key); - if (msg.equals(HapiLocalizer.UNKNOWN_I18N_KEY_MESSAGE)) { - fail("No value for key: " + key); - } - } - } -} 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 0775d598c37..e097e543aff 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 @@ -600,7 +600,9 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong()); + ResourceTable resourceTable = (ResourceTable) myCodeSystemDao.readEntity(codeSystemResource.getIdElement(), null); + Long codeSystemResourcePid = resourceTable.getId(); + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemResourcePid); assertEquals(CS_URL, codeSystem.getCodeSystemUri()); assertEquals("SYSTEM NAME", codeSystem.getName()); 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 a5998ad8b4a..89263f497b2 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 @@ -18,6 +18,7 @@ import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult; import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence; import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; +import org.hl7.fhir.r4.model.codesystems.HttpVerb; import org.junit.*; import org.junit.rules.ExpectedException; import org.mockito.Mock; @@ -52,6 +53,8 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { private IIdType myConceptMapId; private IIdType myExtensionalCsId; private IIdType myExtensionalVsId; + private Long myExtensionalCsIdOnResourceTable; + private Long myExtensionalVsIdOnResourceTable; @Before public void before() { @@ -117,71 +120,120 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { return id; } - private void createAndPersistConceptMap() { + private void createAndPersistConceptMap(HttpVerb theVerb) { ConceptMap conceptMap = createConceptMap(); - persistConceptMap(conceptMap); + conceptMap.setId("ConceptMap/cm"); + persistConceptMap(conceptMap, HttpVerb.POST); } - private void persistConceptMap(ConceptMap theConceptMap) { - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); - } - }); + private void persistConceptMap(ConceptMap theConceptMap, HttpVerb theVerb) { + switch (theVerb) { + case POST: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + case PUT: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myConceptMapId = myConceptMapDao.update(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + default: + throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); + } } - private void loadAndPersistCodeSystemAndValueSet() throws IOException { - loadAndPersistCodeSystem(); - loadAndPersistValueSet(); + private void loadAndPersistCodeSystemAndValueSet(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystem(theVerb); + loadAndPersistValueSet(theVerb); } - private void loadAndPersistCodeSystemAndValueSetWithDesignations() throws IOException { - loadAndPersistCodeSystemWithDesignations(); - loadAndPersistValueSet(); + private void loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSet(theVerb); } - private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude() throws IOException { - loadAndPersistCodeSystemWithDesignations(); - loadAndPersistValueSetWithExclude(); + private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSetWithExclude(theVerb); } - private void loadAndPersistCodeSystem() throws IOException { + private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException { CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); - persistCodeSystem(codeSystem); + codeSystem.setId("CodeSystem/cs"); + persistCodeSystem(codeSystem, theVerb); } - private void loadAndPersistCodeSystemWithDesignations() throws IOException { + private void loadAndPersistCodeSystemWithDesignations(HttpVerb theVerb) throws IOException { CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs-with-designations.xml"); - persistCodeSystem(codeSystem); + codeSystem.setId("CodeSystem/cs"); + persistCodeSystem(codeSystem, theVerb); } - private void persistCodeSystem(CodeSystem theCodeSystem) { - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless(); - } - }); + private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) { + switch (theVerb) { + case POST: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myExtensionalCsId = myCodeSystemDao.create(theCodeSystem, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + case PUT: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myExtensionalCsId = myCodeSystemDao.update(theCodeSystem, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + default: + throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); + } + myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId(); } - private void loadAndPersistValueSet() throws IOException { + private void loadAndPersistValueSet(HttpVerb theVerb) throws IOException { ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml"); - persistValueSet(valueSet); + valueSet.setId("ValueSet/vs"); + persistValueSet(valueSet, theVerb); } - private void loadAndPersistValueSetWithExclude() throws IOException { + private void loadAndPersistValueSetWithExclude(HttpVerb theVerb) throws IOException { ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml"); - persistValueSet(valueSet); + valueSet.setId("ValueSet/vs"); + persistValueSet(valueSet, theVerb); } - private void persistValueSet(ValueSet theValueSet) { - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless(); - } - }); + private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) { + switch (theVerb) { + case POST: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myExtensionalVsId = myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + case PUT: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myExtensionalVsId = myValueSetDao.update(theValueSet, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + default: + throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); + } + myExtensionalVsIdOnResourceTable = myValueSetDao.readEntity(myExtensionalVsId, null).getId(); } @Test @@ -511,7 +563,18 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { conceptMap.getGroup().forEach(t -> t.setSource(null)); conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); - persistConceptMap(conceptMap); + persistConceptMap(conceptMap, HttpVerb.POST); + + } + + @Test + public void testCreateConceptMapWithVirtualSourceSystemWithClientAssignedId() { + ConceptMap conceptMap = createConceptMap(); + conceptMap.getGroup().forEach(t -> t.setSource(null)); + conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); + conceptMap.setId("ConceptMap/cm"); + + persistConceptMap(conceptMap, HttpVerb.PUT); } @@ -567,7 +630,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testDeleteValueSet() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -575,12 +638,12 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); - Long termValueSetId = myTermValueSetDao.findByResourcePid(valueSet.getIdElement().toUnqualifiedVersionless().getIdPartAsLong()).get().getId(); + Long termValueSetId = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get().getId(); assertEquals(3, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue()); assertEquals(24, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); @@ -592,49 +655,16 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId); assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); myTermValueSetDao.deleteByTermValueSetId(termValueSetId); - assertFalse(myTermValueSetDao.findByResourcePid(valueSet.getIdElement().toUnqualifiedVersionless().getIdPartAsLong()).isPresent()); + assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent()); } }); } @Test - public void testDuplicateCodeSystemUrls() throws Exception { - loadAndPersistCodeSystem(); - - expectedException.expect(UnprocessableEntityException.class); - expectedException.expectMessage("Can not create multiple CodeSystem resources with CodeSystem.url \"http://acme.org\", already have one with resource ID: CodeSystem/" + myExtensionalCsId.getIdPart()); - - loadAndPersistCodeSystem(); - } - - @Test - public void testDuplicateConceptMapUrls() { - createAndPersistConceptMap(); - - expectedException.expect(UnprocessableEntityException.class); - expectedException.expectMessage("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart()); - - createAndPersistConceptMap(); - } - - @Test - public void testDuplicateValueSetUrls() throws Exception { + public void testDeleteValueSetWithClientAssignedId() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail. - loadAndPersistCodeSystemAndValueSet(); - - expectedException.expect(UnprocessableEntityException.class); - expectedException.expectMessage("Can not create multiple ValueSet resources with ValueSet.url \"http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2\", already have one with resource ID: ValueSet/" + myExtensionalVsId.getIdPart()); - - loadAndPersistValueSet(); - } - - @Test - public void testExpandTermValueSetAndChildren() throws Exception { - myDaoConfig.setPreExpandValueSetsExperimental(true); - - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -642,7 +672,281 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); + + Long termValueSetId = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get().getId(); + assertEquals(3, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue()); + assertEquals(24, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + myTermValueSetConceptDesignationDao.deleteByTermValueSetId(termValueSetId); + assertEquals(0, myTermValueSetConceptDesignationDao.countByTermValueSetId(termValueSetId).intValue()); + myTermValueSetConceptDao.deleteByTermValueSetId(termValueSetId); + assertEquals(0, myTermValueSetConceptDao.countByTermValueSetId(termValueSetId).intValue()); + myTermValueSetDao.deleteByTermValueSetId(termValueSetId); + assertFalse(myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).isPresent()); + } + }); + } + + @Test + public void testDuplicateCodeSystemUrls() throws Exception { + loadAndPersistCodeSystem(HttpVerb.POST); + + expectedException.expect(UnprocessableEntityException.class); + expectedException.expectMessage("Can not create multiple CodeSystem resources with CodeSystem.url \"http://acme.org\", already have one with resource ID: CodeSystem/" + myExtensionalCsId.getIdPart()); + + loadAndPersistCodeSystem(HttpVerb.POST); + } + + @Test + public void testDuplicateConceptMapUrls() { + createAndPersistConceptMap(HttpVerb.POST); + + expectedException.expect(UnprocessableEntityException.class); + expectedException.expectMessage("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart()); + + createAndPersistConceptMap(HttpVerb.POST); + } + + @Test + public void testDuplicateValueSetUrls() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail. + loadAndPersistCodeSystemAndValueSet(HttpVerb.POST); + + expectedException.expect(UnprocessableEntityException.class); + expectedException.expectMessage("Can not create multiple ValueSet resources with ValueSet.url \"http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2\", already have one with resource ID: ValueSet/" + myExtensionalVsId.getIdPart()); + + loadAndPersistValueSet(HttpVerb.POST); + } + + @Test + public void testExpandTermValueSetAndChildren() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + 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(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); + + ValueSet.ValueSetExpansionContainsComponent containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8450-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure--expiration", containsComponent.getDisplay()); + assertEquals(2, containsComponent.getDesignation().size()); + + ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designationComponent.getValue()); + + designationComponent = containsComponent.getDesignation().get(1); + assertEquals("sv", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(22); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(23); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8492-1", containsComponent.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + } + + @Test + public void testExpandExistingValueSetNotPreExpanded() throws Exception { + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); + + myDaoConfig.setPreExpandValueSetsExperimental(true); + + 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)); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + 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(0, expandedValueSet.getExpansion().getParameter().size()); + + assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); + + ValueSet.ValueSetExpansionContainsComponent containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8450-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure--expiration", containsComponent.getDisplay()); + assertEquals(2, containsComponent.getDesignation().size()); + + ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designationComponent.getValue()); + + designationComponent = containsComponent.getDesignation().get(1); + assertEquals("sv", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(22); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(23); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8492-1", containsComponent.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + myTermSvc.saveDeferred(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + 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(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8450-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure--expiration", containsComponent.getDisplay()); + assertEquals(2, containsComponent.getDesignation().size()); + + designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designationComponent.getValue()); + + designationComponent = containsComponent.getDesignation().get(1); + assertEquals("sv", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(22); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(23); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8492-1", containsComponent.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + } + + @Test + public void testExpandTermValueSetAndChildrenWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); @@ -709,7 +1013,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testExpandTermValueSetAndChildrenWithCount() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -717,7 +1021,76 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 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(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(23, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertEquals(23, expandedValueSet.getExpansion().getContains().size()); + + ValueSet.ValueSetExpansionContainsComponent containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8450-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure--expiration", containsComponent.getDisplay()); + assertEquals(2, containsComponent.getDesignation().size()); + + ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designationComponent.getValue()); + + designationComponent = containsComponent.getDesignation().get(1); + assertEquals("sv", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(22); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + } + + @Test + public void testExpandTermValueSetAndChildrenWithCountWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 23); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); @@ -778,7 +1151,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testExpandTermValueSetAndChildrenWithCountOfZero() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -786,7 +1159,35 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 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(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(0, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertFalse(expandedValueSet.getExpansion().hasContains()); + } + + @Test + public void testExpandTermValueSetAndChildrenWithCountOfZeroWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 0); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); @@ -806,7 +1207,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testExpandTermValueSetAndChildrenWithOffset() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -814,7 +1215,68 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); + ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); + + assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); + assertEquals(1, expandedValueSet.getExpansion().getOffset()); + assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(1, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(1000, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertEquals(codeSystem.getConcept().size() - expandedValueSet.getExpansion().getOffset(), expandedValueSet.getExpansion().getContains().size()); + + ValueSet.ValueSetExpansionContainsComponent containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8493-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure 10 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(21); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(22); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8492-1", containsComponent.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + } + + @Test + public void testExpandTermValueSetAndChildrenWithOffsetWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental()); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); @@ -867,7 +1329,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testExpandTermValueSetAndChildrenWithOffsetAndCount() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -875,7 +1337,62 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, 22); + ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); + + assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal()); + assertEquals(1, expandedValueSet.getExpansion().getOffset()); + assertEquals(2, expandedValueSet.getExpansion().getParameter().size()); + assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName()); + assertEquals(1, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue()); + assertEquals("count", expandedValueSet.getExpansion().getParameter().get(1).getName()); + assertEquals(22, expandedValueSet.getExpansion().getParameter().get(1).getValueIntegerType().getValue().intValue()); + + assertEquals(22, expandedValueSet.getExpansion().getContains().size()); + + ValueSet.ValueSetExpansionContainsComponent containsComponent = expandedValueSet.getExpansion().getContains().get(0); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("11378-7", containsComponent.getCode()); + assertEquals("Systolic blood pressure at First encounter", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + containsComponent = expandedValueSet.getExpansion().getContains().get(1); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8493-9", containsComponent.getCode()); + assertEquals("Systolic blood pressure 10 hour minimum", containsComponent.getDisplay()); + assertFalse(containsComponent.hasDesignation()); + + // ... + + containsComponent = expandedValueSet.getExpansion().getContains().get(21); + assertEquals("http://acme.org", containsComponent.getSystem()); + assertEquals("8491-3", containsComponent.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", containsComponent.getDisplay()); + assertEquals(1, containsComponent.getDesignation().size()); + + ValueSet.ConceptReferenceDesignationComponent designationComponent = containsComponent.getDesignation().get(0); + assertEquals("nl", designationComponent.getLanguage()); + assertEquals("http://snomed.info/sct", designationComponent.getUse().getSystem()); + assertEquals("900000000000013009", designationComponent.getUse().getCode()); + assertEquals("Synonym", designationComponent.getUse().getDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designationComponent.getValue()); + } + + @Test + public void testExpandTermValueSetAndChildrenWithOffsetAndCountWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, 22); ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); @@ -932,7 +1449,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermCodeSystemAndChildren() throws Exception { - loadAndPersistCodeSystemWithDesignations(); + loadAndPersistCodeSystemWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -940,7 +1457,74 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(myExtensionalCsId.getIdPartAsLong()); + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(myExtensionalCsIdOnResourceTable); + assertEquals("http://acme.org", codeSystem.getCodeSystemUri()); + assertNull(codeSystem.getName()); + + TermCodeSystemVersion codeSystemVersion = codeSystem.getCurrentVersion(); + assertEquals(24, codeSystemVersion.getConcepts().size()); + + List concepts = myTermConceptDao.findByCodeSystemVersion(codeSystemVersion); + + TermConcept concept = concepts.get(0); + assertEquals("8450-9", concept.getCode()); + assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); + assertEquals(2, concept.getDesignations().size()); + + List designations = Lists.newArrayList(concept.getDesignations().iterator()); + + TermConceptDesignation designation = designations.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 = designations.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 = concepts.get(1); + assertEquals("11378-7", concept.getCode()); + assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + + // ... + + concept = concepts.get(22); + assertEquals("8491-3", concept.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); + assertEquals(1, concept.getDesignations().size()); + + designation = concept.getDesignations().iterator().next(); + 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 = concepts.get(23); + assertEquals("8492-1", concept.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + } + }); + } + + @Test + public void testStoreTermCodeSystemAndChildrenWithClientAssignedId() throws Exception { + loadAndPersistCodeSystemWithDesignations(HttpVerb.PUT); + + CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); + ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(myExtensionalCsIdOnResourceTable); assertEquals("http://acme.org", codeSystem.getCodeSystemUri()); assertNull(codeSystem.getName()); @@ -1006,7 +1590,9 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong()); + ResourceTable resourceTable = (ResourceTable) myCodeSystemDao.readEntity(codeSystemResource.getIdElement(), null); + Long codeSystemResourcePid = resourceTable.getId(); + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemResourcePid); assertEquals(CS_URL, codeSystem.getCodeSystemUri()); assertEquals("SYSTEM NAME", codeSystem.getName()); @@ -1096,7 +1682,185 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testStoreTermConceptMapAndChildren() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + Optional optionalConceptMap = myTermConceptMapDao.findTermConceptMapByUrl(CM_URL); + assertTrue(optionalConceptMap.isPresent()); + + TermConceptMap conceptMap = optionalConceptMap.get(); + + ourLog.info("ConceptMap:\n" + conceptMap.toString()); + + assertEquals(VS_URL, conceptMap.getSource()); + assertEquals(VS_URL_2, conceptMap.getTarget()); + assertEquals(CM_URL, conceptMap.getUrl()); + assertEquals(3, conceptMap.getConceptMapGroups().size()); + + TermConceptMapGroup group = conceptMap.getConceptMapGroups().get(0); + + ourLog.info("ConceptMap.group(0):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 1", group.getSourceVersion()); + assertEquals(VS_URL, group.getSourceValueSet()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(VS_URL_2, group.getTargetValueSet()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(2, group.getConceptMapGroupElements().size()); + + TermConceptMapGroupElement element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(0).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + TermConceptMapGroupElementTarget target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(0).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + element = group.getConceptMapGroupElements().get(1); + + ourLog.info("ConceptMap.group(0).element(1):\n" + element.toString()); + + assertEquals("23456", element.getCode()); + assertEquals("Source Code 23456", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + ourLog.info("ConceptMap.group(0).element(1).target(0):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // We had deliberately added a duplicate, and here it is... + target = element.getConceptMapGroupElementTargets().get(1); + ourLog.info("ConceptMap.group(0).element(1).target(1):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(1); + + ourLog.info("ConceptMap.group(1):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 3", group.getSourceVersion()); + assertEquals(CS_URL_3, group.getTarget()); + assertEquals("Version 4", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(1).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 3", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(1).element(0).target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = element.getConceptMapGroupElementTargets().get(1); + + ourLog.info("ConceptMap.group(1).element(0).target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(2); + + ourLog.info("ConceptMap.group(2):\n" + group.toString()); + + assertEquals(CS_URL_4, group.getSource()); + assertEquals("Version 5", group.getSourceVersion()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(2).element(0):\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(2).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(ConceptMapEquivalence.NARROWER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + } + }); + } + + @Test + public void testStoreTermConceptMapAndChildrenWithClientAssignedId() { + createAndPersistConceptMap(HttpVerb.PUT); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1276,7 +2040,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testStoreTermValueSetAndChildren() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -1285,7 +2049,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); runInTransaction(()->{ - Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); assertTrue(optionalValueSetByResourcePid.isPresent()); Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); @@ -1300,10 +2064,108 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ - Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName()); + assertEquals(codeSystem.getConcept().size(), termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); + + TermValueSetConcept concept = termValueSet.getConcepts().get(0); + ourLog.info("Code:\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()); + + 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("Code:\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()); + + // ... + + concept = termValueSet.getConcepts().get(22); + ourLog.info("Code:\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()); + + 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("Code:\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()); + }); + } + + @Test + public void testStoreTermValueSetAndChildrenWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + 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("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName()); + assertEquals(0, termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); + }); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); assertTrue(optionalValueSetByResourcePid.isPresent()); Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); @@ -1374,7 +2236,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testStoreTermValueSetAndChildrenWithExclude() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(); + loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -1383,7 +2245,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); runInTransaction(()->{ - Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); assertTrue(optionalValueSetByResourcePid.isPresent()); Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); @@ -1398,10 +2260,108 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ - Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName()); + assertEquals(codeSystem.getConcept().size() - 2, termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); + + TermValueSetConcept concept = termValueSet.getConcepts().get(0); + ourLog.info("Code:\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()); + + 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("Code:\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()); + + // ... + + concept = termValueSet.getConcepts().get(22 - 2); + ourLog.info("Code:\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()); + + 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 - 2); + ourLog.info("Code:\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()); + }); + } + + @Test + public void testStoreTermValueSetAndChildrenWithExcludeWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.PUT); + + 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)); + + 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("Terminology Services Connectation #1 Extensional case #2", termValueSet.getName()); + assertEquals(0, termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); + }); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); assertTrue(optionalValueSetByResourcePid.isPresent()); Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); @@ -1470,7 +2430,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateByCodeSystemsAndSourceCodeOneToMany() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1524,7 +2484,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateByCodeSystemsAndSourceCodeOneToOne() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1598,7 +2558,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateByCodeSystemsAndSourceCodeUnmapped() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1651,7 +2611,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithCodeOnly() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1719,7 +2679,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceAndTargetSystem2() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1767,7 +2727,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceAndTargetSystem3() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1827,7 +2787,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceSystem() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1897,7 +2857,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceSystemAndVersion1() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -1945,7 +2905,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceSystemAndVersion3() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2005,7 +2965,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithSourceValueSet() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2075,7 +3035,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateUsingPredicatesWithTargetValueSet() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2145,7 +3105,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverse() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2194,7 +3154,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseByCodeSystemsAndSourceCodeUnmapped() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2217,7 +3177,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithCodeOnly() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2273,7 +3233,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem1() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2322,7 +3282,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem4() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2371,7 +3331,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithSourceSystem() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2429,7 +3389,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithSourceSystemAndVersion() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2489,7 +3449,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithSourceValueSet() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2547,7 +3507,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testTranslateWithReverseUsingPredicatesWithTargetValueSet() { - createAndPersistConceptMap(); + createAndPersistConceptMap(HttpVerb.POST); ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); @@ -2618,7 +3578,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { public void testValidateCodeIsInPreExpandedValueSet() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -2626,7 +3586,57 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + ValidateCodeResult result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, null, null, null, null); + assertNull(result); + + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, "BOGUS", null, null, null); + assertNull(result); + + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, "11378-7", null, null, null); + assertTrue(result.isResult()); + assertEquals("Validation succeeded", result.getMessage()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, "11378-7", "Systolic blood pressure at First encounter", null, null); + assertTrue(result.isResult()); + assertEquals("Validation succeeded", result.getMessage()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, "http://acme.org", "11378-7", null, null, null); + assertTrue(result.isResult()); + assertEquals("Validation succeeded", result.getMessage()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + Coding coding = new Coding("http://acme.org", "11378-7", "Systolic blood pressure at First encounter"); + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, null, null, coding, null); + assertTrue(result.isResult()); + assertEquals("Validation succeeded", result.getMessage()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + + CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding(new Coding("BOGUS", "BOGUS", "BOGUS")); + codeableConcept.addCoding(coding); + result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, null, null, null, codeableConcept); + assertTrue(result.isResult()); + assertEquals("Validation succeeded", result.getMessage()); + assertEquals("Systolic blood pressure at First encounter", result.getDisplay()); + } + + @Test + public void testValidateCodeIsInPreExpandedValueSetWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); + + 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)); + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); ValidateCodeResult result = myTermSvc.validateCodeIsInPreExpandedValueSet(valueSet, null, null, null, null, null); assertNull(result); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriber.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriber.java index 8f2df1f4d77..4d6b44bef62 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriber.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriber.java @@ -18,10 +18,7 @@ import org.hl7.fhir.instance.model.api.IIdType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessagingException; +import org.springframework.messaging.*; import org.springframework.stereotype.Service; import java.util.Collection; @@ -163,14 +160,7 @@ public class SubscriptionMatchingSubscriber implements MessageHandler { return; } - ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(deliveryMsg); - MessageChannel deliveryChannel = nextActiveSubscription.getSubscribableChannel(); - if (deliveryChannel != null) { - resourceMatched = true; - deliveryChannel.send(wrappedMsg); - } else { - ourLog.warn("Do not have delivery channel for subscription {}", nextActiveSubscription.getIdElement(myFhirContext)); - } + resourceMatched |= sendToDeliveryChannel(nextActiveSubscription, deliveryMsg); } if (!resourceMatched) { @@ -181,6 +171,31 @@ public class SubscriptionMatchingSubscriber implements MessageHandler { } } + private boolean sendToDeliveryChannel(ActiveSubscription nextActiveSubscription, ResourceDeliveryMessage theDeliveryMsg) { + boolean retval = false; + ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(theDeliveryMsg); + MessageChannel deliveryChannel = nextActiveSubscription.getSubscribableChannel(); + if (deliveryChannel != null) { + retval = true; + trySendToDeliveryChannel(wrappedMsg, deliveryChannel); + } else { + ourLog.warn("Do not have delivery channel for subscription {}", nextActiveSubscription.getIdElement(myFhirContext)); + } + return retval; + } + + private void trySendToDeliveryChannel(ResourceDeliveryJsonMessage theWrappedMsg, MessageChannel theDeliveryChannel) { + try { + boolean success = theDeliveryChannel.send(theWrappedMsg); + if (!success) { + ourLog.warn("Failed to send message to Delivery Channel."); + } + } catch (RuntimeException e) { + ourLog.error("Failed to send message to Delivery Channel", e); + throw new RuntimeException("Failed to send message to Delivery Channel", e); + } + } + private String getId(ActiveSubscription theActiveSubscription) { return theActiveSubscription.getIdElement(myFhirContext).toUnqualifiedVersionless().getValue(); } diff --git a/pom.xml b/pom.xml index 02d897fb52e..1e8675e2c32 100755 --- a/pom.xml +++ b/pom.xml @@ -547,6 +547,10 @@ nickrobison-usds Nick Robison + + fitzoh + Andrew Fitzgerald + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index eb85ecd7c68..507f004fe5c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -102,6 +102,10 @@ identifies the LOINC CodeSystem in ValueSet.compose.include.system]]>. This ValueSet includes all LOINC codes. + + A note has been added to the downloads page explaning the removal of the hapi-fhir-utilities + module. Thanks to Andrew Fitzgerald for the PR! +