ChangeStatusPredicate: Support querying by prefix
Change-Id: Ideca3171fb215c7a37c0af5f69492d42e5fa4d3d
This commit is contained in:
@@ -79,7 +79,7 @@ public class ChangeField {
|
||||
@Override
|
||||
public String get(ChangeData input, FillArgs args)
|
||||
throws OrmException {
|
||||
return ChangeStatusPredicate.VALUES.get(
|
||||
return ChangeStatusPredicate.canonicalize(
|
||||
input.change().getStatus());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
|
||||
package com.google.gerrit.server.query.change;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Change.Status;
|
||||
import com.google.gerrit.server.index.ChangeField;
|
||||
@@ -26,6 +23,9 @@ import com.google.gwtorm.server.OrmException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Predicate for a {@link Status}.
|
||||
@@ -33,17 +33,21 @@ import java.util.List;
|
||||
* The actual name of this operator can differ, it usually comes as {@code
|
||||
* status:} but may also be {@code is:} to help do-what-i-meanery for end-users
|
||||
* searching for changes. Either operator name has the same meaning.
|
||||
* <p>
|
||||
* Status names are looked up by prefix case-insensitively.
|
||||
*/
|
||||
public final class ChangeStatusPredicate extends IndexPredicate<ChangeData> {
|
||||
public static final ImmutableBiMap<Change.Status, String> VALUES;
|
||||
private static final TreeMap<String, Change.Status> VALUES;
|
||||
|
||||
static {
|
||||
ImmutableBiMap.Builder<Change.Status, String> values =
|
||||
ImmutableBiMap.builder();
|
||||
VALUES = new TreeMap<>();
|
||||
for (Change.Status s : Change.Status.values()) {
|
||||
values.put(s, s.name().toLowerCase());
|
||||
VALUES.put(canonicalize(s), s);
|
||||
}
|
||||
VALUES = values.build();
|
||||
}
|
||||
|
||||
public static String canonicalize(Change.Status status) {
|
||||
return status.name().toLowerCase();
|
||||
}
|
||||
|
||||
public static Predicate<ChangeData> parse(String value) {
|
||||
@@ -51,11 +55,17 @@ public final class ChangeStatusPredicate extends IndexPredicate<ChangeData> {
|
||||
return open();
|
||||
} else if ("closed".equalsIgnoreCase(value)) {
|
||||
return closed();
|
||||
} else {
|
||||
Change.Status status = VALUES.inverse().get(value.toLowerCase());
|
||||
checkArgument(status != null, "invalid change status: %s", value);
|
||||
return new ChangeStatusPredicate(status);
|
||||
}
|
||||
String lower = value.toLowerCase();
|
||||
NavigableMap<String, Change.Status> head = VALUES.tailMap(lower, true);
|
||||
if (!head.isEmpty()) {
|
||||
// Assume no statuses share a common prefix so we can only walk one entry.
|
||||
Map.Entry<String, Change.Status> e = head.entrySet().iterator().next();
|
||||
if (e.getKey().startsWith(lower)) {
|
||||
return new ChangeStatusPredicate(e.getValue());
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("invalid change status: " + value);
|
||||
}
|
||||
|
||||
public static Predicate<ChangeData> open() {
|
||||
@@ -81,7 +91,7 @@ public final class ChangeStatusPredicate extends IndexPredicate<ChangeData> {
|
||||
private final Change.Status status;
|
||||
|
||||
ChangeStatusPredicate(Change.Status status) {
|
||||
super(ChangeField.STATUS, VALUES.get(status));
|
||||
super(ChangeField.STATUS, canonicalize(status));
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -29,6 +30,7 @@ import com.google.common.hash.Hashing;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||
import com.google.gerrit.extensions.api.projects.ProjectInput;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
import com.google.gerrit.lifecycle.LifecycleManager;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
@@ -262,6 +264,28 @@ public abstract class AbstractQueryChangesTest {
|
||||
assertResultEquals(change1, results.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byStatusPrefix() throws Exception {
|
||||
TestRepository<InMemoryRepository> repo = createProject("repo");
|
||||
ChangeInserter ins1 = newChange(repo, null, null, null, null);
|
||||
Change change1 = ins1.getChange();
|
||||
change1.setStatus(Change.Status.NEW);
|
||||
ins1.insert();
|
||||
ChangeInserter ins2 = newChange(repo, null, null, null, null);
|
||||
Change change2 = ins2.getChange();
|
||||
change2.setStatus(Change.Status.MERGED);
|
||||
ins2.insert();
|
||||
|
||||
assertResultEquals(change1, queryOne("status:n"));
|
||||
assertResultEquals(change1, queryOne("status:ne"));
|
||||
assertResultEquals(change1, queryOne("status:new"));
|
||||
assertResultEquals(change1, queryOne("status:N"));
|
||||
assertResultEquals(change1, queryOne("status:nE"));
|
||||
assertResultEquals(change1, queryOne("status:neW"));
|
||||
assertBadQuery("status:nx");
|
||||
assertBadQuery("status:newx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byCommit() throws Exception {
|
||||
TestRepository<InMemoryRepository> repo = createProject("repo");
|
||||
@@ -944,6 +968,15 @@ public abstract class AbstractQueryChangesTest {
|
||||
assertEquals(message, expected.getId().get(), actual._number);
|
||||
}
|
||||
|
||||
protected void assertBadQuery(Object query) throws Exception {
|
||||
try {
|
||||
query(query);
|
||||
fail("expected BadRequestException for query: " + query);
|
||||
} catch (BadRequestException e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
protected TestRepository<InMemoryRepository> createProject(String name)
|
||||
throws Exception {
|
||||
CreateProject create = projectFactory.create(name);
|
||||
|
||||
Reference in New Issue
Block a user