001/* 002 * #%L 003 * HAPI FHIR JPA Server 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.dao; 021 022import ca.uhn.fhir.i18n.Msg; 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient; 025import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters; 026import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; 027import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 028import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum; 029import ca.uhn.fhir.model.api.IResource; 030import ca.uhn.fhir.rest.api.CacheControlDirective; 031import ca.uhn.fhir.rest.api.Constants; 032import ca.uhn.fhir.rest.api.SortSpec; 033import ca.uhn.fhir.rest.api.server.IBundleProvider; 034import ca.uhn.fhir.rest.api.server.RequestDetails; 035import ca.uhn.fhir.rest.param.DateRangeParam; 036import ca.uhn.fhir.rest.param.StringAndListParam; 037import ca.uhn.fhir.rest.param.TokenOrListParam; 038import ca.uhn.fhir.rest.param.TokenParam; 039import jakarta.servlet.http.HttpServletRequest; 040import org.hl7.fhir.instance.model.api.IBaseResource; 041import org.hl7.fhir.instance.model.api.IIdType; 042import org.hl7.fhir.instance.model.api.IPrimitiveType; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045import org.springframework.beans.factory.annotation.Autowired; 046import org.springframework.transaction.annotation.Propagation; 047import org.springframework.transaction.annotation.Transactional; 048 049import java.util.Collections; 050 051public class JpaResourceDaoPatient<T extends IBaseResource> extends BaseHapiFhirResourceDao<T> 052 implements IFhirResourceDaoPatient<T> { 053 054 private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceDaoPatient.class); 055 056 @Autowired 057 private IRequestPartitionHelperSvc myPartitionHelperSvc; 058 059 private IBundleProvider doEverythingOperation( 060 TokenOrListParam theIds, 061 IPrimitiveType<Integer> theCount, 062 IPrimitiveType<Integer> theOffset, 063 DateRangeParam theLastUpdated, 064 SortSpec theSort, 065 StringAndListParam theContent, 066 StringAndListParam theNarrative, 067 StringAndListParam theFilter, 068 StringAndListParam theTypes, 069 boolean theMdmExpand, 070 RequestDetails theRequest) { 071 SearchParameterMap paramMap = new SearchParameterMap(); 072 if (theCount != null) { 073 paramMap.setCount(theCount.getValue()); 074 } 075 if (theOffset != null) { 076 throw new IllegalArgumentException( 077 Msg.code(1106) + "Everything operation does not support offset searching"); 078 } 079 if (theContent != null) { 080 paramMap.add(Constants.PARAM_CONTENT, theContent); 081 } 082 if (theNarrative != null) { 083 paramMap.add(Constants.PARAM_TEXT, theNarrative); 084 } 085 if (theTypes != null) { 086 paramMap.add(Constants.PARAM_TYPE, theTypes); 087 } else { 088 paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive())); 089 } 090 091 paramMap.setEverythingMode( 092 theIds != null && theIds.getValuesAsQueryTokens().size() == 1 093 ? EverythingModeEnum.PATIENT_INSTANCE 094 : EverythingModeEnum.PATIENT_TYPE); 095 paramMap.setSort(theSort); 096 paramMap.setLastUpdated(theLastUpdated); 097 if (theIds != null) { 098 if (theMdmExpand) { 099 theIds.getValuesAsQueryTokens().forEach(param -> param.setMdmExpand(true)); 100 } 101 paramMap.add("_id", theIds); 102 } 103 104 if (!isPagingProviderDatabaseBacked(theRequest)) { 105 paramMap.setLoadSynchronous(true); 106 } 107 108 RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType( 109 theRequest, getResourceName(), paramMap); 110 111 adjustCount(theRequest, paramMap); 112 113 return mySearchCoordinatorSvc.registerSearch( 114 this, 115 paramMap, 116 getResourceName(), 117 new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), 118 theRequest, 119 requestPartitionId); 120 } 121 122 private void adjustCount(RequestDetails theRequest, SearchParameterMap theParamMap) { 123 if (theRequest.getServer() == null) { 124 return; 125 } 126 127 if (theParamMap.getCount() == null && theRequest.getServer().getDefaultPageSize() != null) { 128 theParamMap.setCount(theRequest.getServer().getDefaultPageSize()); 129 return; 130 } 131 132 Integer maxPageSize = theRequest.getServer().getMaximumPageSize(); 133 if (maxPageSize != null && theParamMap.getCount() > maxPageSize) { 134 ourLog.info( 135 "Reducing {} from {} to {} which is the maximum allowable page size.", 136 Constants.PARAM_COUNT, 137 theParamMap.getCount(), 138 maxPageSize); 139 theParamMap.setCount(maxPageSize); 140 } 141 } 142 143 @Override 144 @Transactional(propagation = Propagation.SUPPORTS) 145 public IBundleProvider patientInstanceEverything( 146 HttpServletRequest theServletRequest, 147 RequestDetails theRequestDetails, 148 PatientEverythingParameters theQueryParams, 149 IIdType theId) { 150 TokenOrListParam id = new TokenOrListParam().add(new TokenParam(theId.getIdPart())); 151 return doEverythingOperation( 152 id, 153 theQueryParams.getCount(), 154 theQueryParams.getOffset(), 155 theQueryParams.getLastUpdated(), 156 theQueryParams.getSort(), 157 theQueryParams.getContent(), 158 theQueryParams.getNarrative(), 159 theQueryParams.getFilter(), 160 theQueryParams.getTypes(), 161 theQueryParams.getMdmExpand(), 162 theRequestDetails); 163 } 164 165 @Override 166 @Transactional(propagation = Propagation.SUPPORTS) 167 public IBundleProvider patientTypeEverything( 168 HttpServletRequest theServletRequest, 169 RequestDetails theRequestDetails, 170 PatientEverythingParameters theQueryParams, 171 TokenOrListParam theId) { 172 return doEverythingOperation( 173 theId, 174 theQueryParams.getCount(), 175 theQueryParams.getOffset(), 176 theQueryParams.getLastUpdated(), 177 theQueryParams.getSort(), 178 theQueryParams.getContent(), 179 theQueryParams.getNarrative(), 180 theQueryParams.getFilter(), 181 theQueryParams.getTypes(), 182 theQueryParams.getMdmExpand(), 183 theRequestDetails); 184 } 185}