Fix issue with partitioning in patient ID compartment mode (#2810)
* Fix issue with partitioning in patient ID compartment mode * Add changelog
This commit is contained in:
parent
9f77c57e5a
commit
6af022062f
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2810
|
||||
title: "An issue in the FHIRPath evaluator prevented Encounters from being stored when using the new
|
||||
PatientIdPartitionInterceptor. This has been corrected."
|
|
@ -23,7 +23,6 @@ package ca.uhn.fhir.jpa.interceptor;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.fhirpath.IFhirPath;
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
|
@ -31,6 +30,7 @@ import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
|
@ -45,7 +45,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import javax.annotation.Nonnull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
@ -62,6 +61,9 @@ public class PatientIdPartitionInterceptor {
|
|||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -72,9 +74,10 @@ public class PatientIdPartitionInterceptor {
|
|||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public PatientIdPartitionInterceptor(FhirContext theFhirContext) {
|
||||
public PatientIdPartitionInterceptor(FhirContext theFhirContext, ISearchParamExtractor theSearchParamExtractor) {
|
||||
this();
|
||||
myFhirContext = theFhirContext;
|
||||
mySearchParamExtractor = theSearchParamExtractor;
|
||||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
|
||||
|
@ -92,14 +95,15 @@ public class PatientIdPartitionInterceptor {
|
|||
throw new MethodNotAllowedException("Patient resource IDs must be client-assigned in patient compartment mode");
|
||||
}
|
||||
} else {
|
||||
IFhirPath fhirPath = myFhirContext.newFhirPath();
|
||||
compartmentIdentity = compartmentSps
|
||||
.stream()
|
||||
.flatMap(param -> Arrays.stream(BaseSearchParamExtractor.splitPathsR4(param.getPath())))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(path -> fhirPath.evaluateFirst(theResource, path, IBaseReference.class))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.map(path -> mySearchParamExtractor.getPathValueExtractor(theResource, path).get())
|
||||
.filter(t -> !t.isEmpty())
|
||||
.map(t -> t.get(0))
|
||||
.filter(t -> t instanceof IBaseReference)
|
||||
.map(t -> (IBaseReference) t)
|
||||
.map(t -> t.getReferenceElement().getValue())
|
||||
.map(t -> new IdType(t).getIdPart())
|
||||
.filter(StringUtils::isNotBlank)
|
||||
|
|
|
@ -5,11 +5,13 @@ import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4SystemTest;
|
|||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
|
@ -18,6 +20,7 @@ import org.hl7.fhir.r4.model.Patient;
|
|||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
@ -31,9 +34,12 @@ public class PatientIdPartitionInterceptorTest extends BaseJpaR4SystemTest {
|
|||
private PatientIdPartitionInterceptor mySvc;
|
||||
private ForceOffsetSearchModeInterceptor myForceOffsetSearchModeInterceptor;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
mySvc = new PatientIdPartitionInterceptor(myFhirCtx);
|
||||
mySvc = new PatientIdPartitionInterceptor(myFhirCtx, mySearchParamExtractor);
|
||||
myForceOffsetSearchModeInterceptor = new ForceOffsetSearchModeInterceptor();
|
||||
|
||||
myInterceptorRegistry.registerInterceptor(mySvc);
|
||||
|
@ -95,6 +101,24 @@ public class PatientIdPartitionInterceptorTest extends BaseJpaR4SystemTest {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Encounter.subject has a FHIRPath expression with a resolve() on it
|
||||
*/
|
||||
@Test
|
||||
public void testCreateEncounter_ValidMembershipInCompartment() {
|
||||
createPatientA();
|
||||
|
||||
Encounter encounter = new Encounter();
|
||||
encounter.getSubject().setReference("Patient/A");
|
||||
Long id = myEncounterDao.create(encounter).getId().getIdPartAsLong();
|
||||
|
||||
runInTransaction(() -> {
|
||||
ResourceTable observation = myResourceTableDao.findById(id).orElseThrow(() -> new IllegalArgumentException());
|
||||
assertEquals("Encounter", observation.getResourceType());
|
||||
assertEquals(65, observation.getPartitionId().getPartitionId());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Type is not in the patient compartment
|
||||
*/
|
||||
|
|
|
@ -534,8 +534,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
return values;
|
||||
}
|
||||
|
||||
protected abstract IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath);
|
||||
|
||||
protected FhirContext getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -81,6 +82,8 @@ public interface ISearchParamExtractor {
|
|||
|
||||
String getDisplayTextForCoding(IBase theValue);
|
||||
|
||||
BaseSearchParamExtractor.IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath);
|
||||
|
||||
List<IBase> getCodingsFromCodeableConcept(IBase theValue);
|
||||
|
||||
String getDisplayTextFromCodeableConcept(IBase theValue);
|
||||
|
|
|
@ -48,7 +48,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
public IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
return () -> {
|
||||
String path = theSinglePath;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
public IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
return () -> {
|
||||
List<IBase> values = new ArrayList<>();
|
||||
List<Base> allValues = myFhirPathEngine.evaluate((Base) theResource, theSinglePath);
|
||||
|
|
|
@ -68,7 +68,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
public IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {
|
||||
return () -> {
|
||||
List<Base> allValues = myFhirPathEngine.evaluate((Base) theResource, theSinglePath);
|
||||
return (List<IBase>) new ArrayList<IBase>(allValues);
|
||||
|
|
|
@ -78,7 +78,7 @@ public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IValueExtractor getPathValueExtractor(IBaseResource theResource, String nextPath) {
|
||||
public IValueExtractor getPathValueExtractor(IBaseResource theResource, String nextPath) {
|
||||
return () -> myFhirPathEngine.evaluate((Base) theResource, nextPath);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue