Repository: metamodel
Updated Branches:
  refs/heads/master 6fc258f8e -> 39947f559


http://git-wip-us.apache.org/repos/asf/metamodel/blob/39947f55/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
----------------------------------------------------------------------
diff --git 
a/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
 
b/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
index c7a7487..c625103 100644
--- 
a/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
+++ 
b/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
@@ -26,11 +26,13 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.function.Consumer;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import org.apache.metamodel.DataContext;
 import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.MetaModelHelper;
 import org.apache.metamodel.QueryPostprocessDataContext;
 import org.apache.metamodel.UpdateScript;
 import org.apache.metamodel.UpdateSummary;
@@ -71,10 +73,8 @@ import com.mongodb.client.MongoIterable;
 /**
  * DataContext implementation for MongoDB.
  *
- * Since MongoDB has no schema, a virtual schema will be used in this
- * DataContext. This implementation supports either automatic discovery of a
- * schema or manual specification of a schema, through the
- * {@link SimpleTableDef} class.
+ * Since MongoDB has no schema, a virtual schema will be used in this 
DataContext. This implementation supports either
+ * automatic discovery of a schema or manual specification of a schema, 
through the {@link SimpleTableDef} class.
  */
 public class MongoDbDataContext extends QueryPostprocessDataContext implements 
UpdateableDataContext {
 
@@ -86,17 +86,13 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     private Schema _schema;
 
     /**
-     * Constructs a {@link MongoDbDataContext}. This constructor accepts a
-     * custom array of {@link SimpleTableDef}s which allows the user to define
-     * his own view on the collections in the database.
+     * Constructs a {@link MongoDbDataContext}. This constructor accepts a 
custom array of {@link SimpleTableDef}s which
+     * allows the user to define his own view on the collections in the 
database.
      *
-     * @param mongoDb
-     *            the mongo db connection
-     * @param tableDefs
-     *            an array of {@link SimpleTableDef}s, which define the table
-     *            and column model of the mongo db collections. (consider using
-     *            {@link #detectSchema(MongoDatabase)} or {@link 
#detectTable(MongoDatabase, String)}
-     *            ).
+     * @param mongoDb the mongo db connection
+     * @param tableDefs an array of {@link SimpleTableDef}s, which define the 
table and column model of the mongo db
+     *            collections. (consider using {@link 
#detectSchema(MongoDatabase)} or
+     *            {@link #detectTable(MongoDatabase, String)} ).
      */
     public MongoDbDataContext(MongoDatabase mongoDb, SimpleTableDef... 
tableDefs) {
         super(false);
@@ -106,25 +102,21 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     }
 
     /**
-     * Constructs a {@link MongoDbDataContext} and automatically detects the
-     * schema structure/view on all collections (see {@link 
#detectSchema(MongoDatabase)}).
+     * Constructs a {@link MongoDbDataContext} and automatically detects the 
schema structure/view on all collections
+     * (see {@link #detectSchema(MongoDatabase)}).
      *
-     * @param mongoDb
-     *            the mongo db connection
+     * @param mongoDb the mongo db connection
      */
     public MongoDbDataContext(MongoDatabase mongoDb) {
         this(mongoDb, detectSchema(mongoDb));
     }
 
     /**
-     * Performs an analysis of the available collections in a Mongo {@link DB}
-     * instance and tries to detect the table's structure based on the first
-     * 1000 documents in each collection.
+     * Performs an analysis of the available collections in a Mongo {@link DB} 
instance and tries to detect the table's
+     * structure based on the first 1000 documents in each collection.
      *
-     * @param mongoDb
-     *            the mongo db to inspect
-     * @return a mutable schema instance, useful for further fine tuning by the
-     *         user.
+     * @param mongoDb the mongo db to inspect
+     * @return a mutable schema instance, useful for further fine tuning by 
the user.
      * @see #detectTable(MongoDatabase, String)
      */
     public static SimpleTableDef[] detectSchema(MongoDatabase mongoDb) {
@@ -139,18 +131,15 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     }
 
     /**
-     * Performs an analysis of an available collection in a Mongo {@link DB}
-     * instance and tries to detect the table structure based on the first 1000
-     * documents in the collection.
+     * Performs an analysis of an available collection in a Mongo {@link DB} 
instance and tries to detect the table
+     * structure based on the first 1000 documents in the collection.
      *
-     * @param mongoDb
-     *            the mongo DB
-     * @param collectionName
-     *            the name of the collection
+     * @param mongoDb the mongo DB
+     * @param collectionName the name of the collection
      * @return a table definition for mongo db.
      */
     public static SimpleTableDef detectTable(MongoDatabase mongoDb, String 
collectionName) {
-        
+
         final MongoCollection<Document> collection = 
mongoDb.getCollection(collectionName);
         final FindIterable<Document> iterable = collection.find().limit(1000);
 
@@ -169,7 +158,7 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
                 }
             }
         }
-           
+
         final String[] columnNames = new String[columnsAndTypes.size()];
         final ColumnType[] columnTypes = new 
ColumnType[columnsAndTypes.size()];
 
@@ -226,7 +215,15 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     protected Number executeCountQuery(Table table, List<FilterItem> 
whereItems, boolean functionApproximationAllowed) {
         final MongoCollection<Document> collection = 
_mongoDb.getCollection(table.getName());
 
-        final Document query = createMongoDbQuery(table, whereItems);
+        final List<FilterItem> postProcessFilters = new ArrayList<>();
+        final Document query = createMongoDbQuery(table, whereItems, whereItem 
-> {
+            postProcessFilters.add(whereItem);
+        });
+
+        if (!postProcessFilters.isEmpty()) {
+            // not possible to use the native API for this
+            return null;
+        }
 
         logger.info("Executing MongoDB 'count' query: {}", query);
         final long count = collection.count(query);
@@ -239,16 +236,16 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
             Object keyValue) {
         final MongoCollection<Document> collection = 
_mongoDb.getCollection(table.getName());
 
-        List<FilterItem> whereItems = new ArrayList<FilterItem>();
-        SelectItem selectItem = new SelectItem(primaryKeyColumn);
-        FilterItem primaryKeyWhereItem = new FilterItem(selectItem, 
OperatorType.EQUALS_TO, keyValue);
+        final List<FilterItem> whereItems = new ArrayList<FilterItem>();
+        final SelectItem selectItem = new SelectItem(primaryKeyColumn);
+        final FilterItem primaryKeyWhereItem = new FilterItem(selectItem, 
OperatorType.EQUALS_TO, keyValue);
         whereItems.add(primaryKeyWhereItem);
-        final Document query = createMongoDbQuery(table, whereItems);
+        final Document query = createMongoDbQuery(table, whereItems, null);
         final Document resultDoc = collection.find(query).first();
 
-        DataSetHeader header = new SimpleDataSetHeader(selectItems);
+        final DataSetHeader header = new SimpleDataSetHeader(selectItems);
 
-        Row row = MongoDBUtils.toRow(resultDoc, header);
+        final Row row = MongoDBUtils.toRow(resultDoc, header);
 
         return row;
     }
@@ -289,7 +286,6 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
 
                     // prepare for a non-post-processed query
 
-
                     // checking if the query is a primary key lookup query
                     if (whereItems.size() == 1) {
                         final FilterItem whereItem = whereItems.get(0);
@@ -297,12 +293,14 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
                         if (!whereItem.isCompoundFilter() && selectItem != 
null && selectItem.getColumn() != null) {
                             final Column column = selectItem.getColumn();
                             if (column.isPrimaryKey() && 
OperatorType.EQUALS_TO.equals(whereItem.getOperator())) {
-                                logger.debug("Query is a primary key lookup 
query. Trying executePrimaryKeyLookupQuery(...)");
+                                logger.debug(
+                                        "Query is a primary key lookup query. 
Trying executePrimaryKeyLookupQuery(...)");
                                 final Object operand = whereItem.getOperand();
                                 final Row row = 
executePrimaryKeyLookupQuery(table, selectItems, column, operand);
                                 if (row == null) {
-                                    logger.debug("DataContext did not return 
any primary key lookup query results. Proceeding "
-                                            + "with manual lookup.");
+                                    logger.debug(
+                                            "DataContext did not return any 
primary key lookup query results. Proceeding "
+                                                    + "with manual lookup.");
                                 } else {
                                     final DataSetHeader header = new 
SimpleDataSetHeader(selectItems);
                                     return new InMemoryDataSet(header, row);
@@ -324,16 +322,12 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
                     }
 
                     if (thereIsAtLeastOneAlias) {
-                        final DataSet dataSet = 
materializeMainSchemaTableInternal(
-                                table,
-                                selectItems,
-                                whereItems,
-                                firstRow,
-                                maxRows, false);
+                        final DataSet dataSet = 
materializeMainSchemaTableInternal(table, selectItems, whereItems,
+                                firstRow, maxRows, false);
                         return dataSet;
                     } else {
-                        final DataSet dataSet = 
materializeMainSchemaTableInternal(table, selectItems, whereItems, firstRow,
-                                maxRows, false);
+                        final DataSet dataSet = 
materializeMainSchemaTableInternal(table, selectItems, whereItems,
+                                firstRow, maxRows, false);
                         return dataSet;
                     }
                 }
@@ -344,19 +338,38 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
         return super.executeQuery(query);
     }
 
+    private DataSet materializeMainSchemaTableInternal(Table table, 
List<SelectItem> selectItems,
+            List<FilterItem> whereItems, int firstRow, int maxRows, boolean 
queryPostProcessed) {
+        final List<FilterItem> postProcessWhereItems = new ArrayList<>();
+        final MongoCursor<Document> cursor = getDocumentMongoCursor(table, 
whereItems, firstRow, maxRows, whereItem -> {
+            postProcessWhereItems.add(whereItem);
+        });
 
-    private DataSet materializeMainSchemaTableInternal(Table table, 
List<SelectItem> selectItems, List<FilterItem> whereItems,
-            int firstRow, int maxRows, boolean queryPostProcessed) {
-        MongoCursor<Document> cursor = getDocumentMongoCursor(table, 
whereItems, firstRow, maxRows);
-
-        return new MongoDbDataSet(cursor, selectItems, queryPostProcessed);
+        final DataSet dataSet;
+        if (postProcessWhereItems.isEmpty()) {
+            dataSet = new MongoDbDataSet(cursor, selectItems, 
queryPostProcessed);
+        } else {
+            final List<SelectItem> selectItemsToQuery = new 
ArrayList<>(selectItems);
+            postProcessWhereItems.forEach(whereItem -> {
+                final Column column = whereItem.getSelectItem().getColumn();
+                if (column != null) {
+                    // TODO: Minor optimization possible here to avoid having 
multiple select items for the same column.
+                    // We could check if the column is already being queried.
+                    selectItemsToQuery.add(new SelectItem(column));
+                }
+            });
+            final DataSet innerDataSet1 = new MongoDbDataSet(cursor, 
selectItemsToQuery, queryPostProcessed);
+            final DataSet innerDataSet2 = 
MetaModelHelper.getFiltered(innerDataSet1, postProcessWhereItems);
+            dataSet = MetaModelHelper.getSelection(selectItems, innerDataSet2);
+        }
+        return dataSet;
     }
 
     private MongoCursor<Document> getDocumentMongoCursor(Table table, 
List<FilterItem> whereItems, int firstRow,
-            int maxRows) {
+            int maxRows, Consumer<FilterItem> 
filterItemsToPostProcessConsumer) {
         final MongoCollection<Document> collection = 
_mongoDb.getCollection(table.getName());
 
-        final Document query = createMongoDbQuery(table, whereItems);
+        final Document query = createMongoDbQuery(table, whereItems, 
filterItemsToPostProcessConsumer);
 
         logger.info("Executing MongoDB 'find' query: {}", query);
         FindIterable<Document> iterable = collection.find(query);
@@ -372,13 +385,18 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
         return iterable.iterator();
     }
 
-    protected Document createMongoDbQuery(Table table, List<FilterItem> 
whereItems) {
+    protected Document createMongoDbQuery(Table table, List<FilterItem> 
whereItems,
+            Consumer<FilterItem> whereItemToPostProcessConsumer) {
         assert _schema == table.getSchema();
 
         final Document query = new Document();
         if (whereItems != null && !whereItems.isEmpty()) {
             for (FilterItem item : whereItems) {
-                convertToCursorObject(query, item);
+                final boolean converted = convertToCursorObject(query, item);
+                if (!converted) {
+                    // it wasn't possible to push down the filter item
+                    whereItemToPostProcessConsumer.accept(item);
+                }
             }
         }
 
@@ -387,52 +405,74 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
 
     private static Object convertArrayToList(Object arr) {
         if (arr instanceof boolean[]) {
-            return Arrays.asList((boolean[])arr);
+            return Arrays.asList((boolean[]) arr);
         } else if (arr instanceof byte[]) {
-            return Arrays.asList((byte[])arr);
+            return Arrays.asList((byte[]) arr);
         } else if (arr instanceof short[]) {
-            return Arrays.asList((short[])arr);
+            return Arrays.asList((short[]) arr);
         } else if (arr instanceof char[]) {
-            return Arrays.asList((char[])arr);
+            return Arrays.asList((char[]) arr);
         } else if (arr instanceof int[]) {
-            return Arrays.asList((int[])arr);
+            return Arrays.asList((int[]) arr);
         } else if (arr instanceof long[]) {
-            return Arrays.asList((long[])arr);
+            return Arrays.asList((long[]) arr);
         } else if (arr instanceof float[]) {
-            return Arrays.asList((float[])arr);
+            return Arrays.asList((float[]) arr);
         } else if (arr instanceof double[]) {
-            return Arrays.asList((double[])arr);
+            return Arrays.asList((double[]) arr);
         } else if (arr instanceof Object[]) {
-            return Arrays.asList((Object[])arr);
+            return Arrays.asList((Object[]) arr);
         }
         // It's not an array.
         return null;
     }
-    
-    private void convertToCursorObject(Document query, FilterItem item) {
+
+    /**
+     * Attempts to convert a FilterItem into a refinement of a MongoDB query
+     * 
+     * @param query
+     * @param item
+     * @return true if the conversion was successful, false if not
+     */
+    private boolean convertToCursorObject(Document query, FilterItem item) {
         if (item.isCompoundFilter()) {
 
-            List<Document> orList = new ArrayList<Document>();
+            final List<Document> orList = new ArrayList<Document>();
 
             final FilterItem[] childItems = item.getChildItems();
             for (FilterItem childItem : childItems) {
-                Document childDoc = new Document();
-                convertToCursorObject(childDoc, childItem);
+                final Document childDoc = new Document();
+                boolean converted = convertToCursorObject(childDoc, childItem);
+                if (!converted) {
+                    return false;
+                }
                 orList.add(childDoc);
             }
 
             query.put("$or", orList);
-
+            return true;
         } else {
 
-            final Column column = item.getSelectItem().getColumn();
+            final SelectItem selectItem = item.getSelectItem();
+            if (selectItem.hasFunction()) {
+                // at this point, (scalar) functions in filters aren't 
possible to push down to the query
+                return false;
+            }
+
+            final Column column = selectItem.getColumn();
             final String columnName = column.getName();
-            final String operatorName = getOperatorName(item);
+            final String operatorName;
+            try {
+                operatorName = getOperatorName(item);
+            } catch (UnsupportedOperationException e) {
+                // not possible to push this operator down to the query
+                return false;
+            }
 
             Object operand = item.getOperand();
             if (ObjectId.isValid(String.valueOf(operand))) {
                 operand = new ObjectId(String.valueOf(operand));
-            } else if (operand != null && operand.getClass().isArray()){
+            } else if (operand != null && operand.getClass().isArray()) {
                 operand = convertArrayToList(operand);
             }
 
@@ -449,15 +489,18 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
                 }
             } else {
                 if (operatorName == null) {
-                    throw new IllegalStateException("Cannot retrieve records 
for a column with two EQUALS_TO operators");
+                    throw new IllegalStateException(
+                            "Cannot retrieve records for a column with two 
EQUALS_TO operators");
                 } else {
                     existingFilterObject.append(operatorName, operand);
                 }
             }
+
+            return true;
         }
     }
 
-    private String getOperatorName(FilterItem item) {
+    private String getOperatorName(FilterItem item) throws 
UnsupportedOperationException {
         final OperatorType operator = item.getOperator();
 
         if (OperatorType.EQUALS_TO.equals(operator)) {
@@ -485,7 +528,7 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
             return "$in";
         }
 
-        throw new IllegalStateException("Unsupported operator type: " + 
operator);
+        throw new UnsupportedOperationException("Unsupported operator type: " 
+ operator);
     }
 
     private Pattern turnOperandIntoRegExp(Object operand) {
@@ -501,24 +544,14 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     @Override
     protected DataSet materializeMainSchemaTable(Table table, List<Column> 
columns, int maxRows) {
 
-        return materializeMainSchemaTableInternal(
-                table,
-                
columns.stream().map(SelectItem::new).collect(Collectors.toList()),
-                null,
-                1,
-                maxRows,
-                true);
+        return materializeMainSchemaTableInternal(table,
+                
columns.stream().map(SelectItem::new).collect(Collectors.toList()), null, 1, 
maxRows, true);
     }
 
     @Override
     protected DataSet materializeMainSchemaTable(Table table, List<Column> 
columns, int firstRow, int maxRows) {
-        return materializeMainSchemaTableInternal(
-                table,
-                
columns.stream().map(SelectItem::new).collect(Collectors.toList()),
-                null,
-                firstRow,
-                maxRows,
-                true);
+        return materializeMainSchemaTableInternal(table,
+                
columns.stream().map(SelectItem::new).collect(Collectors.toList()), null, 
firstRow, maxRows, true);
     }
 
     /**
@@ -547,8 +580,7 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     }
 
     /**
-     * Gets the {@link WriteConcernAdvisor} to use on
-     * {@link #executeUpdate(UpdateScript)} calls.
+     * Gets the {@link WriteConcernAdvisor} to use on {@link 
#executeUpdate(UpdateScript)} calls.
      */
     public WriteConcernAdvisor getWriteConcernAdvisor() {
         if (_writeConcernAdvisor == null) {
@@ -558,8 +590,7 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
     }
 
     /**
-     * Sets a global {@link WriteConcern} advisor to use on
-     * {@link #executeUpdate(UpdateScript)}.
+     * Sets a global {@link WriteConcern} advisor to use on {@link 
#executeUpdate(UpdateScript)}.
      */
     public void setWriteConcernAdvisor(WriteConcernAdvisor 
writeConcernAdvisor) {
         _writeConcernAdvisor = writeConcernAdvisor;
@@ -567,7 +598,8 @@ public class MongoDbDataContext extends 
QueryPostprocessDataContext implements U
 
     /**
      * Gets the {@link DB} instance that this {@link DataContext} is backed by.
-     * @return 
+     * 
+     * @return
      */
     public MongoDatabase getMongoDb() {
         return _mongoDb;

http://git-wip-us.apache.org/repos/asf/metamodel/blob/39947f55/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDeleteBuilder.java
----------------------------------------------------------------------
diff --git 
a/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDeleteBuilder.java
 
b/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDeleteBuilder.java
index 714b8c2..be667d2 100644
--- 
a/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDeleteBuilder.java
+++ 
b/mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDeleteBuilder.java
@@ -44,8 +44,10 @@ final class MongoDbDeleteBuilder extends 
AbstractRowDeletionBuilder {
         final MongoCollection<Document> collection = 
_updateCallback.getCollection(getTable().getName());
 
         final MongoDbDataContext dataContext = 
_updateCallback.getDataContext();
-        final Document query = dataContext.createMongoDbQuery(getTable(), 
getWhereItems());
-        
+        final Document query = dataContext.createMongoDbQuery(getTable(), 
getWhereItems(), whereItem -> {
+            throw new UnsupportedOperationException("Unable to handle WHERE 
item in DELETE: " + whereItem.toSql());
+        });
+
         DeleteResult result = collection.deleteMany(query);
         logger.info("Remove returned result: {}", result);
     }

http://git-wip-us.apache.org/repos/asf/metamodel/blob/39947f55/mongodb/mongo3/src/test/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContextTest.java
----------------------------------------------------------------------
diff --git 
a/mongodb/mongo3/src/test/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContextTest.java
 
b/mongodb/mongo3/src/test/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContextTest.java
index 78fbddc..35c74cc 100644
--- 
a/mongodb/mongo3/src/test/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContextTest.java
+++ 
b/mongodb/mongo3/src/test/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContextTest.java
@@ -32,10 +32,10 @@ import org.apache.metamodel.data.InMemoryDataSet;
 import org.apache.metamodel.query.FunctionType;
 import org.apache.metamodel.query.SelectItem;
 import org.apache.metamodel.schema.ColumnType;
-import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.Table;
 import org.apache.metamodel.util.SimpleTableDef;
 import org.bson.Document;
+import org.junit.Test;
 
 import com.mongodb.MongoClient;
 import com.mongodb.MongoClientURI;
@@ -47,12 +47,12 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
 
     private MongoDatabase mongoDb;
     private MongoClient client;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         if (isConfigured()) {
-            client = new MongoClient(new 
MongoClientURI("mongodb://"+getHostname()+":27017"));
+            client = new MongoClient(new MongoClientURI("mongodb://" + 
getHostname() + ":27017"));
             mongoDb = client.getDatabase(getDatabaseName());
         }
     }
@@ -66,6 +66,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase {
         }
     }
 
+    @Test
     public void testNestedObjectFetching() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
@@ -84,16 +85,16 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         dbRow.append("addresses", list);
         col.insertOne(dbRow);
 
-        final MongoDbDataContext dc = new MongoDbDataContext(mongoDb, new 
SimpleTableDef(getCollectionName(), new String[] {
-                "name.first", "name.last", "gender", "addresses", 
"addresses[0].city", "addresses[0].country",
-                "addresses[5].foobar" }));
+        final MongoDbDataContext dc = new MongoDbDataContext(mongoDb,
+                new SimpleTableDef(getCollectionName(), new String[] { 
"name.first", "name.last", "gender", "addresses",
+                        "addresses[0].city", "addresses[0].country", 
"addresses[5].foobar" }));
 
         final DataSet ds = 
dc.query().from(getCollectionName()).selectAll().execute();
         try {
             assertTrue(ds.next());
             final Object addresses = ds.getRow().getValue(3);
-            assertEquals("Row[values=[John, Doe, MALE, " + addresses + ", 
Copenhagen, Denmark, null]]", ds.getRow()
-                    .toString());
+            assertEquals("Row[values=[John, Doe, MALE, " + addresses + ", 
Copenhagen, Denmark, null]]",
+                    ds.getRow().toString());
             assertTrue(addresses instanceof List);
             assertFalse(ds.next());
         } finally {
@@ -101,12 +102,13 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         }
     }
 
+    @Test
     public void testQueriesWithAutoGeneratedID() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
             return;
         }
-        
+
         mongoDb.createCollection(getCollectionName());
         MongoCollection<Document> col = 
mongoDb.getCollection(getCollectionName());
         col.withWriteConcern(WriteConcern.ACKNOWLEDGED);
@@ -138,8 +140,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         DataSet ds;
 
         // check all 3 entries inserted
-        ds = dc.query().from(getCollectionName()).selectAll()
-                .where("category").eq("gen_id").execute();
+        ds = 
dc.query().from(getCollectionName()).selectAll().where("category").eq("gen_id").execute();
         assertEquals(3, ds.toRows().size());
         ds.close();
 
@@ -150,17 +151,13 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         ds.close();
 
         // select by multiple autogenerated ids
-        ds = dc.query().from(getCollectionName()).select("name")
-                .where("_id").eq(autoGenID1)
-                .or("_id").eq(autoGenID2)
+        ds = 
dc.query().from(getCollectionName()).select("name").where("_id").eq(autoGenID1).or("_id").eq(autoGenID2)
                 .execute();
         assertEquals(2, ds.toRows().size());
         ds.close();
 
         // select by both autogenerated id and fixed id
-        ds = dc.query().from(getCollectionName()).select("name")
-                .where("_id").eq(autoGenID1)
-                .or("_id").eq(fixedID3)
+        ds = 
dc.query().from(getCollectionName()).select("name").where("_id").eq(autoGenID1).or("_id").eq(fixedID3)
                 .execute();
         assertEquals(2, ds.toRows().size());
         ds.close();
@@ -169,9 +166,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         dc.executeUpdate(new UpdateScript() {
             @Override
             public void run(UpdateCallback callback) {
-                callback.deleteFrom(getCollectionName())
-                        .where("_id").eq(autoGenID1)
-                        .execute();
+                
callback.deleteFrom(getCollectionName()).where("_id").eq(autoGenID1).execute();
             }
         });
 
@@ -182,6 +177,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
 
     }
 
+    @Test
     public void testFirstRowAndMaxRows() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
@@ -226,8 +222,79 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         ds.close();
     }
 
+    @Test
+    public void testSelectNestedObject() {
+        if (!isConfigured()) {
+            System.err.println(getInvalidConfigurationMessage());
+            return;
+        }
+
+        try (DataSet ds =
+                executeNestedObjectQuery("SELECT name.given FROM " + 
getCollectionName() + " WHERE id = 42")) {
+            assertTrue(ds.next());
+            assertEquals("John", (String) ds.getRow().getValue(0));
+            assertFalse(ds.next());
+        }
+    }
+
+    @Test
+    public void testWhereNestedObject() {
+        if (!isConfigured()) {
+            System.err.println(getInvalidConfigurationMessage());
+            return;
+        }
+
+        try (DataSet ds =
+                executeNestedObjectQuery("SELECT id FROM " + 
getCollectionName() + " WHERE name.given = 'Jane'")) {
+            assertTrue(ds.next());
+            assertEquals(43, ((Number) ds.getRow().getValue(0)).intValue());
+            assertFalse(ds.next());
+        }
+    }
+
+    @Test
+    public void testSelectAndWhereNestedObject() {
+        if (!isConfigured()) {
+            System.err.println(getInvalidConfigurationMessage());
+            return;
+        }
+
+        try (DataSet ds = executeNestedObjectQuery(
+                "SELECT name.family FROM " + getCollectionName() + " WHERE 
name.given = 'Jane'")) {
+            assertTrue(ds.next());
+            assertEquals("Johnson", (String) ds.getRow().getValue(0));
+            assertFalse(ds.next());
+        }
+    }
+
+    // reusable method for a couple of test cases above
+    private DataSet executeNestedObjectQuery(String sql) {
+        if (mongoDb.getCollection(getCollectionName()) != null) {
+            mongoDb.getCollection(getCollectionName()).drop();
+        }
+        mongoDb.createCollection(getCollectionName());
+        final MongoCollection<Document> col = 
mongoDb.getCollection(getCollectionName());
+
+        // record 1: 42 John Doe
+        col.insertOne(new Document().append("id", 42).append("name",
+                new Document().append("given", "John").append("family", 
"Doe")));
+
+        // record 2: 43 Jane Johnson
+        col.insertOne(new Document().append("id", 43).append("name",
+                new Document().append("given", "Jane").append("family", 
"Johnson")));
+
+        final DataContext dataContext = new MongoDbDataContext(mongoDb);
+
+        
assertTrue(dataContext.getDefaultSchema().getTableNames().contains(getCollectionName()));
+
+        final Table table = 
dataContext.getDefaultSchema().getTableByName(getCollectionName());
+        assertEquals("[_id, id, name]", table.getColumnNames().toString());
+
+        return dataContext.executeQuery(sql);
+    }
+
+    @Test
     public void testRead() throws Exception {
-        // Adding a comment to commit something and invoke a build in Travis...
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
             return;
@@ -259,9 +326,9 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         // Instantiate the actual data context
         final DataContext dataContext = new MongoDbDataContext(mongoDb);
 
-        
assertTrue(Arrays.asList(dataContext.getDefaultSchema().getTableNames()).contains(getCollectionName()));
-        
-        Table table = 
dataContext.getDefaultSchema().getTableByName(getCollectionName());
+        
assertTrue(dataContext.getDefaultSchema().getTableNames().contains(getCollectionName()));
+
+        final Table table = 
dataContext.getDefaultSchema().getTableByName(getCollectionName());
         assertEquals("[_id, baz, foo, id, list, name]", 
Arrays.toString(table.getColumnNames().toArray()));
 
         assertEquals(ColumnType.MAP, table.getColumnByName("baz").getType());
@@ -276,26 +343,22 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         assertFalse(((MongoDbDataSet) ds).isQueryPostProcessed());
         try {
             assertTrue(ds.next());
-            assertEquals(
-                    "Row[values=[record no. 0, bar, Document{{count=0, 
constant=foobarbaz}}, [l1, l2, l3, 0]]]",
+            assertEquals("Row[values=[record no. 0, bar, Document{{count=0, 
constant=foobarbaz}}, [l1, l2, l3, 0]]]",
                     ds.getRow().toString());
 
             assertTrue(ds.next());
-            assertEquals(
-                    "Row[values=[record no. 5, bar, Document{{count=5, 
constant=foobarbaz}}, [l1, l2, l3, 5]]]",
+            assertEquals("Row[values=[record no. 5, bar, Document{{count=5, 
constant=foobarbaz}}, [l1, l2, l3, 5]]]",
                     ds.getRow().toString());
 
             assertTrue(ds.next());
-            assertEquals(
-                    "Row[values=[record no. 10, bar, Document{{count=10, 
constant=foobarbaz}}, [l1, l2, l3, 10]]]",
+            assertEquals("Row[values=[record no. 10, bar, Document{{count=10, 
constant=foobarbaz}}, [l1, l2, l3, 10]]]",
                     ds.getRow().toString());
 
             for (int j = 15; j < 801; j++) {
                 if (j % 5 == 0) {
                     assertTrue(ds.next());
                     assertEquals("Row[values=[record no. " + j + ", bar, 
Document{{count=" + j
-                            + ", constant=foobarbaz}}, [l1, l2, l3, " + j + 
"]]]", ds.getRow()
-                            .toString());
+                            + ", constant=foobarbaz}}, [l1, l2, l3, " + j + 
"]]]", ds.getRow().toString());
                 }
             }
 
@@ -365,8 +428,8 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         }
 
         // test GREATER_THAN_OR_EQUAL
-        ds = 
dataContext.query().from(getCollectionName()).select("id").and("name").where("id")
-                .greaterThanOrEquals(500).and("foo").isEquals("bar").execute();
+        ds = 
dataContext.query().from(getCollectionName()).select("id").and("name").where("id").greaterThanOrEquals(500)
+                .and("foo").isEquals("bar").execute();
         assertEquals(MongoDbDataSet.class, ds.getClass());
         assertFalse(((MongoDbDataSet) ds).isQueryPostProcessed());
 
@@ -378,8 +441,8 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
             ds.close();
         }
 
-        ds = 
dataContext.query().from(getCollectionName()).select("id").and("name").where("id")
-                .greaterThanOrEquals(501).and("foo").isEquals("bar").execute();
+        ds = 
dataContext.query().from(getCollectionName()).select("id").and("name").where("id").greaterThanOrEquals(501)
+                .and("foo").isEquals("bar").execute();
         assertEquals(MongoDbDataSet.class, ds.getClass());
         assertFalse(((MongoDbDataSet) ds).isQueryPostProcessed());
 
@@ -449,30 +512,24 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         ds.close();
     }
 
+    @Test
     public void testCreateAndWriteData() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
             return;
         }
+        
+        if (mongoDb.getCollection(getCollectionName()) != null) {
+            mongoDb.getCollection(getCollectionName()).drop();
+        }
+        
         final MongoDbDataContext dc = new MongoDbDataContext(mongoDb);
-        final Schema defaultSchema = dc.getDefaultSchema();
-
-        dc.executeUpdate(new UpdateScript() {
-            @Override
-            public void run(UpdateCallback callback) {
-                for (Table table : defaultSchema.getTables()) {
-                    callback.deleteFrom(table).execute();
-                }
-            }
-        });
-
-        assertEquals(0, defaultSchema.getTableCount());
 
         dc.executeUpdate(new UpdateScript() {
 
             @Override
             public void run(UpdateCallback callback) {
-                Table table = callback.createTable(defaultSchema, 
"some_entries").withColumn("foo").withColumn("bar")
+                Table table = callback.createTable(dc.getDefaultSchema(), 
getCollectionName()).withColumn("foo").withColumn("bar")
                         .withColumn("baz").withColumn("list").execute();
 
                 callback.insertInto(table).value("foo", 1).value("bar", 
"hello").execute();
@@ -487,12 +544,13 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
                         .value("list", Arrays.asList(1, 2, 3)).execute();
             }
         });
+        dc.refreshSchemas();
 
         DataSet dataSet;
-        assertEquals(1, defaultSchema.getTableCount());
+        assertEquals(1, dc.getDefaultSchema().getTableCount());
 
         // "Pure" SELECT COUNT(*) query
-        dataSet = dc.query().from("some_entries").selectCount().execute();
+        dataSet = dc.query().from(getCollectionName()).selectCount().execute();
         dataSet.close();
         assertTrue(dataSet.next());
         assertEquals(1, dataSet.getSelectItems().size());
@@ -502,7 +560,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         assertEquals(InMemoryDataSet.class, dataSet.getClass());
 
         // A conditional SELECT COUNT(*) query
-        dataSet = 
dc.query().from("some_entries").selectCount().where("foo").greaterThan(2).execute();
+        dataSet = 
dc.query().from(getCollectionName()).selectCount().where("foo").greaterThan(2).execute();
         dataSet.close();
         assertTrue(dataSet.next());
         assertEquals(1, dataSet.getSelectItems().size());
@@ -512,7 +570,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         assertEquals(InMemoryDataSet.class, dataSet.getClass());
 
         // Select columns
-        dataSet = 
dc.query().from("some_entries").select("foo").and("bar").and("baz").and("list").execute();
+        dataSet = 
dc.query().from(getCollectionName()).select("foo").and("bar").and("baz").and("list").execute();
         assertTrue(dataSet.next());
         assertEquals("Row[values=[1, hello, null, null]]", 
dataSet.getRow().toString());
         assertTrue(dataSet.next());
@@ -529,11 +587,11 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         dc.executeUpdate(new UpdateScript() {
             @Override
             public void run(UpdateCallback callback) {
-                
callback.deleteFrom("some_entries").where("foo").greaterThan(2).where("baz").isNotNull().execute();
+                
callback.deleteFrom(getCollectionName()).where("foo").greaterThan(2).where("baz").isNotNull().execute();
             }
         });
 
-        dataSet = dc.query().from("some_entries").select("foo").execute();
+        dataSet = dc.query().from(getCollectionName()).select("foo").execute();
         assertTrue(dataSet.next());
         assertEquals("Row[values=[1]]", dataSet.getRow().toString());
         assertTrue(dataSet.next());
@@ -548,16 +606,17 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         dc.executeUpdate(new UpdateScript() {
             @Override
             public void run(UpdateCallback callback) {
-                callback.dropTable("some_entries").execute();
+                callback.dropTable(getCollectionName()).execute();
             }
         });
 
-        assertNull(dc.getTableByQualifiedLabel("some_entries"));
+        assertNull(dc.getTableByQualifiedLabel(getCollectionName()));
 
         dc.refreshSchemas();
-        assertEquals(0, defaultSchema.getTableCount());
+        assertEquals(0, dc.getDefaultSchema().getTableCount());
     }
 
+    @Test
     public void testSelectWithLikeOperator() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
@@ -582,9 +641,9 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         dbRow3.append("gender", "UNKNOWN");
         col.insertOne(dbRow3);
 
-        final MongoDbDataContext dc = new MongoDbDataContext(mongoDb, new 
SimpleTableDef(getCollectionName(), new String[] {
-                "name.first", "name.last", "gender", "addresses", 
"addresses[0].city", "addresses[0].country",
-                "addresses[5].foobar" }));
+        final MongoDbDataContext dc = new MongoDbDataContext(mongoDb,
+                new SimpleTableDef(getCollectionName(), new String[] { 
"name.first", "name.last", "gender", "addresses",
+                        "addresses[0].city", "addresses[0].country", 
"addresses[5].foobar" }));
 
         final DataSet ds1 = dc.executeQuery("select * from my_collection where 
gender LIKE '%MALE%'");
         final DataSet ds2 = dc.executeQuery("select * from my_collection where 
gender LIKE 'MALE%'");
@@ -609,6 +668,7 @@ public class MongoDbDataContextTest extends MongoDbTestCase 
{
         }
     }
 
+    @Test
     public void testSelectWithAlias() throws Exception {
         if (!isConfigured()) {
             System.err.println(getInvalidConfigurationMessage());
@@ -624,11 +684,11 @@ public class MongoDbDataContextTest extends 
MongoDbTestCase {
         col.insertOne(dbRow);
 
         final MongoDbDataContext dc = new MongoDbDataContext(mongoDb,
-                new SimpleTableDef(getCollectionName(), new String[] {
-                        "name.first", "name.last", "gender", "addresses", 
"addresses[0].city", "addresses[0].country",
-                        "addresses[5].foobar" }));
+                new SimpleTableDef(getCollectionName(), new String[] { 
"name.first", "name.last", "gender", "addresses",
+                        "addresses[0].city", "addresses[0].country", 
"addresses[5].foobar" }));
 
-        final DataSet ds1 = dc.executeQuery("select gender as my_gender, 
name.first as my_name from my_collection where gender LIKE '%MALE%'");
+        final DataSet ds1 = dc.executeQuery(
+                "select gender as my_gender, name.first as my_name from 
my_collection where gender LIKE '%MALE%'");
         final SelectItem[] selectItems = ds1.getSelectItems().toArray(new 
SelectItem[ds1.getSelectItems().size()]);
         SelectItem firstSelectItem = selectItems[0];
         SelectItem secondSelectItem = selectItems[1];

Reply via email to