Skip to content

Commit

Permalink
Allow for _total parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesagnew committed Oct 17, 2018
1 parent a0333a4 commit 99cd4ce
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ public class Constants {
* This is provided for testing only! Use with caution as this property may change.
*/
public static final String TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS = "TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS";
public static final String PARAM_SEARCH_TOTAL_MODE = "_total";

static {
CHARSET_UTF8 = Charset.forName(CHARSET_NAME_UTF8);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ca.uhn.fhir.rest.api;

import java.util.HashMap;
import java.util.Map;

public enum SearchTotalModeEnum {

NONE("none"),
ESTIMATED("estimated"),
ACCURATE("accurate");

private static volatile Map<String, SearchTotalModeEnum> ourCodeToEnum;
private final String myCode;

SearchTotalModeEnum(String theCode) {
myCode = theCode;
}

public String getCode() {
return myCode;
}

public static SearchTotalModeEnum fromCode(String theCode) {
Map<String, SearchTotalModeEnum> map = ourCodeToEnum;
if (map == null) {
map = new HashMap<>();
for (SearchTotalModeEnum next : values()) {
map.put(next.getCode(), next);
}
ourCodeToEnum = map;
}
return map.get(theCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public String getCode() {
public static SummaryEnum fromCode(String theCode) {
Map<String, SummaryEnum> c2s = ourCodeToSummary;
if (c2s == null) {
c2s = new HashMap<String, SummaryEnum>();
c2s = new HashMap<>();
for (SummaryEnum next : values()) {
c2s.put(next.getCode(), next);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,6 @@ public interface IClientExecutable<T extends IClientExecutable<?,Y>, Y> {
/**
* Request that the server modify the response using the <code>_summary</code> param
*/
T summaryMode(SummaryEnum... theSummary);
T summaryMode(SummaryEnum theSummary);

}
10 changes: 10 additions & 0 deletions hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/IQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import org.hl7.fhir.instance.model.api.IBaseBundle;

Expand Down Expand Up @@ -80,6 +82,14 @@ public interface IQuery<Y> extends IBaseQuery<IQuery<Y>>, IClientExecutable<IQue
*/
<B extends IBaseBundle> IQuery<B> returnBundle(Class<B> theClass);

/**
* Request that the server modify the response using the <code>_total</code> param
*
* THIS IS AN EXPERIMENTAL FEATURE - Use with caution, as it may be
* removed or modified in a future version.
*/
IQuery<Y> totalMode(SearchTotalModeEnum theTotalMode);

/**
* Add a "_revinclude" specification
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ <T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, Ba
}

<T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint,
boolean theLogRequestAndResponse, List<SummaryEnum> theSummaryMode, Set<String> theSubsetElements, CacheControlDirective theCacheControlDirective) {
boolean theLogRequestAndResponse, SummaryEnum theSummaryMode, Set<String> theSubsetElements, CacheControlDirective theCacheControlDirective) {

if (!myDontValidateConformance) {
myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this);
Expand All @@ -227,8 +227,7 @@ <T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, Ba
}

if (theSummaryMode != null) {
List<String> summaryModeStrings = theSummaryMode.stream().map(SummaryEnum::getCode).collect(Collectors.toList());;
params.put(Constants.PARAM_SUMMARY, summaryModeStrings);
params.put(Constants.PARAM_SUMMARY, Collections.singletonList(theSummaryMode.getCode()));
} else if (mySummary != null) {
params.put(Constants.PARAM_SUMMARY, Collections.singletonList(mySummary.getCode()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public IDelete delete() {
}

private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdType theId, boolean theVRead, ICallable<T> theNotModifiedHandler, String theIfVersionMatches, Boolean thePrettyPrint,
List<SummaryEnum> theSummary, EncodingEnum theEncoding, Set<String> theSubsetElements) {
SummaryEnum theSummary, EncodingEnum theEncoding, Set<String> theSubsetElements) {
String resName = toResourceName(theType);
IIdType id = theId;
if (!id.hasBaseUrl()) {
Expand Down Expand Up @@ -127,8 +127,8 @@ private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdTyp
invocation.addHeader(Constants.HEADER_IF_NONE_MATCH, '"' + theIfVersionMatches + '"');
}

boolean allowHtmlResponse = (theSummary != null && theSummary.contains(SummaryEnum.TEXT)) || (theSummary == null && getSummary() == SummaryEnum.TEXT);
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, (Class<? extends IBaseResource>) null, id, allowHtmlResponse);
boolean allowHtmlResponse = SummaryEnum.TEXT.equals(theSummary);
ResourceResponseHandler<T> binding = new ResourceResponseHandler<>(theType, (Class<? extends IBaseResource>) null, id, allowHtmlResponse);

if (theNotModifiedHandler == null) {
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements, null);
Expand Down Expand Up @@ -368,7 +368,7 @@ private abstract class BaseClientExecutable<T extends IClientExecutable<?, Y>, Y

protected EncodingEnum myParamEncoding;
protected Boolean myPrettyPrint;
protected List<SummaryEnum> mySummaryMode;
protected SummaryEnum mySummaryMode;
protected CacheControlDirective myCacheControlDirective;
private List<Class<? extends IBaseResource>> myPreferResponseTypes;
private boolean myQueryLogRequestAndResponse;
Expand Down Expand Up @@ -483,15 +483,8 @@ public T prettyPrint() {

@SuppressWarnings("unchecked")
@Override
public T summaryMode(SummaryEnum... theSummary) {
mySummaryMode = null;
if (theSummary != null) {
if (theSummary.length == 1) {
mySummaryMode = Collections.singletonList(theSummary[0]);
} else {
mySummaryMode = Arrays.asList(theSummary);
}
}
public T summaryMode(SummaryEnum theSummary) {
mySummaryMode = theSummary;
return ((T) this);
}

Expand Down Expand Up @@ -1657,20 +1650,21 @@ public List<IBaseResource> invokeClient(String theResponseMimeType, Reader theRe
private class SearchInternal<OUTPUT> extends BaseSearch<IQuery<OUTPUT>, IQuery<OUTPUT>, OUTPUT> implements IQuery<OUTPUT>, IUntypedQuery<IQuery<OUTPUT>> {

private String myCompartmentName;
private List<Include> myInclude = new ArrayList<Include>();
private List<Include> myInclude = new ArrayList<>();
private DateRangeParam myLastUpdated;
private Integer myParamLimit;
private List<Collection<String>> myProfiles = new ArrayList<Collection<String>>();
private List<Collection<String>> myProfiles = new ArrayList<>();
private String myResourceId;
private String myResourceName;
private Class<? extends IBaseResource> myResourceType;
private Class<? extends IBaseBundle> myReturnBundleType;
private List<Include> myRevInclude = new ArrayList<Include>();
private List<Include> myRevInclude = new ArrayList<>();
private SearchStyleEnum mySearchStyle;
private String mySearchUrl;
private List<TokenParam> mySecurity = new ArrayList<TokenParam>();
private List<SortInternal> mySort = new ArrayList<SortInternal>();
private List<TokenParam> myTags = new ArrayList<TokenParam>();
private List<TokenParam> mySecurity = new ArrayList<>();
private List<SortInternal> mySort = new ArrayList<>();
private List<TokenParam> myTags = new ArrayList<>();
private SearchTotalModeEnum myTotalMode;

public SearchInternal() {
myResourceType = null;
Expand Down Expand Up @@ -1792,6 +1786,10 @@ public OUTPUT execute() {
}
}

if (myTotalMode != null) {
addParam(params, Constants.PARAM_SEARCH_TOTAL_MODE, myTotalMode.getCode());
}

IClientResponseHandler<? extends IBase> binding;
binding = new ResourceResponseHandler(myReturnBundleType, getPreferResponseTypes(myResourceType));

Expand Down Expand Up @@ -1843,6 +1841,12 @@ public IQuery limitTo(int theLimitTo) {
return count(theLimitTo);
}

@Override
public IQuery<OUTPUT> totalMode(SearchTotalModeEnum theSearchTotalModeEnum) {
myTotalMode = theSearchTotalModeEnum;
return this;
}

@Override
public IQuery returnBundle(Class theClass) {
if (theClass == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.util.ObjectUtil;
Expand All @@ -31,9 +28,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -54,7 +51,8 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
private Integer myLoadSynchronousUpTo;
private Set<Include> myRevIncludes;
private SortSpec mySort;
private Set<SummaryEnum> mySummaryMode;
private SummaryEnum mySummaryMode;
private SearchTotalModeEnum mySearchTotalMode;

/**
* Constructor
Expand All @@ -70,20 +68,22 @@ public SearchParameterMap(String theName, IQueryParameterType theParam) {
add(theName, theParam);
}

/**
* @return An unmodifiable set
*/
public Set<SummaryEnum> getSummaryMode() {
if (mySummaryMode == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(mySummaryMode);
public SummaryEnum getSummaryMode() {
return mySummaryMode;
}

public void setSummaryMode(Set<SummaryEnum> theSummaryMode) {
public void setSummaryMode(SummaryEnum theSummaryMode) {
mySummaryMode = theSummaryMode;
}

public SearchTotalModeEnum getSearchTotalMode() {
return mySearchTotalMode;
}

public void setSearchTotalMode(SearchTotalModeEnum theSearchTotalMode) {
mySearchTotalMode = theSearchTotalMode;
}

public SearchParameterMap add(String theName, DateParam theDateParam) {
add(theName, (IQueryParameterOr<?>) theDateParam);
return this;
Expand Down Expand Up @@ -261,7 +261,7 @@ public void setSort(SortSpec theSort) {
/**
* This will only return true if all parameters have no modifier of any kind
*/
public boolean isAllParametersHaveNoModifier() {
boolean isAllParametersHaveNoModifier() {
for (List<List<? extends IQueryParameterType>> nextParamName : values()) {
for (List<? extends IQueryParameterType> nextAnd : nextParamName) {
for (IQueryParameterType nextOr : nextAnd) {
Expand Down Expand Up @@ -408,12 +408,10 @@ public String toNormalizedQueryString(FhirContext theCtx) {

// Summary
if (getSummaryMode() != null) {
for (SummaryEnum next : getSummaryMode()) {
addUrlParamSeparator(b);
b.append(Constants.PARAM_SUMMARY);
b.append('=');
b.append(next.getCode());
}
addUrlParamSeparator(b);
b.append(Constants.PARAM_SUMMARY);
b.append('=');
b.append(getSummaryMode().getCode());
}

if (b.length() == 0) {
Expand Down Expand Up @@ -489,7 +487,7 @@ public int compare(Include theO1, Include theO2) {
public class QueryParameterOrComparator implements Comparator<List<IQueryParameterType>> {
private final FhirContext myCtx;

public QueryParameterOrComparator(FhirContext theCtx) {
QueryParameterOrComparator(FhirContext theCtx) {
myCtx = theCtx;
}

Expand All @@ -505,7 +503,7 @@ public class QueryParameterTypeComparator implements Comparator<IQueryParameterT

private final FhirContext myCtx;

public QueryParameterTypeComparator(FhirContext theCtx) {
QueryParameterTypeComparator(FhirContext theCtx) {
myCtx = theCtx;
}

Expand All @@ -516,7 +514,7 @@ public int compare(IQueryParameterType theO1, IQueryParameterType theO2) {

}

static int compare(FhirContext theCtx, IQueryParameterType theO1, IQueryParameterType theO2) {
private static int compare(FhirContext theCtx, IQueryParameterType theO1, IQueryParameterType theO2) {
int retVal;
if (theO1.getMissing() == null && theO2.getMissing() == null) {
retVal = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IPagingProvider;
Expand Down Expand Up @@ -724,8 +725,8 @@ private void doSearch() {
*
* before doing anything else.
*/
boolean wantCount = myParams.getSummaryMode().contains(SummaryEnum.COUNT);
boolean wantOnlyCount = wantCount && myParams.getSummaryMode().size() == 1;
boolean wantOnlyCount = SummaryEnum.COUNT.equals(myParams.getSummaryMode());
boolean wantCount = wantOnlyCount || SearchTotalModeEnum.ACCURATE.equals(myParams.getSearchTotalMode());
if (wantCount) {
ourLog.trace("Performing count");
ISearchBuilder sb = newSearchBuilder();
Expand Down

0 comments on commit 99cd4ce

Please sign in to comment.