From b45ddcc3da1f03cfb07d38bcdbac8b62fe7a0f71 Mon Sep 17 00:00:00 2001 From: Kevin Dougan SmileCDR <72025369+KevinDougan-SmileCDR@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:45:49 -0400 Subject: [PATCH] 2543 - Fix issue where versionned references are not being returned properly. (#2544) * 2543 - Fix issue where versionned references are not being returned properly. * 2543 - Added changelog entries for this fix plus a previous fix for 2533. --- ...-not-being-returned-in-search-queries.yaml | 6 ++ ...ences-are-not-being-returned-properly.yaml | 8 ++ ...irResourceDaoR4VersionedReferenceTest.java | 78 +++++++++++++++++++ .../fhir/jpa/model/entity/ResourceLink.java | 4 + 4 files changed, 96 insertions(+) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2533-fix-issue-with-reference-resources-not-being-returned-in-search-queries.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2543-fix-issue-where-versionned-references-are-not-being-returned-properly.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2533-fix-issue-with-reference-resources-not-being-returned-in-search-queries.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2533-fix-issue-with-reference-resources-not-being-returned-in-search-queries.yaml new file mode 100644 index 00000000000..fae2c3de9a6 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2533-fix-issue-with-reference-resources-not-being-returned-in-search-queries.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 2533 +title: "When issuing a request for a specific Resource and also specifying an _include param, +the referenced resource is not returned when there is only 1 version of the referenced resource available. +When there are more than 1 versions available, the referenced resource is returned in the response bundle." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2543-fix-issue-where-versionned-references-are-not-being-returned-properly.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2543-fix-issue-where-versionned-references-are-not-being-returned-properly.yaml new file mode 100644 index 00000000000..aa180bb0423 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2543-fix-issue-where-versionned-references-are-not-being-returned-properly.yaml @@ -0,0 +1,8 @@ +--- +type: fix +issue: 2543 +title: "When issuing a request for a specific Resource and also specifying an _include param, +the proper historical referenced resource is not returned when there are more than 1 versions of the +referenced resource available, after the reference has been changed from the original version 1 to some other version. +When there are more than 1 versions available, and the referring resource had previously referred to version 1 +but now refers to version 4, the resource returned in the response bundle is for version 1." diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java index bda53b10805..ec689d1a673 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java @@ -444,6 +444,84 @@ public class FhirResourceDaoR4VersionedReferenceTest extends BaseJpaR4Test { assertEquals(conditionId.withVersion("1").getValue(), resources.get(1).getIdElement().getValue()); } + @Test + public void testSearchAndIncludeVersionedReference_WhenMultipleVersionsExist() { + HashSet refPaths = new HashSet(); + refPaths.add("Task.basedOn"); + myFhirCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(refPaths); + myModelConfig.setRespectVersionsForSearchIncludes(true); + myFhirCtx.getParserOptions().setStripVersionsFromReferences(false); + + // Create a Condition + Condition condition = new Condition(); + IIdType conditionId = myConditionDao.create(condition).getId().toUnqualified(); + + // Now, update the Condition 3 times to generate a 4th version of it + condition.setRecordedDate(new Date(System.currentTimeMillis())); + conditionId = myConditionDao.update(condition).getId(); + condition.setRecordedDate(new Date(System.currentTimeMillis() + 1000000)); + conditionId = myConditionDao.update(condition).getId(); + condition.setRecordedDate(new Date(System.currentTimeMillis() + 2000000)); + conditionId = myConditionDao.update(condition).getId(); + + // Create a Task which is basedOn that Condition + Task task = new Task(); + task.setBasedOn(Arrays.asList(new Reference(conditionId))); + IIdType taskId = myTaskDao.create(task).getId().toUnqualified(); + + // Search for the Task using an _include=Task.basedOn and make sure we get the Condition resource in the Response + IBundleProvider outcome = myTaskDao.search(SearchParameterMap.newSynchronous().addInclude(Task.INCLUDE_BASED_ON)); + assertEquals(2, outcome.size()); + List resources = outcome.getResources(0, 2); + assertEquals(2, resources.size(), resources.stream().map(t->t.getIdElement().toUnqualified().getValue()).collect(Collectors.joining(", "))); + assertEquals(taskId.getValue(), resources.get(0).getIdElement().getValue()); + assertEquals(conditionId.getValue(), ((Task)resources.get(0)).getBasedOn().get(0).getReference()); + assertEquals(conditionId.withVersion("4").getValue(), resources.get(1).getIdElement().getValue()); + } + + @Test + public void testSearchAndIncludeVersionedReference_WhenPreviouslyReferencedVersionOne() { + HashSet refPaths = new HashSet(); + refPaths.add("Task.basedOn"); + myFhirCtx.getParserOptions().setDontStripVersionsFromReferencesAtPaths(refPaths); + myModelConfig.setRespectVersionsForSearchIncludes(true); + myFhirCtx.getParserOptions().setStripVersionsFromReferences(false); + + // Create a Condition + Condition condition = new Condition(); + IIdType conditionId = myConditionDao.create(condition).getId().toUnqualified(); + ourLog.info("conditionId: \n{}", conditionId); + + // Create a Task which is basedOn that Condition + Task task = new Task(); + task.setBasedOn(Arrays.asList(new Reference(conditionId))); + IIdType taskId = myTaskDao.create(task).getId().toUnqualified(); + + // Now, update the Condition 3 times to generate a 4th version of it + condition.setRecordedDate(new Date(System.currentTimeMillis())); + conditionId = myConditionDao.update(condition).getId(); + ourLog.info("UPDATED conditionId: \n{}", conditionId); + condition.setRecordedDate(new Date(System.currentTimeMillis() + 1000000)); + conditionId = myConditionDao.update(condition).getId(); + ourLog.info("UPDATED conditionId: \n{}", conditionId); + condition.setRecordedDate(new Date(System.currentTimeMillis() + 2000000)); + conditionId = myConditionDao.update(condition).getId(); + ourLog.info("UPDATED conditionId: \n{}", conditionId); + + // Now, update the Task to refer to the latest version 4 of the Condition + task.setBasedOn(Arrays.asList(new Reference(conditionId))); + taskId = myTaskDao.update(task).getId(); + ourLog.info("UPDATED taskId: \n{}", taskId); + + // Search for the Task using an _include=Task.basedOn and make sure we get the Condition resource in the Response + IBundleProvider outcome = myTaskDao.search(SearchParameterMap.newSynchronous().addInclude(Task.INCLUDE_BASED_ON)); + assertEquals(2, outcome.size()); + List resources = outcome.getResources(0, 2); + assertEquals(2, resources.size(), resources.stream().map(t->t.getIdElement().toUnqualified().getValue()).collect(Collectors.joining(", "))); + assertEquals(taskId.getValue(), resources.get(0).getIdElement().getValue()); + assertEquals(conditionId.getValue(), ((Task)resources.get(0)).getBasedOn().get(0).getReference()); + assertEquals(conditionId.withVersion("4").getValue(), resources.get(1).getIdElement().getValue()); + } @Test public void testSearchAndIncludeUnersionedReference_Asynchronous() { diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceLink.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceLink.java index 98cf2561bfd..581c0de16b0 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceLink.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceLink.java @@ -138,6 +138,7 @@ public class ResourceLink extends BaseResourceIndex { b.append(mySourceResource, obj.mySourceResource); b.append(myTargetResourceUrl, obj.myTargetResourceUrl); b.append(myTargetResourceType, obj.myTargetResourceType); + b.append(myTargetResourceVersion, obj.myTargetResourceVersion); b.append(getTargetResourceId(), obj.getTargetResourceId()); return b.isEquals(); } @@ -150,6 +151,7 @@ public class ResourceLink extends BaseResourceIndex { myTargetResourceId = source.getTargetResourceId(); myTargetResourcePid = source.getTargetResourcePid(); myTargetResourceType = source.getTargetResourceType(); + myTargetResourceVersion = source.getTargetResourceVersion(); myTargetResourceUrl = source.getTargetResourceUrl(); } @@ -244,6 +246,7 @@ public class ResourceLink extends BaseResourceIndex { b.append(mySourcePath); b.append(mySourceResource); b.append(myTargetResourceUrl); + b.append(myTargetResourceVersion); b.append(getTargetResourceType()); b.append(getTargetResourceId()); return b.toHashCode(); @@ -257,6 +260,7 @@ public class ResourceLink extends BaseResourceIndex { b.append(", src=").append(mySourceResourcePid); b.append(", target=").append(myTargetResourcePid); b.append(", targetType=").append(myTargetResourceType); + b.append(", targetVersion=").append(myTargetResourceVersion); b.append(", targetUrl=").append(myTargetResourceUrl); b.append("]");