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.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                        jakarta.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                        @Description(
116                                                        shortDefinition =
117                                                                        "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)")
118                                        @OperationParam(name = Constants.PARAM_MDM, min = 0, max = 1, typeName = "boolean")
119                                        IPrimitiveType<Boolean> theMdmExpand,
120                        @Sort SortSpec theSortSpec,
121                        RequestDetails theRequestDetails) {
122
123                startRequest(theServletRequest);
124                try {
125                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
126                        everythingParams.setCount(theCount);
127                        everythingParams.setOffset(theOffset);
128                        everythingParams.setLastUpdated(theLastUpdated);
129                        everythingParams.setSort(theSortSpec);
130                        everythingParams.setContent(toStringAndList(theContent));
131                        everythingParams.setNarrative(toStringAndList(theNarrative));
132                        everythingParams.setFilter(toStringAndList(theFilter));
133                        everythingParams.setTypes(toStringAndList(theTypes));
134                        everythingParams.setMdmExpand(resolveNullValue(theMdmExpand));
135
136                        return ((IFhirResourceDaoPatient<?>) getDao())
137                                        .patientInstanceEverything(theServletRequest, theRequestDetails, everythingParams, theId);
138                } finally {
139                        endRequest(theServletRequest);
140                }
141        }
142
143        /**
144         * /Patient/$everything
145         */
146        @Operation(
147                        name = JpaConstants.OPERATION_EVERYTHING,
148                        canonicalUrl = "http://hl7.org/fhir/OperationDefinition/Patient-everything",
149                        idempotent = true,
150                        bundleType = BundleTypeEnum.SEARCHSET)
151        public IBundleProvider patientTypeEverything(
152                        jakarta.servlet.http.HttpServletRequest theServletRequest,
153                        @Description(
154                                                        shortDefinition =
155                                                                        "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
156                                        @OperationParam(name = Constants.PARAM_COUNT, typeName = "unsignedInt")
157                                        IPrimitiveType<Integer> theCount,
158                        @Description(
159                                                        shortDefinition =
160                                                                        "Results from this method are returned across multiple pages. This parameter controls the offset when fetching a page.")
161                                        @OperationParam(name = Constants.PARAM_OFFSET, typeName = "unsignedInt")
162                                        IPrimitiveType<Integer> theOffset,
163                        @Description(
164                                                        shortDefinition =
165                                                                        "Only return resources which were last updated as specified by the given range")
166                                        @OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
167                                        DateRangeParam theLastUpdated,
168                        @Description(
169                                                        shortDefinition =
170                                                                        "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)")
171                                        @OperationParam(
172                                                        name = Constants.PARAM_CONTENT,
173                                                        min = 0,
174                                                        max = OperationParam.MAX_UNLIMITED,
175                                                        typeName = "string")
176                                        List<IPrimitiveType<String>> theContent,
177                        @Description(
178                                                        shortDefinition =
179                                                                        "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)")
180                                        @OperationParam(
181                                                        name = Constants.PARAM_TEXT,
182                                                        min = 0,
183                                                        max = OperationParam.MAX_UNLIMITED,
184                                                        typeName = "string")
185                                        List<IPrimitiveType<String>> theNarrative,
186                        @Description(
187                                                        shortDefinition =
188                                                                        "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)")
189                                        @OperationParam(
190                                                        name = Constants.PARAM_FILTER,
191                                                        min = 0,
192                                                        max = OperationParam.MAX_UNLIMITED,
193                                                        typeName = "string")
194                                        List<IPrimitiveType<String>> theFilter,
195                        @Description(
196                                                        shortDefinition =
197                                                                        "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)")
198                                        @OperationParam(
199                                                        name = Constants.PARAM_TYPE,
200                                                        min = 0,
201                                                        max = OperationParam.MAX_UNLIMITED,
202                                                        typeName = "string")
203                                        List<IPrimitiveType<String>> theTypes,
204                        @Description(shortDefinition = "Filter the resources to return based on the patient ids provided.")
205                                        @OperationParam(
206                                                        name = Constants.PARAM_ID,
207                                                        min = 0,
208                                                        max = OperationParam.MAX_UNLIMITED,
209                                                        typeName = "id")
210                                        List<IIdType> theId,
211                        @Description(
212                                                        shortDefinition =
213                                                                        "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)")
214                                        @OperationParam(name = Constants.PARAM_MDM, min = 0, max = 1, typeName = "boolean")
215                                        IPrimitiveType<Boolean> theMdmExpand,
216                        @Sort SortSpec theSortSpec,
217                        RequestDetails theRequestDetails) {
218
219                startRequest(theServletRequest);
220                try {
221                        PatientEverythingParameters everythingParams = new PatientEverythingParameters();
222                        everythingParams.setCount(theCount);
223                        everythingParams.setOffset(theOffset);
224                        everythingParams.setLastUpdated(theLastUpdated);
225                        everythingParams.setSort(theSortSpec);
226                        everythingParams.setContent(toStringAndList(theContent));
227                        everythingParams.setNarrative(toStringAndList(theNarrative));
228                        everythingParams.setFilter(toStringAndList(theFilter));
229                        everythingParams.setTypes(toStringAndList(theTypes));
230                        everythingParams.setMdmExpand(resolveNullValue(theMdmExpand));
231
232                        return ((IFhirResourceDaoPatient<?>) getDao())
233                                        .patientTypeEverything(
234                                                        theServletRequest,
235                                                        theRequestDetails,
236                                                        everythingParams,
237                                                        toFlattenedPatientIdTokenParamList(theId));
238                } finally {
239                        endRequest(theServletRequest);
240                }
241        }
242
243        /**
244         * Given a list of string types, return only the ID portions of any parameters passed in.
245         */
246        private TokenOrListParam toFlattenedPatientIdTokenParamList(List<IIdType> theId) {
247                TokenOrListParam retVal = new TokenOrListParam();
248                if (theId != null) {
249                        for (IIdType next : theId) {
250                                if (isNotBlank(next.getValue())) {
251                                        String[] split = next.getValueAsString().split(",");
252                                        Arrays.stream(split).map(IdDt::new).forEach(id -> {
253                                                retVal.addOr(new TokenParam(id.getIdPart()));
254                                        });
255                                }
256                        }
257                }
258
259                return retVal.getValuesAsQueryTokens().isEmpty() ? null : retVal;
260        }
261
262        private StringAndListParam toStringAndList(List<IPrimitiveType<String>> theNarrative) {
263                StringAndListParam retVal = new StringAndListParam();
264                if (theNarrative != null) {
265                        for (IPrimitiveType<String> next : theNarrative) {
266                                if (isNotBlank(next.getValue())) {
267                                        retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue())));
268                                }
269                        }
270                }
271                if (retVal.getValuesAsQueryTokens().isEmpty()) {
272                        return null;
273                }
274                return retVal;
275        }
276
277        private boolean resolveNullValue(IPrimitiveType<Boolean> theMdmExpand) {
278                return theMdmExpand == null ? Boolean.FALSE : theMdmExpand.getValue();
279        }
280}