From c29bb462c5dfd15faf216bd94851e8621bb76fb4 Mon Sep 17 00:00:00 2001 From: Jaison Baskaran Date: Wed, 13 Apr 2022 15:38:43 -0600 Subject: [PATCH] Add support for additional params with lastN operation on Observation (#3533) --- ...seJpaResourceProviderObservationDstu3.java | 12 ++++- .../BaseJpaResourceProviderObservationR4.java | 10 +++- .../BaseJpaResourceProviderObservationR5.java | 12 ++++- .../r4/ResourceProviderR4ElasticTest.java | 51 ++++++++++++++++++- 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java index 3f30d50e178..0e96abfd198 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderObservationDstu3.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.RawParam; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.DateAndListParam; @@ -16,6 +17,9 @@ import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.UnsignedIntType; import org.hl7.fhir.instance.model.api.IPrimitiveType; +import java.util.List; +import java.util.Map; + /* * #%L * HAPI FHIR JPA Server @@ -75,9 +79,11 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider @Description(shortDefinition="The maximum number of observations to return for each observation code") @OperationParam(name = "max", typeName = "integer", min = 0, max = 1) - IPrimitiveType theMax + IPrimitiveType theMax, - ) { + @RawParam + Map> theAdditionalRawParams + ) { startRequest(theServletRequest); try { SearchParameterMap paramMap = new SearchParameterMap(); @@ -97,6 +103,8 @@ public class BaseJpaResourceProviderObservationDstu3 extends JpaResourceProvider paramMap.setCount(theCount.getValue()); } + getDao().translateRawParameters(theAdditionalRawParams, paramMap); + return ((IFhirResourceDaoObservation) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse); } finally { endRequest(theServletRequest); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java index d9264d60f8a..c2e7ef541d8 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderObservationR4.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.RawParam; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.DateAndListParam; @@ -16,6 +17,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.UnsignedIntType; +import java.util.List; +import java.util.Map; + /* * #%L * HAPI FHIR JPA Server @@ -75,8 +79,10 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4< @Description(shortDefinition="The maximum number of observations to return for each observation code") @OperationParam(name = "max", typeName = "integer", min = 0, max = 1) - IPrimitiveType theMax + IPrimitiveType theMax, + @RawParam + Map> theAdditionalRawParams ) { startRequest(theServletRequest); try { @@ -97,6 +103,8 @@ public class BaseJpaResourceProviderObservationR4 extends JpaResourceProviderR4< paramMap.setCount(theCount.getValue()); } + getDao().translateRawParameters(theAdditionalRawParams, paramMap); + return ((IFhirResourceDaoObservation) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse); } finally { endRequest(theServletRequest); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java index 0368e52f672..3b9349c3835 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderObservationR5.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.RawParam; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.param.DateAndListParam; @@ -16,6 +17,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.r5.model.Observation; import org.hl7.fhir.r5.model.UnsignedIntType; +import java.util.List; +import java.util.Map; + /* * #%L * HAPI FHIR JPA Server @@ -75,9 +79,11 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5< @Description(shortDefinition="The maximum number of observations to return for each observation code") @OperationParam(name = "max", typeName = "integer", min = 0, max = 1) - IPrimitiveType theMax + IPrimitiveType theMax, - ) { + @RawParam + Map> theAdditionalRawParams + ) { startRequest(theServletRequest); try { SearchParameterMap paramMap = new SearchParameterMap(); @@ -97,6 +103,8 @@ public class BaseJpaResourceProviderObservationR5 extends JpaResourceProviderR5< paramMap.setCount(theCount.getValue()); } + getDao().translateRawParameters(theAdditionalRawParams, paramMap); + return ((IFhirResourceDaoObservation) getDao()).observationsLastN(paramMap, theRequestDetails, theServletResponse); } finally { endRequest(theServletRequest); diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ElasticTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ElasticTest.java index 1af39faf51d..49ab785b3d4 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ElasticTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ElasticTest.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider; import ca.uhn.fhir.jpa.test.config.TestHibernateSearchAddInConfig; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.test.utilities.docker.RequiresDocker; @@ -11,8 +12,13 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.hl7.fhir.instance.model.api.IBaseCoding; +import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.Observation; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -26,6 +32,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -35,6 +43,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; @ExtendWith(SpringExtension.class) @RequiresDocker @@ -43,16 +52,22 @@ public class ResourceProviderR4ElasticTest extends BaseResourceProviderR4Test { private static final Logger ourLog = LoggerFactory.getLogger(ResourceProviderR4ElasticTest.class); @Autowired - DaoConfig myDaoConfig; + private DaoConfig myDaoConfig; + + private BaseJpaResourceProvider myObservationResourceProvider; @BeforeEach public void beforeEach() { + myDaoConfig.setLastNEnabled(true); myDaoConfig.setAdvancedLuceneIndexing(true); + myDaoConfig.setStoreResourceInLuceneIndex(true); } @AfterEach public void afterEach() { + myDaoConfig.setLastNEnabled(new DaoConfig().isLastNEnabled()); myDaoConfig.setAdvancedLuceneIndexing(new DaoConfig().isAdvancedLuceneIndexing()); + myDaoConfig.setStoreResourceInLuceneIndex(new DaoConfig().isStoreResourceInLuceneIndex()); } @@ -88,8 +103,14 @@ public class ResourceProviderR4ElasticTest extends BaseResourceProviderR4Test { } private void createObservationWithCode(Coding c) { + Patient patient = new Patient(); + patient.setId("Patient/p-123"); + patient.setActive(true); + myPatientDao.update(patient); Observation observation = new Observation(); + observation.getSubject().setReference("Patient/p-123"); observation.getCode().addCoding(c); + observation.setEffective(new DateTimeType(Date.from(Instant.now()))); myObservationDao.create(observation, mySrd).getId().toUnqualifiedVersionless(); } @@ -108,4 +129,32 @@ public class ResourceProviderR4ElasticTest extends BaseResourceProviderR4Test { }; } + @Test + public void testObservationLastNAllParamsPopulated() { + Coding blood_count = new Coding("http://loinc.org", "789-8", "Erythrocytes [#/volume] in Blood by Automated count"); + Coding vital_signs = new Coding("http://loinc.org", "123-45", "Vital Signs"); + + createObservationWithCode(blood_count); + createObservationWithCode(vital_signs); + + // subject: is declared param on lastN operation + // combo-code: is general Observation param and not a necessary param for lastN + Parameters respParam = myClient + .operation() + .onType(Observation.class) + .named("lastn") + .withParameter(Parameters.class, "subject", new StringType("Patient/p-123")) + .andParameter("combo-code:text", new StringType("Erythrocytes")) + .useHttpGet() + .execute(); + + assertEquals( 1, respParam.getParameter().size(), "Expected only 1 observation for blood count code"); + Bundle bundle = (Bundle) respParam.getParameter().get(0).getResource(); + Observation observation = (Observation) bundle.getEntryFirstRep().getResource(); + + assertEquals("Patient/p-123", observation.getSubject().getReference()); + assertTrue(observation.getCode().getCodingFirstRep().getDisplay().contains("Erythrocytes")); + + } + }