This change introduces a javadoc error: [ERROR] /home/jhyde/regress/calcite/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java:35: error: unexpected end tag: </p> [ERROR] * </p>
Please fix ASAP. > On Jun 13, 2018, at 6:00 PM, mm...@apache.org wrote: > > [CALCITE-2345] Running Unit tests with Fongo and integration tests with real > mongo instance (Andrei Sereda) > > Better test coverage for unit tests using Fongo in-memory implementation of > Mongo API. > New code will decide (at runtime) what connection to make: fongo vs mongo. > Identical tests will be run against > both databases (depending on maven profile surefire vs failsafe) > > Close apache/calcite#723 > > > Project: http://git-wip-us.apache.org/repos/asf/calcite/repo > Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/dcf396a5 > Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/dcf396a5 > Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/dcf396a5 > > Branch: refs/heads/master > Commit: dcf396a5ca92ee0714c28d9a3c310f53f46220ab > Parents: f84a3eb > Author: Andrei Sereda <and...@nospam.com> > Authored: Tue Jun 5 16:23:56 2018 -0400 > Committer: Michael Mior <mm...@uwaterloo.ca> > Committed: Wed Jun 13 18:59:15 2018 -0400 > > ---------------------------------------------------------------------- > mongodb/pom.xml | 10 +- > .../adapter/mongodb/MongoAdapterTest.java | 794 +++++++++++++++--- > .../adapter/mongodb/MongoDatabaseRule.java | 83 ++ > .../org/apache/calcite/test/MongoAdapterIT.java | 830 +------------------ > .../apache/calcite/test/MongoAssertions.java | 101 +++ > .../test/resources/mongo-foodmart-model.json | 221 ----- > mongodb/src/test/resources/mongo-model.json | 70 ++ > .../src/test/resources/mongo-zips-model.json | 41 - > mongodb/src/test/resources/zips-mini.json | 149 ++++ > pom.xml | 9 + > 10 files changed, 1132 insertions(+), 1176 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/mongodb/pom.xml > ---------------------------------------------------------------------- > diff --git a/mongodb/pom.xml b/mongodb/pom.xml > index 25c0642..63cc147 100644 > --- a/mongodb/pom.xml > +++ b/mongodb/pom.xml > @@ -71,6 +71,11 @@ limitations under the License. > <scope>test</scope> > </dependency> > <dependency> > + <groupId>net.hydromatic</groupId> > + <artifactId>foodmart-data-json</artifactId> > + <scope>test</scope> > + </dependency> > + <dependency> > <groupId>org.mongodb</groupId> > <artifactId>mongo-java-driver</artifactId> > </dependency> > @@ -78,11 +83,6 @@ limitations under the License. > <groupId>org.slf4j</groupId> > <artifactId>slf4j-api</artifactId> > </dependency> > - <dependency> > - <groupId>org.slf4j</groupId> > - <artifactId>slf4j-log4j12</artifactId> > - <scope>test</scope> > - </dependency> > </dependencies> > > <build> > > http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/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 b6ca4f3..a4061e4 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 > @@ -16,143 +16,749 @@ > */ > package org.apache.calcite.adapter.mongodb; > > -import org.apache.calcite.jdbc.CalciteConnection; > +import org.apache.calcite.schema.Schema; > +import org.apache.calcite.schema.SchemaFactory; > import org.apache.calcite.schema.SchemaPlus; > import org.apache.calcite.test.CalciteAssert; > +import org.apache.calcite.test.MongoAssertions; > > -import com.github.fakemongo.junit.FongoRule; > + > +import org.apache.calcite.util.Bug; > +import org.apache.calcite.util.Util; > + > +import com.google.common.base.Function; > +import com.google.common.base.Preconditions; > +import com.google.common.io.LineProcessor; > +import com.google.common.io.Resources; > import com.mongodb.client.MongoCollection; > import com.mongodb.client.MongoDatabase; > > +import net.hydromatic.foodmart.data.json.FoodmartJson; > + > +import org.bson.BsonDateTime; > import org.bson.BsonDocument; > +import org.bson.BsonInt32; > +import org.bson.BsonString; > import org.bson.Document; > > -import org.junit.Before; > +import org.hamcrest.CoreMatchers; > + > +import org.junit.Assert; > +import org.junit.BeforeClass; > +import org.junit.ClassRule; > import org.junit.Ignore; > -import org.junit.Rule; > import org.junit.Test; > > -import java.sql.Connection; > -import java.sql.DriverManager; > +import java.io.IOException; > +import java.io.UncheckedIOException; > +import java.net.URL; > +import java.nio.charset.StandardCharsets; > +import java.sql.ResultSet; > import java.sql.SQLException; > +import java.text.SimpleDateFormat; > +import java.util.Date; > +import java.util.List; > +import java.util.Locale; > +import java.util.Map; > > /** > - * Tests current adapter using in-memory (fake) implementation of Mongo API: > - * <a href="https://github.com/fakemongo/fongo">Fongo</a>. > - * > + * 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}). > */ > -public class MongoAdapterTest { > +public class MongoAdapterTest implements SchemaFactory { > + > + /** Connection factory based on the "mongo-zips" model. */ > + protected static final URL MODEL = > MongoAdapterTest.class.getResource("/mongo-model.json"); > + > + /** Number of records in local file */ > + protected static final int ZIPS_SIZE = 149; > + > + @ClassRule > + public static final MongoDatabaseRule RULE = MongoDatabaseRule.create(); > + > + private static MongoSchema schema; > + > + @BeforeClass > + public static void setUp() throws Exception { > + MongoDatabase database = RULE.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")); > > - @Rule > - public final FongoRule rule = new FongoRule(); > + // Manually insert data for data-time test. > + MongoCollection<BsonDocument> datatypes = > database.getCollection("datatypes") > + .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"); > + doc.put("date", new BsonDateTime(date.getTime())); > + doc.put("value", new BsonInt32(1231)); > + doc.put("ownerId", new BsonString("531e7789e4b0853ddb861313")); > + datatypes.insertOne(doc); > > - private MongoDatabase mongoDb; > - private MongoCollection<Document> zips; > + schema = new MongoSchema(database); > + } > + > + private static void populate(MongoCollection<Document> collection, URL > resource) > + throws IOException { > + Preconditions.checkNotNull(collection, "collection"); > + > + if (collection.count() > 0) { > + // delete any existing documents (run from a clean set) > + collection.deleteMany(new BsonDocument()); > + } > > - @Before > - public void setUp() throws Exception { > - mongoDb = rule.getDatabase(getClass().getSimpleName()); > - zips = mongoDb.getCollection("zips"); > + MongoCollection<BsonDocument> bsonCollection = > collection.withDocumentClass(BsonDocument.class); > + Resources.readLines(resource, StandardCharsets.UTF_8, new > LineProcessor<Void>() { > + @Override public boolean processLine(String line) throws IOException { > + bsonCollection.insertOne(BsonDocument.parse(line)); > + return true; > + } > + > + @Override public Void getResult() { > + return null; > + } > + }); > } > > /** > - * Handcrafted connection where we manually added {@link MongoSchema} > + * Returns always the same schema to avoid initialization costs. > */ > - private CalciteAssert.ConnectionFactory newConnectionFactory() { > - return new CalciteAssert.ConnectionFactory() { > - @Override public Connection createConnection() throws SQLException { > - Connection connection = DriverManager.getConnection("jdbc:calcite:"); > - final SchemaPlus root = > connection.unwrap(CalciteConnection.class).getRootSchema(); > - root.add("mongo", new MongoSchema(mongoDb)); > - return connection; > - } > - }; > + @Override public Schema create(SchemaPlus parentSchema, String name, > + Map<String, Object> operand) { > + return schema; > + } > + > + private CalciteAssert.AssertThat assertModel(String model) { > + // ensure that Schema from this instance is being used > + model = model.replace(MongoSchemaFactory.class.getName(), > MongoAdapterTest.class.getName()); > + > + return CalciteAssert.that() > + .withModel(model); > + } > + > + private CalciteAssert.AssertThat assertModel(URL url) { > + Preconditions.checkNotNull(url, "url"); > + try { > + return assertModel(Resources.toString(url, StandardCharsets.UTF_8)); > + } catch (IOException e) { > + throw new UncheckedIOException(e); > + } > } > > @Test > - public void single() { > - zips.insertOne(new Document()); > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select * from \"mongo\".\"zips\"") > + 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]])"); > + } > + > + @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") > + .returns("STATE=AK; ID=99801\n" > + + "STATE=AL; ID=35215\n" > + + "STATE=AL; ID=35401\n") > + .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() > - .returnsCount(1); > + .queryContains( > + mongoChecker( > + "{$skip: 2}", > + "{$limit: 3}", > + "{$project: {STATE: '$state', ID: '$_id'}}")); > } > > - @Test > - public void empty() { > - // for some reason fongo doesn't list collection if it was unused > - zips.insertOne(new Document()); > - zips.deleteMany(new BsonDocument()); > - > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select * from \"mongo\".\"zips\"") > + @Test public void testLimit() { > + assertModel(MODEL) > + .query("select state, id from zips\n" > + + "fetch next 3 rows only") > .runs() > - .returnsCount(0); > + .queryContains( > + mongoChecker( > + "{$limit: 3}", > + "{$project: {STATE: '$state', ID: '$_id'}}")); > } > > - @Test > - public void filter() { > - zips.insertOne(new Document("CITY", "New York").append("STATE", "NY")); > - zips.insertOne(new Document("CITY", "Washington").append("STATE", "DC")); > + @Ignore > + @Test public void testFilterSort() { > + // 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]])"); > + } > > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select cast(_MAP['CITY'] as varchar(20)) as \"city\" > from \"mongo\".\"zips\" " > - + " where _MAP['STATE'] = 'NY'") > - .returns("city=New York\n"); > + @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) > + .returns("CITY=BECKLEY; LONGITUDE=null; LATITUDE=null; > POP=45196; STATE=WV; ID=25801\n" > + + "CITY=ROCKERVILLE; LONGITUDE=null; LATITUDE=null; > POP=45328; STATE=SD; ID=57701\n" > + + "CITY=PAWTUCKET; LONGITUDE=null; LATITUDE=null; > POP=45442; STATE=RI; ID=02860\n" > + + "CITY=LAWTON; LONGITUDE=null; LATITUDE=null; > POP=45542; STATE=OK; ID=73505\n"); > + } > > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select cast(_MAP['CITY'] as varchar(20)) as \"city\" > from \"mongo\".\"zips\" " > - + " where _MAP['STATE'] = 'DC'") > - .returns("city=Washington\n"); > + @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")); > + } > > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select cast(_MAP['CITY'] as varchar(20)) as \"city\" > from \"mongo\".\"zips\" " > - + " where _MAP['STATE'] in ('DC', 'NY')") > - .returns("city=New York\ncity=Washington\n"); > + @Ignore( > + "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(); > } > > - @Test > - public void limit() { > - zips.insertOne(new Document("CITY", "New York").append("STATE", "NY")); > - zips.insertOne(new Document("CITY", "Washington").append("STATE", "DC")); > + /** Tests that we don't generate multiple constraints on the same column. > + * MongoDB doesn't like it. If there is an '=', it supersedes all other > + * 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'}}")); > + } > + > + @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}}")); > + } > > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select * from \"mongo\".\"zips\" limit 1") > - .returnsCount(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}}")); > + } > > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select * from \"mongo\".\"zips\" limit 2") > - .returnsCount(2); > + /** Simple query based on the "mongo-zips" model. */ > + @Test public void testZips() { > + assertModel(MODEL) > + .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}}}")); > } > > - /** > - * Following queries are not supported in Mongo adapter : > - * <pre> > - * {@code A and (B or C)} > - * {@code (A or B) and C} > - * </pre> > + @Test public void testCountGroupByEmptyMultiplyBy2() { > + // This operation is not supported by fongo: > https://github.com/fakemongo/fongo/issues/152 > + 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}]}}}")); > + } > + > + @Test public void testGroupByOneColumnNotProjected() { > + assertModel(MODEL) > + .query("select count(*) from zips group by state order by 1") > + .limit(2) > + .returns("EXPR$0=2\n" > + + "EXPR$0=2\n") > + .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(2) > + .returns("STATE=AK; C=3\nSTATE=AL; 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}}")); > + } > + > + @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}}")); > + } > + > + @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'}}")); > + } > + > + @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}}")); > + } > + > + @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}}")); > + } > + > + @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}}")); > + } > + > + @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}}")); > + } > + > + @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}}")); > + } > + > + @Test public void testDistinctCountOrderBy() { > + // java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be > cast to java.lang.Number > + // 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 limit 5") > + .returns("STATE=VA; CDC=3\n" > + + "STATE=NY; CDC=3\n" > + + "STATE=SC; CDC=3\n" > + + "STATE=RI; CDC=3\n" > + + "STATE=WV; 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}}", > + "{$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}}}")); > + } > + > + @Test public void testFilter() { > + assertModel(MODEL) > + .query("select state, city from zips where state = 'CA'") > + .limit(2) > + .returns("STATE=CA; CITY=LOS ANGELES\n" > + + "STATE=CA; CITY=BELL GARDENS\n") > + .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 > + * right-hand size) so it's worth testing that we handle them right both > + * ways around. */ > + @Test public void testFilterReversed() { > + assertModel(MODEL) > + .query("select state, city from zips where 'WI' < state") > + .limit(2) > + .returns("STATE=WV; CITY=BECKLEY\nSTATE=WV; CITY=ELM GROVE\n"); > + > + assertModel(MODEL) > + .query("select state, city from zips where state > 'WI'") > + .limit(2) > + .returns("STATE=WV; CITY=BECKLEY\n" > + + "STATE=WV; CITY=ELM GROVE\n"); > + } > + > + /** MongoDB's predicates are handed (they can only accept literals on the > + * right-hand size) so it's worth testing that we handle them right both > + * ways around. > * > - * @see <a > href="https://issues.apache.org/jira/browse/CALCITE-2331">[CALCITE-2331]</a> > - */ > - @Ignore("broken; [CALCITE-2331] is logged to fix it") > - @Test > - public void validateCALCITE2331() { > - zips.insertOne(new Document("CITY", "New York").append("STATE", "NY")); > - zips.insertOne(new Document("CITY", "Washington").append("STATE", "DC")); > - > - CalciteAssert.that() > - .with(newConnectionFactory()) > - .query("select cast(_MAP['CITY'] as varchar(20)) as \"city\" > from \"mongo\".\"zips\" " > - + " where _MAP['STATE'] in ('DC', 'NY') and _MAP['CITY'] > = 'New York'") > - .returns("city=New York\n"); > + * <p>Test case for > + * <a > href="https://issues.apache.org/jira/browse/CALCITE-740">[CALCITE-740] > + * Redundant WHERE clause causes wrong result in MongoDB adapter</a>. */ > + @Test public void testFilterPair() { > + final int gt9k = 148; > + final int lt9k = 1; > + final int gt8k = 148; > + final int lt8k = 1; > + checkPredicate(gt9k, "where pop > 8000 and pop > 9000"); > + checkPredicate(gt9k, "where pop > 9000"); > + checkPredicate(lt9k, "where pop < 9000"); > + checkPredicate(gt8k, "where pop > 8000"); > + checkPredicate(lt8k, "where pop < 8000"); > + checkPredicate(gt9k, "where pop > 9000 and pop > 8000"); > + checkPredicate(gt8k, "where pop > 9000 or pop > 8000"); > + checkPredicate(gt8k, "where pop > 8000 or pop > 9000"); > + checkPredicate(lt8k, "where pop < 8000 and pop < 9000"); > + } > + > + private void checkPredicate(int expected, String q) { > + assertModel(MODEL) > + .query("select count(*) as c from zips\n" > + + q) > + .returns("C=" + expected + "\n"); > + assertModel(MODEL) > + .query("select * from zips\n" > + + q) > + .returnsCount(expected); > + } > + > + /** Test case for > + * <a > href="https://issues.apache.org/jira/browse/CALCITE-286">[CALCITE-286] > + * Error casting MongoDB date</a>. */ > + @Test public void testDate() { > + // Assumes that you have created the following collection before running > + // this test: > + // > + // $ mongo > + // > use test > + // switched to db test > + // > db.createCollection("datatypes") > + // { "ok" : 1 } > + // > db.datatypes.insert( { > + // "_id" : ObjectId("53655599e4b0c980df0a8c27"), > + // "_class" : "com.ericblue.Test", > + // "date" : ISODate("2012-09-05T07:00:00Z"), > + // "value" : 1231, > + // "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"); > + } > + > + /** Test case for > + * <a > href="https://issues.apache.org/jira/browse/CALCITE-665">[CALCITE-665] > + * ClassCastException in MongoDB adapter</a>. */ > + @Test public void testCountViaInt() { > + assertModel(MODEL) > + .query("select count(*) from zips") > + .returns( > + new Function<ResultSet, Void>() { > + public Void apply(ResultSet input) { > + try { > + Assert.assertThat(input.next(), CoreMatchers.is(true)); > + Assert.assertThat(input.getInt(1), > CoreMatchers.is(ZIPS_SIZE)); > + return null; > + } catch (SQLException e) { > + throw new RuntimeException(e); > + } > + } > + }); > + } > + > + /** Returns a function that checks that a particular MongoDB pipeline is > + * generated to implement a query. */ > + private static Function<List, Void> mongoChecker(final String... strings) { > + return new Function<List, Void>() { > + public Void apply(List actual) { > + Object[] actualArray = > + actual == null || actual.isEmpty() > + ? null > + : ((List) actual.get(0)).toArray(); > + CalciteAssert.assertArrayEqual("expected MongoDB query not found", > + strings, actualArray); > + return null; > + } > + }; > } > } > > > http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/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 > new file mode 100644 > index 0000000..90bd759 > --- /dev/null > +++ > b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoDatabaseRule.java > @@ -0,0 +1,83 @@ > +/* > + * 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}). > + */ > + 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/dcf396a5/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 00ed03a..bda1163 100644 > --- a/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java > +++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAdapterIT.java > @@ -16,829 +16,29 @@ > */ > package org.apache.calcite.test; > > -import org.apache.calcite.linq4j.Ord; > -import org.apache.calcite.util.Bug; > -import org.apache.calcite.util.Pair; > -import org.apache.calcite.util.Util; > +import org.apache.calcite.adapter.mongodb.MongoAdapterTest; > > -import com.google.common.base.Function; > -import com.google.common.collect.ImmutableMap; > -import com.google.common.collect.Lists; > -import com.google.common.collect.Ordering; > +import org.junit.BeforeClass; > > -import org.hamcrest.CoreMatchers; > -import org.junit.Ignore; > -import org.junit.Test; > - > -import java.sql.ResultSet; > -import java.sql.SQLException; > -import java.util.Arrays; > -import java.util.Collections; > -import java.util.List; > - > -import static org.hamcrest.CoreMatchers.equalTo; > -import static org.junit.Assert.assertThat; > +import static org.junit.Assume.assumeTrue; > > /** > - * Tests for the {@code org.apache.calcite.adapter.mongodb} package. > - * > - * <p>Before calling this test, you need to populate MongoDB, as follows: > + * Used to trigger integration tests from maven (thus class name is suffixed > with {@code IT}). > * > - * <blockquote><code> > - * git clone https://github.com/vlsi/calcite-test-dataset<br> > - * cd calcite-test-dataset<br> > - * mvn install > - * </code></blockquote> > + * <p>If you want to run integration tests from IDE manually set > + * {@code -Dcalcite.integrationTest=true} system property. > * > - * <p>This will create a virtual machine with MongoDB and "zips" and > "foodmart" > - * data sets. > + * For command line use: > + * <pre> > + * $ mvn install -Pit > + * </pre> > + * </p> > */ > -public class MongoAdapterIT { > - public static final String MONGO_FOODMART_SCHEMA = " {\n" > - + " type: 'custom',\n" > - + " name: '_foodmart',\n" > - + " factory: > 'org.apache.calcite.adapter.mongodb.MongoSchemaFactory',\n" > - + " operand: {\n" > - + " host: 'localhost',\n" > - + " database: 'foodmart'\n" > - + " }\n" > - + " },\n" > - + " {\n" > - + " name: 'foodmart',\n" > - + " tables: [\n" > - + " {\n" > - + " name: 'sales_fact_1997',\n" > - + " type: 'view',\n" > - + " sql: 'select cast(_MAP[\\'product_id\\'] AS double) AS > \"product_id\" from \"_foodmart\".\"sales_fact_1997\"'\n" > - + " },\n" > - + " {\n" > - + " name: 'sales_fact_1998',\n" > - + " type: 'view',\n" > - + " sql: 'select cast(_MAP[\\'product_id\\'] AS double) AS > \"product_id\" from \"_foodmart\".\"sales_fact_1998\"'\n" > - + " },\n" > - + " {\n" > - + " name: 'store',\n" > - + " type: 'view',\n" > - + " sql: 'select cast(_MAP[\\'store_id\\'] AS double) AS > \"store_id\", cast(_MAP[\\'store_name\\'] AS varchar(20)) AS \"store_name\" > from \"_foodmart\".\"store\"'\n" > - + " },\n" > - + " {\n" > - + " name: 'warehouse',\n" > - + " type: 'view',\n" > - + " sql: 'select cast(_MAP[\\'warehouse_id\\'] AS double) AS > \"warehouse_id\", cast(_MAP[\\'warehouse_state_province\\'] AS varchar(20)) > AS \"warehouse_state_province\" from \"_foodmart\".\"warehouse\"'\n" > - + " }\n" > - + " ]\n" > - + " }\n"; > - > - public static final String MONGO_FOODMART_MODEL = "{\n" > - + " version: '1.0',\n" > - + " defaultSchema: 'foodmart',\n" > - + " schemas: [\n" > - + MONGO_FOODMART_SCHEMA > - + " ]\n" > - + "}"; > - > - /** Connection factory based on the "mongo-zips" model. */ > - public static final ImmutableMap<String, String> ZIPS = > - ImmutableMap.of("model", > - MongoAdapterIT.class.getResource("/mongo-zips-model.json") > - .getPath()); > - > - /** Connection factory based on the "mongo-zips" model. */ > - public static final ImmutableMap<String, String> FOODMART = > - ImmutableMap.of("model", > - MongoAdapterIT.class.getResource("/mongo-foodmart-model.json") > - .getPath()); > - > - /** Whether to run Mongo tests. Enabled by default, however test is only > - * included if "it" profile is activated ({@code -Pit}). To disable, > - * specify {@code -Dcalcite.test.mongodb=false} on the Java command line. > */ > - public static final boolean ENABLED = > - Util.getBooleanProperty("calcite.test.mongodb", true); > - > - /** Whether to run this test. */ > - protected boolean enabled() { > - return ENABLED; > - } > - > - /** Returns a function that checks that a particular MongoDB pipeline is > - * generated to implement a query. */ > - private static Function<List, Void> mongoChecker(final String... strings) { > - return new Function<List, Void>() { > - public Void apply(List actual) { > - Object[] actualArray = > - actual == null || actual.isEmpty() > - ? null > - : ((List) actual.get(0)).toArray(); > - CalciteAssert.assertArrayEqual("expected MongoDB query not found", > - strings, actualArray); > - return null; > - } > - }; > - } > - > - /** Similar to {@link CalciteAssert#checkResultUnordered}, but filters > strings > - * before comparing them. */ > - static Function<ResultSet, Void> checkResultUnordered( > - final String... lines) { > - return new Function<ResultSet, Void>() { > - public Void apply(ResultSet resultSet) { > - try { > - final List<String> expectedList = > - Ordering.natural().immutableSortedCopy(Arrays.asList(lines)); > - > - final List<String> actualList = Lists.newArrayList(); > - CalciteAssert.toStringList(resultSet, actualList); > - for (int i = 0; i < actualList.size(); i++) { > - String s = actualList.get(i); > - actualList.set(i, > - s.replaceAll("\\.0;", ";").replaceAll("\\.0$", "")); > - } > - Collections.sort(actualList); > - > - assertThat(Ordering.natural().immutableSortedCopy(actualList), > - equalTo(expectedList)); > - return null; > - } catch (SQLException e) { > - throw new RuntimeException(e); > - } > - } > - }; > - } > - > - @Test public void testSort() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select * from zips order by state") > - .returnsCount(29353) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, id from zips\n" > - + "order by state, id offset 2 rows fetch next 3 rows only") > - .returns("STATE=AK; ID=99503\n" > - + "STATE=AK; ID=99504\n" > - + "STATE=AK; ID=99505\n") > - .queryContains( > - mongoChecker( > - "{$project: {STATE: '$state', ID: '$_id'}}", > - "{$sort: {STATE: 1, ID: 1}}", > - "{$skip: 2}", > - "{$limit: 3}")); > - } > - > - @Test public void testOffsetLimit() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, id from zips\n" > - + "fetch next 3 rows only") > - .runs() > - .queryContains( > - mongoChecker( > - "{$limit: 3}", > - "{$project: {STATE: '$state', ID: '$_id'}}")); > - } > - > - @Ignore > - @Test public void testFilterSort() { > - // LONGITUDE and LATITUDE are null because of CALCITE-194. > - Util.discard(Bug.CALCITE_194_FIXED); > - CalciteAssert.that() > - .enable(enabled()) > - .with(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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select * from zips\n" > - + "where pop BETWEEN 20000 AND 20100\n" > - + "order by state desc, pop") > - .limit(4) > - .returns("" > - + "CITY=SHERIDAN; LONGITUDE=null; LATITUDE=null; POP=20025; > STATE=WY; ID=82801\n" > - + "CITY=MOUNTLAKE TERRAC; LONGITUDE=null; LATITUDE=null; > POP=20059; STATE=WA; ID=98043\n" > - + "CITY=FALMOUTH; LONGITUDE=null; LATITUDE=null; POP=20039; > STATE=VA; ID=22405\n" > - + "CITY=FORT WORTH; LONGITUDE=null; LATITUDE=null; POP=20012; > STATE=TX; ID=76104\n"); > - } > - > - @Ignore("broken; [CALCITE-2115] is logged to fix it") > - @Test public void testUnionPlan() { > - CalciteAssert.that() > - .enable(enabled()) > - .withModel(MONGO_FOODMART_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( > - checkResultUnordered( > - "product_id=337", "product_id=1512")); > - } > - > - @Ignore( > - "java.lang.ClassCastException: java.lang.Integer cannot be cast to > java.lang.Double") > - @Test public void testFilterUnionPlan() { > - CalciteAssert.that() > - .enable(enabled()) > - .withModel(MONGO_FOODMART_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(); > - } > - > - /** Tests that we don't generate multiple constraints on the same column. > - * MongoDB doesn't like it. If there is an '=', it supersedes all other > - * operators. */ > - @Test public void testFilterRedundant() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .withModel(MONGO_FOODMART_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=[[_foodmart, warehouse]])") > - .returns( > - 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() { > - CalciteAssert.that() > - .enable(enabled()) > - .withModel(MONGO_FOODMART_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( > - 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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, city from zips") > - .returnsCount(29353); > - } > - > - @Test public void testCountGroupByEmpty() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*) from zips") > - .returns("EXPR$0=29353\n") > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*)*2 from zips") > - .returns("EXPR$0=58706\n") > - .queryContains( > - mongoChecker( > - "{$group: {_id: {}, _0: {$sum: 1}}}", > - "{$project: {'EXPR$0': {$multiply: ['$_0', {$literal: > 2}]}}}")); > - } > - > - @Test public void testGroupByOneColumnNotProjected() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*) from zips group by state order by 1") > - .limit(2) > - .returns("EXPR$0=24\n" > - + "EXPR$0=53\n") > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query( > - "select state, count(*) as c from zips group by state order by > state") > - .limit(2) > - .returns("STATE=AK; C=195\n" > - + "STATE=AL; C=567\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. > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query( > - "select count(*) as c, state from zips group by state order by > state") > - .limit(2) > - .returns("C=195; STATE=AK\n" > - + "C=567; 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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query( > - "select state, avg(pop) as a from zips group by state order by > state") > - .limit(2) > - .returns("STATE=AK; A=2793\n" > - + "STATE=AL; A=7126\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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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=2793; S=544698; C=195\n" > - + "STATE=AL; A=7126; S=4040587; C=567\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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, count(*) as c from zips\n" > - + "group by state having count(*) > 1500 order by state") > - .returns("STATE=CA; C=1516\n" > - + "STATE=NY; C=1595\n" > - + "STATE=TX; C=1671\n") > - .queryContains( > - mongoChecker( > - "{$project: {STATE: '$state'}}", > - "{$group: {_id: '$STATE', C: {$sum: 1}}}", > - "{$project: {STATE: '$_id', C: '$C'}}", > - "{\n" > - + " \"$match\": {\n" > - + " \"C\": {\n" > - + " \"$gt\": 1500\n" > - + " }\n" > - + " }\n" > - + "}", > - "{$sort: {STATE: 1}}")); > - } > - > - @Ignore("https://issues.apache.org/jira/browse/CALCITE-270") > - @Test public void testGroupByHaving2() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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=195; STATE=AK; MIN_POP=0; MAX_POP=32383; > SUM_POP=544698\n" > - + "C=567; STATE=AL; MIN_POP=0; MAX_POP=44165; SUM_POP=4040587\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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*) as c, state, city from zips\n" > - + "group by state, city order by c desc limit 2") > - .returns("C=93; STATE=TX; CITY=HOUSTON\n" > - + "C=56; STATE=CA; CITY=LOS ANGELES\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}}", > - "{$limit: 2}", > - "{$project: {C: 1, STATE: 1, CITY: 1}}")); > - } > - > - @Ignore("broken; [CALCITE-2115] is logged to fix it") > - @Test public void testDistinctCount() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, count(distinct city) as cdc\n" > - + "from zips\n" > - + "group by state\n" > - + "order by cdc desc limit 5") > - .returns("STATE=NY; CDC=1370\n" > - + "STATE=PA; CDC=1369\n" > - + "STATE=TX; CDC=1233\n" > - + "STATE=IL; CDC=1148\n" > - + "STATE=CA; CDC=1072\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}}", > - "{$limit: 5}")); > - } > - > - @Ignore("broken; [CALCITE-2115] is logged to fix it") > - @Test public void testProject() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .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() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, city from zips where state = 'CA'") > - .limit(2) > - .returns("STATE=CA; CITY=LOS ANGELES\n" > - + "STATE=CA; CITY=LOS ANGELES\n") > - .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 > - * right-hand size) so it's worth testing that we handle them right both > - * ways around. */ > - @Test public void testFilterReversed() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, city from zips where 'WI' < state") > - .limit(2) > - .returns("STATE=WV; CITY=BLUEWELL\n" > - + "STATE=WV; CITY=ATHENS\n"); > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select state, city from zips where state > 'WI'") > - .limit(2) > - .returns("STATE=WV; CITY=BLUEWELL\n" > - + "STATE=WV; CITY=ATHENS\n"); > - } > - > - /** MongoDB's predicates are handed (they can only accept literals on the > - * right-hand size) so it's worth testing that we handle them right both > - * ways around. > - * > - * <p>Test case for > - * <a > href="https://issues.apache.org/jira/browse/CALCITE-740">[CALCITE-740] > - * Redundant WHERE clause causes wrong result in MongoDB adapter</a>. */ > - @Test public void testFilterPair() { > - final int gt9k = 8125; > - final int lt9k = 21227; > - final int gt8k = 8707; > - final int lt8k = 20645; > - checkPredicate(gt9k, "where pop > 8000 and pop > 9000"); > - checkPredicate(gt9k, "where pop > 9000"); > - checkPredicate(lt9k, "where pop < 9000"); > - checkPredicate(gt8k, "where pop > 8000"); > - checkPredicate(lt8k, "where pop < 8000"); > - checkPredicate(gt9k, "where pop > 9000 and pop > 8000"); > - checkPredicate(gt8k, "where pop > 9000 or pop > 8000"); > - checkPredicate(gt8k, "where pop > 8000 or pop > 9000"); > - checkPredicate(lt8k, "where pop < 8000 and pop < 9000"); > - } > - > - private void checkPredicate(int expected, String q) { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*) as c from zips\n" > - + q) > - .returns("C=" + expected + "\n"); > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select * from zips\n" > - + q) > - .returnsCount(expected); > - } > - > - @Ignore > - @Test public void testFoodmartQueries() { > - final List<Pair<String, String>> queries = JdbcTest.getFoodmartQueries(); > - for (Ord<Pair<String, String>> query : Ord.zip(queries)) { > -// if (query.i != 29) continue; > - if (query.e.left.contains("agg_")) { > - continue; > - } > - final CalciteAssert.AssertQuery query1 = > - CalciteAssert.that() > - .enable(enabled()) > - .with(FOODMART) > - .query(query.e.left); > - if (query.e.right != null) { > - query1.returns(query.e.right); > - } else { > - query1.runs(); > - } > - } > - } > - > - /** Test case for > - * <a > href="https://issues.apache.org/jira/browse/CALCITE-286">[CALCITE-286] > - * Error casting MongoDB date</a>. */ > - @Test public void testDate() { > - // Assumes that you have created the following collection before running > - // this test: > - // > - // $ mongo > - // > use test > - // switched to db test > - // > db.createCollection("datatypes") > - // { "ok" : 1 } > - // > db.datatypes.insert( { > - // "_id" : ObjectId("53655599e4b0c980df0a8c27"), > - // "_class" : "com.ericblue.Test", > - // "date" : ISODate("2012-09-05T07:00:00Z"), > - // "value" : 1231, > - // "ownerId" : "531e7789e4b0853ddb861313" > - // } ) > - CalciteAssert.that() > - .enable(enabled()) > - .withModel("{\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"); > - } > +public class MongoAdapterIT extends MongoAdapterTest { > > - /** Test case for > - * <a > href="https://issues.apache.org/jira/browse/CALCITE-665">[CALCITE-665] > - * ClassCastException in MongoDB adapter</a>. */ > - @Test public void testCountViaInt() { > - CalciteAssert.that() > - .enable(enabled()) > - .with(ZIPS) > - .query("select count(*) from zips") > - .returns( > - new Function<ResultSet, Void>() { > - public Void apply(ResultSet input) { > - try { > - assertThat(input.next(), CoreMatchers.is(true)); > - assertThat(input.getInt(1), CoreMatchers.is(29353)); > - return null; > - } catch (SQLException e) { > - throw new RuntimeException(e); > - } > - } > - }); > + @BeforeClass > + public static void enforceMongo() { > + assumeTrue(MongoAssertions.useMongo()); > } > } > > > http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java > ---------------------------------------------------------------------- > diff --git > a/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java > b/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java > new file mode 100644 > index 0000000..028286a > --- /dev/null > +++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java > @@ -0,0 +1,101 @@ > +/* > + * 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 org.apache.calcite.util.Util; > + > +import com.google.common.base.Function; > +import com.google.common.collect.Lists; > +import com.google.common.collect.Ordering; > + > +import java.sql.ResultSet; > +import java.sql.SQLException; > +import java.util.Arrays; > +import java.util.Collections; > +import java.util.List; > + > +import static org.hamcrest.CoreMatchers.equalTo; > +import static org.junit.Assert.assertThat; > +import static org.junit.Assume.assumeTrue; > + > +/** > + * Util class which needs to be in the same package as {@link CalciteAssert} > + * due to package-private visibility. > + */ > +public class MongoAssertions { > + > + private MongoAssertions() {} > + > + /** Similar to {@link CalciteAssert#checkResultUnordered}, but filters > strings > + * before comparing them. */ > + public static Function<ResultSet, Void> checkResultUnordered( > + final String... lines) { > + return new Function<ResultSet, Void>() { > + public Void apply(ResultSet resultSet) { > + try { > + final List<String> expectedList = > + Ordering.natural().immutableSortedCopy(Arrays.asList(lines)); > + > + final List<String> actualList = Lists.newArrayList(); > + CalciteAssert.toStringList(resultSet, actualList); > + for (int i = 0; i < actualList.size(); i++) { > + String s = actualList.get(i); > + actualList.set(i, > + s.replaceAll("\\.0;", ";").replaceAll("\\.0$", "")); > + } > + Collections.sort(actualList); > + > + assertThat(Ordering.natural().immutableSortedCopy(actualList), > + equalTo(expectedList)); > + return null; > + } catch (SQLException e) { > + throw new RuntimeException(e); > + } > + } > + }; > + } > + > + /** > + * Whether to run Mongo integration tests. Enabled by default, however > test is only > + * included if "it" profile is activated ({@code -Pit}). To disable, > + * specify {@code -Dcalcite.test.mongodb=false} on the Java command line. > + */ > + public static boolean useMongo() { > + return Util.getBooleanProperty("calcite.integrationTest") > + && Util.getBooleanProperty("calcite.test.mongodb", true); > + } > + > + /** > + * Checks wherever tests should use Fongo instead of Mongo. Opposite of > {@link #useMongo()}. > + */ > + public static boolean useFongo() { > + return !useMongo(); > + } > + > + > + /** > + * Used to skip tests if current instance is not mongo. Some > functionalities > + * are not available in fongo. > + * > + * @see <a > href="https://github.com/fakemongo/fongo/issues/152">Aggregation with $cond > (172)</a> > + */ > + public static void assumeRealMongoInstance() { > + assumeTrue("Expect mongo instance", useMongo()); > + } > +} > + > +// End MongoAssertions.java >