001/*-
002 * #%L
003 * HAPI FHIR JPA - Search Parameters
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.partition;
021
022import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
023import ca.uhn.fhir.interceptor.model.RequestPartitionId;
024import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
025import ca.uhn.fhir.rest.api.server.RequestDetails;
026import jakarta.annotation.Nonnull;
027import jakarta.annotation.Nullable;
028import org.hl7.fhir.instance.model.api.IBaseResource;
029import org.hl7.fhir.instance.model.api.IIdType;
030
031import java.util.Set;
032
033public interface IRequestPartitionHelperSvc {
034
035        @Nonnull
036        RequestPartitionId determineReadPartitionForRequest(
037                        @Nullable RequestDetails theRequest, @Nonnull ReadPartitionIdRequestDetails theDetails);
038
039        /**
040         * Determine partition to use when performing a server operation such as $bulk-import, $bulk-export, $reindex etc.
041         * @param theRequest the request details from the context of the call
042         * @param theOperationName the explicit name of the operation
043         * @return the partition id which should be used for the operation
044         */
045        @Nonnull
046        default RequestPartitionId determineReadPartitionForRequestForServerOperation(
047                        @Nullable RequestDetails theRequest, @Nonnull String theOperationName) {
048                ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forServerOperation(theOperationName);
049                return determineReadPartitionForRequest(theRequest, details);
050        }
051
052        /**
053         * Determine partition to use when performing database reads based on a resource instance.
054         * @param theRequest the request details from the context of the call
055         * @param theId the id of the resource instance
056         * @return the partition id which should be used for the database read
057         */
058        @Nonnull
059        default RequestPartitionId determineReadPartitionForRequestForRead(
060                        @Nullable RequestDetails theRequest, @Nonnull IIdType theId) {
061                ReadPartitionIdRequestDetails details =
062                                ReadPartitionIdRequestDetails.forRead(theId.getResourceType(), theId, theId.hasVersionIdPart());
063                return determineReadPartitionForRequest(theRequest, details);
064        }
065
066        /**
067         * Determine partition to use when performing database reads against a certain resource type based on a resource instance.
068         * @param theRequest the request details from the context of the call
069         * @param theResourceType the resource type
070         * @param theId the id of the resource instance
071         * @return the partition id which should be used for the database read
072         */
073        @Nonnull
074        default RequestPartitionId determineReadPartitionForRequestForRead(
075                        @Nullable RequestDetails theRequest, @Nonnull String theResourceType, @Nonnull IIdType theId) {
076                ReadPartitionIdRequestDetails details =
077                                ReadPartitionIdRequestDetails.forRead(theResourceType, theId, theId.hasVersionIdPart());
078                return determineReadPartitionForRequest(theRequest, details);
079        }
080
081        /**
082         * Determine partition to use when performing a database search against a certain resource type.
083         * @param theRequest the request details from the context of the call
084         * @param theResourceType the resource type
085         * @return the partition id which should be used for the database search
086         */
087        @Nonnull
088        default RequestPartitionId determineReadPartitionForRequestForSearchType(
089                        @Nullable RequestDetails theRequest, @Nonnull String theResourceType) {
090                ReadPartitionIdRequestDetails details =
091                                ReadPartitionIdRequestDetails.forSearchType(theResourceType, SearchParameterMap.newSynchronous(), null);
092                return determineReadPartitionForRequest(theRequest, details);
093        }
094
095        /**
096         * Determine partition to use when performing a database search based on a resource type and other search parameters.
097         * @param theRequest the request details from the context of the call
098         * @param theResourceType the resource type
099         * @param theParams the search parameters
100         * @return the partition id which should be used for the database search
101         */
102        @Nonnull
103        default RequestPartitionId determineReadPartitionForRequestForSearchType(
104                        @Nullable RequestDetails theRequest,
105                        @Nonnull String theResourceType,
106                        @Nonnull SearchParameterMap theParams) {
107                ReadPartitionIdRequestDetails details =
108                                ReadPartitionIdRequestDetails.forSearchType(theResourceType, theParams, null);
109                return determineReadPartitionForRequest(theRequest, details);
110        }
111
112        /**
113         * Determine partition to use when performing a database search based on a resource type, search parameters and a conditional target resource (if available).
114         * @param theRequest the request details from the context of the call
115         * @param theResourceType the resource type
116         * @param theParams the search parameters
117         * @param theConditionalOperationTargetOrNull the conditional target resource
118         * @return the partition id which should be used for the database search
119         */
120        @Nonnull
121        default RequestPartitionId determineReadPartitionForRequestForSearchType(
122                        RequestDetails theRequest,
123                        String theResourceType,
124                        SearchParameterMap theParams,
125                        IBaseResource theConditionalOperationTargetOrNull) {
126                SearchParameterMap searchParameterMap = theParams != null ? theParams : SearchParameterMap.newSynchronous();
127                ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forSearchType(
128                                theResourceType, searchParameterMap, theConditionalOperationTargetOrNull);
129                return determineReadPartitionForRequest(theRequest, details);
130        }
131
132        RequestPartitionId determineGenericPartitionForRequest(RequestDetails theRequestDetails);
133
134        /**
135         * Determine partition to use when performing the history operation based on a resource type and resource instance.
136         * @param theRequest the request details from the context of the call
137         * @param theResourceType the resource type
138         * @param theIdType the id of the resource instance
139         * @return the partition id which should be used for the history operation
140         */
141        @Nonnull
142        default RequestPartitionId determineReadPartitionForRequestForHistory(
143                        @Nullable RequestDetails theRequest, String theResourceType, IIdType theIdType) {
144                ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forHistory(theResourceType, theIdType);
145                return determineReadPartitionForRequest(theRequest, details);
146        }
147
148        default void validateHasPartitionPermissions(
149                        @Nonnull RequestDetails theRequest, String theResourceType, RequestPartitionId theRequestPartitionId) {}
150
151        @Nonnull
152        RequestPartitionId determineCreatePartitionForRequest(
153                        @Nullable RequestDetails theRequest, @Nonnull IBaseResource theResource, @Nonnull String theResourceType);
154
155        @Nonnull
156        Set<Integer> toReadPartitions(@Nonnull RequestPartitionId theRequestPartitionId);
157
158        boolean isResourcePartitionable(String theResourceType);
159
160        /**
161         * <b>No interceptors should be invoked by this method. It should ONLY be used when partition ids are
162         * known, but partition names are not.</b>
163         * <br/><br/>
164         * Ensures the list of partition ids inside the given {@link RequestPartitionId} correctly map to the
165         * list of partition names. If the list of partition names is empty, this method will map the correct
166         * partition names and return a normalized {@link RequestPartitionId}.
167         * <br/><br/>
168         * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}.
169         * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names.
170         */
171        RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId);
172
173        /**
174         * <b>No interceptors should be invoked by this method. It should ONLY be used when partition names are
175         * known, but partition ids are not.</b>
176         * <br/><br/>
177         * Ensures the list of partition names inside the given {@link RequestPartitionId} correctly map to the
178         * list of partition ids. If the list of partition ids is empty, this method will map the correct
179         * partition ids and return a normalized {@link RequestPartitionId}.
180         * <br/><br/>
181         * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}.
182         * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names.
183         */
184        RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId);
185}