From 47494971026143197e6b55a749f9f730e9e488a0 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Fri, 11 Nov 2022 14:42:12 +0100
Subject: [PATCH] WIP: SELECT for GRPC API

---
 .../server/datatype/DoubleDatatype.java       |  2 +
 .../server/datatype/IntegerDatatype.java      |  2 +
 .../caosdb/server/datatype/TextDatatype.java  |  3 +
 .../server/grpc/CaosDBToGrpcConverters.java   | 74 ++++++++++++++++---
 4 files changed, 69 insertions(+), 12 deletions(-)

diff --git a/src/main/java/org/caosdb/server/datatype/DoubleDatatype.java b/src/main/java/org/caosdb/server/datatype/DoubleDatatype.java
index e9e25265..f3f17ace 100644
--- a/src/main/java/org/caosdb/server/datatype/DoubleDatatype.java
+++ b/src/main/java/org/caosdb/server/datatype/DoubleDatatype.java
@@ -34,6 +34,8 @@ public class DoubleDatatype extends AbstractDatatype {
     try {
       if (value instanceof GenericValue) {
         return parse(((GenericValue) value).toDatabaseString());
+      } else if (value instanceof CollectionValue) {
+        throw ServerMessages.DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES;
       } else {
         return parse(value.toString());
       }
diff --git a/src/main/java/org/caosdb/server/datatype/IntegerDatatype.java b/src/main/java/org/caosdb/server/datatype/IntegerDatatype.java
index 0b1116ed..f3a58a4a 100644
--- a/src/main/java/org/caosdb/server/datatype/IntegerDatatype.java
+++ b/src/main/java/org/caosdb/server/datatype/IntegerDatatype.java
@@ -33,6 +33,8 @@ public class IntegerDatatype extends AbstractDatatype {
     try {
       if (value instanceof GenericValue) {
         return new GenericValue(Long.parseLong(((GenericValue) value).toDatabaseString()));
+      } else if (value instanceof CollectionValue) {
+        throw ServerMessages.DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES;
       } else {
         return new GenericValue(Long.parseLong(value.toString()));
       }
diff --git a/src/main/java/org/caosdb/server/datatype/TextDatatype.java b/src/main/java/org/caosdb/server/datatype/TextDatatype.java
index af06ed6d..3b32fadc 100644
--- a/src/main/java/org/caosdb/server/datatype/TextDatatype.java
+++ b/src/main/java/org/caosdb/server/datatype/TextDatatype.java
@@ -23,6 +23,7 @@
 package org.caosdb.server.datatype;
 
 import org.caosdb.server.entity.Message;
+import org.caosdb.server.utils.ServerMessages;
 
 @DatatypeDefinition(name = "Text")
 public class TextDatatype extends AbstractDatatype {
@@ -31,6 +32,8 @@ public class TextDatatype extends AbstractDatatype {
   public SingleValue parseValue(final Object value) throws Message {
     if (value instanceof GenericValue) {
       return (GenericValue) value;
+    } else if (value instanceof CollectionValue) {
+      throw ServerMessages.DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES;
     }
     return new GenericValue(value.toString());
   }
diff --git a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
index af40f735..f9ba7b3c 100644
--- a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
+++ b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
@@ -616,29 +616,31 @@ public class CaosDBToGrpcConverters {
     }
     return result;
   }
-  
+
   private org.caosdb.api.entity.v1.Value.Builder getSelectedValue(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 "value":
-        if(e.hasValue()) {
-          result = convert(e.getValue());
+        if (e.hasValue()) {
+          return convert(e.getValue());
         }
         break;
       case "name":
         if (e.hasName()) {
           result.setScalarValue(convertStringValue(e.getName()));
+          return result;
         }
         break;
 
       case "id":
         result.setScalarValue(convertStringValue(e.getId().toString()));
-        break;
+        return result;
 
       case "description":
         if (e.hasDescription()) {
           result.setScalarValue(convertStringValue(e.getDescription()));
+          return result;
         }
         break;
 
@@ -646,18 +648,21 @@ public class CaosDBToGrpcConverters {
         if (e.hasUnit()) {
           final String unit = getStringUnit(e);
           result.setScalarValue(convertStringValue(unit));
+          return result;
         }
         break;
       case "datatype":
         if (e.hasDatatype()) {
           result.setScalarValue(convertStringValue(e.getDatatype().toString()));
+          return result;
         }
         break;
-
       case "path":
         if (e.hasFileProperties() && e.getFileProperties().hasPath()) {
           result.setScalarValue(convertStringValue(e.getFileProperties().getPath()));
+          return result;
         }
+        break;
       case "parent":
         if (e.hasParents()) {
           CollectionValues.Builder parents = CollectionValues.newBuilder();
@@ -665,12 +670,13 @@ public class CaosDBToGrpcConverters {
             parents.addValues(ScalarValue.newBuilder().setStringValue(p.getName()));
           }
           result.setListValues(parents);
+          return result;
         }
-
+        break;
       default:
         // selector for a normal property
+        List<org.caosdb.api.entity.v1.Value.Builder> results = new LinkedList<>();
         for (Property p : e.getProperties()) {
-          // TODO(tf) - handle multiple matching properties
           if (p.getName() != null && p.getName().equals(selector)) {
             if (s.getSubselection() == null) {
               // no subselection -> just return the actual value
@@ -680,41 +686,53 @@ public class CaosDBToGrpcConverters {
                 throw new TransactionException(m);
               }
 
-              result = convert(p.getValue());
+              results.add(convert(p.getValue()));
             } else {
               // with subselection, e.g. p1.unit, site.geolocation.longitude
               switch (s.getSubselection().getSelector()) {
                 case "name":
                   if (p.hasName()) {
+                    result = org.caosdb.api.entity.v1.Value.newBuilder();
                     result.setScalarValue(convertStringValue(p.getName()));
+                    results.add(result);
                   }
                   break;
 
                 case "id":
+                  result = org.caosdb.api.entity.v1.Value.newBuilder();
                   result.setScalarValue(convertStringValue(p.getId().toString()));
+                  results.add(result);
                   break;
 
                 case "description":
                   if (p.hasDescription()) {
+                    result = org.caosdb.api.entity.v1.Value.newBuilder();
                     result.setScalarValue(convertStringValue(p.getDescription()));
+                    results.add(result);
                   }
                   break;
 
                 case "unit":
                   final String unit = getStringUnit(p);
                   if (unit != null) {
+                    result = org.caosdb.api.entity.v1.Value.newBuilder();
                     result.setScalarValue(convertStringValue(unit));
+                    results.add(result);
                   }
                   break;
 
                 case "datatype":
                   if (p.hasDatatype()) {
+                    result = org.caosdb.api.entity.v1.Value.newBuilder();
                     result.setScalarValue(convertStringValue(p.getDatatype().toString()));
+                    results.add(result);
                   }
                   break;
                 case "value":
-                  if(p.hasValue()) {
+                  if (p.hasValue()) {
+                    result = org.caosdb.api.entity.v1.Value.newBuilder();
                     result = convert(p.getValue());
+                    results.add(result);
                   }
                   break;
                 default:
@@ -723,16 +741,48 @@ public class CaosDBToGrpcConverters {
 
                   if (v instanceof ReferenceValue) {
                     EntityInterface referenced_entity = ((ReferenceValue) v).getEntity();
-                    return getSelectedValue(s.getSubselection(), referenced_entity);
+                    result = getSelectedValue(s.getSubselection(), referenced_entity);
+                    results.add(result);
                   } else if (v instanceof CollectionValue) {
-                    // TODO(tf)
+                    for (Value i : (CollectionValue) v) {
+                      if (i instanceof ReferenceValue) {
+                        EntityInterface referenced_entity = ((ReferenceValue) i).getEntity();
+                        result = getSelectedValue(s.getSubselection(), referenced_entity);
+                        results.add(result);
+                      } else {
+                        // Non-reference scalar value
+                        result = getSelectedValue(s.getSubselection(), p);
+                        results.add(result);
+                      }
+                    }
+                  } else {
+                    // Actual sub-property
+                    result = getSelectedValue(s.getSubselection(), p);
+                    results.add(result);
                   }
                   break;
               }
             }
           }
         }
-        break;
+        if (results.size() > 1) {
+          // There have been multiple matching properties
+          CollectionValues.Builder values = CollectionValues.newBuilder();
+          for (org.caosdb.api.entity.v1.Value.Builder v : results) {
+            // Concatenate all found values to a list
+            if (v.hasScalarValue()) {
+              values.addValues(v.getScalarValueBuilder());
+            } else {
+              values.addAllValues(v.getListValuesBuilder().getValuesList());
+            }
+          }
+          result = org.caosdb.api.entity.v1.Value.newBuilder();
+          result.setListValues(values);
+        } else if (results.size() == 1) {
+          // There has been exactly one matching property
+          result = results.get(0);
+        }
+        return result;
     }
     return result;
   }
-- 
GitLab