You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by mm...@apache.org on 2018/06/13 23:00:45 UTC

[1/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Repository: calcite
Updated Branches:
  refs/heads/master f84a3eb33 -> dcf396a5c


http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/mongodb/src/test/resources/mongo-foodmart-model.json
----------------------------------------------------------------------
diff --git a/mongodb/src/test/resources/mongo-foodmart-model.json b/mongodb/src/test/resources/mongo-foodmart-model.json
deleted file mode 100644
index f83ca44..0000000
--- a/mongodb/src/test/resources/mongo-foodmart-model.json
+++ /dev/null
@@ -1,221 +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.
- */
-{
-  "version": "1.0",
-  "defaultSchema": "foodmart",
-  "schemas": [
-    {
-      "type": "custom",
-      "name": "foodmart_raw",
-      "factory": "org.apache.calcite.adapter.mongodb.MongoSchemaFactory",
-      "operand": {
-        "host": "localhost",
-        "database": "foodmart"
-      }
-    },
-    {
-      "name": "foodmart",
-      "tables": [
-        {
-          "name": "sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\"\nfrom \"foodmart_raw\".\"sales_fact_1997\""
-        },
-        {
-          "name": "sales_fact_1998",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\"\nfrom \"foodmart_raw\".\"sales_fact_1998\""
-        },
-        {
-          "name": "sales_fact_dec_1998",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\"\nfrom \"foodmart_raw\".\"sales_fact_dec_1998\""
-        },
-        {
-          "name": "inventory_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['warehouse_id'] AS INTEGER) AS \"warehouse_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['units_ordered'] AS INTEGER) AS \"units_ordered\",\n cast(_MAP['units_shipped'] AS INTEGER) AS \"units_shipped\",\n cast(_MAP['warehouse_sales'] AS DECIMAL(10,4)) AS \"warehouse_sales\",\n cast(_MAP['warehouse_cost'] AS DECIMAL(10,4)) AS \"warehouse_cost\",\n cast(_MAP['supply_time'] AS SMALLINT) AS \"supply_time\",\n cast(_MAP['store_invoice'] AS DECIMAL(10,4)) AS \"store_invoice\"\nfrom \"foodmart_raw\".\"inventory_fact_1997\""
-        },
-        {
-          "name": "inventory_fact_1998",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['warehouse_id'] AS INTEGER) AS \"warehouse_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['units_ordered'] AS INTEGER) AS \"units_ordered\",\n cast(_MAP['units_shipped'] AS INTEGER) AS \"units_shipped\",\n cast(_MAP['warehouse_sales'] AS DECIMAL(10,4)) AS \"warehouse_sales\",\n cast(_MAP['warehouse_cost'] AS DECIMAL(10,4)) AS \"warehouse_cost\",\n cast(_MAP['supply_time'] AS SMALLINT) AS \"supply_time\",\n cast(_MAP['store_invoice'] AS DECIMAL(10,4)) AS \"store_invoice\"\nfrom \"foodmart_raw\".\"inventory_fact_1998\""
-        },
-        {
-          "name": "agg_pl_01_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['store_sales_sum'] AS DECIMAL(10,4)) AS \"store_sales_sum\",\n cast(_MAP['store_cost_sum'] AS DECIMAL(10,4)) AS \"store_cost_sum\",\n cast(_MAP['unit_sales_sum'] AS DECIMAL(10,4)) AS \"unit_sales_sum\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_pl_01_sales_fact_1997\""
-        },
-        {
-          "name": "agg_ll_01_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_ll_01_sales_fact_1997\""
-        },
-        {
-          "name": "agg_l_03_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_l_03_sales_fact_1997\""
-        },
-        {
-          "name": "agg_l_04_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['customer_count'] AS INTEGER) AS \"customer_count\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_l_04_sales_fact_1997\""
-        },
-        {
-          "name": "agg_l_05_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_l_05_sales_fact_1997\""
-        },
-        {
-          "name": "agg_c_10_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['month_of_year'] AS SMALLINT) AS \"month_of_year\",\n cast(_MAP['quarter'] AS VARCHAR(30)) AS \"quarter\",\n cast(_MAP['the_year'] AS SMALLINT) AS \"the_year\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['customer_count'] AS INTEGER) AS \"customer_count\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_c_10_sales_fact_1997\""
-        },
-        {
-          "name": "agg_c_14_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['month_of_year'] AS SMALLINT) AS \"month_of_year\",\n cast(_MAP['quarter'] AS VARCHAR(30)) AS \"quarter\",\n cast(_MAP['the_year'] AS SMALLINT) AS \"the_year\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_c_14_sales_fact_1997\""
-        },
-        {
-          "name": "agg_lc_100_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['quarter'] AS VARCHAR(30)) AS \"quarter\",\n cast(_MAP['the_year'] AS SMALLINT) AS \"the_year\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_lc_100_sales_fact_1997\""
-        },
-        {
-          "name": "agg_c_special_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['time_month'] AS SMALLINT) AS \"time_month\",\n cast(_MAP['time_quarter'] AS VARCHAR(30)) AS \"time_quarter\",\n cast(_MAP['time_year'] AS SMALLINT) AS \"time_year\",\n cast(_MAP['store_sales_sum'] AS DECIMAL(10,4)) AS \"store_sales_sum\",\n cast(_MAP['store_cost_sum'] AS DECIMAL(10,4)) AS \"store_cost_sum\",\n cast(_MAP['unit_sales_sum'] AS DECIMAL(10,4)) AS \"unit_sales_sum\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_c_special_sales_fact_1997\""
-        },
-        {
-          "name": "agg_g_ms_pcat_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['gender'] AS VARCHAR(30)) AS \"gender\",\n cast(_MAP['marital_status'] AS VARCHAR(30)) AS \"marital_status\",\n cast(_MAP['product_family'] AS VARCHAR(30)) AS \"product_family\",\n cast(_MAP['product_department'] AS VARCHAR(30)) AS \"product_department\",\n cast(_MAP['product_category'] AS VARCHAR(30)) AS \"product_category\",\n cast(_MAP['month_of_year'] AS SMALLINT) AS \"month_of_year\",\n cast(_MAP['quarter'] AS VARCHAR(30)) AS \"quarter\",\n cast(_MAP['the_year'] AS SMALLINT) AS \"the_year\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['customer_count'] AS INTEGER) AS \"customer_count\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_g_ms_pcat_sales_fact_1997\""
-        },
-        {
-          "name": "agg_lc_06_sales_fact_1997",
-          "type": "view",
-          "sql": "select cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['city'] AS VARCHAR(30)) AS \"city\",\n cast(_MAP['state_province'] AS VARCHAR(30)) AS \"state_province\",\n cast(_MAP['country'] AS VARCHAR(30)) AS \"country\",\n cast(_MAP['store_sales'] AS DECIMAL(10,4)) AS \"store_sales\",\n cast(_MAP['store_cost'] AS DECIMAL(10,4)) AS \"store_cost\",\n cast(_MAP['unit_sales'] AS DECIMAL(10,4)) AS \"unit_sales\",\n cast(_MAP['fact_count'] AS INTEGER) AS \"fact_count\"\nfrom \"foodmart_raw\".\"agg_lc_06_sales_fact_1997\""
-        },
-        {
-          "name": "currency",
-          "type": "view",
-          "sql": "select cast(_MAP['currency_id'] AS INTEGER) AS \"currency_id\",\n cast(_MAP['date'] AS DATE) AS \"date\",\n cast(_MAP['currency'] AS VARCHAR(30)) AS \"currency\",\n cast(_MAP['conversion_ratio'] AS DECIMAL(10,4)) AS \"conversion_ratio\"\nfrom \"foodmart_raw\".\"currency\""
-        },
-        {
-          "name": "account",
-          "type": "view",
-          "sql": "select cast(_MAP['account_id'] AS INTEGER) AS \"account_id\",\n cast(_MAP['account_parent'] AS INTEGER) AS \"account_parent\",\n cast(_MAP['account_description'] AS VARCHAR(30)) AS \"account_description\",\n cast(_MAP['account_type'] AS VARCHAR(30)) AS \"account_type\",\n cast(_MAP['account_rollup'] AS VARCHAR(30)) AS \"account_rollup\",\n cast(_MAP['Custom_Members'] AS VARCHAR(255)) AS \"Custom_Members\"\nfrom \"foodmart_raw\".\"account\""
-        },
-        {
-          "name": "category",
-          "type": "view",
-          "sql": "select cast(_MAP['category_id'] AS VARCHAR(30)) AS \"category_id\",\n cast(_MAP['category_parent'] AS VARCHAR(30)) AS \"category_parent\",\n cast(_MAP['category_description'] AS VARCHAR(30)) AS \"category_description\",\n cast(_MAP['category_rollup'] AS VARCHAR(30)) AS \"category_rollup\"\nfrom \"foodmart_raw\".\"category\""
-        },
-        {
-          "name": "customer",
-          "type": "view",
-          "sql": "select cast(_MAP['customer_id'] AS INTEGER) AS \"customer_id\",\n cast(_MAP['account_num'] AS BIGINT) AS \"account_num\",\n cast(_MAP['lname'] AS VARCHAR(30)) AS \"lname\",\n cast(_MAP['fname'] AS VARCHAR(30)) AS \"fname\",\n cast(_MAP['mi'] AS VARCHAR(30)) AS \"mi\",\n cast(_MAP['address1'] AS VARCHAR(30)) AS \"address1\",\n cast(_MAP['address2'] AS VARCHAR(30)) AS \"address2\",\n cast(_MAP['address3'] AS VARCHAR(30)) AS \"address3\",\n cast(_MAP['address4'] AS VARCHAR(30)) AS \"address4\",\n cast(_MAP['city'] AS VARCHAR(30)) AS \"city\",\n cast(_MAP['state_province'] AS VARCHAR(30)) AS \"state_province\",\n cast(_MAP['postal_code'] AS VARCHAR(30)) AS \"postal_code\",\n cast(_MAP['country'] AS VARCHAR(30)) AS \"country\",\n cast(_MAP['customer_region_id'] AS INTEGER) AS \"customer_region_id\",\n cast(_MAP['phone1'] AS VARCHAR(30)) AS \"phone1\",\n cast(_MAP['phone2'] AS VARCHAR(30)) AS \"phone2\",\n cast(_MAP['birthdate'] AS DATE) AS \"birthdate\",\n cast(_MAP['ma
 rital_status'] AS VARCHAR(30)) AS \"marital_status\",\n cast(_MAP['yearly_income'] AS VARCHAR(30)) AS \"yearly_income\",\n cast(_MAP['gender'] AS VARCHAR(30)) AS \"gender\",\n cast(_MAP['total_children'] AS SMALLINT) AS \"total_children\",\n cast(_MAP['num_children_at_home'] AS SMALLINT) AS \"num_children_at_home\",\n cast(_MAP['education'] AS VARCHAR(30)) AS \"education\",\n cast(_MAP['date_accnt_opened'] AS DATE) AS \"date_accnt_opened\",\n cast(_MAP['member_card'] AS VARCHAR(30)) AS \"member_card\",\n cast(_MAP['occupation'] AS VARCHAR(30)) AS \"occupation\",\n cast(_MAP['houseowner'] AS VARCHAR(30)) AS \"houseowner\",\n cast(_MAP['num_cars_owned'] AS INTEGER) AS \"num_cars_owned\",\n cast(_MAP['fullname'] AS VARCHAR(60)) AS \"fullname\"\nfrom \"foodmart_raw\".\"customer\""
-        },
-        {
-          "name": "days",
-          "type": "view",
-          "sql": "select cast(_MAP['day'] AS INTEGER) AS \"day\",\n cast(_MAP['week_day'] AS VARCHAR(30)) AS \"week_day\"\nfrom \"foodmart_raw\".\"days\""
-        },
-        {
-          "name": "department",
-          "type": "view",
-          "sql": "select cast(_MAP['department_id'] AS INTEGER) AS \"department_id\",\n cast(_MAP['department_description'] AS VARCHAR(30)) AS \"department_description\"\nfrom \"foodmart_raw\".\"department\""
-        },
-        {
-          "name": "employee",
-          "type": "view",
-          "sql": "select cast(_MAP['employee_id'] AS INTEGER) AS \"employee_id\",\n cast(_MAP['full_name'] AS VARCHAR(30)) AS \"full_name\",\n cast(_MAP['first_name'] AS VARCHAR(30)) AS \"first_name\",\n cast(_MAP['last_name'] AS VARCHAR(30)) AS \"last_name\",\n cast(_MAP['position_id'] AS INTEGER) AS \"position_id\",\n cast(_MAP['position_title'] AS VARCHAR(30)) AS \"position_title\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['department_id'] AS INTEGER) AS \"department_id\",\n cast(_MAP['birth_date'] AS DATE) AS \"birth_date\",\n cast(_MAP['hire_date'] AS TIMESTAMP) AS \"hire_date\",\n cast(_MAP['end_date'] AS TIMESTAMP) AS \"end_date\",\n cast(_MAP['salary'] AS DECIMAL(10,4)) AS \"salary\",\n cast(_MAP['supervisor_id'] AS INTEGER) AS \"supervisor_id\",\n cast(_MAP['education_level'] AS VARCHAR(30)) AS \"education_level\",\n cast(_MAP['marital_status'] AS VARCHAR(30)) AS \"marital_status\",\n cast(_MAP['gender'] AS VARCHAR(30)) AS \"gender\",\n cast(_MAP['ma
 nagement_role'] AS VARCHAR(30)) AS \"management_role\"\nfrom \"foodmart_raw\".\"employee\""
-        },
-        {
-          "name": "employee_closure",
-          "type": "view",
-          "sql": "select cast(_MAP['employee_id'] AS INTEGER) AS \"employee_id\",\n cast(_MAP['supervisor_id'] AS INTEGER) AS \"supervisor_id\",\n cast(_MAP['distance'] AS INTEGER) AS \"distance\"\nfrom \"foodmart_raw\".\"employee_closure\""
-        },
-        {
-          "name": "expense_fact",
-          "type": "view",
-          "sql": "select cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['account_id'] AS INTEGER) AS \"account_id\",\n cast(_MAP['exp_date'] AS TIMESTAMP) AS \"exp_date\",\n cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['category_id'] AS VARCHAR(30)) AS \"category_id\",\n cast(_MAP['currency_id'] AS INTEGER) AS \"currency_id\",\n cast(_MAP['amount'] AS DECIMAL(10,4)) AS \"amount\"\nfrom \"foodmart_raw\".\"expense_fact\""
-        },
-        {
-          "name": "position",
-          "type": "view",
-          "sql": "select cast(_MAP['position_id'] AS INTEGER) AS \"position_id\",\n cast(_MAP['position_title'] AS VARCHAR(30)) AS \"position_title\",\n cast(_MAP['pay_type'] AS VARCHAR(30)) AS \"pay_type\",\n cast(_MAP['min_scale'] AS DECIMAL(10,4)) AS \"min_scale\",\n cast(_MAP['max_scale'] AS DECIMAL(10,4)) AS \"max_scale\",\n cast(_MAP['management_role'] AS VARCHAR(30)) AS \"management_role\"\nfrom \"foodmart_raw\".\"position\""
-        },
-        {
-          "name": "product",
-          "type": "view",
-          "sql": "select cast(_MAP['product_class_id'] AS INTEGER) AS \"product_class_id\",\n cast(_MAP['product_id'] AS INTEGER) AS \"product_id\",\n cast(_MAP['brand_name'] AS VARCHAR(60)) AS \"brand_name\",\n cast(_MAP['product_name'] AS VARCHAR(60)) AS \"product_name\",\n cast(_MAP['SKU'] AS BIGINT) AS \"SKU\",\n cast(_MAP['SRP'] AS DECIMAL(10,4)) AS \"SRP\",\n cast(_MAP['gross_weight'] AS REAL) AS \"gross_weight\",\n cast(_MAP['net_weight'] AS REAL) AS \"net_weight\",\n cast(_MAP['recyclable_package'] AS BOOLEAN) AS \"recyclable_package\",\n cast(_MAP['low_fat'] AS BOOLEAN) AS \"low_fat\",\n cast(_MAP['units_per_case'] AS SMALLINT) AS \"units_per_case\",\n cast(_MAP['cases_per_pallet'] AS SMALLINT) AS \"cases_per_pallet\",\n cast(_MAP['shelf_width'] AS REAL) AS \"shelf_width\",\n cast(_MAP['shelf_height'] AS REAL) AS \"shelf_height\",\n cast(_MAP['shelf_depth'] AS REAL) AS \"shelf_depth\"\nfrom \"foodmart_raw\".\"product\""
-        },
-        {
-          "name": "product_class",
-          "type": "view",
-          "sql": "select cast(_MAP['product_class_id'] AS INTEGER) AS \"product_class_id\",\n cast(_MAP['product_subcategory'] AS VARCHAR(30)) AS \"product_subcategory\",\n cast(_MAP['product_category'] AS VARCHAR(30)) AS \"product_category\",\n cast(_MAP['product_department'] AS VARCHAR(30)) AS \"product_department\",\n cast(_MAP['product_family'] AS VARCHAR(30)) AS \"product_family\"\nfrom \"foodmart_raw\".\"product_class\""
-        },
-        {
-          "name": "promotion",
-          "type": "view",
-          "sql": "select cast(_MAP['promotion_id'] AS INTEGER) AS \"promotion_id\",\n cast(_MAP['promotion_district_id'] AS INTEGER) AS \"promotion_district_id\",\n cast(_MAP['promotion_name'] AS VARCHAR(30)) AS \"promotion_name\",\n cast(_MAP['media_type'] AS VARCHAR(30)) AS \"media_type\",\n cast(_MAP['cost'] AS DECIMAL(10,4)) AS \"cost\",\n cast(_MAP['start_date'] AS TIMESTAMP) AS \"start_date\",\n cast(_MAP['end_date'] AS TIMESTAMP) AS \"end_date\"\nfrom \"foodmart_raw\".\"promotion\""
-        },
-        {
-          "name": "region",
-          "type": "view",
-          "sql": "select cast(_MAP['region_id'] AS INTEGER) AS \"region_id\",\n cast(_MAP['sales_city'] AS VARCHAR(30)) AS \"sales_city\",\n cast(_MAP['sales_state_province'] AS VARCHAR(30)) AS \"sales_state_province\",\n cast(_MAP['sales_district'] AS VARCHAR(30)) AS \"sales_district\",\n cast(_MAP['sales_region'] AS VARCHAR(30)) AS \"sales_region\",\n cast(_MAP['sales_country'] AS VARCHAR(30)) AS \"sales_country\",\n cast(_MAP['sales_district_id'] AS INTEGER) AS \"sales_district_id\"\nfrom \"foodmart_raw\".\"region\""
-        },
-        {
-          "name": "reserve_employee",
-          "type": "view",
-          "sql": "select cast(_MAP['employee_id'] AS INTEGER) AS \"employee_id\",\n cast(_MAP['full_name'] AS VARCHAR(30)) AS \"full_name\",\n cast(_MAP['first_name'] AS VARCHAR(30)) AS \"first_name\",\n cast(_MAP['last_name'] AS VARCHAR(30)) AS \"last_name\",\n cast(_MAP['position_id'] AS INTEGER) AS \"position_id\",\n cast(_MAP['position_title'] AS VARCHAR(30)) AS \"position_title\",\n cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['department_id'] AS INTEGER) AS \"department_id\",\n cast(_MAP['birth_date'] AS TIMESTAMP) AS \"birth_date\",\n cast(_MAP['hire_date'] AS TIMESTAMP) AS \"hire_date\",\n cast(_MAP['end_date'] AS TIMESTAMP) AS \"end_date\",\n cast(_MAP['salary'] AS DECIMAL(10,4)) AS \"salary\",\n cast(_MAP['supervisor_id'] AS INTEGER) AS \"supervisor_id\",\n cast(_MAP['education_level'] AS VARCHAR(30)) AS \"education_level\",\n cast(_MAP['marital_status'] AS VARCHAR(30)) AS \"marital_status\",\n cast(_MAP['gender'] AS VARCHAR(30)) AS \"gender\"\nfrom \"foo
 dmart_raw\".\"reserve_employee\""
-        },
-        {
-          "name": "salary",
-          "type": "view",
-          "sql": "select cast(_MAP['pay_date'] AS TIMESTAMP) AS \"pay_date\",\n cast(_MAP['employee_id'] AS INTEGER) AS \"employee_id\",\n cast(_MAP['department_id'] AS INTEGER) AS \"department_id\",\n cast(_MAP['currency_id'] AS INTEGER) AS \"currency_id\",\n cast(_MAP['salary_paid'] AS DECIMAL(10,4)) AS \"salary_paid\",\n cast(_MAP['overtime_paid'] AS DECIMAL(10,4)) AS \"overtime_paid\",\n cast(_MAP['vacation_accrued'] AS REAL) AS \"vacation_accrued\",\n cast(_MAP['vacation_used'] AS REAL) AS \"vacation_used\"\nfrom \"foodmart_raw\".\"salary\""
-        },
-        {
-          "name": "store",
-          "type": "view",
-          "sql": "select cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_type'] AS VARCHAR(30)) AS \"store_type\",\n cast(_MAP['region_id'] AS INTEGER) AS \"region_id\",\n cast(_MAP['store_name'] AS VARCHAR(30)) AS \"store_name\",\n cast(_MAP['store_number'] AS INTEGER) AS \"store_number\",\n cast(_MAP['store_street_address'] AS VARCHAR(30)) AS \"store_street_address\",\n cast(_MAP['store_city'] AS VARCHAR(30)) AS \"store_city\",\n cast(_MAP['store_state'] AS VARCHAR(30)) AS \"store_state\",\n cast(_MAP['store_postal_code'] AS VARCHAR(30)) AS \"store_postal_code\",\n cast(_MAP['store_country'] AS VARCHAR(30)) AS \"store_country\",\n cast(_MAP['store_manager'] AS VARCHAR(30)) AS \"store_manager\",\n cast(_MAP['store_phone'] AS VARCHAR(30)) AS \"store_phone\",\n cast(_MAP['store_fax'] AS VARCHAR(30)) AS \"store_fax\",\n cast(_MAP['first_opened_date'] AS TIMESTAMP) AS \"first_opened_date\",\n cast(_MAP['last_remodel_date'] AS TIMESTAMP) AS \"last_remodel_date\",\n
  cast(_MAP['store_sqft'] AS INTEGER) AS \"store_sqft\",\n cast(_MAP['grocery_sqft'] AS INTEGER) AS \"grocery_sqft\",\n cast(_MAP['frozen_sqft'] AS INTEGER) AS \"frozen_sqft\",\n cast(_MAP['meat_sqft'] AS INTEGER) AS \"meat_sqft\",\n cast(_MAP['coffee_bar'] AS BOOLEAN) AS \"coffee_bar\",\n cast(_MAP['video_store'] AS BOOLEAN) AS \"video_store\",\n cast(_MAP['salad_bar'] AS BOOLEAN) AS \"salad_bar\",\n cast(_MAP['prepared_food'] AS BOOLEAN) AS \"prepared_food\",\n cast(_MAP['florist'] AS BOOLEAN) AS \"florist\"\nfrom \"foodmart_raw\".\"store\""
-        },
-        {
-          "name": "store_ragged",
-          "type": "view",
-          "sql": "select cast(_MAP['store_id'] AS INTEGER) AS \"store_id\",\n cast(_MAP['store_type'] AS VARCHAR(30)) AS \"store_type\",\n cast(_MAP['region_id'] AS INTEGER) AS \"region_id\",\n cast(_MAP['store_name'] AS VARCHAR(30)) AS \"store_name\",\n cast(_MAP['store_number'] AS INTEGER) AS \"store_number\",\n cast(_MAP['store_street_address'] AS VARCHAR(30)) AS \"store_street_address\",\n cast(_MAP['store_city'] AS VARCHAR(30)) AS \"store_city\",\n cast(_MAP['store_state'] AS VARCHAR(30)) AS \"store_state\",\n cast(_MAP['store_postal_code'] AS VARCHAR(30)) AS \"store_postal_code\",\n cast(_MAP['store_country'] AS VARCHAR(30)) AS \"store_country\",\n cast(_MAP['store_manager'] AS VARCHAR(30)) AS \"store_manager\",\n cast(_MAP['store_phone'] AS VARCHAR(30)) AS \"store_phone\",\n cast(_MAP['store_fax'] AS VARCHAR(30)) AS \"store_fax\",\n cast(_MAP['first_opened_date'] AS TIMESTAMP) AS \"first_opened_date\",\n cast(_MAP['last_remodel_date'] AS TIMESTAMP) AS \"last_remodel_date\",\n
  cast(_MAP['store_sqft'] AS INTEGER) AS \"store_sqft\",\n cast(_MAP['grocery_sqft'] AS INTEGER) AS \"grocery_sqft\",\n cast(_MAP['frozen_sqft'] AS INTEGER) AS \"frozen_sqft\",\n cast(_MAP['meat_sqft'] AS INTEGER) AS \"meat_sqft\",\n cast(_MAP['coffee_bar'] AS BOOLEAN) AS \"coffee_bar\",\n cast(_MAP['video_store'] AS BOOLEAN) AS \"video_store\",\n cast(_MAP['salad_bar'] AS BOOLEAN) AS \"salad_bar\",\n cast(_MAP['prepared_food'] AS BOOLEAN) AS \"prepared_food\",\n cast(_MAP['florist'] AS BOOLEAN) AS \"florist\"\nfrom \"foodmart_raw\".\"store_ragged\""
-        },
-        {
-          "name": "time_by_day",
-          "type": "view",
-          "sql": "select cast(_MAP['time_id'] AS INTEGER) AS \"time_id\",\n cast(_MAP['the_date'] AS TIMESTAMP) AS \"the_date\",\n cast(_MAP['the_day'] AS VARCHAR(30)) AS \"the_day\",\n cast(_MAP['the_month'] AS VARCHAR(30)) AS \"the_month\",\n cast(_MAP['the_year'] AS SMALLINT) AS \"the_year\",\n cast(_MAP['day_of_month'] AS SMALLINT) AS \"day_of_month\",\n cast(_MAP['week_of_year'] AS INTEGER) AS \"week_of_year\",\n cast(_MAP['month_of_year'] AS SMALLINT) AS \"month_of_year\",\n cast(_MAP['quarter'] AS VARCHAR(30)) AS \"quarter\",\n cast(_MAP['fiscal_period'] AS VARCHAR(30)) AS \"fiscal_period\"\nfrom \"foodmart_raw\".\"time_by_day\""
-        },
-        {
-          "name": "warehouse",
-          "type": "view",
-          "sql": "select cast(_MAP['warehouse_id'] AS INTEGER) AS \"warehouse_id\",\n cast(_MAP['warehouse_class_id'] AS INTEGER) AS \"warehouse_class_id\",\n cast(_MAP['stores_id'] AS INTEGER) AS \"stores_id\",\n cast(_MAP['warehouse_name'] AS VARCHAR(60)) AS \"warehouse_name\",\n cast(_MAP['wa_address1'] AS VARCHAR(30)) AS \"wa_address1\",\n cast(_MAP['wa_address2'] AS VARCHAR(30)) AS \"wa_address2\",\n cast(_MAP['wa_address3'] AS VARCHAR(30)) AS \"wa_address3\",\n cast(_MAP['wa_address4'] AS VARCHAR(30)) AS \"wa_address4\",\n cast(_MAP['warehouse_city'] AS VARCHAR(30)) AS \"warehouse_city\",\n cast(_MAP['warehouse_state_province'] AS VARCHAR(30)) AS \"warehouse_state_province\",\n cast(_MAP['warehouse_postal_code'] AS VARCHAR(30)) AS \"warehouse_postal_code\",\n cast(_MAP['warehouse_country'] AS VARCHAR(30)) AS \"warehouse_country\",\n cast(_MAP['warehouse_owner_name'] AS VARCHAR(30)) AS \"warehouse_owner_name\",\n cast(_MAP['warehouse_phone'] AS VARCHAR(30)) AS \"warehouse_phone
 \",\n cast(_MAP['warehouse_fax'] AS VARCHAR(30)) AS \"warehouse_fax\"\nfrom \"foodmart_raw\".\"warehouse\""
-        },
-        {
-          "name": "warehouse_class",
-          "type": "view",
-          "sql": "select cast(_MAP['warehouse_class_id'] AS INTEGER) AS \"warehouse_class_id\",\n cast(_MAP['description'] AS VARCHAR(30)) AS \"description\"\nfrom \"foodmart_raw\".\"warehouse_class\""
-        }
-      ]
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/mongodb/src/test/resources/mongo-model.json
----------------------------------------------------------------------
diff --git a/mongodb/src/test/resources/mongo-model.json b/mongodb/src/test/resources/mongo-model.json
new file mode 100644
index 0000000..5943df0
--- /dev/null
+++ b/mongodb/src/test/resources/mongo-model.json
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+{
+  "version": "1.0",
+  "defaultSchema": "mongo",
+  "schemas": [
+    {
+      "type": "custom",
+      "name": "mongo_raw",
+      "factory": "org.apache.calcite.adapter.mongodb.MongoSchemaFactory",
+      "operand": {
+        "host": "localhost",
+        "database": "test"
+      }
+    },
+    {
+      "type": "custom",
+      "name": "_foodmart",
+      "factory": "org.apache.calcite.adapter.mongodb.MongoSchemaFactory",
+      "operand": {
+        "host": "localhost",
+        "database": "foodmart"
+      }
+    },
+    {
+      "name": "mongo",
+      "tables": [
+        {
+          "name": "ZIPS",
+          "type": "view",
+          "sql": "select cast(_MAP['city'] AS varchar(20)) AS city,\n cast(_MAP['loc'][0] AS float) AS longitude, cast(_MAP['loc'][1] AS float) AS latitude, cast(_MAP['pop'] AS integer) AS pop, cast(_MAP['state'] AS varchar(2)) AS state, cast(_MAP['_id'] AS varchar(5)) AS id from \"mongo_raw\".\"zips\""
+        },
+        {
+          "name": "sales_fact_1997",
+          "type": "view",
+          "sql": "select cast(_MAP['product_id'] AS double) AS \"product_id\" from \"_foodmart\".\"sales_fact_1997\""
+        },
+        {
+          "name": "sales_fact_1998",
+          "type": "view",
+          "sql": "select cast(_MAP['product_id'] AS double) AS \"product_id\" from \"_foodmart\".\"sales_fact_1998\""
+        },
+        {
+          "name": "store",
+          "type": "view",
+          "sql": "select cast(_MAP['store_id'] AS double) AS \"store_id\", cast(_MAP['store_name'] AS varchar(20)) AS \"store_name\" from \"mongo_raw\".\"store\""
+        },
+        {
+          "name": "warehouse",
+          "type": "view",
+          "sql": "select cast(_MAP['warehouse_id'] AS double) AS \"warehouse_id\", cast(_MAP['warehouse_state_province'] AS varchar(20)) AS \"warehouse_state_province\" from \"mongo_raw\".\"warehouse\""
+        }
+      ]
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/mongodb/src/test/resources/mongo-zips-model.json
----------------------------------------------------------------------
diff --git a/mongodb/src/test/resources/mongo-zips-model.json b/mongodb/src/test/resources/mongo-zips-model.json
deleted file mode 100644
index 669e3b9..0000000
--- a/mongodb/src/test/resources/mongo-zips-model.json
+++ /dev/null
@@ -1,41 +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.
- */
-{
-  "version": "1.0",
-  "defaultSchema": "mongo",
-  "schemas": [
-    {
-      "type": "custom",
-      "name": "mongo_raw",
-      "factory": "org.apache.calcite.adapter.mongodb.MongoSchemaFactory",
-      "operand": {
-        "host": "localhost",
-        "database": "test"
-      }
-    },
-    {
-      "name": "mongo",
-      "tables": [
-        {
-          "name": "ZIPS",
-          "type": "view",
-          "sql": "select cast(_MAP['city'] AS varchar(20)) AS city,\n cast(_MAP['loc'][0] AS float) AS longitude, cast(_MAP['loc'][1] AS float) AS latitude, cast(_MAP['pop'] AS integer) AS pop, cast(_MAP['state'] AS varchar(2)) AS state, cast(_MAP['_id'] AS varchar(5)) AS id from \"mongo_raw\".\"zips\""
-        }
-      ]
-    }
-  ]
-}

http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/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
new file mode 100644
index 0000000..d70eadc
--- /dev/null
+++ b/mongodb/src/test/resources/zips-mini.json
@@ -0,0 +1,149 @@
+{ "_id" : "01701", "city" : "FRAMINGHAM", "loc" : [ -71.42548600000001, 42.300665 ], "pop" : 65046, "state" : "MA" }
+{ "_id" : "02154", "city" : "NORTH WALTHAM", "loc" : [ -71.236497, 42.382492 ], "pop" : 57871, "state" : "MA" }
+{ "_id" : "02401", "city" : "BROCKTON", "loc" : [ -71.03434799999999, 42.081571 ], "pop" : 59498, "state" : "MA" }
+{ "_id" : "02840", "city" : "MIDDLETOWN", "loc" : [ -71.30347999999999, 41.504502 ], "pop" : 47687, "state" : "RI" }
+{ "_id" : "02860", "city" : "PAWTUCKET", "loc" : [ -71.39071300000001, 41.872873 ], "pop" : 45442, "state" : "RI" }
+{ "_id" : "02895", "city" : "NORTH SMITHFIELD", "loc" : [ -71.513683, 41.99948 ], "pop" : 53733, "state" : "RI" }
+{ "_id" : "03060", "city" : "NASHUA", "loc" : [ -71.466684, 42.756395 ], "pop" : 41438, "state" : "NH" }
+{ "_id" : "03103", "city" : "MANCHESTER", "loc" : [ -71.449325, 42.965563 ], "pop" : 36613, "state" : "NH" }
+{ "_id" : "03301", "city" : "CONCORD", "loc" : [ -71.527734, 43.218525 ], "pop" : 34035, "state" : "NH" }
+{ "_id" : "04240", "city" : "LEWISTON", "loc" : [ -70.191619, 44.098538 ], "pop" : 40173, "state" : "ME" }
+{ "_id" : "04401", "city" : "BANGOR", "loc" : [ -68.791839, 44.824199 ], "pop" : 40434, "state" : "ME" }
+{ "_id" : "05301", "city" : "BRATTLEBORO", "loc" : [ -72.593322, 42.857353 ], "pop" : 17522, "state" : "VT" }
+{ "_id" : "05401", "city" : "BURLINGTON", "loc" : [ -73.219875, 44.484023 ], "pop" : 39127, "state" : "VT" }
+{ "_id" : "05701", "city" : "RUTLAND", "loc" : [ -72.97077299999999, 43.614131 ], "pop" : 22576, "state" : "VT" }
+{ "_id" : "06010", "city" : "BRISTOL", "loc" : [ -72.930193, 41.682293 ], "pop" : 60670, "state" : "CT" }
+{ "_id" : "06450", "city" : "MERIDEN", "loc" : [ -72.799734, 41.533396 ], "pop" : 59441, "state" : "CT" }
+{ "_id" : "06902", "city" : "STAMFORD", "loc" : [ -73.53742800000001, 41.052552 ], "pop" : 54605, "state" : "CT" }
+{ "_id" : "07002", "city" : "BAYONNE", "loc" : [ -74.119169, 40.666399 ], "pop" : 61444, "state" : "NJ" }
+{ "_id" : "07087", "city" : "WEEHAWKEN", "loc" : [ -74.030558, 40.768153 ], "pop" : 69646, "state" : "NJ" }
+{ "_id" : "07111", "city" : "IRVINGTON", "loc" : [ -74.23127100000001, 40.7261 ], "pop" : 60986, "state" : "NJ" }
+{ "_id" : "10021", "city" : "NEW YORK", "loc" : [ -73.958805, 40.768476 ], "pop" : 106564, "state" : "NY" }
+{ "_id" : "11226", "city" : "BROOKLYN", "loc" : [ -73.956985, 40.646694 ], "pop" : 111396, "state" : "NY" }
+{ "_id" : "11373", "city" : "JACKSON HEIGHTS", "loc" : [ -73.878551, 40.740388 ], "pop" : 88241, "state" : "NY" }
+{ "_id" : "17042", "city" : "CLEONA", "loc" : [ -76.425895, 40.335912 ], "pop" : 61993, "state" : "PA" }
+{ "_id" : "18042", "city" : "FORKS TOWNSHIP", "loc" : [ -75.23582, 40.6867 ], "pop" : 65784, "state" : "PA" }
+{ "_id" : "19143", "city" : "PHILADELPHIA", "loc" : [ -75.228819, 39.944815 ], "pop" : 80454, "state" : "PA" }
+{ "_id" : "19711", "city" : "NEWARK", "loc" : [ -75.737534, 39.701129 ], "pop" : 50573, "state" : "DE" }
+{ "_id" : "19720", "city" : "MANOR", "loc" : [ -75.589938, 39.67703 ], "pop" : 46906, "state" : "DE" }
+{ "_id" : "19901", "city" : "DOVER", "loc" : [ -75.535983, 39.156639 ], "pop" : 46005, "state" : "DE" }
+{ "_id" : "20011", "city" : "WASHINGTON", "loc" : [ -77.020251, 38.951786 ], "pop" : 62924, "state" : "DC" }
+{ "_id" : "20301", "city" : "PENTAGON", "loc" : [ -77.038196, 38.891019 ], "pop" : 21, "state" : "DC" }
+{ "_id" : "21061", "city" : "GLEN BURNIE", "loc" : [ -76.61886199999999, 39.158968 ], "pop" : 75692, "state" : "MD" }
+{ "_id" : "21207", "city" : "GWYNN OAK", "loc" : [ -76.734064, 39.329628 ], "pop" : 76002, "state" : "MD" }
+{ "_id" : "21215", "city" : "BALTIMORE", "loc" : [ -76.67939699999999, 39.344572 ], "pop" : 74402, "state" : "MD" }
+{ "_id" : "22901", "city" : "CHARLOTTESVILLE", "loc" : [ -78.490869, 38.054752 ], "pop" : 62708, "state" : "VA" }
+{ "_id" : "23464", "city" : "VIRGINIA BEACH", "loc" : [ -76.175909, 36.797772 ], "pop" : 67276, "state" : "VA" }
+{ "_id" : "23602", "city" : "NEWPORT NEWS", "loc" : [ -76.53212499999999, 37.131684 ], "pop" : 68525, "state" : "VA" }
+{ "_id" : "25801", "city" : "BECKLEY", "loc" : [ -81.206084, 37.793214 ], "pop" : 45196, "state" : "WV" }
+{ "_id" : "26003", "city" : "ELM GROVE", "loc" : [ -80.685126, 40.072736 ], "pop" : 49136, "state" : "WV" }
+{ "_id" : "26505", "city" : "STAR CITY", "loc" : [ -79.95422499999999, 39.633858 ], "pop" : 70185, "state" : "WV" }
+{ "_id" : "27292", "city" : "LEXINGTON", "loc" : [ -80.262049, 35.82306 ], "pop" : 69179, "state" : "NC" }
+{ "_id" : "28677", "city" : "STATESVILLE", "loc" : [ -80.894009, 35.799022 ], "pop" : 52895, "state" : "NC" }
+{ "_id" : "29150", "city" : "OSWEGO", "loc" : [ -80.32100800000001, 33.928199 ], "pop" : 46394, "state" : "SC" }
+{ "_id" : "29501", "city" : "FLORENCE", "loc" : [ -79.772786, 34.18375 ], "pop" : 66990, "state" : "SC" }
+{ "_id" : "29801", "city" : "AIKEN", "loc" : [ -81.71942900000001, 33.553024 ], "pop" : 51233, "state" : "SC" }
+{ "_id" : "30032", "city" : "DECATUR", "loc" : [ -84.263165, 33.740825 ], "pop" : 56056, "state" : "GA" }
+{ "_id" : "30906", "city" : "PEACH ORCHARD", "loc" : [ -82.038358, 33.402024 ], "pop" : 58646, "state" : "GA" }
+{ "_id" : "32216", "city" : "JACKSONVILLE", "loc" : [ -81.547387, 30.293907 ], "pop" : 58867, "state" : "FL" }
+{ "_id" : "33012", "city" : "HIALEAH", "loc" : [ -80.30589999999999, 25.865395 ], "pop" : 73194, "state" : "FL" }
+{ "_id" : "33311", "city" : "FORT LAUDERDALE", "loc" : [ -80.172786, 26.142104 ], "pop" : 65378, "state" : "FL" }
+{ "_id" : "35215", "city" : "CENTER POINT", "loc" : [ -86.693197, 33.635447 ], "pop" : 43862, "state" : "AL" }
+{ "_id" : "35401", "city" : "TUSCALOOSA", "loc" : [ -87.56266599999999, 33.196891 ], "pop" : 42124, "state" : "AL" }
+{ "_id" : "35901", "city" : "SOUTHSIDE", "loc" : [ -86.010279, 33.997248 ], "pop" : 44165, "state" : "AL" }
+{ "_id" : "37042", "city" : "CLARKSVILLE", "loc" : [ -87.418621, 36.585315 ], "pop" : 43296, "state" : "TN" }
+{ "_id" : "37211", "city" : "NASHVILLE", "loc" : [ -86.72403799999999, 36.072486 ], "pop" : 51478, "state" : "TN" }
+{ "_id" : "38109", "city" : "MEMPHIS", "loc" : [ -90.073238, 35.042538 ], "pop" : 60508, "state" : "TN" }
+{ "_id" : "39180", "city" : "VICKSBURG", "loc" : [ -90.85065, 32.325824 ], "pop" : 46968, "state" : "MS" }
+{ "_id" : "39401", "city" : "HATTIESBURG", "loc" : [ -89.306471, 31.314553 ], "pop" : 41866, "state" : "MS" }
+{ "_id" : "39440", "city" : "LAUREL", "loc" : [ -89.13115500000001, 31.705444 ], "pop" : 45040, "state" : "MS" }
+{ "_id" : "40214", "city" : "LOUISVILLE", "loc" : [ -85.77802699999999, 38.159318 ], "pop" : 42198, "state" : "KY" }
+{ "_id" : "40216", "city" : "SHIVELY", "loc" : [ -85.831771, 38.186138 ], "pop" : 41719, "state" : "KY" }
+{ "_id" : "40601", "city" : "HATTON", "loc" : [ -84.88061, 38.192831 ], "pop" : 46563, "state" : "KY" }
+{ "_id" : "44035", "city" : "ELYRIA", "loc" : [ -82.10508799999999, 41.372353 ], "pop" : 66674, "state" : "OH" }
+{ "_id" : "44060", "city" : "MENTOR", "loc" : [ -81.342133, 41.689468 ], "pop" : 60109, "state" : "OH" }
+{ "_id" : "44107", "city" : "EDGEWATER", "loc" : [ -81.79714300000001, 41.482654 ], "pop" : 59702, "state" : "OH" }
+{ "_id" : "46360", "city" : "MICHIGAN CITY", "loc" : [ -86.869899, 41.698031 ], "pop" : 55392, "state" : "IN" }
+{ "_id" : "47130", "city" : "JEFFERSONVILLE", "loc" : [ -85.735885, 38.307767 ], "pop" : 56543, "state" : "IN" }
+{ "_id" : "47906", "city" : "WEST LAFAYETTE", "loc" : [ -86.923661, 40.444025 ], "pop" : 54702, "state" : "IN" }
+{ "_id" : "48180", "city" : "TAYLOR", "loc" : [ -83.267269, 42.231738 ], "pop" : 70811, "state" : "MI" }
+{ "_id" : "48185", "city" : "WESTLAND", "loc" : [ -83.374908, 42.318882 ], "pop" : 84712, "state" : "MI" }
+{ "_id" : "48227", "city" : "DETROIT", "loc" : [ -83.193732, 42.388303 ], "pop" : 68390, "state" : "MI" }
+{ "_id" : "50010", "city" : "AMES", "loc" : [ -93.639398, 42.029859 ], "pop" : 52105, "state" : "IA" }
+{ "_id" : "50317", "city" : "PLEASANT HILL", "loc" : [ -93.549446, 41.612499 ], "pop" : 39883, "state" : "IA" }
+{ "_id" : "52001", "city" : "DUBUQUE", "loc" : [ -90.68191400000001, 42.514977 ], "pop" : 41934, "state" : "IA" }
+{ "_id" : "53209", "city" : "MILWAUKEE", "loc" : [ -87.947834, 43.118765 ], "pop" : 51008, "state" : "WI" }
+{ "_id" : "54401", "city" : "WAUSAU", "loc" : [ -89.633955, 44.963433 ], "pop" : 51083, "state" : "WI" }
+{ "_id" : "54901", "city" : "OSHKOSH", "loc" : [ -88.54363499999999, 44.021962 ], "pop" : 57187, "state" : "WI" }
+{ "_id" : "55106", "city" : "SAINT PAUL", "loc" : [ -93.048817, 44.968384 ], "pop" : 47905, "state" : "MN" }
+{ "_id" : "55112", "city" : "NEW BRIGHTON", "loc" : [ -93.199691, 45.074129 ], "pop" : 44128, "state" : "MN" }
+{ "_id" : "55337", "city" : "BURNSVILLE", "loc" : [ -93.275283, 44.76086 ], "pop" : 51421, "state" : "MN" }
+{ "_id" : "57103", "city" : "SIOUX FALLS", "loc" : [ -96.686415, 43.537386 ], "pop" : 32508, "state" : "SD" }
+{ "_id" : "57401", "city" : "ABERDEEN", "loc" : [ -98.485642, 45.466109 ], "pop" : 28786, "state" : "SD" }
+{ "_id" : "57701", "city" : "ROCKERVILLE", "loc" : [ -103.200259, 44.077041 ], "pop" : 45328, "state" : "SD" }
+{ "_id" : "58103", "city" : "FARGO", "loc" : [ -96.812252, 46.856406 ], "pop" : 38483, "state" : "ND" }
+{ "_id" : "58501", "city" : "BISMARCK", "loc" : [ -100.774755, 46.823448 ], "pop" : 36602, "state" : "ND" }
+{ "_id" : "58701", "city" : "MINOT", "loc" : [ -101.298476, 48.22914 ], "pop" : 42195, "state" : "ND" }
+{ "_id" : "59102", "city" : "BILLINGS", "loc" : [ -108.572662, 45.781265 ], "pop" : 40121, "state" : "MT" }
+{ "_id" : "59601", "city" : "HELENA", "loc" : [ -112.021283, 46.613066 ], "pop" : 40102, "state" : "MT" }
+{ "_id" : "59801", "city" : "MISSOULA", "loc" : [ -114.025207, 46.856274 ], "pop" : 33811, "state" : "MT" }
+{ "_id" : "60623", "city" : "CHICAGO", "loc" : [ -87.7157, 41.849015 ], "pop" : 112047, "state" : "IL" }
+{ "_id" : "60634", "city" : "NORRIDGE", "loc" : [ -87.796054, 41.945213 ], "pop" : 69160, "state" : "IL" }
+{ "_id" : "60650", "city" : "CICERO", "loc" : [ -87.76008, 41.84776 ], "pop" : 67670, "state" : "IL" }
+{ "_id" : "63031", "city" : "FLORISSANT", "loc" : [ -90.340097, 38.806865 ], "pop" : 52659, "state" : "MO" }
+{ "_id" : "63116", "city" : "SAINT LOUIS", "loc" : [ -90.26254299999999, 38.581356 ], "pop" : 49014, "state" : "MO" }
+{ "_id" : "63136", "city" : "JENNINGS", "loc" : [ -90.260189, 38.738878 ], "pop" : 54994, "state" : "MO" }
+{ "_id" : "66502", "city" : "MANHATTAN", "loc" : [ -96.585776, 39.193757 ], "pop" : 50178, "state" : "KS" }
+{ "_id" : "67212", "city" : "WICHITA", "loc" : [ -97.438344, 37.700683 ], "pop" : 41349, "state" : "KS" }
+{ "_id" : "67401", "city" : "BAVARIA", "loc" : [ -97.60878700000001, 38.823802 ], "pop" : 45208, "state" : "KS" }
+{ "_id" : "68104", "city" : "OMAHA", "loc" : [ -95.999888, 41.29186 ], "pop" : 35325, "state" : "NE" }
+{ "_id" : "68502", "city" : "LINCOLN", "loc" : [ -96.693763, 40.789282 ], "pop" : 27576, "state" : "NE" }
+{ "_id" : "68847", "city" : "KEARNEY", "loc" : [ -99.077883, 40.713608 ], "pop" : 28674, "state" : "NE" }
+{ "_id" : "70072", "city" : "MARRERO", "loc" : [ -90.110462, 29.859756 ], "pop" : 58905, "state" : "LA" }
+{ "_id" : "70117", "city" : "NEW ORLEANS", "loc" : [ -90.03124, 29.970298 ], "pop" : 56494, "state" : "LA" }
+{ "_id" : "70560", "city" : "NEW IBERIA", "loc" : [ -91.819959, 30.001027 ], "pop" : 56105, "state" : "LA" }
+{ "_id" : "72032", "city" : "CONWAY", "loc" : [ -92.423574, 35.084199 ], "pop" : 43236, "state" : "AR" }
+{ "_id" : "72076", "city" : "GRAVEL RIDGE", "loc" : [ -92.13043500000001, 34.881985 ], "pop" : 37428, "state" : "AR" }
+{ "_id" : "72401", "city" : "JONESBORO", "loc" : [ -90.69652600000001, 35.833016 ], "pop" : 53532, "state" : "AR" }
+{ "_id" : "73034", "city" : "EDMOND", "loc" : [ -97.47983499999999, 35.666483 ], "pop" : 43814, "state" : "OK" }
+{ "_id" : "73505", "city" : "LAWTON", "loc" : [ -98.455234, 34.617939 ], "pop" : 45542, "state" : "OK" }
+{ "_id" : "74801", "city" : "SHAWNEE", "loc" : [ -96.931321, 35.34907 ], "pop" : 40076, "state" : "OK" }
+{ "_id" : "78207", "city" : "SAN ANTONIO", "loc" : [ -98.52596699999999, 29.422855 ], "pop" : 58355, "state" : "TX" }
+{ "_id" : "78521", "city" : "BROWNSVILLE", "loc" : [ -97.461236, 25.922103 ], "pop" : 79463, "state" : "TX" }
+{ "_id" : "78572", "city" : "ALTON", "loc" : [ -98.342647, 26.24153 ], "pop" : 67604, "state" : "TX" }
+{ "_id" : "80123", "city" : "BOW MAR", "loc" : [ -105.07766, 39.596854 ], "pop" : 59418, "state" : "CO" }
+{ "_id" : "80221", "city" : "FEDERAL HEIGHTS", "loc" : [ -105.007985, 39.840562 ], "pop" : 54069, "state" : "CO" }
+{ "_id" : "80631", "city" : "GARDEN CITY", "loc" : [ -104.704756, 40.413968 ], "pop" : 53905, "state" : "CO" }
+{ "_id" : "82001", "city" : "CHEYENNE", "loc" : [ -104.796234, 41.143719 ], "pop" : 33107, "state" : "WY" }
+{ "_id" : "82070", "city" : "LARAMIE", "loc" : [ -105.581146, 41.312907 ], "pop" : 29327, "state" : "WY" }
+{ "_id" : "82716", "city" : "GILLETTE", "loc" : [ -105.497442, 44.282009 ], "pop" : 25968, "state" : "WY" }
+{ "_id" : "83301", "city" : "TWIN FALLS", "loc" : [ -114.469265, 42.556495 ], "pop" : 34539, "state" : "ID" }
+{ "_id" : "83704", "city" : "BOISE", "loc" : [ -116.295099, 43.633001 ], "pop" : 40912, "state" : "ID" }
+{ "_id" : "83814", "city" : "COEUR D ALENE", "loc" : [ -116.784976, 47.692841 ], "pop" : 33589, "state" : "ID" }
+{ "_id" : "84118", "city" : "KEARNS", "loc" : [ -111.98521, 40.652759 ], "pop" : 55999, "state" : "UT" }
+{ "_id" : "84120", "city" : "WEST VALLEY CITY", "loc" : [ -112.009783, 40.68708 ], "pop" : 52854, "state" : "UT" }
+{ "_id" : "84604", "city" : "PROVO", "loc" : [ -111.654906, 40.260681 ], "pop" : 43841, "state" : "UT" }
+{ "_id" : "85023", "city" : "PHOENIX", "loc" : [ -112.111838, 33.632383 ], "pop" : 54668, "state" : "AZ" }
+{ "_id" : "85204", "city" : "MESA", "loc" : [ -111.789554, 33.399168 ], "pop" : 55180, "state" : "AZ" }
+{ "_id" : "85364", "city" : "YUMA", "loc" : [ -114.642362, 32.701507 ], "pop" : 57131, "state" : "AZ" }
+{ "_id" : "87501", "city" : "POJOAQUE VALLEY", "loc" : [ -105.974818, 35.702472 ], "pop" : 51715, "state" : "NM" }
+{ "_id" : "88001", "city" : "LAS CRUCES", "loc" : [ -106.746034, 32.321641 ], "pop" : 57502, "state" : "NM" }
+{ "_id" : "88201", "city" : "ROSWELL", "loc" : [ -104.525857, 33.388504 ], "pop" : 53644, "state" : "NM" }
+{ "_id" : "89031", "city" : "NORTH LAS VEGAS", "loc" : [ -115.124832, 36.206228 ], "pop" : 48113, "state" : "NV" }
+{ "_id" : "89115", "city" : "LAS VEGAS", "loc" : [ -115.067062, 36.215818 ], "pop" : 51532, "state" : "NV" }
+{ "_id" : "89502", "city" : "RENO", "loc" : [ -119.776395, 39.497239 ], "pop" : 38332, "state" : "NV" }
+{ "_id" : "90011", "city" : "LOS ANGELES", "loc" : [ -118.258189, 34.007856 ], "pop" : 96074, "state" : "CA" }
+{ "_id" : "90201", "city" : "BELL GARDENS", "loc" : [ -118.17205, 33.969177 ], "pop" : 99568, "state" : "CA" }
+{ "_id" : "90650", "city" : "NORWALK", "loc" : [ -118.081767, 33.90564 ], "pop" : 94188, "state" : "CA" }
+{ "_id" : "96734", "city" : "KAILUA", "loc" : [ -157.744781, 21.406262 ], "pop" : 53403, "state" : "HI" }
+{ "_id" : "96744", "city" : "KANEOHE", "loc" : [ -157.811543, 21.422819 ], "pop" : 55236, "state" : "HI" }
+{ "_id" : "96818", "city" : "HONOLULU", "loc" : [ -157.926925, 21.353173 ], "pop" : 62915, "state" : "HI" }
+{ "_id" : "97005", "city" : "BEAVERTON", "loc" : [ -122.805395, 45.475035 ], "pop" : 46660, "state" : "OR" }
+{ "_id" : "97206", "city" : "PORTLAND", "loc" : [ -122.59727, 45.483995 ], "pop" : 43134, "state" : "OR" }
+{ "_id" : "97301", "city" : "SALEM", "loc" : [ -122.979692, 44.926039 ], "pop" : 48007, "state" : "OR" }
+{ "_id" : "98031", "city" : "KENT", "loc" : [ -122.193184, 47.388004 ], "pop" : 50515, "state" : "WA" }
+{ "_id" : "98059", "city" : "RENTON", "loc" : [ -122.151178, 47.467383 ], "pop" : 48197, "state" : "WA" }
+{ "_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

http://git-wip-us.apache.org/repos/asf/calcite/blob/dcf396a5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2742011..ee166ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@ limitations under the License.
     <git-commit-id-plugin.version>2.1.9</git-commit-id-plugin.version>
     <geode.version>1.3.0</geode.version>
     <fongo.version>2.1.1</fongo.version>
+    <foodmart-data-json.version>0.4</foodmart-data-json.version>
 
     <!-- We support (and test against) Guava versions between
          19.0 and 23.0. Default is 19.0 due to Cassandra adapter. -->
@@ -466,6 +467,11 @@ limitations under the License.
         <version>${fongo.version}</version>
       </dependency>
       <dependency>
+        <groupId>net.hydromatic</groupId>
+        <artifactId>foodmart-data-json</artifactId>
+        <version>${foodmart-data-json.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.openjdk.jmh</groupId>
         <artifactId>jmh-core</artifactId>
         <version>${jmh.version}</version>
@@ -840,6 +846,9 @@ limitations under the License.
                 <threadCount>6</threadCount>
                 <parallel>both</parallel>
                 <argLine>-Xmx1024m</argLine>
+                <systemPropertyVariables>
+                  <calcite.integrationTest>true</calcite.integrationTest>
+                </systemPropertyVariables>
               </configuration>
             </execution>
             <execution>


Re: [2/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Posted by Michael Mior <mm...@apache.org>.
Fixing now.
--
Michael Mior
mmior@apache.org


Le jeu. 14 juin 2018 à 10:42, Julian Hyde <jh...@apache.org> a écrit :

> 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, mmior@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 <an...@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"
> > -      + "

Re: [2/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Posted by Andrei Sereda <an...@sereda.cc>.
Sorry it was my commit. I should have run site (javadoc) task before
submitting PR.

On Thu, Jun 14, 2018 at 11:05 AM Michael Mior <mm...@apache.org> wrote:

> Done. Thanks for consistently running those tests.
> --
> Michael Mior
> mmior@apache.org
>
>
> Le jeu. 14 juin 2018 à 10:42, Julian Hyde <jh...@apache.org> a écrit :
>
> > 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, mmior@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 <an...@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)
> > > +

Re: [2/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Posted by Michael Mior <mm...@apache.org>.
Done. Thanks for consistently running those tests.
--
Michael Mior
mmior@apache.org


Le jeu. 14 juin 2018 à 10:42, Julian Hyde <jh...@apache.org> a écrit :

> 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, mmior@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 <an...@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"
> > -      + "

Re: [2/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Posted by Julian Hyde <jh...@apache.org>.
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, mmior@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 <an...@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
> 



[2/2] calcite git commit: [CALCITE-2345] Running Unit tests with Fongo and integration tests with real mongo instance (Andrei Sereda)

Posted by mm...@apache.org.
[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 <an...@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