
001package ca.uhn.fhir.jpa.dao.predicate; 002 003/*- 004 * #%L 005 * HAPI FHIR JPA Server 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.jpa.api.svc.IIdHelperService; 025import ca.uhn.fhir.jpa.dao.LegacySearchBuilder; 026import ca.uhn.fhir.model.api.IQueryParameterType; 027import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; 028import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; 029import org.hl7.fhir.r4.model.IdType; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032import org.springframework.beans.factory.annotation.Autowired; 033import org.springframework.context.annotation.Scope; 034import org.springframework.stereotype.Component; 035 036import javax.annotation.Nullable; 037import javax.persistence.criteria.Predicate; 038import java.util.ArrayList; 039import java.util.HashSet; 040import java.util.List; 041import java.util.Set; 042 043import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 044import static org.apache.commons.lang3.StringUtils.isNotBlank; 045 046@Component 047@Scope("prototype") 048public class PredicateBuilderResourceId extends BasePredicateBuilder { 049 private static final Logger ourLog = LoggerFactory.getLogger(PredicateBuilderResourceId.class); 050 051 @Autowired 052 IIdHelperService myIdHelperService; 053 054 public PredicateBuilderResourceId(LegacySearchBuilder theSearchBuilder) { 055 super(theSearchBuilder); 056 } 057 058 @Nullable 059 Predicate addPredicateResourceId(List<List<IQueryParameterType>> theValues, String theResourceName, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) { 060 061 Predicate nextPredicate = createPredicate(theResourceName, theValues, theOperation, theRequestPartitionId); 062 063 if (nextPredicate != null) { 064 myQueryStack.addPredicate(nextPredicate); 065 return nextPredicate; 066 } 067 068 return null; 069 } 070 071 @Nullable 072 private Predicate createPredicate(String theResourceName, List<List<IQueryParameterType>> theValues, SearchFilterParser.CompareOperation theOperation, RequestPartitionId theRequestPartitionId) { 073 Predicate nextPredicate = null; 074 075 Set<ResourcePersistentId> allOrPids = null; 076 077 for (List<? extends IQueryParameterType> nextValue : theValues) { 078 Set<ResourcePersistentId> orPids = new HashSet<>(); 079 boolean haveValue = false; 080 for (IQueryParameterType next : nextValue) { 081 String value = next.getValueAsQueryToken(myContext); 082 if (value != null && value.startsWith("|")) { 083 value = value.substring(1); 084 } 085 086 IdType valueAsId = new IdType(value); 087 if (isNotBlank(value)) { 088 haveValue = true; 089 try { 090 ResourcePersistentId pid = myIdHelperService.resolveResourcePersistentIds(theRequestPartitionId, theResourceName, valueAsId.getIdPart()); 091 orPids.add(pid); 092 } catch (ResourceNotFoundException e) { 093 // This is not an error in a search, it just results in no matchesFhirResourceDaoR4InterceptorTest 094 ourLog.debug("Resource ID {} was requested but does not exist", valueAsId.getIdPart()); 095 } 096 } 097 } 098 if (haveValue) { 099 if (allOrPids == null) { 100 allOrPids = orPids; 101 } else { 102 allOrPids.retainAll(orPids); 103 } 104 105 } 106 } 107 108 if (allOrPids != null && allOrPids.isEmpty()) { 109 110 // This will never match 111 nextPredicate = myCriteriaBuilder.equal(myQueryStack.getResourcePidColumn(), -1); 112 113 } else if (allOrPids != null) { 114 115 SearchFilterParser.CompareOperation operation = defaultIfNull(theOperation, SearchFilterParser.CompareOperation.eq); 116 assert operation == SearchFilterParser.CompareOperation.eq || operation == SearchFilterParser.CompareOperation.ne; 117 List<Predicate> codePredicates = new ArrayList<>(); 118 switch (operation) { 119 default: 120 case eq: 121 codePredicates.add(myQueryStack.getResourcePidColumn().in(ResourcePersistentId.toLongList(allOrPids))); 122 nextPredicate = myCriteriaBuilder.and(toArray(codePredicates)); 123 break; 124 case ne: 125 codePredicates.add(myQueryStack.getResourcePidColumn().in(ResourcePersistentId.toLongList(allOrPids)).not()); 126 nextPredicate = myCriteriaBuilder.and(toArray(codePredicates)); 127 break; 128 } 129 130 } 131 132 return nextPredicate; 133 } 134 135}