Add deleteAllForProject() for changes index

This method was added in Gerrit core to support scenarios involving
the deletion of all changes of a single project.

This is realised by using the _delete_by_query API.

Change-Id: I6ab3388ea8d5a190dae1d50f4c42e7fde9bc57ee
diff --git a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index dfa719c..6166e01 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -88,6 +88,7 @@
 
   protected static final String BULK = "_bulk";
   protected static final String COUNT = "_count";
+  protected static final String DELETE_BY_QUERY = "_delete_by_query";
   protected static final String MAPPINGS = "mappings";
   protected static final String ORDER = "order";
   protected static final String DESC_SORT_ORDER = "desc";
diff --git a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index ec12a7a..eee1be9 100644
--- a/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -19,11 +19,14 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.elasticsearch.ElasticMapping.Mapping;
+import com.google.gerrit.elasticsearch.builders.QueryBuilder;
+import com.google.gerrit.elasticsearch.builders.SearchSourceBuilder;
 import com.google.gerrit.elasticsearch.bulk.BulkRequest;
 import com.google.gerrit.elasticsearch.bulk.IndexRequest;
 import com.google.gerrit.elasticsearch.bulk.UpdateRequest;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
 import com.google.gerrit.entities.converter.ChangeProtoConverter;
 import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.index.QueryOptions;
@@ -40,6 +43,7 @@
 import com.google.gerrit.server.index.change.ChangeIndex;
 import com.google.gerrit.server.index.options.AutoFlush;
 import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.ChangePredicates;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
@@ -191,4 +195,24 @@
 
     return cd;
   }
+
+  @Override
+  public void deleteAllForProject(NameKey project) {
+    QueryBuilder qb;
+    try {
+      qb = queryBuilder.toQueryBuilder(ChangePredicates.project(project));
+    } catch (QueryParseException e) {
+      throw new IllegalStateException("Failed to build project query.", e);
+    }
+    String payload = new SearchSourceBuilder(client.adapter()).query(qb).toString();
+    String uri = getURI(DELETE_BY_QUERY);
+    Response response = postRequestWithRefreshParam(uri, payload);
+    int statusCode = response.getStatusLine().getStatusCode();
+    if (statusCode != HttpStatus.SC_OK) {
+      throw new StorageException(
+          String.format(
+              "Failed to delete changes in project %s from index %s: %s",
+              project, indexName, statusCode));
+    }
+  }
 }