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