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.dao.search; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.jpa.model.entity.ResourceTable; 024import ca.uhn.fhir.jpa.model.entity.StorageSettings; 025import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 026import ca.uhn.fhir.jpa.searchparam.util.LastNParameterHelper; 027import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; 028import com.google.gson.JsonObject; 029import org.hibernate.search.backend.elasticsearch.ElasticsearchExtension; 030import org.hibernate.search.engine.search.aggregation.AggregationKey; 031import org.hibernate.search.engine.search.query.SearchResult; 032import org.hibernate.search.mapper.orm.session.SearchSession; 033 034import java.util.List; 035import java.util.Objects; 036 037public class LastNOperation { 038 public static final String OBSERVATION_RES_TYPE = "Observation"; 039 private final SearchSession mySession; 040 private final FhirContext myFhirContext; 041 private final StorageSettings myStorageSettings; 042 private final ISearchParamRegistry mySearchParamRegistry; 043 private final ExtendedHSearchSearchBuilder myExtendedHSearchSearchBuilder = new ExtendedHSearchSearchBuilder(); 044 045 public LastNOperation( 046 SearchSession theSession, 047 FhirContext theFhirContext, 048 StorageSettings theStorageSettings, 049 ISearchParamRegistry theSearchParamRegistry) { 050 mySession = theSession; 051 myFhirContext = theFhirContext; 052 myStorageSettings = theStorageSettings; 053 mySearchParamRegistry = theSearchParamRegistry; 054 } 055 056 public List<Long> executeLastN(SearchParameterMap theParams, Integer theMaximumResults) { 057 boolean lastNGroupedBySubject = isLastNGroupedBySubject(theParams); 058 LastNAggregation lastNAggregation = 059 new LastNAggregation(getLastNMaxParamValue(theParams), lastNGroupedBySubject); 060 AggregationKey<JsonObject> observationsByCodeKey = AggregationKey.of("lastN_aggregation"); 061 062 SearchResult<ResourceTable> result = mySession 063 .search(ResourceTable.class) 064 .extension(ElasticsearchExtension.get()) 065 .where(f -> f.bool(b -> { 066 // Must match observation type 067 b.must(f.match().field("myResourceType").matching(OBSERVATION_RES_TYPE)); 068 ExtendedHSearchClauseBuilder builder = 069 new ExtendedHSearchClauseBuilder(myFhirContext, myStorageSettings, b, f); 070 myExtendedHSearchSearchBuilder.addAndConsumeAdvancedQueryClauses( 071 builder, OBSERVATION_RES_TYPE, theParams.clone(), mySearchParamRegistry); 072 })) 073 .aggregation(observationsByCodeKey, f -> f.fromJson(lastNAggregation.toAggregation())) 074 .fetch(0); 075 076 JsonObject resultAggregation = result.aggregation(observationsByCodeKey); 077 List<Long> pidList = lastNAggregation.extractResourceIds(resultAggregation); 078 if (theMaximumResults != null && theMaximumResults <= pidList.size()) { 079 return pidList.subList(0, theMaximumResults); 080 } 081 return pidList; 082 } 083 084 private boolean isLastNGroupedBySubject(SearchParameterMap theParams) { 085 String patientParamName = LastNParameterHelper.getPatientParamName(myFhirContext); 086 String subjectParamName = LastNParameterHelper.getSubjectParamName(myFhirContext); 087 return theParams.containsKey(patientParamName) || theParams.containsKey(subjectParamName); 088 } 089 090 private int getLastNMaxParamValue(SearchParameterMap theParams) { 091 return Objects.isNull(theParams.getLastNMax()) ? 1 : theParams.getLastNMax(); 092 } 093}