Improve automatic placeholder creation (#6581)
* Describe placeholder resources in reponse * Include details about placeholders in responses * Add tests * version bump * Address review comments
This commit is contained in:
parent
5c4aae0b26
commit
b75c34bba7
|
@ -49,7 +49,9 @@ public enum StorageResponseCodeEnum implements ICodingEnum {
|
|||
SUCCESSFUL_PATCH_NO_CHANGE("Patch succeeded: No changes were detected so no action was taken."),
|
||||
SUCCESSFUL_CONDITIONAL_PATCH("Conditional patch succeeded."),
|
||||
SUCCESSFUL_CONDITIONAL_PATCH_NO_CHANGE(
|
||||
"Conditional patch succeeded: No changes were detected so no action was taken.");
|
||||
"Conditional patch succeeded: No changes were detected so no action was taken."),
|
||||
AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE("Automatically created placeholder resource."),
|
||||
;
|
||||
|
||||
public static final String SYSTEM = "https://hapifhir.io/fhir/CodeSystem/hapi-fhir-storage-response-code";
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ ca.uhn.fhir.jpa.dao.BaseStorageDao.invalidVersion=Version "{0}" is not valid for
|
|||
ca.uhn.fhir.jpa.dao.BaseStorageDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.missingBody=No body was supplied in request
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.unableToDeleteNotFound=Unable to find resource matching URL "{0}". Nothing has been deleted.
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.successfulAutoCreatePlaceholder=Automatically created placeholder resource with ID: {0}
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.successfulCreate=Successfully created resource "{0}".
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.successfulCreateConditionalNoMatch=Successfully conditionally created resource "{0}". No existing resources matched URL "{1}".
|
||||
ca.uhn.fhir.jpa.dao.BaseStorageDao.successfulCreateConditionalWithMatch=Successfully conditionally created resource "{0}". Existing resource matched URL "{1}".
|
||||
|
|
|
@ -1490,7 +1490,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
}
|
||||
}
|
||||
|
||||
populateOperationOutcomeForUpdate(w, outcome, theMatchUrl, outcome.getOperationType());
|
||||
populateOperationOutcomeForUpdate(w, outcome, theMatchUrl, outcome.getOperationType(), theTransactionDetails);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
|
|
@ -621,7 +621,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
outcome.setId(theResource.getIdElement());
|
||||
}
|
||||
|
||||
populateOperationOutcomeForUpdate(w, outcome, theMatchUrl, theOperationType);
|
||||
populateOperationOutcomeForUpdate(w, outcome, theMatchUrl, theOperationType, theTransactionDetails);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
@ -2465,11 +2465,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
if (!create) {
|
||||
try {
|
||||
entity = readEntityLatestVersion(
|
||||
theRequest, resourceId, theRequestPartitionId, theTransactionDetails);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
if (theTransactionDetails != null && theTransactionDetails.hasNullResolvedResourceId(resourceId)) {
|
||||
create = true;
|
||||
} else {
|
||||
try {
|
||||
entity = readEntityLatestVersion(
|
||||
theRequest, resourceId, theRequestPartitionId, theTransactionDetails);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
create = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2639,7 +2643,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
theRequest, savedEntity, theResource, null, RestOperationTypeEnum.UPDATE)
|
||||
.setCreated(wasDeleted);
|
||||
|
||||
populateOperationOutcomeForUpdate(w, outcome, null, RestOperationTypeEnum.UPDATE);
|
||||
populateOperationOutcomeForUpdate(w, outcome, null, RestOperationTypeEnum.UPDATE, theTransactionDetails);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
|
|
@ -311,7 +311,7 @@ public class TransactionProcessor extends BaseTransactionProcessor {
|
|||
Map<IIdType, IResourceLookup<JpaPid>> outcomes = myIdHelperService.resolveResourceIdentities(
|
||||
theRequestPartitionId, idsToPreResolve.keySet(), resolveMode);
|
||||
for (Map.Entry<IIdType, IResourceLookup<JpaPid>> entry : outcomes.entrySet()) {
|
||||
JpaPid next = (JpaPid) entry.getValue().getPersistentId();
|
||||
JpaPid next = entry.getValue().getPersistentId();
|
||||
IIdType unqualifiedVersionlessId = entry.getKey();
|
||||
foundIds.add(unqualifiedVersionlessId.getValue());
|
||||
theTransactionDetails.addResolvedResourceId(unqualifiedVersionlessId, next);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static ca.uhn.fhir.util.HapiExtensions.EXT_RESOURCE_PLACEHOLDER;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -24,15 +25,19 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.r4.model.AuditEvent;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Identifier;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.ResourceType;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.hl7.fhir.r4.model.Task;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
@ -96,14 +101,25 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
task.addPartOf().setReference("Task/AAA");
|
||||
task.addPartOf().setReference("Task/AAA");
|
||||
task.addPartOf().setReference("Task/AAA");
|
||||
IIdType id = myTaskDao.create(task).getId().toUnqualifiedVersionless();
|
||||
DaoMethodOutcome methodOutcome = myTaskDao.create(task);
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) methodOutcome.getOperationOutcome();
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
assertEquals("SUCCESSFUL_CREATE", oo.getIssue().get(0).getDetails().getCodingFirstRep().getCode());
|
||||
assertEquals("AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE", oo.getIssue().get(1).getDetails().getCodingFirstRep().getCode());
|
||||
assertEquals("Automatically created placeholder resource with ID: Task/AAA/_history/1", oo.getIssue().get(1).getDiagnostics());
|
||||
|
||||
IIdType id = methodOutcome.getId().toUnqualifiedVersionless();
|
||||
task = myTaskDao.read(id);
|
||||
assertThat(task.getPartOf()).hasSize(3);
|
||||
assertEquals("Task/AAA", task.getPartOf().get(0).getReference());
|
||||
assertEquals("Task/AAA", task.getPartOf().get(1).getReference());
|
||||
assertEquals("Task/AAA", task.getPartOf().get(2).getReference());
|
||||
|
||||
Task placeholderTask = myTaskDao.read(new IdType("Task/AAA"), mySrd);
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(placeholderTask));
|
||||
assertNotNull(placeholderTask);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Task.SP_PART_OF, new ReferenceParam("Task/AAA"));
|
||||
List<String> found = toUnqualifiedVersionlessIdValues(myTaskDao.search(params));
|
||||
|
@ -222,7 +238,7 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
IIdType placeholderPatId = placeholderPat.getIdElement();
|
||||
ourLog.debug("\nPlaceholder Patient created:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(placeholderPat));
|
||||
assertThat(placeholderPat.getIdentifier()).isEmpty();
|
||||
Extension extension = placeholderPat.getExtensionByUrl(HapiExtensions.EXT_RESOURCE_PLACEHOLDER);
|
||||
Extension extension = placeholderPat.getExtensionByUrl(EXT_RESOURCE_PLACEHOLDER);
|
||||
assertNotNull(extension);
|
||||
assertTrue(extension.hasValue());
|
||||
assertTrue(((BooleanType) extension.getValue()).booleanValue());
|
||||
|
@ -240,7 +256,7 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
Patient updatedPat = myPatientDao.read(updatedPatId);
|
||||
ourLog.debug("\nUpdated Patient:\n" + myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedPat));
|
||||
assertThat(updatedPat.getIdentifier()).hasSize(1);
|
||||
extension = updatedPat.getExtensionByUrl(HapiExtensions.EXT_RESOURCE_PLACEHOLDER);
|
||||
extension = updatedPat.getExtensionByUrl(EXT_RESOURCE_PLACEHOLDER);
|
||||
assertNull(extension);
|
||||
}
|
||||
|
||||
|
@ -653,7 +669,40 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAutocreatePlaceholderTest() {
|
||||
public void testSearchForPlaceholder() {
|
||||
//Setup
|
||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.addBase("Patient");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.setCode("placeholder");
|
||||
sp.setName("placeholder");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setExpression("extension('" + EXT_RESOURCE_PLACEHOLDER + "').where(value = true)");
|
||||
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
sp.setDescription("Index resources which were automatically created as placeholders");
|
||||
ourLog.info("Search parameter:\n{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
||||
mySearchParameterDao.create(sp, mySrd);
|
||||
|
||||
createPatient(withId("B"), withActiveTrue());
|
||||
|
||||
// Test
|
||||
Observation obsToCreate = new Observation();
|
||||
obsToCreate.getSubject().setReference("Patient/A");
|
||||
myObservationDao.create(obsToCreate, mySrd);
|
||||
|
||||
logAllTokenIndexes("placeholder");
|
||||
|
||||
// Verify
|
||||
SearchParameterMap map = SearchParameterMap.newSynchronous("placeholder", new TokenParam("true"));
|
||||
IBundleProvider outcome = myPatientDao.search(map, mySrd);
|
||||
assertThat(toUnqualifiedVersionlessIdValues(outcome)).asList().containsExactly("Patient/A");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransaction() {
|
||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
|
||||
Observation obs = new Observation();
|
||||
|
@ -663,7 +712,12 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
BundleBuilder builder = new BundleBuilder(myFhirContext);
|
||||
builder.addTransactionUpdateEntry(obs);
|
||||
|
||||
mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
|
||||
Bundle outcome = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||
OperationOutcome oo = (OperationOutcome) outcome.getEntry().get(0).getResponse().getOutcome();
|
||||
assertEquals("SUCCESSFUL_UPDATE_AS_CREATE", oo.getIssue().get(0).getDetails().getCodingFirstRep().getCode());
|
||||
assertEquals("AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE", oo.getIssue().get(1).getDetails().getCodingFirstRep().getCode());
|
||||
assertEquals("Automatically created placeholder resource with ID: Patient/RED/_history/1", oo.getIssue().get(1).getDiagnostics());
|
||||
|
||||
// verify subresource is created
|
||||
Patient returned = myPatientDao.read(patientRef.getReferenceElement());
|
||||
|
@ -672,7 +726,7 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
|
||||
|
||||
@Test
|
||||
public void testAutocreatePlaceholderWithTargetExistingAlreadyTest() {
|
||||
public void testTransaction_TargetExistingAlready() {
|
||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
myStorageSettings.setAutoVersionReferenceAtPaths("Observation.subject");
|
||||
|
||||
|
@ -713,7 +767,7 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
* This test is the same as above, except it uses the serverid (instead of forcedid)
|
||||
*/
|
||||
@Test
|
||||
public void testAutocreatePlaceholderWithExistingTargetWithServerAssignedIdTest() {
|
||||
public void testTransaction_ExistingTargetWithServerAssignedId() {
|
||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
myStorageSettings.setAutoVersionReferenceAtPaths("Observation.subject");
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
@ -2741,6 +2742,51 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithCreatePlaceholders() {
|
||||
// Setup
|
||||
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
|
||||
BiFunction<String, String, Patient> supplier = (patientId, orgRef) -> {
|
||||
Patient patient = new Patient();
|
||||
patient.setId(patientId);
|
||||
patient.setManagingOrganization(new Reference(orgRef));
|
||||
return patient;
|
||||
};
|
||||
BundleBuilder bb = new BundleBuilder(myFhirContext);
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P0", "Organization/O0"));
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P1", "Organization/O0"));
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P2", "Organization/O1"));
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P3", "Organization/O1"));
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P4", "Organization/O2"));
|
||||
bb.addTransactionUpdateEntry(supplier.apply("Patient/P5", "Organization/O2"));
|
||||
Bundle input = bb.getBundleTyped();
|
||||
|
||||
// Test
|
||||
myCaptureQueriesListener.clear();
|
||||
Bundle output = mySystemDao.transaction(mySrd, input);
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
// Verify
|
||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
||||
assertEquals(30, myCaptureQueriesListener.countInsertQueries());
|
||||
assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
|
||||
assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
|
||||
assertEquals(0, myCaptureQueriesListener.countInsertQueriesRepeated());
|
||||
assertEquals(1, myCaptureQueriesListener.countGetConnections());
|
||||
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertNotGone(new IdType("Patient/P" + i));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assertNotGone(new IdType("Organization/O" + i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* See the class javadoc before changing the counts in this test!
|
||||
|
|
|
@ -71,6 +71,7 @@ public class TransactionDetails {
|
|||
private ListMultimap<Pointcut, HookParams> myDeferredInterceptorBroadcasts;
|
||||
private EnumSet<Pointcut> myDeferredInterceptorBroadcastPointcuts;
|
||||
private boolean myFhirTransaction;
|
||||
private List<IIdType> myAutoCreatedPlaceholderResources = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -228,6 +229,24 @@ public class TransactionDetails {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given ID was marked as not existing (i.e. someone called
|
||||
* {@link #addResolvedResourceId(IIdType, IResourcePersistentId)} with an
|
||||
* ID of null).
|
||||
*
|
||||
* @param theId The resource ID
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public boolean hasNullResolvedResourceId(IIdType theId) {
|
||||
if (myResolvedResourceIds != null) {
|
||||
String key = theId.toVersionless().getValue();
|
||||
if (myResolvedResourceIds.containsKey(key)) {
|
||||
return myResolvedResourceIds.get(key) == null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A <b>Resolved Resource ID</b> is a mapping between a resource ID (e.g. "<code>Patient/ABC</code>" or
|
||||
* "<code>Observation/123</code>") and a storage ID for that resource. Resources should only be placed within
|
||||
|
@ -292,8 +311,8 @@ public class TransactionDetails {
|
|||
}
|
||||
|
||||
/**
|
||||
* @since 6.8.0
|
||||
* @see #addResolvedMatchUrl(FhirContext, String, IResourcePersistentId)
|
||||
* @since 6.8.0
|
||||
*/
|
||||
public void removeResolvedMatchUrl(String theMatchUrl) {
|
||||
myResolvedMatchUrls.remove(theMatchUrl);
|
||||
|
@ -442,4 +461,20 @@ public class TransactionDetails {
|
|||
public void setFhirTransaction(boolean theFhirTransaction) {
|
||||
myFhirTransaction = theFhirTransaction;
|
||||
}
|
||||
|
||||
public void addAutoCreatedPlaceholderResource(IIdType theResource) {
|
||||
if (myAutoCreatedPlaceholderResources.isEmpty()) {
|
||||
myAutoCreatedPlaceholderResources = new ArrayList<>();
|
||||
}
|
||||
myAutoCreatedPlaceholderResources.add(theResource);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<IIdType> getAutoCreatedPlaceholderResourcesAndClear() {
|
||||
List<IIdType> retVal = myAutoCreatedPlaceholderResources;
|
||||
if (!myAutoCreatedPlaceholderResources.isEmpty()) {
|
||||
myAutoCreatedPlaceholderResources = Collections.emptyList();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ public abstract class BaseStorageDao {
|
|||
|
||||
protected static final String MESSAGE_KEY_DELETE_RESOURCE_NOT_EXISTING = "deleteResourceNotExisting";
|
||||
protected static final String MESSAGE_KEY_DELETE_RESOURCE_ALREADY_DELETED = "deleteResourceAlreadyDeleted";
|
||||
public static final String OO_ISSUE_CODE_INFORMATIONAL = "informational";
|
||||
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegistry;
|
||||
|
@ -452,7 +453,8 @@ public abstract class BaseStorageDao {
|
|||
|
||||
public IBaseOperationOutcome createInfoOperationOutcome(
|
||||
String theMessage, @Nullable StorageResponseCodeEnum theStorageResponseCode) {
|
||||
return createOperationOutcome(OO_SEVERITY_INFO, theMessage, "informational", theStorageResponseCode);
|
||||
return createOperationOutcome(
|
||||
OO_SEVERITY_INFO, theMessage, OO_ISSUE_CODE_INFORMATIONAL, theStorageResponseCode);
|
||||
}
|
||||
|
||||
private IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) {
|
||||
|
@ -592,7 +594,8 @@ public abstract class BaseStorageDao {
|
|||
@Nullable StopWatch theItemStopwatch,
|
||||
DaoMethodOutcome theMethodOutcome,
|
||||
String theMatchUrl,
|
||||
RestOperationTypeEnum theOperationType) {
|
||||
RestOperationTypeEnum theOperationType,
|
||||
TransactionDetails theTransactionDetails) {
|
||||
String msg;
|
||||
StorageResponseCodeEnum outcome;
|
||||
|
||||
|
@ -723,10 +726,42 @@ public abstract class BaseStorageDao {
|
|||
msg = msg + " " + msgSuffix;
|
||||
}
|
||||
|
||||
theMethodOutcome.setOperationOutcome(createInfoOperationOutcome(msg, outcome));
|
||||
IBaseOperationOutcome oo = createInfoOperationOutcome(msg, outcome);
|
||||
|
||||
if (theTransactionDetails != null) {
|
||||
List<IIdType> autoCreatedPlaceholderResources =
|
||||
theTransactionDetails.getAutoCreatedPlaceholderResourcesAndClear();
|
||||
for (IIdType next : autoCreatedPlaceholderResources) {
|
||||
msg = addIssueToOperationOutcomeForAutoCreatedPlaceholder(getContext(), next, oo);
|
||||
}
|
||||
}
|
||||
|
||||
theMethodOutcome.setOperationOutcome(oo);
|
||||
ourLog.debug(msg);
|
||||
}
|
||||
|
||||
public static String addIssueToOperationOutcomeForAutoCreatedPlaceholder(
|
||||
FhirContext theFhirContext, IIdType thePlaceholderId, IBaseOperationOutcome theOperationOutcomeToPopulate) {
|
||||
String msg;
|
||||
msg = theFhirContext
|
||||
.getLocalizer()
|
||||
.getMessageSanitized(BaseStorageDao.class, "successfulAutoCreatePlaceholder", thePlaceholderId);
|
||||
String detailSystem = StorageResponseCodeEnum.AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE.getSystem();
|
||||
String detailCode = StorageResponseCodeEnum.AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE.getCode();
|
||||
String detailDescription = StorageResponseCodeEnum.AUTOMATICALLY_CREATED_PLACEHOLDER_RESOURCE.getDisplay();
|
||||
OperationOutcomeUtil.addIssue(
|
||||
theFhirContext,
|
||||
theOperationOutcomeToPopulate,
|
||||
OO_SEVERITY_INFO,
|
||||
msg,
|
||||
null,
|
||||
OO_ISSUE_CODE_INFORMATIONAL,
|
||||
detailSystem,
|
||||
detailCode,
|
||||
detailDescription);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a list of references that have versions in their ID whose versions should not be stripped
|
||||
*
|
||||
|
|
|
@ -98,6 +98,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -1946,9 +1947,19 @@ public abstract class BaseTransactionProcessor {
|
|||
|
||||
theIdSubstitutions.updateTargets(newId);
|
||||
|
||||
if (theDaoMethodOutcome.getOperationOutcome() != null) {
|
||||
// This will only be null if we're not intending to return an OO
|
||||
IBaseOperationOutcome operationOutcome = theDaoMethodOutcome.getOperationOutcome();
|
||||
if (operationOutcome != null) {
|
||||
|
||||
List<IIdType> autoCreatedPlaceholders =
|
||||
theTransactionDetails.getAutoCreatedPlaceholderResourcesAndClear();
|
||||
for (IIdType autoCreatedPlaceholder : autoCreatedPlaceholders) {
|
||||
BaseStorageDao.addIssueToOperationOutcomeForAutoCreatedPlaceholder(
|
||||
myContext, autoCreatedPlaceholder, operationOutcome);
|
||||
}
|
||||
|
||||
IBase responseEntry = theEntriesToProcess.getResponseBundleEntryWithVersionlessComparison(newId);
|
||||
myVersionAdapter.setResponseOutcome(responseEntry, theDaoMethodOutcome.getOperationOutcome());
|
||||
myVersionAdapter.setResponseOutcome(responseEntry, operationOutcome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,14 @@ public class DaoResourceLinkResolver<T extends IResourcePersistentId<?>> impleme
|
|||
String idPart = targetResourceId.getIdPart();
|
||||
try {
|
||||
if (persistentId == null) {
|
||||
|
||||
// If we previously looked up the ID, and it was not found, don't bother
|
||||
// looking it up again
|
||||
if (theTransactionDetails != null
|
||||
&& theTransactionDetails.hasNullResolvedResourceId(targetResourceId)) {
|
||||
throw new ResourceNotFoundException(Msg.code(2602));
|
||||
}
|
||||
|
||||
resolvedResource = myIdHelperService.resolveResourceIdentity(
|
||||
theRequestPartitionId,
|
||||
resourceType,
|
||||
|
@ -294,7 +302,9 @@ public class DaoResourceLinkResolver<T extends IResourcePersistentId<?>> impleme
|
|||
theTransactionDetails.addRollbackUndoAction(() -> newResource.setId(existingId));
|
||||
}
|
||||
newResource.setId(resName + "/" + theIdToAssignToPlaceholder);
|
||||
valueOf = placeholderResourceDao.update(newResource, theRequest).getEntity();
|
||||
valueOf = placeholderResourceDao
|
||||
.update(newResource, null, true, false, theRequest, theTransactionDetails)
|
||||
.getEntity();
|
||||
} else {
|
||||
valueOf = placeholderResourceDao.create(newResource, theRequest).getEntity();
|
||||
}
|
||||
|
@ -303,6 +313,7 @@ public class DaoResourceLinkResolver<T extends IResourcePersistentId<?>> impleme
|
|||
persistentId = myIdHelperService.newPid(persistentId.getId());
|
||||
persistentId.setAssociatedResourceId(valueOf.getIdDt());
|
||||
theTransactionDetails.addResolvedResourceId(persistentId.getAssociatedResourceId(), persistentId);
|
||||
theTransactionDetails.addAutoCreatedPlaceholderResource(newResource.getIdElement());
|
||||
}
|
||||
|
||||
return Optional.ofNullable(valueOf);
|
||||
|
|
Loading…
Reference in New Issue