Add a --no-limit option to the ssh and rest query commands

This option will return all possible results and overrides the default
limit and any limit specified using "limit" query operator. This is
useful for applications that need the entire result set with a single
query. Getting data with a single query improves the accuracy since
there is less chance of the data being modified between calls.

Change-Id: Idc4dd5799195110c580c7e6d88c0a6e8c6734d6c
This commit is contained in:
Martin Fick
2018-12-02 23:34:23 -07:00
committed by Sabari Ajay Kumar
parent 36786eaf54
commit b186cd759f
11 changed files with 89 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ _ssh_ -p <port> <host> _gerrit query_
[--submit-records] [--submit-records]
[--all-reviewers] [--all-reviewers]
[--start <n> | -S <n>] [--start <n> | -S <n>]
[--no-limit]
[--] [--]
<query> <query>
[limit:<n>] [limit:<n>]
@@ -101,6 +102,9 @@ command line parser in the server).
-S:: -S::
Number of changes to skip. Number of changes to skip.
--no-limit::
Return all results, overriding the default limit.
limit:<n>:: limit:<n>::
Maximum number of results to return. This is actually a Maximum number of results to return. This is actually a
query operator, and not a command line option. If more query operator, and not a command line option. If more

View File

@@ -350,6 +350,11 @@ be recomputed often, which is slow for projects with big trees.
as link:#tracking-id-info[TrackingIdInfo]. as link:#tracking-id-info[TrackingIdInfo].
-- --
[[no-limit]]
--
* `NO-LIMIT`: Return all results
--
.Request .Request
---- ----
GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0 GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0

View File

@@ -46,6 +46,7 @@ import com.google.gerrit.common.data.LabelFunction;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelValue; import com.google.gerrit.common.data.LabelValue;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.PermissionRule.Action; import com.google.gerrit.common.data.PermissionRule.Action;
import com.google.gerrit.extensions.api.GerritApi; import com.google.gerrit.extensions.api.GerritApi;
@@ -954,6 +955,17 @@ public abstract class AbstractDaemonTest {
} }
} }
protected void allowGlobalCapabilities(
AccountGroup.UUID id, int min, int max, String... capabilityNames) throws Exception {
try (ProjectConfigUpdate u = updateProject(allProjects)) {
for (String capabilityName : capabilityNames) {
Util.allow(
u.getConfig(), capabilityName, id, new PermissionRange(capabilityName, min, max));
}
u.save();
}
}
protected void allowGlobalCapabilities(AccountGroup.UUID id, String... capabilityNames) protected void allowGlobalCapabilities(AccountGroup.UUID id, String... capabilityNames)
throws Exception { throws Exception {
allowGlobalCapabilities(id, Arrays.asList(capabilityNames)); allowGlobalCapabilities(id, Arrays.asList(capabilityNames));

View File

@@ -75,6 +75,7 @@ public interface Changes {
private String query; private String query;
private int limit; private int limit;
private int start; private int start;
private boolean isNoLimit;
private EnumSet<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class); private EnumSet<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class);
public abstract List<ChangeInfo> get() throws RestApiException; public abstract List<ChangeInfo> get() throws RestApiException;
@@ -89,6 +90,11 @@ public interface Changes {
return this; return this;
} }
public QueryRequest withNoLimit() {
this.isNoLimit = true;
return this;
}
public QueryRequest withStart(int start) { public QueryRequest withStart(int start) {
this.start = start; this.start = start;
return this; return this;
@@ -117,6 +123,10 @@ public interface Changes {
return limit; return limit;
} }
public boolean getNoLimit() {
return isNoLimit;
}
public int getStart() { public int getStart() {
return start; return start;
} }
@@ -137,7 +147,11 @@ public interface Changes {
if (!options.isEmpty()) { if (!options.isEmpty()) {
sb.append("options=").append(options); sb.append("options=").append(options);
} }
return sb.append('}').toString(); sb.append('}');
if (isNoLimit == true) {
sb.append(" --no-limit");
}
return sb.toString();
} }
} }

View File

@@ -91,6 +91,7 @@ public abstract class QueryProcessor<T> {
private boolean enforceVisibility = true; private boolean enforceVisibility = true;
private int userProvidedLimit; private int userProvidedLimit;
private boolean isNoLimit;
private Set<String> requestedFields; private Set<String> requestedFields;
protected QueryProcessor( protected QueryProcessor(
@@ -157,6 +158,11 @@ public abstract class QueryProcessor<T> {
return this; return this;
} }
public QueryProcessor<T> setNoLimit(boolean isNoLimit) {
this.isNoLimit = isNoLimit;
return this;
}
public QueryProcessor<T> setRequestedFields(Set<String> fields) { public QueryProcessor<T> setRequestedFields(Set<String> fields) {
requestedFields = fields; requestedFields = fields;
return this; return this;
@@ -354,6 +360,9 @@ public abstract class QueryProcessor<T> {
} }
private int getEffectiveLimit(Predicate<T> p) { private int getEffectiveLimit(Predicate<T> p) {
if (isNoLimit == true) {
return Integer.MAX_VALUE;
}
List<Integer> possibleLimits = new ArrayList<>(4); List<Integer> possibleLimits = new ArrayList<>(4);
possibleLimits.add(getBackendSupportedLimit()); possibleLimits.add(getBackendSupportedLimit());
possibleLimits.add(getPermittedLimit()); possibleLimits.add(getPermittedLimit());

View File

@@ -116,6 +116,7 @@ class ChangesImpl implements Changes {
} }
qc.setLimit(q.getLimit()); qc.setLimit(q.getLimit());
qc.setStart(q.getStart()); qc.setStart(q.getStart());
qc.setNoLimit(q.getNoLimit());
for (ListChangesOption option : q.getOptions()) { for (ListChangesOption option : q.getOptions()) {
qc.addOption(option); qc.addOption(option);
} }

View File

@@ -124,16 +124,28 @@ public class Util {
public static PermissionRule allow( public static PermissionRule allow(
ProjectConfig project, String capabilityName, AccountGroup.UUID group) { ProjectConfig project, String capabilityName, AccountGroup.UUID group) {
return allow(project, capabilityName, group, (PermissionRange) null);
}
public static PermissionRule allow(
ProjectConfig project,
String capabilityName,
AccountGroup.UUID group,
PermissionRange customRange) {
PermissionRule rule = newRule(project, group); PermissionRule rule = newRule(project, group);
project project
.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true) .getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true)
.getPermission(capabilityName, true) .getPermission(capabilityName, true)
.add(rule); .add(rule);
if (GlobalCapability.hasRange(capabilityName)) { if (GlobalCapability.hasRange(capabilityName)) {
PermissionRange.WithDefaults range = GlobalCapability.getRange(capabilityName); if (customRange == null) {
if (range != null) { PermissionRange.WithDefaults range = GlobalCapability.getRange(capabilityName);
rule.setRange(range.getDefaultMin(), range.getDefaultMax()); if (range != null) {
rule.setRange(range.getDefaultMin(), range.getDefaultMax());
}
return rule;
} }
rule.setRange(customRange.getMin(), customRange.getMax());
} }
return rule; return rule;
} }

View File

@@ -120,6 +120,10 @@ public class OutputStreamQuery {
queryProcessor.setUserProvidedLimit(n); queryProcessor.setUserProvidedLimit(n);
} }
public void setNoLimit(boolean on) {
queryProcessor.setNoLimit(on);
}
public void setStart(int n) { public void setStart(int n) {
queryProcessor.setStart(n); queryProcessor.setStart(n);
} }

View File

@@ -82,6 +82,11 @@ public class QueryChanges implements RestReadView<TopLevelResource>, DynamicOpti
imp.setStart(start); imp.setStart(start);
} }
@Option(name = "--no-limit", usage = "Return all results, overriding the default limit")
public void setNoLimit(boolean on) {
imp.setNoLimit(on);
}
@Override @Override
public void setDynamicBean(String plugin, DynamicOptions.DynamicBean dynamicBean) { public void setDynamicBean(String plugin, DynamicOptions.DynamicBean dynamicBean) {
imp.setDynamicBean(plugin, dynamicBean); imp.setDynamicBean(plugin, dynamicBean);

View File

@@ -91,6 +91,11 @@ public class Query extends SshCommand implements DynamicOptions.BeanReceiver {
processor.setStart(start); processor.setStart(start);
} }
@Option(name = "--no-limit", usage = "Return all results, overriding the default limit")
void setNoLimit(boolean on) {
processor.setNoLimit(on);
}
@Argument( @Argument(
index = 0, index = 0,
required = true, required = true,

View File

@@ -71,6 +71,7 @@ import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.group.GroupOperations; import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.common.FooterConstants; import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.LabelFunction; import com.google.gerrit.common.data.LabelFunction;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
@@ -2553,6 +2554,19 @@ public class ChangeIT extends AbstractDaemonTest {
assertThat(Iterables.getOnlyElement(results).changeId).isEqualTo(r2.getChangeId()); assertThat(Iterables.getOnlyElement(results).changeId).isEqualTo(r2.getChangeId());
} }
@Test
public void queryChangesNoLimit() throws Exception {
allowGlobalCapabilities(
SystemGroupBackend.REGISTERED_USERS, 0, 2, GlobalCapability.QUERY_LIMIT);
for (int i = 0; i < 3; i++) {
createChange();
}
List<ChangeInfo> resultsWithDefaultLimit = gApi.changes().query().get();
List<ChangeInfo> resultsWithNoLimit = gApi.changes().query().withNoLimit().get();
assertThat(resultsWithDefaultLimit).hasSize(2);
assertThat(resultsWithNoLimit.size()).isAtLeast(3);
}
@Test @Test
public void queryChangesStart() throws Exception { public void queryChangesStart() throws Exception {
PushOneCommit.Result r1 = createChange(); PushOneCommit.Result r1 = createChange();