Updates to transaction processing

This commit is contained in:
James Agnew 2019-02-28 12:23:48 -05:00
parent 6e41f90bf9
commit 7896887f67
3 changed files with 134 additions and 68 deletions

View File

@ -508,60 +508,65 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
/*
* Look for duplicate conditional creates and consolidate them
*/
Map<String, String> keyToUuid = new HashMap<>();
final HashMap<String, String> keyToUuid = new HashMap<>();
final IdentityHashMap<IBaseResource, String> identityToUuid = new IdentityHashMap<>();
for (int index = 0, originalIndex = 0; index < theEntries.size(); index++, originalIndex++) {
BUNDLEENTRY nextReqEntry = theEntries.get(index);
IBaseResource resource = myVersionAdapter.getResource(nextReqEntry);
if (resource != null) {
String verb = myVersionAdapter.getEntryRequestVerb(nextReqEntry);
String entryUrl = myVersionAdapter.getFullUrl(nextReqEntry);
String requestUrl = myVersionAdapter.getEntryRequestUrl(nextReqEntry);
String ifNoneExist = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
String key = verb + "|" + requestUrl + "|" + ifNoneExist;
// String encoded = myContext.newJsonParser().encodeResourceToString(myVersionAdapter.getResource(nextReqEntry));
// if (encoded.contains("00000011111")) {
// ourLog.info("Resource contains 00000011111");
// }
String verb = myVersionAdapter.getEntryRequestVerb(nextReqEntry);
String entryUrl = myVersionAdapter.getFullUrl(nextReqEntry);
String requestUrl = myVersionAdapter.getEntryRequestUrl(nextReqEntry);
String ifNoneExist = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
String key = verb + "|"+ requestUrl + "|" + ifNoneExist;
// Conditional UPDATE
boolean consolidateEntry = false;
if ("PUT".equals(verb)) {
if (isNotBlank(entryUrl) && isNotBlank(requestUrl)) {
int questionMarkIndex = requestUrl.indexOf('?');
if (questionMarkIndex >= 0 && requestUrl.length() > (questionMarkIndex+1)) {
consolidateEntry = true;
// Conditional UPDATE
boolean consolidateEntry = false;
if ("PUT".equals(verb)) {
if (isNotBlank(entryUrl) && isNotBlank(requestUrl)) {
int questionMarkIndex = requestUrl.indexOf('?');
if (questionMarkIndex >= 0 && requestUrl.length() > (questionMarkIndex + 1)) {
consolidateEntry = true;
}
}
}
}
// Conditional CREATE
if ("POST".equals(verb)) {
if (isNotBlank(entryUrl) && isNotBlank(requestUrl) && isNotBlank(ifNoneExist)) {
if (!entryUrl.equals(requestUrl)) {
consolidateEntry = true;
// Conditional CREATE
if ("POST".equals(verb)) {
if (isNotBlank(entryUrl) && isNotBlank(requestUrl) && isNotBlank(ifNoneExist)) {
if (!entryUrl.equals(requestUrl)) {
consolidateEntry = true;
}
}
}
}
if (consolidateEntry) {
if (!keyToUuid.containsKey(key)) {
keyToUuid.put(key, entryUrl);
} else {
ourLog.info("Discarding transaction bundle entry {} as it contained a duplicate conditional {}", originalIndex, verb);
theEntries.remove(index);
index--;
String existingUuid = keyToUuid.get(key);
for (BUNDLEENTRY nextEntry : theEntries) {
IBaseResource nextResource = myVersionAdapter.getResource(nextEntry);
for (ResourceReferenceInfo nextReference : myContext.newTerser().getAllResourceReferences(nextResource)) {
if (entryUrl.equals(nextReference.getResourceReference().getReferenceElement().getValue())) {
nextReference.getResourceReference().setReference(existingUuid);
if (consolidateEntry) {
if (!keyToUuid.containsKey(key)) {
keyToUuid.put(key, entryUrl);
identityToUuid.put(resource, entryUrl);
} else {
ourLog.info("Discarding transaction bundle entry {} as it contained a duplicate conditional {}", originalIndex, verb);
theEntries.remove(index);
index--;
String existingUuid = keyToUuid.get(key);
for (BUNDLEENTRY nextEntry : theEntries) {
IBaseResource nextResource = myVersionAdapter.getResource(nextEntry);
for (ResourceReferenceInfo nextReference : myContext.newTerser().getAllResourceReferences(nextResource)) {
// We're interested in any references directly to the placeholder ID, but also
// references that have a resource target that has the placeholder ID.
String nextReferenceId = nextReference.getResourceReference().getReferenceElement().getValue();
if (isBlank(nextReferenceId) && nextReference.getResourceReference().getResource() != null) {
nextReferenceId = nextReference.getResourceReference().getResource().getIdElement().getValue();
}
if (entryUrl.equals(nextReferenceId)) {
nextReference.getResourceReference().setReference(existingUuid);
nextReference.getResourceReference().setResource(null);
}
}
}
}
}
}
}

View File

@ -1105,6 +1105,65 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
}
@Test
public void testTransactionWithDuplicateConditionalCreatesWithResourceLinkReference() {
Bundle request = new Bundle();
request.setType(BundleType.TRANSACTION);
Practitioner p = new Practitioner();
p.setId(IdType.newRandomUuid());
p.addIdentifier().setSystem("http://foo").setValue("bar");
request.addEntry()
.setFullUrl(p.getId())
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Practitioner/")
.setIfNoneExist("Practitioner?identifier=http://foo|bar");
Observation o = new Observation();
o.setId(IdType.newRandomUuid());
o.getPerformerFirstRep().setResource(p);
request.addEntry()
.setFullUrl(o.getId())
.setResource(o)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Observation/");
p = new Practitioner();
p.setId(IdType.newRandomUuid());
p.addIdentifier().setSystem("http://foo").setValue("bar");
request.addEntry()
.setFullUrl(p.getId())
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Practitioner/")
.setIfNoneExist("Practitioner?identifier=http://foo|bar");
o = new Observation();
o.setId(IdType.newRandomUuid());
o.getPerformerFirstRep().setResource(p);
request.addEntry()
.setFullUrl(o.getId())
.setResource(o)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Observation/");
Bundle response = mySystemDao.transaction(null, request);
ourLog.info("Response:\n{}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(response));
List<String> responseTypes = response
.getEntry()
.stream()
.map(t -> new IdType(t.getResponse().getLocation()).getResourceType())
.collect(Collectors.toList());
assertThat(responseTypes.toString(), responseTypes, contains("Practitioner", "Observation", "Observation"));
}
@Test
public void testTransactionWithDuplicateConditionalUpdates() {
Bundle request = new Bundle();

View File

@ -157,34 +157,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
}
@Test
public void testManualPagingLinkOffsetDoesntReturnBeyondEnd() {
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(10, 1000));
for (int i = 0; i < 50; i++) {
Organization o = new Organization();
o.setId("O" + i);
o.setName("O" + i);
ourClient.update().resource(o).execute().getId().toUnqualifiedVersionless();
}
Bundle output = ourClient
.search()
.forResource("Organization")
.count(3)
.returnBundle(Bundle.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
String linkNext = output.getLink("next").getUrl();
linkNext = linkNext.replaceAll("_getpagesoffset=[0-9]+", "_getpagesoffset=3300");
assertThat(linkNext, containsString("_getpagesoffset=3300"));
Bundle nextPageBundle = ourClient.loadPage().byUrl(linkNext).andReturnBundle(Bundle.class).execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(nextPageBundle));
assertEquals(null, nextPageBundle.getLink("next"));
}
@Test
public void testSearchLinksWorkWithIncludes() {
@ -228,6 +200,36 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
}
@Test
@Ignore
public void testManualPagingLinkOffsetDoesntReturnBeyondEnd() {
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(10, 1000));
for (int i = 0; i < 50; i++) {
Organization o = new Organization();
o.setId("O" + i);
o.setName("O" + i);
ourClient.update().resource(o).execute().getId().toUnqualifiedVersionless();
}
Bundle output = ourClient
.search()
.forResource("Organization")
.count(3)
.returnBundle(Bundle.class)
.execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
String linkNext = output.getLink("next").getUrl();
linkNext = linkNext.replaceAll("_getpagesoffset=[0-9]+", "_getpagesoffset=3300");
assertThat(linkNext, containsString("_getpagesoffset=3300"));
Bundle nextPageBundle = ourClient.loadPage().byUrl(linkNext).andReturnBundle(Bundle.class).execute();
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(nextPageBundle));
assertEquals(null, nextPageBundle.getLink("next"));
}
@Test
public void testSearchFetchPageBeyondEnd() {
for (int i = 0; i < 10; i++) {