http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/Elasticsearch5AdapterTest.java ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/Elasticsearch5AdapterTest.java b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/Elasticsearch5AdapterTest.java new file mode 100644 index 0000000..9dedbda --- /dev/null +++ b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/Elasticsearch5AdapterTest.java @@ -0,0 +1,405 @@ +/* + * 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.elasticsearch5; + +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 org.apache.calcite.test.ElasticsearchChecker; + +import com.google.common.io.LineProcessor; +import com.google.common.io.Resources; + +import org.elasticsearch.action.bulk.BulkItemResponse; +import org.elasticsearch.action.bulk.BulkRequestBuilder; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Locale; + +/** + * Set of tests for the Elasticsearch 5 adapter. + * + * <p>Uses a real instance via {@link EmbeddedElasticsearchPolicy}. + * The document source is a local {@code zips-mini.json} file + * (located in the classpath). + */ +public class Elasticsearch5AdapterTest { + + @ClassRule // init once for all tests + public static final EmbeddedElasticsearchPolicy POLICY = + EmbeddedElasticsearchPolicy.create(); + + private static final String ZIPS = "zips"; + + /** + * Used to create {@code zips} index and insert some data + * + * @throws Exception when ES instance setup failed + */ + @BeforeClass + public static void setupInstance() throws Exception { + // define mapping so fields are searchable (term query) + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("city").field("type", "string") + .field("index", "not_analyzed").endObject() + .startObject("state").field("type", "string") + .field("index", "not_analyzed").endObject() + .startObject("pop").field("type", "long").endObject() + .endObject() + .endObject(); + + // create index + POLICY.client().admin().indices() + .prepareCreate(ZIPS) + .addMapping(ZIPS, mapping) + .get(); + + BulkRequestBuilder bulk = POLICY.client().prepareBulk() + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + + // load records from file + Resources.readLines(Elasticsearch5AdapterTest.class.getResource("/zips-mini.json"), + StandardCharsets.UTF_8, new LineProcessor<Void>() { + @Override public boolean processLine(String line) throws IOException { + line = line.replaceAll("_id", "id"); // _id is a reserved attribute in ES + bulk.add(POLICY.client().prepareIndex(ZIPS, ZIPS) + .setSource(line.getBytes(StandardCharsets.UTF_8), XContentType.JSON)); + return true; + } + + @Override public Void getResult() { + return null; + } + }); + + if (bulk.numberOfActions() == 0) { + throw new IllegalStateException("No records to be indexed"); + } + + BulkResponse response = bulk.execute().get(); + + if (response.hasFailures()) { + throw new IllegalStateException( + String.format(Locale.getDefault(), "Failed to populate %s:\n%s", POLICY.httpAddress(), + Arrays.stream(response.getItems()).filter(BulkItemResponse::isFailed) + .map(BulkItemResponse::getFailureMessage).findFirst().orElse("<unknown>"))); + } + + } + + 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 Elasticsearch5Schema(POLICY.client(), ZIPS)); + + // add calcite view programmatically + final String viewSql = "select cast(_MAP['city'] AS varchar(20)) AS \"city\", " + + " cast(_MAP['loc'][0] AS float) AS \"longitude\",\n" + + " cast(_MAP['loc'][1] AS float) AS \"latitude\",\n" + + " cast(_MAP['pop'] AS integer) AS \"pop\", " + + " cast(_MAP['state'] AS varchar(2)) AS \"state\", " + + " cast(_MAP['id'] AS varchar(5)) AS \"id\" " + + "from \"elastic\".\"zips\""; + + ViewTableMacro macro = ViewTable.viewMacro(root, viewSql, + Collections.singletonList("elastic"), Arrays.asList("elastic", "view"), false); + root.add("ZIPS", macro); + + return connection; + } + }; + } + + private CalciteAssert.AssertThat calciteAssert() { + return CalciteAssert.that() + .with(newConnectionFactory()); + } + + /** + * Tests using calcite view + */ + @Test + public void view() { + calciteAssert() + .query("select * from zips where \"city\" = 'BROOKLYN'") + .returns("city=BROOKLYN; longitude=-73.956985; latitude=40.646694; " + + "pop=111396; state=NY; id=11226\n") + .returnsCount(1); + } + + @Test + public void emptyResult() { + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from zips limit 0") + .returnsCount(0); + + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" where _MAP['Foo'] = '_MISSING_'") + .returnsCount(0); + } + + @Test + public void basic() throws Exception { + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" where _MAP['city'] = 'BROOKLYN'") + .returnsCount(1); + + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" where" + + " _MAP['city'] in ('BROOKLYN', 'WASHINGTON')") + .returnsCount(2); + + // lower-case + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" where " + + "_MAP['city'] in ('brooklyn', 'Brooklyn', 'BROOK') ") + .returnsCount(0); + + // missing field + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" where _MAP['CITY'] = 'BROOKLYN'") + .returnsCount(0); + + // limit works + CalciteAssert.that() + .with(newConnectionFactory()) + .query("select * from \"elastic\".\"zips\" limit 42") + .returnsCount(42); + + } + + @Test public void testSort() { + final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + + " ElasticsearchSort(sort0=[$4], dir0=[ASC])\n" + + " ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], id=[CAST(ITEM($0, 'id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " ElasticsearchTableScan(table=[[elastic, zips]])"; + + calciteAssert() + .query("select * from zips order by \"state\"") + .returnsCount(10) + .explainContains(explain); + } + + @Test public void testSortLimit() { + final String sql = "select \"state\", \"pop\" from zips\n" + + "order by \"state\", \"pop\" offset 2 rows fetch next 3 rows only"; + calciteAssert() + .query(sql) + .returnsUnordered("state=AK; pop=32383", + "state=AL; pop=42124", + "state=AL; pop=43862") + .queryContains( + ElasticsearchChecker.elasticsearchChecker( + "\"_source\" : [\"state\", \"pop\"]", + "\"sort\": [ {\"state\": \"asc\"}, {\"pop\": \"asc\"}]", + "\"from\": 2", + "\"size\": 3")); + } + + + + @Test public void testOffsetLimit() { + final String sql = "select \"state\", \"id\" from zips\n" + + "offset 2 fetch next 3 rows only"; + calciteAssert() + .query(sql) + .runs() + .queryContains( + ElasticsearchChecker.elasticsearchChecker( + "\"from\": 2", + "\"size\": 3", + "\"_source\" : [\"state\", \"id\"]")); + } + + @Test public void testLimit() { + final String sql = "select \"state\", \"id\" from zips\n" + + "fetch next 3 rows only"; + + calciteAssert() + .query(sql) + .runs() + .queryContains( + ElasticsearchChecker.elasticsearchChecker( + "\"size\": 3", + "\"_source\" : [\"state\", \"id\"]")); + } + + @Test public void testFilterSort() { + final String sql = "select * from zips\n" + + "where \"state\" = 'CA' and \"pop\" >= 94000\n" + + "order by \"state\", \"pop\""; + final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + + " ElasticsearchSort(sort0=[$4], sort1=[$3], dir0=[ASC], dir1=[ASC])\n" + + " ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], id=[CAST(ITEM($0, 'id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " ElasticsearchFilter(condition=[AND(=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n" + + " ElasticsearchTableScan(table=[[elastic, zips]])\n\n"; + calciteAssert() + .query(sql) + .returnsOrdered("city=NORWALK; longitude=-118.081767; latitude=33.90564;" + + " pop=94188; state=CA; id=90650", + "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856;" + + " pop=96074; state=CA; id=90011", + "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177;" + + " pop=99568; state=CA; id=90201") + .queryContains( + ElasticsearchChecker.elasticsearchChecker("\"query\" : " + + "{\"constant_score\":{\"filter\":{\"bool\":" + + "{\"must\":[{\"term\":{\"state\":\"CA\"}}," + + "{\"range\":{\"pop\":{\"gte\":94000}}}]}}}}", + "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, " + + "\"latitude\":{\"script\":\"params._source.loc[1]\"}, " + + "\"city\":{\"script\": \"params._source.city\"}, " + + "\"pop\":{\"script\": \"params._source.pop\"}, " + + "\"state\":{\"script\": \"params._source.state\"}, " + + "\"id\":{\"script\": \"params._source.id\"}}", + "\"sort\": [ {\"state\": \"asc\"}, {\"pop\": \"asc\"}]")) + .explainContains(explain); + } + + @Test public void testFilterSortDesc() { + final String sql = "select * from zips\n" + + "where \"pop\" BETWEEN 95000 AND 100000\n" + + "order by \"state\" desc, \"pop\""; + calciteAssert() + .query(sql) + .limit(4) + .returnsOrdered( + "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856; pop=96074; state=CA; id=90011", + "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177; pop=99568; state=CA; id=90201"); + } + + @Test public void testFilterRedundant() { + final String sql = "select * from zips\n" + + "where \"state\" > 'CA' and \"state\" < 'AZ' and \"state\" = 'OK'"; + calciteAssert() + .query(sql) + .runs() + .queryContains( + ElasticsearchChecker.elasticsearchChecker("" + + "\"query\" : {\"constant_score\":{\"filter\":{\"bool\":" + + "{\"must\":[{\"term\":{\"state\":\"OK\"}}]}}}}", + "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, " + + "\"latitude\":{\"script\":\"params._source.loc[1]\"}, " + + "\"city\":{\"script\": \"params._source.city\"}, " + + "\"pop\":{\"script\": \"params._source.pop\"}, \"state\":{\"script\": \"params._source.state\"}, " + + "\"id\":{\"script\": \"params._source.id\"}}" + )); + } + + @Test public void testInPlan() { + final String[] searches = { + "\"query\" : {\"constant_score\":{\"filter\":{\"bool\":{\"should\":" + + "[{\"bool\":{\"must\":[{\"term\":{\"pop\":96074}}]}},{\"bool\":{\"must\":[{\"term\":" + + "{\"pop\":99568}}]}}]}}}}", + "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, " + + "\"latitude\":{\"script\":\"params._source.loc[1]\"}, " + + "\"city\":{\"script\": \"params._source.city\"}, " + + "\"pop\":{\"script\": \"params._source.pop\"}, " + + "\"state\":{\"script\": \"params._source.state\"}, " + + "\"id\":{\"script\": \"params._source.id\"}}" + }; + + calciteAssert() + .query("select * from zips where \"pop\" in (96074, 99568)") + .returnsUnordered( + "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177; pop=99568; state=CA; id=90201", + "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856; pop=96074; state=CA; id=90011" + ) + .queryContains(ElasticsearchChecker.elasticsearchChecker(searches)); + } + + @Test public void testZips() { + calciteAssert() + .query("select \"state\", \"city\" from zips") + .returnsCount(10); + } + + @Test public void testProject() { + final String sql = "select \"state\", \"city\", 0 as \"zero\"\n" + + "from zips\n" + + "order by \"state\", \"city\""; + + calciteAssert() + .query(sql) + .limit(2) + .returnsUnordered("state=AK; city=ANCHORAGE; zero=0", + "state=AK; city=FAIRBANKS; zero=0") + .queryContains( + ElasticsearchChecker.elasticsearchChecker("\"script_fields\": " + + "{\"zero\":{\"script\": \"0\"}, " + + "\"state\":{\"script\": \"params._source.state\"}, " + + "\"city\":{\"script\": \"params._source.city\"}}", + "\"sort\": [ {\"state\": \"asc\"}, {\"city\": \"asc\"}]")); + } + + @Test public void testFilter() { + final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + + " ElasticsearchProject(state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " ElasticsearchFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n" + + " ElasticsearchTableScan(table=[[elastic, zips]])"; + calciteAssert() + .query("select \"state\", \"city\" from zips where \"state\" = 'CA'") + .limit(3) + .returnsUnordered("state=CA; city=BELL GARDENS", + "state=CA; city=LOS ANGELES", + "state=CA; city=NORWALK") + .explainContains(explain); + } + + @Test public void testFilterReversed() { + calciteAssert() + .query("select \"state\", \"city\" from zips where 'WI' < \"state\" order by \"city\"") + .limit(2) + .returnsUnordered("state=WV; city=BECKLEY", + "state=WY; city=CHEYENNE"); + calciteAssert() + .query("select \"state\", \"city\" from zips where \"state\" > 'WI' order by \"city\"") + .limit(2) + .returnsUnordered("state=WV; city=BECKLEY", + "state=WY; city=CHEYENNE"); + } + +} + +// End Elasticsearch5AdapterTest.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchNode.java ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchNode.java b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchNode.java index d603d87..cd8af9a 100644 --- a/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchNode.java +++ b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchNode.java @@ -118,7 +118,7 @@ class EmbeddedElasticsearchNode implements AutoCloseable { } /** - * Exposes elastic + * Exposes an Elasticsearch * <a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html">transport client</a> * (use of HTTP client is preferred). * http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchPolicy.java ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchPolicy.java b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchPolicy.java new file mode 100644 index 0000000..6db2ddb --- /dev/null +++ b/elasticsearch5/src/test/java/org/apache/calcite/adapter/elasticsearch5/EmbeddedElasticsearchPolicy.java @@ -0,0 +1,103 @@ +/* + * 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.elasticsearch5; + +import com.google.common.base.Preconditions; + +import org.elasticsearch.client.Client; +import org.elasticsearch.common.transport.TransportAddress; + +import org.junit.rules.ExternalResource; + +/** + * Junit rule that is used to initialize a single Elasticsearch node for tests. + * + * <p>For performance reasons (node startup costs), + * the same instance is usually shared across multiple tests. + * + * <p>This rule should be used as follows: + * <pre> + * + * public class MyTest { + * @ClassRule + * public static final ElasticSearchRule RULE = ElasticSearchRule.create(); + * + * @BeforeClass + * public static void setup() { + * // ... populate instance + * } + * + * @Test + * public void myTest() { + * TransportAddress address = RULE.httpAddress(); + * // .... (connect to ES) + * } + * } + * </pre> + * + * @see ExternalResource + */ +class EmbeddedElasticsearchPolicy extends ExternalResource { + + private final EmbeddedElasticsearchNode node; + + private EmbeddedElasticsearchPolicy(EmbeddedElasticsearchNode resource) { + this.node = Preconditions.checkNotNull(resource, "resource"); + } + + @Override protected void before() throws Throwable { + node.start(); + } + + @Override protected void after() { + try { + node.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Factory method to create this rule. + * + * @return new rule instance to be used in unit tests + */ + public static EmbeddedElasticsearchPolicy create() { + return new EmbeddedElasticsearchPolicy(EmbeddedElasticsearchNode.create()); + } + + /** + * Exposes current ES transport client. + * @return running (and initialized) instance of ES node + */ + Client client() { + return node.client(); + } + + /** + * HTTP address for rest clients (can be ES native or any other). + * + * @return {@code HTTP} connection parameters + */ + TransportAddress httpAddress() { + return node.httpAddress(); + } + + +} + +// End EmbeddedElasticsearchPolicy.java http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java b/elasticsearch5/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java new file mode 100644 index 0000000..550c04c --- /dev/null +++ b/elasticsearch5/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java @@ -0,0 +1,53 @@ +/* + * 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.test; + +import com.google.common.base.Function; + +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Utility methods for Elasticsearch tests. + */ +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 Function<List, Void> elasticsearchChecker(final String... strings) { + return new Function<List, Void>() { + @Nullable + @Override public Void apply(@Nullable List actual) { + Object[] actualArray = actual == null || actual.isEmpty() ? null + : ((List) actual.get(0)).toArray(); + CalciteAssert.assertArrayEqual("expected Elasticsearch query not found", strings, + actualArray); + return null; + } + }; + } +} + +// End ElasticsearchChecker.java http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/resources/log4j2.xml ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/resources/log4j2.xml b/elasticsearch5/src/test/resources/log4j2.xml index b38aca2..0a12b9c 100644 --- a/elasticsearch5/src/test/resources/log4j2.xml +++ b/elasticsearch5/src/test/resources/log4j2.xml @@ -13,4 +13,4 @@ <AppenderRef ref="console" /> </Root> </Loggers> -</Configuration> \ No newline at end of file +</Configuration> http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/elasticsearch5/src/test/resources/zips-mini.json ---------------------------------------------------------------------- diff --git a/elasticsearch5/src/test/resources/zips-mini.json b/elasticsearch5/src/test/resources/zips-mini.json index d70eadc..858117a 100644 --- a/elasticsearch5/src/test/resources/zips-mini.json +++ b/elasticsearch5/src/test/resources/zips-mini.json @@ -146,4 +146,4 @@ { "_id" : "98310", "city" : "BREMERTON", "loc" : [ -122.629913, 47.601916 ], "pop" : 49057, "state" : "WA" } { "_id" : "99504", "city" : "ANCHORAGE", "loc" : [ -149.74467, 61.203696 ], "pop" : 32383, "state" : "AK" } { "_id" : "99709", "city" : "FAIRBANKS", "loc" : [ -147.846917, 64.85437 ], "pop" : 23238, "state" : "AK" } -{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" } \ No newline at end of file +{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" } http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java ---------------------------------------------------------------------- diff --git a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java index a4d8900..d6a45d9 100644 --- a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java +++ b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java @@ -22,7 +22,6 @@ import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.test.CalciteAssert; import org.apache.calcite.test.MongoAssertions; - import org.apache.calcite.util.Bug; import org.apache.calcite.util.Util; @@ -65,6 +64,8 @@ import java.util.Map; * Testing mongo adapter functionality. By default runs with * <a href="https://github.com/fakemongo/fongo">Fongo</a> unless {@code IT} maven profile is enabled * (via {@code $ mvn -Pit install}). + * + * @see MongoDatabasePolicy */ public class MongoAdapterTest implements SchemaFactory { @@ -75,27 +76,27 @@ public class MongoAdapterTest implements SchemaFactory { protected static final int ZIPS_SIZE = 149; @ClassRule - public static final MongoDatabaseRule RULE = MongoDatabaseRule.create(); + public static final MongoDatabasePolicy POLICY = MongoDatabasePolicy.create(); private static MongoSchema schema; @BeforeClass public static void setUp() throws Exception { - MongoDatabase database = RULE.database(); + MongoDatabase database = POLICY.database(); populate(database.getCollection("zips"), MongoAdapterTest.class.getResource("/zips-mini.json")); populate(database.getCollection("store"), FoodmartJson.class.getResource("/store.json")); populate(database.getCollection("warehouse"), - FoodmartJson.class.getResource("/warehouse.json")); + FoodmartJson.class.getResource("/warehouse.json")); // Manually insert data for data-time test. MongoCollection<BsonDocument> datatypes = database.getCollection("datatypes") - .withDocumentClass(BsonDocument.class); + .withDocumentClass(BsonDocument.class); if (datatypes.count() > 0) { datatypes.deleteMany(new BsonDocument()); } BsonDocument doc = new BsonDocument(); - Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse("2012-09-05"); + Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT).parse("2012-09-05"); doc.put("date", new BsonDateTime(date.getTime())); doc.put("value", new BsonInt32(1231)); doc.put("ownerId", new BsonString("531e7789e4b0853ddb861313")); @@ -105,7 +106,7 @@ public class MongoAdapterTest implements SchemaFactory { } private static void populate(MongoCollection<Document> collection, URL resource) - throws IOException { + throws IOException { Preconditions.checkNotNull(collection, "collection"); if (collection.count() > 0) { @@ -130,7 +131,7 @@ public class MongoAdapterTest implements SchemaFactory { * Returns always the same schema to avoid initialization costs. */ @Override public Schema create(SchemaPlus parentSchema, String name, - Map<String, Object> operand) { + Map<String, Object> operand) { return schema; } @@ -139,7 +140,7 @@ public class MongoAdapterTest implements SchemaFactory { model = model.replace(MongoSchemaFactory.class.getName(), MongoAdapterTest.class.getName()); return CalciteAssert.that() - .withModel(model); + .withModel(model); } private CalciteAssert.AssertThat assertModel(URL url) { @@ -151,53 +152,52 @@ public class MongoAdapterTest implements SchemaFactory { } } - @Test - public void testSort() { + @Test public void testSort() { assertModel(MODEL) - .query("select * from zips order by state") - .returnsCount(ZIPS_SIZE) - .explainContains("PLAN=MongoToEnumerableConverter\n" - + " MongoSort(sort0=[$4], dir0=[ASC])\n" - + " MongoProject(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " MongoTableScan(table=[[mongo_raw, zips]])"); + .query("select * from zips order by state") + .returnsCount(ZIPS_SIZE) + .explainContains("PLAN=MongoToEnumerableConverter\n" + + " MongoSort(sort0=[$4], dir0=[ASC])\n" + + " MongoProject(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " MongoTableScan(table=[[mongo_raw, zips]])"); } @Test public void testSortLimit() { assertModel(MODEL) - .query("select state, id from zips\n" - + "order by state, id offset 2 rows fetch next 3 rows only") - .returnsOrdered("STATE=AK; ID=99801", - "STATE=AL; ID=35215", - "STATE=AL; ID=35401") - .queryContains( - mongoChecker( - "{$project: {STATE: '$state', ID: '$_id'}}", - "{$sort: {STATE: 1, ID: 1}}", - "{$skip: 2}", - "{$limit: 3}")); + .query("select state, id from zips\n" + + "order by state, id offset 2 rows fetch next 3 rows only") + .returnsOrdered("STATE=AK; ID=99801", + "STATE=AL; ID=35215", + "STATE=AL; ID=35401") + .queryContains( + mongoChecker( + "{$project: {STATE: '$state', ID: '$_id'}}", + "{$sort: {STATE: 1, ID: 1}}", + "{$skip: 2}", + "{$limit: 3}")); } @Test public void testOffsetLimit() { assertModel(MODEL) - .query("select state, id from zips\n" - + "offset 2 fetch next 3 rows only") - .runs() - .queryContains( - mongoChecker( - "{$skip: 2}", - "{$limit: 3}", - "{$project: {STATE: '$state', ID: '$_id'}}")); + .query("select state, id from zips\n" + + "offset 2 fetch next 3 rows only") + .runs() + .queryContains( + mongoChecker( + "{$skip: 2}", + "{$limit: 3}", + "{$project: {STATE: '$state', ID: '$_id'}}")); } @Test public void testLimit() { assertModel(MODEL) - .query("select state, id from zips\n" - + "fetch next 3 rows only") - .runs() - .queryContains( - mongoChecker( - "{$limit: 3}", - "{$project: {STATE: '$state', ID: '$_id'}}")); + .query("select state, id from zips\n" + + "fetch next 3 rows only") + .runs() + .queryContains( + mongoChecker( + "{$limit: 3}", + "{$project: {STATE: '$state', ID: '$_id'}}")); } @Ignore @@ -205,76 +205,76 @@ public class MongoAdapterTest implements SchemaFactory { // LONGITUDE and LATITUDE are null because of CALCITE-194. Util.discard(Bug.CALCITE_194_FIXED); assertModel(MODEL) - .query("select * from zips\n" - + "where city = 'SPRINGFIELD' and id >= '70000'\n" - + "order by state, id") - .returns("" - + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=752; STATE=AR; ID=72157\n" - + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=1992; STATE=CO; ID=81073\n" - + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=5597; STATE=LA; ID=70462\n" - + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=32384; STATE=OR; ID=97477\n" - + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=27521; STATE=OR; ID=97478\n") - .queryContains( - mongoChecker( - "{\n" - + " $match: {\n" - + " city: \"SPRINGFIELD\",\n" - + " _id: {\n" - + " $gte: \"70000\"\n" - + " }\n" - + " }\n" - + "}", - "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}", - "{$sort: {STATE: 1, ID: 1}}")) - .explainContains("PLAN=MongoToEnumerableConverter\n" - + " MongoSort(sort0=[$4], sort1=[$5], dir0=[ASC], dir1=[ASC])\n" - + " MongoProject(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " MongoFilter(condition=[AND(=(CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'SPRINGFIELD'), >=(CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", '70000'))])\n" - + " MongoTableScan(table=[[mongo_raw, zips]])"); + .query("select * from zips\n" + + "where city = 'SPRINGFIELD' and id >= '70000'\n" + + "order by state, id") + .returns("" + + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=752; STATE=AR; ID=72157\n" + + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=1992; STATE=CO; ID=81073\n" + + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=5597; STATE=LA; ID=70462\n" + + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=32384; STATE=OR; ID=97477\n" + + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=27521; STATE=OR; ID=97478\n") + .queryContains( + mongoChecker( + "{\n" + + " $match: {\n" + + " city: \"SPRINGFIELD\",\n" + + " _id: {\n" + + " $gte: \"70000\"\n" + + " }\n" + + " }\n" + + "}", + "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}", + "{$sort: {STATE: 1, ID: 1}}")) + .explainContains("PLAN=MongoToEnumerableConverter\n" + + " MongoSort(sort0=[$4], sort1=[$5], dir0=[ASC], dir1=[ASC])\n" + + " MongoProject(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " MongoFilter(condition=[AND(=(CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'SPRINGFIELD'), >=(CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", '70000'))])\n" + + " MongoTableScan(table=[[mongo_raw, zips]])"); } @Test public void testFilterSortDesc() { assertModel(MODEL) - .query("select * from zips\n" - + "where pop BETWEEN 45000 AND 46000\n" - + "order by state desc, pop") - .limit(4) - .returnsOrdered( - "CITY=BECKLEY; LONGITUDE=null; LATITUDE=null; POP=45196; STATE=WV; ID=25801", - "CITY=ROCKERVILLE; LONGITUDE=null; LATITUDE=null; POP=45328; STATE=SD; ID=57701", - "CITY=PAWTUCKET; LONGITUDE=null; LATITUDE=null; POP=45442; STATE=RI; ID=02860", - "CITY=LAWTON; LONGITUDE=null; LATITUDE=null; POP=45542; STATE=OK; ID=73505"); + .query("select * from zips\n" + + "where pop BETWEEN 45000 AND 46000\n" + + "order by state desc, pop") + .limit(4) + .returnsOrdered( + "CITY=BECKLEY; LONGITUDE=null; LATITUDE=null; POP=45196; STATE=WV; ID=25801", + "CITY=ROCKERVILLE; LONGITUDE=null; LATITUDE=null; POP=45328; STATE=SD; ID=57701", + "CITY=PAWTUCKET; LONGITUDE=null; LATITUDE=null; POP=45442; STATE=RI; ID=02860", + "CITY=LAWTON; LONGITUDE=null; LATITUDE=null; POP=45542; STATE=OK; ID=73505"); } @Ignore("broken; [CALCITE-2115] is logged to fix it") @Test public void testUnionPlan() { assertModel(MODEL) - .query("select * from \"sales_fact_1997\"\n" - + "union all\n" - + "select * from \"sales_fact_1998\"") - .explainContains("PLAN=EnumerableUnion(all=[true])\n" - + " MongoToEnumerableConverter\n" - + " MongoProject(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n" - + " MongoTableScan(table=[[_foodmart, sales_fact_1997]])\n" - + " MongoToEnumerableConverter\n" - + " MongoProject(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n" - + " MongoTableScan(table=[[_foodmart, sales_fact_1998]])") - .limit(2) - .returns( - MongoAssertions.checkResultUnordered( - "product_id=337", "product_id=1512")); + .query("select * from \"sales_fact_1997\"\n" + + "union all\n" + + "select * from \"sales_fact_1998\"") + .explainContains("PLAN=EnumerableUnion(all=[true])\n" + + " MongoToEnumerableConverter\n" + + " MongoProject(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n" + + " MongoTableScan(table=[[_foodmart, sales_fact_1997]])\n" + + " MongoToEnumerableConverter\n" + + " MongoProject(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n" + + " MongoTableScan(table=[[_foodmart, sales_fact_1998]])") + .limit(2) + .returns( + MongoAssertions.checkResultUnordered( + "product_id=337", "product_id=1512")); } @Ignore( - "java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double") + "java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double") @Test public void testFilterUnionPlan() { assertModel(MODEL) - .query("select * from (\n" - + " select * from \"sales_fact_1997\"\n" - + " union all\n" - + " select * from \"sales_fact_1998\")\n" - + "where \"product_id\" = 1") - .runs(); + .query("select * from (\n" + + " select * from \"sales_fact_1997\"\n" + + " union all\n" + + " select * from \"sales_fact_1998\")\n" + + "where \"product_id\" = 1") + .runs(); } /** Tests that we don't generate multiple constraints on the same column. @@ -282,111 +282,111 @@ public class MongoAdapterTest implements SchemaFactory { * operators. */ @Test public void testFilterRedundant() { assertModel(MODEL) - .query( - "select * from zips where state > 'CA' and state < 'AZ' and state = 'OK'") - .runs() - .queryContains( - mongoChecker( - "{\n" - + " \"$match\": {\n" - + " \"state\": \"OK\"\n" - + " }\n" - + "}", - "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}")); + .query( + "select * from zips where state > 'CA' and state < 'AZ' and state = 'OK'") + .runs() + .queryContains( + mongoChecker( + "{\n" + + " \"$match\": {\n" + + " \"state\": \"OK\"\n" + + " }\n" + + "}", + "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}")); } @Test public void testSelectWhere() { assertModel(MODEL) - .query( - "select * from \"warehouse\" where \"warehouse_state_province\" = 'CA'") - .explainContains("PLAN=MongoToEnumerableConverter\n" - + " MongoProject(warehouse_id=[CAST(ITEM($0, 'warehouse_id')):DOUBLE], warehouse_state_province=[CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " MongoFilter(condition=[=(CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n" - + " MongoTableScan(table=[[mongo_raw, warehouse]])") - .returns( - MongoAssertions.checkResultUnordered( - "warehouse_id=6; warehouse_state_province=CA", - "warehouse_id=7; warehouse_state_province=CA", - "warehouse_id=14; warehouse_state_province=CA", - "warehouse_id=24; warehouse_state_province=CA")) - .queryContains( - // Per https://issues.apache.org/jira/browse/CALCITE-164, - // $match must occur before $project for good performance. - mongoChecker( - "{\n" - + " \"$match\": {\n" - + " \"warehouse_state_province\": \"CA\"\n" - + " }\n" - + "}", - "{$project: {warehouse_id: 1, warehouse_state_province: 1}}")); + .query( + "select * from \"warehouse\" where \"warehouse_state_province\" = 'CA'") + .explainContains("PLAN=MongoToEnumerableConverter\n" + + " MongoProject(warehouse_id=[CAST(ITEM($0, 'warehouse_id')):DOUBLE], warehouse_state_province=[CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " MongoFilter(condition=[=(CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n" + + " MongoTableScan(table=[[mongo_raw, warehouse]])") + .returns( + MongoAssertions.checkResultUnordered( + "warehouse_id=6; warehouse_state_province=CA", + "warehouse_id=7; warehouse_state_province=CA", + "warehouse_id=14; warehouse_state_province=CA", + "warehouse_id=24; warehouse_state_province=CA")) + .queryContains( + // Per https://issues.apache.org/jira/browse/CALCITE-164, + // $match must occur before $project for good performance. + mongoChecker( + "{\n" + + " \"$match\": {\n" + + " \"warehouse_state_province\": \"CA\"\n" + + " }\n" + + "}", + "{$project: {warehouse_id: 1, warehouse_state_province: 1}}")); } @Test public void testInPlan() { assertModel(MODEL) - .query("select \"store_id\", \"store_name\" from \"store\"\n" - + "where \"store_name\" in ('Store 1', 'Store 10', 'Store 11', 'Store 15', 'Store 16', 'Store 24', 'Store 3', 'Store 7')") - .returns( - MongoAssertions.checkResultUnordered( - "store_id=1; store_name=Store 1", - "store_id=3; store_name=Store 3", - "store_id=7; store_name=Store 7", - "store_id=10; store_name=Store 10", - "store_id=11; store_name=Store 11", - "store_id=15; store_name=Store 15", - "store_id=16; store_name=Store 16", - "store_id=24; store_name=Store 24")) - .queryContains( - mongoChecker( - "{\n" - + " \"$match\": {\n" - + " \"$or\": [\n" - + " {\n" - + " \"store_name\": \"Store 1\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 10\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 11\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 15\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 16\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 24\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 3\"\n" - + " },\n" - + " {\n" - + " \"store_name\": \"Store 7\"\n" - + " }\n" - + " ]\n" - + " }\n" - + "}", - "{$project: {store_id: 1, store_name: 1}}")); + .query("select \"store_id\", \"store_name\" from \"store\"\n" + + "where \"store_name\" in ('Store 1', 'Store 10', 'Store 11', 'Store 15', 'Store 16', 'Store 24', 'Store 3', 'Store 7')") + .returns( + MongoAssertions.checkResultUnordered( + "store_id=1; store_name=Store 1", + "store_id=3; store_name=Store 3", + "store_id=7; store_name=Store 7", + "store_id=10; store_name=Store 10", + "store_id=11; store_name=Store 11", + "store_id=15; store_name=Store 15", + "store_id=16; store_name=Store 16", + "store_id=24; store_name=Store 24")) + .queryContains( + mongoChecker( + "{\n" + + " \"$match\": {\n" + + " \"$or\": [\n" + + " {\n" + + " \"store_name\": \"Store 1\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 10\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 11\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 15\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 16\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 24\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 3\"\n" + + " },\n" + + " {\n" + + " \"store_name\": \"Store 7\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}", + "{$project: {store_id: 1, store_name: 1}}")); } /** Simple query based on the "mongo-zips" model. */ @Test public void testZips() { assertModel(MODEL) - .query("select state, city from zips") - .returnsCount(ZIPS_SIZE); + .query("select state, city from zips") + .returnsCount(ZIPS_SIZE); } @Test public void testCountGroupByEmpty() { assertModel(MODEL) - .query("select count(*) from zips") - .returns(String.format(Locale.getDefault(), "EXPR$0=%d\n", ZIPS_SIZE)) - .explainContains("PLAN=MongoToEnumerableConverter\n" - + " MongoAggregate(group=[{}], EXPR$0=[COUNT()])\n" - + " MongoTableScan(table=[[mongo_raw, zips]])") - .queryContains( - mongoChecker( - "{$group: {_id: {}, 'EXPR$0': {$sum: 1}}}")); + .query("select count(*) from zips") + .returns(String.format(Locale.ROOT, "EXPR$0=%d\n", ZIPS_SIZE)) + .explainContains("PLAN=MongoToEnumerableConverter\n" + + " MongoAggregate(group=[{}], EXPR$0=[COUNT()])\n" + + " MongoTableScan(table=[[mongo_raw, zips]])") + .queryContains( + mongoChecker( + "{$group: {_id: {}, 'EXPR$0': {$sum: 1}}}")); } @Test public void testCountGroupByEmptyMultiplyBy2() { @@ -394,197 +394,197 @@ public class MongoAdapterTest implements SchemaFactory { MongoAssertions.assumeRealMongoInstance(); assertModel(MODEL) - .query("select count(*)*2 from zips") - .returns(String.format(Locale.getDefault(), "EXPR$0=%d\n", ZIPS_SIZE * 2)) - .queryContains( - mongoChecker( - "{$group: {_id: {}, _0: {$sum: 1}}}", - "{$project: {'EXPR$0': {$multiply: ['$_0', {$literal: 2}]}}}")); + .query("select count(*)*2 from zips") + .returns(String.format(Locale.ROOT, "EXPR$0=%d\n", ZIPS_SIZE * 2)) + .queryContains( + mongoChecker( + "{$group: {_id: {}, _0: {$sum: 1}}}", + "{$project: {'EXPR$0': {$multiply: ['$_0', {$literal: 2}]}}}")); } @Test public void testGroupByOneColumnNotProjected() { assertModel(MODEL) - .query("select count(*) from zips group by state order by 1") - .limit(2) - .returnsUnordered("EXPR$0=2", - "EXPR$0=2") - .queryContains( - mongoChecker( - "{$project: {STATE: '$state'}}", - "{$group: {_id: '$STATE', 'EXPR$0': {$sum: 1}}}", - "{$project: {STATE: '$_id', 'EXPR$0': '$EXPR$0'}}", - "{$project: {'EXPR$0': 1}}", - "{$sort: {EXPR$0: 1}}")); + .query("select count(*) from zips group by state order by 1") + .limit(2) + .returnsUnordered("EXPR$0=2", + "EXPR$0=2") + .queryContains( + mongoChecker( + "{$project: {STATE: '$state'}}", + "{$group: {_id: '$STATE', 'EXPR$0': {$sum: 1}}}", + "{$project: {STATE: '$_id', 'EXPR$0': '$EXPR$0'}}", + "{$project: {'EXPR$0': 1}}", + "{$sort: {EXPR$0: 1}}")); } @Test public void testGroupByOneColumn() { assertModel(MODEL) - .query( - "select state, count(*) as c from zips group by state order by state") - .limit(3) - .returns("STATE=AK; C=3\nSTATE=AL; C=3\nSTATE=AR; C=3\n") - .queryContains( - mongoChecker( - "{$project: {STATE: '$state'}}", - "{$group: {_id: '$STATE', C: {$sum: 1}}}", - "{$project: {STATE: '$_id', C: '$C'}}", - "{$sort: {STATE: 1}}")); + .query( + "select state, count(*) as c from zips group by state order by state") + .limit(3) + .returns("STATE=AK; C=3\nSTATE=AL; C=3\nSTATE=AR; C=3\n") + .queryContains( + mongoChecker( + "{$project: {STATE: '$state'}}", + "{$group: {_id: '$STATE', C: {$sum: 1}}}", + "{$project: {STATE: '$_id', C: '$C'}}", + "{$sort: {STATE: 1}}")); } @Test public void testGroupByOneColumnReversed() { // Note extra $project compared to testGroupByOneColumn. assertModel(MODEL) - .query( - "select count(*) as c, state from zips group by state order by state") - .limit(2) - .returns("C=3; STATE=AK\nC=3; STATE=AL\n") - .queryContains( - mongoChecker( - "{$project: {STATE: '$state'}}", - "{$group: {_id: '$STATE', C: {$sum: 1}}}", - "{$project: {STATE: '$_id', C: '$C'}}", - "{$project: {C: 1, STATE: 1}}", - "{$sort: {STATE: 1}}")); + .query( + "select count(*) as c, state from zips group by state order by state") + .limit(2) + .returns("C=3; STATE=AK\nC=3; STATE=AL\n") + .queryContains( + mongoChecker( + "{$project: {STATE: '$state'}}", + "{$group: {_id: '$STATE', C: {$sum: 1}}}", + "{$project: {STATE: '$_id', C: '$C'}}", + "{$project: {C: 1, STATE: 1}}", + "{$sort: {STATE: 1}}")); } @Test public void testGroupByAvg() { assertModel(MODEL) - .query( - "select state, avg(pop) as a from zips group by state order by state") - .limit(2) - .returns("STATE=AK; A=26856\nSTATE=AL; A=43383\n") - .queryContains( - mongoChecker( - "{$project: {POP: '$pop', STATE: '$state'}}", - "{$group: {_id: '$STATE', A: {$avg: '$POP'}}}", - "{$project: {STATE: '$_id', A: '$A'}}", - "{$sort: {STATE: 1}}")); + .query( + "select state, avg(pop) as a from zips group by state order by state") + .limit(2) + .returns("STATE=AK; A=26856\nSTATE=AL; A=43383\n") + .queryContains( + mongoChecker( + "{$project: {POP: '$pop', STATE: '$state'}}", + "{$group: {_id: '$STATE', A: {$avg: '$POP'}}}", + "{$project: {STATE: '$_id', A: '$A'}}", + "{$sort: {STATE: 1}}")); } @Test public void testGroupByAvgSumCount() { // This operation not supported by fongo: https://github.com/fakemongo/fongo/issues/152 MongoAssertions.assumeRealMongoInstance(); assertModel(MODEL) - .query( - "select state, avg(pop) as a, sum(pop) as s, count(pop) as c from zips group by state order by state") - .limit(2) - .returns("STATE=AK; A=26856; S=80568; C=3\n" - + "STATE=AL; A=43383; S=130151; C=3\n") - .queryContains( - mongoChecker( - "{$project: {POP: '$pop', STATE: '$state'}}", - "{$group: {_id: '$STATE', _1: {$sum: '$POP'}, _2: {$sum: {$cond: [ {$eq: ['POP', null]}, 0, 1]}}}}", - "{$project: {STATE: '$_id', _1: '$_1', _2: '$_2'}}", - "{$sort: {STATE: 1}}", - "{$project: {STATE: 1, A: {$divide: [{$cond:[{$eq: ['$_2', {$literal: 0}]},null,'$_1']}, '$_2']}, S: {$cond:[{$eq: ['$_2', {$literal: 0}]},null,'$_1']}, C: '$_2'}}")); + .query( + "select state, avg(pop) as a, sum(pop) as s, count(pop) as c from zips group by state order by state") + .limit(2) + .returns("STATE=AK; A=26856; S=80568; C=3\n" + + "STATE=AL; A=43383; S=130151; C=3\n") + .queryContains( + mongoChecker( + "{$project: {POP: '$pop', STATE: '$state'}}", + "{$group: {_id: '$STATE', _1: {$sum: '$POP'}, _2: {$sum: {$cond: [ {$eq: ['POP', null]}, 0, 1]}}}}", + "{$project: {STATE: '$_id', _1: '$_1', _2: '$_2'}}", + "{$sort: {STATE: 1}}", + "{$project: {STATE: 1, A: {$divide: [{$cond:[{$eq: ['$_2', {$literal: 0}]},null,'$_1']}, '$_2']}, S: {$cond:[{$eq: ['$_2', {$literal: 0}]},null,'$_1']}, C: '$_2'}}")); } @Test public void testGroupByHaving() { assertModel(MODEL) - .query("select state, count(*) as c from zips\n" - + "group by state having count(*) > 2 order by state") - .returnsCount(47) - .queryContains( - mongoChecker( - "{$project: {STATE: '$state'}}", - "{$group: {_id: '$STATE', C: {$sum: 1}}}", - "{$project: {STATE: '$_id', C: '$C'}}", - "{\n" - + " \"$match\": {\n" - + " \"C\": {\n" - + " \"$gt\": 2\n" - + " }\n" - + " }\n" - + "}", - "{$sort: {STATE: 1}}")); + .query("select state, count(*) as c from zips\n" + + "group by state having count(*) > 2 order by state") + .returnsCount(47) + .queryContains( + mongoChecker( + "{$project: {STATE: '$state'}}", + "{$group: {_id: '$STATE', C: {$sum: 1}}}", + "{$project: {STATE: '$_id', C: '$C'}}", + "{\n" + + " \"$match\": {\n" + + " \"C\": {\n" + + " \"$gt\": 2\n" + + " }\n" + + " }\n" + + "}", + "{$sort: {STATE: 1}}")); } @Ignore("https://issues.apache.org/jira/browse/CALCITE-270") @Test public void testGroupByHaving2() { assertModel(MODEL) - .query("select state, count(*) as c from zips\n" - + "group by state having sum(pop) > 12000000") - .returns("STATE=NY; C=1596\n" - + "STATE=TX; C=1676\n" - + "STATE=FL; C=826\n" - + "STATE=CA; C=1523\n") - .queryContains( - mongoChecker( - "{$project: {STATE: '$state', POP: '$pop'}}", - "{$group: {_id: '$STATE', C: {$sum: 1}, _2: {$sum: '$POP'}}}", - "{$project: {STATE: '$_id', C: '$C', _2: '$_2'}}", - "{\n" - + " $match: {\n" - + " _2: {\n" - + " $gt: 12000000\n" - + " }\n" - + " }\n" - + "}", - "{$project: {STATE: 1, C: 1}}")); + .query("select state, count(*) as c from zips\n" + + "group by state having sum(pop) > 12000000") + .returns("STATE=NY; C=1596\n" + + "STATE=TX; C=1676\n" + + "STATE=FL; C=826\n" + + "STATE=CA; C=1523\n") + .queryContains( + mongoChecker( + "{$project: {STATE: '$state', POP: '$pop'}}", + "{$group: {_id: '$STATE', C: {$sum: 1}, _2: {$sum: '$POP'}}}", + "{$project: {STATE: '$_id', C: '$C', _2: '$_2'}}", + "{\n" + + " $match: {\n" + + " _2: {\n" + + " $gt: 12000000\n" + + " }\n" + + " }\n" + + "}", + "{$project: {STATE: 1, C: 1}}")); } @Test public void testGroupByMinMaxSum() { assertModel(MODEL) - .query("select count(*) as c, state,\n" - + " min(pop) as min_pop, max(pop) as max_pop, sum(pop) as sum_pop\n" - + "from zips group by state order by state") - .limit(2) - .returns("C=3; STATE=AK; MIN_POP=23238; MAX_POP=32383; SUM_POP=80568\n" - + "C=3; STATE=AL; MIN_POP=42124; MAX_POP=44165; SUM_POP=130151\n") - .queryContains( - mongoChecker( - "{$project: {POP: '$pop', STATE: '$state'}}", - "{$group: {_id: '$STATE', C: {$sum: 1}, MIN_POP: {$min: '$POP'}, MAX_POP: {$max: '$POP'}, SUM_POP: {$sum: '$POP'}}}", - "{$project: {STATE: '$_id', C: '$C', MIN_POP: '$MIN_POP', MAX_POP: '$MAX_POP', SUM_POP: '$SUM_POP'}}", - "{$project: {C: 1, STATE: 1, MIN_POP: 1, MAX_POP: 1, SUM_POP: 1}}", - "{$sort: {STATE: 1}}")); + .query("select count(*) as c, state,\n" + + " min(pop) as min_pop, max(pop) as max_pop, sum(pop) as sum_pop\n" + + "from zips group by state order by state") + .limit(2) + .returns("C=3; STATE=AK; MIN_POP=23238; MAX_POP=32383; SUM_POP=80568\n" + + "C=3; STATE=AL; MIN_POP=42124; MAX_POP=44165; SUM_POP=130151\n") + .queryContains( + mongoChecker( + "{$project: {POP: '$pop', STATE: '$state'}}", + "{$group: {_id: '$STATE', C: {$sum: 1}, MIN_POP: {$min: '$POP'}, MAX_POP: {$max: '$POP'}, SUM_POP: {$sum: '$POP'}}}", + "{$project: {STATE: '$_id', C: '$C', MIN_POP: '$MIN_POP', MAX_POP: '$MAX_POP', SUM_POP: '$SUM_POP'}}", + "{$project: {C: 1, STATE: 1, MIN_POP: 1, MAX_POP: 1, SUM_POP: 1}}", + "{$sort: {STATE: 1}}")); } @Test public void testGroupComposite() { assertModel(MODEL) - .query("select count(*) as c, state, city from zips\n" - + "group by state, city\n" - + "order by c desc, city\n" - + "limit 2") - .returns("C=1; STATE=SD; CITY=ABERDEEN\n" - + "C=1; STATE=SC; CITY=AIKEN\n") - .queryContains( - mongoChecker( - "{$project: {CITY: '$city', STATE: '$state'}}", - "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}, C: {$sum: 1}}}", - "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE', C: '$C'}}", - "{$sort: {C: -1, CITY: 1}}", - "{$limit: 2}", - "{$project: {C: 1, STATE: 1, CITY: 1}}")); + .query("select count(*) as c, state, city from zips\n" + + "group by state, city\n" + + "order by c desc, city\n" + + "limit 2") + .returns("C=1; STATE=SD; CITY=ABERDEEN\n" + + "C=1; STATE=SC; CITY=AIKEN\n") + .queryContains( + mongoChecker( + "{$project: {CITY: '$city', STATE: '$state'}}", + "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}, C: {$sum: 1}}}", + "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE', C: '$C'}}", + "{$sort: {C: -1, CITY: 1}}", + "{$limit: 2}", + "{$project: {C: 1, STATE: 1, CITY: 1}}")); } @Ignore("broken; [CALCITE-2115] is logged to fix it") @Test public void testDistinctCount() { assertModel(MODEL) - .query("select state, count(distinct city) as cdc from zips\n" - + "where state in ('CA', 'TX') group by state order by state") - .returns("STATE=CA; CDC=1072\n" - + "STATE=TX; CDC=1233\n") - .queryContains( - mongoChecker( - "{\n" - + " \"$match\": {\n" - + " \"$or\": [\n" - + " {\n" - + " \"state\": \"CA\"\n" - + " },\n" - + " {\n" - + " \"state\": \"TX\"\n" - + " }\n" - + " ]\n" - + " }\n" - + "}", - "{$project: {CITY: '$city', STATE: '$state'}}", - "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}}}", - "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE'}}", - "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}", - "{$project: {STATE: '$_id', CDC: '$CDC'}}", - "{$sort: {STATE: 1}}")); + .query("select state, count(distinct city) as cdc from zips\n" + + "where state in ('CA', 'TX') group by state order by state") + .returns("STATE=CA; CDC=1072\n" + + "STATE=TX; CDC=1233\n") + .queryContains( + mongoChecker( + "{\n" + + " \"$match\": {\n" + + " \"$or\": [\n" + + " {\n" + + " \"state\": \"CA\"\n" + + " },\n" + + " {\n" + + " \"state\": \"TX\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}", + "{$project: {CITY: '$city', STATE: '$state'}}", + "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}}}", + "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE'}}", + "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}", + "{$project: {STATE: '$_id', CDC: '$CDC'}}", + "{$sort: {STATE: 1}}")); } @Test public void testDistinctCountOrderBy() { @@ -592,52 +592,52 @@ public class MongoAdapterTest implements SchemaFactory { // https://github.com/fakemongo/fongo/issues/152 MongoAssertions.assumeRealMongoInstance(); assertModel(MODEL) - .query("select state, count(distinct city) as cdc\n" - + "from zips\n" - + "group by state\n" - + "order by cdc desc, state\n" - + "limit 5") - .returns("STATE=AK; CDC=3\n" - + "STATE=AL; CDC=3\n" - + "STATE=AR; CDC=3\n" - + "STATE=AZ; CDC=3\n" - + "STATE=CA; CDC=3\n") - .queryContains( - mongoChecker( - "{$project: {CITY: '$city', STATE: '$state'}}", - "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}}}", - "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE'}}", - "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}", - "{$project: {STATE: '$_id', CDC: '$CDC'}}", - "{$sort: {CDC: -1, STATE: 1}}", - "{$limit: 5}")); + .query("select state, count(distinct city) as cdc\n" + + "from zips\n" + + "group by state\n" + + "order by cdc desc, state\n" + + "limit 5") + .returns("STATE=AK; CDC=3\n" + + "STATE=AL; CDC=3\n" + + "STATE=AR; CDC=3\n" + + "STATE=AZ; CDC=3\n" + + "STATE=CA; CDC=3\n") + .queryContains( + mongoChecker( + "{$project: {CITY: '$city', STATE: '$state'}}", + "{$group: {_id: {CITY: '$CITY', STATE: '$STATE'}}}", + "{$project: {_id: 0, CITY: '$_id.CITY', STATE: '$_id.STATE'}}", + "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}", + "{$project: {STATE: '$_id', CDC: '$CDC'}}", + "{$sort: {CDC: -1, STATE: 1}}", + "{$limit: 5}")); } @Ignore("broken; [CALCITE-2115] is logged to fix it") @Test public void testProject() { assertModel(MODEL) - .query("select state, city, 0 as zero from zips order by state, city") - .limit(2) - .returns("STATE=AK; CITY=AKHIOK; ZERO=0\n" - + "STATE=AK; CITY=AKIACHAK; ZERO=0\n") - .queryContains( - mongoChecker( - "{$project: {CITY: '$city', STATE: '$state'}}", - "{$sort: {STATE: 1, CITY: 1}}", - "{$project: {STATE: 1, CITY: 1, ZERO: {$literal: 0}}}")); + .query("select state, city, 0 as zero from zips order by state, city") + .limit(2) + .returns("STATE=AK; CITY=AKHIOK; ZERO=0\n" + + "STATE=AK; CITY=AKIACHAK; ZERO=0\n") + .queryContains( + mongoChecker( + "{$project: {CITY: '$city', STATE: '$state'}}", + "{$sort: {STATE: 1, CITY: 1}}", + "{$project: {STATE: 1, CITY: 1, ZERO: {$literal: 0}}}")); } @Test public void testFilter() { assertModel(MODEL) - .query("select state, city from zips where state = 'CA'") - .limit(3) - .returnsUnordered("STATE=CA; CITY=LOS ANGELES", - "STATE=CA; CITY=BELL GARDENS", - "STATE=CA; CITY=NORWALK") - .explainContains("PLAN=MongoToEnumerableConverter\n" - + " MongoProject(STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " MongoFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n" - + " MongoTableScan(table=[[mongo_raw, zips]])"); + .query("select state, city from zips where state = 'CA'") + .limit(3) + .returnsUnordered("STATE=CA; CITY=LOS ANGELES", + "STATE=CA; CITY=BELL GARDENS", + "STATE=CA; CITY=NORWALK") + .explainContains("PLAN=MongoToEnumerableConverter\n" + + " MongoProject(STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " MongoFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n" + + " MongoTableScan(table=[[mongo_raw, zips]])"); } /** MongoDB's predicates are handed (they can only accept literals on the @@ -645,18 +645,18 @@ public class MongoAdapterTest implements SchemaFactory { * ways around. */ @Test public void testFilterReversed() { assertModel(MODEL) - .query("select state, city from zips where 'WI' < state order by state, city") - .limit(3) - .returnsOrdered("STATE=WV; CITY=BECKLEY", - "STATE=WV; CITY=ELM GROVE", - "STATE=WV; CITY=STAR CITY"); + .query("select state, city from zips where 'WI' < state order by state, city") + .limit(3) + .returnsOrdered("STATE=WV; CITY=BECKLEY", + "STATE=WV; CITY=ELM GROVE", + "STATE=WV; CITY=STAR CITY"); assertModel(MODEL) - .query("select state, city from zips where state > 'WI' order by state, city") - .limit(3) - .returnsOrdered("STATE=WV; CITY=BECKLEY", - "STATE=WV; CITY=ELM GROVE", - "STATE=WV; CITY=STAR CITY"); + .query("select state, city from zips where state > 'WI' order by state, city") + .limit(3) + .returnsOrdered("STATE=WV; CITY=BECKLEY", + "STATE=WV; CITY=ELM GROVE", + "STATE=WV; CITY=STAR CITY"); } /** MongoDB's predicates are handed (they can only accept literals on the @@ -684,13 +684,13 @@ public class MongoAdapterTest implements SchemaFactory { private void checkPredicate(int expected, String q) { assertModel(MODEL) - .query("select count(*) as c from zips\n" - + q) - .returns("C=" + expected + "\n"); + .query("select count(*) as c from zips\n" + + q) + .returns("C=" + expected + "\n"); assertModel(MODEL) - .query("select * from zips\n" - + q) - .returnsCount(expected); + .query("select * from zips\n" + + q) + .returnsCount(expected); } /** Test case for @@ -713,22 +713,22 @@ public class MongoAdapterTest implements SchemaFactory { // "ownerId" : "531e7789e4b0853ddb861313" // } ) assertModel("{\n" - + " version: '1.0',\n" - + " defaultSchema: 'test',\n" - + " schemas: [\n" - + " {\n" - + " type: 'custom',\n" - + " name: 'test',\n" - + " factory: 'org.apache.calcite.adapter.mongodb.MongoSchemaFactory',\n" - + " operand: {\n" - + " host: 'localhost',\n" - + " database: 'test'\n" - + " }\n" - + " }\n" - + " ]\n" - + "}") - .query("select cast(_MAP['date'] as DATE) from \"datatypes\"") - .returnsUnordered("EXPR$0=2012-09-05"); + + " version: '1.0',\n" + + " defaultSchema: 'test',\n" + + " schemas: [\n" + + " {\n" + + " type: 'custom',\n" + + " name: 'test',\n" + + " factory: 'org.apache.calcite.adapter.mongodb.MongoSchemaFactory',\n" + + " operand: {\n" + + " host: 'localhost',\n" + + " database: 'test'\n" + + " }\n" + + " }\n" + + " ]\n" + + "}") + .query("select cast(_MAP['date'] as DATE) from \"datatypes\"") + .returnsUnordered("EXPR$0=2012-09-05"); } /** Test case for @@ -762,11 +762,11 @@ public class MongoAdapterTest implements SchemaFactory { return new Function<List, Void>() { public Void apply(List actual) { Object[] actualArray = - actual == null || actual.isEmpty() - ? null - : ((List) actual.get(0)).toArray(); + actual == null || actual.isEmpty() + ? null + : ((List) actual.get(0)).toArray(); CalciteAssert.assertArrayEqual("expected MongoDB query not found", - strings, actualArray); + strings, actualArray); return null; } }; http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabasePolicy.java ---------------------------------------------------------------------- diff --git a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabasePolicy.java b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabasePolicy.java new file mode 100644 index 0000000..52a0715 --- /dev/null +++ b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabasePolicy.java @@ -0,0 +1,84 @@ +/* + * 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.mongodb; + +import org.apache.calcite.test.MongoAssertions; + +import com.github.fakemongo.Fongo; + +import com.google.common.base.Preconditions; + +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; + +import org.junit.rules.ExternalResource; + +/** + * Instantiates a new connection to Fongo (or Mongo) database depending on the + * current profile (unit or integration tests). + * + * <p>By default, this rule is executed as part of a unit test and in-memory database + * <a href="https://github.com/fakemongo/fongo">Fongo</a> is used. + * + * <p>However, if the maven profile is set to {@code IT} (eg. via command line + * {@code $ mvn -Pit install}) this rule will connect to an existing (external) + * Mongo instance ({@code localhost}). + */ +class MongoDatabasePolicy extends ExternalResource { + + private static final String DB_NAME = "test"; + + private final MongoDatabase database; + private final MongoClient client; + + private MongoDatabasePolicy(MongoClient client) { + this.client = Preconditions.checkNotNull(client, "client"); + this.database = client.getDatabase(DB_NAME); + } + + /** + * Creates an instance based on current maven profile (as defined by {@code -Pit}). + * + * @return new instance of the policy to be used by unit tests + */ + static MongoDatabasePolicy create() { + final MongoClient client; + if (MongoAssertions.useMongo()) { + // use to real client (connects to mongo) + client = new MongoClient(); + } else if (MongoAssertions.useFongo()) { + // in-memory DB (fake Mongo) + client = new Fongo(MongoDatabasePolicy.class.getSimpleName()).getMongo(); + } else { + throw new UnsupportedOperationException("I can only connect to Mongo or Fongo instances"); + } + + return new MongoDatabasePolicy(client); + } + + + MongoDatabase database() { + return database; + } + + @Override protected void after() { + client.close(); + } + +} + +// End MongoDatabasePolicy.java http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabaseRule.java ---------------------------------------------------------------------- diff --git a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabaseRule.java b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabaseRule.java deleted file mode 100644 index d73f503..0000000 --- a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabaseRule.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.mongodb; - -import org.apache.calcite.test.MongoAssertions; - -import com.github.fakemongo.Fongo; - -import com.google.common.base.Preconditions; - -import com.mongodb.MongoClient; -import com.mongodb.client.MongoDatabase; - -import org.junit.rules.ExternalResource; - -/** - * Instantiates new connection to fongo (or mongo) database depending on current profile - * (unit or integration tests). - * - * By default, this rule is executed as part of a unit test and in-memory database - * <a href="https://github.com/fakemongo/fongo">fongo</a> is used. - * - * <p>However, if maven profile is set to {@code IT} (eg. via command line - * {@code $ mvn -Pit install}) this rule will connect to existing (external) - * mongo instance ({@code localhost})</p> - * - */ -class MongoDatabaseRule extends ExternalResource { - - private static final String DB_NAME = "test"; - - private final MongoDatabase database; - private final MongoClient client; - - private MongoDatabaseRule(MongoClient client) { - this.client = Preconditions.checkNotNull(client, "client"); - this.database = client.getDatabase(DB_NAME); - } - - /** - * Create an instance based on current maven profile (as defined by {@code -Pit}). - * @return new instance of the rule to be used by unit tests - */ - static MongoDatabaseRule create() { - final MongoClient client; - if (MongoAssertions.useMongo()) { - // use to real client (connects to mongo) - client = new MongoClient(); - } else if (MongoAssertions.useFongo()) { - // in-memory DB (fake Mongo) - client = new Fongo(MongoDatabaseRule.class.getSimpleName()).getMongo(); - } else { - throw new UnsupportedOperationException("I can only connect to Mongo or Fongo instances"); - } - - return new MongoDatabaseRule(client); - } - - - MongoDatabase database() { - return database; - } - - @Override protected void after() { - client.close(); - } - -} - -// End MongoDatabaseRule.java http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java ---------------------------------------------------------------------- diff --git a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java index 207a3b9..218dba3 100644 --- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java +++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java @@ -25,10 +25,10 @@ import static org.junit.Assume.assumeTrue; /** * Used to trigger integration tests from maven (thus class name is suffixed with {@code IT}). * - * If you want to run integration tests from IDE manually set + * <p>If you want to run integration tests from the, IDE manually set the * {@code -Dcalcite.integrationTest=true} system property. - * <br> - * For command line use: + * + * <p>For command line use: * <pre> * $ mvn install -Pit * </pre> http://git-wip-us.apache.org/repos/asf/calcite/blob/6e8bb5a1/mongodb/src/test/resources/zips-mini.json ---------------------------------------------------------------------- diff --git a/mongodb/src/test/resources/zips-mini.json b/mongodb/src/test/resources/zips-mini.json index d70eadc..858117a 100644 --- a/mongodb/src/test/resources/zips-mini.json +++ b/mongodb/src/test/resources/zips-mini.json @@ -146,4 +146,4 @@ { "_id" : "98310", "city" : "BREMERTON", "loc" : [ -122.629913, 47.601916 ], "pop" : 49057, "state" : "WA" } { "_id" : "99504", "city" : "ANCHORAGE", "loc" : [ -149.74467, 61.203696 ], "pop" : 32383, "state" : "AK" } { "_id" : "99709", "city" : "FAIRBANKS", "loc" : [ -147.846917, 64.85437 ], "pop" : 23238, "state" : "AK" } -{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" } \ No newline at end of file +{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" }
