diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 781a06ee062..a9f7d1f5688 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -669,7 +669,9 @@ public class RestfulServer extends HttpServlet implements IRestfulServer allIds = new TreeSet(); for (BundleEntryComponent nextEntry : inputBundle.getEntry()) { nextEntry.getRequest().setMethod(HTTPVerb.PUT); nextEntry.getRequest().setUrl(nextEntry.getResource().getId()); allIds.add(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); } - + mySystemDao.transaction(mySrd, inputBundle); - Bundle responseBundle = ourClient - .operation() - .onInstance(new IdType("Patient/A161443")) - .named("everything") - .withParameter(Parameters.class, "_count", new IntegerType(50)) - .useHttpGet() - .returnResourceType(Bundle.class) - .execute(); - + Bundle responseBundle = ourClient.operation().onInstance(new IdType("Patient/A161443")).named("everything").withParameter(Parameters.class, "_count", new IntegerType(50)).useHttpGet() + .returnResourceType(Bundle.class).execute(); + TreeSet ids = new TreeSet(); for (int i = 0; i < responseBundle.getEntry().size(); i++) { for (BundleEntryComponent nextEntry : responseBundle.getEntry()) { ids.add(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); } } - + String nextUrl = responseBundle.getLink("next").getUrl(); responseBundle = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl); for (int i = 0; i < responseBundle.getEntry().size(); i++) { @@ -189,20 +179,84 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { ids.add(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); } } - + assertThat(ids, hasItem("List/A161444")); assertThat(ids, hasItem("List/A161468")); assertThat(ids, hasItem("List/A161500")); assertEquals(null, responseBundle.getLink("next")); - + ourLog.info("Expected {} - {}", allIds.size(), allIds); ourLog.info("Actual {} - {}", ids.size(), ids); assertEquals(allIds, ids); + + } + + /** + * Per message from David Hay on Skype + */ + @Test + public void testEverythingWithLargeSet2() throws Exception { + Patient p = new Patient(); + p.setActive(true); + IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless(); + + for (int i = 1; i < 77; i++) { + Observation obs = new Observation(); + obs.setId("A" + StringUtils.leftPad(Integer.toString(i), 2, '0')); + obs.setSubject(new Reference(id)); + ourClient.update().resource(obs).execute(); + } + + Bundle responseBundle = ourClient.operation().onInstance(id).named("everything").withParameter(Parameters.class, "_count", new IntegerType(50)).useHttpGet().returnResourceType(Bundle.class) + .execute(); + + TreeSet ids = new TreeSet(); + for (int i = 0; i < responseBundle.getEntry().size(); i++) { + for (BundleEntryComponent nextEntry : responseBundle.getEntry()) { + ids.add(nextEntry.getResource().getIdElement().getIdPart()); + } + } + + ourLog.info("Have {} IDs: {}", ids.size(), ids); + + BundleLinkComponent nextLink = responseBundle.getLink("next"); + while (nextLink != null) { + String nextUrl = nextLink.getUrl(); + responseBundle = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl); + for (int i = 0; i < responseBundle.getEntry().size(); i++) { + for (BundleEntryComponent nextEntry : responseBundle.getEntry()) { + ids.add(nextEntry.getResource().getIdElement().getIdPart()); + } + } + + ourLog.info("Have {} IDs: {}", ids.size(), ids); + nextLink = responseBundle.getLink("next"); + } + + assertThat(ids, hasItem(id.getIdPart())); + for (int i = 1; i < 77; i++) { + assertThat(ids, hasItem("A" + StringUtils.leftPad(Integer.toString(i), 2, '0'))); + } + assertEquals(77, ids.size()); + } + + @Test + public void testEmptySearch() throws Exception { + Bundle responseBundle; + + responseBundle = ourClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals(0, responseBundle.getTotal()); + + responseBundle = ourClient.search().forResource(Patient.class).where(Patient.NAME.matches().value("AAA")).returnBundle(Bundle.class).execute(); + assertEquals(0, responseBundle.getTotal()); + + responseBundle = ourClient.search().forResource(Patient.class).where(new StringClientParam("_content").matches().value("AAA")).returnBundle(Bundle.class).execute(); + assertEquals(0, responseBundle.getTotal()); + } - /** * See #411 * @@ -214,15 +268,15 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { patient.addIdentifier().setSystem("urn:system").setValue("0"); patient.addName().addFamily("testSearchWithMixedParams").addGiven("Joe"); myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless(); - - HttpPost httpPost = new HttpPost(ourServerBase + "/Patient/_search?_format=application/xml"); - httpPost.addHeader("Cache-Control","no-cache"); + + HttpPost httpPost = new HttpPost(ourServerBase + "/Patient/_search?_format=application/xml"); + httpPost.addHeader("Cache-Control", "no-cache"); List parameters = Lists.newArrayList(); parameters.add(new BasicNameValuePair("name", "Smith")); httpPost.setEntity(new UrlEncodedFormEntity(parameters)); ourLog.info("Outgoing post: {}", httpPost); - + CloseableHttpResponse status = ourHttpClient.execute(httpPost); try { String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); @@ -234,7 +288,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { } - @Test public void testSearchPagingKeepsOldSearches() throws Exception { String methodName = "testSearchPagingKeepsOldSearches"; @@ -1875,7 +1928,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { assertEquals(id.withVersion("1").getValue(), history.getEntry().get(2).getResource().getId()); assertEquals(1, ((Patient) history.getEntry().get(2).getResource()).getName().size()); - + try { myBundleDao.validate(history, null, null, null, null, null, mySrd); } catch (PreconditionFailedException e) { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProviderTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProviderTest.java new file mode 100644 index 00000000000..1a8e222d5a0 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/search/PersistedJpaBundleProviderTest.java @@ -0,0 +1,17 @@ +package ca.uhn.fhir.jpa.search; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.springframework.data.domain.Pageable; + +public class PersistedJpaBundleProviderTest { + + @Test + public void testGetPage() { + Pageable page = PersistedJpaBundleProvider.toPage(50, 73); + assertEquals(50, page.getOffset()); +// assertEquals(50, page.get); + } + +} diff --git a/hapi-fhir-jpaserver-base/src/test/resources/logback-test.xml b/hapi-fhir-jpaserver-base/src/test/resources/logback-test.xml index 6c4628357f7..3beabf3d18b 100644 --- a/hapi-fhir-jpaserver-base/src/test/resources/logback-test.xml +++ b/hapi-fhir-jpaserver-base/src/test/resources/logback-test.xml @@ -10,11 +10,11 @@ - + - + @@ -34,7 +34,7 @@ - + diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java b/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java index 649bf14c23c..e36e1dd2a03 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java @@ -28,7 +28,7 @@ public class UhnFhirTestApp { System.setProperty("fhir.db.location", "./target/testdb"); System.setProperty("fhir.db.location.dstu2", "./target/testdb_dstu2"); System.setProperty("fhir.lucene.location.dstu2", "./target/testlucene_dstu2"); - System.setProperty("fhir.db.location.dstu3", "./target/testdb_dstu3"); + System.setProperty("fhir.db.location.dstu3", "./target/fhirtest_dstu3"); System.setProperty("fhir.lucene.location.dstu3", "./target/testlucene_dstu3"); System.setProperty("fhir.db.location.tdl2", "./target/testdb_tdl2"); System.setProperty("fhir.lucene.location.tdl2", "./target/testlucene_tdl2"); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index aa2a605c99a..d4bac5b617f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -16,6 +16,11 @@ ]]> + + Fix a fairly significant issue in JPA Server when using the DatabaseBackedPagingProvider]]>: When paging over the results + of a search / $everything operation, under certain circumstances resources may be missing from the last page of results + that is returned. Thanks to David Hay for reporting! + Client, Server, and JPA server now support experimental support for