From 7f62d60c4e9ab43f3ae0cf4aba7015da9bcad90f Mon Sep 17 00:00:00 2001 From: James Agnew Date: Wed, 30 Oct 2019 14:26:31 -0400 Subject: [PATCH] Correctly Expand ValueSets in non-lucene mode --- .../fhir/jpa/term/BaseTermReadSvcImpl.java | 41 ++++++++++------- .../term/TermCodeSystemStorageSvcImpl.java | 28 ++++++------ .../FhirResourceDaoDstu3ValidateTest.java | 27 ++++++++++++ ...urceDaoR4SearchWithLuceneDisabledTest.java | 44 ++++++++++++++++--- .../dao/r4/FhirResourceDaoR4ValidateTest.java | 2 + .../iar/CodeSystem-iar-citizenship-status.xml | 34 ++++++++++++++ .../iar/ValueSet-iar-citizenship-status.xml | 36 +++++++++++++++ src/changes/changes.xml | 5 +++ 8 files changed, 181 insertions(+), 36 deletions(-) create mode 100644 hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/CodeSystem-iar-citizenship-status.xml create mode 100644 hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/ValueSet-iar-citizenship-status.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java index de6fc3a1a65..da789f46403 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java @@ -424,13 +424,13 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo private void logConceptsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theConceptsExpanded) { if (theConceptsExpanded > 0) { - ourLog.info("{}Have expanded {} concepts in ValueSet[{}]", theLogDescriptionPrefix, theConceptsExpanded, theTermValueSet.getUrl()); + ourLog.debug("{}Have expanded {} concepts in ValueSet[{}]", theLogDescriptionPrefix, theConceptsExpanded, theTermValueSet.getUrl()); } } private void logDesignationsExpanded(String theLogDescriptionPrefix, TermValueSet theTermValueSet, int theDesignationsExpanded) { if (theDesignationsExpanded > 0) { - ourLog.info("{}Have expanded {} designations in ValueSet[{}]", theLogDescriptionPrefix, theDesignationsExpanded, theTermValueSet.getUrl()); + ourLog.debug("{}Have expanded {} designations in ValueSet[{}]", theLogDescriptionPrefix, theDesignationsExpanded, theTermValueSet.getUrl()); } } @@ -446,7 +446,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo StopWatch sw = new StopWatch(); String valueSetInfo = getValueSetInfo(theValueSetToExpand); - ourLog.info("Working with {}", valueSetInfo); + ourLog.debug("Working with {}", valueSetInfo); // Handle includes ourLog.debug("Handling includes"); @@ -488,7 +488,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo myTxTemplate.execute(t -> ((ValueSetConceptAccumulator) theValueSetCodeAccumulator).removeGapsFromConceptOrder()); } - ourLog.info("Done working with {} in {}ms", valueSetInfo, sw.getMillis()); + ourLog.debug("Done working with {} in {}ms", valueSetInfo, sw.getMillis()); } private String getValueSetInfo(ValueSet theValueSet) { @@ -553,7 +553,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo return false; } - ourLog.info("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system); + ourLog.debug("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system); TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system); if (cs != null) { @@ -566,7 +566,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo * since we're going to do it without the database. */ if (myFulltextSearchSvc == null) { - expandWithoutHibernateSearch(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, system, theAdd, theCodeCounter); + expandWithoutHibernateSearch(theValueSetCodeAccumulator, csv, theAddedCodes, theIncludeOrExclude, system, theAdd, theCodeCounter); return false; } @@ -642,7 +642,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo jpaQuery.setMaxResults(maxResultsPerBatch); jpaQuery.setFirstResult(theQueryIndex * maxResultsPerBatch); - ourLog.info("Beginning batch expansion for {} with max results per batch: {}", (theAdd ? "inclusion" : "exclusion"), maxResultsPerBatch); + ourLog.debug("Beginning batch expansion for {} with max results per batch: {}", (theAdd ? "inclusion" : "exclusion"), maxResultsPerBatch); StopWatch swForBatch = new StopWatch(); AtomicInteger countForBatch = new AtomicInteger(0); @@ -661,10 +661,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo } } - ourLog.info("Batch expansion for {} with starting index of {} produced {} results in {}ms", (theAdd ? "inclusion" : "exclusion"), firstResult, countForBatch, swForBatch.getMillis()); + ourLog.debug("Batch expansion for {} with starting index of {} produced {} results in {}ms", (theAdd ? "inclusion" : "exclusion"), firstResult, countForBatch, swForBatch.getMillis()); if (resultsInBatch < maxResultsPerBatch) { - ourLog.info("Expansion for {} produced {} results in {}ms", (theAdd ? "inclusion" : "exclusion"), count, sw.getMillis()); + ourLog.debug("Expansion for {} produced {} results in {}ms", (theAdd ? "inclusion" : "exclusion"), count, sw.getMillis()); return false; } else { return true; @@ -712,7 +712,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo } else if (hasValueSet) { for (CanonicalType nextValueSet : theIncludeOrExclude.getValueSet()) { - ourLog.info("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString()); + ourLog.debug("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString()); List expanded = expandValueSet(nextValueSet.getValueAsString()); Map uriToCodeSystem = new HashMap<>(); @@ -848,7 +848,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo .orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue())); if (theFilter.getOp() == ValueSet.FilterOperator.ISA) { - ourLog.info(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay()); + ourLog.debug(" * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay()); theBool.must(theQb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery()); } else { throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); @@ -1015,7 +1015,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo } private void logFilteringValueOnProperty(String theValue, String theProperty) { - ourLog.info(" * Filtering with value={} on property {}", theValue, theProperty); + ourLog.debug(" * Filtering with value={} on property {}", theValue, theProperty); } private void throwInvalidRequestForOpOnProperty(ValueSet.FilterOperator theOp, String theProperty) { @@ -1060,7 +1060,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo } } - private void expandWithoutHibernateSearch(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) { + private void expandWithoutHibernateSearch(IValueSetConceptAccumulator theValueSetCodeAccumulator, TermCodeSystemVersion theVersion, Set theAddedCodes, ValueSet.ConceptSetComponent theInclude, String theSystem, boolean theAdd, AtomicInteger theCodeCounter) { ourLog.trace("Hibernate search is not enabled"); if (theValueSetCodeAccumulator instanceof ValueSetExpansionComponentWithConceptAccumulator) { Validate.isTrue(((ValueSetExpansionComponentWithConceptAccumulator) theValueSetCodeAccumulator).getParameter().isEmpty(), "Can not expand ValueSet with parameters - Hibernate Search is not enabled on this server."); @@ -1068,12 +1068,21 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo Validate.isTrue(theInclude.getFilter().isEmpty(), "Can not expand ValueSet with filters - Hibernate Search is not enabled on this server."); Validate.isTrue(isNotBlank(theSystem), "Can not expand ValueSet without explicit system - Hibernate Search is not enabled on this server."); + + if (theInclude.getConcept().isEmpty()) { + for (TermConcept next : theVersion.getConcepts()) { + addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, null, theAdd, theCodeCounter, theSystem, next.getCode(), next.getDisplay()); + } + } + for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) { if (!theSystem.equals(theInclude.getSystem())) { continue; } addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, null, theAdd, theCodeCounter, theSystem, next.getCode(), next.getDisplay()); } + + } @Override @@ -1215,7 +1224,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo fetchParents(concept.get(), retVal); - ourLog.info("Fetched {} codes above code {} in {}ms", retVal.size(), theCode, stopwatch.getMillis()); + ourLog.debug("Fetched {} codes above code {} in {}ms", retVal.size(), theCode, stopwatch.getMillis()); return retVal; } @@ -1246,7 +1255,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo fetchChildren(concept.get(), retVal); - ourLog.info("Fetched {} codes below code {} in {}ms", retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS)); + ourLog.debug("Fetched {} codes below code {} in {}ms", retVal.size(), theCode, stopwatch.elapsed(TimeUnit.MILLISECONDS)); return retVal; } @@ -1295,7 +1304,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo @Override @Transactional public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) { - ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); + ourLog.debug("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url"); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java index 3f328f9c10c..6974b7d68d9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java @@ -335,7 +335,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { populateCodeSystemVersionProperties(persCs, theCodeSystem, theResourceEntity); persCs.getConcepts().addAll(BaseTermReadSvcImpl.toPersistedConcepts(theCodeSystem.getConcept(), persCs)); - ourLog.info("Code system has {} concepts", persCs.getConcepts().size()); + ourLog.debug("Code system has {} concepts", persCs.getConcepts().size()); storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, theCodeSystem.getName(), theCodeSystem.getVersion(), persCs, theResourceEntity); } @@ -366,7 +366,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { @Override @Transactional(propagation = Propagation.REQUIRED) public void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, String theSystemName, String theSystemVersionId, TermCodeSystemVersion theCodeSystemVersion, ResourceTable theCodeSystemResourceTable) { - ourLog.info("Storing code system"); + ourLog.debug("Storing code system"); ValidateUtil.isTrueOrThrowInvalidRequest(theCodeSystemVersion.getResource() != null, "No resource supplied"); ValidateUtil.isNotBlankOrThrowInvalidRequest(theSystemUri, "No system URI supplied"); @@ -378,15 +378,15 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { * For now we always delete old versions. At some point it would be nice to allow configuration to keep old versions. */ - ourLog.info("Deleting old code system versions"); for (TermCodeSystemVersion next : existing) { + ourLog.info("Deleting old code system version {}", next.getPid()); Long codeSystemVersionPid = next.getPid(); deleteCodeSystemVersion(codeSystemVersionPid); } - ourLog.info("Flushing..."); + ourLog.debug("Flushing..."); myConceptDao.flush(); - ourLog.info("Done flushing"); + ourLog.debug("Done flushing"); /* * Do the upload @@ -399,7 +399,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { theCodeSystemVersion.setCodeSystemDisplayName(theSystemName); theCodeSystemVersion.setCodeSystemVersionId(theSystemVersionId); - ourLog.info("Validating all codes in CodeSystem for storage (this can take some time for large sets)"); + ourLog.debug("Validating all codes in CodeSystem for storage (this can take some time for large sets)"); // Validate the code system ArrayList conceptsStack = new ArrayList<>(); @@ -409,35 +409,33 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { totalCodeCount += validateConceptForStorage(next, theCodeSystemVersion, conceptsStack, allConcepts); } - ourLog.info("Saving version containing {} concepts", totalCodeCount); + ourLog.debug("Saving version containing {} concepts", totalCodeCount); TermCodeSystemVersion codeSystemVersion = myCodeSystemVersionDao.saveAndFlush(theCodeSystemVersion); - ourLog.info("Saving code system"); + ourLog.debug("Saving code system"); codeSystem.setCurrentVersion(theCodeSystemVersion); codeSystem = myCodeSystemDao.saveAndFlush(codeSystem); - ourLog.info("Setting CodeSystemVersion[{}] on {} concepts...", codeSystem.getPid(), totalCodeCount); + ourLog.debug("Setting CodeSystemVersion[{}] on {} concepts...", codeSystem.getPid(), totalCodeCount); for (TermConcept next : theCodeSystemVersion.getConcepts()) { populateVersion(next, codeSystemVersion); } - ourLog.info("Saving {} concepts...", totalCodeCount); + ourLog.debug("Saving {} concepts...", totalCodeCount); IdentityHashMap conceptsStack2 = new IdentityHashMap<>(); for (TermConcept next : theCodeSystemVersion.getConcepts()) { persistChildren(next, codeSystemVersion, conceptsStack2, totalCodeCount); } - ourLog.info("Done saving concepts, flushing to database"); + ourLog.debug("Done saving concepts, flushing to database"); myConceptDao.flush(); myConceptParentChildLinkDao.flush(); - ourLog.info("Done deleting old code system versions"); - if (myDeferredStorageSvc.isStorageQueueEmpty() == false) { ourLog.info("Note that some concept saving has been deferred"); } @@ -572,7 +570,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { // case for concepts being added to an existing child concept, but won't be the case when // we're recursively adding children) for (TermConcept nextParentConcept : parentConcepts) { - if (nextParentConcept.getChildren().stream().noneMatch(t->t.getChild().getCode().equals(nextCodeToAdd))) { + if (nextParentConcept.getChildren().stream().noneMatch(t -> t.getChild().getCode().equals(nextCodeToAdd))) { TermConceptParentChildLink parentLink = new TermConceptParentChildLink(); parentLink.setParent(nextParentConcept); parentLink.setChild(nextConceptToAdd); @@ -612,7 +610,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { return; } - if (theConceptsStack.size() == 1 || theConceptsStack.size() % 10000 == 0) { + if ((theConceptsStack.size() + 1) % 10000 == 0) { float pct = (float) theConceptsStack.size() / (float) theTotalConcepts; ourLog.info("Have processed {}/{} concepts ({}%)", theConceptsStack.size(), theTotalConcepts, (int) (pct * 100.0f)); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java index 8a4769e4157..3619811ca47 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java @@ -89,6 +89,33 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test { } + + @Test + public void testValidateQuestionnaireResponseWithValueSetIncludingCompleteCodeSystem() throws IOException { + CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/dstu3/iar/CodeSystem-iar-citizenship-status.xml"); + myCodeSystemDao.create(cs); + + ValueSet vs = loadResourceFromClasspath(ValueSet.class, "/dstu3/iar/ValueSet-iar-citizenship-status.xml"); + myValueSetDao.create(vs); + + ValueSet expansion = myValueSetDao.expandByIdentifier("http://ccim.on.ca/fhir/iar/ValueSet/iar-citizenship-status", null); + ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion)); + +// Questionnaire q = loadResourceFromClasspath(Questionnaire.class,"/dstu3/iar/Questionnaire-iar-test.xml" ); +// myQuestionnaireDao.create(q); +// +// +// +// Bundle bundleForValidation = loadResourceFromClasspath(Bundle.class, "/dstu3/iar/Bundle-for-validation.xml"); +// try { +// MethodOutcome outcome = myBundleDao.validate(bundleForValidation, null, null, null, null, null, null); +// ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome())); +// } catch (PreconditionFailedException e) { +// ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome())); +// } + } + + @After public void after() { FhirInstanceValidator val = AopTestUtils.getTargetObject(myValidatorModule); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithLuceneDisabledTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithLuceneDisabledTest.java index 5473e4f1eb6..f9402097f55 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithLuceneDisabledTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithLuceneDisabledTest.java @@ -4,17 +4,21 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc; import ca.uhn.fhir.jpa.config.TestR4WithLuceneDisabledConfig; import ca.uhn.fhir.jpa.dao.*; +import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest; import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; -import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.util.TestUtil; +import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; @@ -31,11 +35,13 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; - +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.List; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.any; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestR4WithLuceneDisabledConfig.class}) @@ -71,7 +77,7 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest { private IFhirResourceDao myCodeSystemDao; @Autowired @Qualifier("myValueSetDaoR4") - private IFhirResourceDao myValueSetDao; + private IFhirResourceDaoValueSet myValueSetDao; @Autowired @Qualifier("myObservationDaoR4") private IFhirResourceDao myObservationDao; @@ -219,6 +225,34 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest { } + protected T loadResourceFromClasspath(Class type, String resourceName) throws IOException { + InputStream stream = FhirResourceDaoDstu2SearchNoFtTest.class.getResourceAsStream(resourceName); + if (stream == null) { + fail("Unable to load resource: " + resourceName); + } + String string = IOUtils.toString(stream, StandardCharsets.UTF_8); + IParser newJsonParser = EncodingEnum.detectEncodingNoDefault(string).newParser(myFhirCtx); + return newJsonParser.parseResource(type, string); + } + + + /** + * A valueset that includes a whole system (i.e. no properties) should expand + */ + @Test + public void testExpandValueSetContainingSystemIncludeWithNoCodes() throws IOException { + CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/dstu3/iar/CodeSystem-iar-citizenship-status.xml"); + myCodeSystemDao.create(cs); + + ValueSet vs = loadResourceFromClasspath(ValueSet.class, "/dstu3/iar/ValueSet-iar-citizenship-status.xml"); + myValueSetDao.create(vs); + + ValueSet expansion = myValueSetDao.expandByIdentifier("http://ccim.on.ca/fhir/iar/ValueSet/iar-citizenship-status", null); + ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expansion)); + + assertEquals(4, expansion.getExpansion().getContains().size()); + + } @AfterClass diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java index d6316e86c50..4fbdbbdb0e8 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java @@ -730,6 +730,8 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test { assertEquals("The questionnaire \"Questionnaire/DOES_NOT_EXIST\" could not be resolved, so no validation can be performed against the base questionnaire", oo.getIssueFirstRep().getDiagnostics()); } + + private IBaseResource findResourceByIdInBundle(Bundle vss, String name) { IBaseResource retVal = null; for (BundleEntryComponent next : vss.getEntry()) { diff --git a/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/CodeSystem-iar-citizenship-status.xml b/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/CodeSystem-iar-citizenship-status.xml new file mode 100644 index 00000000000..db87c99a0d9 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/CodeSystem-iar-citizenship-status.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/ValueSet-iar-citizenship-status.xml b/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/ValueSet-iar-citizenship-status.xml new file mode 100644 index 00000000000..94e52a33812 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/resources/dstu3/iar/ValueSet-iar-citizenship-status.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ca77f971450..879181bbe5d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -480,6 +480,11 @@ JPA servers accidentally stripped the type attribute from the server-exported CapabilityStatement when search parameters of type "special" were found. This has been corrected. + + When running the JPA server without Lucene indexing enabled and performing ValueSet expansion, + the server would incorrectly ignore inclusion rules that specified a system but no codes (i.e. + include the whole system). This has been corrected. +