Line data Source code
1 : // Copyright (C) 2010 The Android Open Source Project
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : package com.google.gerrit.server.query.change;
16 :
17 : import com.google.common.collect.Lists;
18 : import com.google.gerrit.common.Nullable;
19 : import com.google.gerrit.entities.Account;
20 : import com.google.gerrit.entities.AccountGroup;
21 : import com.google.gerrit.index.query.OrPredicate;
22 : import com.google.gerrit.index.query.Predicate;
23 : import com.google.gerrit.index.query.RangeUtil;
24 : import com.google.gerrit.index.query.RangeUtil.Range;
25 : import com.google.gerrit.server.IdentifiedUser;
26 : import com.google.gerrit.server.permissions.PermissionBackend;
27 : import com.google.gerrit.server.project.ProjectCache;
28 : import com.google.gerrit.server.util.LabelVote;
29 : import java.util.ArrayList;
30 : import java.util.List;
31 : import java.util.Set;
32 : import java.util.stream.IntStream;
33 :
34 : public class LabelPredicate extends OrPredicate<ChangeData> {
35 : protected static final int MAX_LABEL_VALUE = 4;
36 : protected static final int MAX_COUNT = 5; // inclusive
37 :
38 : protected static class Args {
39 : protected final ProjectCache projectCache;
40 : protected final PermissionBackend permissionBackend;
41 : protected final IdentifiedUser.GenericFactory userFactory;
42 : protected final String value;
43 : protected final Set<Account.Id> accounts;
44 : protected final AccountGroup.UUID group;
45 : protected final Integer count;
46 : protected final PredicateArgs.Operator countOp;
47 :
48 : protected Args(
49 : ProjectCache projectCache,
50 : PermissionBackend permissionBackend,
51 : IdentifiedUser.GenericFactory userFactory,
52 : String value,
53 : Set<Account.Id> accounts,
54 : AccountGroup.UUID group,
55 : @Nullable Integer count,
56 14 : @Nullable PredicateArgs.Operator countOp) {
57 14 : this.projectCache = projectCache;
58 14 : this.permissionBackend = permissionBackend;
59 14 : this.userFactory = userFactory;
60 14 : this.value = value;
61 14 : this.accounts = accounts;
62 14 : this.group = group;
63 14 : this.count = count;
64 14 : this.countOp = countOp;
65 14 : }
66 : }
67 :
68 : protected static class Parsed {
69 : protected final String label;
70 : protected final String test;
71 : protected final int numericValue;
72 :
73 13 : protected Parsed(String label, String test, int numericValue) {
74 13 : this.label = label;
75 13 : this.test = test;
76 13 : this.numericValue = numericValue;
77 13 : }
78 : }
79 :
80 : protected final String value;
81 :
82 : public LabelPredicate(
83 : ChangeQueryBuilder.Arguments a,
84 : String value,
85 : Set<Account.Id> accounts,
86 : AccountGroup.UUID group,
87 : @Nullable Integer count,
88 : @Nullable PredicateArgs.Operator countOp) {
89 14 : super(
90 14 : predicates(
91 : new Args(
92 : a.projectCache,
93 : a.permissionBackend,
94 : a.userFactory,
95 : value,
96 : accounts,
97 : group,
98 : count,
99 : countOp)));
100 14 : this.value = value;
101 14 : }
102 :
103 : protected static List<Predicate<ChangeData>> predicates(Args args) {
104 14 : String v = args.value;
105 14 : List<Integer> counts = getCounts(args.count, args.countOp);
106 : try {
107 7 : MagicLabelVote mlv = MagicLabelVote.parseWithEquals(v);
108 7 : List<Predicate<ChangeData>> result = Lists.newArrayListWithCapacity(counts.size());
109 7 : if (counts.isEmpty()) {
110 7 : result.add(magicLabelPredicate(args, mlv, /* count= */ null));
111 : } else {
112 4 : counts.forEach(count -> result.add(magicLabelPredicate(args, mlv, count)));
113 : }
114 7 : return result;
115 13 : } catch (IllegalArgumentException e) {
116 : // Try next format.
117 : }
118 :
119 13 : Parsed parsed = null;
120 :
121 : try {
122 10 : LabelVote lv = LabelVote.parse(v);
123 10 : parsed = new Parsed(lv.label(), "=", lv.value());
124 8 : } catch (IllegalArgumentException e) {
125 : // Try next format.
126 10 : }
127 :
128 : try {
129 8 : LabelVote lv = LabelVote.parseWithEquals(v);
130 8 : parsed = new Parsed(lv.label(), "=", lv.value());
131 11 : } catch (IllegalArgumentException e) {
132 : // Try next format.
133 8 : }
134 :
135 : Range range;
136 13 : if (parsed == null) {
137 5 : range = RangeUtil.getRange(v, -MAX_LABEL_VALUE, MAX_LABEL_VALUE);
138 5 : if (range == null) {
139 5 : range = new Range(v, 1, 1);
140 : }
141 : } else {
142 13 : range =
143 13 : RangeUtil.getRange(
144 : parsed.label, parsed.test, parsed.numericValue, -MAX_LABEL_VALUE, MAX_LABEL_VALUE);
145 : }
146 13 : String prefix = range.prefix;
147 13 : int min = range.min;
148 13 : int max = range.max;
149 :
150 : List<Predicate<ChangeData>> r =
151 13 : Lists.newArrayListWithCapacity((counts.isEmpty() ? 1 : counts.size()) * (max - min + 1));
152 13 : for (int i = min; i <= max; i++) {
153 13 : if (counts.isEmpty()) {
154 13 : r.add(onePredicate(args, prefix, i, /* count= */ null));
155 : } else {
156 4 : for (int count : counts) {
157 4 : r.add(onePredicate(args, prefix, i, count));
158 4 : }
159 : }
160 : }
161 13 : return r;
162 : }
163 :
164 : protected static Predicate<ChangeData> onePredicate(
165 : Args args, String label, int expVal, @Nullable Integer count) {
166 13 : if (expVal != 0) {
167 13 : return equalsLabelPredicate(args, label, expVal, count);
168 : }
169 5 : return noLabelQuery(args, label);
170 : }
171 :
172 : protected static Predicate<ChangeData> noLabelQuery(Args args, String label) {
173 5 : List<Predicate<ChangeData>> r = Lists.newArrayListWithCapacity(2 * MAX_LABEL_VALUE);
174 5 : for (int i = 1; i <= MAX_LABEL_VALUE; i++) {
175 5 : r.add(equalsLabelPredicate(args, label, i, /* count= */ null));
176 5 : r.add(equalsLabelPredicate(args, label, -i, /* count= */ null));
177 : }
178 5 : return not(or(r));
179 : }
180 :
181 : protected static Predicate<ChangeData> equalsLabelPredicate(
182 : Args args, String label, int expVal, @Nullable Integer count) {
183 13 : if (args.accounts == null || args.accounts.isEmpty()) {
184 13 : return new EqualsLabelPredicate(args, label, expVal, null, count);
185 : }
186 4 : List<Predicate<ChangeData>> r = new ArrayList<>();
187 4 : for (Account.Id a : args.accounts) {
188 4 : r.add(new EqualsLabelPredicate(args, label, expVal, a, count));
189 4 : }
190 4 : return or(r);
191 : }
192 :
193 : protected static Predicate<ChangeData> magicLabelPredicate(
194 : Args args, MagicLabelVote mlv, @Nullable Integer count) {
195 7 : if (args.accounts == null || args.accounts.isEmpty()) {
196 7 : return new MagicLabelPredicate(args, mlv, /* account= */ null, count);
197 : }
198 1 : List<Predicate<ChangeData>> r = new ArrayList<>();
199 1 : for (Account.Id a : args.accounts) {
200 1 : r.add(new MagicLabelPredicate(args, mlv, a, count));
201 1 : }
202 1 : return or(r);
203 : }
204 :
205 : private static List<Integer> getCounts(
206 : @Nullable Integer count, @Nullable PredicateArgs.Operator countOp) {
207 14 : List<Integer> result = new ArrayList<>();
208 14 : if (count == null) {
209 14 : return result;
210 : }
211 4 : switch (countOp) {
212 : case EQUAL:
213 : case GREATER_EQUAL:
214 : case LESS_EQUAL:
215 4 : result.add(count);
216 4 : break;
217 : case GREATER:
218 : case LESS:
219 : default:
220 : break;
221 : }
222 4 : switch (countOp) {
223 : case GREATER:
224 : case GREATER_EQUAL:
225 4 : IntStream.range(count + 1, MAX_COUNT + 1).forEach(result::add);
226 4 : break;
227 : case LESS:
228 : case LESS_EQUAL:
229 4 : IntStream.range(0, count).forEach(result::add);
230 4 : break;
231 : case EQUAL:
232 : default:
233 : break;
234 : }
235 4 : return result;
236 : }
237 :
238 : @Override
239 : public String toString() {
240 4 : return ChangeQueryBuilder.FIELD_LABEL + ":" + value;
241 : }
242 : }
|