From 094123970a0f106f4dd7fc9c851107d5ddef1642 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Fri, 21 Oct 2022 17:39:22 +0200
Subject: [PATCH] WIP: SELECT for GRPC API

---
 .../container/TransactionContainer.java       | 10 +++
 .../server/grpc/CaosDBToGrpcConverters.java   | 63 ++++++++++++++++++-
 .../grpc/EntityTransactionServiceImpl.java    |  9 +--
 .../caosdb/server/jobs/core/ExecuteQuery.java | 42 +++++--------
 4 files changed, 90 insertions(+), 34 deletions(-)

diff --git a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
index 289287c8..d3963455 100644
--- a/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
+++ b/src/main/java/org/caosdb/server/entity/container/TransactionContainer.java
@@ -34,6 +34,7 @@ import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.Message.MessageType;
 import org.caosdb.server.entity.xml.ToElementable;
 import org.caosdb.server.jobs.JobTarget;
+import org.caosdb.server.query.Query;
 import org.caosdb.server.utils.EntityStatus;
 import org.jdom2.Element;
 
@@ -120,6 +121,7 @@ public class TransactionContainer extends Container<EntityInterface>
   private HashMap<String, FileProperties> files = new HashMap<String, FileProperties>();
 
   private TransactionBenchmark benchmark;
+  private Query query;
 
   public void setFiles(final HashMap<String, FileProperties> files) {
     this.files = files;
@@ -183,4 +185,12 @@ public class TransactionContainer extends Container<EntityInterface>
       addMessage(new Message(MessageType.Error, m.getCode(), m.getDescription(), m.getBody()));
     }
   }
+
+  public void setQuery(Query query) {
+    this.query = query;
+  }
+
+  public Query getQuery() {
+    return query;
+  }
 }
diff --git a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
index 0494e348..867beae5 100644
--- a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
+++ b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
@@ -48,9 +48,11 @@ import org.caosdb.api.entity.v1.ScalarValue;
 import org.caosdb.api.entity.v1.SelectQueryColumn;
 import org.caosdb.api.entity.v1.SelectQueryHeader;
 import org.caosdb.api.entity.v1.SelectQueryResult;
+import org.caosdb.api.entity.v1.SelectQueryRow;
 import org.caosdb.api.entity.v1.SpecialValue;
 import org.caosdb.api.entity.v1.Version;
 import org.caosdb.datetime.DateTimeInterface;
+import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.datatype.AbstractCollectionDatatype;
 import org.caosdb.server.datatype.AbstractDatatype;
 import org.caosdb.server.datatype.BooleanDatatype;
@@ -79,6 +81,8 @@ import org.caosdb.server.entity.wrapper.Property;
 import org.caosdb.server.entity.xml.SerializeFieldStrategy;
 import org.caosdb.server.permissions.EntityACI;
 import org.caosdb.server.permissions.EntityPermission;
+import org.caosdb.server.query.Query;
+import org.caosdb.server.query.Query.Selection;
 
 public class CaosDBToGrpcConverters {
 
@@ -595,16 +599,69 @@ public class CaosDBToGrpcConverters {
 
   public org.caosdb.api.entity.v1.SelectQueryResult.Builder convertSelectResult(
       RetrieveContainer container) {
-    // TODO(tf)
     SelectQueryResult.Builder result = SelectQueryResult.newBuilder();
     result.setHeader(convertSelectQueryHeader(container));
+    for (EntityInterface e : container) {
+      result.addDataRows(convert(container.getQuery().getSelections(), e));
+    }
+    return result;
+  }
+
+  private SelectQueryRow.Builder convert(List<Selection> selections, EntityInterface e) {
+
+    SelectQueryRow.Builder result = SelectQueryRow.newBuilder();
+    for (Selection s : selections) {
+      org.caosdb.api.entity.v1.Value.Builder value = getValue(s, e);
+      result.addCells(value);
+    }
+    return result;
+  }
+
+  private org.caosdb.api.entity.v1.Value.Builder getValue(Selection s, EntityInterface e) {
+    org.caosdb.api.entity.v1.Value.Builder result = org.caosdb.api.entity.v1.Value.newBuilder();
+    String selector = s.getSelector();
+    switch (selector) {
+      case "name":
+        if (e.getName() != null) {
+          result.setScalarValue(ScalarValue.newBuilder().setStringValue(e.getName()));
+        }
+        break;
+
+      case "id":
+        result.setScalarValue(ScalarValue.newBuilder().setStringValue(e.getId().toString()));
+        break;
+
+      default:
+        // selector for a normal property
+        for (Property p : e.getProperties()) {
+          if (p.getName() != null && p.getName().equals(selector) && s.getSubselection() == null) {
+            try {
+              p.parseValue();
+            } catch (Message m) {
+              throw new TransactionException(m);
+            }
+            if (!p.hasValue()) {
+              continue;
+            } else if (p.getValue() instanceof CollectionValue) {
+
+            } else {
+              result.setScalarValue(
+                  ScalarValue.newBuilder().setStringValue(p.getValue().toString()));
+            }
+          }
+        }
+        break;
+    }
+    // TODO Auto-generated method stub
     return result;
   }
 
   private SelectQueryHeader.Builder convertSelectQueryHeader(RetrieveContainer container) {
     SelectQueryHeader.Builder result = SelectQueryHeader.newBuilder();
-    // TODO(tf)
-    result.addColumns(SelectQueryColumn.newBuilder().setName("col1"));
+    Query query = container.getQuery();
+    for (Selection s : query.getSelections()) {
+      result.addColumns(SelectQueryColumn.newBuilder().setName(s.toString()));
+    }
     return result;
   }
 }
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index 09ba156e..8835cb6e 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -60,6 +60,7 @@ import org.caosdb.server.entity.UpdateEntity;
 import org.caosdb.server.entity.container.RetrieveContainer;
 import org.caosdb.server.entity.container.WritableContainer;
 import org.caosdb.server.permissions.EntityPermission;
+import org.caosdb.server.query.Query;
 import org.caosdb.server.transaction.Retrieve;
 import org.caosdb.server.transaction.RetrieveACL;
 import org.caosdb.server.transaction.UpdateACL;
@@ -130,14 +131,14 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
 
     final Retrieve transaction = new Retrieve(container);
     transaction.execute();
-    if (container.getFlags().containsKey("query_count_result")) {
+    if (container.getQuery() != null && container.getQuery().getType() == Query.Type.COUNT) {
       // this was a count query
-      final int count = Integer.parseInt(container.getFlags().get("query_count_result"));
+      final int count = container.getQuery().getCount();
       builder
           .addResponsesBuilder()
           .setRetrieveResponse(RetrieveResponse.newBuilder().setCountResult(count));
-    } else if (container.getFlags().containsKey("query_select")
-        && "true".equals(container.getFlags().get("query_select"))) {
+    } else if (container.getQuery() != null
+        && container.getQuery().getType() == Query.Type.SELECT) {
       // this was a select query
       SelectQueryResult.Builder selectResult = caosdbToGrpc.convertSelectResult(container);
       builder
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 f584d365..352a7428 100644
--- a/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java
+++ b/src/main/java/org/caosdb/server/jobs/core/ExecuteQuery.java
@@ -31,7 +31,6 @@ 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.utils.EntityStatus;
 import org.caosdb.server.utils.ServerMessages;
 
 @JobAnnotation(flag = "query", stage = TransactionStage.INIT)
@@ -40,34 +39,23 @@ public class ExecuteQuery extends FlagJob {
   @Override
   protected void job(final String value) {
 
-    final Query queryInstance = new Query(value, getTransaction().getTransactor(), getContainer());
-    try {
-      if (value != null) {
+    if (value != null) {
+      final Query queryInstance =
+          new Query(value, getTransaction().getTransactor(), getContainer());
+      getContainer().setQuery(queryInstance);
+      try {
         queryInstance.execute(getTransaction().getAccess());
-      }
-    } catch (final ParsingException e) {
-      getContainer().addMessage(ServerMessages.QUERY_PARSING_ERROR);
-      getContainer().setStatus(EntityStatus.UNQUALIFIED);
-    } catch (final UnsupportedOperationException e) {
-      getContainer().addMessage(ServerMessages.QUERY_EXCEPTION);
-      getContainer().setStatus(EntityStatus.UNQUALIFIED);
-      getContainer().addMessage(new Message(MessageType.Info, (MessageCode) null, e.getMessage()));
-    }
-    getContainer().addMessage(queryInstance);
-    switch (queryInstance.getQuery().getType()) {
-      case COUNT:
+      } catch (final ParsingException e) {
+        getContainer().addError(ServerMessages.QUERY_PARSING_ERROR);
+      } catch (final UnsupportedOperationException e) {
+        getContainer().addError(ServerMessages.QUERY_EXCEPTION);
         getContainer()
-            .getFlags()
-            .put("query_count_result", Integer.toString(queryInstance.getCount()));
-        break;
-      case SELECT:
-        getContainer().getFlags().put("query_select", "true");
-
-      default:
-        break;
-    }
-    for (final EntityInterface entity : getContainer()) {
-      getTransaction().getSchedule().addAll(loadJobs(entity, getTransaction()));
+            .addMessage(new Message(MessageType.Info, (MessageCode) null, e.getMessage()));
+      }
+      getContainer().addMessage(queryInstance);
+      for (final EntityInterface entity : getContainer()) {
+        getTransaction().getSchedule().addAll(loadJobs(entity, getTransaction()));
+      }
     }
   }
 }
-- 
GitLab