001/*- 002 * #%L 003 * HAPI FHIR JPA Server - Master Data Management 004 * %% 005 * Copyright (C) 2014 - 2023 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.mdm.svc.candidate; 021 022import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson; 023import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc; 024import ca.uhn.fhir.util.UrlUtil; 025import org.hl7.fhir.instance.model.api.IAnyResource; 026import org.springframework.beans.factory.annotation.Autowired; 027import org.springframework.stereotype.Service; 028 029import java.util.ArrayList; 030import java.util.List; 031import java.util.Optional; 032import java.util.stream.Collectors; 033import javax.annotation.Nonnull; 034import javax.annotation.Nullable; 035 036@Service 037public class MdmCandidateSearchCriteriaBuilderSvc { 038 039 @Autowired 040 private MdmSearchParamSvc myMdmSearchParamSvc; 041 042 /* 043 * Given a list of criteria upon which to block, a resource search parameter, and a list of values for that given search parameter, 044 * build a query url. e.g. 045 * 046 * Patient?active=true&name.given=Gary,Grant&name.family=Graham 047 */ 048 @Nonnull 049 public Optional<String> buildResourceQueryString( 050 String theResourceType, 051 IAnyResource theResource, 052 List<String> theFilterCriteria, 053 @Nullable MdmResourceSearchParamJson resourceSearchParam) { 054 List<String> criteria = new ArrayList<>(); 055 056 // If there are candidate search params, then make use of them, otherwise, search with only the filters. 057 if (resourceSearchParam != null) { 058 resourceSearchParam.iterator().forEachRemaining(searchParam -> { 059 // to compare it to all known GOLDEN_RESOURCE objects, using the overlapping search parameters that they 060 // have. 061 List<String> valuesFromResourceForSearchParam = 062 myMdmSearchParamSvc.getValueFromResourceForSearchParam(theResource, searchParam); 063 if (!valuesFromResourceForSearchParam.isEmpty()) { 064 criteria.add(buildResourceMatchQuery(searchParam, valuesFromResourceForSearchParam)); 065 } 066 }); 067 if (criteria.isEmpty()) { 068 // TODO GGG/KHS, re-evaluate whether we should early drop here. 069 return Optional.empty(); 070 } 071 } 072 073 criteria.addAll(theFilterCriteria); 074 return Optional.of(theResourceType + "?" + String.join("&", criteria)); 075 } 076 077 private String buildResourceMatchQuery(String theSearchParamName, List<String> theResourceValues) { 078 String nameValueOrList = 079 theResourceValues.stream().map(UrlUtil::escapeUrlParam).collect(Collectors.joining(",")); 080 return theSearchParamName + "=" + nameValueOrList; 081 } 082}