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(
057                        name = JpaConstants.OPERATION_EVERYTHING,
058                        canonicalUrl = "http://hl7.org/fhir/OperationDefinition/Patient-everything",
059                        idempotent = true,
060                        bundleType = BundleTypeEnum.SEARCHSET)
061        public IBundleProvider patientInstanceEverything(
062                        javax.servlet.http.HttpServletRequest theServletRequest,
063                        @IdParam IIdType theId,
064                        @Description(
065                                                        shortDefinition =
066                                                                        "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
067                                        @OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
068                                        IPrimitiveType<Integer> theCount,
069                        @Description(
070                                                        shortDefinition =
071                                                                        "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
072                                        @OperationParam(name = Constants.PARAM_OFFSET, typeName = "unsignedInt")
073                                        IPrimitiveType<Integer> theOffset,
074                        @Description(
075                                                        shortDefinition =
076                                                                        "Only return resources which were last updated as specified by the given range")
077                                        @OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
078                                        DateRangeParam theLastUpdated,
079                        @Description(
080                                                        shortDefinition =
081                                                                        "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)")
082                                        @OperationParam(
083                                                        name = Constants.PARAM_CONTENT,
084                                                        min = 0,
085                                                        max = OperationParam.MAX_UNLIMITED,
086                                                        typeName = "string")
087                                        List<IPrimitiveType<String>> theContent,
088                        @Description(
089                                                        shortDefinition =
090                                                                        "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)")
091                                        @OperationParam(
092                                                        name = Constants.PARAM_TEXT,
093                                                        min = 0,
094                                                        max = OperationParam.MAX_UNLIMITED,
095                                                        typeName = "string")
096                                        List<IPrimitiveType<String>> theNarrative,
097                        @Description(
098                                                        shortDefinition =
099                                                                        "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)")
100                                        @OperationParam(
101                                                        name = Constants.PARAM_FILTER,
102                                                        min = 0,
103                                                        max = OperationParam.MAX_UNLIMITED,
104                                                        typeName = "string")
105                                        List<IPrimitiveType<String>> theFilter,
106                        @Description(
107                                                        shortDefinition =
108                                                                        "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)")
109                                        @OperationParam(
110                                                        name = Constants.PARAM_TYPE,
111                                                        min = 0,
112                                                        max = OperationParam.MAX_UNLIMITED,
113                                                        typeName = "string")
114                                        List<IPrimitiveType<String>> theTypes,
115                        @Sort SortSpec theSortSpec,
116                        RequestDetails theRequestDetails) {
117
118                startRequest(theServletRequest);
119                try {
120                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
121                        everythingParams.setCount(theCount);
122                        everythingParams.setOffset(theOffset);
123                        everythingParams.setLastUpdated(theLastUpdated);
124                        everythingParams.setSort(theSortSpec);
125                        everythingParams.setContent(toStringAndList(theContent));
126                        everythingParams.setNarrative(toStringAndList(theNarrative));
127                        everythingParams.setFilter(toStringAndList(theFilter));
128                        everythingParams.setTypes(toStringAndList(theTypes));
129
130                        return ((IFhirResourceDaoPatient<?>) getDao())
131                                        .patientInstanceEverything(theServletRequest, theRequestDetails, everythingParams, theId);
132                } finally {
133                        endRequest(theServletRequest);
134                }
135        }
136
137        /**
138         * /Patient/$everything
139         */
140        @Operation(
141                        name = JpaConstants.OPERATION_EVERYTHING,
142                        canonicalUrl = "http://hl7.org/fhir/OperationDefinition/Patient-everything",
143                        idempotent = true,
144                        bundleType = BundleTypeEnum.SEARCHSET)
145        public IBundleProvider patientTypeEverything(
146                        javax.servlet.http.HttpServletRequest theServletRequest,
147                        @Description(
148                                                        shortDefinition =
149                                                                        "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
150                                        @OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
151                                        IPrimitiveType<Integer> theCount,
152                        @Description(
153                                                        shortDefinition =
154                                                                        "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
155                                        @OperationParam(name = Constants.PARAM_OFFSET, typeName = "unsignedInt")
156                                        IPrimitiveType<Integer> theOffset,
157                        @Description(
158                                                        shortDefinition =
159                                                                        "Only return resources which were last updated as specified by the given range")
160                                        @OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
161                                        DateRangeParam theLastUpdated,
162                        @Description(
163                                                        shortDefinition =
164                                                                        "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)")
165                                        @OperationParam(
166                                                        name = Constants.PARAM_CONTENT,
167                                                        min = 0,
168                                                        max = OperationParam.MAX_UNLIMITED,
169                                                        typeName = "string")
170                                        List<IPrimitiveType<String>> theContent,
171                        @Description(
172                                                        shortDefinition =
173                                                                        "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)")
174                                        @OperationParam(
175                                                        name = Constants.PARAM_TEXT,
176                                                        min = 0,
177                                                        max = OperationParam.MAX_UNLIMITED,
178                                                        typeName = "string")
179                                        List<IPrimitiveType<String>> theNarrative,
180                        @Description(
181                                                        shortDefinition =
182                                                                        "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)")
183                                        @OperationParam(
184                                                        name = Constants.PARAM_FILTER,
185                                                        min = 0,
186                                                        max = OperationParam.MAX_UNLIMITED,
187                                                        typeName = "string")
188                                        List<IPrimitiveType<String>> theFilter,
189                        @Description(
190                                                        shortDefinition =
191                                                                        "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)")
192                                        @OperationParam(
193                                                        name = Constants.PARAM_TYPE,
194                                                        min = 0,
195                                                        max = OperationParam.MAX_UNLIMITED,
196                                                        typeName = "string")
197                                        List<IPrimitiveType<String>> theTypes,
198                        @Description(shortDefinition = "Filter the resources to return based on the patient ids provided.")
199                                        @OperationParam(
200                                                        name = Constants.PARAM_ID,
201                                                        min = 0,
202                                                        max = OperationParam.MAX_UNLIMITED,
203                                                        typeName = "id")
204                                        List<IIdType> theId,
205                        @Sort SortSpec theSortSpec,
206                        RequestDetails theRequestDetails) {
207
208                startRequest(theServletRequest);
209                try {
210                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
211                        everythingParams.setCount(theCount);
212                        everythingParams.setOffset(theOffset);
213                        everythingParams.setLastUpdated(theLastUpdated);
214                        everythingParams.setSort(theSortSpec);
215                        everythingParams.setContent(toStringAndList(theContent));
216                        everythingParams.setNarrative(toStringAndList(theNarrative));
217                        everythingParams.setFilter(toStringAndList(theFilter));
218                        everythingParams.setTypes(toStringAndList(theTypes));
219
220                        return ((IFhirResourceDaoPatient<?>) getDao())
221                                        .patientTypeEverything(
222                                                        theServletRequest,
223                                                        theRequestDetails,
224                                                        everythingParams,
225                                                        toFlattenedPatientIdTokenParamList(theId));
226                } finally {
227                        endRequest(theServletRequest);
228                }
229        }
230
231        /**
232         * Given a list of string types, return only the ID portions of any parameters passed in.
233         */
234        private TokenOrListParam toFlattenedPatientIdTokenParamList(List<IIdType> theId) {
235                TokenOrListParam retVal = new TokenOrListParam();
236                if (theId != null) {
237                        for (IIdType next : theId) {
238                                if (isNotBlank(next.getValue())) {
239                                        String[] split = next.getValueAsString().split(",");
240                                        Arrays.stream(split).map(IdDt::new).forEach(id -> {
241                                                retVal.addOr(new TokenParam(id.getIdPart()));
242                                        });
243                                }
244                        }
245                }
246
247                return retVal.getValuesAsQueryTokens().isEmpty() ? null : retVal;
248        }
249
250        private StringAndListParam toStringAndList(List<IPrimitiveType<String>> theNarrative) {
251                StringAndListParam retVal = new StringAndListParam();
252                if (theNarrative != null) {
253                        for (IPrimitiveType<String> next : theNarrative) {
254                                if (isNotBlank(next.getValue())) {
255                                        retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue())));
256                                }
257                        }
258                }
259                if (retVal.getValuesAsQueryTokens().isEmpty()) {
260                        return null;
261                }
262                return retVal;
263        }
264}