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.api.server.storage.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
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.HasParam;
|
||||||
import ca.uhn.fhir.rest.param.NumberParam;
|
import ca.uhn.fhir.rest.param.NumberParam;
|
||||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||||
|
@ -944,30 +945,46 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
||||||
throw new InvalidRequestException("Invalid resource type: " + targetResourceType);
|
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();
|
ArrayList<IQueryParameterType> orValues = Lists.newArrayList();
|
||||||
|
|
||||||
for (IQueryParameterOr<IQueryParameterType> next : parsedParam.getValuesAsQueryTokens()) {
|
if (paramName.startsWith("_has:")) {
|
||||||
orValues.addAll(next.getValuesAsQueryTokens());
|
|
||||||
|
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.
|
//Handle internal chain inside the has.
|
||||||
if (parameterName.contains(".")) {
|
if (parameterName.contains(".")) {
|
||||||
String chainedPartOfParameter = getChainedPart(parameterName);
|
String chainedPartOfParameter = getChainedPart(parameterName);
|
||||||
|
|
|
@ -876,6 +876,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.addIdentifier().setSystem("urn:system").setValue("NOLINK");
|
obs.addIdentifier().setSystem("urn:system").setValue("NOLINK");
|
||||||
obs.setDevice(new Reference(devId));
|
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);
|
myObservationDao.create(obs, mySrd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -896,6 +901,51 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(params)), empty());
|
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
|
@Test
|
||||||
public void testHasParameterChained() {
|
public void testHasParameterChained() {
|
||||||
IIdType pid0;
|
IIdType pid0;
|
||||||
|
|
Loading…
Reference in New Issue