Part8: Migrate ChangeIndex FieldDefs to the new format SchemaFields

Release-Notes: skip
Change-Id: I5d096731d655f3e2c31f614037e555948d8db510
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommitsAdvertiseRefsHook.java b/java/com/google/gerrit/server/git/receive/ReceiveCommitsAdvertiseRefsHook.java
index c06622b..5667c28 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommitsAdvertiseRefsHook.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommitsAdvertiseRefsHook.java
@@ -114,7 +114,7 @@
                   ChangeField.CHANGE,
                   ChangeField.REVIEWER_SPEC,
                   // Required during advertiseOpenChanges.
-                  ChangeField.PATCH_SET)
+                  ChangeField.PATCH_SET_SPEC)
               .enforceVisibility(true)
               .setLimit(limit)
               .query(
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index 7117d66..09e267e 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -41,6 +41,7 @@
 import com.google.common.flogger.FluentLogger;
 import com.google.common.io.Files;
 import com.google.common.primitives.Longs;
+import com.google.common.reflect.TypeToken;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.Account;
 import com.google.gerrit.entities.Address;
@@ -64,10 +65,12 @@
 import com.google.gerrit.index.SchemaFieldDefs;
 import com.google.gerrit.index.SchemaUtil;
 import com.google.gerrit.json.OutputFormat;
+import com.google.gerrit.proto.Entities;
 import com.google.gerrit.proto.Protos;
 import com.google.gerrit.server.ReviewerByEmailSet;
 import com.google.gerrit.server.ReviewerSet;
 import com.google.gerrit.server.StarredChangesUtil;
+import com.google.gerrit.server.cache.proto.Cache;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.index.change.StalenessChecker.RefStatePattern;
 import com.google.gerrit.server.notedb.ReviewerStateInternal;
@@ -978,13 +981,26 @@
               (cd, field) -> cd.setChange(parseProtoFrom(field, ChangeProtoConverter.INSTANCE)));
 
   /** Serialized approvals for the current patch set, used for pre-populating results. */
-  public static final FieldDef<ChangeData, Iterable<byte[]>> APPROVAL =
-      storedOnly("_approval")
-          .buildRepeatable(
-              cd -> toProtos(PatchSetApprovalProtoConverter.INSTANCE, cd.currentApprovals()),
+  private static final TypeToken<Iterable<Entities.PatchSetApproval>> APPROVAL_TYPE_TOKEN =
+      new TypeToken<Iterable<Entities.PatchSetApproval>>() {
+        private static final long serialVersionUID = 1L;
+      };
+
+  public static final IndexedField<ChangeData, Iterable<Entities.PatchSetApproval>> APPROVAL_FIELD =
+      IndexedField.<ChangeData, Iterable<Entities.PatchSetApproval>>builder(
+              "Approval", APPROVAL_TYPE_TOKEN)
+          .stored()
+          .required()
+          .protoConverter(Optional.of(PatchSetApprovalProtoConverter.INSTANCE))
+          .build(
+              cd ->
+                  entitiesToProtos(PatchSetApprovalProtoConverter.INSTANCE, cd.currentApprovals()),
               (cd, field) ->
                   cd.setCurrentApprovals(
-                      decodeProtos(field, PatchSetApprovalProtoConverter.INSTANCE)));
+                      decodeProtosToEntities(field, PatchSetApprovalProtoConverter.INSTANCE)));
+
+  public static final IndexedField<ChangeData, Iterable<Entities.PatchSetApproval>>.SearchSpec
+      APPROVAL_SPEC = APPROVAL_FIELD.storedOnly("_approval");
 
   public static String formatLabel(String label, int value) {
     return formatLabel(label, value, /* accountId= */ null, /* count= */ null);
@@ -1246,11 +1262,24 @@
       GROUP_FIELD.exact(ChangeQueryBuilder.FIELD_GROUP);
 
   /** Serialized patch set object, used for pre-populating results. */
-  public static final FieldDef<ChangeData, Iterable<byte[]>> PATCH_SET =
-      storedOnly("_patch_set")
-          .buildRepeatable(
-              cd -> toProtos(PatchSetProtoConverter.INSTANCE, cd.patchSets()),
-              (cd, field) -> cd.setPatchSets(decodeProtos(field, PatchSetProtoConverter.INSTANCE)));
+  private static final TypeToken<Iterable<Entities.PatchSet>> PATCH_SET_TYPE_TOKEN =
+      new TypeToken<Iterable<Entities.PatchSet>>() {
+        private static final long serialVersionUID = 1L;
+      };
+
+  public static final IndexedField<ChangeData, Iterable<Entities.PatchSet>> PATCH_SET_FIELD =
+      IndexedField.<ChangeData, Iterable<Entities.PatchSet>>builder(
+              "PatchSet", PATCH_SET_TYPE_TOKEN)
+          .stored()
+          .required()
+          .protoConverter(Optional.of(PatchSetProtoConverter.INSTANCE))
+          .build(
+              cd -> entitiesToProtos(PatchSetProtoConverter.INSTANCE, cd.patchSets()),
+              (cd, value) ->
+                  cd.setPatchSets(decodeProtosToEntities(value, PatchSetProtoConverter.INSTANCE)));
+
+  public static final IndexedField<ChangeData, Iterable<Entities.PatchSet>>.SearchSpec
+      PATCH_SET_SPEC = PATCH_SET_FIELD.storedOnly("_patch_set");
 
   /** Users who have edits on this change. */
   public static final IndexedField<ChangeData, Iterable<Integer>> EDITBY_FIELD =
@@ -1307,9 +1336,9 @@
       SubmitRuleOptions.builder().build();
 
   /** All submit rules results in the form of "$ruleName,$status". */
-  public static final FieldDef<ChangeData, Iterable<String>> SUBMIT_RULE_RESULT =
-      exact("submit_rule_result")
-          .buildRepeatable(
+  public static final IndexedField<ChangeData, Iterable<String>> SUBMIT_RULE_RESULT_FIELD =
+      IndexedField.<ChangeData>iterableStringBuilder("SubmitRuleResult")
+          .build(
               cd -> {
                 List<String> result = new ArrayList<>();
                 List<SubmitRecord> submitRecords = cd.submitRecords(SUBMIT_RULE_OPTIONS_STRICT);
@@ -1319,6 +1348,9 @@
                 return result;
               });
 
+  public static final IndexedField<ChangeData, Iterable<String>>.SearchSpec
+      SUBMIT_RULE_RESULT_SPEC = SUBMIT_RULE_RESULT_FIELD.exact("submit_rule_result");
+
   /**
    * JSON type for storing SubmitRecords.
    *
@@ -1405,12 +1437,17 @@
     }
   }
 
-  public static final FieldDef<ChangeData, Iterable<String>> SUBMIT_RECORD =
-      exact("submit_record").buildRepeatable(ChangeField::formatSubmitRecordValues);
+  public static final IndexedField<ChangeData, Iterable<String>> SUBMIT_RECORD_FIELD =
+      IndexedField.<ChangeData>iterableStringBuilder("SubmitRecord")
+          .build(ChangeField::formatSubmitRecordValues);
 
-  public static final FieldDef<ChangeData, Iterable<byte[]>> STORED_SUBMIT_RECORD_STRICT =
-      storedOnly("full_submit_record_strict")
-          .buildRepeatable(
+  public static final IndexedField<ChangeData, Iterable<String>>.SearchSpec SUBMIT_RECORD_SPEC =
+      SUBMIT_RECORD_FIELD.exact("submit_record");
+
+  public static final IndexedField<ChangeData, Iterable<byte[]>> STORED_SUBMIT_RECORD_STRICT_FIELD =
+      IndexedField.<ChangeData>iterableByteArrayBuilder("FullSubmitRecordStrict")
+          .stored()
+          .build(
               cd -> storedSubmitRecords(cd, SUBMIT_RULE_OPTIONS_STRICT),
               (cd, field) ->
                   parseSubmitRecords(
@@ -1420,17 +1457,27 @@
                       SUBMIT_RULE_OPTIONS_STRICT,
                       cd));
 
-  public static final FieldDef<ChangeData, Iterable<byte[]>> STORED_SUBMIT_RECORD_LENIENT =
-      storedOnly("full_submit_record_lenient")
-          .buildRepeatable(
-              cd -> storedSubmitRecords(cd, SUBMIT_RULE_OPTIONS_LENIENT),
-              (cd, field) ->
-                  parseSubmitRecords(
-                      StreamSupport.stream(field.spliterator(), false)
-                          .map(f -> new String(f, UTF_8))
-                          .collect(toSet()),
-                      SUBMIT_RULE_OPTIONS_LENIENT,
-                      cd));
+  public static final IndexedField<ChangeData, Iterable<byte[]>>.SearchSpec
+      STORED_SUBMIT_RECORD_STRICT_SPEC =
+          STORED_SUBMIT_RECORD_STRICT_FIELD.storedOnly("full_submit_record_strict");
+
+  public static final IndexedField<ChangeData, Iterable<byte[]>>
+      STORED_SUBMIT_RECORD_LENIENT_FIELD =
+          IndexedField.<ChangeData>iterableByteArrayBuilder("FullSubmitRecordLenient")
+              .stored()
+              .build(
+                  cd -> storedSubmitRecords(cd, SUBMIT_RULE_OPTIONS_LENIENT),
+                  (cd, field) ->
+                      parseSubmitRecords(
+                          StreamSupport.stream(field.spliterator(), false)
+                              .map(f -> new String(f, UTF_8))
+                              .collect(toSet()),
+                          SUBMIT_RULE_OPTIONS_LENIENT,
+                          cd));
+
+  public static final IndexedField<ChangeData, Iterable<byte[]>>.SearchSpec
+      STORED_SUBMIT_RECORD_LENIENT_SPEC =
+          STORED_SUBMIT_RECORD_LENIENT_FIELD.storedOnly("full_submit_record_lenient");
 
   public static void parseSubmitRecords(
       Collection<String> values, SubmitRuleOptions opts, ChangeData out) {
@@ -1535,22 +1582,35 @@
   }
 
   /** Serialized submit requirements, used for pre-populating results. */
-  public static final FieldDef<ChangeData, Iterable<byte[]>> STORED_SUBMIT_REQUIREMENTS =
-      storedOnly("full_submit_requirements")
-          .buildRepeatable(
-              cd ->
-                  toProtos(
-                      SubmitRequirementProtoConverter.INSTANCE, cd.submitRequirements().values()),
-              (cd, field) -> parseSubmitRequirements(field, cd));
+  private static final TypeToken<Iterable<Cache.SubmitRequirementResultProto>>
+      STORED_SUBMIT_REQUIREMENTS_TYPE_TOKEN =
+          new TypeToken<Iterable<Cache.SubmitRequirementResultProto>>() {
+            private static final long serialVersionUID = 1L;
+          };
 
-  private static void parseSubmitRequirements(Iterable<byte[]> values, ChangeData out) {
+  public static final IndexedField<ChangeData, Iterable<Cache.SubmitRequirementResultProto>>
+      STORED_SUBMIT_REQUIREMENTS_FIELD =
+          IndexedField.<ChangeData, Iterable<Cache.SubmitRequirementResultProto>>builder(
+                  "StoredSubmitRequirements", STORED_SUBMIT_REQUIREMENTS_TYPE_TOKEN)
+              .stored()
+              .required()
+              .protoConverter(Optional.of(SubmitRequirementProtoConverter.INSTANCE))
+              .build(
+                  cd ->
+                      entitiesToProtos(
+                          SubmitRequirementProtoConverter.INSTANCE,
+                          cd.submitRequirements().values()),
+                  (cd, value) -> parseSubmitRequirements(value, cd));
+
+  public static final IndexedField<ChangeData, Iterable<Cache.SubmitRequirementResultProto>>
+          .SearchSpec
+      STORED_SUBMIT_REQUIREMENTS_SPEC =
+          STORED_SUBMIT_REQUIREMENTS_FIELD.storedOnly("full_submit_requirements");
+
+  private static void parseSubmitRequirements(
+      Iterable<Cache.SubmitRequirementResultProto> values, ChangeData out) {
     out.setSubmitRequirements(
-        StreamSupport.stream(values.spliterator(), false)
-            .map(
-                f ->
-                    SubmitRequirementProtoConverter.INSTANCE.fromProto(
-                        Protos.parseUnchecked(
-                            SubmitRequirementProtoConverter.INSTANCE.getParser(), f)))
+        decodeProtosToEntities(values, SubmitRequirementProtoConverter.INSTANCE).stream()
             .filter(sr -> !sr.isLegacy())
             .collect(
                 ImmutableMap.toImmutableMap(sr -> sr.submitRequirement(), Function.identity())));
@@ -1609,20 +1669,34 @@
     return firstNonNull(c.getTopic(), "");
   }
 
-  private static <T> List<byte[]> toProtos(ProtoConverter<?, T> converter, Collection<T> objects) {
-    return objects.stream().map(object -> toProto(converter, object)).collect(toImmutableList());
-  }
-
   private static <T> byte[] toProto(ProtoConverter<?, T> converter, T object) {
     return Protos.toByteArray(converter.toProto(object));
   }
 
-  private static <T> List<T> decodeProtos(Iterable<byte[]> raw, ProtoConverter<?, T> converter) {
-    return StreamSupport.stream(raw.spliterator(), false)
-        .map(bytes -> parseProtoFrom(bytes, converter))
+  private static <V extends MessageLite, T> V entityToProto(
+      ProtoConverter<V, T> converter, T object) {
+    return converter.toProto(object);
+  }
+
+  private static <V extends MessageLite, T> List<V> entitiesToProtos(
+      ProtoConverter<V, T> converter, Collection<T> objects) {
+    return objects.stream()
+        .map(object -> entityToProto(converter, object))
         .collect(toImmutableList());
   }
 
+  private static <V extends MessageLite, T> List<T> decodeProtosToEntities(
+      Iterable<V> raw, ProtoConverter<V, T> converter) {
+    return StreamSupport.stream(raw.spliterator(), false)
+        .map(proto -> decodeProtoToEntity(proto, converter))
+        .collect(toImmutableList());
+  }
+
+  private static <V extends MessageLite, T> T decodeProtoToEntity(
+      V proto, ProtoConverter<V, T> converter) {
+    return converter.fromProto(proto);
+  }
+
   private static <P extends MessageLite, T> T parseProtoFrom(
       byte[] bytes, ProtoConverter<P, T> converter) {
     P message = Protos.parseUnchecked(converter.getParser(), bytes, 0, bytes.length);
diff --git a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index 6c92f111..b3732f1 100644
--- a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -35,21 +35,15 @@
       schema(
           /* version= */ 74,
           ImmutableList.of(
-              ChangeField.APPROVAL,
               ChangeField.CHANGE,
               ChangeField.ID,
               ChangeField.LEGACY_ID_STR,
-              ChangeField.PATCH_SET,
               ChangeField.REF_STATE,
               ChangeField.REF_STATE_PATTERN,
-              ChangeField.STORED_SUBMIT_RECORD_LENIENT,
-              ChangeField.STORED_SUBMIT_RECORD_STRICT,
-              ChangeField.STORED_SUBMIT_REQUIREMENTS,
-              ChangeField.SUBMIT_RECORD,
-              ChangeField.SUBMIT_RULE_RESULT,
               ChangeField.UPDATED),
           ImmutableList.<IndexedField<ChangeData, ?>>of(
               ChangeField.ADDED_LINES_FIELD,
+              ChangeField.APPROVAL_FIELD,
               ChangeField.ASSIGNEE_FIELD,
               ChangeField.ATTENTION_SET_FULL_FIELD,
               ChangeField.ATTENTION_SET_USERS_COUNT_FIELD,
@@ -84,6 +78,7 @@
               ChangeField.MERGE_FIELD,
               ChangeField.ONLY_EXTENSIONS_FIELD,
               ChangeField.OWNER_FIELD,
+              ChangeField.PATCH_SET_FIELD,
               ChangeField.PATH_FIELD,
               ChangeField.PENDING_REVIEWER_BY_EMAIL_FIELD,
               ChangeField.PENDING_REVIEWER_FIELD,
@@ -91,22 +86,28 @@
               ChangeField.PROJECT_FIELD,
               ChangeField.REF_FIELD,
               ChangeField.REVERT_OF_FIELD,
+              ChangeField.REVIEWEDBY_FIELD,
               ChangeField.REVIEWER_BY_EMAIL_FIELD,
               ChangeField.REVIEWER_FIELD,
               ChangeField.STARBY_FIELD,
               ChangeField.STARTED_FIELD,
               ChangeField.STAR_FIELD,
               ChangeField.STATUS_FIELD,
+              ChangeField.STORED_SUBMIT_RECORD_LENIENT_FIELD,
+              ChangeField.STORED_SUBMIT_RECORD_STRICT_FIELD,
+              ChangeField.STORED_SUBMIT_REQUIREMENTS_FIELD,
               ChangeField.SUBMISSIONID_FIELD,
+              ChangeField.SUBMIT_RECORD_FIELD,
               ChangeField.TOPIC_FIELD,
               ChangeField.TOTAL_COMMENT_COUNT_FIELD,
               ChangeField.TR_FIELD,
               ChangeField.UNRESOLVED_COMMENT_COUNT_FIELD,
               ChangeField.UPLOADER_FIELD,
               ChangeField.WIP_FIELD,
-              ChangeField.REVIEWEDBY_FIELD),
+              ChangeField.SUBMIT_RULE_RESULT_FIELD),
           ImmutableList.<IndexedField<ChangeData, ?>.SearchSpec>of(
               ChangeField.ADDED_LINES_SPEC,
+              ChangeField.APPROVAL_SPEC,
               ChangeField.ASSIGNEE_SPEC,
               ChangeField.ATTENTION_SET_FULL_SPEC,
               ChangeField.ATTENTION_SET_USERS,
@@ -145,6 +146,7 @@
               ChangeField.MERGE_SPEC,
               ChangeField.ONLY_EXTENSIONS_SPEC,
               ChangeField.OWNER_SPEC,
+              ChangeField.PATCH_SET_SPEC,
               ChangeField.PATH_SPEC,
               ChangeField.PENDING_REVIEWER_BY_EMAIL,
               ChangeField.PENDING_REVIEWER_SPEC,
@@ -153,19 +155,24 @@
               ChangeField.PROJECT_SPEC,
               ChangeField.REF_SPEC,
               ChangeField.REVERT_OF,
+              ChangeField.REVIEWEDBY_SPEC,
               ChangeField.REVIEWER_BY_EMAIL,
               ChangeField.REVIEWER_SPEC,
               ChangeField.STARBY_SPEC,
               ChangeField.STARTED_SPEC,
               ChangeField.STAR_SPEC,
               ChangeField.STATUS_SPEC,
+              ChangeField.STORED_SUBMIT_RECORD_LENIENT_SPEC,
+              ChangeField.STORED_SUBMIT_RECORD_STRICT_SPEC,
+              ChangeField.STORED_SUBMIT_REQUIREMENTS_SPEC,
               ChangeField.SUBMISSIONID_SPEC,
+              ChangeField.SUBMIT_RECORD_SPEC,
               ChangeField.TOTAL_COMMENT_COUNT_SPEC,
               ChangeField.TR_SPEC,
               ChangeField.UNRESOLVED_COMMENT_COUNT_SPEC,
               ChangeField.UPLOADER_SPEC,
               ChangeField.WIP_SPEC,
-              ChangeField.REVIEWEDBY_SPEC));
+              ChangeField.SUBMIT_RULE_RESULT_SPEC));
 
   /**
    * Added new field {@link ChangeField#PREFIX_HASHTAG} and {@link ChangeField#PREFIX_TOPIC} to
diff --git a/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java b/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
index ab4bb70..34b40f5 100644
--- a/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
@@ -264,7 +264,7 @@
               .changeIndexQuery(
                   "projectsConsistencyCheckerQueryChanges",
                   q ->
-                      q.setRequestedFields(ChangeField.CHANGE, ChangeField.PATCH_SET)
+                      q.setRequestedFields(ChangeField.CHANGE, ChangeField.PATCH_SET_SPEC)
                           .query(and(basePredicate, or(predicates))))
               .call();
 
diff --git a/java/com/google/gerrit/server/query/change/ChangePredicates.java b/java/com/google/gerrit/server/query/change/ChangePredicates.java
index c2672a9..b268c7c 100644
--- a/java/com/google/gerrit/server/query/change/ChangePredicates.java
+++ b/java/com/google/gerrit/server/query/change/ChangePredicates.java
@@ -348,7 +348,7 @@
    * in the form of 'gerrit~$rule_name'.
    */
   public static Predicate<ChangeData> submitRuleStatus(String value) {
-    return new ChangeIndexPredicate(ChangeField.SUBMIT_RULE_RESULT, value);
+    return new ChangeIndexPredicate(ChangeField.SUBMIT_RULE_RESULT_SPEC, value);
   }
 
   /**
diff --git a/java/com/google/gerrit/server/query/change/SubmitRecordPredicate.java b/java/com/google/gerrit/server/query/change/SubmitRecordPredicate.java
index ecddbb6..1ea6c41 100644
--- a/java/com/google/gerrit/server/query/change/SubmitRecordPredicate.java
+++ b/java/com/google/gerrit/server/query/change/SubmitRecordPredicate.java
@@ -36,7 +36,7 @@
   }
 
   private SubmitRecordPredicate(String value) {
-    super(ChangeField.SUBMIT_RECORD, value);
+    super(ChangeField.SUBMIT_RECORD_SPEC, value);
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/query/change/SubmittablePredicate.java b/java/com/google/gerrit/server/query/change/SubmittablePredicate.java
index 060a92e..e543ac3 100644
--- a/java/com/google/gerrit/server/query/change/SubmittablePredicate.java
+++ b/java/com/google/gerrit/server/query/change/SubmittablePredicate.java
@@ -21,7 +21,7 @@
   protected final SubmitRecord.Status status;
 
   public SubmittablePredicate(SubmitRecord.Status status) {
-    super(ChangeField.SUBMIT_RECORD, status.name());
+    super(ChangeField.SUBMIT_RECORD_SPEC, status.name());
     this.status = status;
   }