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 <[email protected]> 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 [email protected] - * @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(); + } + }
