You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2023/05/12 17:25:32 UTC

[couchdb] branch nouveau-query-deserializer-tests created (now f74572775)

This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a change to branch nouveau-query-deserializer-tests
in repository https://gitbox.apache.org/repos/asf/couchdb.git


      at f74572775 add tests for QueryDeserializer

This branch includes the following new commits:

     new f74572775 add tests for QueryDeserializer

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 01/01: add tests for QueryDeserializer

Posted by rn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch nouveau-query-deserializer-tests
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit f74572775013fe34543d754d56ee23b3927fa2f0
Author: Robert Newson <rn...@apache.org>
AuthorDate: Fri May 12 18:24:18 2023 +0100

    add tests for QueryDeserializer
    
    this class is currently unreachable but might be a new way
    to specify the query in SearchRequest rather than expanding
    the string-based query syntax
---
 .../couchdb/nouveau/lucene9/QueryDeserializer.java | 56 ++++++++++++------
 .../nouveau/lucene9/QuerySerializationTest.java    | 67 +++++++++++++++++++++-
 2 files changed, 101 insertions(+), 22 deletions(-)

diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/QueryDeserializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/QueryDeserializer.java
index cc2cfc827..b0620e661 100644
--- a/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/QueryDeserializer.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/QueryDeserializer.java
@@ -50,19 +50,19 @@ public class QueryDeserializer extends StdDeserializer<Query> {
 
     private Query deserializeNode(final JsonParser parser, final DeserializationContext context, final JsonNode node)
             throws IOException, JsonProcessingException {
-        final String type = node.get("@type").asText();
+        final String type = get(parser, node, "@type").asText();
         switch (type) {
             case "term": {
-                final String field = node.get("field").asText();
-                final String text = node.get("text").asText();
+                final String field = get(parser, node, "field").asText();
+                final String text = get(parser, node, "text").asText();
                 return new TermQuery(new Term(field, text));
             }
             case "boolean": {
-                if (!node.get("clauses").isArray()) {
+                if (!get(parser, node, "clauses").isArray()) {
                     throw new JsonParseException(parser, "boolean clauses must be an array");
                 }
                 final BooleanQuery.Builder builder = new BooleanQuery.Builder();
-                final Iterator<JsonNode> it = node.get("clauses").elements();
+                final Iterator<JsonNode> it = get(parser, node, "clauses").elements();
                 while (it.hasNext()) {
                     final Query q = deserializeNode(parser, context, it.next());
                     builder.add(q, null);
@@ -70,38 +70,38 @@ public class QueryDeserializer extends StdDeserializer<Query> {
                 return builder.build();
             }
             case "wildcard": {
-                final String field = node.get("field").asText();
-                final String text = node.get("text").asText();
+                final String field = get(parser, node, "field").asText();
+                final String text = get(parser, node, "text").asText();
                 return new WildcardQuery(new Term(field, text));
             }
             case "phrase": {
-                final String field = node.get("field").asText();
-                if (!node.get("terms").isArray()) {
+                final String field = get(parser, node, "field").asText();
+                if (!get(parser, node, "terms").isArray()) {
                     throw new JsonParseException(parser, "phrase terms must be an array");
                 }
                 final PhraseQuery.Builder builder = new PhraseQuery.Builder();
-                final Iterator<JsonNode> it = node.get("terms").elements();
+                final Iterator<JsonNode> it = get(parser, node, "terms").elements();
                 while (it.hasNext()) {
                     builder.add(new Term(field, it.next().asText()));
                 }
-                builder.setSlop(node.get("slop").asInt());
+                builder.setSlop(getInt(parser, node, "slop", 0));
                 return builder.build();
             }
             case "prefix": {
-                final String field = node.get("field").asText();
-                final String text = node.get("text").asText();
+                final String field = get(parser, node, "field").asText();
+                final String text = get(parser, node, "text").asText();
                 return new PrefixQuery(new Term(field, text));
             }
             case "fuzzy": {
-                final String field = node.get("field").asText();
-                final String text = node.get("text").asText();
-                final int maxEdits = node.get("max_edits").asInt();
-                final int prefixLength = node.get("prefix_length").asInt();
+                final String field = get(parser, node, "field").asText();
+                final String text = get(parser, node, "text").asText();
+                final int maxEdits = getInt(parser, node, "max_edits", 2);
+                final int prefixLength = getInt(parser, node, "prefix_length", 0);
                 return new FuzzyQuery(new Term(field, text), maxEdits, prefixLength);
             }
             case "regexp": {
-                final String field = node.get("field").asText();
-                final String text = node.get("text").asText();
+                final String field = get(parser, node, "field").asText();
+                final String text = get(parser, node, "text").asText();
                 return new RegexpQuery(new Term(field, text));
             }
             case "term_range": {
@@ -113,4 +113,22 @@ public class QueryDeserializer extends StdDeserializer<Query> {
         }
         throw new JsonParseException(parser, type + " not a supported query type");
     }
+
+    private JsonNode get(final JsonParser parser, final JsonNode node, final String key) throws JsonParseException {
+        if (node.hasNonNull(key)) {
+            return node.get(key);
+        }
+        throw new JsonParseException(parser, key + " is required");
+    }
+
+    private int getInt(final JsonParser parser, final JsonNode node, final String key, final int defaultValue)
+            throws JsonParseException {
+        if (node.hasNonNull(key)) {
+            if (node.get(key).isInt()) {
+                return node.get(key).asInt();
+            }
+            throw new JsonParseException(parser, key + " must be an int");
+        }
+        return defaultValue;
+    }
 }
diff --git a/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/QuerySerializationTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/QuerySerializationTest.java
index 436023ca3..555495a7a 100644
--- a/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/QuerySerializationTest.java
+++ b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/QuerySerializationTest.java
@@ -14,23 +14,36 @@
 package org.apache.couchdb.nouveau.lucene9;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.FuzzyQuery;
+import org.apache.lucene.search.MatchAllDocsQuery;
 import org.apache.lucene.search.PhraseQuery;
+import org.apache.lucene.search.PrefixQuery;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.RegexpQuery;
 import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.WildcardQuery;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 public class QuerySerializationTest {
 
-    @Test
-    public void basicTest() throws Exception {
-        final ObjectMapper mapper = new ObjectMapper();
+    private static ObjectMapper mapper;
+
+    @BeforeAll
+    public static void setup() {
+        mapper = new ObjectMapper();
         mapper.registerModule(new Lucene9Module());
+    }
 
+    @Test
+    public void basicTest() throws Exception {
         final BooleanQuery.Builder builder = new BooleanQuery.Builder();
         builder.add(new TermQuery(new Term("foo", "bar")), Occur.MUST);
         builder.add(new TermQuery(new Term("foo", "bar")), Occur.MUST_NOT);
@@ -42,4 +55,52 @@ public class QuerySerializationTest {
                 "{\"@type\":\"boolean\",\"clauses\":[{\"query\":{\"@type\":\"term\",\"field\":\"foo\",\"term\":\"bar\"},\"occur\":\"must\"},{\"query\":{\"@type\":\"term\",\"field\":\"foo\",\"term\":\"bar\"},\"occur\":\"must_not\"},{\"query\":{\"@type\":\"term\",\"field\":\"foo\",\"term\":\"bar\"},\"occur\":\"should\"},{\"query\":{\"@type\":\"phrase\",\"field\":\"bar\",\"terms\":[\"foo\",\"bar\",\"baz\"],\"slop\":0},\"occur\":\"must\"}]}";
         assertThat(mapper.writeValueAsString(query)).isEqualTo(expected);
     }
+
+    @Test
+    public void deserializeJunk() throws Exception {
+        assertThrows(JsonParseException.class, () -> {
+            mapper.readValue("{}", Query.class);
+        });
+    }
+
+    @Test
+    public void deserializeTermQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"term\", \"field\":\"foo\", \"text\":\"bar\"}", Query.class))
+                .isEqualTo(new TermQuery(new Term("foo", "bar")));
+    }
+
+    @Test
+    public void deserializeWildcardQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"wildcard\", \"field\":\"foo\", \"text\":\"bar\"}", Query.class))
+                .isEqualTo(new WildcardQuery(new Term("foo", "bar")));
+    }
+
+    @Test
+    public void deserializePrefixQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"prefix\", \"field\":\"foo\", \"text\":\"bar\"}", Query.class))
+                .isEqualTo(new PrefixQuery(new Term("foo", "bar")));
+    }
+
+    @Test
+    public void deserializeRegexQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"regexp\", \"field\":\"foo\", \"text\":\"bar\"}", Query.class))
+                .isEqualTo(new RegexpQuery(new Term("foo", "bar")));
+    }
+
+    @Test
+    public void deserializeFuzzyQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"fuzzy\", \"field\":\"foo\", \"text\":\"bar\"}", Query.class))
+                .isEqualTo(new FuzzyQuery(new Term("foo", "bar")));
+    }
+
+    @Test
+    public void deserializePhraseQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"phrase\", \"field\":\"foo\", \"terms\": [\"bar\"]}", Query.class))
+                .isEqualTo(new PhraseQuery.Builder().add(new Term("foo", "bar")).build());
+    }
+
+    @Test
+    public void deserializeMatchAllQuery() throws Exception {
+        assertThat(mapper.readValue("{\"@type\":\"match_all\"}", Query.class)).isEqualTo(new MatchAllDocsQuery());
+    }
 }