001/*- 002 * #%L 003 * HAPI FHIR Storage api 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.dao; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.jpa.model.search.SearchBuilderLoadIncludesParameters; 025import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails; 026import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 027import ca.uhn.fhir.model.api.Include; 028import ca.uhn.fhir.rest.api.server.RequestDetails; 029import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; 030import ca.uhn.fhir.rest.param.DateRangeParam; 031import com.google.common.collect.Streams; 032import jakarta.annotation.Nonnull; 033import jakarta.persistence.EntityManager; 034import org.apache.commons.io.IOUtils; 035import org.hl7.fhir.instance.model.api.IBaseResource; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039import java.util.ArrayList; 040import java.util.Collection; 041import java.util.List; 042import java.util.Set; 043import java.util.stream.Stream; 044 045public interface ISearchBuilder<T extends IResourcePersistentId<?>> { 046 static final Logger ourLog = LoggerFactory.getLogger(ISearchBuilder.class); 047 048 String SEARCH_BUILDER_BEAN_NAME = "SearchBuilder"; 049 050 IResultIterator<T> createQuery( 051 SearchParameterMap theParams, 052 SearchRuntimeDetails theSearchRuntime, 053 RequestDetails theRequest, 054 @Nonnull RequestPartitionId theRequestPartitionId); 055 056 /** 057 * Stream equivalent of createQuery. 058 * Note: the Stream must be closed. 059 */ 060 default Stream<T> createQueryStream( 061 SearchParameterMap theParams, 062 SearchRuntimeDetails theSearchRuntime, 063 RequestDetails theRequest, 064 @Nonnull RequestPartitionId theRequestPartitionId) { 065 IResultIterator<T> iter = createQuery(theParams, theSearchRuntime, theRequest, theRequestPartitionId); 066 // Adapt IResultIterator to stream 067 Stream<T> stream = Streams.stream(iter); 068 // The iterator might have an open ResultSet. Connect the close handler. 069 return stream.onClose(() -> IOUtils.closeQuietly(iter)); 070 } 071 072 Long createCountQuery( 073 SearchParameterMap theParams, 074 String theSearchUuid, 075 RequestDetails theRequest, 076 RequestPartitionId theRequestPartitionId); 077 078 void setMaxResultsToFetch(Integer theMaxResultsToFetch); 079 080 void setDeduplicateInDatabase(boolean theShouldDeduplicateInDB); 081 082 void setRequireTotal(boolean theRequireTotal); 083 084 /** 085 * True if the results should have a 'total' value 086 */ 087 boolean requiresTotal(); 088 089 void loadResourcesByPid( 090 Collection<T> thePids, 091 Collection<T> theIncludedPids, 092 List<IBaseResource> theResourceListToPopulate, 093 boolean theForHistoryOperation, 094 RequestDetails theDetails); 095 096 default List<IBaseResource> loadResourcesByPid(Collection<T> thePids, RequestDetails theDetails) { 097 ArrayList<IBaseResource> result = new ArrayList<>(); 098 loadResourcesByPid(thePids, List.of(), result, false, theDetails); 099 if (result.size() != thePids.size()) { 100 ourLog.warn("Only found {} resources for {} pids", result.size(), thePids.size()); 101 } 102 return result; 103 } 104 105 /** 106 * Use the loadIncludes that takes a parameters object instead. 107 */ 108 @Deprecated 109 Set<T> loadIncludes( 110 FhirContext theContext, 111 EntityManager theEntityManager, 112 Collection<T> theMatches, 113 Collection<Include> theRevIncludes, 114 boolean theReverseMode, 115 DateRangeParam theLastUpdated, 116 String theSearchIdOrDescription, 117 RequestDetails theRequest, 118 Integer theMaxCount); 119 120 default Set<T> loadIncludes(SearchBuilderLoadIncludesParameters<T> theParameters) { 121 return this.loadIncludes( 122 theParameters.getFhirContext(), 123 theParameters.getEntityManager(), 124 theParameters.getMatches(), 125 theParameters.getIncludeFilters(), 126 theParameters.isReverseMode(), 127 theParameters.getLastUpdated(), 128 theParameters.getSearchIdOrDescription(), 129 theParameters.getRequestDetails(), 130 theParameters.getMaxCount()); 131 } 132 133 /** 134 * How many results may be fetched at once 135 */ 136 void setFetchSize(int theFetchSize); 137 138 void setPreviouslyAddedResourcePids(List<T> thePreviouslyAddedResourcePids); 139}