Merge "Refactor gr-diff-processor to use an asynchronous loop"
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 2a58041..0b275c1 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -633,7 +633,7 @@
@Singleton
public class SampleOperator
implements ChangeQueryBuilder.ChangeOperatorFactory {
- public static class MyPredicate extends OperatorPredicate<ChangeData> {
+ public static class MyPredicate extends OperatorChangePredicate<ChangeData> {
...
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
index d5f9b6e..d8f2885 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
@@ -45,6 +45,7 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.change.PostReview;
@@ -60,7 +61,6 @@
import com.google.gerrit.server.notedb.NoteDbChangeState;
import com.google.gerrit.server.notedb.NoteDbUpdateManager;
import com.google.gerrit.server.notedb.TestChangeRebuilderWrapper;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gerrit.testutil.ConfigSuite;
import com.google.gerrit.testutil.NoteDbChecker;
import com.google.gerrit.testutil.NoteDbMode;
@@ -264,13 +264,13 @@
// First write doesn't create the ref, but rebuilding works.
checker.assertNoChangeRef(project, id);
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isNull();
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isNull();
checker.rebuildAndCheckChanges(id);
// Now that there is a ref, writes are "turned on" for this change, and
// NoteDb stays up to date without explicit rebuilding.
gApi.changes().id(id.get()).topic(name("new-topic"));
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isNotNull();
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isNotNull();
checker.checkChanges(id);
}
@@ -323,13 +323,13 @@
Change.Id id = r.getPatchSetId().getParentKey();
ObjectId changeMetaId = getMetaRef(project, changeMetaRef(id));
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isEqualTo(
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isEqualTo(
changeMetaId.name());
putDraft(user, id, 1, "comment by user");
ObjectId userDraftsId = getMetaRef(
allUsers, refsDraftComments(id, user.getId()));
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isEqualTo(
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isEqualTo(
changeMetaId.name()
+ "," + user.getId() + "=" + userDraftsId.name());
@@ -337,7 +337,7 @@
ObjectId adminDraftsId = getMetaRef(
allUsers, refsDraftComments(id, admin.getId()));
assertThat(admin.getId().get()).isLessThan(user.getId().get());
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isEqualTo(
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isEqualTo(
changeMetaId.name()
+ "," + admin.getId() + "=" + adminDraftsId.name()
+ "," + user.getId() + "=" + userDraftsId.name());
@@ -345,7 +345,7 @@
putDraft(admin, id, 2, "revised comment by admin");
adminDraftsId = getMetaRef(
allUsers, refsDraftComments(id, admin.getId()));
- assertThat(unwrapDb().changes().get(id).getNoteDbState()).isEqualTo(
+ assertThat(getUnwrappedDb().changes().get(id).getNoteDbState()).isEqualTo(
changeMetaId.name()
+ "," + admin.getId() + "=" + adminDraftsId.name()
+ "," + user.getId() + "=" + userDraftsId.name());
@@ -374,7 +374,7 @@
// Check that the bundles are equal.
ChangeBundle actual = ChangeBundle.fromNotes(
plcUtil, notesFactory.create(dbProvider.get(), project, id));
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
}
@@ -425,7 +425,7 @@
// Check that the bundles are equal.
ChangeNotes notes = notesFactory.create(dbProvider.get(), project, id);
ChangeBundle actual = ChangeBundle.fromNotes(plcUtil, notes);
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
assertThat(
Iterables.transform(
@@ -464,7 +464,7 @@
// Check that the bundles are equal.
ChangeBundle actual = ChangeBundle.fromNotes(
plcUtil, notesFactory.create(dbProvider.get(), project, id));
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
}
@@ -494,7 +494,7 @@
assertChangeUpToDate(false, id);
assertThat(getMetaRef(project, changeMetaRef(id))).isEqualTo(oldMetaId);
ChangeBundle actual = ChangeBundle.fromNotes(plcUtil, notes);
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
assertChangeUpToDate(false, id);
@@ -536,7 +536,7 @@
// Not up to date, but the actual returned state matches anyway.
assertDraftsUpToDate(false, id, user);
ChangeBundle actual = ChangeBundle.fromNotes(plcUtil, notes);
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
// Another rebuild attempt succeeds
@@ -564,7 +564,7 @@
setNotesMigration(false, false);
putDraft(user, id, 1, "second comment by user");
- ReviewDb db = unwrapDb();
+ ReviewDb db = getUnwrappedDb();
Change c = db.changes().get(id);
// Leave change meta ID alone so DraftCommentNotes does the rebuild.
NoteDbChangeState bogusState = new NoteDbChangeState(
@@ -591,7 +591,7 @@
assertChangeUpToDate(true, id);
assertDraftsUpToDate(false, id, user);
ChangeBundle actual = ChangeBundle.fromNotes(plcUtil, notes);
- ChangeBundle expected = ChangeBundle.fromReviewDb(unwrapDb(), id);
+ ChangeBundle expected = ChangeBundle.fromReviewDb(getUnwrappedDb(), id);
assertThat(actual.differencesFrom(expected)).isEmpty();
// Another rebuild attempt succeeds
@@ -950,7 +950,7 @@
}
private void setInvalidNoteDbState(Change.Id id) throws Exception {
- ReviewDb db = unwrapDb();
+ ReviewDb db = getUnwrappedDb();
Change c = db.changes().get(id);
// In reality we would have NoteDb writes enabled, which would write a real
// state into this field. For tests however, we turn NoteDb writes off, so
@@ -963,7 +963,7 @@
private void assertChangeUpToDate(boolean expected, Change.Id id)
throws Exception {
try (Repository repo = repoManager.openRepository(project)) {
- Change c = unwrapDb().changes().get(id);
+ Change c = getUnwrappedDb().changes().get(id);
assertThat(c).isNotNull();
assertThat(c.getNoteDbState()).isNotNull();
assertThat(NoteDbChangeState.parse(c).isChangeUpToDate(
@@ -975,7 +975,7 @@
private void assertDraftsUpToDate(boolean expected, Change.Id changeId,
TestAccount account) throws Exception {
try (Repository repo = repoManager.openRepository(allUsers)) {
- Change c = unwrapDb().changes().get(changeId);
+ Change c = getUnwrappedDb().changes().get(changeId);
assertThat(c).isNotNull();
assertThat(c.getNoteDbState()).isNotNull();
NoteDbChangeState state = NoteDbChangeState.parse(c);
@@ -1052,11 +1052,8 @@
return msg;
}
- private ReviewDb unwrapDb() {
+ private ReviewDb getUnwrappedDb() {
ReviewDb db = dbProvider.get();
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
+ return ReviewDbUtil.unwrapDb(db);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
index 9991a76..306a69f 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
@@ -39,6 +39,7 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import static com.google.gerrit.reviewdb.server.ReviewDbUtil.unwrapDb;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -48,7 +49,6 @@
import com.google.gerrit.server.index.change.ReindexAfterUpdate;
import com.google.gerrit.server.notedb.ChangeRebuilder;
import com.google.gerrit.server.notedb.NotesMigration;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
@@ -153,7 +153,7 @@
new Callable<Boolean>() {
@Override
public Boolean call() {
- try (ReviewDb db = unwrap(schemaFactory.open())) {
+ try (ReviewDb db = unwrapDb(schemaFactory.open())) {
return rebuilder.rebuildProject(
db, changesByProject, project, allUsersRepo);
} catch (Exception e) {
@@ -234,7 +234,7 @@
ArrayListMultimap.create();
try (ReviewDb db = schemaFactory.open()) {
if (projects.isEmpty() && !changes.isEmpty()) {
- Iterable<Change> todo = unwrap(db).changes().get(
+ Iterable<Change> todo = unwrapDb(db).changes().get(
Iterables.transform(changes, new Function<Integer, Change.Id>() {
@Override
public Change.Id apply(Integer in) {
@@ -245,7 +245,7 @@
changesByProject.put(c.getProject(), c.getId());
}
} else {
- for (Change c : unwrap(db).changes().all()) {
+ for (Change c : unwrapDb(db).changes().all()) {
boolean include = false;
if (projects.isEmpty() && changes.isEmpty()) {
include = true;
@@ -263,11 +263,4 @@
return ImmutableMultimap.copyOf(changesByProject);
}
}
-
- private static ReviewDb unwrap(ReviewDb db) {
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
- }
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
index 540ba0b..198916a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -29,6 +29,7 @@
import com.google.gerrit.pgm.init.api.LibraryDownload;
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import static com.google.gerrit.reviewdb.server.ReviewDbUtil.unwrapDb;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.SitePaths;
@@ -399,7 +400,7 @@
System.err.flush();
} else if (ui.yesno(true, "%s\nExecute now", msg)) {
- try (JdbcSchema db = (JdbcSchema) schema.open();
+ try (JdbcSchema db = (JdbcSchema) unwrapDb(schema.open());
JdbcExecutor e = new JdbcExecutor(db)) {
for (String sql : pruneList) {
e.execute(sql);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DisabledChangesReviewDbWrapper.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/DisabledChangesReviewDbWrapper.java
similarity index 93%
rename from gerrit-server/src/main/java/com/google/gerrit/server/schema/DisabledChangesReviewDbWrapper.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/DisabledChangesReviewDbWrapper.java
index 658f3bb..b70778e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DisabledChangesReviewDbWrapper.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/DisabledChangesReviewDbWrapper.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.reviewdb.server;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.reviewdb.client.Account;
@@ -21,13 +21,6 @@
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.reviewdb.server.ChangeAccess;
-import com.google.gerrit.reviewdb.server.ChangeMessageAccess;
-import com.google.gerrit.reviewdb.server.PatchLineCommentAccess;
-import com.google.gerrit.reviewdb.server.PatchSetAccess;
-import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.reviewdb.server.ReviewDbWrapper;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
@@ -40,7 +33,7 @@
private final DisabledPatchSetAccess patchSets;
private final DisabledPatchLineCommentAccess patchComments;
- DisabledChangesReviewDbWrapper(ReviewDb db) {
+ public DisabledChangesReviewDbWrapper(ReviewDb db) {
super(db);
changes = new DisabledChangeAccess(delegate.changes());
patchSetApprovals =
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
index 5d782dd..42d0993 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
@@ -49,6 +49,13 @@
return CHANGE_ID_FUNCTION;
}
+ public static ReviewDb unwrapDb(ReviewDb db) {
+ if (db instanceof DisabledChangesReviewDbWrapper) {
+ return ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
+ }
+ return db;
+ }
+
private ReviewDbUtil() {
}
}
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index 6aa9e2c..4fc578c 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -190,6 +190,7 @@
['src/test/java/**/*.java'],
excludes = TESTUTIL + PROLOG_TESTS + PROLOG_TEST_CASE + QUERY_TESTS
),
+ resources = glob(['src/test/resources/com/google/gerrit/server/mail/*']),
deps = TESTUTIL_DEPS + [
':testutil',
'//gerrit-antlr:query_exception',
@@ -202,6 +203,7 @@
'//lib:guava',
'//lib:guava-retrying',
'//lib:protobuf',
+ '//lib/commons:validator',
'//lib/dropwizard:dropwizard-core',
'//lib/guice:guice-assistedinject',
'//lib/prolog:runtime',
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
index 9f8411f..3ca0e1b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
@@ -25,6 +25,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -33,7 +34,6 @@
import com.google.gerrit.server.git.BatchUpdate.RepoContext;
import com.google.gerrit.server.git.BatchUpdateReviewDb;
import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -57,10 +57,7 @@
if (db instanceof BatchUpdateReviewDb) {
db = ((BatchUpdateReviewDb) db).unsafeGetDelegate();
}
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
+ return ReviewDbUtil.unwrapDb(db);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
index 93cb01b..1cd8726 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
@@ -146,6 +146,7 @@
psUtil.delete(ctx.getDb(), ctx.getUpdate(patchSet.getId()), patchSet);
accountPatchReviewStore.get().clearReviewed(psId);
+ // Use the unwrap from DeleteDraftChangeOp to handle BatchUpdateReviewDb.
ReviewDb db = DeleteDraftChangeOp.unwrap(ctx.getDb());
db.changeMessages().delete(db.changeMessages().byPatchSet(psId));
db.patchComments().delete(db.patchComments().byPatchSet(psId));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
index 842e8bb..08ef76e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
@@ -24,6 +24,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
@@ -32,7 +33,6 @@
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -186,13 +186,10 @@
throws OrmException {
// Empty update of Change to bump rowVersion, changing its ETag.
// TODO(dborowitz): Include cache info in ETag somehow instead.
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
+ db = ReviewDbUtil.unwrapDb(db);
Change c = db.changes().get(id);
if (c != null) {
db.changes().update(Collections.singleton(c));
}
}
-
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
index eb76350..598ed71 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
@@ -50,7 +50,6 @@
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.NoSuchRefException;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.OrmConcurrencyException;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
@@ -856,7 +855,7 @@
RevWalk rw, Change.Id id) throws Exception {
Change c = newChanges.get(id);
if (c == null) {
- c = unwrap(db).changes().get(id);
+ c = ReviewDbUtil.unwrapDb(db).changes().get(id);
}
// Pass in preloaded change to controlFor, to avoid:
// - reading from a db that does not belong to this update
@@ -903,11 +902,4 @@
op.postUpdate(ctx);
}
}
-
- private static ReviewDb unwrap(ReviewDb db) {
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index bbb325e..66637fb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -37,6 +37,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
+import com.google.common.collect.Collections2;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
@@ -50,8 +51,6 @@
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.google.common.collect.SortedSetMultimap;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.Capable;
@@ -291,7 +290,6 @@
private final TagCache tagCache;
private final AccountCache accountCache;
private final ChangeInserter.Factory changeInserterFactory;
- private final ListeningExecutorService changeUpdateExector;
private final RequestScopePropagator requestScopePropagator;
private final SshInfo sshInfo;
private final AllProjectsName allProjectsName;
@@ -355,7 +353,6 @@
ChangeInserter.Factory changeInserterFactory,
CommitValidators.Factory commitValidatorsFactory,
@CanonicalWebUrl String canonicalWebUrl,
- @ChangeUpdateExecutor ListeningExecutorService changeUpdateExector,
RequestScopePropagator requestScopePropagator,
SshInfo sshInfo,
AllProjectsName allProjectsName,
@@ -392,7 +389,6 @@
this.accountCache = accountCache;
this.changeInserterFactory = changeInserterFactory;
this.commitValidatorsFactory = commitValidatorsFactory;
- this.changeUpdateExector = changeUpdateExector;
this.requestScopePropagator = requestScopePropagator;
this.sshInfo = sshInfo;
this.allProjectsName = allProjectsName;
@@ -1892,17 +1888,19 @@
}
private void readChangesForReplace() throws OrmException {
- List<CheckedFuture<ChangeNotes, OrmException>> futures =
- Lists.newArrayListWithCapacity(replaceByChange.size());
- for (ReplaceRequest request : replaceByChange.values()) {
- futures.add(notesFactory.createAsync(changeUpdateExector, db,
- project.getNameKey(), request.ontoChange));
- }
- for (CheckedFuture<ChangeNotes, OrmException> f : futures) {
- ChangeNotes notes = f.checkedGet();
- if (notes.getChange() != null) {
- replaceByChange.get(notes.getChangeId()).notes = notes;
- }
+ Collection<ChangeNotes> allNotes =
+ notesFactory.create(
+ db,
+ Collections2.transform(
+ replaceByChange.values(),
+ new Function<ReplaceRequest, Change.Id>() {
+ @Override
+ public Change.Id apply(ReplaceRequest in) {
+ return in.ontoChange;
+ }
+ }));
+ for (ChangeNotes notes : allNotes) {
+ replaceByChange.get(notes.getChangeId()).notes = notes;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexPredicate.java
index d3b9e95..ff9ff03 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexPredicate.java
@@ -20,7 +20,7 @@
public abstract class IndexPredicate<I> extends OperatorPredicate<I> {
private final FieldDef<I, ?> def;
- public IndexPredicate(FieldDef<I, ?> def, String value) {
+ protected IndexPredicate(FieldDef<I, ?> def, String value) {
super(def.getName(), value);
this.def = def;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedQuery.java
index 3040ca6..65097b4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedQuery.java
@@ -14,10 +14,8 @@
package com.google.gerrit.server.index;
-import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.gerrit.server.query.DataSource;
import com.google.gerrit.server.query.Paginated;
import com.google.gerrit.server.query.Predicate;
@@ -26,10 +24,7 @@
import com.google.gwtorm.server.ResultSet;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
/**
* Wrapper combining an {@link IndexPredicate} together with a
@@ -48,8 +43,7 @@
private QueryOptions opts;
private final Predicate<T> pred;
- private DataSource<T> source;
- private final Map<T, DataSource<T>> fromSource;
+ protected DataSource<T> source;
public IndexedQuery(Index<I, T> index, Predicate<T> pred,
QueryOptions opts) throws QueryParseException {
@@ -57,7 +51,6 @@
this.opts = opts;
this.pred = pred;
this.source = index.getSource(pred, this.opts);
- this.fromSource = new HashMap<>();
}
@Override
@@ -90,38 +83,7 @@
@Override
public ResultSet<T> read() throws OrmException {
- final DataSource<T> currSource = source;
- final ResultSet<T> rs = currSource.read();
-
- return new ResultSet<T>() {
- @Override
- public Iterator<T> iterator() {
- return Iterables.transform(
- rs,
- new Function<T, T>() {
- @Override
- public
- T apply(T t) {
- fromSource.put(t, currSource);
- return t;
- }
- }).iterator();
- }
-
- @Override
- public List<T> toList() {
- List<T> r = rs.toList();
- for (T t : r) {
- fromSource.put(t, currSource);
- }
- return r;
- }
-
- @Override
- public void close() {
- rs.close();
- }
- };
+ return source.read();
}
@Override
@@ -146,19 +108,6 @@
}
@Override
- public boolean match(T t) throws OrmException {
- return (source != null && fromSource.get(t) == source) || pred.match(t);
- }
-
- @Override
- public int getCost() {
- // Index queries are assumed to be cheaper than any other type of query, so
- // so try to make sure they get picked. Note that pred's cost may be higher
- // because it doesn't know whether it's being used in an index query or not.
- return 1;
- }
-
- @Override
public int hashCode() {
return pred.hashCode();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IntegerRangePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IntegerRangePredicate.java
index 1259951..52c1201 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IntegerRangePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IntegerRangePredicate.java
@@ -33,7 +33,6 @@
protected abstract int getValueInt(T object) throws OrmException;
- @Override
public boolean match(T object) throws OrmException {
int valueInt = getValueInt(object);
return valueInt >= range.min && valueInt <= range.max;
@@ -48,9 +47,4 @@
public int getMaximumValue() {
return range.max;
}
-
- @Override
- public int getCost() {
- return 1;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/TimestampRangePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/TimestampRangePredicate.java
index 8ba7df9..1e2e80b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/TimestampRangePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/TimestampRangePredicate.java
@@ -38,9 +38,4 @@
public abstract Date getMinTimestamp();
public abstract Date getMaxTimestamp();
-
- @Override
- public int getCost() {
- return 1;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountField.java
index 8627e3a..0cbcf1f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountField.java
@@ -114,7 +114,8 @@
public String apply(String in) {
return in.toLowerCase();
}
- });
+ })
+ .toSet();
}
};
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
index 8fe02f4..996caa7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
@@ -14,22 +14,33 @@
package com.google.gerrit.server.index.change;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.index.change.ChangeField.CHANGE;
import static com.google.gerrit.server.index.change.ChangeField.PROJECT;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.index.IndexConfig;
import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.IndexedQuery;
import com.google.gerrit.server.index.QueryOptions;
+import com.google.gerrit.server.query.DataSource;
+import com.google.gerrit.server.query.Matchable;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeDataSource;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -41,7 +52,7 @@
* {@link ChangeDataSource} to be chosen by the query processor.
*/
public class IndexedChangeQuery extends IndexedQuery<Change.Id, ChangeData>
- implements ChangeDataSource {
+ implements ChangeDataSource, Matchable<ChangeData> {
public static QueryOptions oneResult() {
return createOptions(IndexConfig.createDefault(), 0, 1,
ImmutableSet.<String> of());
@@ -65,9 +76,68 @@
opts.limit(), opts.fields());
}
+ private final Map<ChangeData, DataSource<ChangeData>> fromSource;
+
public IndexedChangeQuery(ChangeIndex index, Predicate<ChangeData> pred,
QueryOptions opts) throws QueryParseException {
super(index, pred, convertOptions(opts));
+ this.fromSource = new HashMap<>();
+ }
+
+ @Override
+ public ResultSet<ChangeData> read() throws OrmException {
+ final DataSource<ChangeData> currSource = source;
+ final ResultSet<ChangeData> rs = currSource.read();
+
+ return new ResultSet<ChangeData>() {
+ @Override
+ public Iterator<ChangeData> iterator() {
+ return Iterables.transform(
+ rs,
+ new Function<ChangeData, ChangeData>() {
+ @Override
+ public ChangeData apply(ChangeData cd) {
+ fromSource.put(cd, currSource);
+ return cd;
+ }
+ }).iterator();
+ }
+
+ @Override
+ public List<ChangeData> toList() {
+ List<ChangeData> r = rs.toList();
+ for (ChangeData cd : r) {
+ fromSource.put(cd, currSource);
+ }
+ return r;
+ }
+
+ @Override
+ public void close() {
+ rs.close();
+ }
+ };
+ }
+
+ @Override
+ public boolean match(ChangeData cd) throws OrmException {
+ if (source != null && fromSource.get(cd) == source) {
+ return true;
+ }
+
+ Predicate<ChangeData> pred = getChild(0);
+ checkState(pred.isMatchable(),
+ "match invoked, but child predicate %s " + "doesn't implement %s", pred,
+ Matchable.class.getName());
+ return pred.asMatchable().match(cd);
+ }
+
+ @Override
+ public int getCost() {
+ // Index queries are assumed to be cheaper than any other type of query, so
+ // so try to make sure they get picked. Note that pred's cost may be higher
+ // because it doesn't know whether it's being used in an index query or not.
+ return 1;
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
index 5db8f64..e446f9a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
@@ -151,10 +151,14 @@
throws OrmException, IOException, NoSuchChangeException {
// Reload change, as some time may have passed since GetChanges.
ReviewDb db = ctx.getReviewDbProvider().get();
- Change c = notesFactory
- .createChecked(db, new Project.NameKey(event.getProjectName()), id)
- .getChange();
- indexerFactory.create(executor, indexes).index(db, c);
+ try {
+ Change c = notesFactory
+ .createChecked(db, new Project.NameKey(event.getProjectName()), id)
+ .getChange();
+ indexerFactory.create(executor, indexes).index(db, c);
+ } catch (NoSuchChangeException e) {
+ indexerFactory.create(executor, indexes).delete(id);
+ }
return null;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
index 8a80bfe..6e4e1d4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
@@ -211,6 +211,6 @@
p = Predicate.and(filterPredicate, p);
}
}
- return p == null || p.match(changeData);
+ return p == null || p.asMatchable().match(changeData);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
index 60c7d25..82ed02a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -34,11 +34,6 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
-import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.metrics.Timer1;
@@ -52,6 +47,7 @@
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.git.RefCache;
import com.google.gerrit.server.git.RepoRefCache;
@@ -59,7 +55,6 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -80,7 +75,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.Callable;
/** View of a single {@link Change} based on the log of its notes branch. */
public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
@@ -128,20 +122,16 @@
public ChangeNotes createChecked(ReviewDb db, Change c)
throws OrmException, NoSuchChangeException {
- ChangeNotes notes = create(db, c.getProject(), c.getId());
- if (notes.getChange() == null) {
- throw new NoSuchChangeException(c.getId());
- }
- return notes;
+ return createChecked(db, c.getProject(), c.getId());
}
public ChangeNotes createChecked(ReviewDb db, Project.NameKey project,
Change.Id changeId) throws OrmException, NoSuchChangeException {
- ChangeNotes notes = create(db, project, changeId);
- if (notes.getChange() == null) {
+ Change change = ReviewDbUtil.unwrapDb(db).changes().get(changeId);
+ if (change == null || !change.getProject().equals(project)) {
throw new NoSuchChangeException(changeId);
}
- return notes;
+ return new ChangeNotes(args, change).load();
}
public ChangeNotes createChecked(Change.Id changeId)
@@ -161,7 +151,7 @@
public ChangeNotes create(ReviewDb db, Project.NameKey project,
Change.Id changeId) throws OrmException {
- Change change = unwrap(db).changes().get(changeId);
+ Change change = ReviewDbUtil.unwrapDb(db).changes().get(changeId);
checkNotNull(change,
"change %s not found in ReviewDb", changeId);
checkArgument(change.getProject().equals(project),
@@ -194,7 +184,7 @@
ReviewDb db, Change.Id changeId) throws OrmException {
checkState(!args.migration.readChanges(), "do not call"
+ " createFromIdOnlyWhenNoteDbDisabled when NoteDb is enabled");
- Change change = unwrap(db).changes().get(changeId);
+ Change change = ReviewDbUtil.unwrapDb(db).changes().get(changeId);
checkNotNull(change,
"change %s not found in ReviewDb", changeId);
return new ChangeNotes(args, change).load();
@@ -217,41 +207,6 @@
return new ChangeNotes(args, change).load();
}
- public CheckedFuture<ChangeNotes, OrmException> createAsync(
- final ListeningExecutorService executorService, final ReviewDb db,
- final Project.NameKey project, final Change.Id changeId) {
- return Futures.makeChecked(
- Futures.transformAsync(unwrap(db).changes().getAsync(changeId),
- new AsyncFunction<Change, ChangeNotes>() {
- @Override
- public ListenableFuture<ChangeNotes> apply(
- final Change change) {
- return executorService.submit(new Callable<ChangeNotes>() {
- @Override
- public ChangeNotes call() throws Exception {
- checkArgument(change.getProject().equals(project),
- "passed project %s when creating ChangeNotes for %s,"
- + " but actual project is %s",
- project, changeId, change.getProject());
- // Disable auto-rebuilding. This may be called async for a
- // large number of changes in one project, increasing
- // write contention. Plus, we haven't propagated the
- // request scope for the rebuilder to open the db.
- return new ChangeNotes(args, change, false, null).load();
- }
- });
- }
- }), new Function<Exception, OrmException>() {
- @Override
- public OrmException apply(Exception e) {
- if (e instanceof OrmException) {
- return (OrmException) e;
- }
- return new OrmException(e);
- }
- });
- }
-
public List<ChangeNotes> create(ReviewDb db,
Collection<Change.Id> changeIds) throws OrmException {
List<ChangeNotes> notes = new ArrayList<>();
@@ -266,7 +221,7 @@
return notes;
}
- for (Change c : unwrap(db).changes().get(changeIds)) {
+ for (Change c : ReviewDbUtil.unwrapDb(db).changes().get(changeIds)) {
notes.add(createFromChangeOnlyWhenNoteDbDisabled(c));
}
return notes;
@@ -286,7 +241,7 @@
return notes;
}
- for (Change c : unwrap(db).changes().get(changeIds)) {
+ for (Change c : ReviewDbUtil.unwrapDb(db).changes().get(changeIds)) {
if (c != null && project.equals(c.getDest().getParentKey())) {
ChangeNotes cn = createFromChangeOnlyWhenNoteDbDisabled(c);
if (predicate.apply(cn)) {
@@ -312,7 +267,7 @@
}
}
} else {
- for (Change change : unwrap(db).changes().all()) {
+ for (Change change : ReviewDbUtil.unwrapDb(db).changes().all()) {
ChangeNotes notes = createFromChangeOnlyWhenNoteDbDisabled(change);
if (predicate.apply(notes)) {
m.put(change.getProject(), notes);
@@ -338,7 +293,7 @@
// A batch size of N may overload get(Iterable), so use something smaller,
// but still >1.
for (List<Change.Id> batch : Iterables.partition(ids, 30)) {
- for (Change change : unwrap(db).changes().get(batch)) {
+ for (Change change : ReviewDbUtil.unwrapDb(db).changes().get(batch)) {
notes.add(createFromChangeOnlyWhenNoteDbDisabled(change));
}
}
@@ -349,7 +304,7 @@
Project.NameKey project) throws OrmException, IOException {
Set<Change.Id> ids = scan(repo);
List<ChangeNotes> changeNotes = new ArrayList<>(ids.size());
- db = unwrap(db);
+ db = ReviewDbUtil.unwrapDb(db);
for (Change.Id id : ids) {
Change change = db.changes().get(id);
if (change == null) {
@@ -385,13 +340,6 @@
}
}
- private static ReviewDb unwrap(ReviewDb db) {
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
- }
-
private final RefCache refs;
private Change change;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
index 8f805d9..a181431 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
@@ -61,7 +61,6 @@
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
@@ -157,7 +156,7 @@
public Result rebuild(ReviewDb db, Change.Id changeId)
throws NoSuchChangeException, IOException, OrmException,
ConfigInvalidException {
- db = unwrapDb(db);
+ db = ReviewDbUtil.unwrapDb(db);
Change change = db.changes().get(changeId);
if (change == null) {
throw new NoSuchChangeException(changeId);
@@ -188,7 +187,7 @@
@Override
public NoteDbUpdateManager stage(ReviewDb db, Change.Id changeId)
throws NoSuchChangeException, IOException, OrmException {
- db = unwrapDb(db);
+ db = ReviewDbUtil.unwrapDb(db);
Change change = db.changes().get(changeId);
if (change == null) {
throw new NoSuchChangeException(changeId);
@@ -204,7 +203,7 @@
public Result execute(ReviewDb db, Change.Id changeId,
NoteDbUpdateManager manager) throws NoSuchChangeException, OrmException,
IOException {
- db = unwrapDb(db);
+ db = ReviewDbUtil.unwrapDb(db);
Change change = db.changes().get(changeId);
if (change == null) {
throw new NoSuchChangeException(changeId);
@@ -1021,11 +1020,4 @@
}
}
}
-
- private ReviewDb unwrapDb(ReviewDb db) {
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
index 39b0fa3..899e789 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.query;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.gwtorm.server.OrmException;
import java.util.ArrayList;
@@ -23,7 +25,7 @@
import java.util.List;
/** Requires all predicates to be true. */
-public class AndPredicate<T> extends Predicate<T> {
+public class AndPredicate<T> extends Predicate<T> implements Matchable<T> {
private final List<Predicate<T>> children;
private final int cost;
@@ -39,11 +41,11 @@
if (getClass() == p.getClass()) {
for (Predicate<T> gp : p.getChildren()) {
t.add(gp);
- c += gp.getCost();
+ c += gp.estimateCost();
}
} else {
t.add(p);
- c += p.getCost();
+ c += p.estimateCost();
}
}
children = t;
@@ -71,9 +73,21 @@
}
@Override
+ public boolean isMatchable() {
+ for (Predicate<T> c : children) {
+ if (!c.isMatchable()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
public boolean match(final T object) throws OrmException {
- for (final Predicate<T> c : children) {
- if (!c.match(object)) {
+ for (Predicate<T> c : children) {
+ checkState(c.isMatchable(), "match invoked, but child predicate %s "
+ + "doesn't implement %s", c, Matchable.class.getName());
+ if (!c.asMatchable().match(object)) {
return false;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndSource.java
index 4b62333..168be5d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndSource.java
@@ -36,17 +36,29 @@
implements DataSource<T>, Comparator<Predicate<T>> {
protected final DataSource<T> source;
+ private final IsVisibleToPredicate<T> isVisibleToPredicate;
private final int start;
private final int cardinality;
-
public AndSource(Collection<? extends Predicate<T>> that) {
- this(that, 0);
+ this(that, null, 0);
}
- public AndSource(Collection<? extends Predicate<T>> that, int start) {
+ public AndSource(Predicate<T> that,
+ IsVisibleToPredicate<T> isVisibleToPredicate) {
+ this(that, isVisibleToPredicate, 0);
+ }
+
+ public AndSource(Predicate<T> that,
+ IsVisibleToPredicate<T> isVisibleToPredicate, int start) {
+ this(ImmutableList.of(that), isVisibleToPredicate, start);
+ }
+
+ public AndSource(Collection<? extends Predicate<T>> that,
+ IsVisibleToPredicate<T> isVisibleToPredicate, int start) {
super(that);
checkArgument(start >= 0, "negative start: %s", start);
+ this.isVisibleToPredicate = isVisibleToPredicate;
this.start = start;
int c = Integer.MAX_VALUE;
@@ -56,9 +68,10 @@
if (p instanceof DataSource) {
c = Math.min(c, ((DataSource<?>) p).getCardinality());
- if (p.getCost() < minCost) {
+ int cost = p.estimateCost();
+ if (cost < minCost) {
s = toDataSource(p);
- minCost = p.getCost();
+ minCost = cost;
}
}
}
@@ -85,7 +98,7 @@
int nextStart = 0;
boolean skipped = false;
for (T data : buffer(source.read())) {
- if (match(data)) {
+ if (!isMatchable() || match(data)) {
r.add(data);
} else {
skipped = true;
@@ -124,6 +137,24 @@
return new ListResultSet<>(r);
}
+ @Override
+ public boolean isMatchable() {
+ return isVisibleToPredicate != null || super.isMatchable();
+ }
+
+ @Override
+ public boolean match(T object) throws OrmException {
+ if (isVisibleToPredicate != null && !isVisibleToPredicate.match(object)) {
+ return false;
+ }
+
+ if (super.isMatchable() && !super.match(object)) {
+ return false;
+ }
+
+ return true;
+ }
+
private Iterable<T> buffer(ResultSet<T> scanner) {
return FluentIterable.from(Iterables.partition(scanner, 50))
.transformAndConcat(new Function<List<T>, List<T>>() {
@@ -156,7 +187,7 @@
int cmp = ai - bi;
if (cmp == 0) {
- cmp = a.getCost() - b.getCost();
+ cmp = a.estimateCost() - b.estimateCost();
}
if (cmp == 0
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/IsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/IsVisibleToPredicate.java
new file mode 100644
index 0000000..38411e3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/IsVisibleToPredicate.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 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;
+
+public abstract class IsVisibleToPredicate<T> extends OperatorPredicate<T>
+ implements Matchable<T> {
+ public IsVisibleToPredicate(String name, String value) {
+ super(name, value);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/LimitPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/LimitPredicate.java
index d4e7440..7c38e5a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/LimitPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/LimitPredicate.java
@@ -14,7 +14,7 @@
package com.google.gerrit.server.query;
-public class LimitPredicate<T> extends IntPredicate<T> {
+public class LimitPredicate<T> extends IntPredicate<T> implements Matchable<T> {
@SuppressWarnings("unchecked")
public static Integer getLimit(String fieldName, Predicate<?> p) {
IntPredicate<?> ip = QueryBuilder.find(p, IntPredicate.class, fieldName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/Matchable.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/Matchable.java
new file mode 100644
index 0000000..b37e112
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/Matchable.java
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 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;
+
+import com.google.gwtorm.server.OrmException;
+
+public interface Matchable<T> {
+ /**
+ * Does this predicate match this object?
+ *
+ * @throws OrmException
+ */
+ boolean match(T object) throws OrmException;
+
+ /** @return a cost estimate to run this predicate, higher figures cost more. */
+ int getCost();
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
index 248fb9c..8ffba72 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.query;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.gwtorm.server.OrmException;
import java.util.Collection;
@@ -21,7 +23,7 @@
import java.util.List;
/** Negates the result of another predicate. */
-public class NotPredicate<T> extends Predicate<T> {
+public class NotPredicate<T> extends Predicate<T> implements Matchable<T> {
private final Predicate<T> that;
protected NotPredicate(final Predicate<T> that) {
@@ -58,13 +60,20 @@
}
@Override
+ public boolean isMatchable() {
+ return that.isMatchable();
+ }
+
+ @Override
public boolean match(final T object) throws OrmException {
- return !that.match(object);
+ checkState(that.isMatchable(), "match invoked, but child predicate %s "
+ + "doesn't implement %s", that, Matchable.class.getName());
+ return !that.asMatchable().match(object);
}
@Override
public int getCost() {
- return that.getCost();
+ return that.estimateCost();
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
index e9fea02..2cb70af 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OperatorPredicate.java
@@ -22,7 +22,7 @@
private final String name;
private final String value;
- public OperatorPredicate(final String name, final String value) {
+ protected OperatorPredicate(final String name, final String value) {
this.name = name;
this.value = value;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
index 2432a41..ad15286 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.query;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.gwtorm.server.OrmException;
import java.util.ArrayList;
@@ -23,7 +25,7 @@
import java.util.List;
/** Requires one predicate to be true. */
-public class OrPredicate<T> extends Predicate<T> {
+public class OrPredicate<T> extends Predicate<T> implements Matchable<T> {
private final List<Predicate<T>> children;
private final int cost;
@@ -39,11 +41,11 @@
if (getClass() == p.getClass()) {
for (Predicate<T> gp : p.getChildren()) {
t.add(gp);
- c += gp.getCost();
+ c += gp.estimateCost();
}
} else {
t.add(p);
- c += p.getCost();
+ c += p.estimateCost();
}
}
children = t;
@@ -71,9 +73,21 @@
}
@Override
+ public boolean isMatchable() {
+ for (Predicate<T> c : children) {
+ if (!c.isMatchable()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
public boolean match(final T object) throws OrmException {
for (final Predicate<T> c : children) {
- if (c.match(object)) {
+ checkState(c.isMatchable(), "match invoked, but child predicate %s "
+ + "doesn't implement %s", c, Matchable.class.getName());
+ if (c.asMatchable().match(object)) {
return true;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
index f4be013..3a38da6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
@@ -14,8 +14,9 @@
package com.google.gerrit.server.query;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.collect.Iterables;
-import com.google.gwtorm.server.OrmException;
import java.util.Collection;
import java.util.Collections;
@@ -113,15 +114,23 @@
/** Create a copy of this predicate, with new children. */
public abstract Predicate<T> copy(Collection<? extends Predicate<T>> children);
- /**
- * Does this predicate match this object?
- *
- * @throws OrmException
- */
- public abstract boolean match(T object) throws OrmException;
+ public boolean isMatchable() {
+ return this instanceof Matchable;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Matchable<T> asMatchable() {
+ checkState(isMatchable(), "not matchable");
+ return (Matchable<T>) this;
+ }
/** @return a cost estimate to run this predicate, higher figures cost more. */
- public abstract int getCost();
+ public int estimateCost() {
+ if (!isMatchable()) {
+ return 1;
+ }
+ return asMatchable().getCost();
+ }
@Override
public abstract int hashCode();
@@ -129,7 +138,7 @@
@Override
public abstract boolean equals(Object other);
- private static class Any<T> extends Predicate<T> {
+ private static class Any<T> extends Predicate<T> implements Matchable<T> {
private static final Any<Object> INSTANCE = new Any<>();
private Any() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIdPredicate.java
index 659f5d8..8fda4c0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIdPredicate.java
@@ -18,25 +18,10 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.account.AccountField;
-import com.google.gwtorm.server.OrmException;
public class AccountIdPredicate extends IndexPredicate<AccountState> {
- private final Account.Id accountId;
-
public AccountIdPredicate(Account.Id accountId) {
super(AccountField.ID, AccountQueryBuilder.FIELD_ACCOUNT,
accountId.toString());
- this.accountId = accountId;
}
-
- @Override
- public boolean match(AccountState accountState) throws OrmException {
- return accountId.equals(accountState.getAccount().getId());
- }
-
- @Override
- public int getCost() {
- return 1;
- }
-
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/IsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIsVisibleToPredicate.java
similarity index 88%
rename from gerrit-server/src/main/java/com/google/gerrit/server/query/account/IsVisibleToPredicate.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIsVisibleToPredicate.java
index 8fbe4cf..dc68a61 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/IsVisibleToPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountIsVisibleToPredicate.java
@@ -17,11 +17,12 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountControl;
import com.google.gerrit.server.account.AccountState;
-import com.google.gerrit.server.query.OperatorPredicate;
+import com.google.gerrit.server.query.IsVisibleToPredicate;
import com.google.gerrit.server.query.change.SingleGroupUser;
import com.google.gwtorm.server.OrmException;
-public class IsVisibleToPredicate extends OperatorPredicate<AccountState> {
+public class AccountIsVisibleToPredicate
+ extends IsVisibleToPredicate<AccountState> {
private static String describe(CurrentUser user) {
if (user.isIdentifiedUser()) {
return user.getAccountId().toString();
@@ -35,7 +36,7 @@
private final AccountControl accountControl;
- IsVisibleToPredicate(AccountControl accountControl) {
+ AccountIsVisibleToPredicate(AccountControl accountControl) {
super(AccountQueryBuilder.FIELD_VISIBLETO,
describe(accountControl.getUser()));
this.accountControl = accountControl;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
index b2be7b5..4819404 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
@@ -14,13 +14,14 @@
package com.google.gerrit.server.query.account;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.query.account.AccountQueryBuilder.FIELD_LIMIT;
-import com.google.common.collect.ImmutableList;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountControl;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.index.IndexConfig;
+import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.account.AccountIndexRewriter;
import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
@@ -33,6 +34,13 @@
public class AccountQueryProcessor extends QueryProcessor<AccountState> {
private final AccountControl.Factory accountControlFactory;
+ static {
+ // It is assumed that basic rewrites do not touch visibleto predicates.
+ checkState(
+ !AccountIsVisibleToPredicate.class.isAssignableFrom(IndexPredicate.class),
+ "AccountQueryProcessor assumes visibleto is not used by the index rewriter.");
+ }
+
@Inject
protected AccountQueryProcessor(Provider<CurrentUser> userProvider,
Metrics metrics,
@@ -48,7 +56,7 @@
@Override
protected Predicate<AccountState> enforceVisibility(
Predicate<AccountState> pred) {
- return new AndSource<>(ImmutableList.of(pred,
- new IsVisibleToPredicate(accountControlFactory.get())));
+ return new AndSource<>(pred,
+ new AccountIsVisibleToPredicate(accountControlFactory.get()));
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
index b20a194..241b7fc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
@@ -14,12 +14,11 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IntegerRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
-public class AddedPredicate extends IntegerRangePredicate<ChangeData> {
+public class AddedPredicate extends IntegerRangeChangePredicate {
AddedPredicate(String value) throws QueryParseException {
super(ChangeField.ADDED, value);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
index 5ed871a..477bf16 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
@@ -14,14 +14,13 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.TimestampRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
import java.util.Date;
-public class AfterPredicate extends TimestampRangePredicate<ChangeData> {
+public class AfterPredicate extends TimestampRangeChangePredicate {
private final Date cut;
AfterPredicate(String value) throws QueryParseException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
index 2b140d3..fd6cbee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
@@ -20,13 +20,12 @@
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.index.TimestampRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import java.sql.Timestamp;
-public class AgePredicate extends TimestampRangePredicate<ChangeData> {
+public class AgePredicate extends TimestampRangeChangePredicate {
private final long cut;
AgePredicate(String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndChangeSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndChangeSource.java
index d40e53f..bd7daed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndChangeSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndChangeSource.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.server.query.AndSource;
+import com.google.gerrit.server.query.IsVisibleToPredicate;
import com.google.gerrit.server.query.Predicate;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
@@ -25,13 +26,13 @@
public class AndChangeSource extends AndSource<ChangeData>
implements ChangeDataSource {
- public AndChangeSource(Collection<? extends Predicate<ChangeData>> that) {
- super(that, 0);
+ public AndChangeSource(Collection<Predicate<ChangeData>> that) {
+ super(that);
}
- public AndChangeSource(Collection<? extends Predicate<ChangeData>> that,
- int start) {
- super(that, start);
+ public AndChangeSource(Predicate<ChangeData> that,
+ IsVisibleToPredicate<ChangeData> isVisibleToPredicate, int start) {
+ super(that, isVisibleToPredicate, start);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
index ae192ab..ebaaab9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
@@ -17,11 +17,10 @@
import static com.google.gerrit.server.index.change.ChangeField.AUTHOR;
import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_AUTHOR;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-public class AuthorPredicate extends IndexPredicate<ChangeData> {
+public class AuthorPredicate extends ChangeIndexPredicate {
AuthorPredicate(String value) {
super(AUTHOR, FIELD_AUTHOR, value.toLowerCase());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
index 0618cc2..f36a1631 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
@@ -14,14 +14,13 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.TimestampRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
import java.util.Date;
-public class BeforePredicate extends TimestampRangePredicate<ChangeData> {
+public class BeforePredicate extends TimestampRangeChangePredicate {
private final Date cut;
BeforePredicate(String value) throws QueryParseException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
index 1fbeb86..85d433a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
@@ -15,12 +15,11 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
/** Predicate over Change-Id strings (aka Change.Key). */
-class ChangeIdPredicate extends IndexPredicate<ChangeData> {
+class ChangeIdPredicate extends ChangeIndexPredicate {
ChangeIdPredicate(String id) {
super(ChangeField.ID, ChangeQueryBuilder.FIELD_CHANGE, id);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIndexPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIndexPredicate.java
new file mode 100644
index 0000000..80951fd
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIndexPredicate.java
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 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.server.index.FieldDef;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.query.Matchable;
+
+public abstract class ChangeIndexPredicate extends IndexPredicate<ChangeData>
+ implements Matchable<ChangeData> {
+ protected ChangeIndexPredicate(FieldDef<ChangeData, ?> def, String value) {
+ super(def, value);
+ }
+
+ protected ChangeIndexPredicate(FieldDef<ChangeData, ?> def, String name,
+ String value) {
+ super(def, name, value);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
similarity index 91%
rename from gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
index c4214f2..303c9f8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
@@ -20,11 +20,11 @@
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.query.OperatorPredicate;
+import com.google.gerrit.server.query.IsVisibleToPredicate;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider;
-class IsVisibleToPredicate extends OperatorPredicate<ChangeData> {
+class ChangeIsVisibleToPredicate extends IsVisibleToPredicate<ChangeData> {
private static String describe(CurrentUser user) {
if (user.isIdentifiedUser()) {
return user.getAccountId().toString();
@@ -41,7 +41,8 @@
private final ChangeControl.GenericFactory changeControl;
private final CurrentUser user;
- IsVisibleToPredicate(Provider<ReviewDb> db, ChangeNotes.Factory notesFactory,
+ ChangeIsVisibleToPredicate(Provider<ReviewDb> db,
+ ChangeNotes.Factory notesFactory,
ChangeControl.GenericFactory changeControlFactory, CurrentUser user) {
super(ChangeQueryBuilder.FIELD_VISIBLETO, describe(user));
this.db = db;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeOperatorPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeOperatorPredicate.java
new file mode 100644
index 0000000..6bec598
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeOperatorPredicate.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 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.server.query.Matchable;
+import com.google.gerrit.server.query.OperatorPredicate;
+
+public abstract class ChangeOperatorPredicate extends
+ OperatorPredicate<ChangeData> implements Matchable<ChangeData> {
+
+ protected ChangeOperatorPredicate(String name, String value) {
+ super(name, value);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index b99f024..a150c93 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -479,7 +479,7 @@
// not status: alias?
}
- throw new IllegalArgumentException();
+ throw error("Invalid query");
}
@Operator
@@ -768,7 +768,7 @@
}
public Predicate<ChangeData> visibleto(CurrentUser user) {
- return new IsVisibleToPredicate(args.db, args.notesFactory,
+ return new ChangeIsVisibleToPredicate(args.db, args.notesFactory,
args.changeControlGenericFactory, user);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
index 4e534c8..44e5e7e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryProcessor.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_LIMIT;
-import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.index.IndexConfig;
@@ -44,7 +43,7 @@
static {
// It is assumed that basic rewrites do not touch visibleto predicates.
checkState(
- !IsVisibleToPredicate.class.isAssignableFrom(IndexPredicate.class),
+ !ChangeIsVisibleToPredicate.class.isAssignableFrom(IndexPredicate.class),
"ChangeQueryProcessor assumes visibleto is not used by the index rewriter.");
}
@@ -80,7 +79,7 @@
@Override
protected Predicate<ChangeData> enforceVisibility(
Predicate<ChangeData> pred) {
- return new AndChangeSource(ImmutableList.of(pred, new IsVisibleToPredicate(db,
- notesFactory, changeControlFactory, userProvider.get())), start);
+ return new AndChangeSource(pred, new ChangeIsVisibleToPredicate(db,
+ notesFactory, changeControlFactory, userProvider.get()), start);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeRegexPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeRegexPredicate.java
new file mode 100644
index 0000000..747d72d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeRegexPredicate.java
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 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.server.index.FieldDef;
+import com.google.gerrit.server.index.RegexPredicate;
+import com.google.gerrit.server.query.Matchable;
+
+public abstract class ChangeRegexPredicate extends RegexPredicate<ChangeData>
+ implements Matchable<ChangeData> {
+ protected ChangeRegexPredicate(FieldDef<ChangeData, ?> def, String value) {
+ super(def, value);
+ }
+
+ protected ChangeRegexPredicate(FieldDef<ChangeData, ?> def, String name,
+ String value) {
+ super(def, name, value);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
index 4d42c33..1c92ecf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
@@ -16,7 +16,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.Predicate;
import com.google.gwtorm.server.OrmException;
@@ -36,7 +35,7 @@
* <p>
* Status names are looked up by prefix case-insensitively.
*/
-public final class ChangeStatusPredicate extends IndexPredicate<ChangeData> {
+public final class ChangeStatusPredicate extends ChangeIndexPredicate {
private static final TreeMap<String, Predicate<ChangeData>> PREDICATES;
private static final Predicate<ChangeData> CLOSED;
private static final Predicate<ChangeData> OPEN;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
index 1967a06..48d6e05 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
@@ -17,13 +17,12 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import java.util.Objects;
-class CommentByPredicate extends IndexPredicate<ChangeData> {
+class CommentByPredicate extends ChangeIndexPredicate {
private final Account.Id id;
CommentByPredicate(Account.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
index 5e3fa3d..b351740 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndex;
import com.google.gerrit.server.index.change.IndexedChangeQuery;
@@ -22,7 +21,7 @@
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
-class CommentPredicate extends IndexPredicate<ChangeData> {
+class CommentPredicate extends ChangeIndexPredicate {
private final ChangeIndex index;
CommentPredicate(ChangeIndex index, String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
index 91b2c58..aa3dde3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
@@ -20,10 +20,9 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.index.FieldDef;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gwtorm.server.OrmException;
-class CommitPredicate extends IndexPredicate<ChangeData> {
+class CommitPredicate extends ChangeIndexPredicate {
static FieldDef<ChangeData, ?> commitField(String id) {
if (id.length() == OBJECT_ID_STRING_LENGTH) {
return EXACT_COMMIT;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
index f923d00..06f5379 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
@@ -17,11 +17,10 @@
import static com.google.gerrit.server.index.change.ChangeField.COMMITTER;
import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_COMMITTER;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-public class CommitterPredicate extends IndexPredicate<ChangeData> {
+public class CommitterPredicate extends ChangeIndexPredicate {
CommitterPredicate(String value) {
super(COMMITTER, FIELD_COMMITTER, value.toLowerCase());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
index 74865ec..69bc2ca 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
@@ -25,7 +25,6 @@
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gerrit.server.query.OrPredicate;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
@@ -84,7 +83,7 @@
predicatesForOneChange.add(or(or(filePredicates),
new IsMergePredicate(args, value)));
- predicatesForOneChange.add(new OperatorPredicate<ChangeData>(
+ predicatesForOneChange.add(new ChangeOperatorPredicate(
ChangeQueryBuilder.FIELD_CONFLICTS, value) {
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
index 8e9ac73..9bd6956 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
@@ -14,12 +14,11 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IntegerRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
-public class DeletedPredicate extends IntegerRangePredicate<ChangeData> {
+public class DeletedPredicate extends IntegerRangeChangePredicate {
DeletedPredicate(String value) throws QueryParseException {
super(ChangeField.DELETED, value);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
index a3eaa8a..07e6590 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
@@ -14,13 +14,12 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IntegerRangePredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
import com.google.gwtorm.server.OrmException;
-public class DeltaPredicate extends IntegerRangePredicate<ChangeData> {
+public class DeltaPredicate extends IntegerRangeChangePredicate {
DeltaPredicate(String value) throws QueryParseException {
super(ChangeField.DELTA, value);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DestinationPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DestinationPredicate.java
index 25fa09f..7e573dc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DestinationPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DestinationPredicate.java
@@ -16,12 +16,11 @@
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gwtorm.server.OrmException;
import java.util.Set;
-class DestinationPredicate extends OperatorPredicate<ChangeData> {
+class DestinationPredicate extends ChangeOperatorPredicate {
Set<Branch.NameKey> destinations;
DestinationPredicate(Set<Branch.NameKey> destinations, String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
index f1fa000..8be5235 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class EditByPredicate extends IndexPredicate<ChangeData> {
+class EditByPredicate extends ChangeIndexPredicate {
private final Account.Id id;
EditByPredicate(Account.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
index 8c98b6f..6877761 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
@@ -14,13 +14,12 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
import com.google.gwtorm.server.OrmException;
-class EqualsFilePredicate extends IndexPredicate<ChangeData> {
+class EqualsFilePredicate extends ChangeIndexPredicate {
static Predicate<ChangeData> create(Arguments args, String value) {
Predicate<ChangeData> eqPath =
new EqualsPathPredicate(ChangeQueryBuilder.FIELD_FILE, value);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
index b01fdbe..e752b05 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
@@ -23,7 +23,6 @@
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -32,7 +31,7 @@
import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider;
-class EqualsLabelPredicate extends IndexPredicate<ChangeData> {
+class EqualsLabelPredicate extends ChangeIndexPredicate {
private final ProjectCache projectCache;
private final ChangeControl.GenericFactory ccFactory;
private final IdentifiedUser.GenericFactory userFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
index 85c3cd5..5edd06c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
@@ -14,14 +14,13 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import java.util.Collections;
import java.util.List;
-class EqualsPathPredicate extends IndexPredicate<ChangeData> {
+class EqualsPathPredicate extends ChangeIndexPredicate {
private final String value;
EqualsPathPredicate(String fieldName, String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
index 6658577..510910e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
@@ -17,10 +17,9 @@
import static com.google.gerrit.server.index.change.ChangeField.EXACT_TOPIC;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gwtorm.server.OrmException;
-class ExactTopicPredicate extends IndexPredicate<ChangeData> {
+class ExactTopicPredicate extends ChangeIndexPredicate {
ExactTopicPredicate(String topic) {
super(EXACT_TOPIC, topic);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
index 23b3ee6..5651544 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
@@ -18,14 +18,13 @@
import com.google.common.collect.Iterables;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeIndex;
import com.google.gerrit.server.index.change.IndexedChangeQuery;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gwtorm.server.OrmException;
-class FuzzyTopicPredicate extends IndexPredicate<ChangeData> {
+class FuzzyTopicPredicate extends ChangeIndexPredicate {
private final ChangeIndex index;
FuzzyTopicPredicate(String topic, ChangeIndex index) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
index ff9c544..9e9bc8d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
@@ -15,13 +15,12 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import java.util.List;
-class GroupPredicate extends IndexPredicate<ChangeData> {
+class GroupPredicate extends ChangeIndexPredicate {
GroupPredicate(String group) {
super(ChangeField.GROUP, group);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
index f85a9ed..45a00c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
@@ -17,7 +17,6 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
import com.google.gwtorm.server.ListResultSet;
import com.google.gwtorm.server.OrmException;
@@ -29,8 +28,8 @@
import java.util.Set;
@Deprecated
-class HasDraftByLegacyPredicate extends OperatorPredicate<ChangeData> implements
- ChangeDataSource {
+class HasDraftByLegacyPredicate extends ChangeOperatorPredicate
+ implements ChangeDataSource {
private final Arguments args;
private final Account.Id accountId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
index c18e19c..244589c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class HasDraftByPredicate extends IndexPredicate<ChangeData> {
+class HasDraftByPredicate extends ChangeIndexPredicate {
private final Account.Id accountId;
HasDraftByPredicate(Account.Id accountId) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasStarsPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasStarsPredicate.java
index 83990bc..eb3a137 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasStarsPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasStarsPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-public class HasStarsPredicate extends IndexPredicate<ChangeData> {
+public class HasStarsPredicate extends ChangeIndexPredicate {
private final Account.Id accountId;
HasStarsPredicate(Account.Id accountId) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
index 3f952d3..185a539 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.server.change.HashtagsUtil;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class HashtagPredicate extends IndexPredicate<ChangeData> {
+class HashtagPredicate extends ChangeIndexPredicate {
HashtagPredicate(String hashtag) {
super(ChangeField.HASHTAG, HashtagsUtil.cleanupHashtag(hashtag));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IntegerRangeChangePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IntegerRangeChangePredicate.java
new file mode 100644
index 0000000..a272fbb
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IntegerRangeChangePredicate.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 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.server.index.FieldDef;
+import com.google.gerrit.server.index.IntegerRangePredicate;
+import com.google.gerrit.server.query.Matchable;
+import com.google.gerrit.server.query.QueryParseException;
+
+public abstract class IntegerRangeChangePredicate
+ extends IntegerRangePredicate<ChangeData> implements Matchable<ChangeData> {
+
+ protected IntegerRangeChangePredicate(FieldDef<ChangeData, Integer> type,
+ String value) throws QueryParseException {
+ super(type, value);
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergePredicate.java
index 3c02bab..376ad84 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergePredicate.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.server.git.CodeReviewCommit;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
import com.google.gwtorm.server.OrmException;
@@ -26,7 +25,7 @@
import java.io.IOException;
-public class IsMergePredicate extends OperatorPredicate<ChangeData> {
+public class IsMergePredicate extends ChangeOperatorPredicate {
private final Arguments args;
public IsMergePredicate(Arguments args, String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
index 5dd7dd2..d998fa3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.server.index.FieldDef.FillArgs;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class IsMergeablePredicate extends IndexPredicate<ChangeData> {
+class IsMergeablePredicate extends ChangeIndexPredicate {
private final FillArgs args;
IsMergeablePredicate(FillArgs args) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
index 604f84b..24fcd6b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
@@ -17,7 +17,6 @@
import static com.google.gerrit.server.index.change.ChangeField.REVIEWEDBY;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.query.Predicate;
import com.google.gwtorm.server.OrmException;
@@ -27,7 +26,7 @@
import java.util.List;
import java.util.Set;
-class IsReviewedPredicate extends IndexPredicate<ChangeData> {
+class IsReviewedPredicate extends ChangeIndexPredicate {
private static final Account.Id NOT_REVIEWED =
new Account.Id(ChangeField.NOT_REVIEWED);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
index 634bc4a..929ed18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
@@ -15,12 +15,11 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
@Deprecated
-class IsStarredByPredicate extends IndexPredicate<ChangeData> {
+class IsStarredByPredicate extends ChangeIndexPredicate {
private final Account.Id accountId;
IsStarredByPredicate(Account.Id accountId) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
index 656eca0..425eb00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
@@ -17,10 +17,9 @@
import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
/** Predicate over change number (aka legacy ID or Change.Id). */
-public class LegacyChangeIdPredicate extends IndexPredicate<ChangeData> {
+public class LegacyChangeIdPredicate extends ChangeIndexPredicate {
private final Change.Id id;
LegacyChangeIdPredicate(Change.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyReviewerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyReviewerPredicate.java
index db10670..cd93ed3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyReviewerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyReviewerPredicate.java
@@ -15,12 +15,11 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
@Deprecated
-class LegacyReviewerPredicate extends IndexPredicate<ChangeData> {
+class LegacyReviewerPredicate extends ChangeIndexPredicate {
private final Account.Id id;
LegacyReviewerPredicate(Account.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
index 021b6d7..722a8ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndex;
import com.google.gerrit.server.index.change.IndexedChangeQuery;
@@ -26,7 +25,7 @@
* Predicate to match changes that contains specified text in commit messages
* body.
*/
-class MessagePredicate extends IndexPredicate<ChangeData> {
+class MessagePredicate extends ChangeIndexPredicate {
private final ChangeIndex index;
MessagePredicate(ChangeIndex index, String value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
index bb7cb403a..dfaac08 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
@@ -16,11 +16,10 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class OwnerPredicate extends IndexPredicate<ChangeData> {
+class OwnerPredicate extends ChangeIndexPredicate {
private final Account.Id id;
OwnerPredicate(Account.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
index 467e4c5..72327ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
@@ -17,10 +17,9 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gwtorm.server.OrmException;
-class OwnerinPredicate extends OperatorPredicate<ChangeData> {
+class OwnerinPredicate extends ChangeOperatorPredicate {
private final IdentifiedUser.GenericFactory userFactory;
private final AccountGroup.UUID uuid;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
index 0bb5650..644870d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
@@ -16,11 +16,10 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class ProjectPredicate extends IndexPredicate<ChangeData> {
+class ProjectPredicate extends ChangeIndexPredicate {
ProjectPredicate(String id) {
super(ChangeField.PROJECT, id);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
index 400a204..4c06d1b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class ProjectPrefixPredicate extends IndexPredicate<ChangeData> {
+class ProjectPrefixPredicate extends ChangeIndexPredicate {
ProjectPrefixPredicate(String prefix) {
super(ChangeField.PROJECTS, prefix);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
index e62855f..491aed9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class RefPredicate extends IndexPredicate<ChangeData> {
+class RefPredicate extends ChangeIndexPredicate {
RefPredicate(String ref) {
super(ChangeField.REF, ref);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
index d1e0f02..67efd69 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
@@ -14,14 +14,13 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.server.index.RegexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.util.RegexListSearcher;
import com.google.gwtorm.server.OrmException;
import java.util.List;
-class RegexPathPredicate extends RegexPredicate<ChangeData> {
+class RegexPathPredicate extends ChangeRegexPredicate {
RegexPathPredicate(String re) {
super(ChangeField.PATH, re);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
index 48c815f..007566e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
@@ -16,14 +16,13 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.index.RegexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import dk.brics.automaton.RegExp;
import dk.brics.automaton.RunAutomaton;
-class RegexProjectPredicate extends RegexPredicate<ChangeData> {
+class RegexProjectPredicate extends ChangeRegexPredicate {
private final RunAutomaton pattern;
RegexProjectPredicate(String re) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
index 00c1dfe..c6d1577 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
@@ -15,14 +15,13 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.RegexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
import dk.brics.automaton.RegExp;
import dk.brics.automaton.RunAutomaton;
-class RegexRefPredicate extends RegexPredicate<ChangeData> {
+class RegexRefPredicate extends ChangeRegexPredicate {
private final RunAutomaton pattern;
RegexRefPredicate(String re) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
index d51aaa4..2d65670 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
@@ -17,13 +17,12 @@
import static com.google.gerrit.server.index.change.ChangeField.FUZZY_TOPIC;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.RegexPredicate;
import com.google.gwtorm.server.OrmException;
import dk.brics.automaton.RegExp;
import dk.brics.automaton.RunAutomaton;
-class RegexTopicPredicate extends RegexPredicate<ChangeData> {
+class RegexTopicPredicate extends ChangeRegexPredicate {
private final RunAutomaton pattern;
RegexTopicPredicate(String re) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
index d655a5f..1c4fbbb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
@@ -16,7 +16,6 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.notedb.ReviewerStateInternal;
import com.google.gerrit.server.query.Predicate;
@@ -26,7 +25,7 @@
import java.util.ArrayList;
import java.util.List;
-class ReviewerPredicate extends IndexPredicate<ChangeData> {
+class ReviewerPredicate extends ChangeIndexPredicate {
@SuppressWarnings("deprecation")
static Predicate<ChangeData> create(Arguments args, Account.Id id) {
List<Predicate<ChangeData>> and = new ArrayList<>(2);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
index 76a02432..34c10e3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
@@ -17,10 +17,9 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gwtorm.server.OrmException;
-class ReviewerinPredicate extends OperatorPredicate<ChangeData> {
+class ReviewerinPredicate extends ChangeOperatorPredicate {
private final IdentifiedUser.GenericFactory userFactory;
private final AccountGroup.UUID uuid;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/StarPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/StarPredicate.java
index 2facdb7..a31254f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/StarPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/StarPredicate.java
@@ -16,11 +16,10 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.StarredChangesUtil;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-public class StarPredicate extends IndexPredicate<ChangeData> {
+public class StarPredicate extends ChangeIndexPredicate {
private final Account.Id accountId;
private final String label;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
index 35a5a29..d8d5258 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
@@ -15,11 +15,10 @@
package com.google.gerrit.server.query.change;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
-class SubmissionIdPredicate extends IndexPredicate<ChangeData> {
+class SubmissionIdPredicate extends ChangeIndexPredicate {
SubmissionIdPredicate(String changeSet) {
super(ChangeField.SUBMISSIONID, changeSet);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TimestampRangeChangePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TimestampRangeChangePredicate.java
new file mode 100644
index 0000000..9242d9d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TimestampRangeChangePredicate.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 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.server.index.FieldDef;
+import com.google.gerrit.server.index.TimestampRangePredicate;
+import com.google.gerrit.server.query.Matchable;
+
+import java.sql.Timestamp;
+
+public abstract class TimestampRangeChangePredicate extends
+ TimestampRangePredicate<ChangeData> implements Matchable<ChangeData> {
+ protected TimestampRangeChangePredicate(FieldDef<ChangeData, Timestamp> def,
+ String name, String value) {
+ super(def, name, value);
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
index aed8831..e9be4cd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
@@ -16,7 +16,6 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.config.TrackingFooters;
-import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gwtorm.server.OrmException;
@@ -27,7 +26,7 @@
import java.io.IOException;
import java.util.List;
-class TrackingIdPredicate extends IndexPredicate<ChangeData> {
+class TrackingIdPredicate extends ChangeIndexPredicate {
private static final Logger log = LoggerFactory.getLogger(TrackingIdPredicate.class);
private final TrackingFooters trackingFooters;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/NotesMigrationSchemaFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/NotesMigrationSchemaFactory.java
index 6f39a12..f38ddfa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/NotesMigrationSchemaFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/NotesMigrationSchemaFactory.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.schema;
+import com.google.gerrit.reviewdb.server.DisabledChangesReviewDbWrapper;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gwtorm.server.OrmException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
index cc3dc5d..0b7e8b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
@@ -17,6 +17,7 @@
import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
@@ -92,7 +93,7 @@
}
public void update(final UpdateUI ui) throws OrmException {
- try (ReviewDb db = unwrap(schema.open())) {
+ try (ReviewDb db = ReviewDbUtil.unwrapDb(schema.open())) {
final SchemaVersion u = updater.get();
final CurrentSchemaVersion version = getSchemaVersion(db);
@@ -115,13 +116,6 @@
}
}
- private static ReviewDb unwrap(ReviewDb db) {
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
- }
-
private CurrentSchemaVersion getSchemaVersion(final ReviewDb db) {
try {
return db.schemaVersion().get(new CurrentSchemaVersion.Key());
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
index 5316bcb..0b5ed32 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
@@ -18,7 +18,6 @@
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
-import com.google.gwtorm.server.OrmException;
import org.junit.Ignore;
@@ -44,16 +43,6 @@
}
private Predicate<ChangeData> predicate(String name, String value) {
- return new OperatorPredicate<ChangeData>(name, value) {
- @Override
- public boolean match(ChangeData object) throws OrmException {
- return false;
- }
-
- @Override
- public int getCost() {
- return 0;
- }
- };
+ return new OperatorPredicate<ChangeData>(name, value) {};
}
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/ValidatorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/ValidatorTest.java
new file mode 100644
index 0000000..6707c9f
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/ValidatorTest.java
@@ -0,0 +1,61 @@
+// Copyright (C) 2016 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.mail;
+
+import static com.google.common.truth.Truth.assert_;
+
+import org.apache.commons.validator.routines.EmailValidator;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class ValidatorTest {
+ private static final String UNSUPPORTED_PREFIX = "#! ";
+
+ @Test
+ public void validateTopLevelDomains() throws Exception {
+ try (InputStream in =
+ this.getClass().getResourceAsStream("tlds-alpha-by-domain.txt")) {
+ if (in == null) {
+ throw new Exception("TLD list not found");
+ }
+ BufferedReader r = new BufferedReader(new InputStreamReader(in));
+ String tld;
+ EmailValidator validator = EmailValidator.getInstance();
+ while ((tld = r.readLine()) != null) {
+ if (tld.startsWith("# ") || tld.startsWith("XN--")) {
+ // Ignore comments and non-latin domains
+ continue;
+ }
+ if (tld.startsWith(UNSUPPORTED_PREFIX)) {
+ String test = "test@example."
+ + tld.toLowerCase().substring(UNSUPPORTED_PREFIX.length());
+ assert_()
+ .withFailureMessage("expected invalid TLD \"" + test + "\"")
+ .that(validator.isValid(test))
+ .isFalse();
+ } else {
+ String test = "test@example." + tld.toLowerCase();
+ assert_()
+ .withFailureMessage("failed to validate TLD \"" + test + "\"")
+ .that(validator.isValid(test))
+ .isTrue();
+ }
+ }
+ }
+ }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/PredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/PredicateTest.java
index a0a6e40..7762e50 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/PredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/PredicateTest.java
@@ -24,16 +24,6 @@
protected TestPredicate(String name, String value) {
super(name, value);
}
-
- @Override
- public boolean match(String object) {
- return false;
- }
-
- @Override
- public int getCost() {
- return 0;
- }
}
protected static TestPredicate f(String name, String value) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
index 66eed8b..61bfe78 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
@@ -28,7 +28,6 @@
import com.google.gerrit.server.notedb.ChangeBundle;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeRebuilder;
-import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -71,7 +70,7 @@
public void rebuildAndCheckAllChanges() throws Exception {
rebuildAndCheckChanges(
Iterables.transform(
- unwrapDb().changes().all(),
+ getUnwrappedDb().changes().all(),
ReviewDbUtil.changeIdFunction()));
}
@@ -81,7 +80,7 @@
public void rebuildAndCheckChanges(Iterable<Change.Id> changeIds)
throws Exception {
- ReviewDb db = unwrapDb();
+ ReviewDb db = getUnwrappedDb();
List<ChangeBundle> allExpected = readExpected(changeIds);
@@ -124,7 +123,7 @@
private List<ChangeBundle> readExpected(Iterable<Change.Id> changeIds)
throws Exception {
- ReviewDb db = unwrapDb();
+ ReviewDb db = getUnwrappedDb();
boolean old = notesMigration.readChanges();
try {
notesMigration.setReadChanges(false);
@@ -142,7 +141,7 @@
private void checkActual(List<ChangeBundle> allExpected, List<String> msgs)
throws Exception {
- ReviewDb db = unwrapDb();
+ ReviewDb db = getUnwrappedDb();
boolean oldRead = notesMigration.readChanges();
boolean oldWrite = notesMigration.writeChanges();
try {
@@ -179,11 +178,8 @@
}
}
- private ReviewDb unwrapDb() {
+ private ReviewDb getUnwrappedDb() {
ReviewDb db = dbProvider.get();
- if (db instanceof DisabledChangesReviewDbWrapper) {
- db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
- }
- return db;
+ return ReviewDbUtil.unwrapDb(db);
}
}
diff --git a/gerrit-server/src/test/resources/com/google/gerrit/server/mail/tlds-alpha-by-domain.txt b/gerrit-server/src/test/resources/com/google/gerrit/server/mail/tlds-alpha-by-domain.txt
new file mode 100644
index 0000000..9edf6a4
--- /dev/null
+++ b/gerrit-server/src/test/resources/com/google/gerrit/server/mail/tlds-alpha-by-domain.txt
@@ -0,0 +1,1329 @@
+# Version 2016060601, Last Updated Tue Jun 7 07:07:01 2016 UTC
+# From http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+AAA
+AARP
+ABB
+ABBOTT
+ABBVIE
+ABOGADO
+ABUDHABI
+AC
+ACADEMY
+ACCENTURE
+ACCOUNTANT
+ACCOUNTANTS
+ACO
+ACTIVE
+ACTOR
+AD
+ADAC
+ADS
+ADULT
+AE
+AEG
+AERO
+#! AETNA
+AF
+AFL
+AG
+AGAKHAN
+AGENCY
+AI
+AIG
+AIRFORCE
+AIRTEL
+AKDN
+AL
+ALIBABA
+ALIPAY
+ALLFINANZ
+ALLY
+ALSACE
+AM
+AMICA
+AMSTERDAM
+ANALYTICS
+ANDROID
+ANQUAN
+AO
+APARTMENTS
+APP
+APPLE
+AQ
+AQUARELLE
+AR
+ARAMCO
+ARCHI
+ARMY
+ARPA
+ARTE
+AS
+ASIA
+ASSOCIATES
+AT
+ATTORNEY
+AU
+AUCTION
+AUDI
+AUDIO
+AUTHOR
+AUTO
+AUTOS
+AVIANCA
+AW
+AWS
+AX
+AXA
+AZ
+AZURE
+BA
+BABY
+BAIDU
+BAND
+BANK
+BAR
+BARCELONA
+BARCLAYCARD
+BARCLAYS
+BAREFOOT
+BARGAINS
+BAUHAUS
+BAYERN
+BB
+BBC
+BBVA
+BCG
+BCN
+BD
+BE
+BEATS
+BEER
+BENTLEY
+BERLIN
+BEST
+BET
+BF
+BG
+BH
+BHARTI
+BI
+BIBLE
+BID
+BIKE
+BING
+BINGO
+BIO
+BIZ
+BJ
+BLACK
+BLACKFRIDAY
+#! BLOG
+BLOOMBERG
+BLUE
+BM
+BMS
+BMW
+BN
+BNL
+BNPPARIBAS
+BO
+BOATS
+BOEHRINGER
+BOM
+BOND
+BOO
+BOOK
+BOOTS
+BOSCH
+BOSTIK
+BOT
+BOUTIQUE
+BR
+BRADESCO
+BRIDGESTONE
+BROADWAY
+BROKER
+BROTHER
+BRUSSELS
+BS
+BT
+BUDAPEST
+BUGATTI
+BUILD
+BUILDERS
+BUSINESS
+BUY
+BUZZ
+BV
+BW
+BY
+BZ
+BZH
+CA
+CAB
+CAFE
+CAL
+CALL
+CAMERA
+CAMP
+CANCERRESEARCH
+CANON
+CAPETOWN
+CAPITAL
+CAR
+CARAVAN
+CARDS
+CARE
+CAREER
+CAREERS
+CARS
+CARTIER
+CASA
+CASH
+CASINO
+CAT
+CATERING
+CBA
+CBN
+CC
+CD
+CEB
+CENTER
+CEO
+CERN
+CF
+CFA
+CFD
+CG
+CH
+CHANEL
+CHANNEL
+CHASE
+CHAT
+CHEAP
+CHLOE
+CHRISTMAS
+CHROME
+CHURCH
+CI
+CIPRIANI
+CIRCLE
+CISCO
+CITIC
+CITY
+CITYEATS
+CK
+CL
+CLAIMS
+CLEANING
+CLICK
+CLINIC
+CLINIQUE
+CLOTHING
+CLOUD
+CLUB
+CLUBMED
+CM
+CN
+CO
+COACH
+CODES
+COFFEE
+COLLEGE
+COLOGNE
+COM
+COMMBANK
+COMMUNITY
+COMPANY
+COMPARE
+COMPUTER
+COMSEC
+CONDOS
+CONSTRUCTION
+CONSULTING
+CONTACT
+CONTRACTORS
+COOKING
+COOL
+COOP
+CORSICA
+COUNTRY
+COUPON
+COUPONS
+COURSES
+CR
+CREDIT
+CREDITCARD
+CREDITUNION
+CRICKET
+CROWN
+CRS
+CRUISES
+CSC
+CU
+CUISINELLA
+CV
+CW
+CX
+CY
+CYMRU
+CYOU
+CZ
+DABUR
+DAD
+DANCE
+DATE
+DATING
+DATSUN
+DAY
+DCLK
+#! DDS
+DE
+DEALER
+DEALS
+DEGREE
+DELIVERY
+DELL
+DELOITTE
+DELTA
+DEMOCRAT
+DENTAL
+DENTIST
+DESI
+DESIGN
+DEV
+#! DHL
+DIAMONDS
+DIET
+DIGITAL
+DIRECT
+DIRECTORY
+DISCOUNT
+DJ
+DK
+DM
+DNP
+DO
+DOCS
+DOG
+DOHA
+DOMAINS
+#! DOT
+DOWNLOAD
+DRIVE
+#! DTV
+DUBAI
+DURBAN
+DVAG
+DZ
+EARTH
+EAT
+EC
+EDEKA
+EDU
+EDUCATION
+EE
+EG
+EMAIL
+EMERCK
+ENERGY
+ENGINEER
+ENGINEERING
+ENTERPRISES
+EPSON
+EQUIPMENT
+ER
+ERNI
+ES
+ESQ
+ESTATE
+ET
+EU
+EUROVISION
+EUS
+EVENTS
+EVERBANK
+EXCHANGE
+EXPERT
+EXPOSED
+EXPRESS
+EXTRASPACE
+FAGE
+FAIL
+FAIRWINDS
+FAITH
+FAMILY
+FAN
+FANS
+FARM
+FASHION
+FAST
+FEEDBACK
+FERRERO
+FI
+FILM
+FINAL
+FINANCE
+FINANCIAL
+FIRESTONE
+FIRMDALE
+FISH
+FISHING
+FIT
+FITNESS
+FJ
+FK
+FLICKR
+FLIGHTS
+#! FLIR
+FLORIST
+FLOWERS
+FLSMIDTH
+FLY
+FM
+FO
+FOO
+FOOTBALL
+FORD
+FOREX
+FORSALE
+FORUM
+FOUNDATION
+FOX
+FR
+FRESENIUS
+FRL
+FROGANS
+FRONTIER
+FTR
+FUND
+FURNITURE
+FUTBOL
+FYI
+GA
+GAL
+GALLERY
+GALLO
+GALLUP
+GAME
+#! GAMES
+GARDEN
+GB
+GBIZ
+GD
+GDN
+GE
+GEA
+GENT
+GENTING
+GF
+GG
+GGEE
+GH
+GI
+GIFT
+GIFTS
+GIVES
+GIVING
+GL
+GLASS
+GLE
+GLOBAL
+GLOBO
+GM
+GMAIL
+GMBH
+GMO
+GMX
+GN
+GOLD
+GOLDPOINT
+GOLF
+GOO
+GOOG
+GOOGLE
+GOP
+GOT
+GOV
+GP
+GQ
+GR
+GRAINGER
+GRAPHICS
+GRATIS
+GREEN
+GRIPE
+GROUP
+GS
+GT
+GU
+#! GUARDIAN
+GUCCI
+GUGE
+GUIDE
+GUITARS
+GURU
+GW
+GY
+HAMBURG
+HANGOUT
+HAUS
+HDFCBANK
+HEALTH
+HEALTHCARE
+HELP
+HELSINKI
+HERE
+HERMES
+HIPHOP
+#! HISAMITSU
+HITACHI
+HIV
+HK
+#! HKT
+HM
+HN
+HOCKEY
+HOLDINGS
+HOLIDAY
+HOMEDEPOT
+HOMES
+HONDA
+HORSE
+HOST
+HOSTING
+HOTELES
+HOTMAIL
+HOUSE
+HOW
+HR
+HSBC
+HT
+HTC
+HU
+HYUNDAI
+IBM
+ICBC
+ICE
+ICU
+ID
+IE
+IFM
+IINET
+IL
+IM
+IMAMAT
+IMMO
+IMMOBILIEN
+IN
+INDUSTRIES
+INFINITI
+INFO
+ING
+INK
+INSTITUTE
+INSURANCE
+INSURE
+INT
+INTERNATIONAL
+INVESTMENTS
+IO
+IPIRANGA
+IQ
+IR
+IRISH
+IS
+ISELECT
+ISMAILI
+IST
+ISTANBUL
+IT
+ITAU
+IWC
+JAGUAR
+JAVA
+JCB
+JCP
+JE
+JETZT
+JEWELRY
+JLC
+JLL
+JM
+JMP
+JNJ
+JO
+JOBS
+JOBURG
+JOT
+JOY
+JP
+JPMORGAN
+JPRS
+JUEGOS
+KAUFEN
+KDDI
+KE
+KERRYHOTELS
+KERRYLOGISTICS
+KERRYPROPERTIES
+KFH
+KG
+KH
+KI
+KIA
+KIM
+KINDER
+KITCHEN
+KIWI
+KM
+KN
+KOELN
+KOMATSU
+KP
+KPMG
+KPN
+KR
+KRD
+KRED
+KUOKGROUP
+KW
+KY
+KYOTO
+KZ
+LA
+LACAIXA
+LAMBORGHINI
+LAMER
+LANCASTER
+LAND
+LANDROVER
+LANXESS
+LASALLE
+LAT
+LATROBE
+LAW
+LAWYER
+LB
+LC
+LDS
+LEASE
+LECLERC
+LEGAL
+LEXUS
+LGBT
+LI
+LIAISON
+LIDL
+LIFE
+LIFEINSURANCE
+LIFESTYLE
+LIGHTING
+LIKE
+LIMITED
+LIMO
+LINCOLN
+LINDE
+LINK
+#! LIPSY
+LIVE
+LIVING
+LIXIL
+LK
+LOAN
+LOANS
+#! LOCKER
+LOCUS
+LOL
+LONDON
+LOTTE
+LOTTO
+LOVE
+LR
+LS
+LT
+LTD
+LTDA
+LU
+LUPIN
+LUXE
+LUXURY
+LV
+LY
+MA
+MADRID
+MAIF
+MAISON
+MAKEUP
+MAN
+MANAGEMENT
+MANGO
+MARKET
+MARKETING
+MARKETS
+MARRIOTT
+#! MATTEL
+MBA
+MC
+MD
+ME
+MED
+MEDIA
+MEET
+MELBOURNE
+MEME
+MEMORIAL
+MEN
+MENU
+MEO
+#! METLIFE
+MG
+MH
+MIAMI
+MICROSOFT
+MIL
+MINI
+MK
+ML
+#! MLB
+MLS
+MM
+MMA
+MN
+MO
+MOBI
+MOBILY
+MODA
+MOE
+MOI
+MOM
+MONASH
+MONEY
+MONTBLANC
+MORMON
+MORTGAGE
+MOSCOW
+MOTORCYCLES
+MOV
+MOVIE
+MOVISTAR
+MP
+MQ
+MR
+MS
+MT
+MTN
+MTPC
+MTR
+MU
+MUSEUM
+MUTUAL
+MUTUELLE
+MV
+MW
+MX
+MY
+MZ
+NA
+NADEX
+NAGOYA
+NAME
+NATURA
+NAVY
+NC
+NE
+NEC
+NET
+NETBANK
+#! NETFLIX
+NETWORK
+NEUSTAR
+NEW
+NEWS
+#! NEXT
+#! NEXTDIRECT
+NEXUS
+NF
+NG
+NGO
+NHK
+NI
+NICO
+NIKON
+NINJA
+NISSAN
+NISSAY
+NL
+NO
+NOKIA
+NORTHWESTERNMUTUAL
+NORTON
+NOWRUZ
+#! NOWTV
+NP
+NR
+NRA
+NRW
+NTT
+NU
+NYC
+NZ
+OBI
+OFFICE
+OKINAWA
+#! OLAYAN
+#! OLAYANGROUP
+#! OLLO
+OM
+OMEGA
+ONE
+ONG
+ONL
+ONLINE
+OOO
+ORACLE
+ORANGE
+ORG
+ORGANIC
+ORIGINS
+OSAKA
+OTSUKA
+#! OTT
+OVH
+PA
+PAGE
+PAMPEREDCHEF
+PANERAI
+PARIS
+PARS
+PARTNERS
+PARTS
+PARTY
+PASSAGENS
+#! PCCW
+PE
+PET
+PF
+PG
+PH
+PHARMACY
+PHILIPS
+PHOTO
+PHOTOGRAPHY
+PHOTOS
+PHYSIO
+PIAGET
+PICS
+PICTET
+PICTURES
+PID
+PIN
+PING
+PINK
+#! PIONEER
+PIZZA
+PK
+PL
+PLACE
+PLAY
+PLAYSTATION
+PLUMBING
+PLUS
+PM
+PN
+POHL
+POKER
+PORN
+POST
+PR
+PRAXI
+PRESS
+PRO
+PROD
+PRODUCTIONS
+PROF
+PROGRESSIVE
+PROMO
+PROPERTIES
+PROPERTY
+PROTECTION
+PS
+PT
+PUB
+PW
+PWC
+PY
+QA
+QPON
+QUEBEC
+QUEST
+RACING
+RE
+READ
+#! REALESTATE
+REALTOR
+REALTY
+RECIPES
+RED
+REDSTONE
+REDUMBRELLA
+REHAB
+REISE
+REISEN
+REIT
+REN
+RENT
+RENTALS
+REPAIR
+REPORT
+REPUBLICAN
+REST
+RESTAURANT
+REVIEW
+REVIEWS
+REXROTH
+RICH
+#! RICHARDLI
+RICOH
+RIO
+RIP
+RO
+ROCHER
+ROCKS
+RODEO
+ROOM
+RS
+RSVP
+RU
+RUHR
+RUN
+RW
+RWE
+RYUKYU
+SA
+SAARLAND
+SAFE
+SAFETY
+SAKURA
+SALE
+SALON
+SAMSUNG
+SANDVIK
+SANDVIKCOROMANT
+SANOFI
+SAP
+SAPO
+SARL
+SAS
+SAXO
+SB
+SBI
+SBS
+SC
+SCA
+SCB
+SCHAEFFLER
+SCHMIDT
+SCHOLARSHIPS
+SCHOOL
+SCHULE
+SCHWARZ
+SCIENCE
+SCOR
+SCOT
+SD
+SE
+SEAT
+SECURITY
+SEEK
+SELECT
+SENER
+SERVICES
+SEVEN
+SEW
+SEX
+SEXY
+SFR
+SG
+SH
+SHARP
+SHAW
+SHELL
+SHIA
+SHIKSHA
+SHOES
+#! SHOP
+SHOUJI
+SHOW
+SHRIRAM
+SI
+SINA
+SINGLES
+SITE
+SJ
+SK
+SKI
+SKIN
+SKY
+SKYPE
+SL
+SM
+SMILE
+SN
+SNCF
+SO
+SOCCER
+SOCIAL
+SOFTBANK
+SOFTWARE
+SOHU
+SOLAR
+SOLUTIONS
+SONG
+SONY
+SOY
+SPACE
+SPIEGEL
+SPOT
+SPREADBETTING
+SR
+SRL
+ST
+STADA
+STAR
+STARHUB
+STATEBANK
+STATEFARM
+STATOIL
+STC
+STCGROUP
+STOCKHOLM
+STORAGE
+STORE
+STREAM
+STUDIO
+STUDY
+STYLE
+SU
+SUCKS
+SUPPLIES
+SUPPLY
+SUPPORT
+SURF
+SURGERY
+SUZUKI
+SV
+SWATCH
+SWISS
+SX
+SY
+SYDNEY
+SYMANTEC
+SYSTEMS
+SZ
+TAB
+TAIPEI
+TALK
+TAOBAO
+TATAMOTORS
+TATAR
+TATTOO
+TAX
+TAXI
+TC
+TCI
+TD
+TEAM
+TECH
+TECHNOLOGY
+TEL
+TELECITY
+TELEFONICA
+TEMASEK
+TENNIS
+TEVA
+TF
+TG
+TH
+THD
+THEATER
+THEATRE
+TICKETS
+TIENDA
+TIFFANY
+TIPS
+TIRES
+TIROL
+TJ
+TK
+TL
+TM
+TMALL
+TN
+TO
+TODAY
+TOKYO
+TOOLS
+TOP
+TORAY
+TOSHIBA
+TOTAL
+TOURS
+TOWN
+TOYOTA
+TOYS
+TR
+TRADE
+TRADING
+TRAINING
+TRAVEL
+TRAVELERS
+TRAVELERSINSURANCE
+TRUST
+TRV
+TT
+TUBE
+TUI
+TUNES
+TUSHU
+TV
+TVS
+TW
+TZ
+UA
+UBS
+UG
+UK
+UNICOM
+UNIVERSITY
+UNO
+UOL
+#! UPS
+US
+UY
+UZ
+VA
+VACATIONS
+VANA
+VC
+VE
+VEGAS
+VENTURES
+VERISIGN
+VERSICHERUNG
+VET
+VG
+VI
+VIAJES
+VIDEO
+VIG
+VIKING
+VILLAS
+VIN
+VIP
+VIRGIN
+VISION
+VISTA
+VISTAPRINT
+VIVA
+VLAANDEREN
+VN
+VODKA
+VOLKSWAGEN
+VOTE
+VOTING
+VOTO
+VOYAGE
+VU
+VUELOS
+WALES
+WALTER
+WANG
+WANGGOU
+#! WARMAN
+WATCH
+WATCHES
+WEATHER
+WEATHERCHANNEL
+WEBCAM
+WEBER
+WEBSITE
+WED
+WEDDING
+WEIBO
+WEIR
+WF
+WHOSWHO
+WIEN
+WIKI
+WILLIAMHILL
+WIN
+WINDOWS
+WINE
+WME
+WOLTERSKLUWER
+WORK
+WORKS
+WORLD
+WS
+WTC
+WTF
+XBOX
+XEROX
+XIHUAN
+XIN
+XN--11B4C3D
+XN--1CK2E1B
+XN--1QQW23A
+XN--30RR7Y
+XN--3BST00M
+XN--3DS443G
+XN--3E0B707E
+XN--3PXU8K
+XN--42C2D9A
+XN--45BRJ9C
+XN--45Q11C
+XN--4GBRIM
+XN--55QW42G
+XN--55QX5D
+XN--5TZM5G
+XN--6FRZ82G
+XN--6QQ986B3XL
+XN--80ADXHKS
+XN--80AO21A
+XN--80ASEHDB
+XN--80ASWG
+XN--8Y0A063A
+XN--90A3AC
+XN--90AIS
+XN--9DBQ2A
+XN--9ET52U
+XN--9KRT00A
+XN--B4W605FERD
+XN--BCK1B9A5DRE4C
+XN--C1AVG
+XN--C2BR7G
+XN--CCK2B3B
+XN--CG4BKI
+XN--CLCHC0EA0B2G2A9GCD
+XN--CZR694B
+XN--CZRS0T
+XN--CZRU2D
+XN--D1ACJ3B
+XN--D1ALF
+XN--E1A4C
+XN--ECKVDTC9D
+XN--EFVY88H
+XN--ESTV75G
+XN--FCT429K
+XN--FHBEI
+XN--FIQ228C5HS
+XN--FIQ64B
+XN--FIQS8S
+XN--FIQZ9S
+XN--FJQ720A
+XN--FLW351E
+XN--FPCRJ9C3D
+XN--FZC2C9E2C
+XN--FZYS8D69UVGM
+XN--G2XX48C
+XN--GCKR3F0F
+XN--GECRJ9C
+XN--H2BRJ9C
+XN--HXT814E
+XN--I1B6B1A6A2E
+XN--IMR513N
+XN--IO0A7I
+XN--J1AEF
+XN--J1AMH
+XN--J6W193G
+XN--JLQ61U9W7B
+XN--JVR189M
+XN--KCRX77D1X4A
+XN--KPRW13D
+XN--KPRY57D
+XN--KPU716F
+XN--KPUT3I
+XN--L1ACC
+XN--LGBBAT1AD8J
+XN--MGB9AWBF
+XN--MGBA3A3EJT
+XN--MGBA3A4F16A
+XN--MGBA7C0BBN0A
+XN--MGBAAM7A8H
+XN--MGBAB2BD
+XN--MGBAYH7GPA
+XN--MGBB9FBPOB
+XN--MGBBH1A71E
+XN--MGBC0A9AZCG
+XN--MGBCA7DZDO
+XN--MGBERP4A5D4AR
+XN--MGBPL2FH
+XN--MGBT3DHD
+XN--MGBTX2B
+XN--MGBX4CD0AB
+XN--MIX891F
+XN--MK1BU44C
+XN--MXTQ1M
+XN--NGBC5AZD
+XN--NGBE9E0A
+XN--NODE
+XN--NQV7F
+XN--NQV7FS00EMA
+XN--NYQY26A
+XN--O3CW4H
+XN--OGBPF8FL
+XN--P1ACF
+XN--P1AI
+XN--PBT977C
+XN--PGBS0DH
+XN--PSSY2U
+XN--Q9JYB4C
+XN--QCKA1PMC
+XN--QXAM
+XN--RHQV96G
+XN--ROVU88B
+XN--S9BRJ9C
+XN--SES554G
+XN--T60B56A
+XN--TCKWE
+XN--UNUP4Y
+XN--VERMGENSBERATER-CTB
+XN--VERMGENSBERATUNG-PWB
+XN--VHQUV
+XN--VUQ861B
+XN--W4R85EL8FHU5DNRA
+XN--W4RS40L
+XN--WGBH1C
+XN--WGBL6A
+XN--XHQ521B
+XN--XKC2AL3HYE2A
+XN--XKC2DL3A5EE0H
+XN--Y9A3AQ
+XN--YFRO4I67O
+XN--YGBI2AMMX
+XN--ZFR164B
+XPERIA
+XXX
+XYZ
+YACHTS
+YAHOO
+YAMAXUN
+YANDEX
+YE
+YODOBASHI
+YOGA
+YOKOHAMA
+YOU
+YOUTUBE
+YT
+YUN
+ZA
+#! ZAPPOS
+ZARA
+ZERO
+ZIP
+ZM
+ZONE
+ZUERICH
+ZW
diff --git a/lib/commons/BUCK b/lib/commons/BUCK
index f9bf064..7c27477 100644
--- a/lib/commons/BUCK
+++ b/lib/commons/BUCK
@@ -72,10 +72,15 @@
exclude = ['META-INF/LICENSE'],
)
+# When updating the version of commons-validator, also update the
+# list of supported TLDs in:
+# gerrit-server/src/test/resources/com/google/gerrit/server/mail/tlds-alpha-by-domain.txt
+# from:
+# http://data.iana.org/TLD/tlds-alpha-by-domain.txt
maven_jar(
name = 'validator',
- id = 'commons-validator:commons-validator:1.4.1',
- sha1 = '2231238e391057a53f92bde5bbc588622c1956c3',
+ id = 'commons-validator:commons-validator:1.5.1',
+ sha1 = '86d05a46e8f064b300657f751b5a98c62807e2a0',
license = 'Apache2.0',
)
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
index 6eecd42..2d40ee2 160000
--- a/plugins/cookbook-plugin
+++ b/plugins/cookbook-plugin
@@ -1 +1 @@
-Subproject commit 6eecd42fd629c700409826273d9ed02499a1d12c
+Subproject commit 2d40ee25a029deaefeddb6ffe5679a68aa10d8db
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index 3f92e44..557e7b8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -83,6 +83,12 @@
return null;
},
+ getLineNumberByChild: function(node) {
+ var lineEl = this.getLineElByChild(node);
+ return lineEl ?
+ parseInt(lineEl.getAttribute('data-value'), 10) : null;
+ },
+
renderLineRange: function(startLine, endLine, opt_side) {
var groups =
this._builder.getGroupsByLineRange(startLine, endLine, opt_side);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
index c8ed041..bc3b23f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
@@ -20,7 +20,7 @@
<dom-module id="gr-diff-highlight">
<template>
<style>
- :host {
+ .contentWrapper ::content {
position: relative;
}
.contentWrapper ::content .range {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
index db092e6..1c3572d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
@@ -59,6 +59,11 @@
},
_enabledChanged: function() {
+ if (this.enabled) {
+ this.listen(document, 'selectionchange', '_handleSelectionChange');
+ } else {
+ this.unlisten(document, 'selectionchange', '_handleSelectionChange');
+ }
for (var eventName in this._enabledListeners) {
var methodName = this._enabledListeners[eventName];
if (this.enabled) {
@@ -88,6 +93,14 @@
}
},
+ _handleSelectionChange: function() {
+ // Can't use up or down events to handle selection started and/or ended in
+ // in comment threads or outside of diff.
+ // Debounce removeActionBox to give it a chance to react to click/tap.
+ this._removeActionBoxDebounced();
+ this.debounce('selectionChange', this._handleSelection, 200);
+ },
+
_handleRender: function() {
this._applyAllHighlights();
},
@@ -129,6 +142,111 @@
}, this);
},
+ /**
+ * Convert DOM Range selection to concrete numbers (line, column, side).
+ * Moves range end if it's not inside td.content.
+ * Returns null if selection end is not valid (outside of diff).
+ *
+ * @param {Node} node td.content child
+ * @param {number} offset offset within node
+ * @return {{
+ * node: Node,
+ * side: string,
+ * line: Number,
+ * column: Number
+ * }}
+ */
+ _normalizeSelectionSide: function(node, offset) {
+ var column;
+ if (!this.contains(node)) {
+ return;
+ }
+ var lineEl = this.diffBuilder.getLineElByChild(node);
+ if (!lineEl) {
+ return;
+ }
+ var side = this.diffBuilder.getSideByLineEl(lineEl);
+ if (!side) {
+ return;
+ }
+ var line = this.diffBuilder.getLineNumberByChild(lineEl);
+ if (!line) {
+ return;
+ }
+ var content = this.diffBuilder.getContentByLineEl(lineEl);
+ if (!content) {
+ return;
+ }
+ if (!content.contains(node)) {
+ node = content;
+ column = 0;
+ } else {
+ var thread = content.querySelector('gr-diff-comment-thread');
+ if (thread && thread.contains(node)) {
+ column = this._getLength(content);
+ node = content;
+ } else {
+ column = this._convertOffsetToColumn(node, offset);
+ }
+ }
+
+ return {
+ node: node,
+ side: side,
+ line: line,
+ column: column,
+ };
+ },
+
+ _handleSelection: function() {
+ var selection = window.getSelection();
+ if (selection.rangeCount != 1) {
+ return;
+ }
+ var range = selection.getRangeAt(0);
+ if (range.collapsed) {
+ return;
+ }
+ var start =
+ this._normalizeSelectionSide(range.startContainer, range.startOffset);
+ if (!start) {
+ return;
+ }
+ var end =
+ this._normalizeSelectionSide(range.endContainer, range.endOffset);
+ if (!end) {
+ return;
+ }
+ if (start.side !== end.side ||
+ end.line < start.line ||
+ (start.line === end.line && start.column === end.column)) {
+ return;
+ }
+
+ // TODO (viktard): Drop empty first and last lines from selection.
+
+ var actionBox = document.createElement('gr-selection-action-box');
+ Polymer.dom(this.root).appendChild(actionBox);
+ actionBox.range = {
+ startLine: start.line,
+ startChar: start.column,
+ endLine: end.line,
+ endChar: end.column,
+ };
+ actionBox.side = start.side;
+ if (start.line === end.line) {
+ actionBox.placeAbove(range);
+ } else if (start.node instanceof Text) {
+ actionBox.placeAbove(start.node.splitText(start.column));
+ start.node.parentElement.normalize(); // Undo splitText from above.
+ } else if (start.node.classList.contains('content') &&
+ start.node.firstChild) {
+ actionBox.placeAbove(start.node.firstChild);
+ } else {
+ actionBox.placeAbove(start.node);
+ }
+ },
+
_renderCommentRange: function(comment, el) {
var lineEl = this.diffBuilder.getLineElByChild(el);
if (!lineEl) {
@@ -181,6 +299,10 @@
range.endLine, range.endChar, side);
},
+ _removeActionBoxDebounced: function() {
+ this.debounce('removeActionBox', this._removeActionBox, 10);
+ },
+
_removeActionBox: function() {
var actionBox = this.$$('gr-selection-action-box');
if (actionBox) {
@@ -188,8 +310,24 @@
}
},
+ _convertOffsetToColumn: function(el, offset) {
+ if (el instanceof Element && el.classList.contains('content')) {
+ return offset;
+ }
+ while (el.previousSibling ||
+ !el.parentElement.classList.contains('content')) {
+ if (el.previousSibling) {
+ el = el.previousSibling;
+ offset += this._getLength(el);
+ } else {
+ el = el.parentElement;
+ }
+ }
+ return offset;
+ },
+
/**
- * Traverse diff content from right to left, call callback for each node.
+ * Traverse Element from right to left, call callback for each node.
* Stops if callback returns true.
*
* @param {!Node} startNode
@@ -200,7 +338,9 @@
var travelLeft = opt_flags && opt_flags.left;
var node = startNode;
while (node) {
- if (node instanceof Element && node.tagName !== 'HL') {
+ if (node instanceof Element &&
+ node.tagName !== 'HL' &&
+ node.tagName !== 'SPAN') {
break;
}
var nextNode = travelLeft ? node.previousSibling : node.nextSibling;
@@ -222,7 +362,6 @@
node = node.firstChild;
var length = 0;
while (node) {
- // Only measure Text nodes and <hl>
if (node instanceof Text || node.tagName == 'HL') {
length += this._getLength(node);
}
@@ -242,10 +381,16 @@
* @return {!Element} Wrapped node.
*/
_wrapInHighlight: function(node, cssClass) {
- var hl = document.createElement('hl');
- hl.className = cssClass;
- Polymer.dom(node.parentElement).replaceChild(hl, node);
- hl.appendChild(node);
+ var hl;
+ if (node.tagName === 'HL') {
+ hl = node;
+ hl.classList.add(cssClass);
+ } else {
+ hl = document.createElement('hl');
+ hl.className = cssClass;
+ Polymer.dom(node.parentElement).replaceChild(hl, node);
+ hl.appendChild(node);
+ }
return hl;
},
@@ -256,7 +401,7 @@
* @param {number} offset
* @return {!Text} Trailing Text Node.
*/
- _splitText: function(node, offset) {
+ _splitTextNode: function(node, offset) {
if (node.textContent.match(REGEX_ASTRAL_SYMBOL)) {
// DOM Api for splitText() is broken for Unicode:
// https://mathiasbynens.be/notes/javascript-unicode
@@ -275,10 +420,41 @@
},
/**
+ * Split Node at offset.
+ * If Node is Element, it's cloned and the node at offset is split too.
+ *
+ * @param {!Node} node
+ * @param {number} offset
+ * @return {!Node} Trailing Node.
+ */
+ _splitNode: function(element, offset) {
+ if (element instanceof Text) {
+ return this._splitTextNode(element, offset);
+ }
+ var tail = element.cloneNode(false);
+ element.parentElement.insertBefore(tail, element.nextSibling);
+ // Skip nodes before offset.
+ var node = element.firstChild;
+ while (node &&
+ this._getLength(node) <= offset ||
+ this._getLength(node) === 0) {
+ offset -= this._getLength(node);
+ node = node.nextSibling;
+ }
+ if (this._getLength(node) > offset) {
+ tail.appendChild(this._splitNode(node, offset));
+ }
+ while (node.nextSibling) {
+ tail.appendChild(node.nextSibling);
+ }
+ return tail;
+ },
+
+ /**
* Split Text Node and wrap it in hl with cssClass.
* Wraps trailing part after split, tailing one if opt_firstPart is true.
*
- * @param {!Text} node
+ * @param {!Node} node
* @param {number} offset
* @param {string} cssClass
* @param {boolean=} opt_firstPart
@@ -288,10 +464,10 @@
return this._wrapInHighlight(node, cssClass);
} else {
if (opt_firstPart) {
- this._splitText(node, offset);
+ this._splitNode(node, offset);
// Node points to first part of the Text, second one is sibling.
} else {
- node = this._splitText(node, offset);
+ node = this._splitNode(node, offset);
}
return this._wrapInHighlight(node, cssClass);
}
@@ -329,29 +505,21 @@
if (startNode instanceof Text) {
startNode =
this._splitAndWrapInHighlight(startNode, startOffset, cssClass);
- startContent.insertBefore(startNode, startNode.nextSibling);
// Edge case: single line, text node wraps the highlight.
if (isOneLine && this._getLength(startNode) > length) {
- var extra = this._splitText(startNode.firstChild, length);
+ var extra = this._splitTextNode(startNode.firstChild, length);
startContent.insertBefore(extra, startNode.nextSibling);
startContent.normalize();
}
} else if (startNode.tagName == 'HL') {
if (!startNode.classList.contains(cssClass)) {
- var hl = startNode;
- startNode = this._splitAndWrapInHighlight(
- startNode.firstChild, startOffset, cssClass);
- startContent.insertBefore(startNode, hl.nextSibling);
// Edge case: single line, <hl> wraps the highlight.
- if (isOneLine && this._getLength(startNode) > length) {
- var trailingHl = hl.cloneNode(false);
- trailingHl.appendChild(
- this._splitText(startNode.firstChild, length));
- startContent.insertBefore(trailingHl, startNode.nextSibling);
+ // Should leave wrapping HL's content after the highlight.
+ if (isOneLine && startOffset + length < this._getLength(startNode)) {
+ this._splitNode(startNode, startOffset + length);
}
- if (hl.textContent.length === 0) {
- hl.remove();
- }
+ startNode =
+ this._splitAndWrapInHighlight(startNode, startOffset, cssClass);
}
} else {
startNode = null;
@@ -393,8 +561,7 @@
// Split text inside HL.
var hl = endNode;
endNode = this._splitAndWrapInHighlight(
- endNode.firstChild, endOffset, cssClass, true);
- endContent.insertBefore(endNode, hl);
+ endNode, endOffset, cssClass, true);
if (hl.textContent.length === 0) {
hl.remove();
}
@@ -424,19 +591,32 @@
// Grow starting highlight until endNode or end of line.
if (startNode && startNode != endNode) {
- this._traverseContentSiblings(startNode.nextSibling, function(node) {
- startNode.textContent += node.textContent;
- node.remove();
+ var growStartHl = function(node) {
+ if (node instanceof Text || node.tagName === 'SPAN') {
+ startNode.appendChild(node);
+ } else if (node.tagName === 'HL') {
+ this._traverseContentSiblings(node.firstChild, growStartHl);
+ node.remove();
+ }
return node == endNode;
- });
+ }.bind(this);
+ this._traverseContentSiblings(startNode.nextSibling, growStartHl);
+ startNode.normalize();
}
if (!isOneLine && endNode) {
+ var growEndHl = function(node) {
+ if (node instanceof Text || node.tagName === 'SPAN') {
+ endNode.insertBefore(node, endNode.firstChild);
+ } else if (node.tagName === 'HL') {
+ this._traverseContentSiblings(node.firstChild, growEndHl);
+ node.remove();
+ }
+ }.bind(this);
// Prepend text up to line start to the ending highlight.
- this._traverseContentSiblings(endNode.previousSibling, function(node) {
- endNode.textContent = node.textContent + endNode.textContent;
- node.remove();
- }, {left: true});
+ this._traverseContentSiblings(
+ endNode.previousSibling, growEndHl, {left: true});
+ endNode.normalize();
}
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
index 60bfb96..0df6a20 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
@@ -31,38 +31,74 @@
<tbody class="section both">
<tr class="diff-row side-by-side" left-type="both" right-type="both">
- <td class="left lineNum" data-value="138"></td>
+ <td class="left lineNum" data-value="138">138</td>
<td class="content both darkHighlight">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</td>
- <td class="right lineNum" data-value="119"></td>
+ <td class="right lineNum" data-value="119">119</td>
<td class="content both darkHighlight">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</td>
</tr>
</tbody>
<tbody class="section delta">
<tr class="diff-row side-by-side" left-type="remove" right-type="add">
- <td class="left lineNum" data-value="140"></td>
+ <td class="left lineNum" data-value="140">140</td>
<!-- Next tag is formatted to eliminate zero-length text nodes. -->
- <td class="content remove lightHighlight">na💢ti <hl class="foo">te, inquit</hl>, sumus <hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a udiam, <hl>quid</hl> sit, quod <hl>Epicurum</hl><gr-diff-comment-thread>
+ <td class="content remove lightHighlight">na💢ti <hl class="foo">te, inquit</hl>, sumus <hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a <hl><span class="tab withIndicator" style="tab-size:8;"></span></hl>udiam, <hl>quid</hl> sit, <span class="tab withIndicator" style="tab-size:8;"></span>quod <hl>Epicurum</hl><gr-diff-comment-thread>
[Yet another random diff thread content here]
</gr-diff-comment-thread></td>
- <td class="right lineNum" data-value="121"></td>
- <td class="content add lightHighlight">
- nacti ,
- <hl>,</hl>
- sumus otiosum, audiam, sit, quod
- </td>
+ <td class="right lineNum" data-value="120">120</td>
+ <!-- Next tag is formatted to eliminate zero-length text nodes. -->
+ <td class="content add lightHighlight">nacti , <hl>,</hl> sumus <hl><span class="tab withIndicator" style="tab-size:8;"></span></hl> otiosum, <span class="tab withIndicator" style="tab-size:8;"></span> audiam, sit, quod</td>
</tr>
</tbody>
<tbody class="section both">
<tr class="diff-row side-by-side" left-type="both" right-type="both">
- <td class="left lineNum" data-value="149"></td>
- <td class="content both darkHighlight">nam et complectitur verbis, quod vult, et dicit plane, quod intellegam;</td>
+ <td class="left lineNum" data-value="141"></td>
+ <td class="content both darkHighlight">nam et<hl><span class="tab withIndicator" style="tab-size:8;"> </span></hl>complectitur<span class="tab withIndicator" style="tab-size:8;"> </span>verbis, quod vult, et dicit plane, quod intellegam;</td>
<td class="right lineNum" data-value="130"></td>
<td class="content both darkHighlight">nam et complectitur verbis, quod vult, et dicit plane, quod intellegam;</td>
</tr>
</tbody>
+ <tbody class="section contextControl">
+ <tr class="diff-row side-by-side" left-type="contextControl" right-type="contextControl">
+ <td class="left contextLineNum" data-value="@@"></td>
+ <td>
+ <gr-button>+10↑</gr-button>
+ -
+ <gr-button>Show 21 common lines</gr-button>
+ -
+ <gr-button>+10↓</gr-button>
+ </td>
+ <td class="right contextLineNum" data-value="@@"></td>
+ <td>
+ <gr-button>+10↑</gr-button>
+ -
+ <gr-button>Show 21 common lines</gr-button>
+ -
+ <gr-button>+10↓</gr-button>
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody class="section delta">
+ <tr class="diff-row side-by-side" left-type="blank" right-type="add">
+ <td class="left"></td>
+ <td class="blank darkHighlight"></td>
+ <td class="right lineNum" data-value="146"></td>
+ <td class="content add darkHighlight">[17] Quid igitur est? inquit; audire enim cupio, quid non probes. Principio, inquam,</td>
+ </tr>
+ </tbody>
+
+ <tbody class="section both">
+ <tr class="diff-row side-by-side" left-type="both" right-type="both">
+ <td class="left lineNum" data-value="165"></td>
+ <td class="content both darkHighlight">in physicis, quibus maxime gloriatur, primum totus est alienus. Democritea dicit</td>
+ <td class="right lineNum" data-value="147"></td>
+ <td class="content both darkHighlight">in physicis, <hl><span class="tab withIndicator" style="tab-size:8;"> </span></hl> quibus maxime gloriatur, primum totus est alienus. Democritea dicit</td>
+ </tr>
+ </tbody>
+
</table>
</gr-diff-highlight>
</template>
@@ -116,6 +152,28 @@
}
});
+ test('does not listen to selectionchange when disabled', function() {
+ sandbox.stub(element, '_handleSelection');
+ sandbox.stub(element, '_removeActionBox');
+ element.enabled = false;
+ document.dispatchEvent(new CustomEvent('selectionchange'));
+ element.flushDebouncer('selectionChange');
+ assert.isFalse(element._handleSelection.called);
+ element.flushDebouncer('removeActionBox');
+ assert.isFalse(element._removeActionBox.called);
+ });
+
+ test('listens to selectionchange when enabled', function() {
+ sandbox.stub(element, '_handleSelection');
+ sandbox.stub(element, '_removeActionBox');
+ element.enabled = true;
+ document.dispatchEvent(new CustomEvent('selectionchange'));
+ element.flushDebouncer('selectionChange');
+ assert.isTrue(element._handleSelection.called);
+ element.flushDebouncer('removeActionBox');
+ assert.isTrue(element._removeActionBox.called);
+ });
+
suite('comment events', function() {
var builder;
@@ -162,7 +220,6 @@
});
});
-
test('renders lines in comment range on comment discard', function(done) {
element.fire('comment-discard', {
comment: {
@@ -254,10 +311,10 @@
var diff = element.querySelector('#diffTable');
var startContent =
diff.querySelector('.left.lineNum[data-value="138"] ~ .content');
- var endContent =
- diff.querySelector('.left.lineNum[data-value="149"] ~ .content');
var betweenContent =
diff.querySelector('.left.lineNum[data-value="140"] ~ .content');
+ var endContent =
+ diff.querySelector('.left.lineNum[data-value="141"] ~ .content');
var commentThread =
diff.querySelector('gr-diff-comment-thread');
var builder = {
@@ -271,9 +328,9 @@
element.enabled = true;
builder.getContentByLine.withArgs(138, 'left').returns(
startContent);
- builder.getContentByLine.withArgs(149, 'left').returns(
+ builder.getContentByLine.withArgs(141, 'left').returns(
endContent);
- element._applyRangedHighlight('some', 138, 4, 149, 8, 'left');
+ element._applyRangedHighlight('some', 138, 4, 141, 28, 'left');
assert.instanceOf(startContent.childNodes[0], Text);
assert.equal(startContent.childNodes[0].textContent, '[14]');
assert.instanceOf(startContent.childNodes[1], Element);
@@ -282,14 +339,6 @@
assert.equal(startContent.childNodes[1].tagName, 'HL');
assert.equal(startContent.childNodes[1].className, 'some');
- assert.instanceOf(endContent.childNodes[0], Element);
- assert.equal(endContent.childNodes[0].textContent, 'nam et c');
- assert.equal(endContent.childNodes[0].tagName, 'HL');
- assert.equal(endContent.childNodes[0].className, 'some');
- assert.instanceOf(endContent.childNodes[1], Text);
- assert.equal(endContent.childNodes[1].textContent,
- 'omplectitur verbis, quod vult, et dicit plane, quod intellegam;');
-
assert.instanceOf(betweenContent.firstChild, Element);
assert.equal(betweenContent.firstChild.tagName, 'HL');
assert.equal(betweenContent.firstChild.className, 'some');
@@ -304,6 +353,22 @@
assert.strictEqual(betweenContent.querySelector('gr-diff-comment-thread'),
commentThread, 'Comment threads should be preserved.');
+
+ assert.instanceOf(endContent.childNodes[0], Element);
+ assert.equal(endContent.childNodes[0].textContent,
+ 'nam et\tcomplectitur\tverbis, ');
+ assert.equal(endContent.childNodes[0].tagName, 'HL');
+ assert.equal(endContent.childNodes[0].className, 'some');
+ assert.instanceOf(endContent.childNodes[1], Text);
+ assert.equal(endContent.childNodes[1].textContent,
+ 'quod vult, et dicit plane, quod intellegam;');
+ var endHl = endContent.querySelector('hl.some');
+ assert.equal(endHl.childNodes.length, 5);
+ var tabs = endHl.querySelectorAll('span.tab');
+ assert.equal(tabs.length, 2);
+ assert.equal(tabs[0].previousSibling.textContent, 'nam et');
+ assert.equal(tabs[1].previousSibling.textContent, 'complectitur');
+ assert.equal(tabs[1].nextSibling.textContent, 'verbis, ');
});
suite('single line ranges', function() {
@@ -334,10 +399,18 @@
assert.equal(content.firstChild.tagName, 'HL');
assert.equal(content.firstChild.className, 'some');
assert.equal(content.childNodes.length, 2);
- assert.equal(content.firstChild.childNodes.length, 1);
+ assert.equal(content.firstChild.childNodes.length, 5);
assert.equal(content.firstChild.textContent,
'na💢ti te, inquit, sumus aliquando otiosum, certe a udiam, ' +
'quid sit, quod Epicurum');
+ var tabs = content.querySelectorAll('span.tab');
+ assert.equal(tabs.length, 2);
+ assert.strictEqual(tabs[1].previousSibling, tabs[0].nextSibling);
+ assert.equal(tabs[0].previousSibling.textContent,
+ 'na💢ti te, inquit, sumus aliquando otiosum, certe a ');
+ assert.equal(tabs[1].previousSibling.textContent,
+ 'udiam, quid sit, ');
+ assert.equal(tabs[1].nextSibling.textContent, 'quod Epicurum');
});
test('merging multiple other hls', function() {
@@ -346,7 +419,8 @@
assert.equal(content.childNodes.length, 4);
var hl = content.querySelector('hl.some');
assert.strictEqual(content.firstChild, hl.previousSibling);
- assert.equal(hl.childNodes.length, 1);
+ assert.equal(hl.childNodes.length, 5);
+ assert.equal(content.querySelectorAll('span.tab').length, 2);
assert.equal(hl.textContent,
'a💢ti te, inquit, sumus aliquando otiosum, certe a udiam, ' +
'quid sit, quod Epicuru');
@@ -375,7 +449,7 @@
// After: na💢ti <hl class="foo">te, in</hl><hl class="some">quit, ...
element._applyRangedHighlight('some', 140, 12, 140, 21, 'left');
var hl = content.querySelector('hl.some');
- assert.equal(hl.outerHTML, '<hl class="some">quit, sum</hl>');
+ assert.equal(hl.textContent, 'quit, sum');
assert.equal(
hl.previousSibling.outerHTML, '<hl class="foo">te, in</hl>');
});
@@ -385,7 +459,7 @@
// After: <hl class="foo">t</hl><hl="some">e, i</hl><hl class="foo">n..
element._applyRangedHighlight('some', 140, 7, 140, 12, 'left');
var hl = content.querySelector('hl.some');
- assert.equal(hl.outerHTML, '<hl class="some">e, in</hl>');
+ assert.equal(hl.textContent, 'e, in');
assert.equal(hl.previousSibling.outerHTML, '<hl class="foo">t</hl>');
assert.equal(hl.nextSibling.outerHTML, '<hl class="foo">quit</hl>');
});
@@ -393,7 +467,7 @@
test('hl starts and ends in different hls', function() {
element._applyRangedHighlight('some', 140, 8, 140, 27, 'left');
var hl = content.querySelector('hl.some');
- assert.equal(hl.outerHTML, '<hl class="some">, inquit, sumus ali</hl>');
+ assert.equal(hl.textContent, ', inquit, sumus ali');
assert.equal(hl.previousSibling.outerHTML, '<hl class="foo">te</hl>');
assert.equal(hl.nextSibling.outerHTML, '<hl class="bar">quando</hl>');
});
@@ -408,9 +482,7 @@
test('hl starting and ending in boundaries', function() {
element._applyRangedHighlight('some', 140, 6, 140, 33, 'left');
var hl = content.querySelector('hl.some');
- assert.equal(
- hl.outerHTML, '<hl class="some">te, inquit, sumus aliquando</hl>');
- assert.notOk(content.querySelector('.foo'));
+ assert.equal(hl.textContent, 'te, inquit, sumus aliquando');
assert.notOk(content.querySelector('.bar'));
});
@@ -422,7 +494,7 @@
assert.equal(hl.outerHTML, '<hl class="some">a💢t</hl>');
});
- test('growing hl left including another hl', function() {
+ test('growing hl right including another hl', function() {
element._applyRangedHighlight('some', 140, 1, 140, 4, 'left');
element._applyRangedHighlight('some', 140, 3, 140, 10, 'left');
assert.equal(content.querySelectorAll('hl.some').length, 1);
@@ -431,7 +503,7 @@
assert.equal(hl.nextSibling.outerHTML, '<hl class="foo">inquit</hl>');
});
- test('growing hl right to start of line', function() {
+ test('growing hl left to start of line', function() {
element._applyRangedHighlight('some', 140, 2, 140, 5, 'left');
element._applyRangedHighlight('some', 140, 0, 140, 3, 'left');
assert.equal(content.querySelectorAll('hl.some').length, 1);
@@ -439,6 +511,14 @@
assert.equal(hl.outerHTML, '<hl class="some">na💢ti</hl>');
assert.strictEqual(content.firstChild, hl);
});
+
+ test('splitting hl containing a tab', function() {
+ element._applyRangedHighlight('some', 140, 63, 140, 72, 'left');
+ assert.equal(content.querySelector('hl.some').textContent, 'sit, quod');
+ element._applyRangedHighlight('another', 140, 66, 140, 81, 'left');
+ assert.equal(content.querySelector('hl.another').textContent,
+ ', quod Epicurum');
+ });
});
test('_applyAllHighlights', function() {
@@ -499,5 +579,281 @@
element.fire('show-context');
assert.isFalse(element._applyAllHighlights.called);
});
+
+ suite('selection', function() {
+ var diff;
+ var builder;
+ var contentStubs;
+
+ var stubContent = function(line, side, opt_child) {
+ var content = diff.querySelector(
+ '.' + side + '.lineNum[data-value="' + line + '"] ~ .content');
+ var lineEl = diff.querySelector(
+ '.' + side + '.lineNum[data-value="' + line + '"]');
+ contentStubs.push({
+ lineEl: lineEl,
+ content: content,
+ });
+ builder.getContentByLineEl.withArgs(lineEl).returns(content);
+ builder.getLineNumberByChild.withArgs(lineEl).returns(line);
+ builder.getContentByLine.withArgs(line, side).returns(content);
+ builder.getSideByLineEl.withArgs(lineEl).returns(side);
+ return content;
+ };
+
+ var emulateSelection = function(
+ startNode, startOffset, endNode, endOffset) {
+ var selection = window.getSelection();
+ var range = document.createRange();
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
+ selection.addRange(range);
+ element._handleSelection();
+ };
+
+ var getActionRange = function() {
+ return Polymer.dom(element.root).querySelector(
+ 'gr-selection-action-box').range;
+ };
+
+ var getActionSide = function() {
+ return Polymer.dom(element.root).querySelector(
+ 'gr-selection-action-box').side;
+ };
+
+ var getLineElByChild = function(node) {
+ var stubs = contentStubs.find(function(stub) {
+ return stub.content.contains(node);
+ });
+ return stubs && stubs.lineEl;
+ };
+
+ setup(function() {
+ contentStubs = [];
+ stub('gr-selection-action-box', {
+ placeAbove: sandbox.stub(),
+ });
+ diff = element.querySelector('#diffTable');
+ builder = {
+ getContentByLine: sandbox.stub(),
+ getContentByLineEl: sandbox.stub(),
+ getLineElByChild: getLineElByChild,
+ getLineNumberByChild: sandbox.stub(),
+ getSideByLineEl: sandbox.stub(),
+ };
+ element._cachedDiffBuilder = builder;
+ element.enabled = true;
+ });
+
+ teardown(function() {
+ contentStubs = null;
+ window.getSelection().removeAllRanges();
+ });
+
+ test('single line', function() {
+ var content = stubContent(138, 'left');
+ emulateSelection(content.firstChild, 5, content.firstChild, 12);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 138,
+ startChar: 5,
+ endLine: 138,
+ endChar: 12,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('multiline', function() {
+ var startContent = stubContent(119, 'right');
+ var endContent = stubContent(120, 'right');
+ emulateSelection(
+ startContent.firstChild, 10, endContent.lastChild, 7);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 119,
+ startChar: 10,
+ endLine: 120,
+ endChar: 34,
+ });
+ assert.equal(getActionSide(), 'right');
+ });
+
+ test('multiline grow end highlight over tabs', function() {
+ var startContent = stubContent(119, 'right');
+ var endContent = stubContent(120, 'right');
+ emulateSelection(startContent.firstChild, 10, endContent.firstChild, 2);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 119,
+ startChar: 10,
+ endLine: 120,
+ endChar: 2,
+ });
+ assert.equal(getActionSide(), 'right');
+ });
+
+ test('collapsed', function() {
+ var content = stubContent(138, 'left');
+ emulateSelection(content.firstChild, 5, content.firstChild, 5);
+ assert.isOk(window.getSelection().getRangeAt(0).startContainer);
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('starts inside hl', function() {
+ var content = stubContent(140, 'left');
+ var hl = content.querySelector('.foo');
+ emulateSelection(hl.firstChild, 2, hl.nextSibling, 7);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 8,
+ endLine: 140,
+ endChar: 23,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('ends inside hl', function() {
+ var content = stubContent(140, 'left');
+ var hl = content.querySelector('.bar');
+ emulateSelection(hl.previousSibling, 2, hl.firstChild, 3);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 18,
+ endLine: 140,
+ endChar: 27,
+ });
+ });
+
+ test('multiple hl', function() {
+ var content = stubContent(140, 'left');
+ var hl = content.querySelectorAll('hl')[4];
+ emulateSelection(content.firstChild, 2, hl.firstChild, 2);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 2,
+ endLine: 140,
+ endChar: 60,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('starts outside of diff', function() {
+ var content = stubContent(140, 'left');
+ emulateSelection(content.previousElementSibling.firstChild, 2,
+ content.firstChild, 2);
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('ends outside of diff', function() {
+ var content = stubContent(140, 'left');
+ emulateSelection(content.nextElementSibling.firstChild, 2,
+ content.firstChild, 2);
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('starts and ends on different sides', function() {
+ var startContent = stubContent(140, 'left');
+ var endContent = stubContent(130, 'right');
+ emulateSelection(startContent.firstChild, 2, endContent.firstChild, 2);
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('starts in comment thread element', function() {
+ var startContent = stubContent(140, 'left');
+ var comment = startContent.querySelector('gr-diff-comment-thread');
+ var endContent = stubContent(141, 'left');
+ emulateSelection(comment.firstChild, 2, endContent.firstChild, 4);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 81,
+ endLine: 141,
+ endChar: 4,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('ends in comment thread element', function() {
+ var content = stubContent(140, 'left');
+ var comment = content.querySelector('gr-diff-comment-thread');
+ emulateSelection(content.firstChild, 4, comment.firstChild, 1);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 4,
+ endLine: 140,
+ endChar: 81,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('starts in context element', function() {
+ var contextControl = diff.querySelector('.contextControl');
+ var content = stubContent(146, 'right');
+ emulateSelection(contextControl, 0, content.firstChild, 7);
+ // TODO (viktard): Select nearest line.
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('ends in context element', function() {
+ var contextControl = diff.querySelector('.contextControl');
+ var content = stubContent(141, 'left');
+ emulateSelection(content.firstChild, 2, contextControl, 0);
+ // TODO (viktard): Select nearest line.
+ assert.isFalse(element.isRangeSelected());
+ });
+
+ test('selection containing context element', function() {
+ var startContent = stubContent(130, 'right');
+ var endContent = stubContent(146, 'right');
+ emulateSelection(startContent.firstChild, 3, endContent.firstChild, 14);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 130,
+ startChar: 3,
+ endLine: 146,
+ endChar: 14,
+ });
+ assert.equal(getActionSide(), 'right');
+ });
+
+ test('ends at a tab', function() {
+ var content = stubContent(140, 'left');
+ emulateSelection(
+ content.firstChild, 1, content.querySelector('span'), 0);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 1,
+ endLine: 140,
+ endChar: 51,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ test('starts at a tab', function() {
+ var content = stubContent(140, 'left');
+ emulateSelection(
+ content.querySelectorAll('hl')[3], 0,
+ content.querySelectorAll('span')[1], 0);
+ assert.isTrue(element.isRangeSelected());
+ assert.deepEqual(getActionRange(), {
+ startLine: 140,
+ startChar: 51,
+ endLine: 140,
+ endChar: 68,
+ });
+ assert.equal(getActionSide(), 'left');
+ });
+
+ // TODO (viktard): Selection starts in line number.
+ // TODO (viktard): Empty lines in selection start.
+ // TODO (viktard): Empty lines in selection end.
+ // TODO (viktard): Only empty lines selected.
+ // TODO (viktard): Unified mode.
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
index 6f95789..9a8ea37 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
@@ -29,6 +29,7 @@
cursor: pointer;
padding: .3em;
position: absolute;
+ white-space: nowrap;
}
.arrow {
background: #fff;
@@ -36,6 +37,7 @@
border-width: 0 1px 1px 0;
height: var(--gr-arrow-size);
left: calc(50% - 1em);
+ margin-top: .05em;
position: absolute;
transform: rotate(45deg);
width: var(--gr-arrow-size);