Transaction with conditional delete and update on the same resource should not fail (#5318)

* Transaction with conditional delete and update on the same resource should not fail - test

* Transaction with conditional delete and update on the same resource should not fail - implementation

* Transaction with conditional delete and update on the same resource should not fail - added changelog

* Transaction with conditional delete and update on the same resource should not fail - fixes
This commit is contained in:
volodymyr-korzh 2023-09-15 14:14:18 -06:00 committed by GitHub
parent 8b7c9f1453
commit f94295d46c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 4 deletions

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 5316
jira: SMILE-7168
title: "Previously, performing a FHIR transaction containing both a conditional delete and a conditional update
on the same resource would fail. This has been fixed."

View File

@ -1544,7 +1544,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
provenance = historyEntry.getProvenance();
}
if (provenance == null) {
provenance = new ResourceHistoryProvenanceEntity();
provenance = historyEntry.toProvenance();
}
provenance.setResourceHistoryTable(historyEntry);
provenance.setResourceTable(theEntity);

View File

@ -111,6 +111,9 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
@Column(name = "REQUEST_ID", length = Constants.REQUEST_ID_LENGTH, nullable = true)
private String myRequestId;
@Transient
private transient ResourceHistoryProvenanceEntity myNewHistoryProvenanceEntity;
/**
* Constructor
*/
@ -302,4 +305,17 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
public boolean hasResource() {
return myResource != null || myResourceTextVc != null;
}
/**
* This method creates a new HistoryProvenance entity, or might reuse the current one if we've
* already created one in the current transaction. This is because we can only increment
* the version once in a DB transaction (since hibernate manages that number) so creating
* multiple {@link ResourceHistoryProvenanceEntity} entities will result in a constraint error.
*/
public ResourceHistoryProvenanceEntity toProvenance() {
if (myNewHistoryProvenanceEntity == null) {
myNewHistoryProvenanceEntity = new ResourceHistoryProvenanceEntity();
}
return myNewHistoryProvenanceEntity;
}
}

View File

@ -27,11 +27,11 @@ import static org.apache.commons.lang3.StringUtils.countMatches;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.in;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
@ -451,12 +451,22 @@ public class FhirSystemDaoTransactionR5Test extends BaseJpaR5Test {
/**
* If a conditional delete and conditional update are both used on the same condition,
* the update should win.
* We need to test this scenario with both empty and non-empty RequestDetails.requestId parameter,
* as providing RequestDetails.requestId previously caused javax.persistence.EntityExistsException
* during persistence of ResourceHistoryProvenanceEntity.
*
* @param theReturnRequestId if RequestDetails.requestId should return non-null value
*/
@Test
public void testConditionalDeleteAndConditionalUpdateOnSameResource() {
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void createBundle_withConditionalDeleteAndConditionalUpdateOnSameResource_updatesResource(boolean theReturnRequestId) {
Bundle outcome;
Patient actual;
if (theReturnRequestId) {
when(mySrd.getRequestId()).thenReturn("requestId");
}
// First pass (resource doesn't already exist)
outcome = mySystemDao.transaction(mySrd, createBundleWithConditionalDeleteAndConditionalUpdateOnSameResource(myFhirContext));