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.search.cache;
021
022import ca.uhn.fhir.interceptor.model.RequestPartitionId;
023import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
024import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
025import ca.uhn.fhir.jpa.entity.Search;
026import ca.uhn.fhir.jpa.entity.SearchResult;
027import ca.uhn.fhir.jpa.model.dao.JpaPid;
028import ca.uhn.fhir.rest.api.server.RequestDetails;
029import com.google.common.collect.Lists;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032import org.springframework.beans.factory.annotation.Autowired;
033import org.springframework.data.domain.Pageable;
034
035import java.util.Collections;
036import java.util.List;
037
038import static ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl.toPage;
039
040public class DatabaseSearchResultCacheSvcImpl implements ISearchResultCacheSvc {
041        private static final Logger ourLog = LoggerFactory.getLogger(DatabaseSearchResultCacheSvcImpl.class);
042
043        @Autowired
044        private ISearchResultDao mySearchResultDao;
045
046        @Autowired
047        private IHapiTransactionService myTransactionService;
048
049        @Override
050        public List<JpaPid> fetchResultPids(
051                        Search theSearch,
052                        int theFrom,
053                        int theTo,
054                        RequestDetails theRequestDetails,
055                        RequestPartitionId theRequestPartitionId) {
056                return myTransactionService
057                                .withRequest(theRequestDetails)
058                                .withRequestPartitionId(theRequestPartitionId)
059                                .execute(() -> {
060                                        final Pageable page = toPage(theFrom, theTo);
061                                        if (page == null) {
062                                                return Collections.emptyList();
063                                        }
064
065                                        List<Long> retVal = mySearchResultDao
066                                                        .findWithSearchPid(theSearch.getId(), page)
067                                                        .getContent();
068
069                                        ourLog.debug("fetchResultPids for range {}-{} returned {} pids", theFrom, theTo, retVal.size());
070
071                                        return JpaPid.fromLongList(retVal);
072                                });
073        }
074
075        @Override
076        public List<JpaPid> fetchAllResultPids(
077                        Search theSearch, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
078                return myTransactionService
079                                .withRequest(theRequestDetails)
080                                .withRequestPartitionId(theRequestPartitionId)
081                                .execute(() -> {
082                                        List<Long> retVal = mySearchResultDao.findWithSearchPidOrderIndependent(theSearch.getId());
083                                        ourLog.trace("fetchAllResultPids returned {} pids", retVal.size());
084                                        return JpaPid.fromLongList(retVal);
085                                });
086        }
087
088        @Override
089        public void storeResults(
090                        Search theSearch,
091                        List<JpaPid> thePreviouslyStoredResourcePids,
092                        List<JpaPid> theNewResourcePids,
093                        RequestDetails theRequestDetails,
094                        RequestPartitionId theRequestPartitionId) {
095                myTransactionService
096                                .withRequest(theRequestDetails)
097                                .withRequestPartitionId(theRequestPartitionId)
098                                .execute(() -> {
099                                        List<SearchResult> resultsToSave = Lists.newArrayList();
100
101                                        ourLog.debug(
102                                                        "Storing {} results with {} previous for search",
103                                                        theNewResourcePids.size(),
104                                                        thePreviouslyStoredResourcePids.size());
105
106                                        int order = thePreviouslyStoredResourcePids.size();
107                                        for (JpaPid nextPid : theNewResourcePids) {
108                                                SearchResult nextResult = new SearchResult(theSearch);
109                                                nextResult.setResourcePid(nextPid.getId());
110                                                nextResult.setOrder(order);
111                                                resultsToSave.add(nextResult);
112                                                ourLog.trace("Saving ORDER[{}] Resource {}", order, nextResult.getResourcePid());
113
114                                                order++;
115                                        }
116
117                                        mySearchResultDao.saveAll(resultsToSave);
118                                });
119        }
120}