001/*-
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2025 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.search;
021
022import ca.uhn.fhir.interceptor.model.RequestPartitionId;
023import ca.uhn.fhir.jpa.config.JpaConfig;
024import ca.uhn.fhir.jpa.dao.ISearchBuilder;
025import ca.uhn.fhir.jpa.entity.Search;
026import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
027import ca.uhn.fhir.jpa.model.dao.JpaPid;
028import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
029import ca.uhn.fhir.jpa.search.builder.tasks.SearchTask;
030import ca.uhn.fhir.rest.api.server.IBundleProvider;
031import ca.uhn.fhir.rest.api.server.RequestDetails;
032import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
033import ca.uhn.fhir.rest.param.HistorySearchStyleEnum;
034import jakarta.annotation.Nonnull;
035import jakarta.annotation.Nullable;
036import org.springframework.beans.factory.annotation.Autowired;
037import org.springframework.context.ApplicationContext;
038
039import java.util.Date;
040import java.util.List;
041import java.util.UUID;
042
043import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
044
045public class PersistedJpaBundleProviderFactory {
046
047        @Autowired
048        private ApplicationContext myApplicationContext;
049
050        public PersistedJpaBundleProvider newInstance(RequestDetails theRequest, String theUuid) {
051                Object retVal = myApplicationContext.getBean(JpaConfig.PERSISTED_JPA_BUNDLE_PROVIDER, theRequest, theUuid);
052                return (PersistedJpaBundleProvider) retVal;
053        }
054
055        public PersistedJpaBundleProvider newInstance(RequestDetails theRequest, Search theSearch) {
056                Object retVal =
057                                myApplicationContext.getBean(JpaConfig.PERSISTED_JPA_BUNDLE_PROVIDER_BY_SEARCH, theRequest, theSearch);
058                return (PersistedJpaBundleProvider) retVal;
059        }
060
061        public PersistedJpaSearchFirstPageBundleProvider newInstanceFirstPage(
062                        RequestDetails theRequestDetails,
063                        SearchTask theTask,
064                        ISearchBuilder<JpaPid> theSearchBuilder,
065                        RequestPartitionId theRequestPartitionId) {
066                return (PersistedJpaSearchFirstPageBundleProvider) myApplicationContext.getBean(
067                                JpaConfig.PERSISTED_JPA_SEARCH_FIRST_PAGE_BUNDLE_PROVIDER,
068                                theRequestDetails,
069                                theTask,
070                                theSearchBuilder,
071                                theRequestPartitionId);
072        }
073
074        public IBundleProvider history(
075                        RequestDetails theRequest,
076                        String theResourceType,
077                        @Nullable JpaPid theResourcePid,
078                        Date theRangeStartInclusive,
079                        Date theRangeEndInclusive,
080                        Integer theOffset,
081                        RequestPartitionId theRequestPartitionId) {
082                return history(
083                                theRequest,
084                                theResourceType,
085                                theResourcePid,
086                                theRangeStartInclusive,
087                                theRangeEndInclusive,
088                                theOffset,
089                                null,
090                                theRequestPartitionId);
091        }
092
093        public IBundleProvider history(
094                        RequestDetails theRequest,
095                        String theResourceType,
096                        @Nullable JpaPid theResourcePid,
097                        Date theRangeStartInclusive,
098                        Date theRangeEndInclusive,
099                        Integer theOffset,
100                        HistorySearchStyleEnum searchParameterType,
101                        RequestPartitionId theRequestPartitionId) {
102                String resourceName = defaultIfBlank(theResourceType, null);
103
104                Search search = new Search();
105                search.setOffset(theOffset);
106                search.setDeleted(false);
107                search.setCreated(new Date());
108                search.setLastUpdated(theRangeStartInclusive, theRangeEndInclusive);
109                search.setUuid(UUID.randomUUID().toString());
110                search.setResourceType(resourceName);
111                search.setResourceId(theResourcePid);
112                search.setSearchType(SearchTypeEnum.HISTORY);
113                search.setStatus(SearchStatusEnum.FINISHED);
114                search.setHistorySearchStyle(searchParameterType);
115
116                PersistedJpaBundleProvider provider = newInstance(theRequest, search);
117                provider.setRequestPartitionId(theRequestPartitionId);
118
119                return provider;
120        }
121
122        /**
123         * Create an unlimited history bundle provider for bulk export operations
124         * that can paginate through history entries for specific resource IDs.
125         */
126        public IBundleProvider historyFromResourceIds(
127                        String theResourceType,
128                        @Nullable List<IResourcePersistentId<?>> theResourceIds,
129                        RequestPartitionId theRequestPartitionId,
130                        @Nullable Date theRangeStartInclusive,
131                        @Nonnull Date theRangeEndInclusive) {
132
133                return (PersistedJpaIdSearchBundleProvider) myApplicationContext.getBean(
134                                JpaConfig.PERSISTED_JPA_ID_SEARCH_BUNDLE_PROVIDER,
135                                theResourceType,
136                                theResourceIds,
137                                theRequestPartitionId,
138                                theRangeStartInclusive,
139                                theRangeEndInclusive);
140        }
141}