| // Copyright (C) 2021 The Android Open Source Project | |
| // | |
| // 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. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.gerrit.server.query.change; | |
| import com.google.gerrit.index.query.NotPredicate; | |
| import com.google.gerrit.index.query.Predicate; | |
| import com.google.gerrit.server.index.change.ChangeField; | |
| public class IsSubmittablePredicate extends BooleanPredicate { | |
| public IsSubmittablePredicate() { | |
| super(ChangeField.IS_SUBMITTABLE_SPEC); | |
| } | |
| /** | |
| * Rewrite the is:submittable predicate. | |
| * | |
| * <p>If we run a query with "is:submittable OR -is:submittable" the result should match all | |
| * changes. In Lucene, we keep separate sub-indexes for open and closed changes. The Lucene | |
| * backend inspects the input predicate and depending on all its child predicates decides if the | |
| * query should run against the open sub-index, closed sub-index or both. | |
| * | |
| * <p>The "is:submittable" operator is implemented as: | |
| * | |
| * <p>issubmittable:1 | |
| * | |
| * <p>But we want to exclude closed changes from being matched by this query. For the normal case, | |
| * we rewrite the query as: | |
| * | |
| * <p>issubmittable:1 AND status:new | |
| * | |
| * <p>Hence Lucene will match the query against the open sub-index. For the negated case (i.e. | |
| * "-is:submittable"), we cannot just negate the previous query because it would result in: | |
| * | |
| * <p>-(issubmittable:1 AND status:new) | |
| * | |
| * <p>Lucene will conclude that it should look for changes that are <b>not</b> new and hence will | |
| * run the query against the closed sub-index, not matching with changes that are open but not | |
| * submittable. For this case, we need to rewrite the query to match with closed changes <b>or</b> | |
| * changes that are not submittable. | |
| */ | |
| public static Predicate<ChangeData> rewrite(Predicate<ChangeData> in) { | |
| if (in instanceof IsSubmittablePredicate) { | |
| return Predicate.and( | |
| new BooleanPredicate(ChangeField.IS_SUBMITTABLE_SPEC), ChangeStatusPredicate.open()); | |
| } | |
| if (in instanceof NotPredicate && in.getChild(0) instanceof IsSubmittablePredicate) { | |
| return Predicate.or( | |
| Predicate.not(new BooleanPredicate(ChangeField.IS_SUBMITTABLE_SPEC)), | |
| ChangeStatusPredicate.closed()); | |
| } | |
| return in; | |
| } | |
| } |