001/*
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2023 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 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.Arrays;
049import java.util.Collections;
050import javax.servlet.http.HttpServletRequest;
051
052public class JpaResourceDaoPatient<T extends IBaseResource> extends BaseHapiFhirResourceDao<T>
053                implements IFhirResourceDaoPatient<T> {
054
055        private static final Logger ourLog = LoggerFactory.getLogger(JpaResourceDaoPatient.class);
056
057        @Autowired
058        private IRequestPartitionHelperSvc myPartitionHelperSvc;
059
060        private IBundleProvider doEverythingOperation(
061                        TokenOrListParam theIds,
062                        IPrimitiveType<Integer> theCount,
063                        IPrimitiveType<Integer> theOffset,
064                        DateRangeParam theLastUpdated,
065                        SortSpec theSort,
066                        StringAndListParam theContent,
067                        StringAndListParam theNarrative,
068                        StringAndListParam theFilter,
069                        StringAndListParam theTypes,
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 (theRequest.getParameters().containsKey("_mdm")) {
099                                String[] paramVal = theRequest.getParameters().get("_mdm");
100                                if (Arrays.asList(paramVal).contains("true")) {
101                                        theIds.getValuesAsQueryTokens().forEach(param -> param.setMdmExpand(true));
102                                }
103                        }
104                        paramMap.add("_id", theIds);
105                }
106
107                if (!isPagingProviderDatabaseBacked(theRequest)) {
108                        paramMap.setLoadSynchronous(true);
109                }
110
111                RequestPartitionId requestPartitionId = myPartitionHelperSvc.determineReadPartitionForRequestForSearchType(
112                                theRequest, getResourceName(), paramMap, null);
113
114                adjustCount(theRequest, paramMap);
115
116                return mySearchCoordinatorSvc.registerSearch(
117                                this,
118                                paramMap,
119                                getResourceName(),
120                                new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)),
121                                theRequest,
122                                requestPartitionId);
123        }
124
125        private void adjustCount(RequestDetails theRequest, SearchParameterMap theParamMap) {
126                if (theRequest.getServer() == null) {
127                        return;
128                }
129
130                if (theParamMap.getCount() == null && theRequest.getServer().getDefaultPageSize() != null) {
131                        theParamMap.setCount(theRequest.getServer().getDefaultPageSize());
132                        return;
133                }
134
135                Integer maxPageSize = theRequest.getServer().getMaximumPageSize();
136                if (maxPageSize != null && theParamMap.getCount() > maxPageSize) {
137                        ourLog.info(
138                                        "Reducing {} from {} to {} which is the maximum allowable page size.",
139                                        Constants.PARAM_COUNT,
140                                        theParamMap.getCount(),
141                                        maxPageSize);
142                        theParamMap.setCount(maxPageSize);
143                }
144        }
145
146        @Override
147        @Transactional(propagation = Propagation.SUPPORTS)
148        public IBundleProvider patientInstanceEverything(
149                        HttpServletRequest theServletRequest,
150                        RequestDetails theRequestDetails,
151                        PatientEverythingParameters theQueryParams,
152                        IIdType theId) {
153                TokenOrListParam id = new TokenOrListParam().add(new TokenParam(theId.getIdPart()));
154                return doEverythingOperation(
155                                id,
156                                theQueryParams.getCount(),
157                                theQueryParams.getOffset(),
158                                theQueryParams.getLastUpdated(),
159                                theQueryParams.getSort(),
160                                theQueryParams.getContent(),
161                                theQueryParams.getNarrative(),
162                                theQueryParams.getFilter(),
163                                theQueryParams.getTypes(),
164                                theRequestDetails);
165        }
166
167        @Override
168        @Transactional(propagation = Propagation.SUPPORTS)
169        public IBundleProvider patientTypeEverything(
170                        HttpServletRequest theServletRequest,
171                        RequestDetails theRequestDetails,
172                        PatientEverythingParameters theQueryParams,
173                        TokenOrListParam theId) {
174                return doEverythingOperation(
175                                theId,
176                                theQueryParams.getCount(),
177                                theQueryParams.getOffset(),
178                                theQueryParams.getLastUpdated(),
179                                theQueryParams.getSort(),
180                                theQueryParams.getContent(),
181                                theQueryParams.getNarrative(),
182                                theQueryParams.getFilter(),
183                                theQueryParams.getTypes(),
184                                theRequestDetails);
185        }
186}