From e67a750c4f5a152c95b9ccf1c1a8f534fc84bb06 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Wed, 28 Aug 2019 18:49:18 -0400 Subject: [PATCH 01/11] validate-code operation now works with client-assigned IDs; added a bunch of failing tests to work on tomorrow. --- .../jpa/dao/data/ITermValueSetConceptDao.java | 4 +- .../jpa/term/BaseHapiTerminologySvcImpl.java | 23 +- .../jpa/term/HapiTerminologySvcDstu3.java | 24 +- .../fhir/jpa/term/HapiTerminologySvcR5.java | 5 +- .../jpa/term/TerminologySvcImplR4Test.java | 1028 +++++++++++++++-- 5 files changed, 981 insertions(+), 103 deletions(-) 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/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 2e3324b8719..065bdcba08c 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 @@ -145,6 +145,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; @@ -964,24 +965,24 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, 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(); + ResourceTable resource = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); + Long resourcePid = resource.getId(); List concepts = new ArrayList<>(); if (isNotBlank(theCode)) { if (isNotBlank(theSystem)) { - concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theSystem, theCode); + concepts.addAll(findByValueSetResourcePidSystemAndCode(resourcePid, theSystem, theCode)); } else { - concepts = myValueSetConceptDao.findOneByValueSetIdAndCode(valueSetId, theCode); + concepts.addAll(myValueSetConceptDao.findByValueSetResourcePidAndCode(resourcePid, theCode)); } } else if (theCoding != null) { if (theCoding.hasSystem() && theCoding.hasCode()) { - concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theCoding.getSystem(), theCoding.getCode()); + concepts.addAll(findByValueSetResourcePidSystemAndCode(resourcePid, 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(resourcePid, coding.getSystem(), coding.getCode())); if (!concepts.isEmpty()) { break; } @@ -1002,6 +1003,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(); @@ -1467,6 +1477,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); } 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..01e07e2706a 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 @@ -365,23 +365,17 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen @Override public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) { 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 = 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(); - 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); + 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())); } + + return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); } } 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..89f12cb4c45 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 @@ -10,8 +10,8 @@ import ca.uhn.fhir.util.UrlUtil; 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,7 +291,8 @@ 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); + 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()); 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..f12f8ad4a8e 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; @@ -117,71 +118,118 @@ 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); + } } - 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); + } } @Test @@ -511,7 +559,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 +626,41 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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(); + 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(valueSet.getIdElement().toUnqualifiedVersionless().getIdPartAsLong()).isPresent()); + } + }); + } + + @Test + public void testDeleteValueSetWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -599,22 +692,22 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { @Test public void testDuplicateCodeSystemUrls() throws Exception { - loadAndPersistCodeSystem(); + 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(); + loadAndPersistCodeSystem(HttpVerb.POST); } @Test public void testDuplicateConceptMapUrls() { - createAndPersistConceptMap(); + 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(); + createAndPersistConceptMap(HttpVerb.POST); } @Test @@ -622,19 +715,94 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myDaoConfig.setPreExpandValueSetsExperimental(true); // DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail. - loadAndPersistCodeSystemAndValueSet(); + 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(); + loadAndPersistValueSet(HttpVerb.POST); } @Test public void testExpandTermValueSetAndChildren() throws Exception { myDaoConfig.setPreExpandValueSetsExperimental(true); - loadAndPersistCodeSystemAndValueSetWithDesignations(); + 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.preExpandValueSetToTerminologyTables(); + + 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 testExpandTermValueSetAndChildrenWithClientAssignedId() throws Exception { + myDaoConfig.setPreExpandValueSetsExperimental(true); + + loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT); CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId); ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem)); @@ -709,7 +877,76 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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)); @@ -778,7 +1015,35 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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)); @@ -806,7 +1071,68 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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)); @@ -867,7 +1193,62 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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)); @@ -932,7 +1313,74 @@ 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)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(myExtensionalCsId.getIdPartAsLong()); + 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)); @@ -1096,7 +1544,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 +1902,105 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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.preExpandValueSetToTerminologyTables(); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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)); @@ -1374,7 +2098,105 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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.preExpandValueSetToTerminologyTables(); + + runInTransaction(()->{ + Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsId.getIdPartAsLong()); + 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)); @@ -1470,7 +2292,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 +2346,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 +2420,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 +2473,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 +2541,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 +2589,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 +2649,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 +2719,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 +2767,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 +2827,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 +2897,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 +2967,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 +3016,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 +3039,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 +3095,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 +3144,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 +3193,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 +3251,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 +3311,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 +3369,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 +3440,57 @@ 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)); + + ValueSet valueSet = myValueSetDao.read(myExtensionalVsId); + ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet)); + + myTermSvc.preExpandValueSetToTerminologyTables(); + + 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)); From c22bf8b09fa2ef7bcd96eb5f5bdbd5091a319c74 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Thu, 29 Aug 2019 10:48:54 -0400 Subject: [PATCH 02/11] Fixed handling of client-assigned IDs throughout terminology services. --- .../jpa/term/BaseHapiTerminologySvcImpl.java | 14 ++++---- .../jpa/term/TerminologySvcImplDstu3Test.java | 3 +- .../jpa/term/TerminologySvcImplR4Test.java | 35 +++++++++++-------- 3 files changed, 29 insertions(+), 23 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 065bdcba08c..23b3bf33fef 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 @@ -487,7 +487,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, Optional optionalTermValueSet; if (theValueSetToExpand.hasId()) { - optionalTermValueSet = myValueSetDao.findByResourcePid(theValueSetToExpand.getIdElement().getIdPartAsLong()); + Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSetToExpand); + optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); } else if (theValueSetToExpand.hasUrl()) { optionalTermValueSet = myValueSetDao.findByUrl(theValueSetToExpand.getUrl()); } else { @@ -965,24 +966,23 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) { ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet.hasId(), "ValueSet.id is required"); - ResourceTable resource = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); - Long resourcePid = resource.getId(); + Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSet); List concepts = new ArrayList<>(); if (isNotBlank(theCode)) { if (isNotBlank(theSystem)) { - concepts.addAll(findByValueSetResourcePidSystemAndCode(resourcePid, theSystem, theCode)); + concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, theSystem, theCode)); } else { - concepts.addAll(myValueSetConceptDao.findByValueSetResourcePidAndCode(resourcePid, theCode)); + concepts.addAll(myValueSetConceptDao.findByValueSetResourcePidAndCode(valueSetResourcePid, theCode)); } } else if (theCoding != null) { if (theCoding.hasSystem() && theCoding.hasCode()) { - concepts.addAll(findByValueSetResourcePidSystemAndCode(resourcePid, 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.addAll(findByValueSetResourcePidSystemAndCode(resourcePid, coding.getSystem(), coding.getCode())); + concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, coding.getSystem(), coding.getCode())); if (!concepts.isEmpty()) { break; } 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..12253ff265e 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 @@ -1,6 +1,7 @@ package ca.uhn.fhir.jpa.term; import ca.uhn.fhir.jpa.dao.DaoConfig; +import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; @@ -600,7 +601,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong()); + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(IDao.RESOURCE_PID.get(codeSystemResource)); 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 f12f8ad4a8e..20c197cc74e 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 @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term; import ca.uhn.fhir.context.support.IContextValidationSupport; import ca.uhn.fhir.jpa.dao.DaoConfig; +import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.entity.*; @@ -53,6 +54,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() { @@ -195,6 +198,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { default: throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); } + myExtensionalCsIdOnResourceTable = myCodeSystemDao.readEntity(myExtensionalCsId, null).getId(); } private void loadAndPersistValueSet(HttpVerb theVerb) throws IOException { @@ -230,6 +234,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { default: throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); } + myExtensionalVsIdOnResourceTable = myValueSetDao.readEntity(myExtensionalVsId, null).getId(); } @Test @@ -639,7 +644,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { 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()); @@ -651,7 +656,7 @@ 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()); } }); } @@ -673,7 +678,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { 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()); @@ -685,7 +690,7 @@ 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()); } }); } @@ -1321,7 +1326,7 @@ 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()); @@ -1388,7 +1393,7 @@ 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()); @@ -1454,7 +1459,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong()); + TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(IDao.RESOURCE_PID.get(codeSystemResource)); assertEquals(CS_URL, codeSystem.getCodeSystemUri()); assertEquals("SYSTEM NAME", codeSystem.getName()); @@ -1911,7 +1916,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"); @@ -1929,7 +1934,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandValueSetToTerminologyTables(); 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"); @@ -2009,7 +2014,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"); @@ -2027,7 +2032,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandValueSetToTerminologyTables(); 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"); @@ -2107,7 +2112,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"); @@ -2125,7 +2130,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandValueSetToTerminologyTables(); 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"); @@ -2205,7 +2210,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"); @@ -2223,7 +2228,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { myTermSvc.preExpandValueSetToTerminologyTables(); 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"); From e03d6a5d47fd77aa43665273583f0cefb62648eb Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Thu, 29 Aug 2019 18:09:30 -0400 Subject: [PATCH 03/11] Fixed handling of pre-expansion in light of pre-existing, non-pre-expanded ValueSets. --- .../ca/uhn/fhir/i18n/hapi-messages.properties | 3 +- .../dstu3/FhirResourceDaoValueSetDstu3.java | 2 +- .../jpa/dao/r4/FhirResourceDaoValueSetR4.java | 2 +- .../jpa/dao/r5/FhirResourceDaoValueSetR5.java | 2 +- .../jpa/term/BaseHapiTerminologySvcImpl.java | 64 +++++-- .../jpa/term/HapiTerminologySvcDstu2.java | 5 + .../jpa/term/HapiTerminologySvcDstu3.java | 7 + .../fhir/jpa/term/HapiTerminologySvcR4.java | 6 + .../fhir/jpa/term/HapiTerminologySvcR5.java | 7 + .../fhir/jpa/term/IHapiTerminologySvc.java | 9 +- .../dao/r4/FhirResourceDaoR4ValueSetTest.java | 63 ++++++- .../jpa/term/TerminologySvcImplR4Test.java | 168 ++++++++++++++++-- 12 files changed, 294 insertions(+), 44 deletions(-) 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..29f36f8dfb1 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,7 +127,8 @@ 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.term.BaseHapiTerminologySvcImpl.valueSetNotReadyForExpand={0} is present in terminology tables but not ready for persistence-backed invocation of operation $expand. Will perform in-memory expansion without parameters. Current status: {1} | {2} +ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.valueSetNotReadyForValidateCode={0} is present in terminology tables but not ready for persistence-backed invocation of operation $validation-code. Will perform in-memory code validation. Current status: {1} | {2} ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1} 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/term/BaseHapiTerminologySvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java index 23b3bf33fef..b5d67196547 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 @@ -496,12 +496,26 @@ 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) { + String statusMsg = myContext.getLocalizer().getMessage( + TermValueSetPreExpansionStatusEnum.class, + termValueSet.getExpansionStatus().getCode()); + String msg = myContext.getLocalizer().getMessage( + BaseHapiTerminologySvcImpl.class, + "valueSetNotReadyForExpand", + getValueSetInfo(theValueSetToExpand), + termValueSet.getExpansionStatus().name(), + statusMsg); + ourLog.warn(msg); + return expandValueSet(theValueSetToExpand); // In-memory expansion. + } ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent(); expansionComponent.setIdentifier(UUID.randomUUID().toString()); @@ -516,20 +530,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); @@ -962,6 +962,36 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, } } + @Override + public boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet) { + Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSet); + 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) { + String statusMsg = myContext.getLocalizer().getMessage( + TermValueSetPreExpansionStatusEnum.class, + termValueSet.getExpansionStatus().getCode()); + String msg = myContext.getLocalizer().getMessage( + BaseHapiTerminologySvcImpl.class, + "valueSetNotReadyForValidateCode", + getValueSetInfo(theValueSet), + termValueSet.getExpansionStatus().name(), + statusMsg); + ourLog.warn(msg); + return false; + } + + return true; + } + protected ValidateCodeResult validateCodeIsInPreExpandedValueSet( ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) { @@ -1810,7 +1840,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 01e07e2706a..e0cefaa1a07 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 @@ -378,4 +378,11 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + 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 89f12cb4c45..1064ad04fd9 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 @@ -305,4 +305,11 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4); } + + @Override + public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) { + 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/term/TerminologySvcImplR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java index 20c197cc74e..261ea694ca5 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 @@ -639,7 +639,7 @@ 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)); @@ -673,7 +673,7 @@ 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)); @@ -740,7 +740,7 @@ 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)); @@ -803,6 +803,138 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { 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); @@ -815,7 +947,7 @@ 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)); @@ -890,7 +1022,7 @@ 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)); @@ -959,7 +1091,7 @@ 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)); @@ -1028,7 +1160,7 @@ 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)); @@ -1056,7 +1188,7 @@ 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)); @@ -1084,7 +1216,7 @@ 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)); @@ -1145,7 +1277,7 @@ 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)); @@ -1206,7 +1338,7 @@ 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)); @@ -1261,7 +1393,7 @@ 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)); @@ -1931,7 +2063,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); @@ -2029,7 +2161,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); @@ -2127,7 +2259,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); @@ -2225,7 +2357,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus()); }); - myTermSvc.preExpandValueSetToTerminologyTables(); + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); runInTransaction(()->{ Optional optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable); @@ -3453,7 +3585,7 @@ 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); @@ -3503,7 +3635,7 @@ 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); From 8ef9c61b8398812ca4b2d7be88261bba4acf4382 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Fri, 30 Aug 2019 10:47:21 -0400 Subject: [PATCH 04/11] Address review comments; improve logging. --- .../ca/uhn/fhir/i18n/hapi-messages.properties | 7 ------ .../TermValueSetPreExpansionStatusEnum.java | 18 +++++++++----- .../jpa/term/BaseHapiTerminologySvcImpl.java | 24 ++++--------------- ...ermValueSetPreExpansionStatusEnumTest.java | 21 ---------------- 4 files changed, 16 insertions(+), 54 deletions(-) delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermValueSetPreExpansionStatusEnumTest.java 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 29f36f8dfb1..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,12 +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={0} is present in terminology tables but not ready for persistence-backed invocation of operation $expand. Will perform in-memory expansion without parameters. Current status: {1} | {2} -ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.valueSetNotReadyForValidateCode={0} is present in terminology tables but not ready for persistence-backed invocation of operation $validation-code. Will perform in-memory code validation. Current status: {1} | {2} 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/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 b5d67196547..ed8c94a000c 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 @@ -504,16 +504,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, TermValueSet termValueSet = optionalTermValueSet.get(); if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) { - String statusMsg = myContext.getLocalizer().getMessage( - TermValueSetPreExpansionStatusEnum.class, - termValueSet.getExpansionStatus().getCode()); - String msg = myContext.getLocalizer().getMessage( - BaseHapiTerminologySvcImpl.class, - "valueSetNotReadyForExpand", - getValueSetInfo(theValueSetToExpand), - termValueSet.getExpansionStatus().name(), - statusMsg); - ourLog.warn(msg); + 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. } @@ -976,16 +968,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, TermValueSet termValueSet = optionalTermValueSet.get(); if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) { - String statusMsg = myContext.getLocalizer().getMessage( - TermValueSetPreExpansionStatusEnum.class, - termValueSet.getExpansionStatus().getCode()); - String msg = myContext.getLocalizer().getMessage( - BaseHapiTerminologySvcImpl.class, - "valueSetNotReadyForValidateCode", - getValueSetInfo(theValueSet), - termValueSet.getExpansionStatus().name(), - statusMsg); - ourLog.warn(msg); + 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; } 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); - } - } - } -} From f29abd716733537bfe77de961c46652c78a96aad Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Fri, 30 Aug 2019 19:31:05 -0400 Subject: [PATCH 05/11] Fixed ResourceTable lookups for pre-expansion and code validation. --- .../main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java | 2 +- .../fhir/jpa/term/BaseHapiTerminologySvcImpl.java | 14 +++++++++----- .../fhir/jpa/term/TerminologySvcImplDstu3Test.java | 5 +++-- .../fhir/jpa/term/TerminologySvcImplR4Test.java | 5 +++-- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index 7a7f588a72f..6f3bac4aba6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -149,7 +149,7 @@ public class DaoConfig { /** * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}! */ - private boolean myPreExpandValueSetsExperimental = false; + private boolean myPreExpandValueSetsExperimental = true; private boolean myFilterParameterEnabled = false; private StoreMetaSourceInformation myStoreMetaSourceInformation = StoreMetaSourceInformation.SOURCE_URI_AND_REQUEST_ID; /** 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 ed8c94a000c..8c8843c6ee9 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 @@ -487,7 +487,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, Optional optionalTermValueSet; if (theValueSetToExpand.hasId()) { - Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSetToExpand); + ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSetToExpand.getIdElement(), null); + Long valueSetResourcePid = resourceTable.getId(); optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); } else if (theValueSetToExpand.hasUrl()) { optionalTermValueSet = myValueSetDao.findByUrl(theValueSetToExpand.getUrl()); @@ -956,7 +957,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override public boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet) { - Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSet); + ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); + Long valueSetResourcePid = resourceTable.getId(); Optional optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); if (!optionalTermValueSet.isPresent()) { @@ -980,7 +982,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) { ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet.hasId(), "ValueSet.id is required"); - Long valueSetResourcePid = IDao.RESOURCE_PID.get(theValueSet); + ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); + Long valueSetResourcePid = resourceTable.getId(); List concepts = new ArrayList<>(); if (isNotBlank(theCode)) { @@ -1625,7 +1628,8 @@ 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); + ResourceTable resourceTable = (ResourceTable) myCodeSystemResourceDao.readEntity(theCodeSystem.getIdElement(), null); + Long codeSystemResourcePid = resourceTable.getId(); TermCodeSystemVersion persCs = myCodeSystemVersionDao.findCurrentVersionForCodeSystemResourcePid(codeSystemResourcePid); if (persCs != null) { ourLog.info("Code system version already exists in database"); @@ -1822,7 +1826,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ourLog.info("Done storing TermConceptMap."); } - @Scheduled(fixedDelay = 600000) // 10 minutes. + @Scheduled(fixedDelay = 6000) // 10 minutes. @Override public synchronized void preExpandDeferredValueSetsToTerminologyTables() { if (isNotSafeToPreExpandValueSets()) { 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 12253ff265e..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 @@ -1,7 +1,6 @@ package ca.uhn.fhir.jpa.term; import ca.uhn.fhir.jpa.dao.DaoConfig; -import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test; import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; @@ -601,7 +600,9 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(IDao.RESOURCE_PID.get(codeSystemResource)); + 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 261ea694ca5..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 @@ -2,7 +2,6 @@ package ca.uhn.fhir.jpa.term; import ca.uhn.fhir.context.support.IContextValidationSupport; import ca.uhn.fhir.jpa.dao.DaoConfig; -import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.entity.*; @@ -1591,7 +1590,9 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus theStatus) { - TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(IDao.RESOURCE_PID.get(codeSystemResource)); + 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()); From 548647defeebdefdb5b6f75be38448ec386f9a4a Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Fri, 30 Aug 2019 19:31:45 -0400 Subject: [PATCH 06/11] Toggle pre-expansion config. --- .../src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index 6f3bac4aba6..7a7f588a72f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -149,7 +149,7 @@ public class DaoConfig { /** * EXPERIMENTAL - Do not use in production! Do not change default of {@code false}! */ - private boolean myPreExpandValueSetsExperimental = true; + private boolean myPreExpandValueSetsExperimental = false; private boolean myFilterParameterEnabled = false; private StoreMetaSourceInformation myStoreMetaSourceInformation = StoreMetaSourceInformation.SOURCE_URI_AND_REQUEST_ID; /** From 16963881b0cca028489cd0846fc7b78f35957f1a Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Fri, 30 Aug 2019 19:36:34 -0400 Subject: [PATCH 07/11] Reset pre-expansion schedule. --- .../java/ca/uhn/fhir/jpa/term/BaseHapiTerminologySvcImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8c8843c6ee9..8ca7a3bc03b 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 @@ -1826,7 +1826,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ourLog.info("Done storing TermConceptMap."); } - @Scheduled(fixedDelay = 6000) // 10 minutes. + @Scheduled(fixedDelay = 600000) // 10 minutes. @Override public synchronized void preExpandDeferredValueSetsToTerminologyTables() { if (isNotSafeToPreExpandValueSets()) { From 8ce8f1e86404d89a3e7e82d35450a2d6cf43e6eb Mon Sep 17 00:00:00 2001 From: James Agnew Date: Sun, 1 Sep 2019 18:41:17 -0400 Subject: [PATCH 08/11] Credit for #1461 --- pom.xml | 4 ++++ src/changes/changes.xml | 4 ++++ 2 files changed, 8 insertions(+) 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! + From 9ea937d0070c6c0a4b13b4d6559738f4edb1eed4 Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Tue, 27 Aug 2019 13:58:47 -0400 Subject: [PATCH 09/11] extra logging around send to subscription delivery channel --- .../SubscriptionMatchingSubscriber.java | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) 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(); } From c34d8458ef6c4ee811cdba5a5bf374d312c9f6cf Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Mon, 2 Sep 2019 18:16:46 -0400 Subject: [PATCH 10/11] Refactor getting resource PIDs with utility methods. --- .../jpa/term/BaseHapiTerminologySvcImpl.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 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 8ca7a3bc03b..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.*; @@ -487,8 +488,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, Optional optionalTermValueSet; if (theValueSetToExpand.hasId()) { - ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSetToExpand.getIdElement(), null); - Long valueSetResourcePid = resourceTable.getId(); + Long valueSetResourcePid = getValueSetResourcePid(theValueSetToExpand.getIdElement()); optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); } else if (theValueSetToExpand.hasUrl()) { optionalTermValueSet = myValueSetDao.findByUrl(theValueSetToExpand.getUrl()); @@ -957,8 +957,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, @Override public boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet) { - ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); - Long valueSetResourcePid = resourceTable.getId(); + Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement()); Optional optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid); if (!optionalTermValueSet.isPresent()) { @@ -982,8 +981,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc, ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) { ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet.hasId(), "ValueSet.id is required"); - ResourceTable resourceTable = (ResourceTable) myValueSetResourceDao.readEntity(theValueSet.getIdElement(), null); - Long valueSetResourcePid = resourceTable.getId(); + Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement()); List concepts = new ArrayList<>(); if (isNotBlank(theCode)) { @@ -1161,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; @@ -1628,8 +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()); - ResourceTable resourceTable = (ResourceTable) myCodeSystemResourceDao.readEntity(theCodeSystem.getIdElement(), null); - Long codeSystemResourcePid = resourceTable.getId(); + Long codeSystemResourcePid = getCodeSystemResourcePid(theCodeSystem.getIdElement()); TermCodeSystemVersion persCs = myCodeSystemVersionDao.findCurrentVersionForCodeSystemResourcePid(codeSystemResourcePid); if (persCs != null) { ourLog.info("Code system version already exists in database"); From 02a896f31e385825a584f8293a8523cb96220339 Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Mon, 2 Sep 2019 21:28:51 -0400 Subject: [PATCH 11/11] Fix NPE for ValueSet operation validate-code when Coding and/or CodeableConcept is null for DSTU3/R5. --- .../fhir/jpa/term/HapiTerminologySvcDstu3.java | 17 +++++++++++++---- .../uhn/fhir/jpa/term/HapiTerminologySvcR5.java | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) 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 e0cefaa1a07..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,16 +365,23 @@ 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 = 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); @@ -381,6 +389,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen @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/HapiTerminologySvcR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR5.java index 1064ad04fd9..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,6 +7,7 @@ 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; @@ -291,16 +292,23 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements @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 = 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); @@ -308,6 +316,7 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements @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);