Merge "Migrate part of ChangeIndex FieldDefs to the new format SchemaFields"
diff --git a/java/com/google/gerrit/index/testing/AbstractFakeIndex.java b/java/com/google/gerrit/index/testing/AbstractFakeIndex.java
index 50efef0..086ad90 100644
--- a/java/com/google/gerrit/index/testing/AbstractFakeIndex.java
+++ b/java/com/google/gerrit/index/testing/AbstractFakeIndex.java
@@ -265,7 +265,7 @@
     protected ChangeData valueFor(Map<String, Object> doc) {
       ChangeData cd =
           changeDataFactory.create(
-              Project.nameKey((String) doc.get(ChangeField.PROJECT.getName())),
+              Project.nameKey((String) doc.get(ChangeField.PROJECT_SPEC.getName())),
               Change.id(Integer.valueOf((String) doc.get(ChangeField.LEGACY_ID_STR.getName()))));
       for (SchemaField<ChangeData, ?> field : getSchema().getSchemaFields().values()) {
         field.setIfPossible(cd, new FakeStoredValue(doc.get(field.getName())));
diff --git a/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 1e34b4f..6419468 100644
--- a/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -18,7 +18,7 @@
 import static com.google.gerrit.lucene.AbstractLuceneIndex.sortFieldName;
 import static com.google.gerrit.server.git.QueueProvider.QueueType.INTERACTIVE;
 import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID_STR;
-import static com.google.gerrit.server.index.change.ChangeField.PROJECT;
+import static com.google.gerrit.server.index.change.ChangeField.PROJECT_SPEC;
 import static com.google.gerrit.server.index.change.ChangeIndexRewriter.CLOSED_STATUSES;
 import static com.google.gerrit.server.index.change.ChangeIndexRewriter.OPEN_STATUSES;
 import static java.util.Objects.requireNonNull;
@@ -536,7 +536,7 @@
 
       Change.Id id = Change.id(Integer.valueOf(f.stringValue()));
       // IndexUtils#changeFields ensures either CHANGE or PROJECT is always present.
-      IndexableField project = doc.get(PROJECT.getName()).iterator().next();
+      IndexableField project = doc.get(PROJECT_SPEC.getName()).iterator().next();
       cd = changeDataFactory.create(Project.nameKey(project.stringValue()), id);
     }
 
diff --git a/java/com/google/gerrit/server/index/IndexUtils.java b/java/com/google/gerrit/server/index/IndexUtils.java
index 80cc463..7d40c00 100644
--- a/java/com/google/gerrit/server/index/IndexUtils.java
+++ b/java/com/google/gerrit/server/index/IndexUtils.java
@@ -16,7 +16,7 @@
 
 import static com.google.gerrit.server.index.change.ChangeField.CHANGE;
 import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID_STR;
-import static com.google.gerrit.server.index.change.ChangeField.PROJECT;
+import static com.google.gerrit.server.index.change.ChangeField.PROJECT_SPEC;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
@@ -81,10 +81,10 @@
       // A Change is always sufficient.
       return fs;
     }
-    if (fs.contains(PROJECT.getName()) && fs.contains(LEGACY_ID_STR.getName())) {
+    if (fs.contains(PROJECT_SPEC.getName()) && fs.contains(LEGACY_ID_STR.getName())) {
       return fs;
     }
-    return Sets.union(fs, ImmutableSet.of(LEGACY_ID_STR.getName(), PROJECT.getName()));
+    return Sets.union(fs, ImmutableSet.of(LEGACY_ID_STR.getName(), PROJECT_SPEC.getName()));
   }
 
   /**
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index c334c98..4c38346 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -62,6 +62,7 @@
 import com.google.gerrit.entities.converter.PatchSetProtoConverter;
 import com.google.gerrit.entities.converter.ProtoConverter;
 import com.google.gerrit.index.FieldDef;
+import com.google.gerrit.index.IndexedField;
 import com.google.gerrit.index.RefState;
 import com.google.gerrit.index.SchemaFieldDefs;
 import com.google.gerrit.index.SchemaUtil;
@@ -128,39 +129,63 @@
       prefix(ChangeQueryBuilder.FIELD_CHANGE_ID).build(changeGetter(c -> c.getKey().get()));
 
   /** Change status string, in the same format as {@code status:}. */
-  public static final FieldDef<ChangeData, String> STATUS =
-      exact(ChangeQueryBuilder.FIELD_STATUS)
+  public static final IndexedField<ChangeData, String> STATUS_FIELD =
+      IndexedField.<ChangeData>stringBuilder("Status")
+          .required()
+          .size(20)
           .build(changeGetter(c -> ChangeStatusPredicate.canonicalize(c.getStatus())));
 
+  public static final IndexedField<ChangeData, String>.SearchSpec STATUS_SPEC =
+      STATUS_FIELD.exact(ChangeQueryBuilder.FIELD_STATUS);
+
   /** Project containing the change. */
-  public static final FieldDef<ChangeData, String> PROJECT =
-      exact(ChangeQueryBuilder.FIELD_PROJECT)
+  public static final IndexedField<ChangeData, String> PROJECT_FIELD =
+      IndexedField.<ChangeData>stringBuilder("Project")
+          .required()
           .stored()
+          .size(200)
           .build(changeGetter(c -> c.getProject().get()));
 
+  public static final IndexedField<ChangeData, String>.SearchSpec PROJECT_SPEC =
+      PROJECT_FIELD.exact(ChangeQueryBuilder.FIELD_PROJECT);
+
   /** Project containing the change, as a prefix field. */
-  public static final FieldDef<ChangeData, String> PROJECTS =
-      prefix(ChangeQueryBuilder.FIELD_PROJECTS).build(changeGetter(c -> c.getProject().get()));
+  public static final IndexedField<ChangeData, String>.SearchSpec PROJECTS_SPEC =
+      PROJECT_FIELD.prefix(ChangeQueryBuilder.FIELD_PROJECTS);
 
   /** Reference (aka branch) the change will submit onto. */
-  public static final FieldDef<ChangeData, String> REF =
-      exact(ChangeQueryBuilder.FIELD_REF).build(changeGetter(c -> c.getDest().branch()));
+  public static final IndexedField<ChangeData, String> REF_FIELD =
+      IndexedField.<ChangeData>stringBuilder("Ref")
+          .required()
+          .size(300)
+          .build(changeGetter(c -> c.getDest().branch()));
+
+  public static final IndexedField<ChangeData, String>.SearchSpec REF_SPEC =
+      REF_FIELD.exact(ChangeQueryBuilder.FIELD_REF);
 
   /** Topic, a short annotation on the branch. */
-  public static final FieldDef<ChangeData, String> EXACT_TOPIC =
-      exact("topic4").build(ChangeField::getTopic);
+  public static final IndexedField<ChangeData, String> TOPIC_FIELD =
+      IndexedField.<ChangeData>stringBuilder("Topic").size(500).build(ChangeField::getTopic);
+
+  public static final IndexedField<ChangeData, String>.SearchSpec EXACT_TOPIC =
+      TOPIC_FIELD.exact("topic4");
 
   /** Topic, a short annotation on the branch. */
-  public static final FieldDef<ChangeData, String> FUZZY_TOPIC =
-      fullText("topic5").build(ChangeField::getTopic);
+  public static final IndexedField<ChangeData, String>.SearchSpec FUZZY_TOPIC =
+      TOPIC_FIELD.fullText("topic5");
 
   /** Topic, a short annotation on the branch. */
-  public static final FieldDef<ChangeData, String> PREFIX_TOPIC =
-      prefix("topic6").build(ChangeField::getTopic);
+  public static final IndexedField<ChangeData, String>.SearchSpec PREFIX_TOPIC =
+      TOPIC_FIELD.prefix("topic6");
 
-  /** Submission id assigned by MergeOp. */
-  public static final FieldDef<ChangeData, String> SUBMISSIONID =
-      exact(ChangeQueryBuilder.FIELD_SUBMISSIONID).build(changeGetter(Change::getSubmissionId));
+  /** {@link com.google.gerrit.entities.SubmissionId} assigned by MergeOp. */
+  public static final IndexedField<ChangeData, String> SUBMISSIONID_FIELD =
+      IndexedField.<ChangeData>stringBuilder("SubmissionId")
+          .size(500)
+          .build(changeGetter(Change::getSubmissionId));
+
+  public static final IndexedField<ChangeData, String>.SearchSpec SUBMISSIONID_SPEC =
+      SUBMISSIONID_FIELD.exact(ChangeQueryBuilder.FIELD_SUBMISSIONID);
 
   /** Last update time since January 1, 1970. */
   // TODO(issue-15518): Migrate type for timestamp index fields from Timestamp to Instant
diff --git a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index 6116f5a..0ce08b8 100644
--- a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.index.SchemaUtil.schema;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.index.Schema;
 import com.google.gerrit.index.SchemaDefinitions;
 import com.google.gerrit.server.query.change.ChangeData;
@@ -32,79 +33,87 @@
   static final Schema<ChangeData> V74 =
       schema(
           /* version= */ 74,
-          ChangeField.ADDED,
-          ChangeField.APPROVAL,
-          ChangeField.ASSIGNEE,
-          ChangeField.ATTENTION_SET_FULL,
-          ChangeField.ATTENTION_SET_USERS,
-          ChangeField.ATTENTION_SET_USERS_COUNT,
-          ChangeField.AUTHOR,
-          ChangeField.CHANGE,
-          ChangeField.CHERRY_PICK,
-          ChangeField.CHERRY_PICK_OF_CHANGE,
-          ChangeField.CHERRY_PICK_OF_PATCHSET,
-          ChangeField.COMMENT,
-          ChangeField.COMMENTBY,
-          ChangeField.COMMIT,
-          ChangeField.COMMIT_MESSAGE,
-          ChangeField.COMMITTER,
-          ChangeField.DELETED,
-          ChangeField.DELTA,
-          ChangeField.DIRECTORY,
-          ChangeField.DRAFTBY,
-          ChangeField.EDITBY,
-          ChangeField.EXACT_AUTHOR,
-          ChangeField.EXACT_COMMIT,
-          ChangeField.EXACT_COMMITTER,
-          ChangeField.EXACT_TOPIC,
-          ChangeField.EXTENSION,
-          ChangeField.FILE_PART,
-          ChangeField.FOOTER,
-          ChangeField.FUZZY_HASHTAG,
-          ChangeField.FUZZY_TOPIC,
-          ChangeField.GROUP,
-          ChangeField.HASHTAG,
-          ChangeField.HASHTAG_CASE_AWARE,
-          ChangeField.ID,
-          ChangeField.IS_PURE_REVERT,
-          ChangeField.IS_SUBMITTABLE,
-          ChangeField.LABEL,
-          ChangeField.LEGACY_ID_STR,
-          ChangeField.MERGE,
-          ChangeField.MERGEABLE,
-          ChangeField.MERGED_ON,
-          ChangeField.ONLY_EXTENSIONS,
-          ChangeField.OWNER,
-          ChangeField.PATCH_SET,
-          ChangeField.PATH,
-          ChangeField.PENDING_REVIEWER,
-          ChangeField.PENDING_REVIEWER_BY_EMAIL,
-          ChangeField.PRIVATE,
-          ChangeField.PROJECT,
-          ChangeField.PROJECTS,
-          ChangeField.REF,
-          ChangeField.REF_STATE,
-          ChangeField.REF_STATE_PATTERN,
-          ChangeField.REVERT_OF,
-          ChangeField.REVIEWEDBY,
-          ChangeField.REVIEWER,
-          ChangeField.REVIEWER_BY_EMAIL,
-          ChangeField.STAR,
-          ChangeField.STARBY,
-          ChangeField.STARTED,
-          ChangeField.STATUS,
-          ChangeField.STORED_SUBMIT_RECORD_LENIENT,
-          ChangeField.STORED_SUBMIT_RECORD_STRICT,
-          ChangeField.STORED_SUBMIT_REQUIREMENTS,
-          ChangeField.SUBMISSIONID,
-          ChangeField.SUBMIT_RECORD,
-          ChangeField.SUBMIT_RULE_RESULT,
-          ChangeField.TOTAL_COMMENT_COUNT,
-          ChangeField.TR,
-          ChangeField.UNRESOLVED_COMMENT_COUNT,
-          ChangeField.UPDATED,
-          ChangeField.UPLOADER,
-          ChangeField.WIP);
+          ImmutableList.of(
+              ChangeField.ADDED,
+              ChangeField.APPROVAL,
+              ChangeField.ASSIGNEE,
+              ChangeField.ATTENTION_SET_FULL,
+              ChangeField.ATTENTION_SET_USERS,
+              ChangeField.ATTENTION_SET_USERS_COUNT,
+              ChangeField.AUTHOR,
+              ChangeField.CHANGE,
+              ChangeField.CHERRY_PICK,
+              ChangeField.CHERRY_PICK_OF_CHANGE,
+              ChangeField.CHERRY_PICK_OF_PATCHSET,
+              ChangeField.COMMENT,
+              ChangeField.COMMENTBY,
+              ChangeField.COMMIT,
+              ChangeField.COMMIT_MESSAGE,
+              ChangeField.COMMITTER,
+              ChangeField.DELETED,
+              ChangeField.DELTA,
+              ChangeField.DIRECTORY,
+              ChangeField.DRAFTBY,
+              ChangeField.EDITBY,
+              ChangeField.EXACT_AUTHOR,
+              ChangeField.EXACT_COMMIT,
+              ChangeField.EXACT_COMMITTER,
+              ChangeField.EXTENSION,
+              ChangeField.FILE_PART,
+              ChangeField.FOOTER,
+              ChangeField.FUZZY_HASHTAG,
+              ChangeField.GROUP,
+              ChangeField.HASHTAG,
+              ChangeField.HASHTAG_CASE_AWARE,
+              ChangeField.ID,
+              ChangeField.IS_PURE_REVERT,
+              ChangeField.IS_SUBMITTABLE,
+              ChangeField.LABEL,
+              ChangeField.LEGACY_ID_STR,
+              ChangeField.MERGE,
+              ChangeField.MERGEABLE,
+              ChangeField.MERGED_ON,
+              ChangeField.ONLY_EXTENSIONS,
+              ChangeField.OWNER,
+              ChangeField.PATCH_SET,
+              ChangeField.PATH,
+              ChangeField.PENDING_REVIEWER,
+              ChangeField.PENDING_REVIEWER_BY_EMAIL,
+              ChangeField.PRIVATE,
+              ChangeField.REF_STATE,
+              ChangeField.REF_STATE_PATTERN,
+              ChangeField.REVERT_OF,
+              ChangeField.REVIEWEDBY,
+              ChangeField.REVIEWER,
+              ChangeField.REVIEWER_BY_EMAIL,
+              ChangeField.STAR,
+              ChangeField.STARBY,
+              ChangeField.STARTED,
+              ChangeField.STORED_SUBMIT_RECORD_LENIENT,
+              ChangeField.STORED_SUBMIT_RECORD_STRICT,
+              ChangeField.STORED_SUBMIT_REQUIREMENTS,
+              ChangeField.SUBMIT_RECORD,
+              ChangeField.SUBMIT_RULE_RESULT,
+              ChangeField.TOTAL_COMMENT_COUNT,
+              ChangeField.TR,
+              ChangeField.UNRESOLVED_COMMENT_COUNT,
+              ChangeField.UPDATED,
+              ChangeField.UPLOADER,
+              ChangeField.WIP),
+          ImmutableList.of(
+              ChangeField.SUBMISSIONID_FIELD,
+              ChangeField.STATUS_FIELD,
+              ChangeField.PROJECT_FIELD,
+              ChangeField.REF_FIELD,
+              ChangeField.TOPIC_FIELD),
+          ImmutableList.of(
+              ChangeField.EXACT_TOPIC,
+              ChangeField.FUZZY_TOPIC,
+              ChangeField.SUBMISSIONID_SPEC,
+              ChangeField.STATUS_SPEC,
+              ChangeField.PROJECT_SPEC,
+              ChangeField.PROJECTS_SPEC,
+              ChangeField.REF_SPEC));
 
   /**
    * Added new field {@link ChangeField#PREFIX_HASHTAG} and {@link ChangeField#PREFIX_TOPIC} to
@@ -115,7 +124,7 @@
       new Schema.Builder<ChangeData>()
           .add(V74)
           .add(ChangeField.PREFIX_HASHTAG)
-          .add(ChangeField.PREFIX_TOPIC)
+          .addSearchSpecs(ChangeField.PREFIX_TOPIC)
           .build();
 
   /** Added new field {@link ChangeField#FOOTER_NAME}. */
diff --git a/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java b/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
index 339d7bb..76610f3 100644
--- a/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
+++ b/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
@@ -16,7 +16,7 @@
 
 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 static com.google.gerrit.server.index.change.ChangeField.PROJECT_SPEC;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
@@ -69,9 +69,9 @@
       int limit,
       Set<String> fields) {
     // Always include project since it is needed to load the change from NoteDb.
-    if (!fields.contains(CHANGE.getName()) && !fields.contains(PROJECT.getName())) {
+    if (!fields.contains(CHANGE.getName()) && !fields.contains(PROJECT_SPEC.getName())) {
       fields = new HashSet<>(fields);
-      fields.add(PROJECT.getName());
+      fields.add(PROJECT_SPEC.getName());
     }
     return QueryOptions.create(config, start, pageSize, pageSizeMultiplier, limit, fields);
   }
diff --git a/java/com/google/gerrit/server/query/change/ChangePredicates.java b/java/com/google/gerrit/server/query/change/ChangePredicates.java
index 3363ad7..7dad123 100644
--- a/java/com/google/gerrit/server/query/change/ChangePredicates.java
+++ b/java/com/google/gerrit/server/query/change/ChangePredicates.java
@@ -170,12 +170,12 @@
    * com.google.gerrit.entities.Project.NameKey}.
    */
   public static Predicate<ChangeData> project(Project.NameKey id) {
-    return new ChangeIndexPredicate(ChangeField.PROJECT, id.get());
+    return new ChangeIndexPredicate(ChangeField.PROJECT_SPEC, id.get());
   }
 
   /** Returns a predicate that matches changes targeted at the provided {@code refName}. */
   public static Predicate<ChangeData> ref(String refName) {
-    return new ChangeIndexPredicate(ChangeField.REF, refName);
+    return new ChangeIndexPredicate(ChangeField.REF_SPEC, refName);
   }
 
   /** Returns a predicate that matches changes in the provided {@code topic}. */
@@ -195,7 +195,7 @@
 
   /** Returns a predicate that matches changes submitted in the provided {@code changeSet}. */
   public static Predicate<ChangeData> submissionId(String changeSet) {
-    return new ChangeIndexPredicate(ChangeField.SUBMISSIONID, changeSet);
+    return new ChangeIndexPredicate(ChangeField.SUBMISSIONID_SPEC, changeSet);
   }
 
   /** Returns a predicate that matches changes that modified the provided {@code path}. */
@@ -308,7 +308,7 @@
    * its name.
    */
   public static Predicate<ChangeData> projectPrefix(String prefix) {
-    return new ChangeIndexPredicate(ChangeField.PROJECTS, prefix);
+    return new ChangeIndexPredicate(ChangeField.PROJECTS_SPEC, prefix);
   }
 
   /**
diff --git a/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java b/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
index 9aff0c5..0dc923f 100644
--- a/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
@@ -104,7 +104,7 @@
   @Nullable private final Change.Status status;
 
   private ChangeStatusPredicate(@Nullable Change.Status status) {
-    super(ChangeField.STATUS, status != null ? canonicalize(status) : INVALID_STATUS);
+    super(ChangeField.STATUS_SPEC, status != null ? canonicalize(status) : INVALID_STATUS);
     this.status = status;
   }
 
diff --git a/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java b/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
index bbdfc66..a51dcc4 100644
--- a/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
+++ b/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
@@ -24,7 +24,7 @@
   protected final RunAutomaton pattern;
 
   public RegexProjectPredicate(String re) {
-    super(ChangeField.PROJECT, re);
+    super(ChangeField.PROJECT_SPEC, re);
 
     if (re.startsWith("^")) {
       re = re.substring(1);
diff --git a/java/com/google/gerrit/server/query/change/RegexRefPredicate.java b/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
index b2dba72..cc556ba 100644
--- a/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
+++ b/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
@@ -24,7 +24,7 @@
   protected final RunAutomaton pattern;
 
   public RegexRefPredicate(String re) throws QueryParseException {
-    super(ChangeField.REF, re);
+    super(ChangeField.REF_SPEC, re);
 
     if (re.startsWith("^")) {
       re = re.substring(1);
diff --git a/javatests/com/google/gerrit/server/index/change/FakeChangeIndex.java b/javatests/com/google/gerrit/server/index/change/FakeChangeIndex.java
index f70c97a..451126c 100644
--- a/javatests/com/google/gerrit/server/index/change/FakeChangeIndex.java
+++ b/javatests/com/google/gerrit/server/index/change/FakeChangeIndex.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.index.SchemaUtil.schema;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.Schema;
@@ -29,10 +30,19 @@
 
 @Ignore
 public class FakeChangeIndex implements ChangeIndex {
-  static final Schema<ChangeData> V1 = schema(1, ChangeField.STATUS);
+  static final Schema<ChangeData> V1 =
+      schema(
+          1,
+          ImmutableList.of(),
+          ImmutableList.of(ChangeField.STATUS_FIELD),
+          ImmutableList.of(ChangeField.STATUS_SPEC));
 
   static final Schema<ChangeData> V2 =
-      schema(2, ChangeField.STATUS, ChangeField.PATH, ChangeField.UPDATED);
+      schema(
+          2,
+          ImmutableList.of(ChangeField.PATH, ChangeField.UPDATED),
+          ImmutableList.of(ChangeField.STATUS_FIELD),
+          ImmutableList.of(ChangeField.STATUS_SPEC));
 
   private static class Source implements ChangeDataSource {
     private final Predicate<ChangeData> p;