Add changelog
This commit is contained in:
parent
71ed25b77c
commit
fe98162616
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 2876
|
||||||
|
jira: SMILE-1153
|
||||||
|
title: "Fixed a bug in transaction bundle processing, specifically for bundles which contained both a conditional create, and a resource which relied on this conditional create as a reference.
|
||||||
|
This would cause the referring resource to generate a contained resource instead of appropriately referencing the existing patient."
|
|
@ -94,6 +94,7 @@ import com.google.common.collect.Sets;
|
||||||
import com.google.common.hash.HashFunction;
|
import com.google.common.hash.HashFunction;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
@ -1162,10 +1163,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
validateResourceForStorage((T) theResource, entity);
|
validateResourceForStorage((T) theResource, entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String resourceType = myContext.getResourceType(theResource);
|
if (!StringUtils.isBlank(entity.getResourceType())) {
|
||||||
if (isNotBlank(entity.getResourceType()) && !entity.getResourceType().equals(resourceType)) {
|
validateIncomingResourceTypeMatchesExisting(theResource, entity);
|
||||||
throw new UnprocessableEntityException(
|
|
||||||
"Existing resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] is of type[" + entity.getResourceType() + "] - Cannot update with [" + resourceType + "]");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1206,6 +1205,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
if (thePerformIndexing || ((ResourceTable) theEntity).getVersion() == 1) {
|
if (thePerformIndexing || ((ResourceTable) theEntity).getVersion() == 1) {
|
||||||
|
|
||||||
newParams = new ResourceIndexedSearchParams();
|
newParams = new ResourceIndexedSearchParams();
|
||||||
|
|
||||||
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, theTransactionDetails, entity, theResource, existingParams, theRequest, thePerformIndexing);
|
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, theTransactionDetails, entity, theResource, existingParams, theRequest, thePerformIndexing);
|
||||||
|
|
||||||
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, true);
|
changed = populateResourceIntoEntity(theTransactionDetails, theRequest, theResource, entity, true);
|
||||||
|
@ -1415,6 +1415,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateIncomingResourceTypeMatchesExisting(IBaseResource theResource, ResourceTable entity) {
|
||||||
|
String resourceType = myContext.getResourceType(theResource);
|
||||||
|
if (!resourceType.equals(entity.getResourceType())) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
"Existing resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] is of type[" + entity.getResourceType() + "] - Cannot update with [" + resourceType + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
||||||
IBasePersistedResource theEntity, IIdType theResourceId, IBaseResource theOldResource, TransactionDetails theTransactionDetails) {
|
IBasePersistedResource theEntity, IIdType theResourceId, IBaseResource theOldResource, TransactionDetails theTransactionDetails) {
|
||||||
|
|
|
@ -262,7 +262,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
entity.setCreatedByMatchUrl(theIfNoneExist);
|
entity.setCreatedByMatchUrl(theIfNoneExist);
|
||||||
entity.setVersion(1);
|
entity.setVersion(1);
|
||||||
|
|
||||||
//FIXME GGG is this possibly where we are fetching the thing?
|
|
||||||
if (isNotBlank(theIfNoneExist)) {
|
if (isNotBlank(theIfNoneExist)) {
|
||||||
Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theIfNoneExist, myResourceType, theTransactionDetails, theRequest);
|
Set<ResourcePersistentId> match = myMatchResourceUrlService.processMatchUrl(theIfNoneExist, myResourceType, theTransactionDetails, theRequest);
|
||||||
if (match.size() > 1) {
|
if (match.size() > 1) {
|
||||||
|
@ -279,7 +278,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
};
|
};
|
||||||
|
|
||||||
Supplier<IIdType> idSupplier = () -> {
|
Supplier<IIdType> idSupplier = () -> {
|
||||||
return myTxTemplate.execute(tx -> {
|
myTxTemplate.execute(tx -> {
|
||||||
IIdType retVal = myIdHelperService.translatePidIdToForcedId(myFhirContext, myResourceName, pid);
|
IIdType retVal = myIdHelperService.translatePidIdToForcedId(myFhirContext, myResourceName, pid);
|
||||||
if (!retVal.hasVersionIdPart()) {
|
if (!retVal.hasVersionIdPart()) {
|
||||||
IIdType idWithVersion = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION, pid.getIdAsLong());
|
IIdType idWithVersion = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.RESOURCE_CONDITIONAL_CREATE_VERSION, pid.getIdAsLong());
|
||||||
|
|
|
@ -791,6 +791,8 @@ public abstract class BaseTransactionProcessor {
|
||||||
String matchUrl = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
|
String matchUrl = myVersionAdapter.getEntryRequestIfNoneExist(nextReqEntry);
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.create(res, matchUrl, false, theTransactionDetails, theRequest);
|
outcome = resourceDao.create(res, matchUrl, false, theTransactionDetails, theRequest);
|
||||||
|
// IS THIS THE MAGIC SAUCE?
|
||||||
|
res.setId(outcome.getId());
|
||||||
if (nextResourceId != null) {
|
if (nextResourceId != null) {
|
||||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequest);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequest);
|
||||||
}
|
}
|
||||||
|
@ -865,7 +867,6 @@ public abstract class BaseTransactionProcessor {
|
||||||
matchUrl = parts.getResourceType();
|
matchUrl = parts.getResourceType();
|
||||||
}
|
}
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
//TODO FIXME GGG This update call comes back with a contained resource.
|
|
||||||
outcome = resourceDao.update(res, matchUrl, false, false, theRequest, theTransactionDetails);
|
outcome = resourceDao.update(res, matchUrl, false, false, theRequest, theTransactionDetails);
|
||||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||||
|
|
|
@ -129,6 +129,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
partitionId = RequestPartitionId.allPartitions();
|
partitionId = RequestPartitionId.allPartitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//THIS IS THE NEW SPOT
|
||||||
mySearchParamExtractorService.extractFromResource(partitionId, theRequest, theParams, theEntity, theResource, theTransactionDetails, theFailOnInvalidReference);
|
mySearchParamExtractorService.extractFromResource(partitionId, theRequest, theParams, theEntity, theResource, theTransactionDetails, theFailOnInvalidReference);
|
||||||
|
|
||||||
Set<Map.Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
|
Set<Map.Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
|
||||||
|
|
|
@ -78,6 +78,7 @@ import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
@ -964,6 +965,17 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to determine if a set of SPs for a resource uses a resolve as part of its fhir path.
|
||||||
|
*/
|
||||||
|
private boolean anySearchParameterUsesResolve(Collection<RuntimeSearchParam> searchParams, RestSearchParameterTypeEnum theSearchParamType) {
|
||||||
|
return searchParams.stream()
|
||||||
|
.filter(param -> param.getParamType() != theSearchParamType)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.anyMatch(param -> param.getPath().contains("resolve"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HAPI FHIR Reference objects (e.g. {@link org.hl7.fhir.r4.model.Reference}) can hold references either by text
|
* HAPI FHIR Reference objects (e.g. {@link org.hl7.fhir.r4.model.Reference}) can hold references either by text
|
||||||
* (e.g. "#3") or by resource (e.g. "new Reference(patientInstance)"). The FHIRPath evaluator only understands the
|
* (e.g. "#3") or by resource (e.g. "new Reference(patientInstance)"). The FHIRPath evaluator only understands the
|
||||||
|
@ -974,17 +986,12 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
* if we think there's actually a chance
|
* if we think there's actually a chance
|
||||||
*/
|
*/
|
||||||
private void cleanUpContainedResourceReferences(IBaseResource theResource, RestSearchParameterTypeEnum theSearchParamType, Collection<RuntimeSearchParam> searchParams) {
|
private void cleanUpContainedResourceReferences(IBaseResource theResource, RestSearchParameterTypeEnum theSearchParamType, Collection<RuntimeSearchParam> searchParams) {
|
||||||
boolean havePathWithResolveExpression = myModelConfig.isIndexOnContainedResources();
|
boolean havePathWithResolveExpression =
|
||||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
myModelConfig.isIndexOnContainedResources()
|
||||||
if (nextSpDef.getParamType() != theSearchParamType) {
|
|| anySearchParameterUsesResolve(searchParams, theSearchParamType);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (defaultString(nextSpDef.getPath()).contains("resolve")) {
|
|
||||||
havePathWithResolveExpression = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (havePathWithResolveExpression) {
|
if (havePathWithResolveExpression) {
|
||||||
|
//FIXME GGG/JA: At this point, if the Task.basedOn.reference.resource does _not_ have an ID, we will attempt to contain it internally.
|
||||||
myContext.newTerser().containResources(theResource, FhirTerser.OptionsEnum.MODIFY_RESOURCE, FhirTerser.OptionsEnum.STORE_AND_REUSE_RESULTS);
|
myContext.newTerser().containResources(theResource, FhirTerser.OptionsEnum.MODIFY_RESOURCE, FhirTerser.OptionsEnum.STORE_AND_REUSE_RESULTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue