Add chain on _type parameter
This commit is contained in:
parent
14316147c5
commit
0ac434ea5d
|
@ -260,6 +260,7 @@ public class Constants {
|
|||
*/
|
||||
public static final String EXT_META_SOURCE = "http://hapifhir.io/fhir/StructureDefinition/resource-meta-source";
|
||||
public static final String PARAM_FHIRPATH = "_fhirpath";
|
||||
public static final String PARAM_TYPE = "_type";
|
||||
|
||||
static {
|
||||
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
||||
|
|
|
@ -135,3 +135,6 @@ ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateValueSetUrl=Can no
|
|||
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
||||
|
||||
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
|
||||
|
||||
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidTargetTypeForChain=Resource type "{0}" is not a valid target type for reference search parameter: {1}
|
||||
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidResourceType=Invalid/unsupported resource type: "{0}"
|
||||
|
|
|
@ -20,14 +20,31 @@ package ca.uhn.fhir.jpa.dao.predicate;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.ResourceMetaParams;
|
||||
|
@ -47,22 +64,36 @@ import ca.uhn.fhir.rest.param.*;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.persistence.criteria.*;
|
||||
import java.util.*;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
|
@ -273,20 +304,43 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
}
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theReferenceParam.getResourceType());
|
||||
resourceTypes = new ArrayList<>(1);
|
||||
resourceTypes.add(resDef.getImplementingClass());
|
||||
} catch (DataFormatException e) {
|
||||
throw new InvalidRequestException("Invalid resource type: " + theReferenceParam.getResourceType());
|
||||
throw newInvalidResourceTypeException(theReferenceParam.getResourceType());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Handle chain on _type
|
||||
String chain = theReferenceParam.getChain();
|
||||
if (Constants.PARAM_TYPE.equals(chain)) {
|
||||
String typeValue = theReferenceParam.getValue();
|
||||
|
||||
Class<? extends IBaseResource> wantedType;
|
||||
try {
|
||||
wantedType = myContext.getResourceDefinition(typeValue).getImplementingClass();
|
||||
} catch (DataFormatException e) {
|
||||
throw newInvalidResourceTypeException(typeValue);
|
||||
}
|
||||
if (!resourceTypes.contains(wantedType)) {
|
||||
String searchParamName = theResourceName + ":" + theParamName;
|
||||
String msg = myContext.getLocalizer().getMessage(PredicateBuilderReference.class, "invalidTargetTypeForChain", typeValue, searchParamName);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
Predicate targetTypeParameter = myCriteriaBuilder.equal(theJoin.get("myTargetResourceType"), typeValue);
|
||||
myQueryRoot.addPredicate(targetTypeParameter);
|
||||
return targetTypeParameter;
|
||||
}
|
||||
|
||||
boolean foundChainMatch = false;
|
||||
List<Class<? extends IBaseResource>> candidateTargetTypes = new ArrayList<>();
|
||||
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
||||
|
||||
String chain = theReferenceParam.getChain();
|
||||
String remainingChain = null;
|
||||
int chainDotIndex = chain.indexOf('.');
|
||||
if (chainDotIndex != -1) {
|
||||
|
@ -355,6 +409,12 @@ class PredicateBuilderReference extends BasePredicateBuilder {
|
|||
return predicate;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private InvalidRequestException newInvalidResourceTypeException(String theResourceType) {
|
||||
String msg = myContext.getLocalizer().getMessageSanitized(PredicateBuilderReference.class, "invalidResourceType", theResourceType);
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
private void warnAboutPerformanceOnUnqualifiedResources(String theParamName, RequestDetails theRequest, List<Class<? extends IBaseResource>> theCandidateTargetTypes) {
|
||||
String message = new StringBuilder()
|
||||
.append("This search uses an unqualified resource(a parameter in a chain without a resource type). ")
|
||||
|
|
|
@ -316,6 +316,67 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(ids, empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChainOnType() {
|
||||
|
||||
Patient sub1 = new Patient();
|
||||
sub1.setActive(true);
|
||||
sub1.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub1Id = myPatientDao.create(sub1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Group sub2 = new Group();
|
||||
sub2.setActive(true);
|
||||
sub2.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub2Id = myGroupDao.create(sub2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc1 = new Encounter();
|
||||
enc1.getSubject().setReference(sub1Id);
|
||||
String enc1Id = myEncounterDao.create(enc1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc2 = new Encounter();
|
||||
enc2.getSubject().setReference(sub2Id);
|
||||
String enc2Id = myEncounterDao.create(enc2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
List<String> ids;
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "Patient").setChain("_type"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc1Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "Group").setChain("_type"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc2Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "Organization").setChain("_type"));
|
||||
try {
|
||||
myEncounterDao.search(map);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource type \"Organization\" is not a valid target type for reference search parameter: Encounter:subject", e.getMessage());
|
||||
}
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "HelpImABug").setChain("_type"));
|
||||
try {
|
||||
myEncounterDao.search(map);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Invalid/unsupported resource type: \"HelpImABug\"", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #441
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue