Support double _has expressions (#1939)
* Support nested _has queries * Add changelog
This commit is contained in:
parent
6825d2fcf0
commit
e65c264927
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 1939
|
||||
title: "The JPA server is now able to support _has queries where the linked search expression on the right hand side of the
|
||||
_has parameter is a second _has query."
|
|
@ -62,6 +62,7 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.HasOrListParam;
|
||||
import ca.uhn.fhir.rest.param.HasParam;
|
||||
import ca.uhn.fhir.rest.param.NumberParam;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
|
@ -944,30 +945,46 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
throw new InvalidRequestException("Invalid resource type: " + targetResourceType);
|
||||
}
|
||||
|
||||
//Ensure that the name of the search param
|
||||
// (e.g. the `code` in Patient?_has:Observation:subject:code=sys|val)
|
||||
// exists on the target resource type.
|
||||
RuntimeSearchParam owningParameterDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramName);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + parameterName);
|
||||
}
|
||||
|
||||
//Ensure that the name of the back-referenced search param on the target (e.g. the `subject` in Patient?_has:Observation:subject:code=sys|val)
|
||||
//exists on the target resource.
|
||||
owningParameterDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramReference);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + paramReference);
|
||||
}
|
||||
|
||||
RuntimeSearchParam paramDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramName);
|
||||
|
||||
IQueryParameterAnd<IQueryParameterOr<IQueryParameterType>> parsedParam = (IQueryParameterAnd<IQueryParameterOr<IQueryParameterType>>) ParameterUtil.parseQueryParams(myContext, paramDef, paramName, parameters);
|
||||
|
||||
ArrayList<IQueryParameterType> orValues = Lists.newArrayList();
|
||||
|
||||
for (IQueryParameterOr<IQueryParameterType> next : parsedParam.getValuesAsQueryTokens()) {
|
||||
orValues.addAll(next.getValuesAsQueryTokens());
|
||||
if (paramName.startsWith("_has:")) {
|
||||
|
||||
ourLog.trace("Handing double _has query: {}", paramName);
|
||||
|
||||
String qualifier = paramName.substring(4);
|
||||
paramName = Constants.PARAM_HAS;
|
||||
for (IQueryParameterType next : nextOrList) {
|
||||
HasParam nextHasParam = new HasParam();
|
||||
nextHasParam.setValueAsQueryToken(myContext, Constants.PARAM_HAS, qualifier, next.getValueAsQueryToken(myContext));
|
||||
orValues.add(nextHasParam);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//Ensure that the name of the search param
|
||||
// (e.g. the `code` in Patient?_has:Observation:subject:code=sys|val)
|
||||
// exists on the target resource type.
|
||||
RuntimeSearchParam owningParameterDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramName);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + parameterName);
|
||||
}
|
||||
|
||||
//Ensure that the name of the back-referenced search param on the target (e.g. the `subject` in Patient?_has:Observation:subject:code=sys|val)
|
||||
//exists on the target resource.
|
||||
owningParameterDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramReference);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + paramReference);
|
||||
}
|
||||
|
||||
RuntimeSearchParam paramDef = mySearchParamRegistry.getSearchParamByName(targetResourceDefinition, paramName);
|
||||
IQueryParameterAnd<IQueryParameterOr<IQueryParameterType>> parsedParam = (IQueryParameterAnd<IQueryParameterOr<IQueryParameterType>>) ParameterUtil.parseQueryParams(myContext, paramDef, paramName, parameters);
|
||||
|
||||
for (IQueryParameterOr<IQueryParameterType> next : parsedParam.getValuesAsQueryTokens()) {
|
||||
orValues.addAll(next.getValuesAsQueryTokens());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Handle internal chain inside the has.
|
||||
if (parameterName.contains(".")) {
|
||||
String chainedPartOfParameter = getChainedPart(parameterName);
|
||||
|
|
|
@ -876,6 +876,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("NOLINK");
|
||||
obs.setDevice(new Reference(devId));
|
||||
IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
DiagnosticReport dr = new DiagnosticReport();
|
||||
dr.addResult().setReference(obsId.getValue());
|
||||
dr.setStatus(DiagnosticReport.DiagnosticReportStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd);
|
||||
}
|
||||
|
||||
|
@ -896,6 +901,51 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(params)), empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasParameterDouble() {
|
||||
// Matching
|
||||
IIdType pid0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("00");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
pid0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("NOLINK");
|
||||
obs.setSubject(new Reference(pid0));
|
||||
IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
DiagnosticReport dr = new DiagnosticReport();
|
||||
dr.addResult().setReference(obsId.getValue());
|
||||
dr.setStatus(DiagnosticReport.DiagnosticReportStatus.FINAL);
|
||||
myDiagnosticReportDao.create(dr, mySrd);
|
||||
}
|
||||
|
||||
// Matching
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
IIdType pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.addIdentifier().setSystem("urn:system").setValue("NOLINK");
|
||||
obs.setSubject(new Reference(pid1));
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
}
|
||||
|
||||
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||
|
||||
// Double _has
|
||||
params = new SearchParameterMap();
|
||||
params.add("_has", new HasParam("Observation", "subject", "_has:DiagnosticReport:result:status", "final"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(params)), containsInAnyOrder(pid0.getValue()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHasParameterChained() {
|
||||
IIdType pid0;
|
||||
|
|
Loading…
Reference in New Issue