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.provider;
021
022import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient;
023import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters;
024import ca.uhn.fhir.jpa.model.util.JpaConstants;
025import ca.uhn.fhir.model.api.annotation.Description;
026import ca.uhn.fhir.model.primitive.IdDt;
027import ca.uhn.fhir.model.valueset.BundleTypeEnum;
028import ca.uhn.fhir.rest.annotation.IdParam;
029import ca.uhn.fhir.rest.annotation.Operation;
030import ca.uhn.fhir.rest.annotation.OperationParam;
031import ca.uhn.fhir.rest.annotation.Sort;
032import ca.uhn.fhir.rest.api.Constants;
033import ca.uhn.fhir.rest.api.SortSpec;
034import ca.uhn.fhir.rest.api.server.IBundleProvider;
035import ca.uhn.fhir.rest.api.server.RequestDetails;
036import ca.uhn.fhir.rest.param.DateRangeParam;
037import ca.uhn.fhir.rest.param.StringAndListParam;
038import ca.uhn.fhir.rest.param.StringOrListParam;
039import ca.uhn.fhir.rest.param.StringParam;
040import ca.uhn.fhir.rest.param.TokenOrListParam;
041import ca.uhn.fhir.rest.param.TokenParam;
042import org.hl7.fhir.instance.model.api.IBaseResource;
043import org.hl7.fhir.instance.model.api.IIdType;
044import org.hl7.fhir.instance.model.api.IPrimitiveType;
045
046import java.util.Arrays;
047import java.util.List;
048
049import static org.apache.commons.lang3.StringUtils.isNotBlank;
050
051public abstract class BaseJpaResourceProviderPatient<T extends IBaseResource> extends BaseJpaResourceProvider<T> {
052
053        /**
054         * Patient/123/$everything
055         */
056        @Operation(name = JpaConstants.OPERATION_EVERYTHING, canonicalUrl = "http://hl7.org/fhir/OperationDefinition/Patient-everything", idempotent = true, bundleType = BundleTypeEnum.SEARCHSET)
057        public IBundleProvider patientInstanceEverything(
058
059                javax.servlet.http.HttpServletRequest theServletRequest,
060
061                @IdParam
062                IIdType theId,
063
064                @Description(shortDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
065                @OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
066                IPrimitiveType<Integer> theCount,
067
068                @Description(shortDefinition = "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
069                @OperationParam(name = Constants.PARAM_OFFSET, typeName = "unsignedInt")
070                IPrimitiveType<Integer> theOffset,
071
072                @Description(shortDefinition = "Only return resources which were last updated as specified by the given range")
073                @OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
074                        DateRangeParam theLastUpdated,
075
076                @Description(shortDefinition = "Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
077                @OperationParam(name = Constants.PARAM_CONTENT, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
078                List<IPrimitiveType<String>> theContent,
079
080                @Description(shortDefinition = "Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
081                @OperationParam(name = Constants.PARAM_TEXT, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
082                List<IPrimitiveType<String>> theNarrative,
083
084                @Description(shortDefinition = "Filter the resources to return only resources matching the given _filter filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
085                @OperationParam(name = Constants.PARAM_FILTER, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
086                List<IPrimitiveType<String>> theFilter,
087
088                @Description(shortDefinition = "Filter the resources to return only resources matching the given _type filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
089                @OperationParam(name = Constants.PARAM_TYPE, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
090                List<IPrimitiveType<String>> theTypes,
091
092                @Sort
093                        SortSpec theSortSpec,
094
095                RequestDetails theRequestDetails
096        ) {
097
098                startRequest(theServletRequest);
099                try {
100                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
101                        everythingParams.setCount(theCount);
102                        everythingParams.setOffset(theOffset);
103                        everythingParams.setLastUpdated(theLastUpdated);
104                        everythingParams.setSort(theSortSpec);
105                        everythingParams.setContent(toStringAndList(theContent));
106                        everythingParams.setNarrative(toStringAndList(theNarrative));
107                        everythingParams.setFilter(toStringAndList(theFilter));
108                        everythingParams.setTypes(toStringAndList(theTypes));
109
110                        return ((IFhirResourceDaoPatient<?>) getDao()).patientInstanceEverything(theServletRequest, theRequestDetails, everythingParams, theId);
111                } finally {
112                        endRequest(theServletRequest);
113                }
114        }
115
116        /**
117         * /Patient/$everything
118         */
119        @Operation(name = JpaConstants.OPERATION_EVERYTHING, canonicalUrl = "http://hl7.org/fhir/OperationDefinition/Patient-everything", idempotent = true, bundleType = BundleTypeEnum.SEARCHSET)
120        public IBundleProvider patientTypeEverything(
121
122                javax.servlet.http.HttpServletRequest theServletRequest,
123
124                @Description(shortDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
125                @OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
126                IPrimitiveType<Integer> theCount,
127
128                @Description(shortDefinition = "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
129                @OperationParam(name = Constants.PARAM_OFFSET, typeName = "unsignedInt")
130                IPrimitiveType<Integer> theOffset,
131
132                @Description(shortDefinition = "Only return resources which were last updated as specified by the given range")
133                @OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
134                        DateRangeParam theLastUpdated,
135
136                @Description(shortDefinition = "Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
137                @OperationParam(name = Constants.PARAM_CONTENT, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
138                List<IPrimitiveType<String>> theContent,
139
140                @Description(shortDefinition = "Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
141                @OperationParam(name = Constants.PARAM_TEXT, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
142                List<IPrimitiveType<String>> theNarrative,
143
144                @Description(shortDefinition = "Filter the resources to return only resources matching the given _filter filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
145                @OperationParam(name = Constants.PARAM_FILTER, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
146                List<IPrimitiveType<String>> theFilter,
147
148                @Description(shortDefinition = "Filter the resources to return only resources matching the given _type filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
149                @OperationParam(name = Constants.PARAM_TYPE, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "string")
150                List<IPrimitiveType<String>> theTypes,
151
152
153                @Description(shortDefinition = "Filter the resources to return based on the patient ids provided.")
154                @OperationParam(name = Constants.PARAM_ID, min = 0, max = OperationParam.MAX_UNLIMITED, typeName = "id")
155                List<IIdType> theId,
156
157                @Sort
158                        SortSpec theSortSpec,
159
160                RequestDetails theRequestDetails
161        ) {
162
163                startRequest(theServletRequest);
164                try {
165                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
166                        everythingParams.setCount(theCount);
167                        everythingParams.setOffset(theOffset);
168                        everythingParams.setLastUpdated(theLastUpdated);
169                        everythingParams.setSort(theSortSpec);
170                        everythingParams.setContent(toStringAndList(theContent));
171                        everythingParams.setNarrative(toStringAndList(theNarrative));
172                        everythingParams.setFilter(toStringAndList(theFilter));
173                        everythingParams.setTypes(toStringAndList(theTypes));
174
175                        return ((IFhirResourceDaoPatient<?>) getDao()).patientTypeEverything(theServletRequest, theRequestDetails, everythingParams, toFlattenedPatientIdTokenParamList(theId));
176                } finally {
177                        endRequest(theServletRequest);
178                }
179
180        }
181
182        /**
183         * Given a list of string types, return only the ID portions of any parameters passed in.
184         */
185        private TokenOrListParam toFlattenedPatientIdTokenParamList(List<IIdType> theId) {
186                TokenOrListParam retVal = new TokenOrListParam();
187                if (theId != null) {
188                        for (IIdType next : theId) {
189                                if (isNotBlank(next.getValue())) {
190                                        String[] split = next.getValueAsString().split(",");
191                                        Arrays.stream(split).map(IdDt::new).forEach(id -> {
192                                                retVal.addOr(new TokenParam(id.getIdPart()));
193                                        });
194                                }
195                        }
196                }
197
198                return retVal.getValuesAsQueryTokens().isEmpty() ? null: retVal;
199        }
200
201        private StringAndListParam toStringAndList(List<IPrimitiveType<String>> theNarrative) {
202                StringAndListParam retVal = new StringAndListParam();
203                if (theNarrative != null) {
204                        for (IPrimitiveType<String> next : theNarrative) {
205                                if (isNotBlank(next.getValue())) {
206                                        retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue())));
207                                }
208                        }
209                }
210                if (retVal.getValuesAsQueryTokens().isEmpty()) {
211                        return null;
212                }
213                return retVal;
214        }
215
216}