Repository: calcite Updated Branches: refs/heads/master 6fbb67561 -> 53b6f454f
http://git-wip-us.apache.org/repos/asf/calcite/blob/53b6f454/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java ---------------------------------------------------------------------- diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java index 9a2f69e..5cdd82f 100644 --- a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java +++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java @@ -18,14 +18,24 @@ package org.apache.calcite.adapter.elasticsearch; import org.apache.calcite.util.Closer; +import org.apache.http.HttpEntity; import org.apache.http.HttpHost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.elasticsearch.client.RestClient; import org.elasticsearch.common.transport.TransportAddress; import org.junit.rules.ExternalResource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Objects; /** @@ -83,7 +93,71 @@ class EmbeddedElasticsearchPolicy extends ExternalResource { } /** - * Exposes Jackson API to be used for low-level ES. + * Creates index in elastic search given mapping. + * + * @param index index of the index + * @param mapping field and field type mapping + * @throws IOException if there is an error + */ + void createIndex(String index, Map<String, String> mapping) throws IOException { + Objects.requireNonNull(index, "index"); + Objects.requireNonNull(mapping, "mapping"); + + ObjectNode json = mapper().createObjectNode(); + for (Map.Entry<String, String> entry: mapping.entrySet()) { + json.set(entry.getKey(), json.objectNode().put("type", entry.getValue())); + } + + json = (ObjectNode) json.objectNode().set("properties", json); + json = (ObjectNode) json.objectNode().set(index, json); + json = (ObjectNode) json.objectNode().set("mappings", json); + + // create index and mapping + final HttpEntity entity = new StringEntity(mapper().writeValueAsString(json), + ContentType.APPLICATION_JSON); + restClient().performRequest("PUT", "/" + index, Collections.emptyMap(), entity); + } + + void insertDocument(String index, ObjectNode document) throws IOException { + Objects.requireNonNull(index, "index"); + Objects.requireNonNull(document, "document"); + String uri = String.format(Locale.ROOT, + "/%s/%s/?refresh", index, index); + StringEntity entity = new StringEntity(mapper().writeValueAsString(document), + ContentType.APPLICATION_JSON); + + restClient().performRequest("POST", uri, + Collections.emptyMap(), + entity); + } + + void insertBulk(String index, List<ObjectNode> documents) throws IOException { + Objects.requireNonNull(index, "index"); + Objects.requireNonNull(documents, "documents"); + + if (documents.isEmpty()) { + // nothing to process + return; + } + + List<String> bulk = new ArrayList<>(documents.size() * 2); + for (ObjectNode doc: documents) { + bulk.add("{\"index\": {} }"); // index/type will be derived from _bulk URI + bulk.add(mapper().writeValueAsString(doc)); + } + + final StringEntity entity = new StringEntity(String.join("\n", bulk) + "\n", + ContentType.APPLICATION_JSON); + + final String uri = String.format(Locale.ROOT, "/%s/%s/_bulk?refresh", index, index); + + restClient().performRequest("POST", uri, + Collections.emptyMap(), + entity); + } + + /** + * Exposes Jackson API to be used to parse search results. * @return existing instance of ObjectMapper */ ObjectMapper mapper() { http://git-wip-us.apache.org/repos/asf/calcite/blob/53b6f454/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ProjectionTest.java ---------------------------------------------------------------------- diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ProjectionTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ProjectionTest.java new file mode 100644 index 0000000..9830036 --- /dev/null +++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ProjectionTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.adapter.elasticsearch; + +import org.apache.calcite.jdbc.CalciteConnection; +import org.apache.calcite.schema.SchemaPlus; +import org.apache.calcite.schema.impl.ViewTable; +import org.apache.calcite.schema.impl.ViewTableMacro; +import org.apache.calcite.test.CalciteAssert; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableMap; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; + +/** + * Checks renaming of fields (also upper, lower cases) during projections + */ +public class ProjectionTest { + + @ClassRule + public static final EmbeddedElasticsearchPolicy NODE = EmbeddedElasticsearchPolicy.create(); + + private static final String NAME = "docs"; + + @BeforeClass + public static void setupInstance() throws Exception { + + final Map<String, String> mappings = ImmutableMap.of("A", "keyword", + "b", "keyword", "cCC", "keyword", "DDd", "keyword"); + + NODE.createIndex(NAME, mappings); + + String doc = "{'A': 'aa', 'b': 'bb', 'cCC': 'cc', 'DDd': 'dd'}".replace('\'', '"'); + NODE.insertDocument(NAME, (ObjectNode) NODE.mapper().readTree(doc)); + } + + private CalciteAssert.ConnectionFactory newConnectionFactory() { + return new CalciteAssert.ConnectionFactory() { + @Override public Connection createConnection() throws SQLException { + final Connection connection = DriverManager.getConnection("jdbc:calcite:"); + final SchemaPlus root = connection.unwrap(CalciteConnection.class).getRootSchema(); + + root.add("elastic", new ElasticsearchSchema(NODE.restClient(), NODE.mapper(), NAME)); + + // add calcite view programmatically + final String viewSql = String.format(Locale.ROOT, + "select cast(_MAP['A'] AS varchar(2)) AS \"a\", " + + " cast(_MAP['b'] AS varchar(2)) AS \"b\", " + + " cast(_MAP['cCC'] AS varchar(2)) AS \"c\", " + + " cast(_MAP['DDd'] AS varchar(2)) AS \"d\" " + + " from \"elastic\".\"%s\"", NAME); + + ViewTableMacro macro = ViewTable.viewMacro(root, viewSql, + Collections.singletonList("elastic"), Arrays.asList("elastic", "view"), false); + root.add("VIEW", macro); + + return connection; + } + }; + } + + @Test + public void projection() { + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from view") + .returns("a=aa; b=bb; c=cc; d=dd\n"); + } +} + +// End ProjectionTest.java http://git-wip-us.apache.org/repos/asf/calcite/blob/53b6f454/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/QueryBuildersTest.java ---------------------------------------------------------------------- diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/QueryBuildersTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/QueryBuildersTest.java new file mode 100644 index 0000000..7ae2c42 --- /dev/null +++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/QueryBuildersTest.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.adapter.elasticsearch; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.Test; + +import java.io.IOException; +import java.io.StringWriter; + +import static org.junit.Assert.assertEquals; + +/** + * Check that internal queries are correctly converted to ES search query (as JSON) + */ +public class QueryBuildersTest { + + private final ObjectMapper mapper = new ObjectMapper(); + + @Test + public void term() throws Exception { + assertEquals("{\"term\":{\"foo\":\"bar\"}}", + toJson(QueryBuilders.termQuery("foo", "bar"))); + assertEquals("{\"term\":{\"foo\":true}}", + toJson(QueryBuilders.termQuery("foo", true))); + assertEquals("{\"term\":{\"foo\":false}}", + toJson(QueryBuilders.termQuery("foo", false))); + assertEquals("{\"term\":{\"foo\":123}}", + toJson(QueryBuilders.termQuery("foo", (long) 123))); + assertEquals("{\"term\":{\"foo\":41}}", + toJson(QueryBuilders.termQuery("foo", (short) 41))); + assertEquals("{\"term\":{\"foo\":42.42}}", + toJson(QueryBuilders.termQuery("foo", 42.42D))); + assertEquals("{\"term\":{\"foo\":1.1}}", + toJson(QueryBuilders.termQuery("foo", 1.1F))); + } + + @Test + public void boolQuery() throws Exception { + QueryBuilders.QueryBuilder q1 = QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery("foo", "bar")); + + assertEquals("{\"bool\":{\"must\":{\"term\":{\"foo\":\"bar\"}}}}", + toJson(q1)); + + QueryBuilders.QueryBuilder q2 = QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery("f1", "v1")).must(QueryBuilders.termQuery("f2", "v2")); + + assertEquals("{\"bool\":{\"must\":[{\"term\":{\"f1\":\"v1\"}},{\"term\":{\"f2\":\"v2\"}}]}}", + toJson(q2) + ); + + QueryBuilders.QueryBuilder q3 = QueryBuilders.boolQuery() + .mustNot(QueryBuilders.termQuery("f1", "v1")); + + assertEquals("{\"bool\":{\"must_not\":{\"term\":{\"f1\":\"v1\"}}}}", + toJson(q3) + ); + + } + + @Test + public void exists() throws Exception { + assertEquals("{\"exists\":{\"field\":\"foo\"}}", + toJson(QueryBuilders.existsQuery("foo"))); + } + + @Test + public void range() throws Exception { + assertEquals("{\"range\":{\"f\":{\"lt\":0}}}", + toJson(QueryBuilders.rangeQuery("f").lt(0))); + assertEquals("{\"range\":{\"f\":{\"gt\":0}}}", + toJson(QueryBuilders.rangeQuery("f").gt(0))); + assertEquals("{\"range\":{\"f\":{\"gte\":0}}}", + toJson(QueryBuilders.rangeQuery("f").gte(0))); + assertEquals("{\"range\":{\"f\":{\"lte\":0}}}", + toJson(QueryBuilders.rangeQuery("f").lte(0))); + assertEquals("{\"range\":{\"f\":{\"gt\":1,\"lt\":2}}}", + toJson(QueryBuilders.rangeQuery("f").gt(1).lt(2))); + assertEquals("{\"range\":{\"f\":{\"gt\":11,\"lt\":0}}}", + toJson(QueryBuilders.rangeQuery("f").lt(0).gt(11))); + assertEquals("{\"range\":{\"f\":{\"gt\":1,\"lte\":2}}}", + toJson(QueryBuilders.rangeQuery("f").gt(1).lte(2))); + assertEquals("{\"range\":{\"f\":{\"gte\":1,\"lte\":\"zz\"}}}", + toJson(QueryBuilders.rangeQuery("f").gte(1).lte("zz"))); + assertEquals("{\"range\":{\"f\":{\"gte\":1}}}", + toJson(QueryBuilders.rangeQuery("f").gte(1))); + assertEquals("{\"range\":{\"f\":{\"gte\":\"zz\"}}}", + toJson(QueryBuilders.rangeQuery("f").gte("zz"))); + assertEquals("{\"range\":{\"f\":{\"gt\":\"a\",\"lt\":\"z\"}}}", + toJson(QueryBuilders.rangeQuery("f").gt("a").lt("z"))); + assertEquals("{\"range\":{\"f\":{\"gte\":3}}}", + toJson(QueryBuilders.rangeQuery("f").gt(1).gt(2).gte(3))); + assertEquals("{\"range\":{\"f\":{\"lte\":3}}}", + toJson(QueryBuilders.rangeQuery("f").lt(1).lt(2).lte(3))); + } + + private String toJson(QueryBuilders.QueryBuilder builder) throws IOException { + StringWriter writer = new StringWriter(); + JsonGenerator gen = mapper.getFactory().createGenerator(writer); + builder.writeJson(gen); + gen.flush(); + gen.close(); + return writer.toString(); + } +} + +// End QueryBuildersTest.java http://git-wip-us.apache.org/repos/asf/calcite/blob/53b6f454/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java ---------------------------------------------------------------------- diff --git a/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java b/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java index 68fc073..823d4f1 100644 --- a/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java +++ b/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java @@ -17,6 +17,7 @@ package org.apache.calcite.test; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; /** @@ -26,17 +27,19 @@ public class ElasticsearchChecker { private ElasticsearchChecker() {} + /** Returns a function that checks that a particular Elasticsearch pipeline is * generated to implement a query. * @param strings expected expressions * @return validation function */ public static Consumer<List> elasticsearchChecker(final String... strings) { + Objects.requireNonNull(strings, "strings"); return actual -> { Object[] actualArray = actual == null || actual.isEmpty() ? null - : ((List) actual.get(0)).toArray(); + : ((List) actual.get(0)).toArray(); CalciteAssert.assertArrayEqual("expected Elasticsearch query not found", strings, - actualArray); + actualArray); }; } }
