From 39b6d02d555b878bf48ea89a1258f39f2e2f114b Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Thu, 13 Feb 2020 15:36:56 +0100
Subject: [PATCH] WIP: empty and null values

---
 .../java/caosdb/server/entity/Entity.java     |  6 +++-
 .../java/caosdb/server/query/CQLParser.g4     |  6 ++--
 .../java/caosdb/server/query/TestCQL.java     | 36 +++++++++++++------
 3 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/src/main/java/caosdb/server/entity/Entity.java b/src/main/java/caosdb/server/entity/Entity.java
index 19cd9307..f9713af2 100644
--- a/src/main/java/caosdb/server/entity/Entity.java
+++ b/src/main/java/caosdb/server/entity/Entity.java
@@ -799,8 +799,10 @@ public class Entity extends AbstractObservable implements EntityInterface {
 
         if (pe.getText() != null && pe.getTextTrim() != "") {
           vals.add(new GenericValue(pe.getTextTrim()));
-        } else {
+        } else if (pe.getAttribute("null") != null) {
           vals.add(null);
+        } else {
+          vals.add(new GenericValue(""));
         }
       } else if (pe.getName().equalsIgnoreCase("Property")) {
         // Parse sub elements which represent PROPERTIES of this
@@ -864,6 +866,8 @@ public class Entity extends AbstractObservable implements EntityInterface {
     // Parse VALUE.
     if (vals.size() != 0) {
       setValue(vals);
+    } else if (element.getAttribute("null") != null) {
+      setValue(null);
     } else if (element.getTextTrim() != null && !element.getTextTrim().equals("")) {
       setValue(new GenericValue(element.getTextTrim()));
     }
diff --git a/src/main/java/caosdb/server/query/CQLParser.g4 b/src/main/java/caosdb/server/query/CQLParser.g4
index a545871d..af981d6a 100644
--- a/src/main/java/caosdb/server/query/CQLParser.g4
+++ b/src/main/java/caosdb/server/query/CQLParser.g4
@@ -441,7 +441,7 @@ minmax returns [String agg]
 ;
 
 value returns [String str]
-:
+: 
 	number {$str = $text;}
 	| datetime {$str = $text;}
 	| atom {$str = $atom.ep.toString();}
@@ -483,7 +483,7 @@ single_quoted returns [Query.Pattern ep] locals [StringBuffer sb, int patternTyp
 		r = SINGLE_QUOTE_STAR {$sb.append($r.text); $patternType = Query.Pattern.TYPE_LIKE;}
 	|
 		s = ~SINGLE_QUOTE_END {$sb.append($s.text);}
-	)+?
+	)*?
 	SINGLE_QUOTE_END
 ;
 
@@ -503,6 +503,6 @@ double_quoted returns [Query.Pattern ep] locals [StringBuffer sb, int patternTyp
 		r = DOUBLE_QUOTE_STAR {$sb.append($r.text); $patternType = Query.Pattern.TYPE_LIKE;}
 	|
 		s = ~DOUBLE_QUOTE_END {$sb.append($s.text);}
-	)+?
+	)*?
 	DOUBLE_QUOTE_END
 ;
diff --git a/src/test/java/caosdb/server/query/TestCQL.java b/src/test/java/caosdb/server/query/TestCQL.java
index 6f311ad2..54d4339b 100644
--- a/src/test/java/caosdb/server/query/TestCQL.java
+++ b/src/test/java/caosdb/server/query/TestCQL.java
@@ -28,6 +28,15 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+
+import caosdb.server.CaosDBServer;
+import caosdb.server.database.access.Access;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.database.exceptions.TransactionException;
+import caosdb.server.query.CQLParser.CqContext;
+import caosdb.server.query.Query.Pattern;
+import caosdb.server.query.Query.QueryException;
+import caosdb.server.utils.Initialization;
 import java.io.IOException;
 import java.sql.SQLException;
 import java.util.LinkedList;
@@ -38,14 +47,6 @@ import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import caosdb.server.CaosDBServer;
-import caosdb.server.database.access.Access;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
-import caosdb.server.database.exceptions.TransactionException;
-import caosdb.server.query.CQLParser.CqContext;
-import caosdb.server.query.Query.Pattern;
-import caosdb.server.query.Query.QueryException;
-import caosdb.server.utils.Initialization;
 
 public class TestCQL {
 
@@ -235,6 +236,8 @@ public class TestCQL {
 
   String referenceByLikePattern = "FIND ENTITY WHICH IS REFERENCED BY *name*";
 
+  String emptyTextValue = "FIND ENTITY WITH prop=''";
+
   @Test
   public void testQuery1()
       throws InterruptedException, SQLException, ConnectionException, QueryException {
@@ -6219,6 +6222,7 @@ public class TestCQL {
     assertEquals("SAT(SimulationData/2016\\_single/2018-01-10/%)", storedAt.toString());
   }
 
+  @Test
   public void testFilePathInQuotes2() {
     CQLLexer lexer = new CQLLexer(CharStreams.fromString(query_filepath_quotes_2));
     final CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -6246,11 +6250,23 @@ public class TestCQL {
     final ParseTree satFilter = whichclause.getChild(1).getChild(0);
     assertEquals(2, satFilter.getChildCount());
     assertEquals("IS STORED AT", satFilter.getChild(0).getText());
-    assertEquals("'/SimulationData/2016_single/2018-01-10/**'", satFilter.getChild(1).getText());
+    assertEquals("/SimulationData/2016_single/2018-01-10/**", satFilter.getChild(1).getText());
 
     assertTrue(sfq.filter instanceof StoredAt);
     final StoredAt storedAt = (StoredAt) sfq.filter;
     assertTrue(storedAt.pattern_matching);
-    assertEquals("SAT(SimulationData/2016\\_single/2018-01-10/%%)", storedAt.toString());
+    assertEquals("SAT(SimulationData/2016\\_single/2018-01-10/%)", storedAt.toString());
+  }
+
+  @Test
+  public void testEmptyTextValue() {
+    CQLLexer lexer = new CQLLexer(CharStreams.fromString(emptyTextValue));
+    final CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+    final CQLParser parser = new CQLParser(tokens);
+    final CqContext sfq = parser.cq();
+
+    EntityFilterInterface pov = sfq.filter;
+    assertEquals("POV(prop,=,)", pov.toString());
   }
 }
-- 
GitLab