From aa2568f9c1435110f1520e45b86f34f62d2749cd Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Fri, 6 Aug 2021 00:10:33 +0200
Subject: [PATCH] WIP: count query

---
 pom.xml                                       |  2 +-
 .../grpc/EntityTransactionServiceImpl.java    | 14 ++++-
 .../caosdb/server/jobs/core/ExecuteQuery.java |  6 +-
 .../java/org/caosdb/server/query/Query.java   | 62 +++++++++++--------
 4 files changed, 54 insertions(+), 30 deletions(-)

diff --git a/pom.xml b/pom.xml
index 70646648..1396ba39 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.caosdb</groupId>
   <artifactId>caosdb-server</artifactId>
-  <version>0.5.0-GRPC0.0.9</version>
+  <version>0.5.0-GRPC0.0.10</version>
   <packaging>jar</packaging>
   <name>CaosDB Server</name>
   <scm>
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index 98887751..20cf56b1 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -218,7 +218,8 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
     for (final TransactionRequest sub_request : request.getRequestsList()) {
       if (sub_request.getRetrieveRequest().hasQuery()
           && !sub_request.getRetrieveRequest().getQuery().getQuery().isBlank()) {
-        container.getFlags().put("query", sub_request.getRetrieveRequest().getQuery().getQuery());
+        final String query = sub_request.getRetrieveRequest().getQuery().getQuery();
+        container.getFlags().put("query", query);
       } else {
         final String id = sub_request.getRetrieveRequest().getId();
         if (!id.isBlank()) {
@@ -234,10 +235,17 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
 
     final Retrieve transaction = new Retrieve(container);
     transaction.execute();
-    for (final EntityInterface entity : container) {
+    if (container.getFlags().containsKey("_isCount")) {
+      final int count = Integer.parseInt(container.getFlags().get("_isCount"));
       builder
           .addResponsesBuilder()
-          .setRetrieveResponse(RetrieveResponse.newBuilder().setEntity(convert(entity)));
+          .setRetrieveResponse(RetrieveResponse.newBuilder().setCountResult(count));
+    } else {
+      for (final EntityInterface entity : container) {
+        builder
+            .addResponsesBuilder()
+            .setRetrieveResponse(RetrieveResponse.newBuilder().setEntity(convert(entity)));
+      }
     }
 
     // Add those entities which have not been retrieved because the have a string id
diff --git a/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java b/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java
index 399039a0..31bedc97 100644
--- a/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java
+++ b/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java
@@ -29,6 +29,7 @@ import org.caosdb.server.jobs.JobAnnotation;
 import org.caosdb.server.jobs.TransactionStage;
 import org.caosdb.server.query.Query;
 import org.caosdb.server.query.Query.ParsingException;
+import org.caosdb.server.query.Query.Type;
 import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
@@ -52,7 +53,10 @@ public class ExecuteQuery extends FlagJob {
       getContainer().addMessage(new Message(e.getMessage()));
     }
     getContainer().addMessage(queryInstance);
-    for (EntityInterface entity : getContainer()) {
+    if (queryInstance.getQuery().getType() == Type.COUNT) {
+      getContainer().getFlags().put("count", Integer.toString(queryInstance.getCount()));
+    }
+    for (final EntityInterface entity : getContainer()) {
       getTransaction().getSchedule().addAll(loadJobs(entity, getTransaction()));
     }
   }
diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java
index dca63841..eebd2b2e 100644
--- a/src/main/java/org/caosdb/server/query/Query.java
+++ b/src/main/java/org/caosdb/server/query/Query.java
@@ -174,7 +174,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
   }
 
   public static class IdVersionPair {
-    public IdVersionPair(Integer id, String version) {
+    public IdVersionPair(final Integer id, final String version) {
       this.id = id;
       this.version = version;
     }
@@ -191,9 +191,9 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
       if (obj instanceof IdVersionPair) {
-        IdVersionPair that = (IdVersionPair) obj;
+        final IdVersionPair that = (IdVersionPair) obj;
         return this.id == that.id && this.version == that.version;
       }
       return false;
@@ -205,12 +205,12 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
   }
 
-  private boolean filterEntitiesWithoutRetrievePermisions =
+  private final boolean filterEntitiesWithoutRetrievePermisions =
       !CaosDBServer.getServerProperty(
               ServerProperties.KEY_QUERY_FILTER_ENTITIES_WITHOUT_RETRIEVE_PERMISSIONS)
           .equalsIgnoreCase("FALSE");
 
-  private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
+  private final Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
   List<IdVersionPair> resultSet = null;
   private final String query;
   private Pattern entity = null;
@@ -461,8 +461,8 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
   }
 
-  private String initQuery(boolean versioned) throws QueryException {
-    String sql = "call initQuery(" + versioned + ")";
+  private String initQuery(final boolean versioned) throws QueryException {
+    final String sql = "call initQuery(" + versioned + ")";
     try (final CallableStatement callInitQuery = getConnection().prepareCall(sql)) {
       ResultSet initQueryResult = null;
       initQueryResult = callInitQuery.executeQuery();
@@ -481,7 +481,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @param optimize whether to run optimize() immediately.
    * @throws ParsingException
    */
-  public void parse(boolean optimize) throws ParsingException {
+  public void parse(final boolean optimize) throws ParsingException {
     final long t1 = System.currentTimeMillis();
     CQLLexer lexer;
     lexer = new CQLLexer(CharStreams.fromString(this.query));
@@ -544,7 +544,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     }
   }
 
-  private String executeStrategy(boolean versioned) throws QueryException {
+  private String executeStrategy(final boolean versioned) throws QueryException {
     if (this.entity != null) {
       return sourceStrategy(initQuery(versioned));
     } else if (this.role == Role.ENTITY && this.filter == null) {
@@ -567,7 +567,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @throws QueryException
    */
   private String generateSelectStatementForResultSet(
-      final String resultSetTableName, boolean versioned) {
+      final String resultSetTableName, final boolean versioned) {
     if (resultSetTableName.equals("entities")) {
       return "SELECT entity_id AS id"
           + (versioned ? ", version AS version" : "")
@@ -592,7 +592,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @return list of results of this query.
    * @throws QueryException
    */
-  private List<IdVersionPair> getResultSet(final String resultSetTableName, boolean versioned)
+  private List<IdVersionPair> getResultSet(final String resultSetTableName, final boolean versioned)
       throws QueryException {
     ResultSet finishResultSet = null;
     try {
@@ -688,7 +688,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @param key
    * @param resultSet
    */
-  private void setCache(String key, List<IdVersionPair> resultSet) {
+  private void setCache(final String key, final List<IdVersionPair> resultSet) {
     synchronized (cache) {
       if (resultSet instanceof Serializable) {
         cache.put(key, (Serializable) resultSet);
@@ -705,11 +705,11 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @return
    */
   @SuppressWarnings("unchecked")
-  private List<IdVersionPair> getCached(String key) {
+  private List<IdVersionPair> getCached(final String key) {
     return (List<IdVersionPair>) cache.get(key);
   }
 
-  protected void executeNoCache(Access access) {
+  protected void executeNoCache(final Access access) {
     try {
       this.resultSet = getResultSet(executeStrategy(this.versioned), this.versioned);
     } finally {
@@ -799,7 +799,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       return entities;
     }
 
-    List<IdVersionPair> result = new ArrayList<>();
+    final List<IdVersionPair> result = new ArrayList<>();
     final Iterator<IdVersionPair> iterator = entities.iterator();
     while (iterator.hasNext()) {
       final long t1 = System.currentTimeMillis();
@@ -866,11 +866,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       return;
     }
     ret.setAttribute("string", this.query);
-    if (this.resultSet != null) {
-      ret.setAttribute("results", Integer.toString(this.resultSet.size()));
-    } else {
-      ret.setAttribute("results", "0");
-    }
+    ret.setAttribute("results", Integer.toString(getCount()));
     ret.setAttribute("cached", Boolean.toString(this.cached));
     ret.setAttribute("etag", cacheETag);
 
@@ -971,11 +967,19 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @return A Cache key.
    */
   String getCacheKey() {
-    StringBuilder sb = new StringBuilder();
-    if (this.versioned) sb.append("versioned");
-    if (this.role != null) sb.append(this.role.toString());
-    if (this.entity != null) sb.append(this.entity.toString());
-    if (this.filter != null) sb.append(this.filter.getCacheKey());
+    final StringBuilder sb = new StringBuilder();
+    if (this.versioned) {
+      sb.append("versioned");
+    }
+    if (this.role != null) {
+      sb.append(this.role.toString());
+    }
+    if (this.entity != null) {
+      sb.append(this.entity.toString());
+    }
+    if (this.filter != null) {
+      sb.append(this.filter.getCacheKey());
+    }
     return sb.toString();
   }
 
@@ -998,4 +1002,12 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
   public static String getETag() {
     return cacheETag;
   }
+
+  public int getCount() {
+    if (this.resultSet != null) {
+      return this.resultSet.size();
+    } else {
+      return -1;
+    }
+  }
 }
-- 
GitLab