You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gora.apache.org by dr...@apache.org on 2020/03/23 21:01:37 UTC

[gora] 05/07: GORA-649 MongoFilterUtil: Avoid changing query passed as reference

This is an automated email from the ASF dual-hosted git repository.

drazzib pushed a commit to branch GORA-649-replace-deprecated-mongo-api
in repository https://gitbox.apache.org/repos/asf/gora.git

commit cfb563cc55e0b85ba9b723c9f6e03a1c2910fda8
Author: Damien Raude-Morvan <dr...@drazzib.com>
AuthorDate: Mon Mar 23 21:58:26 2020 +0100

    GORA-649 MongoFilterUtil: Avoid changing query passed as reference
    
    Return an Optional<> with subfilter to apply
---
 .../gora/mongodb/filters/DefaultFactory.java       | 83 ++++++++++------------
 .../apache/gora/mongodb/filters/FilterFactory.java |  7 +-
 .../gora/mongodb/filters/MongoFilterUtil.java      | 28 ++++----
 .../gora/mongodb/filters/DefaultFactoryTest.java   | 41 ++++++-----
 4 files changed, 76 insertions(+), 83 deletions(-)

diff --git a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/DefaultFactory.java b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/DefaultFactory.java
index 597f7e9..bd26209 100644
--- a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/DefaultFactory.java
+++ b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/DefaultFactory.java
@@ -17,19 +17,21 @@
  */
 package org.apache.gora.mongodb.filters;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.gora.filter.*;
 import org.apache.gora.mongodb.store.MongoMapping;
 import org.apache.gora.mongodb.store.MongoStore;
 import org.apache.gora.persistency.impl.PersistentBase;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
-import com.mongodb.BasicDBObject;
-import com.mongodb.DBObject;
-import com.mongodb.QueryBuilder;
+import static com.mongodb.client.model.Filters.*;
 
 public class DefaultFactory<K, T extends PersistentBase> extends
     BaseFactory<K, T> {
@@ -45,8 +47,8 @@ public class DefaultFactory<K, T extends PersistentBase> extends
   }
 
   @Override
-  public DBObject createFilter(final Filter<K, T> filter,
-      final MongoStore<K, T> store) {
+  public Bson createFilter(final Filter<K, T> filter,
+                           final MongoStore<K, T> store) {
 
     if (filter instanceof FilterList) {
       FilterList<K, T> filterList = (FilterList<K, T>) filter;
@@ -64,19 +66,17 @@ public class DefaultFactory<K, T extends PersistentBase> extends
     }
   }
 
-  protected DBObject transformListFilter(final FilterList<K, T> filterList,
-      final MongoStore<K, T> store) {
-    BasicDBObject query = new BasicDBObject();
-    for (Filter<K, T> filter : filterList.getFilters()) {
-      boolean succeeded = getFilterUtil().setFilter(query, filter, store);
-      if (!succeeded) {
-        return null;
-      }
-    }
-    return query;
+  protected Bson transformListFilter(final FilterList<K, T> filterList,
+                                     final MongoStore<K, T> store) {
+    List<Bson> filters = filterList.getFilters().stream()
+            .map(filter -> getFilterUtil().setFilter(filter, store))
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .collect(Collectors.toList());
+    return filters.isEmpty() ? new Document() : and(filters);
   }
 
-  protected DBObject transformFieldFilter(
+  protected Bson transformFieldFilter(
       final SingleFieldValueFilter<K, T> fieldFilter,
       final MongoStore<K, T> store) {
     MongoMapping mapping = store.getMapping();
@@ -85,17 +85,16 @@ public class DefaultFactory<K, T extends PersistentBase> extends
     FilterOp filterOp = fieldFilter.getFilterOp();
     List<Object> operands = fieldFilter.getOperands();
 
-    QueryBuilder builder = QueryBuilder.start(dbFieldName);
-    builder = appendToBuilder(builder, filterOp, operands);
+    Bson filter = appendToBuilder(dbFieldName, filterOp, operands);
     if (!fieldFilter.isFilterIfMissing()) {
       // If false, the find query will pass if the column is not found.
-      DBObject notExist = QueryBuilder.start(dbFieldName).exists(false).get();
-      builder = QueryBuilder.start().or(notExist, builder.get());
+      Bson notExist = exists(dbFieldName, false);
+      filter = or(notExist, filter);
     }
-    return builder.get();
+    return filter;
   }
 
-  protected DBObject transformMapFilter(
+  protected Bson transformMapFilter(
       final MapFieldValueFilter<K, T> mapFilter, final MongoStore<K, T> store) {
     MongoMapping mapping = store.getMapping();
     String dbFieldName = mapping.getDocumentField(mapFilter.getFieldName())
@@ -104,51 +103,43 @@ public class DefaultFactory<K, T extends PersistentBase> extends
     FilterOp filterOp = mapFilter.getFilterOp();
     List<Object> operands = mapFilter.getOperands();
 
-    QueryBuilder builder = QueryBuilder.start(dbFieldName);
-    builder = appendToBuilder(builder, filterOp, operands);
+    Bson filter = appendToBuilder(dbFieldName, filterOp, operands);
     if (!mapFilter.isFilterIfMissing()) {
       // If false, the find query will pass if the column is not found.
-      DBObject notExist = QueryBuilder.start(dbFieldName).exists(false).get();
-      builder = QueryBuilder.start().or(notExist, builder.get());
+      Bson notExist = exists(dbFieldName, false);
+      filter = or(notExist, filter);
     }
-    return builder.get();
+    return filter;
   }
 
-  protected QueryBuilder appendToBuilder(final QueryBuilder builder,
+  protected Bson appendToBuilder(final String dbFieldName,
       final FilterOp filterOp, final List<Object> rawOperands) {
     List<String> operands = convertOperandsToString(rawOperands);
     switch (filterOp) {
     case EQUALS:
       if (operands.size() == 1) {
-        builder.is(operands.iterator().next());
+        return eq(dbFieldName, operands.iterator().next());
       } else {
-        builder.in(operands);
+        return in(dbFieldName, operands);
       }
-      break;
     case NOT_EQUALS:
       if (operands.size() == 1) {
-        builder.notEquals(operands.iterator().next());
+        return ne(dbFieldName, operands.iterator().next());
       } else {
-        builder.notIn(operands);
+        return nin(dbFieldName, operands);
       }
-      break;
     case LESS:
-      builder.lessThan(operands);
-      break;
+      return lt(dbFieldName, operands);
     case LESS_OR_EQUAL:
-      builder.lessThanEquals(operands);
-      break;
+      return lte(dbFieldName, operands);
     case GREATER:
-      builder.greaterThan(operands);
-      break;
+      return gt(dbFieldName, operands);
     case GREATER_OR_EQUAL:
-      builder.greaterThanEquals(operands);
-      break;
+      return gte(dbFieldName, operands);
     default:
       throw new IllegalArgumentException(filterOp
           + " no MongoDB equivalent yet");
     }
-    return builder;
   }
 
   /**
diff --git a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/FilterFactory.java b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/FilterFactory.java
index c68364f..5276852 100644
--- a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/FilterFactory.java
+++ b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/FilterFactory.java
@@ -17,13 +17,12 @@
  */
 package org.apache.gora.mongodb.filters;
 
-import java.util.List;
-
 import org.apache.gora.filter.Filter;
 import org.apache.gora.mongodb.store.MongoStore;
 import org.apache.gora.persistency.impl.PersistentBase;
+import org.bson.conversions.Bson;
 
-import com.mongodb.DBObject;
+import java.util.List;
 
 /**
  * Describe factory which create remote filter for MongoDB.
@@ -38,5 +37,5 @@ public interface FilterFactory<K, T extends PersistentBase> {
 
   List<String> getSupportedFilters();
 
-  DBObject createFilter(Filter<K, T> filter, MongoStore<K, T> store);
+  Bson createFilter(Filter<K, T> filter, MongoStore<K, T> store);
 }
diff --git a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/MongoFilterUtil.java b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/MongoFilterUtil.java
index 8779af4..a7ccdc0 100644
--- a/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/MongoFilterUtil.java
+++ b/gora-mongodb/src/main/java/org/apache/gora/mongodb/filters/MongoFilterUtil.java
@@ -17,9 +17,6 @@
  */
 package org.apache.gora.mongodb.filters;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.gora.filter.Filter;
@@ -28,8 +25,11 @@ import org.apache.gora.persistency.impl.PersistentBase;
 import org.apache.gora.util.GoraException;
 import org.apache.gora.util.ReflectionUtils;
 import org.apache.hadoop.conf.Configuration;
+import org.bson.conversions.Bson;
 
-import com.mongodb.DBObject;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
 
 /**
  * Manage creation of filtering {@link org.apache.gora.query.Query} using
@@ -40,8 +40,7 @@ import com.mongodb.DBObject;
  * </p>
  * 
  * @author Damien Raude-Morvan draudemorvan@dictanova.com
- * @see #setFilter(com.mongodb.DBObject, org.apache.gora.filter.Filter,
- *      org.apache.gora.mongodb.store.MongoStore)
+ * @see #setFilter(Filter, MongoStore)
  */
 public class MongoFilterUtil<K, T extends PersistentBase> {
 
@@ -87,32 +86,29 @@ public class MongoFilterUtil<K, T extends PersistentBase> {
   /**
    * Set a filter on the <tt>query</tt>. It translates a Gora filter to a
    * MongoDB filter.
-   * 
-   * @param query
-   *          The Mongo Query
+   *
    * @param filter
    *          The Gora filter.
    * @param store
    *          The MongoStore.
    * @return if remote filter is successfully applied.
    */
-  public boolean setFilter(final DBObject query, final Filter<K, T> filter,
-      final MongoStore<K, T> store) {
+  public Optional<Bson> setFilter(final Filter<K, T> filter,
+                                  final MongoStore<K, T> store) {
 
     FilterFactory<K, T> factory = getFactory(filter);
     if (factory == null) {
       LOG.warn("MongoDB remote filter factory not yet implemented for "
           + filter.getClass().getCanonicalName());
-      return false;
+      return Optional.empty();
     } else {
-      DBObject mongoFilter = factory.createFilter(filter, store);
+      Bson mongoFilter = factory.createFilter(filter, store);
       if (mongoFilter == null) {
         LOG.warn("MongoDB remote filter not yet implemented for "
             + filter.getClass().getCanonicalName());
-        return false;
+        return Optional.empty();
       } else {
-        query.putAll(mongoFilter);
-        return true;
+        return Optional.of(mongoFilter);
       }
     }
   }
diff --git a/gora-mongodb/src/test/java/org/apache/gora/mongodb/filters/DefaultFactoryTest.java b/gora-mongodb/src/test/java/org/apache/gora/mongodb/filters/DefaultFactoryTest.java
index 3658e42..966f9be 100644
--- a/gora-mongodb/src/test/java/org/apache/gora/mongodb/filters/DefaultFactoryTest.java
+++ b/gora-mongodb/src/test/java/org/apache/gora/mongodb/filters/DefaultFactoryTest.java
@@ -17,8 +17,7 @@
  */
 package org.apache.gora.mongodb.filters;
 
-import static org.junit.Assert.assertEquals;
-
+import com.mongodb.MongoClient;
 import org.apache.avro.util.Utf8;
 import org.apache.gora.examples.generated.WebPage;
 import org.apache.gora.filter.FilterList;
@@ -27,11 +26,13 @@ import org.apache.gora.filter.MapFieldValueFilter;
 import org.apache.gora.filter.SingleFieldValueFilter;
 import org.apache.gora.mongodb.store.MongoStore;
 import org.apache.hadoop.conf.Configuration;
+import org.bson.BsonDocument;
+import org.bson.conversions.Bson;
 import org.json.JSONObject;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.mongodb.DBObject;
+import static org.junit.Assert.assertEquals;
 
 public class DefaultFactoryTest {
 
@@ -56,9 +57,9 @@ public class DefaultFactoryTest {
     filter.setFilterOp(FilterOp.NOT_EQUALS);
     filter.setFilterIfMissing(true);
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"url\" : { \"$ne\" : \"http://www.example.com\"}}").toString(),
-            new JSONObject(dbObject.toString()).toString());
+            new JSONObject(asJson(dbObject)).toString());
   }
 
   @Test
@@ -67,9 +68,9 @@ public class DefaultFactoryTest {
     filter.setFilterOp(FilterOp.EQUALS);
     filter.setFilterIfMissing(false); // include doc with missing field
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"$or\" : [ { \"url\" : { \"$exists\" : false}} , " +
-                    "{ \"url\" : \"http://www.example.com\"}]}").toString(), new JSONObject(dbObject.toString()).toString());
+                    "{ \"url\" : \"http://www.example.com\"}]}").toString(), new JSONObject(asJson(dbObject)).toString());
   }
 
   @Test
@@ -78,9 +79,9 @@ public class DefaultFactoryTest {
     filter.setFilterOp(FilterOp.NOT_EQUALS);
     filter.setFilterIfMissing(true);
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"h.C·T\" : { \"$ne\" : \"text/html\"}}").toString(),
-            new JSONObject(dbObject.toString()).toString());
+            new JSONObject(asJson(dbObject)).toString());
   }
 
   @Test
@@ -89,17 +90,17 @@ public class DefaultFactoryTest {
     filter.setFilterOp(FilterOp.EQUALS);
     filter.setFilterIfMissing(false); // include doc with missing field
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"$or\" : [ { \"h.C·T\" : { \"$exists\" : false}} , " +
-                    "{ \"h.C·T\" : \"text/html\"}]}").toString(), new JSONObject(dbObject.toString()).toString());
+                    "{ \"h.C·T\" : \"text/html\"}]}").toString(), new JSONObject(asJson(dbObject)).toString());
   }
 
   @Test
   public void testCreateFilter_list_empty() throws Exception {
     FilterList<String, WebPage> filter = new FilterList<>();
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
-    assertEquals(new JSONObject("{ }").toString(), new JSONObject(dbObject.toString()).toString());
+    Bson dbObject = filterFactory.createFilter(filter, store);
+    assertEquals(new JSONObject("{ }").toString(), new JSONObject(asJson(dbObject)).toString());
   }
 
   @Test
@@ -114,9 +115,9 @@ public class DefaultFactoryTest {
     urlFilter.setFilterOp(FilterOp.EQUALS);
     filter.addFilter(urlFilter);
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"h.C·T\" : \"text/html\" , \"url\" : \"http://www.example.com\"}").toString(),
-            new JSONObject(dbObject.toString()).toString());
+            new JSONObject(asJson(dbObject)).toString());
   }
 
   /**
@@ -131,9 +132,9 @@ public class DefaultFactoryTest {
     filter.getOperands().add(new Utf8("http://www.example.com"));
     filter.setFilterIfMissing(true);
 
-    DBObject dbObject = filterFactory.createFilter(filter, store);
+    Bson dbObject = filterFactory.createFilter(filter, store);
     assertEquals(new JSONObject("{ \"url\" : \"http://www.example.com\"}").toString(),
-            new JSONObject(dbObject.toString()).toString());
+            new JSONObject(asJson(dbObject)).toString());
   }
 
   private MapFieldValueFilter<String, WebPage> createHeadersFilter() {
@@ -150,4 +151,10 @@ public class DefaultFactoryTest {
     filter.getOperands().add("http://www.example.com");
     return filter;
   }
+
+  private static String asJson(Bson bson) {
+    BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
+    return bsonDocument.toString();
+  }
+
 }