Support alias "self" in queries
Writing an expression like "owner:self status:open" will now identify changes that the caller owns and are still open. This self alias is valid in contexts where a user is expected as an argument to a query operator. Change-Id: I87e58dda43d8da560b31400f1257857b0ea96175
This commit is contained in:
@@ -75,7 +75,8 @@ Change-Id that was scraped out of the commit message.
|
|||||||
[[owner]]
|
[[owner]]
|
||||||
owner:'USER'::
|
owner:'USER'::
|
||||||
+
|
+
|
||||||
Changes originally submitted by 'USER'.
|
Changes originally submitted by 'USER'. The special case of
|
||||||
|
`owner:self` will find changes owned by the caller.
|
||||||
|
|
||||||
[[ownerin]]
|
[[ownerin]]
|
||||||
ownerin:'GROUP'::
|
ownerin:'GROUP'::
|
||||||
@@ -85,7 +86,9 @@ Changes originally submitted by a user in 'GROUP'.
|
|||||||
[[reviewer]]
|
[[reviewer]]
|
||||||
reviewer:'USER'::
|
reviewer:'USER'::
|
||||||
+
|
+
|
||||||
Changes that have been, or need to be, reviewed by 'USER'.
|
Changes that have been, or need to be, reviewed by 'USER'. The
|
||||||
|
special case of `reviewer:self` will find changes where the caller
|
||||||
|
has been added as a reviewer.
|
||||||
|
|
||||||
[[reviewerin]]
|
[[reviewerin]]
|
||||||
reviewerin:'GROUP'::
|
reviewerin:'GROUP'::
|
||||||
@@ -213,6 +216,16 @@ is:reviewed::
|
|||||||
True if there is at least one non-zero score on the change, in any
|
True if there is at least one non-zero score on the change, in any
|
||||||
approval category, by any user.
|
approval category, by any user.
|
||||||
|
|
||||||
|
is:owner::
|
||||||
|
+
|
||||||
|
True on any change where the current user is the change owner.
|
||||||
|
Same as `owner:self`.
|
||||||
|
|
||||||
|
is:reviewer::
|
||||||
|
+
|
||||||
|
True on any change where the current user is a reviewer.
|
||||||
|
Same as `reviewer:self`.
|
||||||
|
|
||||||
is:open::
|
is:open::
|
||||||
+
|
+
|
||||||
True if the change is other open or submitted, merge pending.
|
True if the change is other open or submitted, merge pending.
|
||||||
@@ -373,16 +386,20 @@ the change. This flag is always added to any query.
|
|||||||
starredby:'USER'::
|
starredby:'USER'::
|
||||||
+
|
+
|
||||||
Matches changes that have been starred by 'USER'.
|
Matches changes that have been starred by 'USER'.
|
||||||
|
The special case `starredby:self` applies to the caller.
|
||||||
|
|
||||||
watchedby:'USER'::
|
watchedby:'USER'::
|
||||||
+
|
+
|
||||||
Matches changes that 'USER' has configured watch filters for.
|
Matches changes that 'USER' has configured watch filters for.
|
||||||
|
The special case `watchedby:self` applies to the caller.
|
||||||
|
|
||||||
draftby:'USER'::
|
draftby:'USER'::
|
||||||
+
|
+
|
||||||
Matches changes that 'USER' has left unpublished drafts on.
|
Matches changes that 'USER' has left unpublished drafts on.
|
||||||
Since the drafts are unpublished, it is not possible to see the
|
Since the drafts are unpublished, it is not possible to see the
|
||||||
draft text, or even how many drafts there are.
|
draft text, or even how many drafts there are. The special case
|
||||||
|
of `draftby:self` will find changes where the caller has created
|
||||||
|
a draft comment.
|
||||||
|
|
||||||
limit:'CNT'::
|
limit:'CNT'::
|
||||||
+
|
+
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.query;
|
package com.google.gerrit.server.query;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -44,23 +45,35 @@ import java.util.List;
|
|||||||
public abstract class Predicate<T> {
|
public abstract class Predicate<T> {
|
||||||
/** Combine the passed predicates into a single AND node. */
|
/** Combine the passed predicates into a single AND node. */
|
||||||
public static <T> Predicate<T> and(final Predicate<T>... that) {
|
public static <T> Predicate<T> and(final Predicate<T>... that) {
|
||||||
|
if (that.length == 1) {
|
||||||
|
return that[0];
|
||||||
|
}
|
||||||
return new AndPredicate<T>(that);
|
return new AndPredicate<T>(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Combine the passed predicates into a single AND node. */
|
/** Combine the passed predicates into a single AND node. */
|
||||||
public static <T> Predicate<T> and(
|
public static <T> Predicate<T> and(
|
||||||
final Collection<? extends Predicate<T>> that) {
|
final Collection<? extends Predicate<T>> that) {
|
||||||
|
if (that.size() == 1) {
|
||||||
|
return Iterables.getOnlyElement(that);
|
||||||
|
}
|
||||||
return new AndPredicate<T>(that);
|
return new AndPredicate<T>(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Combine the passed predicates into a single OR node. */
|
/** Combine the passed predicates into a single OR node. */
|
||||||
public static <T> Predicate<T> or(final Predicate<T>... that) {
|
public static <T> Predicate<T> or(final Predicate<T>... that) {
|
||||||
|
if (that.length == 1) {
|
||||||
|
return that[0];
|
||||||
|
}
|
||||||
return new OrPredicate<T>(that);
|
return new OrPredicate<T>(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Combine the passed predicates into a single OR node. */
|
/** Combine the passed predicates into a single OR node. */
|
||||||
public static <T> Predicate<T> or(
|
public static <T> Predicate<T> or(
|
||||||
final Collection<? extends Predicate<T>> that) {
|
final Collection<? extends Predicate<T>> that) {
|
||||||
|
if (that.size() == 1) {
|
||||||
|
return Iterables.getOnlyElement(that);
|
||||||
|
}
|
||||||
return new OrPredicate<T>(that);
|
return new OrPredicate<T>(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.query.change;
|
package com.google.gerrit.server.query.change;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gerrit.common.data.ApprovalTypes;
|
import com.google.gerrit.common.data.ApprovalTypes;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||||
@@ -44,6 +45,7 @@ import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -206,10 +208,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ("draft".equalsIgnoreCase(value)) {
|
if ("draft".equalsIgnoreCase(value)) {
|
||||||
if (currentUser instanceof IdentifiedUser) {
|
return new HasDraftByPredicate(args.dbProvider, self());
|
||||||
return new HasDraftByPredicate(args.dbProvider,
|
|
||||||
((IdentifiedUser) currentUser).getAccountId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -233,6 +232,14 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
return new IsReviewedPredicate(args.dbProvider);
|
return new IsReviewedPredicate(args.dbProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("owner".equalsIgnoreCase(value)) {
|
||||||
|
return new OwnerPredicate(args.dbProvider, self());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("reviewer".equalsIgnoreCase(value)) {
|
||||||
|
return new ReviewerPredicate(args.dbProvider, self());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return status(value);
|
return status(value);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@@ -303,42 +310,59 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> starredby(String who)
|
public Predicate<ChangeData> starredby(String who)
|
||||||
throws QueryParseException, OrmException {
|
throws QueryParseException, OrmException {
|
||||||
Account account = args.accountResolver.find(who);
|
if ("self".equals(who)) {
|
||||||
if (account == null) {
|
return new IsStarredByPredicate(args.dbProvider, currentUser);
|
||||||
throw error("User " + who + " not found");
|
|
||||||
}
|
}
|
||||||
return new IsStarredByPredicate(args.dbProvider, //
|
Set<Account.Id> m = parseAccount(who);
|
||||||
args.userFactory.create(args.dbProvider, account.getId()));
|
List<IsStarredByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
|
for (Account.Id id : m) {
|
||||||
|
p.add(new IsStarredByPredicate(args.dbProvider,
|
||||||
|
args.userFactory.create(args.dbProvider, id)));
|
||||||
|
}
|
||||||
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> watchedby(String who)
|
public Predicate<ChangeData> watchedby(String who)
|
||||||
throws QueryParseException, OrmException {
|
throws QueryParseException, OrmException {
|
||||||
Account account = args.accountResolver.find(who);
|
Set<Account.Id> m = parseAccount(who);
|
||||||
if (account == null) {
|
List<IsWatchedByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
throw error("User " + who + " not found");
|
for (Account.Id id : m) {
|
||||||
|
if (currentUser instanceof IdentifiedUser
|
||||||
|
&& id.equals(((IdentifiedUser) currentUser).getAccountId())) {
|
||||||
|
p.add(new IsWatchedByPredicate(args, currentUser));
|
||||||
|
} else {
|
||||||
|
p.add(new IsWatchedByPredicate(args,
|
||||||
|
args.userFactory.create(args.dbProvider, id)));
|
||||||
}
|
}
|
||||||
return new IsWatchedByPredicate(args, args.userFactory.create(
|
}
|
||||||
args.dbProvider, account.getId()));
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> draftby(String who) throws QueryParseException,
|
public Predicate<ChangeData> draftby(String who) throws QueryParseException,
|
||||||
OrmException {
|
OrmException {
|
||||||
Account account = args.accountResolver.find(who);
|
Set<Account.Id> m = parseAccount(who);
|
||||||
if (account == null) {
|
List<HasDraftByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
throw error("User " + who + " not found");
|
for (Account.Id id : m) {
|
||||||
|
p.add(new HasDraftByPredicate(args.dbProvider, id));
|
||||||
}
|
}
|
||||||
return new HasDraftByPredicate(args.dbProvider, account.getId());
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> visibleto(String who)
|
public Predicate<ChangeData> visibleto(String who)
|
||||||
throws QueryParseException, OrmException {
|
throws QueryParseException, OrmException {
|
||||||
Account account = args.accountResolver.find(who);
|
if ("self".equals(who)) {
|
||||||
if (account != null) {
|
return is_visible();
|
||||||
return visibleto(args.userFactory
|
}
|
||||||
.create(args.dbProvider, account.getId()));
|
Set<Account.Id> m = args.accountResolver.findAll(who);
|
||||||
|
if (!m.isEmpty()) {
|
||||||
|
List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
|
for (Account.Id id : m) {
|
||||||
|
return visibleto(args.userFactory.create(args.dbProvider, id));
|
||||||
|
}
|
||||||
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If its not an account, maybe its a group?
|
// If its not an account, maybe its a group?
|
||||||
@@ -375,24 +399,17 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> owner(String who) throws QueryParseException,
|
public Predicate<ChangeData> owner(String who) throws QueryParseException,
|
||||||
OrmException {
|
OrmException {
|
||||||
Set<Account.Id> m = args.accountResolver.findAll(who);
|
Set<Account.Id> m = parseAccount(who);
|
||||||
if (m.isEmpty()) {
|
List<OwnerPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
throw error("User " + who + " not found");
|
|
||||||
} else if (m.size() == 1) {
|
|
||||||
Account.Id id = m.iterator().next();
|
|
||||||
return new OwnerPredicate(args.dbProvider, id);
|
|
||||||
} else {
|
|
||||||
List<OwnerPredicate> p = new ArrayList<OwnerPredicate>(m.size());
|
|
||||||
for (Account.Id id : m) {
|
for (Account.Id id : m) {
|
||||||
p.add(new OwnerPredicate(args.dbProvider, id));
|
p.add(new OwnerPredicate(args.dbProvider, id));
|
||||||
}
|
}
|
||||||
return Predicate.or(p);
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> ownerin(String group) throws QueryParseException,
|
public Predicate<ChangeData> ownerin(String group)
|
||||||
OrmException {
|
throws QueryParseException {
|
||||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||||
if (g == null) {
|
if (g == null) {
|
||||||
throw error("Group " + group + " not found");
|
throw error("Group " + group + " not found");
|
||||||
@@ -403,24 +420,17 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> reviewer(String who)
|
public Predicate<ChangeData> reviewer(String who)
|
||||||
throws QueryParseException, OrmException {
|
throws QueryParseException, OrmException {
|
||||||
Set<Account.Id> m = args.accountResolver.findAll(who);
|
Set<Account.Id> m = parseAccount(who);
|
||||||
if (m.isEmpty()) {
|
List<ReviewerPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||||
throw error("User " + who + " not found");
|
|
||||||
} else if (m.size() == 1) {
|
|
||||||
Account.Id id = m.iterator().next();
|
|
||||||
return new ReviewerPredicate(args.dbProvider, id);
|
|
||||||
} else {
|
|
||||||
List<ReviewerPredicate> p = new ArrayList<ReviewerPredicate>(m.size());
|
|
||||||
for (Account.Id id : m) {
|
for (Account.Id id : m) {
|
||||||
p.add(new ReviewerPredicate(args.dbProvider, id));
|
p.add(new ReviewerPredicate(args.dbProvider, id));
|
||||||
}
|
}
|
||||||
return Predicate.or(p);
|
return Predicate.or(p);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> reviewerin(String group)
|
public Predicate<ChangeData> reviewerin(String group)
|
||||||
throws QueryParseException, OrmException {
|
throws QueryParseException {
|
||||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||||
if (g == null) {
|
if (g == null) {
|
||||||
throw error("Group " + group + " not found");
|
throw error("Group " + group + " not found");
|
||||||
@@ -532,4 +542,23 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
throw error("Unsupported query:" + query);
|
throw error("Unsupported query:" + query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<Account.Id> parseAccount(String who)
|
||||||
|
throws QueryParseException, OrmException {
|
||||||
|
if ("self".equals(who)) {
|
||||||
|
return Collections.singleton(self());
|
||||||
|
}
|
||||||
|
Set<Account.Id> matches = args.accountResolver.findAll(who);
|
||||||
|
if (matches.isEmpty()) {
|
||||||
|
throw error("User " + who + " not found");
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Account.Id self() {
|
||||||
|
if (currentUser instanceof IdentifiedUser) {
|
||||||
|
return ((IdentifiedUser) currentUser).getAccountId();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user