Introduced docGroupRef & added VC reference in collection query.

Change-Id: I4eb6f99279594ab825a3b1ebed9dedb076feb72b
diff --git a/Changes b/Changes
index b96ad94..f8944ae 100644
--- a/Changes
+++ b/Changes
@@ -1,65 +1,69 @@
+0.30 2018-07-31
+    - Introduced docGroupRef and added VC reference in collection query (margaretha)
+    - Fixed checking error in QuerySerializer (margaretha)
+
 0.29 2018-07-23
-  - Added check for errors on QuerySerializer object (diewald)
-  - Support verbatim string values in Poliqarp
+    - Added check for errors on QuerySerializer object (diewald)
+    - Support verbatim string values in Poliqarp
     (fixes #42; diewald)
-  - Fix support for verbatim string values in collection queries
+    - Fix support for verbatim string values in collection queries
     (diewald)
 
 0.28 2018-01-10
-	- Added some enums for koral:operation (margaretha)
-	- Fixed node serialization of Annis QL containing lemma (margaretha)
-	- Added serialization for Annis keyword "lemma" (margaretha)
-	- Removed version from FCSQL processor (margaretha)
-	- Fixed Annis regex bug regarding slash after foundry (margaretha)
-  - Fixed use of regular expressions in corpus queries
-    (margaretha, diewald)
-  - Fixed treatment of 'AND' and 'and' in vc serialization (diewald)
-	
+    - Added some enums for koral:operation (margaretha)
+    - Fixed node serialization of Annis QL containing lemma (margaretha)
+    - Added serialization for Annis keyword "lemma" (margaretha)
+    - Removed version from FCSQL processor (margaretha)
+    - Fixed Annis regex bug regarding slash after foundry (margaretha)
+    - Fixed use of regular expressions in corpus queries
+      (margaretha, diewald)
+    - Fixed treatment of 'AND' and 'and' in vc serialization (diewald)
+    
 0.27 2017-09-12
-	- Changed Cosmas2 wildcards serialization as regex (margaretha)  
-	- Fixed OP IN with classRefCheck.INCLUDES (margaretha)
-	- Implemented OP PV with exclusion (margaretha)
-	
+    - Changed Cosmas2 wildcards serialization as regex (margaretha)  
+    - Fixed OP IN with classRefCheck.INCLUDES (margaretha)
+    - Implemented OP PV with exclusion (margaretha)
+    
 0.26 2017-06-29
-	- Updated collection query grammar (margaretha)
-	- Updated maven dependency phase (margaretha)
+    - Updated collection query grammar (margaretha)
+    - Updated maven dependency phase (margaretha)
     - Fixed handling of non-necessary brackets in tokens (diewald)
     - Improved error handling (margaretha)
     - Added wrap to koral:span serialization (margaretha)
 
 0.25 2017-05-10
-	- Altered dominance and relation serialization (margaretha)
-	 
+    - Altered dominance and relation serialization (margaretha)
+     
 0.24 2017-05-03
-	- Fixed serialization of regexes for VCs (diewald)	
-	- Implemented exclusion in Cosmas2 IN operation (margaretha)
-	- Restructured test suite (margaretha)
-	
+    - Fixed serialization of regexes for VCs (diewald)    
+    - Implemented exclusion in Cosmas2 IN operation (margaretha)
+    - Restructured test suite (margaretha)
+    
 0.23 2016-10-27
-	- Added tests and comments for FCSQL (margaretha)
-	- Added quantifier for FCSQL QueryGroup (margaretha)
-	- Improved Poliqarp+ test suite (diewald)
-  - Removed redundant min serialization in repetitions (diewald)
+    - Added tests and comments for FCSQL (margaretha)
+    - Added quantifier for FCSQL QueryGroup (margaretha)
+    - Improved Poliqarp+ test suite (diewald)
+    - Removed redundant min serialization in repetitions (diewald)
 
 0.22 2016-06-15
     - Spans now always wrap terms (diewald)
-	- Cosmas-II "und", "oder", and "nicht" operations
-	  now serialize to unordered sequences (diewald)
-	- Cleanup POM (diewald)
-	- Fixed deserialization of unnecessary brackets
-	  around terms and termGroups in Poliqarp (diewald)
-	- Support for FCS 2.0 (margaretha)
-	- Fixed handling of escapes in regex
-	  (issue #21; diewald)
+    - Cosmas-II "und", "oder", and "nicht" operations
+      now serialize to unordered sequences (diewald)
+    - Cleanup POM (diewald)
+    - Fixed deserialization of unnecessary brackets
+      around terms and termGroups in Poliqarp (diewald)
+    - Support for FCS 2.0 (margaretha)
+    - Fixed handling of escapes in regex
+      (issue #21; diewald)
 
 0.21 2015-10-27
     - Improved meta query builder (hanl)
 
 0.2 2015-06-25
-        - Switch to "koral:" prefix (bingel)
-	- Coverage of KoralQuery 0.3
-	  (see http://korap.github.io/Koral/)
-          (bingel)
+    - Switch to "koral:" prefix (bingel)
+    - Coverage of KoralQuery 0.3
+      (see http://korap.github.io/Koral/)
+      (bingel)
 
 0.1 2015-02-10
-        - First version published to GitHub (bingel)
+    - First version published to GitHub (bingel)
diff --git a/pom.xml b/pom.xml
index 7cffd74..4661e94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
 	<groupId>de.ids_mannheim.korap</groupId>
 	<artifactId>Koral</artifactId>
-	<version>0.29</version>
+	<version>0.30</version>
 	<packaging>jar</packaging>
 	<name>Koral</name>
 	<url>http://maven.apache.org</url>
diff --git a/src/main/antlr/collection/CollectionQueryLexer.g4 b/src/main/antlr/collection/CollectionQueryLexer.g4
index 546bcc4..b286288 100644
--- a/src/main/antlr/collection/CollectionQueryLexer.g4
+++ b/src/main/antlr/collection/CollectionQueryLexer.g4
@@ -45,6 +45,7 @@
 UNTIL				: 'until';
 IN					: 'in';
 ON					: 'on';
+REF                 : 'referTo';
 WS 					: ( ' ' | '\t' | '\r' | '\n' )+ -> channel(HIDDEN);
 fragment NO_RE      : ~[ \t\/];
 fragment ALPHABET   : ~('\t' | ' ' | '/' | '*' | '?' | '+' | '{' | '}' | '[' | ']'
@@ -66,7 +67,4 @@
 WORD				: ALPHABET+;
 //WORD                : ALPHABET* ALPHA ALPHABET*;  // needs to have at least one alphabetical letter (non-numeric)
 
-REGEX     		     : SLASH .*? SLASH; 
-
-
-
+REGEX     		    : SLASH .*? SLASH; 
diff --git a/src/main/antlr/collection/CollectionQueryParser.g4 b/src/main/antlr/collection/CollectionQueryParser.g4
index 074f5aa..4999d25 100644
--- a/src/main/antlr/collection/CollectionQueryParser.g4
+++ b/src/main/antlr/collection/CollectionQueryParser.g4
@@ -27,15 +27,24 @@
 | ON
 ;
 
+vcOp
+: REF
+;
+
 operator
 :	(NEG? EQ) | LT | GT | LEQ | GEQ | TILDE | NEGTILDE;
 
 expr
 : constraint
 | dateConstraint
+| vcConstraint
 | token
 ;
 
+vcConstraint
+: vcOp vcName 
+;
+
 dateConstraint
 : field dateOp date
 //| date dateOp field dateOp date
@@ -45,6 +54,11 @@
 : field operator value flag?
 ;
 
+vcName
+: WORD
+| WORD SLASH WORD
+;
+
 token
 : LB (term|termGroup) RB
 ;
diff --git a/src/main/java/de/ids_mannheim/korap/query/object/KoralType.java b/src/main/java/de/ids_mannheim/korap/query/object/KoralType.java
index beb76ab..cfa0f97 100644
--- a/src/main/java/de/ids_mannheim/korap/query/object/KoralType.java
+++ b/src/main/java/de/ids_mannheim/korap/query/object/KoralType.java
@@ -10,7 +10,8 @@
     TERMGROUP("koral:termGroup"), TERM("koral:term"), TOKEN("koral:token"), 
     SPAN("koral:span"), GROUP("koral:group"), BOUNDARY("koral:boundary"), 
     RELATION("koral:relation"), DISTANCE("koral:distance"), REFERENCE(
-    "koral:reference"), DOCUMENT("koral:doc"), DOCUMENTGROUP("koral:docGroup"),
+    "koral:reference"), DOCUMENT("koral:doc"), DOCUMENT_GROUP("koral:docGroup"),
+    DOCUMENT_GROUP_REF("koral:docGroupRef"),
     COSMAS_DISTANCE("cosmas:distance");
 
     String value;
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryProcessor.java b/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryProcessor.java
index 76162d0..674fd92 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryProcessor.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryProcessor.java
@@ -112,7 +112,7 @@
             stackedObjects++;
         }
 
-        if (nodeCat.equals("constraint")) {
+        else if (nodeCat.equals("constraint")) {
             ParseTree fieldNode = getFirstChildWithCat(node, "field");
             String field = fieldNode.getChild(0).toStringTree(parser);
             ParseTree operatorNode = getFirstChildWithCat(node, "operator");
@@ -141,7 +141,7 @@
             putIntoSuperObject(term);
         }
 
-        if (nodeCat.equals("dateConstraint")) {
+        else if (nodeCat.equals("dateConstraint")) {
             ParseTree fieldNode = getFirstChildWithCat(node, "field");
             String field = fieldNode.getChild(0).toStringTree(parser);
             ParseTree dateOpNode = getFirstChildWithCat(node, "dateOp");
@@ -166,8 +166,25 @@
             putIntoSuperObject(term);
 
         }
-
-        if (nodeCat.equals("token")) {
+        
+        else if (nodeCat.equals("vcConstraint")) {
+            ParseTree vcOp = getFirstChildWithCat(node, "vcOp");
+            String vcOpStr = vcOp.getChild(0).toString();
+            if (!vcOpStr.equals("referTo")){
+                addError(StatusCodes.UNKNOWN_QUERY_ELEMENT,
+                        "Unknown vc operator: "+vcOpStr);
+            }
+            
+            ParseTree vcName = getFirstChildWithCat(node, "vcName");
+            String vcNameStr = "";
+            for (int i=0; i < vcName.getChildCount(); i++){
+                vcNameStr = vcNameStr+vcName.getChild(i).toString();
+            }
+            Map<String, Object> term = KoralObjectGenerator.makeDocGroupRef(vcNameStr);
+            putIntoSuperObject(term);
+        }
+        
+        else if (nodeCat.equals("token")) {
             Map<String, Object> token = KoralObjectGenerator
                     .makeToken();
             // handle negation
@@ -218,6 +235,7 @@
             visited.add(node.getChild(0));
             visited.add(node.getChild(2));
         }
+        
         objectsToPop.push(stackedObjects);
 
         /*
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
index 4c02a31..725203b 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
@@ -211,6 +211,10 @@
 				return true;
 			};
 		};
+		
+		if (!errors.isEmpty()){
+		    return true;
+		}
 		return false;
 	}
 	
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/util/KoralObjectGenerator.java b/src/main/java/de/ids_mannheim/korap/query/serialize/util/KoralObjectGenerator.java
index ee592d0..a02570e 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/util/KoralObjectGenerator.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/util/KoralObjectGenerator.java
@@ -62,11 +62,18 @@
         term.put("@type", KoralType.DOCUMENT.toString());
         return term;
     }
+    
+    public static Map<String, Object> makeDocGroupRef (String ref) {
+        Map<String, Object> term = new HashMap<String, Object>();
+        term.put("@type", KoralType.DOCUMENT_GROUP_REF.toString());
+        term.put("ref", ref);
+        return term;
+    }
 
 
     public static Map<String, Object> makeDocGroup (String relation) {
         Map<String, Object> term = new HashMap<String, Object>();
-        term.put("@type", KoralType.DOCUMENTGROUP.toString());
+        term.put("@type", KoralType.DOCUMENT_GROUP.toString());
         term.put("operation", "operation:" + relation);
         term.put("operands", new ArrayList<Object>());
         return term;
diff --git a/src/test/java/de/ids_mannheim/korap/query/test/collection/CollectionQueryProcessorTest.java b/src/test/java/de/ids_mannheim/korap/query/test/collection/CollectionQueryProcessorTest.java
index 75a1a91..76d3af0 100644
--- a/src/test/java/de/ids_mannheim/korap/query/test/collection/CollectionQueryProcessorTest.java
+++ b/src/test/java/de/ids_mannheim/korap/query/test/collection/CollectionQueryProcessorTest.java
@@ -1,5 +1,13 @@
 package de.ids_mannheim.korap.query.test.collection;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -7,27 +15,33 @@
 import de.ids_mannheim.korap.query.serialize.QuerySerializer;
 import de.ids_mannheim.korap.query.serialize.QueryUtils;
 
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-
 public class CollectionQueryProcessorTest {
 
-    String query = "foo";
-    String ql = "poliqarpplus";
-    String collection;
-    ArrayList<JsonNode> operands;
+    private String query = "foo";
+    private String ql = "poliqarpplus";
+    private String collection;
 
-    QuerySerializer qs = new QuerySerializer();
-    ObjectMapper mapper = new ObjectMapper();
-    JsonNode res;
+    public static final QuerySerializer qs = new QuerySerializer();
+    public static final ObjectMapper mapper = new ObjectMapper();
+    private JsonNode res;
 
-
+    @Test
+    public void testVCRef () throws IOException {
+        collection = "referTo vc-filename";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:docGroupRef", res.at("/collection/@type").asText());
+        assertEquals("vc-filename", res.at("/collection/ref").asText());
+        
+        collection = "referTo mickey/MyVC";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:docGroupRef", res.at("/collection/@type").asText());
+        assertEquals("mickey/MyVC", res.at("/collection/ref").asText());
+    }
+    
     @Test
     public void testContext () throws JsonProcessingException, IOException {
         collection = "textClass=politik";