Add config item to auto create references in JPA

This commit is contained in:
James 2017-08-31 08:57:51 -04:00
parent a24cbd7da5
commit 78fd13c2f4
4 changed files with 683 additions and 490 deletions

View File

@ -332,7 +332,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
if (myConfig.isEnforceReferentialIntegrityOnWrite() == false) {
continue;
}
String resName = getContext().getResourceDefinition(type).getName();
RuntimeResourceDefinition missingResourceDef = getContext().getResourceDefinition(type);
String resName = missingResourceDef.getName();
if (getConfig().isAutoCreatePlaceholderReferenceTargets()) {
IBaseResource newResource = missingResourceDef.newInstance();
newResource.setId(resName + "/" + id);
autoCreateResource(newResource);
}
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
@ -367,6 +375,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return retVal;
}
private <T extends IBaseResource> void autoCreateResource(T theResource) {
IFhirResourceDao<T> dao = (IFhirResourceDao<T>) getDao(theResource.getClass());
dao.create(theResource);
}
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
}

View File

@ -0,0 +1,140 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.dao.*;
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.IssueType;
import org.hl7.fhir.r4.model.Quantity.QuantityComparator;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
@SuppressWarnings({ "unchecked", "deprecation" })
public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoCreatePlaceholdersR4Test.class);
@After
public final void afterResetDao() {
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(new DaoConfig().isAutoCreatePlaceholderReferenceTargets());
}
@Test
public void testCreateWithBadReferenceFails() {
Observation o = new Observation();
o.setStatus(ObservationStatus.FINAL);
o.getSubject().setReference("Patient/FOO");
try {
myObservationDao.create(o, mySrd);
fail();
} catch (InvalidRequestException e) {
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
}
}
@Test
public void testCreateWithBadReferenceIsPermitted() {
assertFalse(myDaoConfig.isAutoCreatePlaceholderReferenceTargets());
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
Observation o = new Observation();
o.setStatus(ObservationStatus.FINAL);
o.getSubject().setReference("Patient/FOO");
try {
myObservationDao.create(o, mySrd);
fail();
} catch (InvalidRequestException e) {
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
}
}
@Test
public void testUpdateWithBadReferenceFails() {
Observation o = new Observation();
o.setStatus(ObservationStatus.FINAL);
IIdType id = myObservationDao.create(o, mySrd).getId();
o = new Observation();
o.setId(id);
o.setStatus(ObservationStatus.FINAL);
o.getSubject().setReference("Patient/FOO");
try {
myObservationDao.update(o, mySrd);
fail();
} catch (InvalidRequestException e) {
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
}
}
@Test
public void testUpdateWithBadReferenceIsPermitted() {
assertFalse(myDaoConfig.isAutoCreatePlaceholderReferenceTargets());
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
Observation o = new Observation();
o.setStatus(ObservationStatus.FINAL);
IIdType id = myObservationDao.create(o, mySrd).getId();
o = new Observation();
o.setId(id);
o.setStatus(ObservationStatus.FINAL);
o.getSubject().setReference("Patient/FOO");
try {
myObservationDao.update(o, mySrd);
fail();
} catch (InvalidRequestException e) {
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
}
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}

View File

@ -337,6 +337,11 @@
to Eugene Lubarsky for the pull request, and for convincing James not to
optimize something that did not need optimizing!
</action>
<action type="add">
A new config property has been added to the JPA seerver DaoConfig called "setAutoCreatePlaceholderReferenceTargets".
This property causes references to unknown resources in created/updated resources to have a placeholder
target resource automatically created.
</action>
</release>
<release version="2.5" date="2017-06-08">
<action type="fix">