Add an isEmpty() method to IBundleProvider
This commit is contained in:
parent
dff2fdd3cf
commit
1c7c83cd8e
|
@ -13,6 +13,8 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@SuppressWarnings("null")
|
||||
// START SNIPPET: provider
|
||||
public class PagingPatientProvider implements IResourceProvider {
|
||||
|
@ -43,7 +45,8 @@ public class PagingPatientProvider implements IResourceProvider {
|
|||
return matchingResourceIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
|
||||
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
|
||||
|
|
|
@ -1765,14 +1765,30 @@ public class GenericJaxRsClientDstu3Test {
|
|||
@Test
|
||||
public void testTransactionWithString() {
|
||||
|
||||
org.hl7.fhir.dstu3.model.Bundle req = new org.hl7.fhir.dstu3.model.Bundle();
|
||||
Bundle req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("PAT_FAMILY");
|
||||
req.addEntry().setResource(patient);
|
||||
patient.setId("C01");
|
||||
patient.addName().setFamily("Smith").addGiven("John");
|
||||
req.addEntry()
|
||||
.setFullUrl("Patient/C01")
|
||||
.setResource(patient).getRequest().setMethod(HTTPVerb.PUT).setUrl("Patient/C01");
|
||||
|
||||
Observation observation = new Observation();
|
||||
observation.getCode().setText("OBS_TEXT");
|
||||
req.addEntry().setResource(observation);
|
||||
String reqString = ourCtx.newJsonParser().encodeResourceToString(req);
|
||||
observation.setId("C02");
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
observation.setEffective(new DateTimeType("2019-02-21T13:35:00-05:00"));
|
||||
observation.getSubject().setReference("Patient/C01");
|
||||
observation.getCode().addCoding().setSystem("http://loinc.org").setCode("3141-9").setDisplay("Body Weight Measured");
|
||||
observation.setValue(new Quantity(null, 190, "http://unitsofmeaure.org", "{lb_av}", "{lb_av}"));
|
||||
req.addEntry()
|
||||
.setFullUrl("Observation/C02")
|
||||
.setResource(observation).getRequest().setMethod(HTTPVerb.PUT).setUrl("Observation/C02");
|
||||
String reqString = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(req);
|
||||
ourLog.info(reqString);
|
||||
reqString = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(req);
|
||||
ourLog.info(reqString);
|
||||
|
||||
org.hl7.fhir.dstu3.model.Bundle resp = new org.hl7.fhir.dstu3.model.Bundle();
|
||||
resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.springframework.transaction.TransactionStatus;
|
|||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
@ -222,6 +223,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
return new InstantDt(mySearchEntity.getCreated());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
||||
ensureDependenciesInjected();
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -56,6 +57,7 @@ public class PersistedJpaSearchFirstPageBundleProvider extends PersistedJpaBundl
|
|||
myTxManager = theTxManager;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
SearchCoordinatorSvcImpl.verifySearchHasntFailedOrThrowInternalErrorException(mySearch);
|
||||
|
|
|
@ -99,6 +99,7 @@ public class TestUtil {
|
|||
if (!isTransient) {
|
||||
boolean hasColumn = nextField.getAnnotation(Column.class) != null;
|
||||
boolean hasJoinColumn = nextField.getAnnotation(JoinColumn.class) != null;
|
||||
boolean hasEmbeddedId = nextField.getAnnotation(EmbeddedId.class) != null;
|
||||
OneToMany oneToMany = nextField.getAnnotation(OneToMany.class);
|
||||
OneToOne oneToOne = nextField.getAnnotation(OneToOne.class);
|
||||
boolean isOtherSideOfOneToManyMapping = oneToMany != null && isNotBlank(oneToMany.mappedBy());
|
||||
|
@ -107,7 +108,8 @@ public class TestUtil {
|
|||
hasColumn ||
|
||||
hasJoinColumn ||
|
||||
isOtherSideOfOneToManyMapping ||
|
||||
isOtherSideOfOneToOneMapping, "Non-transient has no @Column or @JoinColumn: " + nextField);
|
||||
isOtherSideOfOneToOneMapping ||
|
||||
hasEmbeddedId, "Non-transient has no @Column or @JoinColumn or @EmbeddedId: " + nextField);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,8 +2,14 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -11,6 +17,9 @@ import org.junit.Test;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
||||
|
@ -60,6 +69,88 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteCircularReferenceInTransaction() throws IOException {
|
||||
|
||||
// Create two resources with a circular reference
|
||||
Organization org1 = new Organization();
|
||||
org1.setId(IdType.newRandomUuid());
|
||||
Organization org2 = new Organization();
|
||||
org2.setId(IdType.newRandomUuid());
|
||||
org1.getPartOf().setReference(org2.getId());
|
||||
org2.getPartOf().setReference(org1.getId());
|
||||
|
||||
// Upload them in a transaction
|
||||
Bundle createTransaction = new Bundle();
|
||||
createTransaction.setType(Bundle.BundleType.TRANSACTION);
|
||||
createTransaction
|
||||
.addEntry()
|
||||
.setResource(org1)
|
||||
.setFullUrl(org1.getId())
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.POST)
|
||||
.setUrl("Organization");
|
||||
createTransaction
|
||||
.addEntry()
|
||||
.setResource(org2)
|
||||
.setFullUrl(org2.getId())
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.POST)
|
||||
.setUrl("Organization");
|
||||
|
||||
Bundle createResponse = mySystemDao.transaction(mySrd, createTransaction);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createResponse));
|
||||
|
||||
IdType orgId1 = new IdType(createResponse.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||
IdType orgId2 = new IdType(createResponse.getEntry().get(1).getResponse().getLocation()).toUnqualifiedVersionless();
|
||||
|
||||
// Nope, can't delete 'em!
|
||||
try {
|
||||
myOrganizationDao.delete(orgId1);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
// good
|
||||
}
|
||||
try {
|
||||
myOrganizationDao.delete(orgId2);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
// Now in a transaction
|
||||
Bundle deleteTransaction = new Bundle();
|
||||
deleteTransaction.setType(Bundle.BundleType.TRANSACTION);
|
||||
deleteTransaction.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.DELETE)
|
||||
.setUrl(orgId1.getValue());
|
||||
deleteTransaction.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.DELETE)
|
||||
.setUrl(orgId2.getValue());
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(deleteTransaction));
|
||||
mySystemDao.transaction(mySrd, deleteTransaction);
|
||||
|
||||
// Make sure they were deleted
|
||||
try {
|
||||
myOrganizationDao.read(orgId1);
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// good
|
||||
}
|
||||
try {
|
||||
myOrganizationDao.read(orgId2);
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResourceIsConsideredDeletedIfOnlyResourceTableEntryIsDeleted() {
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package ca.uhn.fhir.rest.api.server;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -97,7 +99,7 @@ public interface IBundleProvider {
|
|||
* additional 20 resources which matched a client's _include specification.
|
||||
* <p>
|
||||
* Note that if this bundle provider was loaded using a
|
||||
* page ID (i.e. via {@link ca.uhn.fhir.rest.server.IPagingProvider#retrieveResultList(String, String)}
|
||||
* page ID (i.e. via {@link ca.uhn.fhir.rest.server.IPagingProvider#retrieveResultList(RequestDetails, String, String)}
|
||||
* because {@link #getNextPageId()} provided a value on the
|
||||
* previous page, then the indexes should be ignored and the
|
||||
* whole page returned.
|
||||
|
@ -107,6 +109,7 @@ public interface IBundleProvider {
|
|||
* @param theToIndex The high index (exclusive) to return
|
||||
* @return A list of resources. The size of this list must be at least <code>theToIndex - theFromIndex</code>.
|
||||
*/
|
||||
@Nonnull
|
||||
List<IBaseResource> getResources(int theFromIndex, int theToIndex);
|
||||
|
||||
/**
|
||||
|
@ -126,6 +129,7 @@ public interface IBundleProvider {
|
|||
* the search, and not to the individual page.
|
||||
* </p>
|
||||
*/
|
||||
@Nullable
|
||||
String getUuid();
|
||||
|
||||
/**
|
||||
|
@ -144,6 +148,19 @@ public interface IBundleProvider {
|
|||
* _include's or OperationOutcome). May return {@literal null} if the total size is not
|
||||
* known or would be too expensive to calculate.
|
||||
*/
|
||||
@Nullable
|
||||
Integer size();
|
||||
|
||||
/**
|
||||
* This method returns <code>true</code> if the bundle provider knows that at least
|
||||
* one result exists.
|
||||
*/
|
||||
default boolean isEmpty() {
|
||||
Integer size = size();
|
||||
if (size != null) {
|
||||
return size > 0;
|
||||
}
|
||||
return getResources(0, 1).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.server;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -84,6 +85,7 @@ public class BundleProviderWithNamedPages extends SimpleBundleProvider {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
return (List<IBaseResource>) getList(); // indexes are ignored for this provider type
|
||||
|
|
|
@ -29,6 +29,8 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Utility methods for working with {@link IBundleProvider}
|
||||
*/
|
||||
|
@ -46,6 +48,7 @@ public class BundleProviders {
|
|||
public static IBundleProvider newEmptyList() {
|
||||
final InstantDt published = InstantDt.withCurrentTime();
|
||||
return new IBundleProvider() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -78,6 +79,7 @@ public class SimpleBundleProvider implements IBundleProvider {
|
|||
myPublished = thePublished;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
return (List<IBaseResource>) myList.subList(theFromIndex, Math.min(theToIndex, myList.size()));
|
||||
|
|
|
@ -168,6 +168,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
return resources.getPublished();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
List<IBaseResource> retVal = resources.getResources(theFromIndex, theToIndex);
|
||||
|
|
|
@ -51,6 +51,8 @@ import static org.junit.Assert.*;
|
|||
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class SearchDstu2Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
@ -556,6 +558,7 @@ public class SearchDstu2Test {
|
|||
return ourReturnPublished;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
throw new IllegalStateException();
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -120,6 +121,7 @@ public class SearchHl7OrgDstu2Test {
|
|||
return ourReturnPublished;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
throw new IllegalStateException();
|
||||
|
|
|
@ -239,6 +239,11 @@
|
|||
been corrected. Note that at this time, we do not index canonical references
|
||||
at all (as we were previously doing it incorrectly). This will be improved soon.
|
||||
</action>
|
||||
<action type="add">
|
||||
IBundleProvider now has an isEmpty() method that can be used to check whether any
|
||||
results exist. A default implementation has been provided, so this is not
|
||||
a breaking change.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.8.0" date="2019-05-30" description="Hippo">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue