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.interceptor.model.RequestPartitionId;
023import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient;
024import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters;
025import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
026import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
027import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
028import ca.uhn.fhir.model.api.IResource;
029import ca.uhn.fhir.rest.api.CacheControlDirective;
030import ca.uhn.fhir.rest.api.Constants;
031import ca.uhn.fhir.rest.api.SortSpec;
032import ca.uhn.fhir.rest.api.server.IBundleProvider;
033import ca.uhn.fhir.rest.api.server.RequestDetails;
034import ca.uhn.fhir.rest.param.DateRangeParam;
035import ca.uhn.fhir.rest.param.StringAndListParam;
036import ca.uhn.fhir.rest.param.TokenOrListParam;
037import ca.uhn.fhir.rest.param.TokenParam;
038import jakarta.servlet.http.HttpServletRequest;
039import org.hl7.fhir.instance.model.api.IBaseResource;
040import org.hl7.fhir.instance.model.api.IIdType;
041import org.hl7.fhir.instance.model.api.IPrimitiveType;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044import org.springframework.beans.factory.annotation.Autowired;
045import org.springframework.transaction.annotation.Propagation;
046import org.springframework.transaction.annotation.Transactional;
047
048import java.util.Collections;
049
050public class JpaResourceDaoPatient<T extends IBaseResource> extends BaseHapiFhirResourceDao<T>
051                implements IFhirResourceDaoPatient<T> {
052
053        private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceDaoPatient.class);
054
055        @Autowired
056        private IRequestPartitionHelperSvc myPartitionHelperSvc;
057
058        private IBundleProvider doEverythingOperation(
059                        TokenOrListParam theIds,
060                        IPrimitiveType<Integer> theCount,
061                        IPrimitiveType<Integer> theOffset,
062                        DateRangeParam theLastUpdated,
063                        SortSpec theSort,
064                        StringAndListParam theContent,
065                        StringAndListParam theNarrative,
066                        StringAndListParam theFilter,
067                        StringAndListParam theTypes,
068                        boolean theMdmExpand,
069                        RequestDetails theRequest) {
070                SearchParameterMap paramMap = new SearchParameterMap();
071                if (theCount != null) {
072                        paramMap.setCount(theCount.getValue());
073                }
074                if (theOffset != null) {
075                        paramMap.setOffset(theOffset.getValue());
076                }
077                if (theContent != null) {
078                        paramMap.add(Constants.PARAM_CONTENT, theContent);
079                }
080                if (theNarrative != null) {
081                        paramMap.add(Constants.PARAM_TEXT, theNarrative);
082                }
083                if (theTypes != null) {
084                        paramMap.add(Constants.PARAM_TYPE, theTypes);
085                } else {
086                        paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
087                }
088
089                paramMap.setEverythingMode(
090                                theIds != null && theIds.getValuesAsQueryTokens().size() == 1
091                                                ? EverythingModeEnum.PATIENT_INSTANCE
092                                                : EverythingModeEnum.PATIENT_TYPE);
093                paramMap.setSort(theSort);
094                paramMap.setLastUpdated(theLastUpdated);
095                if (theIds != null) {
096                        if (theMdmExpand) {
097                                theIds.getValuesAsQueryTokens().forEach(param -> param.setMdmExpand(true));
098                        }
099                        paramMap.add("_id", theIds);
100                }
101
102                if (!isPagingProviderDatabaseBacked(theRequest)) {
103                        paramMap.setLoadSynchronous(true);
104                }
105
106                RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(
107                                theRequest, getResourceName(), paramMap);
108
109                adjustCount(theRequest, paramMap);
110
111                return mySearchCoordinatorSvc.registerSearch(
112                                this,
113                                paramMap,
114                                getResourceName(),
115                                new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)),
116                                theRequest,
117                                requestPartitionId);
118        }
119
120        private void adjustCount(RequestDetails theRequest, SearchParameterMap theParamMap) {
121                if (theRequest.getServer() == null) {
122                        return;
123                }
124
125                if (theParamMap.getCount() == null && theRequest.getServer().getDefaultPageSize() != null) {
126                        theParamMap.setCount(theRequest.getServer().getDefaultPageSize());
127                        return;
128                }
129
130                Integer maxPageSize = theRequest.getServer().getMaximumPageSize();
131                if (maxPageSize != null && theParamMap.getCount() > maxPageSize) {
132                        ourLog.info(
133                                        "Reducing {} from {} to {} which is the maximum allowable page size.",
134                                        Constants.PARAM_COUNT,
135                                        theParamMap.getCount(),
136                                        maxPageSize);
137                        theParamMap.setCount(maxPageSize);
138                }
139        }
140
141        @Override
142        @Transactional(propagation = Propagation.SUPPORTS)
143        public IBundleProvider patientInstanceEverything(
144                        HttpServletRequest theServletRequest,
145                        RequestDetails theRequestDetails,
146                        PatientEverythingParameters theQueryParams,
147                        IIdType theId) {
148                TokenOrListParam id = new TokenOrListParam().add(new TokenParam(theId.getIdPart()));
149                return doEverythingOperation(
150                                id,
151                                theQueryParams.getCount(),
152                                theQueryParams.getOffset(),
153                                theQueryParams.getLastUpdated(),
154                                theQueryParams.getSort(),
155                                theQueryParams.getContent(),
156                                theQueryParams.getNarrative(),
157                                theQueryParams.getFilter(),
158                                theQueryParams.getTypes(),
159                                theQueryParams.getMdmExpand(),
160                                theRequestDetails);
161        }
162
163        @Override
164        @Transactional(propagation = Propagation.SUPPORTS)
165        public IBundleProvider patientTypeEverything(
166                        HttpServletRequest theServletRequest,
167                        RequestDetails theRequestDetails,
168                        PatientEverythingParameters theQueryParams,
169                        TokenOrListParam theId) {
170                return doEverythingOperation(
171                                theId,
172                                theQueryParams.getCount(),
173                                theQueryParams.getOffset(),
174                                theQueryParams.getLastUpdated(),
175                                theQueryParams.getSort(),
176                                theQueryParams.getContent(),
177                                theQueryParams.getNarrative(),
178                                theQueryParams.getFilter(),
179                                theQueryParams.getTypes(),
180                                theQueryParams.getMdmExpand(),
181                                theRequestDetails);
182        }
183}