Browse Source

DATAMONGO-2499 - Hacking

Works, still not sure if that's a good solution.
issue/DATAMONGO-2499
Christoph Strobl 6 years ago
parent
commit
32c73b7117
  1. 58
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java
  2. 40
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java

58
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java

@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -394,7 +395,41 @@ public class Criteria implements CriteriaDefinition {
* @see <a href="https://docs.mongodb.com/manual/reference/operator/query/not/">MongoDB Query operator: $not</a> * @see <a href="https://docs.mongodb.com/manual/reference/operator/query/not/">MongoDB Query operator: $not</a>
*/ */
public Criteria not() { public Criteria not() {
return not(null); return not((Object)null);
}
public Criteria not(Consumer<Criteria> source) {
Criteria sink = new Criteria(this.key);
source.accept(sink);
List<Criteria> target = new ArrayList<>();
for(Criteria criteria : sink.criteriaChain) {
boolean nextIsNot = false;
for(Entry<String, Object> entry : criteria.criteria.entrySet()) {
if(entry.getKey().equals("$not")) {
nextIsNot = true;
continue;
}
Criteria extractedSingleCriteria = new Criteria(criteria.key);
if(nextIsNot) {
extractedSingleCriteria = new Criteria("$not");
extractedSingleCriteria.criteria.put(criteria.key, new Document(entry.getKey(), entry.getValue()));
nextIsNot = false;
} else {
extractedSingleCriteria.criteria.put(entry.getKey(), entry.getValue());
}
target.add(extractedSingleCriteria);
}
}
List bsonList = createCriteriaList(target.toArray(new Criteria[0]), true);
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
}
public Criteria not(Criteria... criteria) {
List bsonList = createCriteriaList(criteria, true);
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
} }
/** /**
@ -660,7 +695,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria * @param criteria
*/ */
public Criteria orOperator(Criteria... criteria) { public Criteria orOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria); List bsonList = createCriteriaList(criteria, false);
return registerCriteriaChainElement(new Criteria("$or").is(bsonList)); return registerCriteriaChainElement(new Criteria("$or").is(bsonList));
} }
@ -674,7 +709,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria * @param criteria
*/ */
public Criteria norOperator(Criteria... criteria) { public Criteria norOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria); List bsonList = createCriteriaList(criteria, false);
return registerCriteriaChainElement(new Criteria("$nor").is(bsonList)); return registerCriteriaChainElement(new Criteria("$nor").is(bsonList));
} }
@ -688,7 +723,7 @@ public class Criteria implements CriteriaDefinition {
* @param criteria * @param criteria
*/ */
public Criteria andOperator(Criteria... criteria) { public Criteria andOperator(Criteria... criteria) {
BasicDBList bsonList = createCriteriaList(criteria); List bsonList = createCriteriaList(criteria, false);
return registerCriteriaChainElement(new Criteria("$and").is(bsonList)); return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
} }
@ -775,16 +810,23 @@ public class Criteria implements CriteriaDefinition {
queryCriteria.put(this.key, this.isValue); queryCriteria.put(this.key, this.isValue);
queryCriteria.putAll(document); queryCriteria.putAll(document);
} else { } else {
queryCriteria.put(this.key, document); if(!document.isEmpty()) {
queryCriteria.put(this.key, document);
}
} }
return queryCriteria; return queryCriteria;
} }
private BasicDBList createCriteriaList(Criteria[] criteria) { private List createCriteriaList(Criteria[] criteria, boolean not) {
BasicDBList bsonList = new BasicDBList(); List bsonList = new ArrayList();
for (Criteria c : criteria) { for (Criteria c : criteria) {
bsonList.add(c.getCriteriaObject());
Document co = c.getCriteriaObject();
if(not) {
co = new Document("$not", co);
}
bsonList.add(co);
} }
return bsonList; return bsonList;
} }

40
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java

@ -19,6 +19,8 @@ import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.core.query.Query.*;
import java.util.function.Consumer;
import org.bson.Document; import org.bson.Document;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
@ -350,6 +352,44 @@ class QueryTests {
compareQueries(target, source); compareQueries(target, source);
} }
@Test // DATAMONGO-2499
void notCombiningSeveralIndedependentCriterias() {
Query source = new Query(new Criteria().not(Criteria.where("age").gt(30), Criteria.where("age").lt(20)));
Document target = source.getQueryObject();
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"$not\": {\"age\": {\"$gt\": 30}}}, {\"$not\": {\"age\": {\"$lt\": 20}}}]}"));
}
@Test // DATAMONGO-2499
void notCombiningSingleCriteria() {
Query source = new Query(Criteria.where("age").not(age -> age.gt(30).lt(20)));
Document target = source.getQueryObject();
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"$not\": {\"age\": {\"$gt\": 30}}}, {\"$not\": {\"age\": {\"$lt\": 20}}}]}"));
}
@Test // DATAMONGO-2499
void notCombiningSingleCriteriaWithAnother() {
Query source = new Query(Criteria.where("age").not(age -> age.gt(30).lt(20)).exists(true));
Document target = source.getQueryObject();
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"$not\": {\"age\": {\"$gt\": 30}}}, {\"$not\": {\"age\": {\"$lt\": 20}}}], \"age\": {\"$exists\": true}}"));
}
@Test // DATAMONGO-2499
void notCombiningSingleCriteriaWithNestedNot() {
Query source = new Query(Criteria.where("age").not(age -> age.gt(30).not().lt(20)));
Document target = source.getQueryObject();
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"$not\": {\"age\": {\"$gt\": 30}}}, {\"$not\": { \"$not\": {\"age\": {\"$lt\": 20}}}}]}"));
}
private void compareQueries(Query actual, Query expected) { private void compareQueries(Query actual, Query expected) {
assertThat(actual.getCollation()).isEqualTo(expected.getCollation()); assertThat(actual.getCollation()).isEqualTo(expected.getCollation());

Loading…
Cancel
Save