issue-2901 checkin to test

This commit is contained in:
leif stawnyczy 2021-08-30 10:29:59 -04:00
parent 99cd865174
commit e7c6ce920d
4 changed files with 205 additions and 19 deletions

View File

@ -1206,7 +1206,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
if (thePerformIndexing || ((ResourceTable) theEntity).getVersion() == 1) {
newParams = new ResourceIndexedSearchParams();
//FIX ME GGG: This is where the placeholder references end up getting created, deeeeeep down the stakc.
//FIXME GGG: This is where the placeholder references end up getting created, deeeeeep down the stakc.
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, theTransactionDetails, entity, theResource, existingParams, theRequest, thePerformIndexing);
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, true);

View File

@ -61,6 +61,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.rest.server.exceptions.PayloadTooLargeException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding;
@ -403,7 +404,8 @@ public abstract class BaseTransactionProcessor {
throw new InvalidRequestException("Unable to process transaction where incoming Bundle.type = " + transactionType);
}
int numberOfEntries = myVersionAdapter.getEntries(theRequest).size();
List<IBase> requestEntries = myVersionAdapter.getEntries(theRequest);
int numberOfEntries = requestEntries.size();
if (myDaoConfig.getMaximumTransactionBundleSize() != null && numberOfEntries > myDaoConfig.getMaximumTransactionBundleSize()) {
throw new PayloadTooLargeException("Transaction Bundle Too large. Transaction bundle contains " +
@ -416,7 +418,27 @@ public abstract class BaseTransactionProcessor {
final TransactionDetails transactionDetails = new TransactionDetails();
final StopWatch transactionStopWatch = new StopWatch();
List<IBase> requestEntries = myVersionAdapter.getEntries(theRequest);
//TODO
// Create Autoreference Placeholders is enabled
// we should create any sub reference that doesn't already exist
// if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {
// List<IBase> referencesToCreate = new ArrayList<>();
// for (IBase entry : requestEntries) {
// IBaseResource resource = myVersionAdapter.getResource(entry);
// Set<IBaseReference> referencesToAutoVersion = BaseStorageDao.extractReferencesToAutoVersion(myContext,
// myModelConfig,
// resource);
// for (IBaseReference subReference : referencesToAutoVersion) {
// // doesn't exist - add it to the entries to be created
// org.hl7.fhir.r4.model.Bundle.BundleEntryRequestComponent req = new org.hl7.fhir.r4.model.Bundle.BundleEntryRequestComponent();
// req.setMethod(org.hl7.fhir.r4.model.Bundle.HTTPVerb.PUT);
// req.setUrl(subReference.getReferenceElement().getValue());
//// req.setIfNoneExist(); //TODO - look at conditional creates to see how this works
// referencesToCreate.add(req); // adding the request should add it to theIdToPersistence map later
// }
// }
// requestEntries.addAll(referencesToCreate);
// }
// Do all entries have a verb?
for (int i = 0; i < numberOfEntries; i++) {
@ -488,6 +510,9 @@ public abstract class BaseTransactionProcessor {
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_INFO, params);
}
//FIXME - remove before committing
ourLog.info(myContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(response));
return response;
}
@ -614,13 +639,22 @@ public abstract class BaseTransactionProcessor {
theEntries, theTransactionStopWatch);
theTransactionStopWatch.startTask("Commit writes to database");
ourLog.info("Retval has " + retVal.values().size());
return retVal;
};
Map<IBase, IIdType> entriesToProcess;
try {
entriesToProcess = myHapiTransactionService.execute(theRequestDetails, theTransactionDetails, txCallback);
} finally {
}
catch (Exception ex) {
//FIXME - remove
ourLog.info("FindME");
ourLog.info(ex.getLocalizedMessage());
ex.printStackTrace();
entriesToProcess = new HashMap<>();
}
finally {
if (writeOperationsDetails != null) {
HookParams params = new HookParams()
.add(TransactionDetails.class, theTransactionDetails)
@ -1198,14 +1232,24 @@ public abstract class BaseTransactionProcessor {
IBaseResource nextResource = nextOutcome.getResource();
//TODO - should we add the autoversioned resources to our idtoPersistedoutcomes here?
// idToPersistedOutcomes has no entry for them at this point (if they were not in the
// top level bundle)
// should we just add no-op values to the map (since they are all going to be gets)?
// for (IBaseReference autoVersionRef : referencesToAutoVersion) {
// IBaseResource baseResource = myVersionAdapter.getResource(autoVersionRef);
// IFhirResourceDao dao = getDaoOrThrowException(baseResource.getClass());
//
// theIdToPersistedOutcome.put(baseResource.getIdElement(), );
// IFhirResourceDao dao = myDaoRegistry.getResourceDao(autoVersionRef.getReferenceElement().getResourceType());
// IBaseResource baseResource;
// try {
// baseResource = dao.read(autoVersionRef.getReferenceElement());
// } catch (ResourceNotFoundException ex) {
// not found
// baseResource =
// DaoMethodOutcome outcome = new DaoMethodOutcome();
// outcome.setResource(baseResource);
// outcome.setNop(true); // we are just reading it
// theIdToPersistedOutcome.put(autoVersionRef.getReferenceElement(), outcome);
// }
// }
resolveReferencesThenSaveAndIndexResource(theRequest, theTransactionDetails,
theIdSubstitutions, theIdToPersistedOutcome,
entriesToProcess, nonUpdatedEntities,
@ -1263,8 +1307,27 @@ public abstract class BaseTransactionProcessor {
throw new InvalidRequestException("Unable to satisfy placeholder ID " + nextId.getValue() + " found in element named '" + nextRef.getName() + "' within resource of type: " + nextResource.getIdElement().getResourceType());
} else {
if (theReferencesToAutoVersion.contains(resourceReference)) {
//TODO - if we get here and there's still no
// value in theIdToPersistedOutcome map
// we should throw an invalid request exception
DaoMethodOutcome outcome = theIdToPersistedOutcome.get(nextId);
if (!outcome.isNop() && !Boolean.TRUE.equals(outcome.getCreated())) {
if (outcome == null) {
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceReference.getReferenceElement().getResourceType());
IBaseResource baseResource;
try {
// DB hit
baseResource = dao.read(resourceReference.getReferenceElement());
} catch (ResourceNotFoundException ex) {
// does not exist - add the history/1
String val = resourceReference.getReferenceElement().getValue();
resourceReference.getReferenceElement().setValue(val + "/_history/1");
}
}
if (outcome != null && !outcome.isNop() && !Boolean.TRUE.equals(outcome.getCreated())) {
addRollbackReferenceRestore(theTransactionDetails, resourceReference);
resourceReference.setReference(nextId.getValue());
resourceReference.setResource(null);

View File

@ -1,17 +1,20 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.BundleBuilder;
import ca.uhn.fhir.util.HapiExtensions;
import com.google.common.collect.Sets;
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.Extension;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Identifier;
@ -21,6 +24,8 @@ import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Task;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
@ -565,6 +570,61 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
}
@Test
public void testAutocreatePlaceholderTest() {
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
Observation obs = new Observation();
obs.setId("Observation/DEF");
Reference patientRef = new Reference("Patient/RED");
obs.setSubject(patientRef);
BundleBuilder builder = new BundleBuilder(myFhirCtx);
builder.addTransactionUpdateEntry(obs);
mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
Patient returned = myPatientDao.read(patientRef.getReferenceElement());
Assertions.assertTrue(returned != null);
}
@Test
public void testAutocreatePlaceholderWithTargetExistingAlreadyTest() {
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
myModelConfig.setAutoVersionReferenceAtPaths("Observation.subject");
String patientId = "Patient/RED";
// create
Patient patient = new Patient();
// patient.setId(patientId);
patient.setIdElement(new IdType(patientId));
// patient.setActive(true);
myPatientDao.update(patient);
// update
patient.setActive(true);
myPatientDao.update(patient);
// observation (with version 2)
Observation obs = new Observation();
obs.setId("Observation/DEF");
Reference patientRef = new Reference(patientId);
obs.setSubject(patientRef);
BundleBuilder builder = new BundleBuilder(myFhirCtx);
builder.addTransactionUpdateEntry(obs);
Bundle transaction = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
Patient returned = myPatientDao.read(patientRef.getReferenceElement());
Assertions.assertTrue(returned != null);
Assertions.assertTrue(returned.getActive());
Observation retObservation = myObservationDao.read(obs.getIdElement());
Assertions.assertTrue(retObservation != null);
}
// always work with the put
// conditional create (replace put with conditional create?)
}

View File

@ -1,12 +1,10 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.ParserOptions;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.provider.r4.ResourceProviderR4Test;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.TokenParam;
@ -24,10 +22,12 @@ import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Task;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.InputStreamReader;
import java.sql.Ref;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
@ -298,6 +298,53 @@ public class FhirResourceDaoR4VersionedReferenceTest extends BaseJpaR4Test {
assertEquals(patientIdString, observation.getSubject().getReference());
}
@Test
public void testInsertVersionedReferenceAtPathUsingTransaction() {
// myFhirCtx.getParserOptions().setStripVersionsFromReferences(false);
// myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
myModelConfig.setAutoVersionReferenceAtPaths("Observation.subject");
Patient p = new Patient();
p.setActive(true);
IIdType patientId = myPatientDao.create(p).getId().toUnqualified();
assertEquals("1", patientId.getVersionIdPart());
assertEquals(null, patientId.getBaseUrl());
String patientIdString = patientId.getValue();
// Create - put an unversioned reference in the subject
Observation observation = new Observation();
observation.getSubject().setReference(patientId.toVersionless().getValue());
BundleBuilder builder = new BundleBuilder(myFhirCtx);
builder.addTransactionUpdateEntry(observation);
Bundle transaction = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
Observation ret = myObservationDao.read(observation.getIdElement());
Assertions.assertTrue(ret != null);
// Read back and verify that reference is now versioned
// observation = myObservationDao.read(observationId);
// assertEquals(patientIdString, observation.getSubject().getReference());
//
// myCaptureQueriesListener.clear();
//
// // Update - put an unversioned reference in the subject
// observation = new Observation();
// observation.setId(observationId);
// observation.addIdentifier().setSystem("http://foo").setValue("bar");
// observation.getSubject().setReference(patientId.toVersionless().getValue());
// myObservationDao.update(observation);
//
// // Make sure we're not introducing any extra DB operations
// assertEquals(5, myCaptureQueriesListener.logSelectQueries().size());
//
// // Read back and verify that reference is now versioned
// observation = myObservationDao.read(observationId);
// assertEquals(patientIdString, observation.getSubject().getReference());
}
@Test
public void testInsertVersionedReferenceAtPath_InTransaction_SourceAndTargetBothCreated() {
myFhirCtx.getParserOptions().setStripVersionsFromReferences(false);
@ -827,27 +874,43 @@ public class FhirResourceDaoR4VersionedReferenceTest extends BaseJpaR4Test {
assertThat(versionedPatientReference, is(equalTo("Patient/RED/_history/1")));
}
@Test
@DisplayName("GH-2901 Test no NPE is thrown on autoversioned references")
public void testNoNpeMinimal() {
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(false);
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
myModelConfig.setAutoVersionReferenceAtPaths("Observation.subject");
// ParserOptions options = new ParserOptions();
// options.setDontStripVersionsFromReferencesAtPaths("Observation.subject");
// myFhirCtx.setParserOptions(options);
Patient patient = new Patient();
patient.setId("Patient/RED");
myPatientDao.update(patient);
Observation obs = new Observation();
obs.setId("Observation/DEF");
obs.setSubject(new Reference("Patient/RED"));
Reference patientRef = new Reference("Patient/RED");
obs.setSubject(patientRef);
BundleBuilder builder = new BundleBuilder(myFhirCtx);
builder.addTransactionUpdateEntry(obs);
mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
//1 make sure this test throws the InvalidRequestException (make separate test for this)
//2 add a test for patient created before bundle and then process observation with reference to patient (null check for outcome)
//3
// Assertions.assertThrows()
try {
Bundle returnedTr = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
System.out.println("returned " + returnedTr.getEntry().size());
Observation obRet = myObservationDao.read(obs.getIdElement());
System.out.println("HELLO " + obRet.getId());
Patient returned = myPatientDao.read(patientRef.getReferenceElement());
Assertions.assertTrue(returned != null);
}
catch (Exception ex) {
System.out.println("TEST " + ex.getLocalizedMessage());
Assertions.assertTrue(ex == null);
}
}