Allow comparison operators also for integers

Resolves #218

Change-Id: I4317c348c7ecbeb9112578facf19f546cff89227
Reviewed-on: https://korap.ids-mannheim.de/gerrit/c/KorAP/Koral/+/9098
Reviewed-by: Marc Kupietz <kupietz@ids-mannheim.de>
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 c74e155..9f521a6 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
@@ -134,7 +134,7 @@
             String match = operatorNode.getText();
             term.put("match", "match:" + interpretMatchOperator(match));
 
-            if (!checkOperatorValueConformance(term)) {
+            if (!inferValueTypeAndCheckOperatorConformance(term)) {
                 ArrayList<Object> errors = new ArrayList<>(3);
                 errors.add(StatusCodes.INCOMPATIBLE_OPERATOR_AND_OPERAND);
                 errors.add("Operator "+match+" is not acceptable.");
@@ -168,7 +168,7 @@
             term.putAll(parseValue(dateNode));
             String match = dateOpNode.getText();
             term.put("match", "match:" + interpretMatchOperator(match));
-            if (!checkOperatorValueConformance(term)) {
+            if (!inferValueTypeAndCheckOperatorConformance(term)) {
                 requestMap = new HashMap<String, Object>();
                 return;
             }
@@ -295,10 +295,13 @@
 
     /**
      * Checks whether the combination of operator and value is legal
-     * (inequation operators <,>,<=,>= may only be used with dates).
+     * (inequation operators <,>,<=,>= may only be used with dates and integers).
      */
-    private boolean checkOperatorValueConformance (
+    private boolean inferValueTypeAndCheckOperatorConformance(
             Map<String, Object> term) {
+        if ((term.get("type") == null) && ((String) term.get("value")).matches("[0-9]+")) {
+            term.put("type", "type:integer");
+        }
         String match = (String) term.get("match");
         String type = (String) term.get("type");
         if (type == null || type.equals("type:regex")) {
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 aa5ae40..f460cd1 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
@@ -380,8 +380,7 @@
                 .asText());
         assertEquals("pubDate", res.at("/collection/operands/1/key").asText());
         assertEquals("2014", res.at("/collection/operands/1/value").asText());
-        assertTrue(res.at("/collection/operands/1/type")
-                .isMissingNode());
+        assertEquals("type:integer", res.at("/collection/operands/1/type").asText());
         assertEquals("match:eq", res.at("/collection/operands/1/match")
                 .asText());
         assertTrue(res.at("/warnings/0").isMissingNode());
@@ -672,6 +671,80 @@
 
 
     @Test
+    public void testIntegerConstraints() throws IOException {
+        collection = "nTok != 200";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("200", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:ne", res.at("/collection/match").asText());
+
+
+        collection = "nTok > 200";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("200", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:gt", res.at("/collection/match").asText());
+
+        collection = "nTok != 2000";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("2000", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:ne", res.at("/collection/match").asText());
+
+        collection = "nTok < 2000";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("2000", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:lt", res.at("/collection/match").asText());
+
+        collection = "nTok = 2000";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("2000", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:eq", res.at("/collection/match").asText());
+
+        collection = "nTok >= 2000";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("2000", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:geq", res.at("/collection/match").asText());
+
+        collection = "nTok <= 2000";
+        qs.setQuery(query, ql);
+        qs.setCollection(collection);
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("koral:doc", res.at("/collection/@type").asText());
+        assertEquals("nTok", res.at("/collection/key").asText());
+        assertEquals("2000", res.at("/collection/value").asText());
+        assertEquals("type:integer", res.at("/collection/type").asText());
+        assertEquals("match:leq", res.at("/collection/match").asText());
+    }
+
+    @Test
     public void testDateYear () throws JsonProcessingException, IOException {
         collection = "pubDate in 2000";
         qs.setQuery(query, ql);
@@ -690,7 +763,7 @@
         assertEquals("koral:doc", res.at("/collection/@type").asText());
         assertEquals("pubDate", res.at("/collection/key").asText());
         assertEquals("2000", res.at("/collection/value").asText());
-        assertTrue(res.at("/collection/type").isMissingNode());
+        assertEquals("type:integer", res.at("/collection/type").asText());
         assertEquals("match:eq", res.at("/collection/match").asText());
 
         collection = "pubDate since 2000";