001/*- 002 * #%L 003 * Smile CDR - CDR 004 * %% 005 * Copyright (C) 2016 - 2024 Smile CDR, Inc. 006 * %% 007 * All rights reserved. 008 * #L% 009 */ 010package ca.cdr.api.fhirgw.model; 011 012import ca.uhn.fhir.model.api.Include; 013import ca.uhn.fhir.rest.api.SearchStyleEnum; 014import ca.uhn.fhir.rest.api.SearchTotalModeEnum; 015import ca.uhn.fhir.rest.api.SortSpec; 016import ca.uhn.fhir.rest.param.DateRangeParam; 017import ca.uhn.fhir.rest.param.UriAndListParam; 018import ca.uhn.fhir.rest.param.UriOrListParam; 019import com.google.common.collect.ArrayListMultimap; 020import com.google.common.collect.ListMultimap; 021import com.google.common.collect.Multimap; 022import com.google.common.collect.Multimaps; 023import jakarta.annotation.Nonnull; 024import jakarta.annotation.Nullable; 025import org.apache.commons.lang3.Validate; 026 027import java.util.Collections; 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 034 035/** 036 * This class represents a FHIR Gateway Search request 037 */ 038public class SearchRequest extends BaseRequest<SearchRequest> { 039 040 private ListMultimap<String, String> myParameters = EMPTY_STRING_MULTIMAP; 041 private Set<Include> myIncludes = Collections.emptySet(); 042 private Set<Include> myRevIncludes = Collections.emptySet(); 043 private SortSpec mySort; 044 private Integer myCount; 045 private SearchTotalModeEnum myTotalMode; 046 private Integer myOffset; 047 private DateRangeParam myLastUpdated; 048 private UriAndListParam myProfile; 049 050 @Nullable 051 private SearchStyleEnum mySearchStyle; 052 053 /** 054 * Constructor 055 */ 056 public SearchRequest() { 057 // nothing 058 } 059 060 /** 061 * Copy constructor 062 */ 063 public SearchRequest(SearchRequest theSearchRequest) { 064 super(theSearchRequest); 065 066 if (!theSearchRequest.getParameters().isEmpty()) { 067 myParameters = ArrayListMultimap.create(); 068 myParameters.putAll(theSearchRequest.getParameters()); 069 } 070 071 if (!theSearchRequest.getIncludes().isEmpty()) { 072 myIncludes = new HashSet<>(); 073 for (Include next : theSearchRequest.getIncludes()) { 074 myIncludes.add(next.toLocked()); 075 } 076 } 077 078 if (!theSearchRequest.getRevIncludes().isEmpty()) { 079 myRevIncludes = new HashSet<>(); 080 for (Include next : theSearchRequest.getRevIncludes()) { 081 myRevIncludes.add(next.toLocked()); 082 } 083 } 084 085 if (theSearchRequest.getSort() != null) { 086 mySort = clone(theSearchRequest.getSort()); 087 } 088 089 if (theSearchRequest.getLastUpdated() != null) { 090 myLastUpdated = new DateRangeParam( 091 theSearchRequest.getLastUpdated().getLowerBound() != null 092 ? theSearchRequest.getLastUpdated().getLowerBound().getValueAsString() 093 : null, 094 theSearchRequest.getLastUpdated().getUpperBound() != null 095 ? theSearchRequest.getLastUpdated().getUpperBound().getValueAsString() 096 : null); 097 } 098 099 if (theSearchRequest.getProfile() != null) { 100 myProfile = new UriAndListParam(); 101 for (UriOrListParam uriOrListParam : theSearchRequest.getProfile().getValuesAsQueryTokens()) { 102 myProfile.addAnd(uriOrListParam); 103 } 104 } 105 106 myCount = theSearchRequest.getCount(); 107 myOffset = theSearchRequest.getOffset(); 108 myTotalMode = theSearchRequest.getTotalMode(); 109 } 110 111 private static SortSpec clone(SortSpec theSort) { 112 if (theSort == null) { 113 return null; 114 } 115 return new SortSpec(theSort.getParamName(), theSort.getOrder(), clone(theSort.getChain())); 116 } 117 118 /** 119 * Specifies the search form (GET vs POST) to use for this search. If set to 120 * <code>null</code>, the default will be used. 121 */ 122 @Nullable 123 public SearchStyleEnum getSearchStyle() { 124 return mySearchStyle; 125 } 126 127 /** 128 * Specifies the search form (GET vs POST) to use for this search. If set to 129 * <code>null</code>, the default will be used. 130 */ 131 public void setSearchStyle(@Nullable SearchStyleEnum theSearchStyle) { 132 mySearchStyle = theSearchStyle; 133 } 134 135 public Multimap<String, String> getParameters() { 136 return Multimaps.unmodifiableMultimap(myParameters); 137 } 138 139 public SearchRequest setParameters(Map<String, List<String>> theParameters) { 140 Validate.notNull(theParameters, "theParameters must not be null"); 141 myParameters = ArrayListMultimap.create(); 142 for (Map.Entry<String, List<String>> next : theParameters.entrySet()) { 143 myParameters.putAll(next.getKey(), next.getValue()); 144 } 145 return this; 146 } 147 148 /** 149 * Remove all parameters with the given name 150 * 151 * @return Returns any parameter values that were removed 152 */ 153 public List<String> removeParameters(String theName) { 154 if (!myParameters.isEmpty()) { 155 return Collections.unmodifiableList(myParameters.removeAll(theName)); 156 } else { 157 return Collections.emptyList(); 158 } 159 } 160 161 /** 162 * Remove the parameter with the given name and value, if found. Any other parameters with the same name are kept. 163 * 164 * @param theName The parameter name 165 * @param theValue The parameter value 166 * @return Returns <code>true</code> if a parameter value was removed 167 */ 168 public boolean removeParameter(String theName, String theValue) { 169 return myParameters.remove(theName, theValue); 170 } 171 172 /** 173 * Returns the first parameter value for a given parameter name (returns <code>null</code> if no parameters match the given name) 174 * 175 * @param theName The parameter name 176 * @return The value, or <code>null</code> 177 */ 178 @Nullable 179 public String getParameter(String theName) { 180 List<String> values = getParameters(theName); 181 if (!values.isEmpty()) { 182 return values.get(0); 183 } 184 return null; 185 } 186 187 /** 188 * Returns a List of parameter values for the given name. Will not return <code>null</code>. 189 * 190 * @param theName The parameter name 191 * @return A List of values, or an empty List 192 */ 193 @Nonnull 194 public List<String> getParameters(String theName) { 195 List<String> values = myParameters.get(theName); 196 values = defaultIfNull(values, Collections.emptyList()); 197 return Collections.unmodifiableList(values); 198 } 199 200 public Set<Include> getIncludes() { 201 return myIncludes; 202 } 203 204 public SearchRequest setIncludes(Set<Include> theIncludes) { 205 Validate.notNull(theIncludes, "theIncludes must not be null"); 206 myIncludes = theIncludes; 207 return this; 208 } 209 210 public Set<Include> getRevIncludes() { 211 return myRevIncludes; 212 } 213 214 public SearchRequest setRevIncludes(Set<Include> theRevIncludes) { 215 Validate.notNull(theRevIncludes, "theRevIncludes must not be null"); 216 myRevIncludes = theRevIncludes; 217 return this; 218 } 219 220 public SortSpec getSort() { 221 return mySort; 222 } 223 224 public SearchRequest setSort(SortSpec theSort) { 225 mySort = theSort; 226 return this; 227 } 228 229 public Integer getCount() { 230 return myCount; 231 } 232 233 public SearchRequest setCount(Integer theCount) { 234 myCount = theCount; 235 return this; 236 } 237 238 public Integer getOffset() { 239 return myOffset; 240 } 241 242 public SearchRequest setOffset(Integer theOffset) { 243 myOffset = theOffset; 244 return this; 245 } 246 247 public DateRangeParam getLastUpdated() { 248 return myLastUpdated; 249 } 250 251 public SearchRequest setLastUpdated(DateRangeParam theLastUpdated) { 252 myLastUpdated = theLastUpdated; 253 return this; 254 } 255 256 public UriAndListParam getProfile() { 257 return myProfile; 258 } 259 260 public SearchRequest setProfile(UriAndListParam theProfile) { 261 myProfile = theProfile; 262 return this; 263 } 264 265 public SearchTotalModeEnum getTotalMode() { 266 return myTotalMode; 267 } 268 269 public SearchRequest setTotalMode(SearchTotalModeEnum theTotalMode) { 270 myTotalMode = theTotalMode; 271 return this; 272 } 273 274 /** 275 * Add a new search parameter 276 */ 277 public void addParameter(String theName, String theValue) { 278 Validate.notBlank(theName, "theName must not be empty"); 279 Validate.notBlank(theValue, "theValue must not be empty"); 280 if (myParameters.isEmpty()) { 281 myParameters = ArrayListMultimap.create(); 282 } 283 myParameters.put(theName, theValue); 284 } 285}