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}