diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5603-is-a-descendent-of.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5603-is-a-descendent-of.yaml new file mode 100644 index 000000000000..1c8244a07ee5 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5603-is-a-descendent-of.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5603 +jira: SMILE-8000 +title: "Previously, the semantics of `is-a` were incorrect in Valueset Expansion. The implementation previously used the behaviour of `descendent-of`, which means that `A is-a A` was not being considered as true. This has been corrected. In addition, +`descendent-of` is now supported, which compares for strict descendency, and does not include itself. Thanks to Ole Hedegaard (@ohetrifork) for the fix." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/upgrade.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/upgrade.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/version.yaml new file mode 100644 index 000000000000..9e4b8d89de0d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/version.yaml @@ -0,0 +1,3 @@ +--- +release-date: "2023-05-18" +codename: "Borealis" diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java index 4c3420ea4eaa..86235e0403be 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java @@ -1598,6 +1598,16 @@ private void handleFilterConceptAndCode( TermConcept code = findCodeForFilterCriteria(theSystem, theFilter); if (theFilter.getOp() == ValueSet.FilterOperator.ISA) { + ourLog.debug( + " * Filtering on specific code and codes with a parent of {}/{}/{}", + code.getId(), + code.getCode(), + code.getDisplay()); + + b.must(f.bool() + .should(f.match().field("myParentPids").matching("" + code.getId())) + .should(f.match().field("myId").matching(code.getId()))); + } else if (theFilter.getOp() == ValueSet.FilterOperator.DESCENDENTOF) { ourLog.debug( " * Filtering on codes with a parent of {}/{}/{}", code.getId(), code.getCode(), code.getDisplay()); diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithElasticSearchIT.java b/hapi-fhir-jpaserver-elastic-test-utilities/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithElasticSearchIT.java index a17f61fe13e2..615f5d9e1652 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithElasticSearchIT.java +++ b/hapi-fhir-jpaserver-elastic-test-utilities/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchWithElasticSearchIT.java @@ -786,7 +786,7 @@ public void testExpandWithIsAInExternalValueSet() { logAndValidateValueSet(result); ArrayList codes = toCodesContains(result.getExpansion().getContains()); - assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); } @Test diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java index d5c500e4b171..c5ac179edbe4 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3TerminologyTest.java @@ -313,7 +313,7 @@ public void testExpandWithCodesAndDisplayFilterBlank() { .setSystem(codeSystem.getUrl()) .addFilter() .setProperty("concept") - .setOp(FilterOperator.ISA) + .setOp(FilterOperator.DESCENDENTOF) .setValue("dogs"); myValueSetDao.create(valueSet, mySrd); @@ -504,7 +504,7 @@ public void testExpandWithIsAInExternalValueSet() { logAndValidateValueSet(result); ArrayList codes = toCodesContains(result.getExpansion().getContains()); - assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); } @@ -535,7 +535,7 @@ public void testExpandWithIsAInExternalValueSetReindex() { logAndValidateValueSet(result); ArrayList codes = toCodesContains(result.getExpansion().getContains()); - assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); } @@ -650,7 +650,7 @@ public void testIndexingIsDeferredForLargeCodeSystems() { ValueSet vs = new ValueSet(); ConceptSetComponent include = vs.getCompose().addInclude(); include.setSystem(URL_MY_CODE_SYSTEM); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); ValueSet result = myValueSetDao.expand(vs, null); logAndValidateValueSet(result); @@ -669,7 +669,7 @@ public void testIndexingIsDeferredForLargeCodeSystems() { vs = new ValueSet(); include = vs.getCompose().addInclude(); include.setSystem(URL_MY_CODE_SYSTEM); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); result = myValueSetDao.expand(vs, null); logAndValidateValueSet(result); diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetVersionedTest.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetVersionedTest.java index aeb4cc7328c6..98dd6fb4ec15 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetVersionedTest.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ValueSetVersionedTest.java @@ -230,7 +230,7 @@ private ValueSet createLocalVs(String theCodeSystemUrl, String theValueSetVersio ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(theCodeSystemUrl); include.setVersion(theValueSetVersion); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); return myLocalVs; } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java index 048e242d7002..789e11b60f11 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TerminologyTest.java @@ -353,7 +353,7 @@ public void testExpandWithCodesAndDisplayFilterBlank() { .setSystem(codeSystem.getUrl()) .addFilter() .setProperty("concept") - .setOp(FilterOperator.ISA) + .setOp(FilterOperator.DESCENDENTOF) .setValue("dogs"); myValueSetDao.create(valueSet, mySrd); @@ -584,7 +584,7 @@ public void testExpandWithIsAInExternalValueSet() { logAndValidateValueSet(result); ArrayList codes = toCodesContains(result.getExpansion().getContains()); - assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); } @@ -610,6 +610,34 @@ public void testExpandWithIsAInExternalValueSetReindex() { logAndValidateValueSet(result); ArrayList codes = toCodesContains(result.getExpansion().getContains()); + assertEquals(3, codes.size()); + assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB")); + + } + + @Test + public void testExpandWithDescendentOfInExternalValueSetReindex() { + TermReindexingSvcImpl.setForceSaveDeferredAlwaysForUnitTest(true); + + createExternalCsAndLocalVs(); + + myResourceReindexingSvc.markAllResourcesForReindexing(); + myResourceReindexingSvc.forceReindexingPass(); + myResourceReindexingSvc.forceReindexingPass(); + myTerminologyDeferredStorageSvc.saveDeferred(); + myTerminologyDeferredStorageSvc.saveDeferred(); + myTerminologyDeferredStorageSvc.saveDeferred(); + + ValueSet vs = new ValueSet(); + ConceptSetComponent include = vs.getCompose().addInclude(); + include.setSystem(TermTestUtil.URL_MY_CODE_SYSTEM); + include.addFilter().setOp(FilterOperator.DESCENDENTOF).setValue("childAA").setProperty("concept"); + + ValueSet result = myValueSetDao.expand(vs, null); // breakpoint + logAndValidateValueSet(result); + + ArrayList codes = toCodesContains(result.getExpansion().getContains()); + assertEquals(2, codes.size()); assertThat(codes, containsInAnyOrder("childAAA", "childAAB")); } @@ -795,7 +823,7 @@ public void testIndexingIsDeferredForLargeCodeSystems() { ValueSet vs = new ValueSet(); ConceptSetComponent include = vs.getCompose().addInclude(); include.setSystem(TermTestUtil.URL_MY_CODE_SYSTEM); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); ValueSet result = myValueSetDao.expand(vs, null); logAndValidateValueSet(result); @@ -814,7 +842,7 @@ public void testIndexingIsDeferredForLargeCodeSystems() { vs = new ValueSet(); include = vs.getCompose().addInclude(); include.setSystem(TermTestUtil.URL_MY_CODE_SYSTEM); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); result = myValueSetDao.expand(vs, null); logAndValidateValueSet(result); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetNoVerCSNoVerTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetNoVerCSNoVerTest.java index 2ab6dd76bf74..a3e9614ff32f 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetNoVerCSNoVerTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetNoVerCSNoVerTest.java @@ -202,7 +202,7 @@ private void createLocalVsForCodeSystem(CodeSystem codeSystem) { myLocalVs.setUrl(URL_MY_VALUE_SET); ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(codeSystem.getUrl()); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless(); } @@ -1199,7 +1199,7 @@ private void createHierarchicalVs() { .setSystem(URL_MY_CODE_SYSTEM) .addFilter() .setProperty("concept") - .setOp(FilterOperator.ISA) + .setOp(FilterOperator.DESCENDENTOF) .setValue("A"); myLocalVs .getCompose() diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSNoVerTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSNoVerTest.java index 7b56df6dbc80..cb8de80537b5 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSNoVerTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSNoVerTest.java @@ -167,7 +167,7 @@ private void createLocalVsForCodeSystem(CodeSystem codeSystem) { myLocalVs.setUrl(URL_MY_VALUE_SET); ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(codeSystem.getUrl()); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless(); } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSVerTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSVerTest.java index cc8d09d8ff79..f10efb5b1f6e 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSVerTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ValueSetVerCSVerTest.java @@ -196,7 +196,7 @@ private ValueSet createLocalVs(String theCodeSystemUrl, String theValueSetVersio ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(theCodeSystemUrl); include.setVersion(theValueSetVersion); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); return myLocalVs; } diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetTest.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetTest.java index f5f882e38fff..9df23b883144 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetTest.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetTest.java @@ -208,7 +208,7 @@ private void createLocalVs(CodeSystem codeSystem) { myLocalVs.setUrl(URL_MY_VALUE_SET); ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(codeSystem.getUrl()); - include.addFilter().setProperty("concept").setOp(Enumerations.FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(Enumerations.FilterOperator.DESCENDENTOF).setValue("ParentA"); myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless(); } diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetVersionedTest.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetVersionedTest.java index 824384e57c47..c7af44cab70a 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetVersionedTest.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ValueSetVersionedTest.java @@ -231,7 +231,7 @@ private ValueSet createLocalVs(String theCodeSystemUrl, String theValueSetVersio ConceptSetComponent include = myLocalVs.getCompose().addInclude(); include.setSystem(theCodeSystemUrl); include.setVersion(theValueSetVersion); - include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("ParentA"); + include.addFilter().setProperty("concept").setOp(FilterOperator.DESCENDENTOF).setValue("ParentA"); return myLocalVs; } diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/api/BaseChannelSettings.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/api/BaseChannelSettings.java index 29a4b6d086e9..0776d1b8bb30 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/api/BaseChannelSettings.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/api/BaseChannelSettings.java @@ -26,6 +26,9 @@ public abstract class BaseChannelSettings implements IChannelSettings { private ChannelRetryConfiguration myRetryConfigurationParameters; + // init true to match previous behaviour + private boolean myUseJacksonMessageConverter = true; + /** * Default true. Used by IChannelNamer to decide how to qualify the channel name. */