From b4607c362870ecc4b3592aa174314c7f193f8f5f Mon Sep 17 00:00:00 2001 From: Ken Stevens Date: Fri, 6 Sep 2024 10:49:19 -0400 Subject: [PATCH 01/13] Ks 20240904 intermittents (#6264) --- .../uhn/fhir/jpa/model/config/PartitionSettings.java | 1 + .../server/HashMapResourceProviderExtension.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/config/PartitionSettings.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/config/PartitionSettings.java index f077d3baf0e..379f8098f23 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/config/PartitionSettings.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/config/PartitionSettings.java @@ -34,6 +34,7 @@ public class PartitionSettings { private boolean myAlwaysOpenNewTransactionForDifferentPartition; private boolean myConditionalCreateDuplicateIdentifiersEnabled = false; + public PartitionSettings() {} /** * Should we always open a new database transaction if the partition context changes * diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/HashMapResourceProviderExtension.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/HashMapResourceProviderExtension.java index 47be1c0016f..5ed7c33677b 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/HashMapResourceProviderExtension.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/HashMapResourceProviderExtension.java @@ -40,6 +40,7 @@ public class HashMapResourceProviderExtension extends H private final RestfulServerExtension myRestfulServerExtension; private boolean myClearBetweenTests = true; + private boolean myInitialized = false; private final List myUpdates = new ArrayList<>(); /** @@ -55,7 +56,9 @@ public class HashMapResourceProviderExtension extends H @Override public void afterEach(ExtensionContext context) throws Exception { - myRestfulServerExtension.getRestfulServer().unregisterProvider(HashMapResourceProviderExtension.this); + if (myClearBetweenTests) { + myRestfulServerExtension.getRestfulServer().unregisterProvider(HashMapResourceProviderExtension.this); + } } @Override @@ -77,8 +80,11 @@ public class HashMapResourceProviderExtension extends H if (myClearBetweenTests) { clear(); clearCounts(); + myRestfulServerExtension.getRestfulServer().registerProvider(HashMapResourceProviderExtension.this); + } else if (!myInitialized) { + myInitialized = true; + myRestfulServerExtension.getRestfulServer().registerProvider(HashMapResourceProviderExtension.this); } - myRestfulServerExtension.getRestfulServer().registerProvider(HashMapResourceProviderExtension.this); } @Override From 12765ac397030493929cbeec6d1ddd2d0472d642 Mon Sep 17 00:00:00 2001 From: jdar8 <69840459+jdar8@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:16:49 -0700 Subject: [PATCH 02/13] Disabling enforce referential integrity on write still checks references (#6219) * fix * tests, changelog, spotless * document tests better * address review comments * reset settings so other tests don't fail * unused import --------- Co-authored-by: jdar --- ...y-on-write-disabled-still-checks-refs.yaml | 6 + ...ResourceDaoR4ReferentialIntegrityTest.java | 168 +++++++++++++++--- .../dao/index/DaoResourceLinkResolver.java | 57 ++++-- 3 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6218-fix-ref-integrity-on-write-disabled-still-checks-refs.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6218-fix-ref-integrity-on-write-disabled-still-checks-refs.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6218-fix-ref-integrity-on-write-disabled-still-checks-refs.yaml new file mode 100644 index 00000000000..b6469d5c8b5 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6218-fix-ref-integrity-on-write-disabled-still-checks-refs.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 6218 +jira: SMILE-8370 +title: "Previously, when disabling the 'Enforce Referential Integrity on Write' setting, referential integrity was still +partially enforced when posting a resource with an invalid reference. This has now been fixed." diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ReferentialIntegrityTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ReferentialIntegrityTest.java index f75fce4b44c..8020f0556ea 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ReferentialIntegrityTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ReferentialIntegrityTest.java @@ -1,19 +1,26 @@ package ca.uhn.fhir.jpa.dao.r4; -import static org.junit.jupiter.api.Assertions.assertEquals; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Reference; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -import static org.assertj.core.api.Assertions.assertThat; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; public class FhirResourceDaoR4ReferentialIntegrityTest extends BaseJpaR4Test { @@ -23,51 +30,168 @@ public class FhirResourceDaoR4ReferentialIntegrityTest extends BaseJpaR4Test { myStorageSettings.setEnforceReferentialIntegrityOnWrite(new JpaStorageSettings().isEnforceReferentialIntegrityOnWrite()); myStorageSettings.setEnforceReferentialIntegrityOnDelete(new JpaStorageSettings().isEnforceReferentialIntegrityOnDelete()); myStorageSettings.setEnforceReferenceTargetTypes(new JpaStorageSettings().isEnforceReferenceTargetTypes()); + myStorageSettings.setResourceClientIdStrategy(new JpaStorageSettings().getResourceClientIdStrategy()); + } + + @ParameterizedTest + @MethodSource("paramsProvider_withResourceType") + public void referentialIntegrityOnWriteSetting_unknownIds_fullScopeTest(boolean theIsEnforceRefIntegrityEnabled, + JpaStorageSettings.ClientIdStrategyEnum theClientIdStrategy, + String theReferenceId) { + // Given + myStorageSettings.setEnforceReferentialIntegrityOnWrite(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setEnforceReferenceTargetTypes(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setResourceClientIdStrategy(theClientIdStrategy); + + Patient p = new Patient(); + p.setManagingOrganization(new Reference(theReferenceId)); + + if (theIsEnforceRefIntegrityEnabled) { + try { + // When + myPatientDao.create(p); + fail(); + } catch (InvalidRequestException e) { + // Then + assertEquals(Msg.code(1094) + "Resource " + theReferenceId + " not found, specified in path: Patient.managingOrganization", e.getMessage()); + } + } else { + // Disabled ref integrity on write case: all POSTs should succeed + // When + IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + // Then + p = myPatientDao.read(id); + assertEquals(theReferenceId, p.getManagingOrganization().getReference()); + } + } + + private static Stream paramsProvider_withResourceType() { + // theIsEnforceRefIntegrityEnabled, theClientIdStrategy, theReferenceId + // note: client ID is tested since resolving the resource reference is different depending on the strategy + return Stream.of( + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "Organization/123"), + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "Organization/A123"), + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ANY, "Organization/123"), + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ANY, "Organization/A123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "Organization/123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "Organization/A123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ANY, "Organization/123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ANY, "Organization/A123") + ); } @Test - public void testCreateUnknownReferenceFail() throws Exception { + public void testRefIntegrityOnWrite_withReferenceIdOfAnotherResourceType() { + // Given + myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC); + // Create Observation with some ID... + Observation obs = new Observation(); + IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + + // And reference a non-existing Organization resource with the same ID as the Observation Patient p = new Patient(); - p.setManagingOrganization(new Reference("Organization/AAA")); + p.setManagingOrganization(new Reference(new IdType("Organization", obsId.getIdPart()))); + try { + // When myPatientDao.create(p); fail(); - } catch (InvalidRequestException e) { - assertEquals(Msg.code(1094) + "Resource Organization/AAA not found, specified in path: Patient.managingOrganization", e.getMessage()); + } catch (UnprocessableEntityException e) { + // Then: identify that it is the wrong resource type, since ref integrity is enabled + assertEquals(Msg.code(1095) + "Resource contains reference to unknown resource ID Organization/" + obsId.getIdPart(), e.getMessage()); } + // Given: now disable referential integrity on write + myStorageSettings.setEnforceReferentialIntegrityOnWrite(false); + // When + IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + // Then: this should now succeed + p = myPatientDao.read(id); + assertEquals("Organization/" + obsId.getIdPart(), p.getManagingOrganization().getReference()); } - @Test - public void testCreateUnknownReferenceAllowed() { - myStorageSettings.setEnforceReferentialIntegrityOnWrite(false); + @ParameterizedTest + @MethodSource("paramsProvider_noResourceType") + public void testRefIntegrityOnWrite_withValidReferenceId_shouldAlwaysSucceed(boolean theIsEnforceRefIntegrityEnabled, + JpaStorageSettings.ClientIdStrategyEnum theClientIdStrategy, + String theReferenceId) { + // Given + myStorageSettings.setEnforceReferentialIntegrityOnWrite(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setEnforceReferenceTargetTypes(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setResourceClientIdStrategy(theClientIdStrategy); + + Organization obs = new Organization(); + obs.setId(theReferenceId); + myOrganizationDao.update(obs, mySrd); + String qualifiedReferenceId = "Organization/" + theReferenceId; Patient p = new Patient(); - p.setManagingOrganization(new Reference("Organization/AAA")); + p.setManagingOrganization(new Reference(qualifiedReferenceId)); + + // When IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + // Then p = myPatientDao.read(id); - assertEquals("Organization/AAA", p.getManagingOrganization().getReference()); - + assertEquals(qualifiedReferenceId, p.getManagingOrganization().getReference()); } - @Test - public void testCreateUnknownReferenceAllowed_NumericId() { - myStorageSettings.setEnforceReferentialIntegrityOnWrite(false); - myStorageSettings.setEnforceReferenceTargetTypes(false); + private static Stream paramsProvider_noResourceType() { + // theIsEnforceRefIntegrityEnabled, theClientIdStrategy, theReferenceId + // note: client ID is tested since resolving the resource reference is different depending on the strategy + return Stream.of( + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "A123"), + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ANY, "123"), + Arguments.of(true, JpaStorageSettings.ClientIdStrategyEnum.ANY, "A123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ALPHANUMERIC, "A123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ANY, "123"), + Arguments.of(false, JpaStorageSettings.ClientIdStrategyEnum.ANY, "A123") + ); + } + + @ParameterizedTest + @MethodSource("paramsProvider_noResourceType") + public void testRefIntegrityOnWrite_withReferenceIdOfDeletedResource(boolean theIsEnforceRefIntegrityEnabled, + JpaStorageSettings.ClientIdStrategyEnum theClientIdStrategy, + String theReferenceId) { + // Given + myStorageSettings.setEnforceReferentialIntegrityOnWrite(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setEnforceReferenceTargetTypes(theIsEnforceRefIntegrityEnabled); + myStorageSettings.setResourceClientIdStrategy(theClientIdStrategy); + + Organization obs = new Organization(); + obs.setId(theReferenceId); + IIdType obsId = myOrganizationDao.update(obs, mySrd).getId(); + String qualifiedReferenceId = "Organization/" + theReferenceId; + + myOrganizationDao.delete(obsId, mySrd); Patient p = new Patient(); - p.setManagingOrganization(new Reference("Organization/123")); - IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + p.setManagingOrganization(new Reference(qualifiedReferenceId)); - p = myPatientDao.read(id); - assertEquals("Organization/123", p.getManagingOrganization().getReference()); + if (theIsEnforceRefIntegrityEnabled) { + try { + // When + myPatientDao.create(p); + fail(); + } catch (InvalidRequestException e) { + // Then + assertEquals(Msg.code(1096) + "Resource " + qualifiedReferenceId + " is deleted, specified in path: Patient.managingOrganization", e.getMessage()); + } + } else { + // Disabled ref integrity on write case: all POSTs should succeed + // When + IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + // Then + p = myPatientDao.read(id); + assertEquals(qualifiedReferenceId, p.getManagingOrganization().getReference()); + } } @Test - public void testDeleteFail() throws Exception { + public void testDeleteFail() { Organization o = new Organization(); o.setName("FOO"); IIdType oid = myOrganizationDao.create(o).getId().toUnqualifiedVersionless(); @@ -89,7 +213,7 @@ public class FhirResourceDaoR4ReferentialIntegrityTest extends BaseJpaR4Test { } @Test - public void testDeleteAllow() throws Exception { + public void testDeleteAllow() { myStorageSettings.setEnforceReferentialIntegrityOnDelete(false); Organization o = new Organization(); diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/dao/index/DaoResourceLinkResolver.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/dao/index/DaoResourceLinkResolver.java index e76ed2801bb..9434e126936 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/dao/index/DaoResourceLinkResolver.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/dao/index/DaoResourceLinkResolver.java @@ -134,7 +134,7 @@ public class DaoResourceLinkResolver implements type, targetReference, idPart, theRequest, theTransactionDetails); if (!createdTableOpt.isPresent()) { - if (myStorageSettings.isEnforceReferentialIntegrityOnWrite() == false) { + if (!myStorageSettings.isEnforceReferentialIntegrityOnWrite()) { return null; } @@ -150,20 +150,8 @@ public class DaoResourceLinkResolver implements "Resolved resource of type {} as PID: {}", resolvedResource.getResourceType(), resolvedResource.getPersistentId()); - if (!resourceType.equals(resolvedResource.getResourceType())) { - ourLog.error( - "Resource with PID {} was of type {} and wanted {}", - resolvedResource.getPersistentId(), - resourceType, - resolvedResource.getResourceType()); - throw new UnprocessableEntityException(Msg.code(1095) - + "Resource contains reference to unknown resource ID " + targetResourceId.getValue()); - } - - if (resolvedResource.getDeleted() != null) { - String resName = resolvedResource.getResourceType(); - throw new InvalidRequestException(Msg.code(1096) + "Resource " + resName + "/" + idPart - + " is deleted, specified in path: " + sourcePath); + if (!validateResolvedResourceOrThrow(resourceType, resolvedResource, targetResourceId, idPart, sourcePath)) { + return null; } if (persistentId == null) { @@ -182,6 +170,45 @@ public class DaoResourceLinkResolver implements return resolvedResource; } + /** + * Validates the resolved resource. + * If 'Enforce Referential Integrity on Write' is enabled: + * Throws UnprocessableEntityException when resource types do not match + * Throws InvalidRequestException when the resolved resource was deleted + *

+ * Otherwise, return false when resource types do not match or resource was deleted + * and return true if the resolved resource is valid. + */ + private boolean validateResolvedResourceOrThrow( + String resourceType, + IResourceLookup resolvedResource, + IIdType targetResourceId, + String idPart, + String sourcePath) { + if (!resourceType.equals(resolvedResource.getResourceType())) { + ourLog.error( + "Resource with PID {} was of type {} and wanted {}", + resolvedResource.getPersistentId(), + resourceType, + resolvedResource.getResourceType()); + if (!myStorageSettings.isEnforceReferentialIntegrityOnWrite()) { + return false; + } + throw new UnprocessableEntityException(Msg.code(1095) + + "Resource contains reference to unknown resource ID " + targetResourceId.getValue()); + } + + if (resolvedResource.getDeleted() != null) { + if (!myStorageSettings.isEnforceReferentialIntegrityOnWrite()) { + return false; + } + String resName = resolvedResource.getResourceType(); + throw new InvalidRequestException(Msg.code(1096) + "Resource " + resName + "/" + idPart + + " is deleted, specified in path: " + sourcePath); + } + return true; + } + @Nullable @Override public IBaseResource loadTargetResource( From d9f3ac1c3ba53a37657258ac17c501254c2cc537 Mon Sep 17 00:00:00 2001 From: dotasek Date: Fri, 6 Sep 2024 14:51:05 -0400 Subject: [PATCH 03/13] Bump org.hl7.fhir.core to 6.3.23 (#6266) * Bump org.hl7.fhir.core to 6.3.23 * Fix breaking test (check for no value and null) * Fix typo --- .../resources/ca/uhn/hapi/fhir/changelog/7_6_0/changes.yaml | 1 + .../ca/uhn/fhir/jpa/packages/PackageInstallerSvcImpl.java | 4 ++-- pom.xml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/changes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/changes.yaml index 0510a3e0708..7d14d84956f 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/changes.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/changes.yaml @@ -4,6 +4,7 @@ title: "The version of a few dependencies have been bumped to more recent versions (dependent HAPI modules listed in brackets):

    +
  • org.hl7.fhir.core (Base): 6.3.18 -> 6.3.23
  • Bower/Moment.js (hapi-fhir-testpage-overlay): 2.27.0 -> 2.29.4
  • htmlunit (Base): 3.9.0 -> 3.11.0
  • Elasticsearch (Base): 8.11.1 -> 8.14.3
  • diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/packages/PackageInstallerSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/packages/PackageInstallerSvcImpl.java index d7f6f5da0b4..122caf5b490 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/packages/PackageInstallerSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/packages/PackageInstallerSvcImpl.java @@ -588,8 +588,8 @@ public class PackageInstallerSvcImpl implements IPackageInstallerSvc { if (statusTypes.isEmpty()) { return true; } - // Resource has a null status field - if (statusTypes.get(0).getValue() == null) { + // Resource has no status field, or an explicitly null one + if (!statusTypes.get(0).hasValue() || statusTypes.get(0).getValue() == null) { return false; } // Resource has a status, and we need to check based on type diff --git a/pom.xml b/pom.xml index 8aa11b301dd..a7cae721347 100644 --- a/pom.xml +++ b/pom.xml @@ -948,7 +948,7 @@ - 6.3.18 + 6.3.23 2.41.1 -Dfile.encoding=UTF-8 -Xmx2048m From 2717a0dc95174cb72a75f42d654d560492139be9 Mon Sep 17 00:00:00 2001 From: Tadgh Date: Fri, 6 Sep 2024 14:45:07 -0700 Subject: [PATCH 04/13] Add knowledge of 6.8.8 --- hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java index 9ab4d7734cc..bf46c7fe3bf 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java @@ -136,6 +136,7 @@ public enum VersionEnum { V6_8_5, V6_8_6, V6_8_7, + V6_8_8, V6_9_0, From c00292767de3ebb7420bef11cfdf0baa79ffaac0 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Tue, 10 Sep 2024 11:44:53 -0400 Subject: [PATCH 05/13] Rename test so that it will run from Maven and the pipeline since it didn't before. Fix small bug that made the test error out. (#6273) --- ...urceListenerTests.java => CrResourceListenerTest.java} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/{CrResourceListenerTests.java => CrResourceListenerTest.java} (95%) diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTests.java b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTest.java similarity index 95% rename from hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTests.java rename to hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTest.java index 481999ed95a..f0205f86b5f 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTests.java +++ b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/CrResourceListenerTest.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.cr.r4; -import ca.uhn.fhir.jpa.cache.ResourceChangeListenerCacheRefresherImpl; +import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCacheRefresher; import ca.uhn.fhir.jpa.cache.ResourceChangeListenerRegistryImpl; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.IdType; @@ -16,13 +16,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; @ExtendWith(SpringExtension.class) -public class CrResourceListenerTests extends BaseCrR4TestServer { +public class CrResourceListenerTest extends BaseCrR4TestServer { @Autowired EvaluationSettings myEvaluationSettings; @Autowired ResourceChangeListenerRegistryImpl myResourceChangeListenerRegistry; @Autowired - ResourceChangeListenerCacheRefresherImpl myResourceChangeListenerCacheRefresher; + IResourceChangeListenerCacheRefresher myResourceChangeListenerCacheRefresher; public MeasureReport runEvaluateMeasure(String periodStart, String periodEnd, String subject, String measureId, String reportType, String practitioner){ @@ -118,7 +118,7 @@ public class CrResourceListenerTests extends BaseCrR4TestServer { myResourceChangeListenerCacheRefresher.refreshExpiredCachesAndNotifyListeners(); //cache should be invalidated for matching library name and version - assertThat(myEvaluationSettings.getLibraryCache()).hasSize(6); + assertThat(myEvaluationSettings.getLibraryCache()).hasSize(7); } @Test From ab2ba05fb595ee0823c407c61b3a301670991a92 Mon Sep 17 00:00:00 2001 From: jmarchionatto <60409882+jmarchionatto@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:48:54 -0400 Subject: [PATCH 06/13] =?UTF-8?q?Narrow=20version=20check=20scope=20to=20f?= =?UTF-8?q?ix=20intermittency=20produced=20because=20argu=E2=80=A6=20(#627?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Narrow version check scope to fix intermittency produced because argument was present in CodeSystem field different from version * Remove duplication * Remove code duplication * fix comment syntax --------- Co-authored-by: juan.marchionatto --- ...erminologySvcImplCurrentVersionR4Test.java | 132 ++++++------------ 1 file changed, 42 insertions(+), 90 deletions(-) diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplCurrentVersionR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplCurrentVersionR4Test.java index 3eb62d47179..11d7cb3b767 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplCurrentVersionR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplCurrentVersionR4Test.java @@ -1,9 +1,8 @@ package ca.uhn.fhir.jpa.term; -import static org.junit.jupiter.api.Assertions.assertNull; import ca.uhn.fhir.context.support.IValidationSupport; -import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.LookupCodeRequest; +import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.config.JpaConfig; import ca.uhn.fhir.jpa.entity.TermCodeSystem; @@ -20,9 +19,10 @@ import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import jakarta.persistence.EntityManager; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.IdType; @@ -40,8 +40,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.io.ClassPathResource; -import jakarta.persistence.EntityManager; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -82,14 +80,12 @@ import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_UPLOAD_ import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_XML_FILE; import static java.util.stream.Collectors.joining; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.fail; import static org.hl7.fhir.common.hapi.validation.support.ValidationConstants.LOINC_ALL_VALUESET_ID; import static org.hl7.fhir.common.hapi.validation.support.ValidationConstants.LOINC_LOW; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; - import static org.mockito.Mockito.when; /** @@ -141,9 +137,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { @Autowired private Batch2JobHelper myBatchJobHelper; - - private ZipCollectionBuilder myFiles; - private ServletRequestDetails myRequestDetails = new ServletRequestDetails(); + private final ServletRequestDetails myRequestDetails = new ServletRequestDetails(); private Properties uploadProperties; private IFhirResourceDao myValueSetIFhirResourceDao; @@ -182,17 +176,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { private void validateValidateCode(String theCurrentVersion, Collection allVersions) { - IValidationSupport.CodeValidationResult resultNoVersioned = myCodeSystemDao.validateCode(null, - new UriType(BASE_LOINC_URL), null, new CodeType(VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE), - null, null, null, null); - assertNotNull(resultNoVersioned); - assertEquals(prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), resultNoVersioned.getDisplay()); - - IValidationSupport.CodeValidationResult resultVersioned = myCodeSystemDao.validateCode(null, - new UriType(BASE_LOINC_URL), null, new CodeType(VS_VERSIONED_ON_UPLOAD_FIRST_CODE), - null, null, null, null); - assertNotNull(resultVersioned); - assertEquals(prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), resultVersioned.getDisplay()); + validateValidateCodeForVersion(theCurrentVersion); allVersions.forEach(this::validateValidateCodeForVersion); } @@ -215,13 +199,15 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { private void validateValueLookup(String theCurrentVersion, Collection allVersions) { IValidationSupport.LookupCodeResult resultNoVer = myValidationSupport.lookupCode( - new ValidationSupportContext(myValidationSupport), new LookupCodeRequest(BASE_LOINC_URL, VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE)); + new ValidationSupportContext(myValidationSupport), + new LookupCodeRequest(BASE_LOINC_URL, VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE)); assertNotNull(resultNoVer); String expectedNoVer = prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY); assertEquals(expectedNoVer, resultNoVer.getCodeDisplay()); IValidationSupport.LookupCodeResult resultWithVer = myValidationSupport.lookupCode( - new ValidationSupportContext(myValidationSupport), new LookupCodeRequest(BASE_LOINC_URL, VS_VERSIONED_ON_UPLOAD_FIRST_CODE)); + new ValidationSupportContext(myValidationSupport), + new LookupCodeRequest(BASE_LOINC_URL, VS_VERSIONED_ON_UPLOAD_FIRST_CODE)); assertNotNull(resultWithVer); String expectedWithVer = prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY); assertEquals(expectedWithVer, resultWithVer.getCodeDisplay()); @@ -278,42 +264,28 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { private void validateExpandedTermConcepts(String theCurrentVersion, Collection theAllVersions) { runInTransaction(() -> { - TermConcept termConceptNoVerCsvNoVer = (TermConcept) myEntityManager.createQuery( - "select tc from TermConcept tc join fetch tc.myCodeSystem tcsv where tc.myCode = '" + - VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId is null").getSingleResult(); - assertNotNull(termConceptNoVerCsvNoVer); - // data should have version because it was loaded with a version - assertEquals(prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptNoVerCsvNoVer.getDisplay()); - - TermConcept termConceptVerCsvNoVer = (TermConcept) myEntityManager.createQuery( - "select tc from TermConcept tc join fetch tc.myCodeSystem tcsv where tc.myCode = '" + - VS_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId is null").getSingleResult(); - assertNotNull(termConceptVerCsvNoVer); - // data should have version because it was loaded with a version - assertEquals(prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptVerCsvNoVer.getDisplay()); - - if (theCurrentVersion != null) { - TermConcept termConceptNoVerCsvVer = (TermConcept) myEntityManager.createQuery( + TermConcept termConceptNoVerCsvNoVer = (TermConcept) myEntityManager.createQuery( "select tc from TermConcept tc join fetch tc.myCodeSystem tcsv where tc.myCode = '" + - VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId = '" + theCurrentVersion + "'").getSingleResult(); - assertNotNull(termConceptNoVerCsvVer); + VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId is null").getSingleResult(); + assertNotNull(termConceptNoVerCsvNoVer); // data should have version because it was loaded with a version - assertEquals(prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptNoVerCsvVer.getDisplay()); + assertEquals(prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptNoVerCsvNoVer.getDisplay()); - TermConcept termConceptVerCsvVer = (TermConcept) myEntityManager.createQuery( + TermConcept termConceptVerCsvNoVer = (TermConcept) myEntityManager.createQuery( "select tc from TermConcept tc join fetch tc.myCodeSystem tcsv where tc.myCode = '" + - VS_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId = '" + theCurrentVersion + "'").getSingleResult(); - assertNotNull(termConceptVerCsvVer); + VS_VERSIONED_ON_UPLOAD_FIRST_CODE + "' and tcsv.myCodeSystemVersionId is null").getSingleResult(); + assertNotNull(termConceptVerCsvNoVer); // data should have version because it was loaded with a version - assertEquals(prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptVerCsvVer.getDisplay()); - } + assertEquals(prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), termConceptVerCsvNoVer.getDisplay()); - theAllVersions.forEach(this::validateExpandedTermConceptsForVersion); + if (theCurrentVersion != null) { + validateExpandedTermConceptsForVersion(theCurrentVersion); + } + theAllVersions.forEach(this::validateExpandedTermConceptsForVersion); }); } - private void validateExpandedTermConceptsForVersion(String theVersion) { TermConcept termConceptNoVer = (TermConcept) myEntityManager.createQuery( "select tc from TermConcept tc join fetch tc.myCodeSystem tcsv where tc.myCode = '" + @@ -384,7 +356,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { * no the CodeSystem version. */ private void validateValueSetSearchForVersion(String theVersion) { - // for no versioned VS (VS version, different than CS version) + // for no versioned VS (VS version, different from CS version) SearchParameterMap paramsUploadNoVer = new SearchParameterMap("url", new UriParam(VS_NO_VERSIONED_ON_UPLOAD)); paramsUploadNoVer.add("version", new TokenParam(theVersion)); @@ -398,7 +370,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { assertEquals(expectedLoadNoVersionUnqualifiedId, loadNoVersionValueSet.getIdElement().getIdPart()); - // versioned VS (VS version, different than CS version) + // versioned VS (VS version, different from CS version) SearchParameterMap paramsUploadVer = new SearchParameterMap("url", new UriParam(VS_VERSIONED_ON_UPLOAD)); paramsUploadVer.add("version", new TokenParam(VS_ANSWER_LIST_VERSION + "-" + theVersion)); @@ -437,8 +409,8 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { Set theExpectedIdVersionsPlusNull = Sets.newHashSet(theExpectedIdVersions); theExpectedIdVersionsPlusNull.add(null); - assertThat(theExpectedIdVersionsPlusNull).containsExactlyInAnyOrderElementsOf(theValueSets.stream().map(r -> ((ValueSet) r).getVersion()).toList()); - + List valueSetVersions = theValueSets.stream().map(r -> ((ValueSet) r).getVersion()).toList(); + assertThat(valueSetVersions).containsExactlyInAnyOrderElementsOf(theExpectedIdVersionsPlusNull); } @@ -455,14 +427,13 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { // for CodeSystem: // _ current CS is present and has no version - CodeSystem codeSystem = myCodeSystemDao.read(new IdType(LOINC_LOW)); + CodeSystem codeSystem = myCodeSystemDao.read(new IdType(LOINC_LOW), myRequestDetails); String csString = myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem); - ourLog.info("CodeSystem:\n" + csString); + ourLog.info("CodeSystem:\n {}", csString); HashSet shouldNotBePresentVersions = new HashSet<>(possibleVersions); theAllVersions.forEach(shouldNotBePresentVersions::remove); - shouldNotBePresentVersions.forEach(vv -> assertFalse(csString.contains(vv), - "Found version string: '" + vv + "' in CodeSystem: " + csString)); + assertThat(shouldNotBePresentVersions).noneSatisfy(vv -> assertThat(vv).isEqualTo(codeSystem.getVersion())); // same reading it from term service CodeSystem cs = myITermReadSvc.fetchCanonicalCodeSystemFromCompleteContext(BASE_LOINC_URL); @@ -501,7 +472,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { @Test() public void uploadCurrentNoVersion() throws Exception { - IIdType csId = uploadLoincCodeSystem(null, true); + uploadLoincCodeSystem(null, true); runCommonValidations(Collections.emptyList()); @@ -516,7 +487,7 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { @Test() public void uploadWithVersion() throws Exception { String ver = "2.67"; - IIdType csId = uploadLoincCodeSystem(ver, true); + uploadLoincCodeSystem(ver, true); runCommonValidations(Collections.singletonList(ver)); @@ -637,25 +608,6 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { assertThat(vsContainsDisplay).contains(expectedDisplay); } - - private void validateValidateCodeLoincAllVS(String theCurrentVersion, Collection allVersions) { - IValidationSupport.CodeValidationResult resultNoVersioned = myCodeSystemDao.validateCode(null, - new UriType(BASE_LOINC_URL), null, new CodeType(VS_NO_VERSIONED_ON_UPLOAD_FIRST_CODE), - null, null, null, null); - assertNotNull(resultNoVersioned); - assertEquals(prefixWithVersion(theCurrentVersion, VS_NO_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), resultNoVersioned.getDisplay()); - - IValidationSupport.CodeValidationResult resultVersioned = myCodeSystemDao.validateCode(null, - new UriType(BASE_LOINC_URL), null, new CodeType(VS_VERSIONED_ON_UPLOAD_FIRST_CODE), - null, null, null, null); - assertNotNull(resultVersioned); - assertEquals(prefixWithVersion(theCurrentVersion, VS_VERSIONED_ON_UPLOAD_FIRST_DISPLAY), resultVersioned.getDisplay()); - - allVersions.forEach(this::validateValidateCodeForVersion); - } - - - private void validateValueExpandLoincAllVsForVersion(String theVersion) { ValueSet vs = myValueSetDao.expandByIdentifier(LOINC_ALL_VS_URL + "|" + theVersion, null); assertThat(vs.getExpansion().getContains()).hasSize(ALL_VS_QTY); @@ -664,7 +616,6 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { checkContainsElementVersion(vs, theVersion); } - /** * Validates TermConcepts were created in the sequence indicated by the parameters * and their displays match the expected versions @@ -735,8 +686,8 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { } - private IIdType uploadLoincCodeSystem(String theVersion, boolean theMakeItCurrent) throws Exception { - myFiles = new ZipCollectionBuilder(); + private void uploadLoincCodeSystem(String theVersion, boolean theMakeItCurrent) throws Exception { + ZipCollectionBuilder files = new ZipCollectionBuilder(); myRequestDetails.getUserData().put(LOINC_CODESYSTEM_MAKE_CURRENT, theMakeItCurrent); uploadProperties.put(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), Boolean.toString(theMakeItCurrent)); @@ -749,12 +700,10 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { uploadProperties.put(LOINC_CODESYSTEM_VERSION.getCode(), theVersion); } - addLoincMandatoryFilesToZip(myFiles, theVersion); + addLoincMandatoryFilesToZip(files, theVersion); - UploadStatistics stats = myTermLoaderSvc.loadLoinc(myFiles.getFiles(), mySrd); + myTermLoaderSvc.loadLoinc(files.getFiles(), mySrd); myTerminologyDeferredStorageSvc.saveAllDeferred(); - - return stats.getTarget(); } @@ -787,10 +736,12 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { private TermCodeSystemVersion fetchCurrentCodeSystemVersion() { runInTransaction(() -> { + @SuppressWarnings("unchecked") List tcsList = myEntityManager.createQuery("from TermCodeSystem").getResultList(); + @SuppressWarnings("unchecked") List tcsvList = myEntityManager.createQuery("from TermCodeSystemVersion").getResultList(); - ourLog.error("tcslist: {}", tcsList.stream().map(tcs -> tcs.toString()).collect(joining("\n", "\n", ""))); - ourLog.error("tcsvlist: {}", tcsvList.stream().map(v -> v.toString()).collect(joining("\n", "\n", ""))); + ourLog.error("tcslist: {}", tcsList.stream().map(TermCodeSystem::toString).collect(joining("\n", "\n", ""))); + ourLog.error("tcsvlist: {}", tcsvList.stream().map(TermCodeSystemVersion::toString).collect(joining("\n", "\n", ""))); if (tcsList.size() != 1) { throw new IllegalStateException("More than one TCS: " + @@ -807,8 +758,9 @@ public class TerminologySvcImplCurrentVersionR4Test extends BaseJpaR4Test { } - private static void addBaseLoincMandatoryFilesToZip( - ZipCollectionBuilder theFiles, Boolean theIncludeTop2000, String theClassPathPrefix) throws IOException { + private static void addBaseLoincMandatoryFilesToZip(ZipCollectionBuilder theFiles, + @SuppressWarnings("SameParameterValue") Boolean theIncludeTop2000, + String theClassPathPrefix) throws IOException { theFiles.addFileZip(theClassPathPrefix, LOINC_XML_FILE.getCode()); theFiles.addFileZip(theClassPathPrefix, LOINC_GROUP_FILE_DEFAULT.getCode()); theFiles.addFileZip(theClassPathPrefix, LOINC_GROUP_TERMS_FILE_DEFAULT.getCode()); From 699f863fe2f7646262bdd2bc885a796518b9ad74 Mon Sep 17 00:00:00 2001 From: jmarchionatto <60409882+jmarchionatto@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:31:32 -0400 Subject: [PATCH 07/13] Jm improve test server helper (#6281) * Improve docs as indexing is not the only function using extraction * Add providers map which to be able to add any kind of provider dynamically --------- Co-authored-by: juan.marchionatto --- .../extractor/ISearchParamExtractor.java | 6 ++--- .../test/utilities/RestServerR4Helper.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java index 77a43ddc2e5..e8d1755c780 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ISearchParamExtractor.java @@ -44,13 +44,13 @@ public interface ISearchParamExtractor { /** * Constant for the {@literal theSearchParamFilter} parameters on this interface - * indicating that all search parameters should be indexed. + * indicating that all search parameters should be extracted. */ ISearchParamFilter ALL_PARAMS = t -> t; /** * Constant for the {@literal theSearchParamFilter} parameters on this interface - * indicating that no search parameters should be indexed. + * indicating that no search parameters should be extracted. */ ISearchParamFilter NO_PARAMS = t -> Collections.emptyList(); @@ -155,7 +155,7 @@ public interface ISearchParamExtractor { interface ISearchParamFilter { /** - * Given the list of search parameters for indexing, an implementation of this + * Given the list of search parameters for extracting, an implementation of this * interface may selectively remove any that it wants to remove (or can add if desired). *

    * Implementations must not modify the list that is passed in. If changes are diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/RestServerR4Helper.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/RestServerR4Helper.java index 5ac8aa67343..435d000939c 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/RestServerR4Helper.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/RestServerR4Helper.java @@ -221,6 +221,28 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa myRestServer.setConceptMapResourceProvider(theResourceProvider); } + public HashMapResourceProvider getResourceProvider(Class theResourceType) { + @SuppressWarnings("unchecked") + HashMapResourceProvider resourceProvider = (HashMapResourceProvider) myRestServer.myResourceProvidersMap.get(theResourceType); + assert resourceProvider != null : "No resource provider defined for resource type: '" + theResourceType + "'" ; + return resourceProvider; + } + + public void setResourceProvider(HashMapResourceProvider theResourceProvider) { + assert theResourceProvider.getResourceType() != null : "resourceProvider doesn't have a resourceType"; + @SuppressWarnings("unchecked") + HashMapResourceProvider resourceProvider = (HashMapResourceProvider) myRestServer.myResourceProvidersMap.get(theResourceProvider.getResourceType()); + + if (resourceProvider != null) { + resourceProvider.getStoredResources().forEach(theResourceProvider::store); + myRestServer.unregisterProvider(resourceProvider); + } + + registerProvider(theResourceProvider); + myRestServer.myResourceProvidersMap.put(theResourceProvider.getResourceType(), theResourceProvider); + } + + public void setPagingProvider(IPagingProvider thePagingProvider) { myPagingProvider = thePagingProvider; } @@ -295,6 +317,8 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa private HashMapResourceProvider myConceptMapResourceProvider; private RestServerDstu3Helper.MyPlainProvider myPlainProvider; + private final Map, HashMapResourceProvider> myResourceProvidersMap = new HashMap<>(); + private final boolean myInitialTransactionLatchEnabled; private PagingHttpMethodEnum myPagingHttpMethod = PagingHttpMethodEnum.GET; From 02d38bce1467aefad359385d2052221808a376db Mon Sep 17 00:00:00 2001 From: TipzCM Date: Fri, 13 Sep 2024 12:33:40 -0400 Subject: [PATCH 08/13] removing unneeded fields from HRJ_RESOURCE table (#6284) --- ...e-unneeded-fields-from-resource-table.yaml | 10 +++++++ .../fhir/jpa/model/entity/ResourceTable.java | 30 ------------------- 2 files changed, 10 insertions(+), 30 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6283-remove-unneeded-fields-from-resource-table.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6283-remove-unneeded-fields-from-resource-table.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6283-remove-unneeded-fields-from-resource-table.yaml new file mode 100644 index 00000000000..a1e871a8656 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6283-remove-unneeded-fields-from-resource-table.yaml @@ -0,0 +1,10 @@ +--- +type: remove +issue: 6283 +title: "Hibernate Search Fulltext fields which were unused + have been removed from indexing. + This will reduce storage usage in Lucene and Elasticsearch. + The fields that were removed are: `myNarrativeTextEdgeNGram`, + `myNarrativeTextNGram`, `myNarrativeTextPhonetic`, `myContentTextEdgeNGram`, + `myContentTextNGram`, `myContentTextPhonetic`. +" diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java index e897ae71786..6163011eeb4 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceTable.java @@ -119,21 +119,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas searchable = Searchable.YES, projectable = Projectable.YES, analyzer = "standardAnalyzer") - @FullTextField( - name = "myContentTextEdgeNGram", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompleteEdgeAnalyzer") - @FullTextField( - name = "myContentTextNGram", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompleteNGramAnalyzer") - @FullTextField( - name = "myContentTextPhonetic", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompletePhoneticAnalyzer") @OptimisticLock(excluded = true) @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "myVersion"))) private String myContentText; @@ -171,21 +156,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas searchable = Searchable.YES, projectable = Projectable.YES, analyzer = "standardAnalyzer") - @FullTextField( - name = "myNarrativeTextEdgeNGram", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompleteEdgeAnalyzer") - @FullTextField( - name = "myNarrativeTextNGram", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompleteNGramAnalyzer") - @FullTextField( - name = "myNarrativeTextPhonetic", - searchable = Searchable.YES, - projectable = Projectable.NO, - analyzer = "autocompletePhoneticAnalyzer") @OptimisticLock(excluded = true) @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "myVersion"))) private String myNarrativeText; From 1fad912193ec1da9e41dc7c46473365075446fa5 Mon Sep 17 00:00:00 2001 From: Aditya Dave Date: Wed, 18 Sep 2024 10:01:17 -0400 Subject: [PATCH 09/13] 6262 cds hooks returns 400 when extension passed in the cdsservicerequestjson (#6274) * fail test * potential fix * spotless * alternative fix * spotless * remove the new method and replace usage for the old one * spotless * fix issue with context failing deserialization * add validation for context, hook and hook instance * spotless * add message codes * spotless * changelog * cleanup * spotless * bump version to 7.5.1-SNAPSHOT --- hapi-deployable-pom/pom.xml | 2 +- hapi-fhir-android/pom.xml | 2 +- hapi-fhir-base/pom.xml | 2 +- hapi-fhir-bom/pom.xml | 4 +- hapi-fhir-checkstyle/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-api/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-app/pom.xml | 2 +- hapi-fhir-cli/pom.xml | 2 +- hapi-fhir-client-okhttp/pom.xml | 2 +- hapi-fhir-client/pom.xml | 2 +- hapi-fhir-converter/pom.xml | 2 +- hapi-fhir-dist/pom.xml | 2 +- hapi-fhir-docs/pom.xml | 2 +- ...tion-when-extension-passed-in-request.yaml | 4 + hapi-fhir-jacoco/pom.xml | 2 +- hapi-fhir-jaxrsserver-base/pom.xml | 2 +- hapi-fhir-jpa/pom.xml | 2 +- hapi-fhir-jpaserver-base/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-jpaserver-hfql/pom.xml | 2 +- hapi-fhir-jpaserver-ips/pom.xml | 2 +- hapi-fhir-jpaserver-mdm/pom.xml | 2 +- hapi-fhir-jpaserver-model/pom.xml | 2 +- hapi-fhir-jpaserver-searchparam/pom.xml | 2 +- hapi-fhir-jpaserver-subscription/pom.xml | 2 +- hapi-fhir-jpaserver-test-dstu2/pom.xml | 2 +- hapi-fhir-jpaserver-test-dstu3/pom.xml | 2 +- hapi-fhir-jpaserver-test-r4/pom.xml | 2 +- hapi-fhir-jpaserver-test-r4b/pom.xml | 2 +- hapi-fhir-jpaserver-test-r5/pom.xml | 2 +- hapi-fhir-jpaserver-test-utilities/pom.xml | 2 +- hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 2 +- hapi-fhir-server-cds-hooks/pom.xml | 2 +- .../cdshooks/api/ICdsServiceRegistry.java | 2 +- .../cdshooks/api/json/CdsHooksExtension.java | 2 + .../json/CdsServiceRequestContextJson.java | 2 + .../fhir/cdshooks/config/CdsHooksConfig.java | 5 +- .../controller/CdsHooksController.java | 3 +- .../CdsServiceRequestJsonDeserializer.java | 111 ++++++----- .../cdshooks/svc/CdsServiceRegistryImpl.java | 23 +-- .../controller/CdsHooksControllerTest.java | 15 +- ...CdsServiceRequestJsonDeserializerTest.java | 187 ++++++++++++------ .../svc/CdsServiceRegistryImplTest.java | 7 +- hapi-fhir-server-mdm/pom.xml | 2 +- hapi-fhir-server-openapi/pom.xml | 2 +- hapi-fhir-server/pom.xml | 2 +- .../hapi-fhir-caching-api/pom.xml | 2 +- .../hapi-fhir-caching-caffeine/pom.xml | 4 +- .../hapi-fhir-caching-guava/pom.xml | 2 +- .../hapi-fhir-caching-testing/pom.xml | 2 +- hapi-fhir-serviceloaders/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../hapi-fhir-spring-boot-samples/pom.xml | 2 +- .../hapi-fhir-spring-boot-starter/pom.xml | 2 +- hapi-fhir-spring-boot/pom.xml | 2 +- hapi-fhir-sql-migrate/pom.xml | 2 +- hapi-fhir-storage-batch2-jobs/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-storage-batch2/pom.xml | 2 +- hapi-fhir-storage-cr/pom.xml | 2 +- hapi-fhir-storage-mdm/pom.xml | 2 +- hapi-fhir-storage-test-utilities/pom.xml | 2 +- hapi-fhir-storage/pom.xml | 2 +- hapi-fhir-structures-dstu2.1/pom.xml | 2 +- hapi-fhir-structures-dstu2/pom.xml | 2 +- hapi-fhir-structures-dstu3/pom.xml | 2 +- hapi-fhir-structures-hl7org-dstu2/pom.xml | 2 +- hapi-fhir-structures-r4/pom.xml | 2 +- hapi-fhir-structures-r4b/pom.xml | 2 +- hapi-fhir-structures-r5/pom.xml | 2 +- hapi-fhir-test-utilities/pom.xml | 2 +- hapi-fhir-testpage-overlay/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-validation-resources-dstu2/pom.xml | 2 +- hapi-fhir-validation-resources-dstu3/pom.xml | 2 +- hapi-fhir-validation-resources-r4/pom.xml | 2 +- hapi-fhir-validation-resources-r4b/pom.xml | 2 +- hapi-fhir-validation-resources-r5/pom.xml | 2 +- hapi-fhir-validation/pom.xml | 2 +- hapi-tinder-plugin/pom.xml | 2 +- hapi-tinder-test/pom.xml | 2 +- pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- 88 files changed, 305 insertions(+), 214 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6262-fix-cds-hooks-invocation-when-extension-passed-in-request.yaml diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index b6007b191bb..a63d30df6f8 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 53f3353e6a7..bbb4e7d9acb 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 6cec98a4b87..b845c698f1b 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index b18421ade9c..22b8724f7e8 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -4,7 +4,7 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT pom HAPI FHIR BOM @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 34b9a244edc..e3a44edd071 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index d8ade0aa363..64ba6637ea2 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 7997bade47d..c6e0de92d36 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index 6ad7cc96fd9..25ee977592a 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index d1d0a155112..5e6bb12d288 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index c0837508600..53a25a1d95d 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 99cc8732e05..8ee8cee53fa 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index f9fdfc45a2c..ed0a4dd5507 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index 7659f76387a..095b30baec8 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6262-fix-cds-hooks-invocation-when-extension-passed-in-request.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6262-fix-cds-hooks-invocation-when-extension-passed-in-request.yaml new file mode 100644 index 00000000000..a68ee312359 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6262-fix-cds-hooks-invocation-when-extension-passed-in-request.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 6262 +title: "Previously, when a `extension` was passed in as a part of the CDS hooks request, it would result in a `400 service not found`. This behaviour has now been fixed." diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index a104bf476fb..c15128beca5 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index dd8da0f3742..4346a3fd25d 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index 85a9534d7d5..c01367fde30 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 54888458cbf..4a7722fa96d 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index 541c6bcf8e4..63278c80de9 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-hfql/pom.xml b/hapi-fhir-jpaserver-hfql/pom.xml index c3518186230..b645a59783e 100644 --- a/hapi-fhir-jpaserver-hfql/pom.xml +++ b/hapi-fhir-jpaserver-hfql/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml index c3bb21c52f4..854a185fe21 100644 --- a/hapi-fhir-jpaserver-ips/pom.xml +++ b/hapi-fhir-jpaserver-ips/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index c0b4ddef5d2..33f317dc5d5 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 9ee46575c6e..3eb70e0326c 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index 7c33dcd01cc..1a24fcf3297 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 4e85901e5e9..ba09eed0ab5 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index fe968fe84cb..c3f924fd915 100644 --- a/hapi-fhir-jpaserver-test-dstu2/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index e8d0f1f6bb4..d665c0f3c97 100644 --- a/hapi-fhir-jpaserver-test-dstu3/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index 548d7257155..86ac609723f 100644 --- a/hapi-fhir-jpaserver-test-r4/pom.xml +++ b/hapi-fhir-jpaserver-test-r4/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index 37dad0b5380..dec34cddda1 100644 --- a/hapi-fhir-jpaserver-test-r4b/pom.xml +++ b/hapi-fhir-jpaserver-test-r4b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml index 9922a18d6d9..32b02b3e1ad 100644 --- a/hapi-fhir-jpaserver-test-r5/pom.xml +++ b/hapi-fhir-jpaserver-test-r5/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index 61c593d03cf..71e63e55591 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 47dd4ef075c..f62519f252c 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-cds-hooks/pom.xml b/hapi-fhir-server-cds-hooks/pom.xml index 5f52f9cdf23..1f396dc4fdc 100644 --- a/hapi-fhir-server-cds-hooks/pom.xml +++ b/hapi-fhir-server-cds-hooks/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/ICdsServiceRegistry.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/ICdsServiceRegistry.java index e385650dc25..e3002797b60 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/ICdsServiceRegistry.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/ICdsServiceRegistry.java @@ -45,7 +45,7 @@ public interface ICdsServiceRegistry { * @param theCdsServiceRequestJson the service request * @return the service response */ - CdsServiceResponseJson callService(String theServiceId, CdsServiceRequestJson theCdsServiceRequestJson); + CdsServiceResponseJson callService(String theServiceId, Object theCdsServiceRequestJson); /** * This is the REST method available at https://example.com/cds-services/{theServiceId}/feedback diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsHooksExtension.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsHooksExtension.java index adfbf119e5d..f4d41bc2189 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsHooksExtension.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsHooksExtension.java @@ -20,9 +20,11 @@ package ca.uhn.hapi.fhir.cdshooks.api.json; import ca.uhn.fhir.model.api.IModelJson; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * Users can define CDS Hooks extensions by extending this class. * Implementors can extend this class for defining their custom extensions. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class CdsHooksExtension implements IModelJson {} diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsServiceRequestContextJson.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsServiceRequestContextJson.java index de2988594c7..9fb8649e5ee 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsServiceRequestContextJson.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/api/json/CdsServiceRequestContextJson.java @@ -21,6 +21,7 @@ package ca.uhn.hapi.fhir.cdshooks.api.json; import ca.uhn.fhir.model.api.IModelJson; import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.hl7.fhir.instance.model.api.IBaseResource; import java.util.Collections; @@ -29,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +@JsonIgnoreProperties(ignoreUnknown = true) public class CdsServiceRequestContextJson extends BaseCdsServiceJson implements IModelJson { @JsonAnyGetter diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/config/CdsHooksConfig.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/config/CdsHooksConfig.java index 37efd73711c..34f9b2258ab 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/config/CdsHooksConfig.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/config/CdsHooksConfig.java @@ -31,6 +31,7 @@ import ca.uhn.hapi.fhir.cdshooks.api.ICdsConfigService; import ca.uhn.hapi.fhir.cdshooks.api.ICdsHooksDaoAuthorizationSvc; import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry; import ca.uhn.hapi.fhir.cdshooks.module.CdsHooksObjectMapperFactory; +import ca.uhn.hapi.fhir.cdshooks.serializer.CdsServiceRequestJsonDeserializer; import ca.uhn.hapi.fhir.cdshooks.svc.CdsConfigServiceImpl; import ca.uhn.hapi.fhir.cdshooks.svc.CdsHooksContextBooter; import ca.uhn.hapi.fhir.cdshooks.svc.CdsServiceRegistryImpl; @@ -100,13 +101,15 @@ public class CdsHooksConfig { ICdsCrServiceFactory theCdsCrServiceFactory, ICrDiscoveryServiceFactory theCrDiscoveryServiceFactory, FhirContext theFhirContext) { + final CdsServiceRequestJsonDeserializer cdsServiceRequestJsonDeserializer = + new CdsServiceRequestJsonDeserializer(theFhirContext, theObjectMapper); return new CdsServiceRegistryImpl( theCdsHooksContextBooter, theCdsPrefetchSvc, theObjectMapper, theCdsCrServiceFactory, theCrDiscoveryServiceFactory, - theFhirContext); + cdsServiceRequestJsonDeserializer); } @Bean diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksController.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksController.java index 10896e2f74a..0ae202abec4 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksController.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksController.java @@ -21,7 +21,6 @@ package ca.uhn.hapi.fhir.cdshooks.controller; import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceFeedbackJson; -import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServicesJson; import org.springframework.http.HttpStatus; @@ -73,7 +72,7 @@ public class CdsHooksController { method = {RequestMethod.POST}, consumes = {MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity cdsServiceRequest( - @PathVariable("cds_hook") String theCdsHook, @RequestBody CdsServiceRequestJson theCdsServiceRequestJson) { + @PathVariable("cds_hook") String theCdsHook, @RequestBody Object theCdsServiceRequestJson) { CdsServiceResponseJson response = myCdsServiceRegistry.callService(theCdsHook, theCdsServiceRequestJson); return ResponseEntity.status(200) .contentType(MediaType.APPLICATION_JSON) diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializer.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializer.java index 6019a3d114c..d64ff9c3964 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializer.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializer.java @@ -20,84 +20,60 @@ package ca.uhn.hapi.fhir.cdshooks.serializer; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.serializer.FhirResourceDeserializer; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsHooksExtension; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestContextJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson; -import ca.uhn.hapi.fhir.cdshooks.svc.CdsServiceRegistryImpl; -import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.module.SimpleModule; +import jakarta.annotation.Nonnull; import org.hl7.fhir.instance.model.api.IBaseResource; -import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; -public class CdsServiceRequestJsonDeserializer extends StdDeserializer { - - private final CdsServiceRegistryImpl myCdsServiceRegistry; +public class CdsServiceRequestJsonDeserializer { private final ObjectMapper myObjectMapper; private final FhirContext myFhirContext; private final IParser myParser; - public CdsServiceRequestJsonDeserializer(CdsServiceRegistryImpl theCdsServiceRegistry, FhirContext theFhirContext) { - super(CdsServiceRequestJson.class); - myCdsServiceRegistry = theCdsServiceRegistry; + public CdsServiceRequestJsonDeserializer( + @Nonnull FhirContext theFhirContext, @Nonnull ObjectMapper theObjectMapper) { myFhirContext = theFhirContext; myParser = myFhirContext.newJsonParser().setPrettyPrint(true); - // We create a new ObjectMapper instead of using the one from the ApplicationContext to avoid an infinite loop - // during deserialization. - myObjectMapper = new ObjectMapper(); - configureObjectMapper(myObjectMapper); + myObjectMapper = theObjectMapper; } - @Override - public CdsServiceRequestJson deserialize(JsonParser theJsonParser, DeserializationContext theDeserializationContext) - throws IOException { - final JsonNode cdsServiceRequestJsonNode = theJsonParser.getCodec().readTree(theJsonParser); - final JsonNode hookNode = cdsServiceRequestJsonNode.get("hook"); - final JsonNode extensionNode = cdsServiceRequestJsonNode.get("extension"); - final JsonNode requestContext = cdsServiceRequestJsonNode.get("context"); - final CdsServiceRequestJson cdsServiceRequestJson = - myObjectMapper.treeToValue(cdsServiceRequestJsonNode, CdsServiceRequestJson.class); - if (extensionNode != null) { - CdsHooksExtension myRequestExtension = deserializeExtension(hookNode.textValue(), extensionNode.toString()); - cdsServiceRequestJson.setExtension(myRequestExtension); + public CdsServiceRequestJson deserialize( + @Nonnull CdsServiceJson theCdsServiceJson, @Nonnull Object theCdsServiceRequestJson) { + final JsonNode cdsServiceRequestJsonNode = + myObjectMapper.convertValue(theCdsServiceRequestJson, JsonNode.class); + final JsonNode contextNode = cdsServiceRequestJsonNode.get("context"); + validateHookInstance(cdsServiceRequestJsonNode.get("hookInstance")); + validateHook(cdsServiceRequestJsonNode.get("hook")); + validateContext(contextNode); + try { + final JsonNode extensionNode = cdsServiceRequestJsonNode.get("extension"); + final CdsServiceRequestJson cdsServiceRequestJson = + myObjectMapper.convertValue(cdsServiceRequestJsonNode, CdsServiceRequestJson.class); + LinkedHashMap map = myObjectMapper.readValue(contextNode.toString(), LinkedHashMap.class); + cdsServiceRequestJson.setContext(deserializeContext(map)); + if (extensionNode != null) { + CdsHooksExtension myRequestExtension = + deserializeExtension(theCdsServiceJson, extensionNode.toString()); + cdsServiceRequestJson.setExtension(myRequestExtension); + } + return cdsServiceRequestJson; + } catch (JsonProcessingException | IllegalArgumentException theEx) { + throw new InvalidRequestException(Msg.code(2551) + "Invalid CdsServiceRequest received. " + theEx); } - if (requestContext != null) { - LinkedHashMap map = - myObjectMapper.readValue(requestContext.toString(), LinkedHashMap.class); - cdsServiceRequestJson.setContext(deserializeRequestContext(map)); - } - return cdsServiceRequestJson; } - void configureObjectMapper(ObjectMapper theObjectMapper) { - SimpleModule module = new SimpleModule(); - module.addDeserializer(IBaseResource.class, new FhirResourceDeserializer(myFhirContext)); - theObjectMapper.registerModule(module); - // set this as we will need to ignore properties which are not defined by specific implementation. - theObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } - - CdsHooksExtension deserializeExtension(String theServiceId, String theExtension) throws JsonProcessingException { - final CdsServiceJson cdsServicesJson = myCdsServiceRegistry.getCdsServiceJson(theServiceId); - Class extensionClass = cdsServicesJson.getExtensionClass(); - if (extensionClass == null) { - return null; - } - return myObjectMapper.readValue(theExtension, extensionClass); - } - - CdsServiceRequestContextJson deserializeRequestContext(LinkedHashMap theMap) + CdsServiceRequestContextJson deserializeContext(LinkedHashMap theMap) throws JsonProcessingException { final CdsServiceRequestContextJson cdsServiceRequestContextJson = new CdsServiceRequestContextJson(); for (Map.Entry entry : theMap.entrySet()) { @@ -114,4 +90,31 @@ public class CdsServiceRequestJsonDeserializer extends StdDeserializer extensionClass = theCdsServiceJson.getExtensionClass(); + if (extensionClass == null) { + return null; + } + return myObjectMapper.readValue(theExtension, extensionClass); + } + + private void validateHook(JsonNode hookIdNode) { + if (hookIdNode == null) { + throw new InvalidRequestException(Msg.code(2549) + "hook cannot be null for a CdsServiceRequest."); + } + } + + private void validateHookInstance(JsonNode hookInstanceNode) { + if (hookInstanceNode == null) { + throw new InvalidRequestException(Msg.code(2548) + "hookInstance cannot be null for a CdsServiceRequest."); + } + } + + private void validateContext(JsonNode requestContextNode) { + if (requestContextNode == null) { + throw new InvalidRequestException(Msg.code(2550) + "context cannot be null for a CdsServiceRequest."); + } + } } diff --git a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImpl.java b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImpl.java index 720fca731d7..8613dee9554 100644 --- a/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImpl.java +++ b/hapi-fhir-server-cds-hooks/src/main/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImpl.java @@ -20,7 +20,6 @@ package ca.uhn.hapi.fhir.cdshooks.svc; import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.hapi.fhir.cdshooks.api.ICdsMethod; @@ -38,7 +37,6 @@ import ca.uhn.hapi.fhir.cdshooks.svc.cr.discovery.ICrDiscoveryServiceFactory; import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsPrefetchSvc; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.annotation.PostConstruct; @@ -50,7 +48,7 @@ import java.util.function.Function; public class CdsServiceRegistryImpl implements ICdsServiceRegistry { private static final Logger ourLog = LoggerFactory.getLogger(CdsServiceRegistryImpl.class); - + private final CdsServiceRequestJsonDeserializer myCdsServiceRequestJsonDeserializer; private CdsServiceCache myServiceCache; private final CdsHooksContextBooter myCdsHooksContextBooter; @@ -65,19 +63,13 @@ public class CdsServiceRegistryImpl implements ICdsServiceRegistry { ObjectMapper theObjectMapper, ICdsCrServiceFactory theCdsCrServiceFactory, ICrDiscoveryServiceFactory theCrDiscoveryServiceFactory, - FhirContext theFhirContext) { + CdsServiceRequestJsonDeserializer theCdsServiceRequestJsonDeserializer) { myCdsHooksContextBooter = theCdsHooksContextBooter; myCdsPrefetchSvc = theCdsPrefetchSvc; myObjectMapper = theObjectMapper; - // registering this deserializer here instead of - // CdsHooksObjectMapperFactory to avoid circular - // dependency - SimpleModule module = new SimpleModule(); - module.addDeserializer( - CdsServiceRequestJson.class, new CdsServiceRequestJsonDeserializer(this, theFhirContext)); - myObjectMapper.registerModule(module); myCdsCrServiceFactory = theCdsCrServiceFactory; myCrDiscoveryServiceFactory = theCrDiscoveryServiceFactory; + myCdsServiceRequestJsonDeserializer = theCdsServiceRequestJsonDeserializer; } @PostConstruct @@ -91,10 +83,13 @@ public class CdsServiceRegistryImpl implements ICdsServiceRegistry { } @Override - public CdsServiceResponseJson callService(String theServiceId, CdsServiceRequestJson theCdsServiceRequestJson) { + public CdsServiceResponseJson callService(String theServiceId, Object theCdsServiceRequestJson) { + final CdsServiceJson cdsServiceJson = getCdsServiceJson(theServiceId); + final CdsServiceRequestJson deserializedRequest = + myCdsServiceRequestJsonDeserializer.deserialize(cdsServiceJson, theCdsServiceRequestJson); ICdsServiceMethod serviceMethod = (ICdsServiceMethod) getCdsServiceMethodOrThrowException(theServiceId); - myCdsPrefetchSvc.augmentRequest(theCdsServiceRequestJson, serviceMethod); - Object response = serviceMethod.invoke(myObjectMapper, theCdsServiceRequestJson, theServiceId); + myCdsPrefetchSvc.augmentRequest(deserializedRequest, serviceMethod); + Object response = serviceMethod.invoke(myObjectMapper, deserializedRequest, theServiceId); return encodeServiceResponse(theServiceId, response); } diff --git a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksControllerTest.java b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksControllerTest.java index e6067fc16f4..22065764b41 100644 --- a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksControllerTest.java +++ b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/controller/CdsHooksControllerTest.java @@ -5,6 +5,7 @@ import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceFeebackOutcomeEnum; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceFeedbackJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson; +import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestContextJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseCardJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseJson; @@ -118,6 +119,7 @@ public class CdsHooksControllerTest { request.setHookInstance(TEST_HOOK_INSTANCE); request.setHook(HelloWorldService.TEST_HOOK); request.setFhirServer(TEST_FHIR_SERVER); + request.setContext( withCdsServiceRequestContext()); String requestBody = myObjectMapper.writeValueAsString(request); @@ -142,8 +144,9 @@ public class CdsHooksControllerTest { CdsServiceRequestJson request = new CdsServiceRequestJson(); request.setExtension(requestExtension); request.setFhirServer(TEST_FHIR_SERVER); - request.setHook(HelloWorldService.TEST_HOOK_UNIVERSE_ID); - + request.setHook(HelloWorldService.TEST_HOOK); + request.setContext(withCdsServiceRequestContext()); + request.setHookInstance(UUID.randomUUID().toString()); String requestBody = myObjectMapper.writeValueAsString(request); @@ -163,6 +166,7 @@ public class CdsHooksControllerTest { request.setHookInstance(TEST_HOOK_INSTANCE); request.setHook(HelloWorldService.TEST_HOOK); request.setFhirServer(TEST_FHIR_SERVER); + request.setContext(withCdsServiceRequestContext()); String requestBody = myObjectMapper.writeValueAsString(request); @@ -268,4 +272,11 @@ public class CdsHooksControllerTest { return JsonUtil.serialize(input, true); } + @Nonnull + private static CdsServiceRequestContextJson withCdsServiceRequestContext() { + CdsServiceRequestContextJson cdsServiceRequestContextJson = new CdsServiceRequestContextJson(); + cdsServiceRequestContextJson.put("patientId", "Patient/123"); + return cdsServiceRequestContextJson; + } + } diff --git a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializerTest.java b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializerTest.java index 0e1e659cc8a..ecd8176ce6a 100644 --- a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializerTest.java +++ b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/serializer/CdsServiceRequestJsonDeserializerTest.java @@ -1,106 +1,152 @@ package ca.uhn.hapi.fhir.cdshooks.serializer; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.hapi.fhir.cdshooks.api.json.CdsHooksExtension; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestContextJson; +import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson; import ca.uhn.hapi.fhir.cdshooks.custom.extensions.model.ExampleExtension; -import ca.uhn.hapi.fhir.cdshooks.svc.CdsServiceRegistryImpl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Nonnull; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.util.LinkedHashMap; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.doReturn; +import static org.assertj.core.api.Assertions.assertThatThrownBy; -@ExtendWith(MockitoExtension.class) class CdsServiceRequestJsonDeserializerTest { - @Mock - private CdsServiceRegistryImpl myCdsServiceRegistry; + private static final String SERVICE_ID = "service-id"; + private static final String EXAMPLE_PROPERTY_VALUE = "example-value"; + private static final String EXAMPLE_PROPERTY_KEY = "example-property"; + private static final String HOOK_ID = "hook-id"; private final FhirContext myFhirContext = FhirContext.forR4(); + private final ObjectMapper myObjectMapper = new ObjectMapper(); private CdsServiceRequestJsonDeserializer myFixture; @BeforeEach() void setup() { - myFixture = new CdsServiceRequestJsonDeserializer(myCdsServiceRegistry, myFhirContext); + myFixture = new CdsServiceRequestJsonDeserializer(myFhirContext, myObjectMapper); } @Test - void configureObjectMapper() { + void deserialize_shouldDeserialize_whenValidCdsServiceRequestWithExtensionReceived() { // setup - ObjectMapper input = new ObjectMapper(); + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap extension = withExtension(); + final LinkedHashMap request = withRequest(extension); + request.put("context", withContext()); // execute - myFixture.configureObjectMapper(input); + final CdsServiceRequestJson actual = myFixture.deserialize(cdsServiceJson, request); // validate - assertThat(input.getRegisteredModuleIds()).hasSize(1); + assertThat(actual.getExtension()).isInstanceOf(ExampleExtension.class); + final ExampleExtension actualExtension = (ExampleExtension) actual.getExtension(); + assertThat(actualExtension.getExampleProperty()).isEqualTo(EXAMPLE_PROPERTY_VALUE); } @Test - void deserializeExtensionWhenClassFoundShouldDeserializeExtension() throws JsonProcessingException { + void deserialize_shouldIgnoreExtraFieldsInsideExtension_whenExtensionContainsMoreFieldsThanDefinedInClass() { + // setup + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap extension = withExtension(); + extension.put("example-extra-property", "example-extra-value"); + final LinkedHashMap request = withRequest(extension); + request.put("context", withContext()); + // execute + final CdsServiceRequestJson actual = myFixture.deserialize(cdsServiceJson, request); + // validate + assertThat(actual.getExtension()).isInstanceOf(ExampleExtension.class); + final ExampleExtension actualExtension = (ExampleExtension) actual.getExtension(); + assertThat(actualExtension.getExampleProperty()).isEqualTo(EXAMPLE_PROPERTY_VALUE); + assertThat(actual.getContext().get("encounterId")).isEqualTo("Encounter/123"); + } + + @Nonnull + private static LinkedHashMap withContext() { + final LinkedHashMap context = new LinkedHashMap<>(); + context.put("encounterId", "Encounter/123"); + return context; + } + + @Test + void deserialize_shouldThrow_whenCdsServiceRequestIncludesInvalidProperty() { + // setup + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap extension = withExtension(); + final LinkedHashMap request = withRequest(extension); + request.put("invalid-key", "some-value"); + request.put("context", withContext()); + // execute & validate + assertThatThrownBy( + () -> myFixture.deserialize(cdsServiceJson, request)) + .isInstanceOf(InvalidRequestException.class) + .hasMessageContaining("HAPI-2551:") + .hasMessageContaining("Invalid CdsServiceRequest received."); + } + + @Test + void deserialize_shouldReturnNullExtension_whenNotClassFound() { // setup - final String serviceId = "service-id"; - final String extension = """ - { - "example-property": "example-value" - } - """; final CdsServiceJson cdsServiceJson = new CdsServiceJson(); - cdsServiceJson.setId(serviceId); - cdsServiceJson.setExtensionClass(ExampleExtension.class); - doReturn(cdsServiceJson).when(myCdsServiceRegistry).getCdsServiceJson(serviceId); + cdsServiceJson.setId(SERVICE_ID); + final LinkedHashMap extension = withExtension(); + extension.put("example-extra-property", "example-extra-value"); + final LinkedHashMap request = withRequest(extension); + request.put("context", withContext()); // execute - final ExampleExtension actual = (ExampleExtension) myFixture.deserializeExtension(serviceId, extension); + final CdsServiceRequestJson actual = myFixture.deserialize(cdsServiceJson, request); // validate - assertThat(actual.getExampleProperty()).isEqualTo("example-value"); + assertThat(actual.getExtension()).isNull(); } @Test - void deserializeExtensionWhenClassFoundButExtensionHasExtraPropertiesShouldIgnoreExtraProperties() throws JsonProcessingException { + void deserialize_shouldThrow_whenHookNotFoundInRequest() { // setup - final String serviceId = "service-id"; - final String extension = """ - { - "example-property": "example-value", - "example-extra-property": "example-extra-value" - } - """; - final CdsServiceJson cdsServiceJson = new CdsServiceJson(); - cdsServiceJson.setId(serviceId); - cdsServiceJson.setExtensionClass(ExampleExtension.class); - doReturn(cdsServiceJson).when(myCdsServiceRegistry).getCdsServiceJson(serviceId); - // execute - final ExampleExtension actual = (ExampleExtension) myFixture.deserializeExtension(serviceId, extension); - // validate - assertThat(actual.getExampleProperty()).isEqualTo("example-value"); + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap request = new LinkedHashMap<>(); + request.put("context", withContext()); + request.put("hookInstance", UUID.randomUUID().toString()); + // execute and validate + assertThatThrownBy(() -> myFixture.deserialize(cdsServiceJson, request)) + .isInstanceOf(InvalidRequestException.class) + .hasMessageContaining("HAPI-2549:") + .hasMessageContaining("hook cannot be null for a CdsServiceRequest."); } @Test - void deserializeExtensionWhenNotClassFoundShouldReturnNull() throws JsonProcessingException { + void deserialize_shouldThrow_whenContextNotFoundInRequest() { // setup - final String serviceId = "service-id"; - final String extension = """ - { - "example-property": "example-value" - } - """; - final CdsServiceJson cdsServiceJson = new CdsServiceJson(); - cdsServiceJson.setId(serviceId); - doReturn(cdsServiceJson).when(myCdsServiceRegistry).getCdsServiceJson(serviceId); - // execute - final CdsHooksExtension actual = myFixture.deserializeExtension(serviceId, extension); - // validate - assertThat(actual).isNull(); + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap request = new LinkedHashMap<>(); + request.put("hook", HOOK_ID); + request.put("hookInstance", UUID.randomUUID().toString()); + // execute and validate + assertThatThrownBy(() -> myFixture.deserialize(cdsServiceJson, request)) + .isInstanceOf(InvalidRequestException.class) + .hasMessageContaining("HAPI-2550:") + .hasMessageContaining("context cannot be null for a CdsServiceRequest."); } @Test - void deserializeRequestContextShouldDeserializeValidContext() throws JsonProcessingException { + void deserialize_shouldThrow_whenHookInstanceNotFoundInRequest() { + // setup + final CdsServiceJson cdsServiceJson = withCdsServiceJsonIncludingExtensionClass(); + final LinkedHashMap request = new LinkedHashMap<>(); + request.put("context", withContext()); + request.put("hook", HOOK_ID); + // execute and validate + assertThatThrownBy(() -> myFixture.deserialize(cdsServiceJson, request)) + .isInstanceOf(InvalidRequestException.class) + .hasMessageContaining("HAPI-2548:") + .hasMessageContaining("hookInstance cannot be null for a CdsServiceRequest."); + } + + @Test + void deserializeRequestContext_shouldDeserialize_whenContextIsValid() throws JsonProcessingException { // setup final String encounterId = "123"; final Patient patientContext = new Patient(); @@ -109,9 +155,34 @@ class CdsServiceRequestJsonDeserializerTest { input.put("encounterId", encounterId); input.put("patient", patientContext); // execute - final CdsServiceRequestContextJson actual = myFixture.deserializeRequestContext(input); + final CdsServiceRequestContextJson actual = myFixture.deserializeContext(input); // validate assertThat(actual.get("encounterId")).isEqualTo(encounterId); assertThat(actual.get("patient")).usingRecursiveComparison().isEqualTo(patientContext); } + + @Nonnull + private static LinkedHashMap withExtension() { + final LinkedHashMap extension = new LinkedHashMap<>(); + extension.put(EXAMPLE_PROPERTY_KEY, EXAMPLE_PROPERTY_VALUE); + return extension; + } + + @Nonnull + private static CdsServiceJson withCdsServiceJsonIncludingExtensionClass() { + final CdsServiceJson cdsServiceJson = new CdsServiceJson(); + cdsServiceJson.setId(SERVICE_ID); + cdsServiceJson.setExtensionClass(ExampleExtension.class); + cdsServiceJson.setHook(HOOK_ID); + return cdsServiceJson; + } + + @Nonnull + private static LinkedHashMap withRequest(@Nonnull LinkedHashMap theExtension) { + final LinkedHashMap request = new LinkedHashMap<>(); + request.put("extension", theExtension); + request.put("hookInstance", UUID.randomUUID().toString()); + request.put("hook", HOOK_ID); + return request; + } } diff --git a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImplTest.java b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImplTest.java index 4bb7f699331..3ba49b9f5f6 100644 --- a/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImplTest.java +++ b/hapi-fhir-server-cds-hooks/src/test/java/ca/uhn/hapi/fhir/cdshooks/svc/CdsServiceRegistryImplTest.java @@ -1,10 +1,10 @@ package ca.uhn.hapi.fhir.cdshooks.svc; import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceFeedbackJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceJson; import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseJson; +import ca.uhn.hapi.fhir.cdshooks.serializer.CdsServiceRequestJsonDeserializer; import ca.uhn.hapi.fhir.cdshooks.svc.cr.ICdsCrServiceFactory; import ca.uhn.hapi.fhir.cdshooks.svc.cr.discovery.ICrDiscoveryServiceFactory; import ca.uhn.hapi.fhir.cdshooks.svc.prefetch.CdsPrefetchSvc; @@ -33,13 +33,14 @@ class CdsServiceRegistryImplTest { private ICrDiscoveryServiceFactory myCrDiscoveryServiceFactory; @Mock private CdsServiceCache myCdsServiceCache; + @Mock + private CdsServiceRequestJsonDeserializer myCdsServiceRequestJsonDeserializer; private final ObjectMapper myObjectMapper = new ObjectMapper(); - private final FhirContext myFhirContext = FhirContext.forR4(); private CdsServiceRegistryImpl myFixture; @BeforeEach() void setup() { - myFixture = new CdsServiceRegistryImpl(myCdsHooksContextBooter, myCdsPrefetchSvc, myObjectMapper, myCdsCrServiceFactory, myCrDiscoveryServiceFactory, myFhirContext); + myFixture = new CdsServiceRegistryImpl(myCdsHooksContextBooter, myCdsPrefetchSvc, myObjectMapper, myCdsCrServiceFactory, myCrDiscoveryServiceFactory, myCdsServiceRequestJsonDeserializer); } @Test diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 5e2b9ee3e05..95abe58fe85 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index 8850b3445eb..89e2600dd02 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index 457cd28044c..be0015008a1 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml index cee8e510785..39836ddc8e4 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml index 428f89dc3d4..e8eae8ff086 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index 8dc3778e4ab..89e57090090 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml index f3a6f30fdc7..1d43c70ed0e 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml @@ -7,7 +7,7 @@ hapi-fhir ca.uhn.hapi.fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index dc407e19ef3..13859f26fee 100644 --- a/hapi-fhir-serviceloaders/pom.xml +++ b/hapi-fhir-serviceloaders/pom.xml @@ -5,7 +5,7 @@ hapi-deployable-pom ca.uhn.hapi.fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 58fdac09a26..7301924dde5 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 7a634812925..137bd075790 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index 7fd06fcf3bf..106a0cf80bf 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index 1f735d48418..0c2e4ed2f08 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index 62f9c031867..6c62b628f06 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index b65824baf92..52a41c7dc64 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index d7c752647e1..4877a32ed4f 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 429c1914686..08f9decc2d8 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 6ad5389cf0f..bcab73f8584 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-test-utilities/pom.xml b/hapi-fhir-storage-batch2-test-utilities/pom.xml index c5433cf41b0..e695c5bed3f 100644 --- a/hapi-fhir-storage-batch2-test-utilities/pom.xml +++ b/hapi-fhir-storage-batch2-test-utilities/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 28434f97f04..682fa7b8e69 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index 3cc3d4e2d6c..8d77500f0de 100644 --- a/hapi-fhir-storage-cr/pom.xml +++ b/hapi-fhir-storage-cr/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index 6075061dc6a..7f6779287ec 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index db16c567f49..2496ea7f0ba 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index b20baf0c3d7..dbf8d1ced1d 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index ad65f33ad54..9b0b6862b32 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 891eb98b319..718c23b5326 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index cf3ae30aba5..99473d8ea42 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index dc22111adef..c93237fa349 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 612e2dcfb14..fa613174e8a 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index a810259a2c7..4eb3c7bd63b 100644 --- a/hapi-fhir-structures-r4b/pom.xml +++ b/hapi-fhir-structures-r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index a3c7f077788..10380569b8a 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 23ef56c067d..f29a7f80edc 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 86cb5491962..fca8cd4ec66 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 39a50f70244..2e4c696ee12 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 1cd6e7487ec..138e7289d27 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index f50bea30960..e0004b8c837 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index f0c88093297..c6ab551404a 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4b/pom.xml b/hapi-fhir-validation-resources-r4b/pom.xml index 75b31d7a730..325d05648e8 100644 --- a/hapi-fhir-validation-resources-r4b/pom.xml +++ b/hapi-fhir-validation-resources-r4b/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 97ca30bf0c8..b853d0cc3ab 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 64edc13bbe8..49d73daa1e0 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 78c7469c56f..94029265a48 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index c8b8229c4ba..466e9d27784 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index a7cae721347..e6f098ceece 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index ed8ad2356a4..f69c2fd2d79 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index 7e5d062d647..991c29eff82 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 487e1f73df6..4e278702a42 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.5.0-SNAPSHOT + 7.5.1-SNAPSHOT ../../pom.xml From fb93c3d601272a146904e438c11af93f32e70f1e Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Thu, 19 Sep 2024 13:59:58 -0400 Subject: [PATCH 10/13] Expose hapi-fhir-storage-cr config to downstream modules for testing (#6272) * Ensure IRepositoryFactory returns a Repository, and not a HapiFhirRepository. * Rename test so that it will run from Maven and the pipeline since it didn't before. Fix small bug that made the test error out. * Move TestCrConfig and TestCrR4Config to main source folder. Extract TestHapiFhirCrPartitionConfig as separate test config to be used only in the test source folder. Add Maven compile dependency to hapi-fhir-jpaserver-base in order to ensure that moved Config classes will compile. * Add possible code change to RequestDetailsClone to clone partition info. * Introduce separate factory interface for Repository to preserve backward compatibility. * Remove IRepositoryFactoryForInterface. * Spotless * Add javadoc. * Get rid of TODO. * Restore RepositoryConfig to master. * Move test config to different packages. * Leverage use of new RepositoryFactoryForRepositoryInterface for CrR4Config and RepositoryFactoryForRepositoryInterface. * Ensure CrR4Config and RepositoryConfig make use of new RepositoryFactoryForRepositoryInterface. * Add copyright header * Add @FunctionalInterface to factory. --- hapi-fhir-storage-cr/pom.xml | 14 ++++++++ .../fhir/cr/common/IRepositoryFactory.java | 2 ++ ...positoryFactoryForRepositoryInterface.java | 31 +++++++++++++++++ .../uhn/fhir/cr/config/RepositoryConfig.java | 8 +++++ .../ca/uhn/fhir/cr/config/r4/CrR4Config.java | 4 ++- .../cr/config/test}/TestCqlProperties.java | 25 ++++++++++++-- .../fhir/cr/config/test}/TestCrConfig.java | 34 ++++++++++++++----- .../cr/config/test}/r4/TestCrR4Config.java | 28 +++++++++++++-- .../cr/TestHapiFhirCrPartitionConfig.java | 10 ++++++ .../uhn/fhir/cr/dstu3/TestCrDstu3Config.java | 6 ++-- .../ca/uhn/fhir/cr/r4/BaseCrR4TestServer.java | 3 ++ 11 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/RepositoryFactoryForRepositoryInterface.java rename hapi-fhir-storage-cr/src/{test/java/ca/uhn/fhir/cr => main/java/ca/uhn/fhir/cr/config/test}/TestCqlProperties.java (92%) rename hapi-fhir-storage-cr/src/{test/java/ca/uhn/fhir/cr => main/java/ca/uhn/fhir/cr/config/test}/TestCrConfig.java (89%) rename hapi-fhir-storage-cr/src/{test/java/ca/uhn/fhir/cr => main/java/ca/uhn/fhir/cr/config/test}/r4/TestCrR4Config.java (88%) create mode 100644 hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestHapiFhirCrPartitionConfig.java diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index 8d77500f0de..775a22c5e41 100644 --- a/hapi-fhir-storage-cr/pom.xml +++ b/hapi-fhir-storage-cr/pom.xml @@ -145,6 +145,20 @@ jakarta.xml.bind-api + + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-base + ${project.version} + + + + org.glassfish + jakarta.json + + + + org.testcontainers diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/IRepositoryFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/IRepositoryFactory.java index 24963a9cc85..82094e62a6c 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/IRepositoryFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/IRepositoryFactory.java @@ -21,8 +21,10 @@ package ca.uhn.fhir.cr.common; import ca.uhn.fhir.cr.repo.HapiFhirRepository; import ca.uhn.fhir.rest.api.server.RequestDetails; +import com.google.common.annotations.Beta; @FunctionalInterface +@Beta public interface IRepositoryFactory { HapiFhirRepository create(RequestDetails theRequestDetails); } diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/RepositoryFactoryForRepositoryInterface.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/RepositoryFactoryForRepositoryInterface.java new file mode 100644 index 00000000000..a01f5736000 --- /dev/null +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/common/RepositoryFactoryForRepositoryInterface.java @@ -0,0 +1,31 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.common; + +import ca.uhn.fhir.rest.api.server.RequestDetails; +import org.opencds.cqf.fhir.api.Repository; + +/** + * Factory interface to return a {@link Repository} from a {@link RequestDetails} + */ +@FunctionalInterface +public interface RepositoryFactoryForRepositoryInterface { + Repository create(RequestDetails theRequestDetails); +} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/RepositoryConfig.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/RepositoryConfig.java index fb40025f58a..93d4c0f58ce 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/RepositoryConfig.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/RepositoryConfig.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.cr.config; import ca.uhn.fhir.cr.common.IRepositoryFactory; +import ca.uhn.fhir.cr.common.RepositoryFactoryForRepositoryInterface; import ca.uhn.fhir.cr.repo.HapiFhirRepository; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.server.RestfulServer; @@ -28,8 +29,15 @@ import org.springframework.context.annotation.Configuration; @Configuration public class RepositoryConfig { + @Bean IRepositoryFactory repositoryFactory(DaoRegistry theDaoRegistry, RestfulServer theRestfulServer) { return rd -> new HapiFhirRepository(theDaoRegistry, rd, theRestfulServer); } + + @Bean + RepositoryFactoryForRepositoryInterface repositoryFactoryForInterface( + DaoRegistry theDaoRegistry, RestfulServer theRestfulServer) { + return rd -> new HapiFhirRepository(theDaoRegistry, rd, theRestfulServer); + } } diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java index 19466eba19b..3cdc398e0c0 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.cr.config.r4; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.cr.common.IRepositoryFactory; +import ca.uhn.fhir.cr.common.RepositoryFactoryForRepositoryInterface; import ca.uhn.fhir.cr.config.ProviderLoader; import ca.uhn.fhir.cr.config.ProviderSelector; import ca.uhn.fhir.cr.config.RepositoryConfig; @@ -66,7 +67,8 @@ public class CrR4Config { @Bean IMeasureServiceFactory r4MeasureServiceFactory( - IRepositoryFactory theRepositoryFactory, MeasureEvaluationOptions theEvaluationOptions) { + RepositoryFactoryForRepositoryInterface theRepositoryFactory, + MeasureEvaluationOptions theEvaluationOptions) { return rd -> new R4MeasureService(theRepositoryFactory.create(rd), theEvaluationOptions); } diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCqlProperties.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCqlProperties.java similarity index 92% rename from hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCqlProperties.java rename to hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCqlProperties.java index b9c5c081728..1be7c4f3505 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCqlProperties.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCqlProperties.java @@ -1,4 +1,23 @@ -package ca.uhn.fhir.cr; +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.config.test; import org.cqframework.cql.cql2elm.CqlCompilerException; import org.cqframework.cql.cql2elm.CqlCompilerOptions; @@ -7,7 +26,9 @@ import org.cqframework.cql.cql2elm.LibraryBuilder; import org.opencds.cqf.fhir.cql.CqlEngineOptions; import org.opencds.cqf.fhir.cql.CqlOptions; - +/** + * Common CQL properties shared with downstream modules. + */ public class TestCqlProperties { //cql settings diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCrConfig.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCrConfig.java similarity index 89% rename from hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCrConfig.java rename to hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCrConfig.java index 4f42ae49d52..9a9f43a902f 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestCrConfig.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/TestCrConfig.java @@ -1,4 +1,23 @@ -package ca.uhn.fhir.cr; +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.config.test; import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider; import ca.uhn.fhir.context.FhirContext; @@ -47,6 +66,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +/** + * Common hapi-fhir clinical reasoning config shared with downstream modules. + */ @Configuration @Import({SubscriptionSubmitterConfig.class, SubscriptionChannelConfig.class}) public class TestCrConfig { @@ -77,7 +99,9 @@ public class TestCrConfig { } @Bean public TestCqlProperties testCqlProperties(){ - return new TestCqlProperties();} + return new TestCqlProperties(); + } + @Bean public JpaStorageSettings storageSettings() { JpaStorageSettings storageSettings = new JpaStorageSettings(); @@ -87,12 +111,6 @@ public class TestCrConfig { storageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY); return storageSettings; } - - @Bean - public PartitionHelper partitionHelper() { - return new PartitionHelper(); - } - @Bean public ModelManager modelManager(Map theGlobalModelCache) { return new ModelManager(theGlobalModelCache); diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/TestCrR4Config.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/r4/TestCrR4Config.java similarity index 88% rename from hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/TestCrR4Config.java rename to hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/r4/TestCrR4Config.java index e80eab49bc4..9e5b4c50466 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/TestCrR4Config.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/test/r4/TestCrR4Config.java @@ -1,9 +1,28 @@ -package ca.uhn.fhir.cr.r4; +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.config.test.r4; -import ca.uhn.fhir.cr.TestCqlProperties; -import ca.uhn.fhir.cr.TestCrConfig; import ca.uhn.fhir.cr.common.CqlThreadFactory; import ca.uhn.fhir.cr.config.r4.CrR4Config; +import ca.uhn.fhir.cr.config.test.TestCqlProperties; +import ca.uhn.fhir.cr.config.test.TestCrConfig; import org.cqframework.cql.cql2elm.CqlCompilerOptions; import org.cqframework.cql.cql2elm.model.CompiledLibrary; import org.cqframework.cql.cql2elm.model.Model; @@ -30,6 +49,9 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +/** + * Common hapi-fhir clinical reasoning config specifically for R4 shared with downstream modules. + */ @Configuration @Import({TestCrConfig.class, CrR4Config.class}) public class TestCrR4Config { diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestHapiFhirCrPartitionConfig.java b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestHapiFhirCrPartitionConfig.java new file mode 100644 index 00000000000..6b95b55deed --- /dev/null +++ b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/TestHapiFhirCrPartitionConfig.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.cr; + +import org.springframework.context.annotation.Bean; + +public class TestHapiFhirCrPartitionConfig { + @Bean + public PartitionHelper partitionHelper() { + return new PartitionHelper(); + } +} diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/dstu3/TestCrDstu3Config.java b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/dstu3/TestCrDstu3Config.java index 39fc0b34651..a79d4968627 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/dstu3/TestCrDstu3Config.java +++ b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/dstu3/TestCrDstu3Config.java @@ -1,8 +1,9 @@ package ca.uhn.fhir.cr.dstu3; -import ca.uhn.fhir.cr.TestCqlProperties; -import ca.uhn.fhir.cr.TestCrConfig; +import ca.uhn.fhir.cr.TestHapiFhirCrPartitionConfig; +import ca.uhn.fhir.cr.config.test.TestCqlProperties; import ca.uhn.fhir.cr.config.dstu3.CrDstu3Config; +import ca.uhn.fhir.cr.config.test.TestCrConfig; import org.cqframework.cql.cql2elm.CqlCompilerOptions; import org.cqframework.cql.cql2elm.model.CompiledLibrary; import org.cqframework.cql.cql2elm.model.Model; @@ -26,6 +27,7 @@ import java.util.Set; @Configuration @Import({ + TestHapiFhirCrPartitionConfig.class, TestCrConfig.class, CrDstu3Config.class }) diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/BaseCrR4TestServer.java b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/BaseCrR4TestServer.java index 686681d6352..49e31bad8c6 100644 --- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/BaseCrR4TestServer.java +++ b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/BaseCrR4TestServer.java @@ -2,10 +2,12 @@ package ca.uhn.fhir.cr.r4; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.cr.IResourceLoader; +import ca.uhn.fhir.cr.TestHapiFhirCrPartitionConfig; import ca.uhn.fhir.cr.config.r4.ApplyOperationConfig; import ca.uhn.fhir.cr.config.r4.ExtractOperationConfig; import ca.uhn.fhir.cr.config.r4.PackageOperationConfig; import ca.uhn.fhir.cr.config.r4.PopulateOperationConfig; +import ca.uhn.fhir.cr.config.test.r4.TestCrR4Config; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; @@ -38,6 +40,7 @@ import java.util.concurrent.TimeUnit; @ContextConfiguration(classes = { + TestHapiFhirCrPartitionConfig.class, TestCrR4Config.class, ApplyOperationConfig.class, ExtractOperationConfig.class, From 4aea94ccb607bf3100f0f9f0f9db8ade5e1f9066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Delopst?= Date: Tue, 24 Sep 2024 16:43:17 +0200 Subject: [PATCH 11/13] Fix forced ID migration for MSSQL (#6290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Primož Delopst --- .../taskdef/ForceIdMigrationFixTask.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ForceIdMigrationFixTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ForceIdMigrationFixTask.java index 07607a90845..543fd942892 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ForceIdMigrationFixTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/ForceIdMigrationFixTask.java @@ -89,7 +89,7 @@ public class ForceIdMigrationFixTask extends BaseTask { " set fhir_id = coalesce( " + // case 5. - " trim(fhir_id), " + trimFhirId() + // case 3 " (select f.forced_id from hfj_forced_id f where f.resource_pid = res_id), " @@ -109,6 +109,22 @@ public class ForceIdMigrationFixTask extends BaseTask { } } + private String trimFhirId() { + switch (getDriverType()) { + case MSSQL_2012: + return " LTRIM(RTRIM(fhir_id)), "; + case H2_EMBEDDED: + case DERBY_EMBEDDED: + case MARIADB_10_1: + case MYSQL_5_7: + case POSTGRES_9_4: + case ORACLE_12C: + case COCKROACHDB_21_1: + default: + return " trim(fhir_id), "; + } + } + private String getWhereClauseByDBType() { switch (getDriverType()) { case MSSQL_2012: From 20d3e6bb252eff52def255669ca6f590c2d8db59 Mon Sep 17 00:00:00 2001 From: Martha Mitran Date: Tue, 24 Sep 2024 16:46:38 -0700 Subject: [PATCH 12/13] Fix missing qualifier search for reference search parameters (#6306) * Fix missing qualifier search for reference search parameter. Reuse tests and run them for both indexing enabled and disabled. * Fix edge case where the search parameter has multiple paths. Add a test. Fix some of the compile warnings in a test class. * Fix test setup. --- ...er-does-not-work-reference-parameters.yaml | 6 + .../ResourceLinkPredicateBuilder.java | 13 +- .../FhirResourceDaoR4SearchMissingTest.java | 963 +++++++++--------- .../provider/r4/ResourceProviderR4Test.java | 292 +++--- 4 files changed, 631 insertions(+), 643 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6305-search-missing-qualifier-does-not-work-reference-parameters.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6305-search-missing-qualifier-does-not-work-reference-parameters.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6305-search-missing-qualifier-does-not-work-reference-parameters.yaml new file mode 100644 index 00000000000..da98735c073 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6305-search-missing-qualifier-does-not-work-reference-parameters.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 6305 +title: "Previously, when having StorageSettings#getIndexMissingFields() == IndexEnabledEnum.DISABLED (default value) +and attempting to search with the missing qualifier against a resource type with multiple search parameters of type reference, +the returned results would be incorrect. This has been fixed." \ No newline at end of file diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java index ab4b1afdefc..79981c2ca7f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java @@ -800,14 +800,19 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im subquery.addCustomColumns(1); subquery.addFromTable(getTable()); + String resourceType = theParams.getResourceTablePredicateBuilder().getResourceType(); + RuntimeSearchParam paramDefinition = + mySearchParamRegistry.getRuntimeSearchParam(resourceType, theParams.getParamName()); + List pathList = paramDefinition.getPathsSplitForResourceType(resourceType); + Condition subQueryCondition = ComboCondition.and( BinaryCondition.equalTo( getResourceIdColumn(), theParams.getResourceTablePredicateBuilder().getResourceIdColumn()), - BinaryCondition.equalTo( - getResourceTypeColumn(), - generatePlaceholder( - theParams.getResourceTablePredicateBuilder().getResourceType()))); + BinaryCondition.equalTo(getResourceTypeColumn(), generatePlaceholder(resourceType)), + ComboCondition.or(pathList.stream() + .map(path -> BinaryCondition.equalTo(getColumnSourcePath(), generatePlaceholder(path))) + .toArray(BinaryCondition[]::new))); subquery.addCondition(subQueryCondition); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchMissingTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchMissingTest.java index 742fb1ed48d..811ea570e2f 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchMissingTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchMissingTest.java @@ -1,9 +1,10 @@ package ca.uhn.fhir.jpa.dao.r4; -import static org.junit.jupiter.api.Assertions.assertEquals; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized; +import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.api.server.IBundleProvider; @@ -12,7 +13,6 @@ import ca.uhn.fhir.rest.param.QuantityParam; import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; -import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.DecimalType; @@ -26,513 +26,528 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.List; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; -public class FhirResourceDaoR4SearchMissingTest extends BaseJpaR4Test { - private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4SearchMissingTest.class); +public class FhirResourceDaoR4SearchMissingTest { - @BeforeEach - public void beforeResetMissing() { - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.ENABLED); - } - - @AfterEach - public void afterResetSearch() { - myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED); - } - - @Test - public void testIndexMissingFieldsDisabledDontAllowInSearch_NonReference() { - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); - - SearchParameterMap params = new SearchParameterMap(); - params.add(Patient.SP_ACTIVE, new StringParam().setMissing(true)); - try { - myPatientDao.search(params); - } catch (MethodNotAllowedException e) { - assertEquals(Msg.code(985) + ":missing modifier is disabled on this server", e.getMessage()); + @Nested + class IndexMissingDisabledTests extends MissingTests { + @BeforeEach + public void before() { + myStorageSettings.setIndexMissingFields(StorageSettings.IndexEnabledEnum.DISABLED); } - } - @Test - public void testIndexMissingFieldsDisabledDontAllowInSearch_Reference() { - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); - - SearchParameterMap params = new SearchParameterMap(); - params.add(Patient.SP_ORGANIZATION, new StringParam().setMissing(true)); - try { - myPatientDao.search(params); - } catch (MethodNotAllowedException e) { - assertEquals(Msg.code(985) + ":missing modifier is disabled on this server", e.getMessage()); - } - } - - @Test - public void testIndexMissingFieldsDisabledDontCreateIndexes() { - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); - Organization org = new Organization(); - org.setActive(true); - myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - - runInTransaction(() -> { - assertThat(mySearchParamPresentDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); - assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); - }); - - } - - @Test - public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantitySearchSupported() { - - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); - myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); - Organization org = new Organization(); - org.setActive(true); - myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - - runInTransaction(() -> { - assertThat(mySearchParamPresentDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); - assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); - }); - - } - - @Test - public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantityStorageSupported() { - - myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED); - myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED); - Organization org = new Organization(); - org.setActive(true); - myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - - runInTransaction(() -> { - assertThat(mySearchParamPresentDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); - assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); - assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); - }); - - } - - @SuppressWarnings("unused") - @Test - public void testSearchResourceReferenceMissingChain() { - IIdType oid1; - { + @Test + public void testIndexMissingFieldsDisabledDontCreateIndexes() { Organization org = new Organization(); org.setActive(true); - oid1 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - } - IIdType tid1; - { - Task task = new Task(); - task.setRequester(new Reference(oid1)); - tid1 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); - } - IIdType tid2; - { - Task task = new Task(); - task.setOwner(new Reference(oid1)); - tid2 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); + myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); + + runInTransaction(() -> { + assertThat(mySearchParamPresentDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); + assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); + }); + } - IIdType oid2; - { + @Test + public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantitySearchSupported() { + myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); Organization org = new Organization(); org.setActive(true); - org.setName("NAME"); - oid2 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - } - IIdType tid3; - { - Task task = new Task(); - task.setRequester(new Reference(oid2)); - tid3 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); + myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); + + runInTransaction(() -> { + assertThat(mySearchParamPresentDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); + assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); + }); + } - SearchParameterMap map; - List ids; + @Test + public void testIndexMissingFieldsDisabledDontCreateIndexesWithNormalizedQuantityStorageSupported() { + myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED); + Organization org = new Organization(); + org.setActive(true); + myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); - map = new SearchParameterMap(); - map.add(Organization.SP_NAME, new StringParam().setMissing(true)); - ids = toUnqualifiedVersionlessIds(myOrganizationDao.search(map)); - assertThat(ids).containsExactly(oid1); + runInTransaction(() -> { + assertThat(mySearchParamPresentDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamStringDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamDateDao.findAll()).isEmpty(); + assertThat(myResourceIndexedSearchParamTokenDao.findAll()).hasSize(1); + assertThat(myResourceIndexedSearchParamQuantityDao.findAll()).isEmpty(); + }); - ourLog.info("Starting Search 2"); - - map = new SearchParameterMap(); - map.add(Task.SP_REQUESTER, new ReferenceParam("Organization", "name:missing", "true")); - ids = toUnqualifiedVersionlessIds(myTaskDao.search(map)); - assertThat(ids).containsExactly(tid1); // NOT tid2 - - map = new SearchParameterMap(); - map.add(Task.SP_REQUESTER, new ReferenceParam("Organization", "name:missing", "false")); - ids = toUnqualifiedVersionlessIds(myTaskDao.search(map)); - assertThat(ids).containsExactly(tid3); - - map = new SearchParameterMap(); - map.add(Patient.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true")); - ids = toUnqualifiedVersionlessIds(myPatientDao.search(map)); - assertThat(ids).isEmpty(); - - } - - @Test - public void testSearchWithMissingDate() { - IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId(); - IIdType notMissing; - IIdType missing; - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("002"); - patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); - patient.setBirthDateElement(new DateType("2011-01-01")); - patient.getManagingOrganization().setReferenceElement(orgId); - notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - // Date Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - DateParam param = new DateParam(); - param.setMissing(false); - params.add(Patient.SP_BIRTHDATE, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).containsSubsequence(notMissing); - assertThat(patients).doesNotContainSubsequence(missing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - DateParam param = new DateParam(); - param.setMissing(true); - params.add(Patient.SP_BIRTHDATE, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); } } - @Test - public void testSearchWithMissingCoords() { - String locId = myLocationDao.create(new Location(), mySrd).getId().toUnqualifiedVersionless().getValue(); - String locId2 = myLocationDao.create(new Location().setPosition(new Location.LocationPositionComponent(new DecimalType(10), new DecimalType(10))), mySrd).getId().toUnqualifiedVersionless().getValue(); - - runInTransaction(() -> { - ourLog.info("Coords:\n * {}", myResourceIndexedSearchParamCoordsDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * "))); - }); - - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - TokenParam param = new TokenParam(); - param.setMissing(true); - params.add(Location.SP_NEAR, param); - myCaptureQueriesListener.clear(); - List patients = toUnqualifiedVersionlessIdValues(myLocationDao.search(params)); - myCaptureQueriesListener.logSelectQueriesForCurrentThread(0); - assertThat(patients).containsSubsequence(locId); - assertThat(patients).doesNotContainSubsequence(locId2); + @Nested + class IndexMissingEnabledTests extends MissingTests { + @BeforeEach + public void before() { + myStorageSettings.setIndexMissingFields(StorageSettings.IndexEnabledEnum.ENABLED); } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - TokenParam param = new TokenParam(); - param.setMissing(false); - params.add(Location.SP_NEAR, param); - List patients = toUnqualifiedVersionlessIdValues(myLocationDao.search(params)); - assertThat(patients).containsSubsequence(locId2); - assertThat(patients).doesNotContainSubsequence(locId); + + + @SuppressWarnings("unused") + @Test + public void testSearchResourceReferenceMissingChain() { + IIdType oid1; + { + Organization org = new Organization(); + org.setActive(true); + oid1 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); + } + IIdType tid1; + { + Task task = new Task(); + task.setRequester(new Reference(oid1)); + tid1 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); + } + { + Task task = new Task(); + task.setOwner(new Reference(oid1)); + myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); + } + + IIdType oid2; + { + Organization org = new Organization(); + org.setActive(true); + org.setName("NAME"); + oid2 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); + } + IIdType tid3; + { + Task task = new Task(); + task.setRequester(new Reference(oid2)); + tid3 = myTaskDao.create(task, mySrd).getId().toUnqualifiedVersionless(); + } + + SearchParameterMap map; + List ids; + + map = new SearchParameterMap(); + map.add(Organization.SP_NAME, new StringParam().setMissing(true)); + ids = toUnqualifiedVersionlessIds(myOrganizationDao.search(map, mySrd)); + assertThat(ids).containsExactly(oid1); + + ourLog.info("Starting Search 2"); + + map = new SearchParameterMap(); + map.add(Task.SP_REQUESTER, new ReferenceParam("Organization", "name:missing", "true")); + ids = toUnqualifiedVersionlessIds(myTaskDao.search(map, mySrd)); + assertThat(ids).containsExactly(tid1); // NOT tid2 + + map = new SearchParameterMap(); + map.add(Task.SP_REQUESTER, new ReferenceParam("Organization", "name:missing", "false")); + ids = toUnqualifiedVersionlessIds(myTaskDao.search(map, mySrd)); + assertThat(ids).containsExactly(tid3); + + map = new SearchParameterMap(); + map.add(Patient.SP_ORGANIZATION, new ReferenceParam("Organization", "name:missing", "true")); + ids = toUnqualifiedVersionlessIds(myPatientDao.search(map, mySrd)); + assertThat(ids).isEmpty(); + } } - @Test - public void testSearchWithMissingDate2() { - MedicationRequest mr1 = new MedicationRequest(); - mr1.addCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); - mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01"); - IIdType id1 = myMedicationRequestDao.create(mr1).getId().toUnqualifiedVersionless(); + static class MissingTests extends BaseJpaR4Test { + @AfterEach + public void after() { + myStorageSettings.setIndexMissingFields(new StorageSettings().getIndexMissingFields()); + myStorageSettings.setNormalizedQuantitySearchLevel(new StorageSettings().getNormalizedQuantitySearchLevel()); - MedicationRequest mr2 = new MedicationRequest(); - mr2.addCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); - IIdType id2 = myMedicationRequestDao.create(mr2).getId().toUnqualifiedVersionless(); - - SearchParameterMap map = new SearchParameterMap(); - map.add(MedicationRequest.SP_DATE, new DateParam().setMissing(true)); - IBundleProvider results = myMedicationRequestDao.search(map); - List ids = toUnqualifiedVersionlessIdValues(results); - - assertThat(ids).containsExactly(id2.getValue()); - - } - - @Test - public void testSearchWithMissingQuantity() { - IIdType notMissing; - IIdType missing; - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); } - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("002"); - obs.setValue(new Quantity(123)); - notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + + @Test + public void testSearchWithMissingDate() { + IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId(); + IIdType notMissing; + IIdType missing; + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("002"); + patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); + patient.setBirthDateElement(new DateType("2011-01-01")); + patient.getManagingOrganization().setReferenceElement(orgId); + notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + // Date Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + DateParam param = new DateParam(); + param.setMissing(false); + params.add(Patient.SP_BIRTHDATE, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(notMissing); + assertThat(patients).doesNotContainSubsequence(missing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + DateParam param = new DateParam(); + param.setMissing(true); + params.add(Patient.SP_BIRTHDATE, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } } - // Quantity Param - { + + @Test + public void testSearchWithMissingCoords() { + String locId = myLocationDao.create(new Location(), mySrd).getId().toUnqualifiedVersionless().getValue(); + String locId2 = myLocationDao.create(new Location().setPosition(new Location.LocationPositionComponent(new DecimalType(10), new DecimalType(10))), mySrd).getId().toUnqualifiedVersionless().getValue(); + + runInTransaction(() -> ourLog.info("Coords:\n * {}", + myResourceIndexedSearchParamCoordsDao.findAll().stream() + .map(ResourceIndexedSearchParamCoords::toString).collect(Collectors.joining("\n * ")) + ) + ); + + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + TokenParam param = new TokenParam(); + param.setMissing(true); + params.add(Location.SP_NEAR, param); + myCaptureQueriesListener.clear(); + List patients = toUnqualifiedVersionlessIdValues(myLocationDao.search(params, mySrd)); + myCaptureQueriesListener.logSelectQueriesForCurrentThread(0); + assertThat(patients).containsSubsequence(locId); + assertThat(patients).doesNotContainSubsequence(locId2); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + TokenParam param = new TokenParam(); + param.setMissing(false); + params.add(Location.SP_NEAR, param); + List patients = toUnqualifiedVersionlessIdValues(myLocationDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(locId2); + assertThat(patients).doesNotContainSubsequence(locId); + } + } + + @Test + public void testSearchWithMissingDate2() { + MedicationRequest mr1 = new MedicationRequest(); + mr1.addCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); + mr1.addDosageInstruction().getTiming().addEventElement().setValueAsString("2017-01-01"); + myMedicationRequestDao.create(mr1, mySrd).getId().toUnqualifiedVersionless(); + + MedicationRequest mr2 = new MedicationRequest(); + mr2.addCategory().addCoding().setSystem("urn:medicationroute").setCode("oral"); + IIdType id2 = myMedicationRequestDao.create(mr2, mySrd).getId().toUnqualifiedVersionless(); + + SearchParameterMap map = new SearchParameterMap(); + map.add(MedicationRequest.SP_DATE, new DateParam().setMissing(true)); + IBundleProvider results = myMedicationRequestDao.search(map, mySrd); + List ids = toUnqualifiedVersionlessIdValues(results); + + assertThat(ids).containsExactly(id2.getValue()); + + } + + @Test + public void testSearchWithMissingQuantity() { + IIdType notMissing; + IIdType missing; + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("002"); + obs.setValue(new Quantity(123)); + notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + // Quantity Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(false); + params.add(Observation.SP_VALUE_QUANTITY, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(true); + params.add(Observation.SP_VALUE_QUANTITY, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } + } + + @Test + public void testSearchWithMissingQuantityWithNormalizedQuantitySearchSupported() { + + myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); + IIdType notMissing; + IIdType missing; + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("002"); + obs.setValue(new Quantity(123)); + notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + + runInTransaction(() -> { + ourLog.info("Quantity Indexes:\n * {}", + myResourceIndexedSearchParamQuantityDao.findAll().stream() + .filter(t -> t.getParamName().equals("value-quantity")).map(ResourceIndexedSearchParamQuantity::toString).collect(Collectors.joining("\n * ") + ) + ); + ourLog.info("Normalized Quantity Indexes:\n * {}", + myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream(). + filter(t -> t.getParamName().equals("value-quantity")).map(ResourceIndexedSearchParamQuantityNormalized::toString).collect(Collectors.joining("\n * ") + ) + ); + }); + + // Quantity Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(false); + params.add(Observation.SP_VALUE_QUANTITY, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(true); + params.add(Observation.SP_VALUE_QUANTITY, param); + myCaptureQueriesListener.clear(); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + myCaptureQueriesListener.logSelectQueries(); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } + + } + + @Test + public void testSearchWithMissingQuantityWithNormalizedQuantityStorageSupported() { + + myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED); + IIdType notMissing; + IIdType missing; + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("002"); + obs.setValue(new Quantity(123)); + notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + // Quantity Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(false); + params.add(Observation.SP_VALUE_QUANTITY, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + QuantityParam param = new QuantityParam(); + param.setMissing(true); + params.add(Observation.SP_VALUE_QUANTITY, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } + + } + + + @Test + public void testSearchWithMissingReference() { + IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless(); + IIdType notMissing; + IIdType missing; + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("002"); + patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); + patient.setBirthDateElement(new DateType("2011-01-01")); + patient.getManagingOrganization().setReferenceElement(orgId); + notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + // Reference Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + ReferenceParam param = new ReferenceParam(); + param.setMissing(false); + params.add(Patient.SP_ORGANIZATION, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + ReferenceParam param = new ReferenceParam(); + param.setMissing(true); + params.add(Patient.SP_ORGANIZATION, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + assertThat(patients).doesNotContainSubsequence(orgId); + } + } + + + @Test + public void testSearchWithMissingReference_resourceTypeWithMultipleReferences() { + IIdType patientId = createPatient(); + IIdType observationId = createObservation(withSubject(patientId)); + SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(false); - params.add(Observation.SP_VALUE_QUANTITY, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); + params.add(Observation.SP_PERFORMER, new ReferenceParam().setMissing(true)); + IBundleProvider bundleProvider = myObservationDao.search(params, mySrd); + assertThat(bundleProvider.getAllResourceIds()).containsExactly(observationId.getIdPart()); } - { + + @Test + public void testSearchWithMissingReference_searchParamMultiplePaths() { + IIdType encounterId = createEncounter(); + createObservation(withEncounter(encounterId.getValue())); + SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(true); - params.add(Observation.SP_VALUE_QUANTITY, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); - } - } - - @Test - public void testSearchWithMissingQuantityWithNormalizedQuantitySearchSupported() { - - myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED); - IIdType notMissing; - IIdType missing; - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - } - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("002"); - obs.setValue(new Quantity(123)); - notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + params.add(Observation.SP_ENCOUNTER, new ReferenceParam().setMissing(true)); + IBundleProvider bundleProvider = myObservationDao.search(params, mySrd); + assertThat(bundleProvider.getAllResourceIds()).isEmpty(); } - runInTransaction(() -> { - ourLog.info("Quantity Indexes:\n * {}", myResourceIndexedSearchParamQuantityDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).map(t -> t.toString()).collect(Collectors.joining("\n * "))); - ourLog.info("Normalized Quantity Indexes:\n * {}", myResourceIndexedSearchParamQuantityNormalizedDao.findAll().stream().filter(t -> t.getParamName().equals("value-quantity")).map(t -> t.toString()).collect(Collectors.joining("\n * "))); - }); - - // Quantity Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(false); - params.add(Observation.SP_VALUE_QUANTITY, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(true); - params.add(Observation.SP_VALUE_QUANTITY, param); - myCaptureQueriesListener.clear(); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - myCaptureQueriesListener.logSelectQueries(); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); + @Test + public void testSearchWithMissingString() { + IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId(); + IIdType notMissing; + IIdType missing; + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("urn:system").setValue("002"); + patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); + patient.setBirthDateElement(new DateType("2011-01-01")); + patient.getManagingOrganization().setReferenceElement(orgId); + notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); + } + // String Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + StringParam param = new StringParam(); + param.setMissing(false); + params.add(Patient.SP_FAMILY, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + StringParam param = new StringParam(); + param.setMissing(true); + params.add(Patient.SP_FAMILY, param); + List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } } - } - - @Test - public void testSearchWithMissingQuantityWithNormalizedQuantityStorageSupported() { - - myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED); - IIdType notMissing; - IIdType missing; - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - } - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("002"); - obs.setValue(new Quantity(123)); - notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - } - // Quantity Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(false); - params.add(Observation.SP_VALUE_QUANTITY, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - QuantityParam param = new QuantityParam(); - param.setMissing(true); - params.add(Observation.SP_VALUE_QUANTITY, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); - } - - } - - - @Test - public void testSearchWithMissingReference() { - IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId().toUnqualifiedVersionless(); - IIdType notMissing; - IIdType missing; - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("002"); - patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); - patient.setBirthDateElement(new DateType("2011-01-01")); - patient.getManagingOrganization().setReferenceElement(orgId); - notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - // Reference Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - ReferenceParam param = new ReferenceParam(); - param.setMissing(false); - params.add(Patient.SP_ORGANIZATION, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - ReferenceParam param = new ReferenceParam(); - param.setMissing(true); - params.add(Patient.SP_ORGANIZATION, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); - assertThat(patients).doesNotContainSubsequence(orgId); - } - } - - @Test - public void testSearchWithMissingString() { - IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId(); - IIdType notMissing; - IIdType missing; - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - { - Patient patient = new Patient(); - patient.addIdentifier().setSystem("urn:system").setValue("002"); - patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John"); - patient.setBirthDateElement(new DateType("2011-01-01")); - patient.getManagingOrganization().setReferenceElement(orgId); - notMissing = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - } - // String Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - StringParam param = new StringParam(); - param.setMissing(false); - params.add(Patient.SP_FAMILY, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - StringParam param = new StringParam(); - param.setMissing(true); - params.add(Patient.SP_FAMILY, param); - List patients = toUnqualifiedVersionlessIds(myPatientDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); - } - } - - @Test - public void testSearchWithToken() { - IIdType notMissing; - IIdType missing; - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("001"); - missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - } - { - Observation obs = new Observation(); - obs.addIdentifier().setSystem("urn:system").setValue("002"); - obs.getCode().addCoding().setSystem("urn:system").setCode("002"); - notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - } - // Token Param - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - TokenParam param = new TokenParam(); - param.setMissing(false); - params.add(Observation.SP_CODE, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).doesNotContainSubsequence(missing); - assertThat(patients).containsSubsequence(notMissing); - } - { - SearchParameterMap params = new SearchParameterMap(); - params.setLoadSynchronous(true); - TokenParam param = new TokenParam(); - param.setMissing(true); - params.add(Observation.SP_CODE, param); - List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params)); - assertThat(patients).containsSubsequence(missing); - assertThat(patients).doesNotContainSubsequence(notMissing); + @Test + public void testSearchWithToken() { + IIdType notMissing; + IIdType missing; + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("001"); + missing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + { + Observation obs = new Observation(); + obs.addIdentifier().setSystem("urn:system").setValue("002"); + obs.getCode().addCoding().setSystem("urn:system").setCode("002"); + notMissing = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); + } + // Token Param + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + TokenParam param = new TokenParam(); + param.setMissing(false); + params.add(Observation.SP_CODE, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).doesNotContainSubsequence(missing); + assertThat(patients).containsSubsequence(notMissing); + } + { + SearchParameterMap params = new SearchParameterMap(); + params.setLoadSynchronous(true); + TokenParam param = new TokenParam(); + param.setMissing(true); + params.add(Observation.SP_CODE, param); + List patients = toUnqualifiedVersionlessIds(myObservationDao.search(params, mySrd)); + assertThat(patients).containsSubsequence(missing); + assertThat(patients).doesNotContainSubsequence(notMissing); + } } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java index cb098dc7012..427970449c6 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java @@ -217,7 +217,7 @@ import static org.mockito.Mockito.when; public class ResourceProviderR4Test extends BaseResourceProviderR4Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4Test.class); private SearchCoordinatorSvcImpl mySearchCoordinatorSvcRaw; - private CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor(); + private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor(); @Autowired private ISearchDao mySearchEntityDao; @@ -413,15 +413,15 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient pt1 = new Patient(); pt1.addName().setFamily("Elizabeth"); - String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue(); + String pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless().getValue(); Patient pt2 = new Patient(); pt2.addName().setFamily("fghijk"); - String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue(); + String pt2id = myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless().getValue(); Patient pt3 = new Patient(); pt3.addName().setFamily("zzzzz"); - myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue(); + myPatientDao.create(pt3, mySrd).getId().toUnqualifiedVersionless().getValue(); Bundle output = myClient @@ -450,7 +450,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient pt1 = new Patient(); pt1.addName().setFamily("Smith%"); - String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue(); + String pt1id = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless().getValue(); Bundle output = myClient .search() @@ -463,7 +463,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient pt2 = new Patient(); pt2.addName().setFamily("Sm%ith"); - String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue(); + String pt2id = myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless().getValue(); output = myClient .search() @@ -740,7 +740,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient p = new Patient(); p.addName().setFamily("FAM").addGiven("GIV"); - IIdType id = myPatientDao.create(p).getId(); + IIdType id = myPatientDao.create(p, mySrd).getId(); myClient.read().resource("Patient").withId(id.toUnqualifiedVersionless()).execute(); @@ -763,7 +763,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient p = new Patient(); p.addName().setFamily("FAM").addGiven("GIV"); - IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless(); + IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); myClient .delete() @@ -1025,57 +1025,58 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { public void testCreateAndReadBackResourceWithContainedReferenceToContainer() { myFhirContext.setParserErrorHandler(new StrictErrorHandler()); - String input = "{\n" + - " \"resourceType\": \"Organization\",\n" + - " \"id\": \"1\",\n" + - " \"meta\": {\n" + - " \"tag\": [\n" + - " {\n" + - " \"system\": \"https://blah.org/deployment\",\n" + - " \"code\": \"e69414dd-b5c2-462d-bcfd-9d04d6b16596\",\n" + - " \"display\": \"DEPLOYMENT\"\n" + - " },\n" + - " {\n" + - " \"system\": \"https://blah.org/region\",\n" + - " \"code\": \"b47d7a5b-b159-4bed-a8f8-3258e6603adb\",\n" + - " \"display\": \"REGION\"\n" + - " },\n" + - " {\n" + - " \"system\": \"https://blah.org/provider\",\n" + - " \"code\": \"28c30004-0333-40cf-9e7f-3f9e080930bd\",\n" + - " \"display\": \"PROVIDER\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"contained\": [\n" + - " {\n" + - " \"resourceType\": \"Location\",\n" + - " \"id\": \"2\",\n" + - " \"position\": {\n" + - " \"longitude\": 51.443238301454289,\n" + - " \"latitude\": 7.34196905697293\n" + - " },\n" + - " \"managingOrganization\": {\n" + - " \"reference\": \"#\"\n" + - " }\n" + - " }\n" + - " ],\n" + - " \"type\": [\n" + - " {\n" + - " \"coding\": [\n" + - " {\n" + - " \"system\": \"https://blah.org/fmc/OrganizationType\",\n" + - " \"code\": \"CLINIC\",\n" + - " \"display\": \"Clinic\"\n" + - " }\n" + - " ]\n" + - " }\n" + - " ],\n" + - " \"name\": \"testOrg\"\n" + - "}"; + String input = """ +{ + "resourceType": "Organization", + "id": "1", + "meta": { + "tag": [ + { + "system": "https://blah.org/deployment", + "code": "e69414dd-b5c2-462d-bcfd-9d04d6b16596", + "display": "DEPLOYMENT" + }, + { + "system": "https://blah.org/region", + "code": "b47d7a5b-b159-4bed-a8f8-3258e6603adb", + "display": "REGION" + }, + { + "system": "https://blah.org/provider", + "code": "28c30004-0333-40cf-9e7f-3f9e080930bd", + "display": "PROVIDER" + } + ] + }, + "contained": [ + { + "resourceType": "Location", + "id": "2", + "position": { + "longitude": 51.443238301454289, + "latitude": 7.34196905697293 + }, + "managingOrganization": { + "reference": "#" + } + } + ], + "type": [ + { + "coding": [ + { + "system": "https://blah.org/fmc/OrganizationType", + "code": "CLINIC", + "display": "Clinic" + } + ] + } + ], + "name": "testOrg" +}"""; Organization org = myFhirContext.newJsonParser().parseResource(Organization.class, input); - IIdType id = myOrganizationDao.create(org).getId(); + IIdType id = myOrganizationDao.create(org, mySrd).getId(); org = myOrganizationDao.read(id); String output = myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(org); @@ -1095,9 +1096,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } List outcome = myClient.transaction().withResources(resources).prettyPrint().encodedXml().execute(); - runInTransaction(() -> { - assertEquals(100, myResourceTableDao.count()); - }); + runInTransaction(() -> assertEquals(100, myResourceTableDao.count())); Bundle found = myClient .search() @@ -1306,7 +1305,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } @Test - public void testCreateQuestionnaireResponseWithValidation() throws IOException { + public void testCreateQuestionnaireResponseWithValidation() { CodeSystem cs = new CodeSystem(); cs.setUrl("http://cs"); cs.setStatus(Enumerations.PublicationStatus.ACTIVE); @@ -1906,8 +1905,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { * Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL but we want to make sure that works too.. */ Socket sock = new Socket(); - sock.setSoTimeout(3000); - try { + try (sock) { + sock.setSoTimeout(3000); sock.connect(new InetSocketAddress("localhost", myPort)); sock.getOutputStream().write(("DELETE /fhir/context/Patient?identifier=http://ghh.org/patient|" + methodName + " HTTP/1.1\n").getBytes(StandardCharsets.UTF_8)); sock.getOutputStream().write("Host: localhost\n".getBytes(StandardCharsets.UTF_8)); @@ -1915,7 +1914,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { BufferedReader socketInput = new BufferedReader(new InputStreamReader(sock.getInputStream())); - // String response = ""; StringBuilder b = new StringBuilder(); char[] buf = new char[1000]; while (socketInput.read(buf) != -1) { @@ -1925,9 +1923,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { ourLog.debug("Resp: {}", resp); } catch (SocketTimeoutException e) { - e.printStackTrace(); - } finally { - sock.close(); + ourLog.debug(e.getMessage(), e); } Thread.sleep(1000); @@ -2398,7 +2394,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { assertThat(idValues).as(idValues.toString()).hasSize(10); idValues = searchAndReturnUnqualifiedIdValues(myServerBase + "/_history?_at=gt" + InstantDt.withCurrentTime().getYear()); - assertThat(idValues).hasSize(0); + assertThat(idValues).isEmpty(); } @@ -2427,7 +2423,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myMemoryCacheService.invalidateCaches(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID); } - Bundle history = myClient.history().onInstance(id.getValue()).andReturnBundle(Bundle.class).execute(); + Bundle history = myClient.history().onInstance(id.getValue()).returnBundle(Bundle.class).execute(); assertEquals(1, history.getEntry().size()); BundleEntryComponent historyEntry0 = history.getEntry().get(0); // validate entry.fullUrl @@ -2476,7 +2472,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myMemoryCacheService.invalidateCaches(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID); } - Bundle history = myClient.history().onInstance(id.getValue()).andReturnBundle(Bundle.class).execute(); + Bundle history = myClient.history().onInstance(id.getValue()).returnBundle(Bundle.class).execute(); assertEquals(1, history.getEntry().size()); BundleEntryComponent historyEntry0 = history.getEntry().get(0); // validate entry.fullUrl @@ -2508,7 +2504,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { ourLog.info("Res ID: {}", id); - Bundle history = myClient.history().onInstance(id.getValue()).andReturnBundle(Bundle.class).prettyPrint().summaryMode(SummaryEnum.DATA).execute(); + Bundle history = myClient.history().onInstance(id.getValue()).returnBundle(Bundle.class).prettyPrint().summaryMode(SummaryEnum.DATA).execute(); assertThat(history.getEntry()).hasSize(3); assertEquals(id.withVersion("3").getValue(), history.getEntry().get(0).getResource().getId()); assertThat(((Patient) history.getEntry().get(0).getResource()).getName()).hasSize(1); @@ -2746,7 +2742,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { int total = 20; Organization org = new Organization(); org.setName("ORG"); - IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless(); + IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); Coding tagCode = new Coding(); tagCode.setCode("test"); @@ -2757,7 +2753,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { .addTag(tagCode); t.setStatus(Task.TaskStatus.REQUESTED); t.getOwner().setReference(orgId.getValue()); - myTaskDao.create(t); + myTaskDao.create(t, mySrd); } HashSet ids = new HashSet<>(); @@ -2835,12 +2831,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { if (orgCount > 0) { Organization org = new Organization(); org.setName("ORG"); - IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless(); + IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); orgCount--; t.getOwner().setReference(orgId.getValue()); } - myTaskDao.create(t); + myTaskDao.create(t, mySrd); } } @@ -2909,12 +2905,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { if (orgCount > 0) { Organization org = new Organization(); org.setName("ORG"); - IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless(); + IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); orgCount--; t.getOwner().setReference(orgId.getValue()); } - myTaskDao.create(t); + myTaskDao.create(t, mySrd); } } @@ -2961,13 +2957,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { public void testIncludeCountDoesntIncludeIncludes() { Organization org = new Organization(); org.setName("ORG"); - IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless(); + IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless(); for (int i = 0; i < 10; i++) { Patient pt = new Patient(); pt.getManagingOrganization().setReference(orgId.getValue()); pt.addName().setFamily("FAM" + i); - myPatientDao.create(pt); + myPatientDao.create(pt, mySrd); } Bundle bundle = myClient @@ -3168,7 +3164,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient newPt = myClient.read().resource(Patient.class).withId(pid1.getIdPart()).execute(); assertEquals("2", newPt.getIdElement().getVersionIdPart()); - assertEquals(false, newPt.getActive()); + assertFalse(newPt.getActive()); } @Test @@ -3196,7 +3192,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient newPt = myClient.read().resource(Patient.class).withId(pid1.getIdPart()).execute(); assertEquals("1", newPt.getIdElement().getVersionIdPart()); - assertEquals(true, newPt.getActive()); + assertTrue(newPt.getActive()); } @Test @@ -3226,7 +3222,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient newPt = myClient.read().resource(Patient.class).withId(pid1.getIdPart()).execute(); assertEquals("2", newPt.getIdElement().getVersionIdPart()); - assertEquals(false, newPt.getActive()); + assertFalse(newPt.getActive()); } @Test @@ -3255,7 +3251,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Patient newPt = myClient.read().resource(Patient.class).withId(pid1.getIdPart()).execute(); assertEquals("2", newPt.getIdElement().getVersionIdPart()); - assertEquals(false, newPt.getActive()); + assertFalse(newPt.getActive()); } @Test @@ -3323,12 +3319,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { { Bundle returned = myClient.search().forResource(Patient.class).encodedXml().returnBundle(Bundle.class).execute(); - assertThat(returned.getEntry().size()).isGreaterThan(1); + assertThat(returned.getEntry()).hasSizeGreaterThan(1); assertEquals(BundleType.SEARCHSET, returned.getType()); } { Bundle returned = myClient.search().forResource(Patient.class).encodedJson().returnBundle(Bundle.class).execute(); - assertThat(returned.getEntry().size()).isGreaterThan(1); + assertThat(returned.getEntry()).hasSizeGreaterThan(1); } } @@ -3350,7 +3346,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } }); - Bundle bundle = myClient.history().onServer().andReturnBundle(Bundle.class).execute(); + Bundle bundle = myClient.history().onServer().returnBundle(Bundle.class).execute(); assertEquals(1, bundle.getTotal()); assertThat(bundle.getEntry()).hasSize(1); assertEquals(id2.getIdPart(), bundle.getEntry().get(0).getResource().getIdElement().getIdPart()); @@ -3507,15 +3503,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { assertThat(text).doesNotContain("\"B\""); assertThat(text).doesNotContain("\"B1\""); } - - -// HttpGet read = new HttpGet(ourServerBase + "/Observation?patient=P5000000302&_sort:desc=code&code:in=http://fkcfhir.org/fhir/vs/ccdacapddialysisorder"); -// try (CloseableHttpResponse response = ourHttpClient.execute(read)) { -// String text = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); -// ourLog.info(text); -// assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatusLine().getStatusCode()); -// assertThat(text).doesNotContain("\"text\",\"type\""); -// } } @Test @@ -3873,9 +3860,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { p.addName().setFamily(methodName + "1"); IIdType pid1 = myClient.create().resource(p).execute().getId().toUnqualifiedVersionless(); - Thread.sleep(10); long time1 = System.currentTimeMillis(); - Thread.sleep(10); Patient p2 = new Patient(); p2.addName().setFamily(methodName + "2"); @@ -4064,9 +4049,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { public void testSearchLastUpdatedParamRp() throws InterruptedException { String methodName = "testSearchLastUpdatedParamRp"; - int sleep = 100; - Thread.sleep(sleep); - DateTimeType beforeAny = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI); IIdType id1a; { @@ -4083,9 +4065,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { id1b = myClient.create().resource(patient).execute().getId().toUnqualifiedVersionless(); } - Thread.sleep(1100); DateTimeType beforeR2 = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI); - Thread.sleep(1100); IIdType id2; { @@ -4249,13 +4229,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Bundle bundle = myFhirContext.newXmlParser().parseResource(Bundle.class, resp); matches = bundle.getEntry().size(); - assertThat(matches).isGreaterThan(0); + assertThat(matches).isPositive(); } @Test public void testSearchReturnsSearchDate() throws Exception { Date before = new Date(); - Thread.sleep(1); //@formatter:off Bundle found = myClient @@ -4266,7 +4245,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { .execute(); //@formatter:on - Thread.sleep(1); Date after = new Date(); InstantType updated = found.getMeta().getLastUpdatedElement(); @@ -4300,7 +4278,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4313,7 +4291,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4326,7 +4304,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4339,24 +4317,24 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } // > 1m String uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt1|http://unitsofmeasure.org|m"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); List ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(3); //>= 100cm uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt100|http://unitsofmeasure.org|cm"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(3); //>= 10dm uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt10|http://unitsofmeasure.org|dm"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(3); } @@ -4381,7 +4359,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4392,7 +4370,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4403,7 +4381,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4414,7 +4392,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } String uri; @@ -4451,7 +4429,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4462,7 +4440,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -4474,7 +4452,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } myCaptureQueriesListener.clear(); @@ -4490,8 +4468,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { //-- check use normalized quantity table to search String searchSql = myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, true); - assertThat(searchSql).doesNotContain("HFJ_SPIDX_QUANTITY t0"); - assertThat(searchSql).contains("HFJ_SPIDX_QUANTITY_NRML"); + assertThat(searchSql).doesNotContain("HFJ_SPIDX_QUANTITY t0").contains("HFJ_SPIDX_QUANTITY_NRML"); } @Test @@ -5044,7 +5021,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5056,7 +5033,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5068,7 +5045,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid3 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5080,7 +5057,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid4 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } String uri = myServerBase + "/Observation?_sort=code-value-quantity"; @@ -5092,7 +5069,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { found = myFhirContext.newXmlParser().parseResource(Bundle.class, output); } - ourLog.debug("Bundle: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(found)); + ourLog.debug("Bundle: {}\n", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(found)); List list = toUnqualifiedVersionlessIds(found); assertThat(found.getEntry()).hasSize(4); @@ -5129,7 +5106,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5145,7 +5122,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5161,7 +5138,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { oid3 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -5176,7 +5153,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { comp.setValue(new Quantity().setValue(250)); oid4 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } String uri = myServerBase + "/Observation?_sort=combo-code-value-quantity"; @@ -5188,7 +5165,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { found = myFhirContext.newXmlParser().parseResource(Bundle.class, output); } - ourLog.debug("Bundle: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(found)); + ourLog.debug("Bundle: {}\n", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(found)); List list = toUnqualifiedVersionlessIds(found); assertThat(found.getEntry()).hasSize(4); @@ -5264,9 +5241,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { List list = toUnqualifiedVersionlessIds(found); ourLog.info(methodName + " found: " + list.toString() + " - Wanted " + orgMissing + " but not " + orgNotMissing); - assertThat(list).doesNotContain(orgNotMissing); - assertThat(list).doesNotContain(deletedIdMissingTrue); - assertThat(list).contains(orgMissing); + assertThat(list).doesNotContain(orgNotMissing).doesNotContain(deletedIdMissingTrue).contains(orgMissing); } @Test @@ -5927,7 +5902,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { } Date before = new Date(); - Thread.sleep(100); pt = new Patient(); pt.setId(id.getIdPart()); @@ -6450,7 +6424,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { cc.addCoding().setCode("2345-7").setSystem("http://loinc.org"); obs.setValue(new Quantity().setValueElement(new DecimalType(125.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); IIdType opid1 = myObservationDao.create(obs, mySrd).getId(); @@ -6463,7 +6437,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { cc.addCoding().setCode("2345-7").setSystem("http://loinc.org"); obs.setValue(new Quantity().setValueElement(new DecimalType(24.12)).setUnit("CM").setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm")); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); myObservationDao.update(obs, mySrd); } @@ -6479,7 +6453,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -6492,7 +6466,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } { @@ -6505,25 +6479,25 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { myObservationDao.create(obs, mySrd); - ourLog.debug("Observation: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); + ourLog.debug("Observation: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs)); } // > 1m String uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt1|http://unitsofmeasure.org|m"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); List ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(2); //>= 100cm uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt100|http://unitsofmeasure.org|cm"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(2); //>= 10dm uri = myServerBase + "/Observation?code-value-quantity=http://" + UrlUtil.escapeUrlParam("loinc.org|2345-7$gt10|http://unitsofmeasure.org|dm"); - ourLog.info("uri = " + uri); + ourLog.info("uri = {}", uri); ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); assertThat(ids).hasSize(2); } @@ -6540,7 +6514,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { patient.setBirthDateElement(new DateType("2073")); pid0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - ourLog.debug("Patient: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient)); + ourLog.debug("Patient: {}\n", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient)); ourLog.info("pid0 " + pid0); } @@ -6553,7 +6527,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); ourLog.info(resp); Bundle bundle = myFhirContext.newXmlParser().parseResource(Bundle.class, resp); - ourLog.debug("Patient: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + ourLog.debug("Patient: {}\n", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); } uri = myServerBase + "/Patient?_total=accurate&birthdate=gt2072-01-01"; @@ -6564,7 +6538,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); ourLog.info(resp); Bundle bundle = myFhirContext.newXmlParser().parseResource(Bundle.class, resp); - ourLog.debug("Patient: \n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); + ourLog.debug("Patient: {}\n", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); } } @@ -6995,9 +6969,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { && theInput.IsEnforceRefOnType && theInput.IsEnforceRefOnWrite).isFalse(); } catch (InvalidRequestException ex) { - assertThat(ex.getMessage().contains( - "Invalid resource reference" - )).as(ex.getMessage()).isTrue(); + assertThat(ex.getMessage()).as(ex.getMessage()).contains("Invalid resource reference"); } finally { myStorageSettings.setEnforceReferentialIntegrityOnWrite(isEnforceRefOnWrite); myStorageSettings.setEnforceReferenceTargetTypes(isEnforceRefTargetTypes); @@ -7331,9 +7303,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { patient.setBirthDate(cal.getTime()); } return patient; - }, (isMissing) -> { - return doSearch(Patient.class, Patient.BIRTHDATE.isMissing(isMissing)); - }); + }, (isMissing) -> doSearch(Patient.class, Patient.BIRTHDATE.isMissing(isMissing))); } @ParameterizedTest @@ -7346,9 +7316,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { patient.setGender(AdministrativeGender.FEMALE); } return patient; - }, isMissing -> { - return doSearch(Patient.class, Patient.GENDER.isMissing(isMissing)); - }); + }, isMissing -> doSearch(Patient.class, Patient.GENDER.isMissing(isMissing))); } @ParameterizedTest @@ -7364,9 +7332,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { patient.setGeneralPractitioner(Collections.singletonList(new Reference(practitionerId))); } return patient; - }, isMissing -> { - return doSearch(Patient.class, Patient.GENERAL_PRACTITIONER.isMissing(isMissing)); - }); + }, isMissing -> doSearch(Patient.class, Patient.GENERAL_PRACTITIONER.isMissing(isMissing))); } @ParameterizedTest @@ -7409,9 +7375,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { sp.setUrl("http://example.com"); } return sp; - }, isMissing -> { - return doSearch(SearchParameter.class, SearchParameter.URL.isMissing(isMissing)); - }); + }, isMissing -> doSearch(SearchParameter.class, SearchParameter.URL.isMissing(isMissing))); } @ParameterizedTest @@ -7424,9 +7388,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { obs.setValue(new Quantity(3)); } return obs; - }, isMissing -> { - return doSearch(Observation.class, Observation.VALUE_QUANTITY.isMissing(isMissing)); - }); + }, isMissing -> doSearch(Observation.class, Observation.VALUE_QUANTITY.isMissing(isMissing))); } @ParameterizedTest @@ -7457,7 +7419,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { Y doTask(X theInput); } - private static class MissingSearchTestParameters { + public static class MissingSearchTestParameters { /** * The setting for IndexMissingFields */ From 377e44b6cacae415639c7890dd901d2d63db093a Mon Sep 17 00:00:00 2001 From: Tadgh Date: Wed, 25 Sep 2024 20:38:22 +0000 Subject: [PATCH 13/13] attribution and pom change (#6309) --- .../fhir/changelog/7_6_0/6290-mssql-migration-trim-fix.yaml | 5 +++++ pom.xml | 1 + 2 files changed, 6 insertions(+) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6290-mssql-migration-trim-fix.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6290-mssql-migration-trim-fix.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6290-mssql-migration-trim-fix.yaml new file mode 100644 index 00000000000..435207a3454 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_6_0/6290-mssql-migration-trim-fix.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 6290 +title: "Previously, a specific migration task was using the `TRIM()` function, which does not exist in MSSQL 2012. This was causing migrations targeting MSSQL 2012 to fail. +This has been corrected and replaced with usage of a combination of LTRIM() and RTRIM(). Thanks to Primož Delopst at Better for the contribution!" diff --git a/pom.xml b/pom.xml index e6f098ceece..481c3a77047 100644 --- a/pom.xml +++ b/pom.xml @@ -869,6 +869,7 @@ delopst Primož Delopst + Better Zach Smith