From 46a6b7aaef677d1e5ce86de01592d0b49f2dc391 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Tue, 24 Sep 2019 15:30:40 -0400 Subject: [PATCH] Troubleshooting lack of ValueSet pre-expansion when updating a ValueSet via transaction bundle. --- .../jpa/term/BaseHapiTerminologySvcImpl.java | 8 +- .../r4/ResourceProviderR4ValueSetTest.java | 188 +++++++++++++++++- 2 files changed, 190 insertions(+), 6 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index d66593320bc..46ab97242e2 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 @@ -1870,7 +1870,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override @Transactional public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) { - ourLog.info("Storing TermConceptMap {}", theConceptMap.getIdElement().getValue()); + ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url"); @@ -1981,7 +1981,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, throw new UnprocessableEntityException(msg); } - ourLog.info("Done storing TermConceptMap[{}]", termConceptMap.getId()); + ourLog.info("Done storing TermConceptMap[{}] for {}", termConceptMap.getId(), theConceptMap.getIdElement().toVersionless().getValueAsString()); } @Override @@ -2077,7 +2077,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override @Transactional public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) { - ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue()); + ourLog.info("Storing TermValueSet for {}", theValueSet.getIdElement().toVersionless().getValueAsString()); ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url"); @@ -2111,7 +2111,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, throw new UnprocessableEntityException(msg); } - ourLog.info("Done storing TermValueSet[{}]", termValueSet.getId()); + ourLog.info("Done storing TermValueSet[{}] for {}", termValueSet.getId(), theValueSet.getIdElement().toVersionless().getValueAsString()); } @Override diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java index 967eac53868..94aeccc0712 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetTest.java @@ -3,8 +3,7 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.data.IResourceTableDao; -import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; -import ca.uhn.fhir.jpa.entity.TermConcept; +import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.term.IHapiTerminologySvc; @@ -36,6 +35,7 @@ import org.springframework.transaction.support.TransactionTemplate; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Optional; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET; @@ -57,12 +57,28 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { loadAndPersistValueSet(theVerb); } + private void loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSet(theVerb); + } + + private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb theVerb) throws IOException { + loadAndPersistCodeSystemWithDesignations(theVerb); + loadAndPersistValueSetWithExclude(theVerb); + } + private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException { CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml"); codeSystem.setId("CodeSystem/cs"); persistCodeSystem(codeSystem, theVerb); } + private void loadAndPersistCodeSystemWithDesignations(HttpVerb theVerb) throws IOException { + CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs-with-designations.xml"); + codeSystem.setId("CodeSystem/cs"); + persistCodeSystem(codeSystem, theVerb); + } + private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) { switch (theVerb) { case POST: @@ -93,6 +109,12 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { persistValueSet(valueSet, theVerb); } + private void loadAndPersistValueSetWithExclude(HttpVerb theVerb) throws IOException { + ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml"); + valueSet.setId("ValueSet/vs"); + persistValueSet(valueSet, theVerb); + } + private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) { switch (theVerb) { case POST: @@ -687,6 +709,168 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test { } } + @Test + public void testUpdateValueSetTriggersAnotherPreExpansion() 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)); + + String initialValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(initialValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem); + + ValueSet updatedValueSet = valueSet; + updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED")); + persistValueSet(updatedValueSet, HttpVerb.PUT); + updatedValueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet)); + + String updatedValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(updatedValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem); + } + + @Test + public void testUpdateValueSetTriggersAnotherPreExpansionUsingTransactionBundle() throws Exception { + myDaoConfig.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)); + + String initialValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(initialValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem); + + ValueSet updatedValueSet = valueSet; + updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED")); + + String requestUrl = ourClient.getServerBase().concat("/").concat(myExtensionalVsId.getValueAsString()); + Bundle bundle = new Bundle(); + bundle.setType(Bundle.BundleType.TRANSACTION); + bundle + .addEntry() + .setFullUrl(updatedValueSet.getUrl()) + .setResource(updatedValueSet) + .getRequest() + .setMethod(Bundle.HTTPVerb.PUT) + .setUrl(requestUrl); + ourLog.info("Transaction Bundle:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + ourClient.transaction().withBundle(bundle).execute(); + + updatedValueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet)); + + String updatedValueSetName = valueSet.getName(); + validateTermValueSetNotExpanded(updatedValueSetName); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem); + } + + private void validateTermValueSetNotExpanded(String theValueSetName) { + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); + assertTrue(optionalValueSetByResourcePid.isPresent()); + + Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); + assertTrue(optionalValueSetByUrl.isPresent()); + + TermValueSet termValueSet = optionalValueSetByUrl.get(); + assertSame(optionalValueSetByResourcePid.get(), termValueSet); + ourLog.info("ValueSet:\n" + termValueSet.toString()); + assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl()); + assertEquals(theValueSetName, termValueSet.getName()); + assertEquals(0, termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); + }); + } + + private void validateTermValueSetExpandedAndChildren(String theValueSetName, CodeSystem theCodeSystem) { + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); + assertTrue(optionalValueSetByResourcePid.isPresent()); + + Optional optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"); + assertTrue(optionalValueSetByUrl.isPresent()); + + TermValueSet termValueSet = optionalValueSetByUrl.get(); + assertSame(optionalValueSetByResourcePid.get(), termValueSet); + ourLog.info("ValueSet:\n" + termValueSet.toString()); + assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl()); + assertEquals(theValueSetName, termValueSet.getName()); + assertEquals(theCodeSystem.getConcept().size(), termValueSet.getConcepts().size()); + assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus()); + + TermValueSetConcept concept = termValueSet.getConcepts().get(0); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8450-9", concept.getCode()); + assertEquals("Systolic blood pressure--expiration", concept.getDisplay()); + assertEquals(2, concept.getDesignations().size()); + assertEquals(0, concept.getOrder()); + + TermValueSetConceptDesignation designation = concept.getDesignations().get(0); + assertEquals("nl", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systolische bloeddruk - expiratie", designation.getValue()); + + designation = concept.getDesignations().get(1); + assertEquals("sv", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systoliskt blodtryck - utgång", designation.getValue()); + + concept = termValueSet.getConcepts().get(1); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("11378-7", concept.getCode()); + assertEquals("Systolic blood pressure at First encounter", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + assertEquals(1, concept.getOrder()); + + // ... + + concept = termValueSet.getConcepts().get(22); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8491-3", concept.getCode()); + assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay()); + assertEquals(1, concept.getDesignations().size()); + assertEquals(22, concept.getOrder()); + + designation = concept.getDesignations().get(0); + assertEquals("nl", designation.getLanguage()); + assertEquals("http://snomed.info/sct", designation.getUseSystem()); + assertEquals("900000000000013009", designation.getUseCode()); + assertEquals("Synonym", designation.getUseDisplay()); + assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue()); + + concept = termValueSet.getConcepts().get(23); + ourLog.info("Concept:\n" + concept.toString()); + assertEquals("http://acme.org", concept.getSystem()); + assertEquals("8492-1", concept.getCode()); + assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay()); + assertEquals(0, concept.getDesignations().size()); + assertEquals(23, concept.getOrder()); + }); + } + @Test public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception { loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);