- new date operators in collection queries ("in", "on", "since" instead "=", "<",...)
- disambiguation date/string in collection queries
- jsonify collection tests
diff --git a/src/test/java/CollectionQueryTreeTest.java b/src/test/java/CollectionQueryTreeTest.java
index ebe9cc7..acf09d7 100644
--- a/src/test/java/CollectionQueryTreeTest.java
+++ b/src/test/java/CollectionQueryTreeTest.java
@@ -1,301 +1,378 @@
 import static org.junit.Assert.*;
-import de.ids_mannheim.korap.query.serialize.CollectionQueryTree;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import de.ids_mannheim.korap.query.serialize.QuerySerializer;
 import de.ids_mannheim.korap.util.QueryException;
+
 import org.junit.Test;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 public class CollectionQueryTreeTest {
 
-	CollectionQueryTree cqt;
-	String map;
-	private String query;
-	private String expected;
+	String query = "foo";
+	String ql = "poliqarpplus";
+	String collection;
+	ArrayList<JsonNode> operands;
 
+	QuerySerializer qs = new QuerySerializer();
+	ObjectMapper mapper = new ObjectMapper();
+	JsonNode res;
+	
 	@Test
-	public void testSimple() throws QueryException {
-		query = "textClass=Sport";
-		//      String regex1 = "{@type=korap:filter, filter={@type=korap:doc, attribute=textClass, key=Sport, match=match:eq}}";
-		expected = "{@type=korap:doc, key=textClass, value=Sport, match=match:eq}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-
-		query = "textClass!=Sport";
-		//	      String regex1 = "{@type=korap:filter, filter={@type=korap:doc, attribute=textClass, key=Sport, match=match:eq}}";
-		expected = "{@type=korap:doc, key=textClass, value=Sport, match=match:ne}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testContext() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=politik";
+		String contextString = "http://ids-mannheim.de/ns/KorAP/json-ld/v0.2/context.jsonld";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals(contextString, res.get("@context").asText());
 	}
 	
 	@Test
-	public void testContains() throws QueryException {
-		query = "title~Mannheim";
-		expected = 
-			"{@type=korap:doc, key=title, value=Mannheim, match=match:contains}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testSimple() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=politik";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/key").asText());
+		assertEquals("politik", 		res.at("/collection/value").asText());
+		assertEquals("match:eq", 		res.at("/collection/match").asText());
 		
-		query = "title~\"IDS Mannheim\"";
-		expected = 
-			"{@type=korap:doc, key=title, value=IDS Mannheim, match=match:contains}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		collection = "textClass!=politik";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/key").asText());
+		assertEquals("politik", 		res.at("/collection/value").asText());
+		assertEquals("match:ne", 		res.at("/collection/match").asText());
 	}
 	
 	@Test
-	public void testTwoConjuncts() throws QueryException {
-		query = "textClass=Sport & year=2014";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-					"{@type=korap:doc, key=year, type=type:date, value=2014, match=match:eq}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-	}
-
-    //todo year type is not yet serialized!
-	@Test
-	public void testThreeConjuncts() throws QueryException {
-		query = "textClass=Sport & year=2014 & corpusID=WPD";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=year, type=type:date, value=2014, match=match:eq}," +
-						"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}" +
-					"]}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-	}
-	
-
-	@Test
-	public void testTwoDisjuncts() throws QueryException {
-		query = "textClass=Sport | year=2014";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:or, operands=[" +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-					"{@type=korap:doc, key=year, type=type:date, value=2014, match=match:eq}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testContains() throws QueryException, JsonProcessingException, IOException {
+		collection = "title~Mannheim";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("title", 			res.at("/collection/key").asText());
+		assertEquals("Mannheim", 		res.at("/collection/value").asText());
+		assertEquals("match:contains",  res.at("/collection/match").asText());
+		
+		collection = "title~\"IDS Mannheim\"";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("title",	 		res.at("/collection/key").asText());
+		assertEquals("IDS Mannheim",	res.at("/collection/value").asText());
+		assertEquals("match:contains",	res.at("/collection/match").asText());
 	}
 	
 	@Test
-	public void testThreeDisjuncts() throws QueryException {
-		query = "textClass=Sport | year=2014 | corpusID=WPD";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:or, operands=[" +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-					"{@type=korap:docGroup, operation=operation:or, operands=[" +
-						"{@type=korap:doc, key=year, type=type:date, value=2014, match=match:eq}," +
-						"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}" +
-					"]}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-	}
-
-
-	@Test
-	public void testMixed() throws QueryException {
-		query = "(textClass=Sport | textClass=ausland) & corpusID=WPD";
-		expected = 
-			
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:docGroup, operation=operation:or, operands=[" +
-						"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-						"{@type=korap:doc, key=textClass, value=ausland, match=match:eq}" +
-					"]}," +
-					"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testTwoConjuncts() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=Sport & pubDate in 2014";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/match").asText());
 		
-		query = "(textClass=Sport & textClass=ausland) & corpusID=WPD";
-		expected = 
-			
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-						"{@type=korap:doc, key=textClass, value=ausland, match=match:eq}" +
-					"]}," +
-					"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "(textClass=Sport & textClass=ausland) | (corpusID=WPD & author=White)";
-		expected = 
-			
-				"{@type=korap:docGroup, operation=operation:or, operands=[" +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-						"{@type=korap:doc, key=textClass, value=ausland, match=match:eq}" +
-					"]}," +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}," +
-						"{@type=korap:doc, key=author, value=White, match=match:eq}" +
-					"]}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "(textClass=Sport & textClass=ausland) | (corpusID=WPD & author=White & year=2010)";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:or, operands=[" +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-						"{@type=korap:doc, key=textClass, value=ausland, match=match:eq}" +
-					"]}," +
-					"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:doc, key=corpusID, value=WPD, match=match:eq}," +
-						"{@type=korap:docGroup, operation=operation:and, operands=[" +
-							"{@type=korap:doc, key=author, value=White, match=match:eq}," +
-							"{@type=korap:doc, key=year, type=type:date, value=2010, match=match:eq}" +
-						"]}" +
-					"]}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		collection = "textClass=Sport & pubDate=2014";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/value").asText());
+		assertEquals(true,				res.at("/collection/operands/1/type").isMissingNode());
+		assertEquals("match:eq",		res.at("/collection/operands/1/match").asText());
 	}
 
 	@Test
-	public void testDate() throws QueryException {
-		// search for pubDate between 1990 and 2010!
-		query = "1990<pubDate<2010";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:doc, key=pubDate, type=type:date, value=1990, match=match:gt}," +
-					"{@type=korap:doc, key=pubDate, type=type:date, value=2010, match=match:lt}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "pubDate>=1990";
-		expected = 
-				"{@type=korap:doc, key=pubDate, type=type:date, value=1990, match=match:geq}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "pubDate>=1990-05";
-		expected = 
-				"{@type=korap:doc, key=pubDate, type=type:date, value=1990-05, match=match:geq}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "pubDate>=1990-05-01";
-		expected = 
-				"{@type=korap:doc, key=pubDate, type=type:date, value=1990-05-01, match=match:geq}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testThreeConjuncts() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=Sport & pubDate in 2014 & corpusId=WPD";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:docGroup", 	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/operands/0/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/operands/0/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("corpusId", 		res.at("/collection/operands/1/operands/1/key").asText());
+		assertEquals("WPD",				res.at("/collection/operands/1/operands/1/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/1/match").asText());
 	}
-
 	@Test
-	public void testRegex() throws QueryException {
-		query = "author=/Go.*he/";
-		expected = 
-				"{@type=korap:doc, key=author, value=Go.*he, type=type:regex, match=match:eq}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testTwoDisjuncts() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=Sport | pubDate in 2014";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/match").asText());
 	}
 	
 	@Test
-	public void testContentFilter() throws QueryException {
-		query = "[base=Schwalbe]";
-		expected = 
-				"{@type=korap:token, wrap={@type=korap:term, layer=lemma, key=Schwalbe, match=match:eq}}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "[cnx/base=Schwalbe]";
-		expected = 
-				"{@type=korap:token, wrap={@type=korap:term, foundry=cnx, layer=lemma, key=Schwalbe, match=match:eq}}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "[base!=Schwalbe]";
-		expected = 
-				"{@type=korap:token, wrap={@type=korap:term, layer=lemma, key=Schwalbe, match=match:ne}}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
-		
-		query = "[base=Schwalbe] & [orth=Foul]";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-						"{@type=korap:token, wrap={@type=korap:term, layer=lemma, key=Schwalbe, match=match:eq}}," +
-						"{@type=korap:token, wrap={@type=korap:term, layer=orth, key=Foul, match=match:eq}}" +
-					"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testThreeDisjuncts() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=Sport | pubDate in 2014 | corpusId=WPD";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:docGroup", 	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/operands/0/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/operands/0/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("corpusId", 		res.at("/collection/operands/1/operands/1/key").asText());
+		assertEquals("WPD",				res.at("/collection/operands/1/operands/1/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/1/match").asText());
 	}
 	
 	@Test
-	public void testContentMetaMixed() throws QueryException {
-		query = "textClass=Sport & [base=Schwalbe]";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}," +
-					"{@type=korap:token, wrap={@type=korap:term, layer=lemma, key=Schwalbe, match=match:eq}}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+	public void testMixed() throws QueryException, JsonProcessingException, IOException {
+		collection = "textClass=Sport | (pubDate in 2014 & corpusId=WPD)";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:docGroup", 	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/operands/0/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/operands/0/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("corpusId", 		res.at("/collection/operands/1/operands/1/key").asText());
+		assertEquals("WPD",				res.at("/collection/operands/1/operands/1/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/1/match").asText());
 		
-		query = "[base=Schwalbe] & textClass=Sport";
-		expected = 
-				"{@type=korap:docGroup, operation=operation:and, operands=[" +
-					"{@type=korap:token, wrap={@type=korap:term, layer=lemma, key=Schwalbe, match=match:eq}}," +
-					"{@type=korap:doc, key=textClass, value=Sport, match=match:eq}" +
-				"]}";
-		cqt = new CollectionQueryTree();
-		cqt.process(query);
-		map = cqt.getRequestMap().get("collection").toString();
-		assertEquals(expected.replaceAll(" ", ""), map.replaceAll(" ", ""));
+		collection = "textClass=Sport | pubDate in 2014 & corpusId=WPD";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/@type").asText());
+		assertEquals("textClass", 		res.at("/collection/operands/0/key").asText());
+		assertEquals("Sport",			res.at("/collection/operands/0/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/0/match").asText());
+		assertEquals("korap:docGroup", 	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("pubDate",	 		res.at("/collection/operands/1/operands/0/key").asText());
+		assertEquals("2014",			res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("type:date",		res.at("/collection/operands/1/operands/0/type").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/0/match").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("corpusId", 		res.at("/collection/operands/1/operands/1/key").asText());
+		assertEquals("WPD",				res.at("/collection/operands/1/operands/1/value").asText());
+		assertEquals("match:eq",		res.at("/collection/operands/1/operands/1/match").asText());
+		
+		collection = "(textClass=Sport | pubDate in 2014) & corpusId=WPD";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/0/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operands/0/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/0/@type").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/1/@type").asText());
+		assertEquals("korap:doc",	 	res.at("/collection/operands/1/@type").asText());
+		
+		collection = "(textClass=Sport & pubDate in 2014) & corpusId=WPD";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/0/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/0/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/0/@type").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/1/@type").asText());
+		assertEquals("korap:doc",	 	res.at("/collection/operands/1/@type").asText());
+		
+		collection = "(textClass=Sport & textClass=ausland) | (corpusID=WPD & author=White)";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/0/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/0/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/0/@type").asText());
+		assertEquals("Sport",	 		res.at("/collection/operands/0/operands/0/value").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/1/@type").asText());
+		assertEquals("ausland",	 		res.at("/collection/operands/0/operands/1/value").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("WPD",		 		res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("White",	 		res.at("/collection/operands/1/operands/1/value").asText());
+		
+		collection = "(textClass=Sport & textClass=ausland) | (corpusID=WPD & author=White & pubDate in 2000)";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:docGroup", 	res.at("/collection/@type").asText());
+		assertEquals("operation:or",	res.at("/collection/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/0/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/0/operation").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operation").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/0/@type").asText());
+		assertEquals("Sport",	 		res.at("/collection/operands/0/operands/0/value").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/0/operands/1/@type").asText());
+		assertEquals("ausland",	 		res.at("/collection/operands/0/operands/1/value").asText());
+		assertEquals("korap:doc", 		res.at("/collection/operands/1/operands/0/@type").asText());
+		assertEquals("WPD",		 		res.at("/collection/operands/1/operands/0/value").asText());
+		assertEquals("korap:docGroup",	res.at("/collection/operands/1/operands/1/@type").asText());
+		assertEquals("operation:and",	res.at("/collection/operands/1/operands/1/operation").asText());
+		assertEquals("White",	 		res.at("/collection/operands/1/operands/1/operands/0/value").asText());
+		assertEquals("2000",	 		res.at("/collection/operands/1/operands/1/operands/1/value").asText());
 	}
 
+	@Test
+	public void testDateYear() throws QueryException, JsonProcessingException, IOException {
+		collection = "pubDate in 2000";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000",	 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:eq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate = 2000";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000",	 		res.at("/collection/value").asText());
+		assertEquals(true, 				res.at("/collection/type").isMissingNode());
+		assertEquals("match:eq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate since 2000";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000",	 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:geq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate until 2000";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000",	 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:leq", 		res.at("/collection/match").asText());
+	}
+	
+	@Test
+	public void testDateMonthDay() throws QueryException, JsonProcessingException, IOException {
+		collection = "pubDate in 2000-02";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000-02",	 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:eq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate = 2000-12";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000-12",	 		res.at("/collection/value").asText());
+		assertEquals(true, 				res.at("/collection/type").isMissingNode());
+		assertEquals("match:eq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate since 2000-02-01";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000-02-01", 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:geq", 		res.at("/collection/match").asText());
+		
+		collection = "pubDate until 2000-01-01";
+		qs.setQuery(query,ql);
+		qs.setCollection(collection);
+		res = mapper.readTree(qs.toJSON());
+		assertEquals("korap:doc", 		res.at("/collection/@type").asText());
+		assertEquals("pubDate", 		res.at("/collection/key").asText());
+		assertEquals("2000-01-01", 		res.at("/collection/value").asText());
+		assertEquals("type:date", 		res.at("/collection/type").asText());
+		assertEquals("match:leq", 		res.at("/collection/match").asText());
+	}
 }