From 920755427bb21b416fa093535ee10f871cb61ebb Mon Sep 17 00:00:00 2001 From: StevenXLi Date: Wed, 11 Jan 2023 08:03:51 -0500 Subject: [PATCH] 4420 tags are not included in search results after using $meta delete on one tag (#4421) * added failing test * added a check for when the tag storage mode is non-versioned in meta delete to only check latest version of resource, added more test * added change log Co-authored-by: Steven Li --- ...ts-after-using-meta-delete-on-one-tag.yaml | 6 +++ .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 19 ++++---- .../jpa/dao/r4/FhirResourceDaoR4TagsTest.java | 45 +++++++++++++++++++ 3 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4420-tags-are-not-included-in-search-results-after-using-meta-delete-on-one-tag.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4420-tags-are-not-included-in-search-results-after-using-meta-delete-on-one-tag.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4420-tags-are-not-included-in-search-results-after-using-meta-delete-on-one-tag.yaml new file mode 100644 index 00000000000..4717062ae85 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_4_0/4420-tags-are-not-included-in-search-results-after-using-meta-delete-on-one-tag.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4420 +jira: SMILE-5734 +title: "Fixed a bug with $meta-delete which will cause the resource, when included as part of a search result, +to have all its tags be missing." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 5620930922d..badb4250d3f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -57,7 +57,6 @@ import ca.uhn.fhir.jpa.model.entity.TagTypeEnum; import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; -import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory; import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum; @@ -84,6 +83,7 @@ import ca.uhn.fhir.rest.api.server.IPreResourceShowDetails; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.SimplePreResourceAccessDetails; import ca.uhn.fhir.rest.api.server.SimplePreResourceShowDetails; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.storage.IDeleteExpungeJobSubmitter; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; @@ -663,7 +663,7 @@ public abstract class BaseHapiFhirResourceDao extends B TransactionDetails transactionDetails = new TransactionDetails(); List deletedResources = new ArrayList<>(); for (P pid : theResourceIds) { - JpaPid jpaPid = (JpaPid)pid; + JpaPid jpaPid = (JpaPid) pid; ResourceTable entity = myEntityManager.find(ResourceTable.class, jpaPid.getId()); deletedResources.add(entity); @@ -1039,11 +1039,11 @@ public abstract class BaseHapiFhirResourceDao extends B } ResourceTable latestVersion = readEntityLatestVersion(theResourceId, theRequest, transactionDetails); - if (latestVersion.getVersion() != entity.getVersion()) { + boolean nonVersionedTags = myDaoConfig.getTagStorageMode() != DaoConfig.TagStorageModeEnum.VERSIONED; + if (latestVersion.getVersion() != entity.getVersion() || nonVersionedTags) { doMetaDelete(theMetaDel, entity, theRequest, transactionDetails); } else { doMetaDelete(theMetaDel, latestVersion, theRequest, transactionDetails); - // Also update history entry ResourceHistoryTable history = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(entity.getId(), entity.getVersion()); doMetaDelete(theMetaDel, history, theRequest, transactionDetails); @@ -1123,7 +1123,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Transactional public T readByPid(IResourcePersistentId thePid, boolean theDeletedOk) { StopWatch w = new StopWatch(); - JpaPid jpaPid = (JpaPid)thePid; + JpaPid jpaPid = (JpaPid) thePid; Optional entity = myResourceTableDao.findById(jpaPid.getId()); if (!entity.isPresent()) { @@ -1219,7 +1219,7 @@ public abstract class BaseHapiFhirResourceDao extends B @SuppressWarnings("unchecked") @Override public void reindex(IResourcePersistentId thePid, RequestDetails theRequest, TransactionDetails theTransactionDetails) { - JpaPid jpaPid = (JpaPid)thePid; + JpaPid jpaPid = (JpaPid) thePid; Optional entityOpt = myResourceTableDao.findById(jpaPid.getId()); if (!entityOpt.isPresent()) { ourLog.warn("Unable to find entity with PID: {}", jpaPid.getId()); @@ -1312,7 +1312,7 @@ public abstract class BaseHapiFhirResourceDao extends B @Override protected IBasePersistedResource readEntityLatestVersion(IResourcePersistentId thePersistentId, RequestDetails theRequestDetails, TransactionDetails theTransactionDetails) { - JpaPid jpaPid = (JpaPid)thePersistentId; + JpaPid jpaPid = (JpaPid) thePersistentId; return myEntityManager.find(ResourceTable.class, jpaPid.getId()); } @@ -1334,7 +1334,7 @@ public abstract class BaseHapiFhirResourceDao extends B throw new ResourceNotFoundException(Msg.code(1997) + theId); } if (theTransactionDetails.hasResolvedResourceIds()) { - persistentId = (JpaPid)theTransactionDetails.getResolvedResourceId(theId); + persistentId = (JpaPid) theTransactionDetails.getResolvedResourceId(theId); } } @@ -1658,7 +1658,7 @@ public abstract class BaseHapiFhirResourceDao extends B // Pre-cache the match URL if (outcome.getPersistentId() != null) { - myMatchResourceUrlService.matchUrlResolved(theTransactionDetails, getResourceName(), theMatchUrl, (JpaPid)outcome.getPersistentId()); + myMatchResourceUrlService.matchUrlResolved(theTransactionDetails, getResourceName(), theMatchUrl, (JpaPid) outcome.getPersistentId()); } return outcome; @@ -1703,7 +1703,6 @@ public abstract class BaseHapiFhirResourceDao extends B } - /** * Method for updating the historical version of the resource when a history version id is included in the request. * diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TagsTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TagsTest.java index a54994dc87d..555c761b22d 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TagsTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4TagsTest.java @@ -427,6 +427,51 @@ public class FhirResourceDaoR4TagsTest extends BaseResourceProviderR4Test { validatePatientSearchResultsForInlineTags(outcome); } + @Test + public void testMetaDelete_TagStorageModeNonVersioned_ShouldShowRemainingTagsInGetAllResources() { + myDaoConfig.setTagStorageMode(DaoConfig.TagStorageModeEnum.NON_VERSIONED); + Patient pt = new Patient(); + Meta pMeta = new Meta(); + pMeta.addTag().setSystem("urn:system1").setCode("urn:code1"); + pMeta.addTag().setSystem("urn:system2").setCode("urn:code2"); + pt.setMeta(pMeta); + IIdType id = myClient.create().resource(pt).execute().getId().toUnqualifiedVersionless(); + + Meta meta = myClient.meta().get(Meta.class).fromResource(id).execute(); + assertEquals(2, meta.getTag().size()); + + Meta inMeta = new Meta(); + inMeta.addTag().setSystem("urn:system2").setCode("urn:code2"); + meta = myClient.meta().delete().onResource(id).meta(inMeta).execute(); + assertEquals(1, meta.getTag().size()); + + Bundle patientBundle = myClient.search().forResource("Patient").returnBundle(Bundle.class).execute(); + Patient patient = (Patient) patientBundle.getEntry().get(0).getResource(); + assertEquals(1, patient.getMeta().getTag().size()); + } + + @Test + public void testMetaDelete_TagStorageModeVersioned_ShouldShowRemainingTagsInGetAllResources() { + Patient pt = new Patient(); + Meta pMeta = new Meta(); + pMeta.addTag().setSystem("urn:system1").setCode("urn:code1"); + pMeta.addTag().setSystem("urn:system2").setCode("urn:code2"); + pt.setMeta(pMeta); + IIdType id = myClient.create().resource(pt).execute().getId().toUnqualifiedVersionless(); + + Meta meta = myClient.meta().get(Meta.class).fromResource(id).execute(); + assertEquals(2, meta.getTag().size()); + + Meta inMeta = new Meta(); + inMeta.addTag().setSystem("urn:system2").setCode("urn:code2"); + meta = myClient.meta().delete().onResource(id).meta(inMeta).execute(); + assertEquals(1, meta.getTag().size()); + + Bundle patientBundle = myClient.search().forResource("Patient").returnBundle(Bundle.class).execute(); + Patient patient = (Patient) patientBundle.getEntry().get(0).getResource(); + assertEquals(1, patient.getMeta().getTag().size()); + } + @Test public void testInlineTags_Search_Profile() { myDaoConfig.setTagStorageMode(DaoConfig.TagStorageModeEnum.INLINE);