diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java
index 502aeb408..b73536dd9 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java
@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import org.bson.BSON;
import org.bson.BsonRegularExpression;
import org.bson.Document;
+import org.bson.types.Binary;
import org.springframework.data.domain.Example;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Point;
@@ -41,6 +42,7 @@ import org.springframework.data.mongodb.core.schema.JsonSchemaProperty;
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
+import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -357,7 +359,7 @@ public class Criteria implements CriteriaDefinition {
/**
* Creates a criterion using the {@literal $type} operator.
*
- * @param type must not be {@literal null}.
+ * @param types must not be {@literal null}.
* @return this
* @since 2.1
* @see MongoDB Query operator: $type
@@ -623,6 +625,18 @@ public class Criteria implements CriteriaDefinition {
return registerCriteriaChainElement(schemaCriteria);
}
+ /**
+ * Use {@link BitwiseCriteriaOperators} as gateway to create a criterion using one of the
+ * bitwise operators like
+ * {@code $bitsAllClear}.
+ *
+ * @return new instance of {@link BitwiseCriteriaOperators}. Never {@literal null}.
+ * @since 2.1
+ */
+ public BitwiseCriteriaOperators bits() {
+ return new BitwiseCriteriaOperatorsImpl(this);
+ }
+
/**
* Creates an 'or' criteria using the $or operator for all of the provided criteria
*
@@ -664,118 +678,6 @@ public class Criteria implements CriteriaDefinition {
BasicDBList bsonList = createCriteriaList(criteria);
return registerCriteriaChainElement(new Criteria("$and").is(bsonList));
}
-
- /**
- * Creates a criterion using the {@literal $bitsAllClear} operator.
- *
- * @param numericBitmask non-negative numeric bitmask
- * @return
- * @see MongoDB Query operator:
- * $bitsAllClear
- * @since 2.1
- */
- public Criteria bitsAllClear(int numericBitmask) {
- criteria.put("$bitsAllClear", Integer.valueOf(numericBitmask));
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAllClear} operator.
- *
- * @param bitPositions positions of set bits
- * @return
- * @see MongoDB Query operator:
- * $bitsAllClear
- * @since 2.1
- */
- public Criteria bitsAllClear(Collection bitPositions) {
- criteria.put("$bitsAllClear", bitPositions);
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAllSet} operator.
- *
- * @param numericBitmask non-negative numeric bitmask
- * @return
- * @see MongoDB Query operator:
- * $bitsAllSet
- * @since 2.1
- */
- public Criteria bitsAllSet(int numericBitmask) {
- criteria.put("$bitsAllSet", Integer.valueOf(numericBitmask));
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAllSet} operator.
- *
- * @param bitPositions positions of set bits
- * @return
- * @see MongoDB Query operator:
- * $bitsAllSet
- * @since 2.1
- */
- public Criteria bitsAllSet(Collection bitPositions) {
- criteria.put("$bitsAllSet", bitPositions);
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAnyClear} operator.
- *
- * @param numericBitmask non-negative numeric bitmask
- * @return
- * @see MongoDB Query operator:
- * $bitsAnyClear
- * @since 2.1
- */
- public Criteria bitsAnyClear(int numericBitmask) {
- criteria.put("$bitsAnyClear", Integer.valueOf(numericBitmask));
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAnyClear} operator.
- *
- * @param bitPositions positions of set bits
- * @return
- * @see MongoDB Query operator:
- * $bitsAnyClear
- * @since 2.1
- */
- public Criteria bitsAnyClear(Collection bitPositions) {
- criteria.put("$bitsAnyClear", bitPositions);
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAnySet} operator.
- *
- * @param numericBitmask non-negative numeric bitmask
- * @return
- * @see MongoDB Query operator:
- * $bitsAnySet
- * @since 2.1
- */
- public Criteria bitsAnySet(int numericBitmask) {
- criteria.put("$bitsAnySet", Integer.valueOf(numericBitmask));
- return this;
- }
-
- /**
- * Creates a criterion using the {@literal $bitsAnySet} operator.
- *
- * @param bitPositions positions of set bits
- * @return
- * @see MongoDB Query operator:
- * $bitsAnySet
- * @since 2.1
- */
- public Criteria bitsAnySet(Collection bitPositions) {
- criteria.put("$bitsAnySet", bitPositions);
- return this;
- }
private Criteria registerCriteriaChainElement(Criteria criteria) {
@@ -993,4 +895,324 @@ public class Criteria implements CriteriaDefinition {
return value instanceof GeoJson
|| (value instanceof GeoCommand && ((GeoCommand) value).getShape() instanceof GeoJson);
}
+
+ /**
+ * MongoDB specific bitwise query
+ * operators like {@code $bitsAllClear, $bitsAllSet,...} for usage with {@link Criteria#bits()} and {@link Query}.
+ *
+ * @author Christoph Strobl
+ * @since 2.1
+ * @see https://docs.mongodb.com/manual/reference/operator/query-bitwise/
+ * @currentRead Beyond the Shadows - Brent Weeks
+ */
+ public interface BitwiseCriteriaOperators {
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where all given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param numericBitmask non-negative numeric bitmask.
+ * @return target {@link Criteria}.
+ * @see MongoDB Query operator:
+ * $bitsAllClear
+ * @since 2.1
+ */
+ Criteria allClear(int numericBitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where all given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param bitmask string representation of a bitmask that will be converted to its base64 encoded {@link Binary}
+ * representation. Must not be {@literal null} nor empty.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when bitmask is {@literal null} or empty.
+ * @see MongoDB Query operator:
+ * $bitsAllClear
+ * @since 2.1
+ */
+ Criteria allClear(String bitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where all given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param positions list of non-negative integer positions. Positions start at 0 from the least significant bit.
+ * Must not be {@literal null} nor contain {@literal null} elements.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when positions is {@literal null} or contains {@literal null} elements.
+ * @see MongoDB Query operator:
+ * $bitsAllClear
+ * @since 2.1
+ */
+ Criteria allClear(List positions);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllSet} matching documents where all given bit positions are set (i.e.
+ * 1).
+ *
+ * @param numericBitmask non-negative numeric bitmask.
+ * @return target {@link Criteria}.
+ * @see MongoDB Query operator:
+ * $bitsAllSet
+ * @since 2.1
+ */
+ Criteria allSet(int numericBitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllSet} matching documents where all given bit positions are set (i.e.
+ * 1).
+ *
+ * @param bitmask string representation of a bitmask that will be converted to its base64 encoded {@link Binary}
+ * representation. Must not be {@literal null} nor empty.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when bitmask is {@literal null} or empty.
+ * @see MongoDB Query operator:
+ * $bitsAllSet
+ * @since 2.1
+ */
+ Criteria allSet(String bitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllSet} matching documents where all given bit positions are set (i.e.
+ * 1).
+ *
+ * @param positions list of non-negative integer positions. Positions start at 0 from the least significant bit.
+ * Must not be {@literal null} nor contain {@literal null} elements.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when positions is {@literal null} or contains {@literal null} elements.
+ * @see MongoDB Query operator:
+ * $bitsAllSet
+ * @since 2.1
+ */
+ Criteria allSet(List positions);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where any given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param numericBitmask non-negative numeric bitmask.
+ * @return target {@link Criteria}.
+ * @see MongoDB Query operator:
+ * $bitsAnyClear
+ * @since 2.1
+ */
+ Criteria anyClear(int numericBitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where any given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param bitmask string representation of a bitmask that will be converted to its base64 encoded {@link Binary}
+ * representation. Must not be {@literal null} nor empty.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when bitmask is {@literal null} or empty.
+ * @see MongoDB Query operator:
+ * $bitsAnyClear
+ * @since 2.1
+ */
+ Criteria anyClear(String bitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllClear} matching documents where any given bit positions are clear
+ * (i.e. 0).
+ *
+ * @param positions list of non-negative integer positions. Positions start at 0 from the least significant bit.
+ * Must not be {@literal null} nor contain {@literal null} elements.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when positions is {@literal null} or contains {@literal null} elements.
+ * @see MongoDB Query operator:
+ * $bitsAnyClear
+ * @since 2.1
+ */
+ Criteria anyClear(List positions);
+
+ /**
+ * Creates a criterion using {@literal $bitsAllSet} matching documents where any given bit positions are set (i.e.
+ * 1).
+ *
+ * @param numericBitmask non-negative numeric bitmask.
+ * @return target {@link Criteria}.
+ * @see MongoDB Query operator:
+ * $bitsAnySet
+ * @since 2.1
+ */
+ Criteria anySet(int numericBitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAnySet} matching documents where any given bit positions are set (i.e.
+ * 1).
+ *
+ * @param bitmask string representation of a bitmask that will be converted to its base64 encoded {@link Binary}
+ * representation. Must not be {@literal null} nor empty.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when bitmask is {@literal null} or empty.
+ * @see MongoDB Query operator:
+ * $bitsAnySet
+ * @since 2.1
+ */
+ Criteria anySet(String bitmask);
+
+ /**
+ * Creates a criterion using {@literal $bitsAnySet} matching documents where any given bit positions are set (i.e.
+ * 1).
+ *
+ * @param positions list of non-negative integer positions. Positions start at 0 from the least significant bit.
+ * Must not be {@literal null} nor contain {@literal null} elements.
+ * @return target {@link Criteria}.
+ * @throws IllegalArgumentException when positions is {@literal null} or contains {@literal null} elements.
+ * @see MongoDB Query operator:
+ * $bitsAnySet
+ * @since 2.1
+ */
+ Criteria anySet(List positions);
+
+ }
+
+ /**
+ * Default implementation of {@link BitwiseCriteriaOperators}.
+ *
+ * @author Christoph Strobl
+ * @currentRead Beyond the Shadows - Brent Weeks
+ */
+ private static class BitwiseCriteriaOperatorsImpl implements BitwiseCriteriaOperators {
+
+ private final Criteria target;
+
+ BitwiseCriteriaOperatorsImpl(Criteria target) {
+ this.target = target;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allClear(int)
+ */
+ @Override
+ public Criteria allClear(int numericBitmask) {
+ return numericBitmask("$bitsAllClear", numericBitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allClear(java.lang.String)
+ */
+ @Override
+ public Criteria allClear(String bitmask) {
+ return stringBitmask("$bitsAllClear", bitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allClear(java.util.List)
+ */
+ @Override
+ public Criteria allClear(List positions) {
+ return positions("$bitsAllClear", positions);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allSet(int)
+ */
+ @Override
+ public Criteria allSet(int numericBitmask) {
+ return numericBitmask("$bitsAllSet", numericBitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allSet(java.lang.String)
+ */
+ @Override
+ public Criteria allSet(String bitmask) {
+ return stringBitmask("$bitsAllSet", bitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#allSet(java.util.List)
+ */
+ @Override
+ public Criteria allSet(List positions) {
+ return positions("$bitsAllSet", positions);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anyClear(int)
+ */
+ @Override
+ public Criteria anyClear(int numericBitmask) {
+ return numericBitmask("$bitsAnyClear", numericBitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anyClear(java.lang.String)
+ */
+ @Override
+ public Criteria anyClear(String bitmask) {
+ return stringBitmask("$bitsAnyClear", bitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anyClear(java.util.List)
+ */
+ @Override
+ public Criteria anyClear(List positions) {
+ return positions("$bitsAnyClear", positions);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anySet(int)
+ */
+ @Override
+ public Criteria anySet(int numericBitmask) {
+ return numericBitmask("$bitsAnySet", numericBitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anySet(java.lang.String)
+ */
+ @Override
+ public Criteria anySet(String bitmask) {
+ return stringBitmask("$bitsAnySet", bitmask);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.mongodb.core.query.BitwiseCriteriaOperators#anySet(java.util.Collection)
+ */
+ @Override
+ public Criteria anySet(List positions) {
+ return positions("$bitsAnySet", positions);
+ }
+
+ private Criteria positions(String operator, List positions) {
+
+ Assert.notNull(positions, "Positions must not be null!");
+ Assert.noNullElements(positions.toArray(), "Positions must not contain null values.");
+
+ target.criteria.put(operator, positions);
+ return target;
+ }
+
+ private Criteria stringBitmask(String operator, String bitmask) {
+
+ Assert.hasText(bitmask, "Bitmask must not be null!");
+
+ target.criteria.put(operator, new Binary(Base64Utils.decodeFromString(bitmask)));
+ return target;
+ }
+
+ private Criteria numericBitmask(String operator, int bitmask) {
+
+ target.criteria.put(operator, bitmask);
+ return target;
+ }
+ }
}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
index eab9e1d50..9aa7990b5 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java
@@ -3361,61 +3361,6 @@ public class MongoTemplateTests {
assertThat(template.count(query(where("field").is("stark")), Sample.class)).isEqualTo(0L);
}
- @Test // DATAMONGO-1808
- public void testFindByBitmasks() {
- DocumentWithBitmask document = new DocumentWithBitmask(0b101);
- template.insert(document);
-
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAllClear(0b010)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAllClear(Arrays.asList(1))),
- DocumentWithBitmask.class)).hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAllClear(0b010)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAllClear(Arrays.asList(1))),
- DocumentWithBitmask.class)).hasSize(1);
-
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAllSet(0b101)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAllSet(Arrays.asList(0, 2))),
- DocumentWithBitmask.class)).hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAllSet(0b101)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAllSet(Arrays.asList(0, 2))),
- DocumentWithBitmask.class)).hasSize(1);
-
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAnyClear(0b111)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAnyClear(Arrays.asList(0, 1, 2))),
- DocumentWithBitmask.class)).hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAnyClear(0b111)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAnyClear(Arrays.asList(0, 1, 2))),
- DocumentWithBitmask.class)).hasSize(1);
-
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAnySet(0b111)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("intValue").bitsAnySet(Arrays.asList(0, 1, 2))),
- DocumentWithBitmask.class)).hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAnySet(0b111)), DocumentWithBitmask.class))
- .hasSize(1);
- assertThat(template.find(Query.query(Criteria.where("binaryValue").bitsAnySet(Arrays.asList(0, 1, 2))),
- DocumentWithBitmask.class)).hasSize(1);
- }
-
- @NoArgsConstructor
- static class DocumentWithBitmask {
- @Id String id;
- int intValue;
- byte[] binaryValue;
-
- public DocumentWithBitmask(int value) {
- this.intValue = value;
- this.binaryValue = new byte[] { (byte) value };
- }
-
- }
-
static class TypeWithNumbers {
@Id String id;
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java
index 1bbcd28fb..8830e4e42 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2018 the original author or authors.
+ * Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,268 +15,151 @@
*/
package org.springframework.data.mongodb.core.query;
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.mongodb.core.query.Criteria.*;
+import static org.springframework.data.mongodb.core.query.Query.*;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
import java.util.Arrays;
-import java.util.Collections;
-import org.bson.Document;
+import org.bson.types.Binary;
+import org.junit.Before;
import org.junit.Test;
-import org.springframework.data.geo.Point;
-import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
-import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
-import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
-import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.util.Base64Utils;
+
+import com.mongodb.MongoClient;
/**
- * @author Oliver Gierke
- * @author Thomas Darimont
+ * Integration tests for {@link Criteria} usage as part of a {@link Query}.
+ *
* @author Christoph Strobl
+ * @author Andreas Zink
*/
public class CriteriaTests {
- @Test
- public void testSimpleCriteria() {
- Criteria c = new Criteria("name").is("Bubba");
- assertEquals(Document.parse("{ \"name\" : \"Bubba\"}"), c.getCriteriaObject());
- }
-
- @Test
- public void testNotEqualCriteria() {
- Criteria c = new Criteria("name").ne("Bubba");
- assertEquals(Document.parse("{ \"name\" : { \"$ne\" : \"Bubba\"}}"), c.getCriteriaObject());
- }
-
- @Test
- public void buildsIsNullCriteriaCorrectly() {
-
- Document reference = new Document("name", null);
-
- Criteria criteria = new Criteria("name").is(null);
- assertThat(criteria.getCriteriaObject(), is(reference));
- }
-
- @Test
- public void testChainedCriteria() {
- Criteria c = new Criteria("name").is("Bubba").and("age").lt(21);
- assertEquals(Document.parse("{ \"name\" : \"Bubba\" , \"age\" : { \"$lt\" : 21}}"), c.getCriteriaObject());
- }
-
- @Test(expected = InvalidMongoDbApiUsageException.class)
- public void testCriteriaWithMultipleConditionsForSameKey() {
- Criteria c = new Criteria("name").gte("M").and("name").ne("A");
- c.getCriteriaObject();
- }
-
- @Test
- public void equalIfCriteriaMatches() {
-
- Criteria left = new Criteria("name").is("Foo").and("lastname").is("Bar");
- Criteria right = new Criteria("name").is("Bar").and("lastname").is("Bar");
-
- assertThat(left, is(not(right)));
- assertThat(right, is(not(left)));
- }
-
- @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
- public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
-
- new Criteria() //
- .not() //
- .andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
- }
-
- @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
- public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
-
- new Criteria() //
- .not() //
- .orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
- }
-
- @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
- public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
-
- new Criteria() //
- .not() //
- .norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
- }
-
- @Test // DATAMONGO-507
- public void shouldNegateFollowingSimpleExpression() {
-
- Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
- Document co = c.getCriteriaObject();
-
- assertThat(co, is(notNullValue()));
- assertThat(co, is(Document.parse("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}")));
- }
-
- @Test // DATAMONGO-1068
- public void getCriteriaObjectShouldReturnEmptyDocumentWhenNoCriteriaSpecified() {
-
- Document document = new Criteria().getCriteriaObject();
-
- assertThat(document, equalTo(new Document()));
- }
-
- @Test // DATAMONGO-1068
- public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresent() {
+ MongoOperations ops;
+ MongoClient client;
- Document document = new Criteria().lt("foo").getCriteriaObject();
+ static final DocumentWithBitmask FIFTY_FOUR/*00110110*/ = new DocumentWithBitmask("1", Integer.valueOf(54),
+ Integer.toBinaryString(54));
+ static final DocumentWithBitmask TWENTY_INT/*00010100*/ = new DocumentWithBitmask("2", Integer.valueOf(20),
+ Integer.toBinaryString(20));
+ static final DocumentWithBitmask TWENTY_FLOAT/*00010100*/ = new DocumentWithBitmask("3", Float.valueOf(20),
+ Integer.toBinaryString(20));
+ static final DocumentWithBitmask ONE_HUNDRED_TWO/*01100110*/ = new DocumentWithBitmask("4",
+ new Binary(Base64Utils.decodeFromString("Zg==")), "01100110");
- assertThat(document, equalTo(new Document().append("$lt", "foo")));
- }
+ @Before
+ public void setUp() {
- @Test // DATAMONGO-1068
- public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresentButMultipleCriteriasPresent() {
+ client = new MongoClient();
+ ops = new MongoTemplate(client, "criteria-tests");
- Document document = new Criteria().lt("foo").gt("bar").getCriteriaObject();
+ ops.dropCollection(DocumentWithBitmask.class);
- assertThat(document, equalTo(new Document().append("$lt", "foo").append("$gt", "bar")));
+ ops.insert(FIFTY_FOUR);
+ ops.insert(TWENTY_INT);
+ ops.insert(TWENTY_FLOAT);
+ ops.insert(ONE_HUNDRED_TWO);
}
- @Test // DATAMONGO-1068
- public void getCriteriaObjectShouldRespectNotWhenNoKeyPresent() {
-
- Document document = new Criteria().lt("foo").not().getCriteriaObject();
-
- assertThat(document, equalTo(new Document().append("$not", new Document("$lt", "foo"))));
- }
-
- @Test // DATAMONGO-1135
- public void geoJsonTypesShouldBeWrappedInGeometry() {
-
- Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).getCriteriaObject();
-
- assertThat(document, isBsonObject().containing("foo.$near.$geometry", new GeoJsonPoint(100, 200)));
- }
-
- @Test // DATAMONGO-1135
- public void legacyCoordinateTypesShouldNotBeWrappedInGeometry() {
-
- Document document = new Criteria("foo").near(new Point(100, 200)).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAllClearWithBitPositions() {
- assertThat(document, isBsonObject().notContaining("foo.$near.$geometry"));
+ assertThat(ops.find(query(where("value").bits().allClear(Arrays.asList(1, 5))), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
}
- @Test // DATAMONGO-1135
- public void maxDistanceShouldBeMappedInsideNearWhenUsedAlongWithGeoJsonType() {
-
- Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).maxDistance(50D).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAllClearWithNumericBitmask() {
- assertThat(document, isBsonObject().containing("foo.$near.$maxDistance", 50D));
+ assertThat(ops.find(query(where("value").bits().allClear(35)), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
}
- @Test // DATAMONGO-1135
- public void maxDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
-
- Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).maxDistance(50D).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAllClearWithStringBitmask() {
- assertThat(document, isBsonObject().containing("foo.$nearSphere.$maxDistance", 50D));
+ assertThat(ops.find(query(where("value").bits().allClear("ID==")), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
}
- @Test // DATAMONGO-1110
- public void minDistanceShouldBeMappedInsideNearWhenUsedAlongWithGeoJsonType() {
-
- Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).minDistance(50D).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAllSetWithBitPositions() {
- assertThat(document, isBsonObject().containing("foo.$near.$minDistance", 50D));
+ assertThat(ops.find(query(where("value").bits().allSet(Arrays.asList(1, 5))), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR, ONE_HUNDRED_TWO);
}
- @Test // DATAMONGO-1110
- public void minDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
-
- Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).minDistance(50D).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAllSetWithNumericBitmask() {
- assertThat(document, isBsonObject().containing("foo.$nearSphere.$minDistance", 50D));
+ assertThat(ops.find(query(where("value").bits().allSet(50)), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR);
}
- @Test // DATAMONGO-1110
- public void minAndMaxDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
-
- Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).minDistance(50D).maxDistance(100D)
- .getCriteriaObject();
-
- assertThat(document, isBsonObject().containing("foo.$nearSphere.$minDistance", 50D));
- assertThat(document, isBsonObject().containing("foo.$nearSphere.$maxDistance", 100D));
- }
+ @Test // DATAMONGO-1808
+ public void bitsAllSetWithStringBitmask() {
- @Test(expected = IllegalArgumentException.class) // DATAMONGO-1134
- public void intersectsShouldThrowExceptionWhenCalledWihtNullValue() {
- new Criteria("foo").intersects(null);
+ assertThat(ops.find(query(where("value").bits().allSet("MC==")), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR);
}
- @Test // DATAMONGO-1134
- public void intersectsShouldWrapGeoJsonTypeInGeometryCorrectly() {
-
- GeoJsonLineString lineString = new GeoJsonLineString(new Point(0, 0), new Point(10, 10));
- Document document = new Criteria("foo").intersects(lineString).getCriteriaObject();
+ @Test // DATAMONGO-1808
+ public void bitsAnyClearWithBitPositions() {
- assertThat(document, isBsonObject().containing("foo.$geoIntersects.$geometry", lineString));
+ assertThat(ops.find(query(where("value").bits().anyClear(Arrays.asList(1, 5))), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
}
- @Test // DATAMONGO-1835
- public void extractsJsonSchemaInChainCorrectly() {
-
- MongoJsonSchema schema = MongoJsonSchema.builder().required("name").build();
- Criteria critera = Criteria.where("foo").is("bar").andDocumentStructureMatches(schema);
+ @Test // DATAMONGO-1808
+ public void bitsAnyClearWithNumericBitmask() {
- assertThat(critera.getCriteriaObject(), is(equalTo(new Document("foo", "bar").append("$jsonSchema",
- new Document("type", "object").append("required", Collections.singletonList("name"))))));
+ assertThat(ops.find(query(where("value").bits().anyClear(35)), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR, TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
}
- @Test // DATAMONGO-1835
- public void extractsJsonSchemaFromFactoryMethodCorrectly() {
-
- MongoJsonSchema schema = MongoJsonSchema.builder().required("name").build();
- Criteria critera = Criteria.matchingDocumentStructure(schema);
+ @Test // DATAMONGO-1808
+ public void bitsAnyClearWithStringBitmask() {
- assertThat(critera.getCriteriaObject(), is(equalTo(new Document("$jsonSchema",
- new Document("type", "object").append("required", Collections.singletonList("name"))))));
+ assertThat(ops.find(query(where("value").bits().anyClear("MC==")), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
}
@Test // DATAMONGO-1808
- public void testBitsAllClear() {
- Criteria numericBitmaskCriteria = new Criteria("field").bitsAllClear(0b101);
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAllClear\" : 5} }"),
- numericBitmaskCriteria.getCriteriaObject());
-
- Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAllClear(Arrays.asList(0, 2));
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAllClear\" : [ 0, 2 ]} }"),
- bitPositionsBitmaskCriteria.getCriteriaObject());
+ public void bitsAnySetWithBitPositions() {
+
+ assertThat(ops.find(query(where("value").bits().anySet(Arrays.asList(1, 5))), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR, ONE_HUNDRED_TWO);
}
@Test // DATAMONGO-1808
- public void testBitsAllSet() {
- Criteria numericBitmaskCriteria = new Criteria("field").bitsAllSet(0b101);
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAllSet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject());
+ public void bitsAnySetWithNumericBitmask() {
- Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAllSet(Arrays.asList(0, 2));
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAllSet\" : [ 0, 2 ]} }"),
- bitPositionsBitmaskCriteria.getCriteriaObject());
+ assertThat(ops.find(query(where("value").bits().anySet(35)), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR, ONE_HUNDRED_TWO);
}
@Test // DATAMONGO-1808
- public void testBitsAnyClear() {
- Criteria numericBitmaskCriteria = new Criteria("field").bitsAnyClear(0b101);
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : 5} }"),
- numericBitmaskCriteria.getCriteriaObject());
-
- Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAnyClear(Arrays.asList(0, 2));
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : [ 0, 2 ]} }"),
- bitPositionsBitmaskCriteria.getCriteriaObject());
+ public void bitsAnySetWithStringBitmask() {
+
+ assertThat(ops.find(query(where("value").bits().anySet("MC==")), DocumentWithBitmask.class))
+ .containsExactlyInAnyOrder(FIFTY_FOUR, TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
}
- @Test // DATAMONGO-1808
- public void testBitsAnySet() {
- Criteria numericBitmaskCriteria = new Criteria("field").bitsAnySet(0b101);
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject());
+ @Data
+ @EqualsAndHashCode(exclude = "value")
+ @AllArgsConstructor
+ static class DocumentWithBitmask {
- Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAnySet(Arrays.asList(0, 2));
- assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : [ 0, 2 ]} }"),
- bitPositionsBitmaskCriteria.getCriteriaObject());
+ @Id String id;
+ Object value;
+ String binaryValue;
}
}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaUnitTests.java
new file mode 100644
index 000000000..c492bd615
--- /dev/null
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/CriteriaUnitTests.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2010-2018 the original author or authors.
+ *
+ * Licensed 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.springframework.data.mongodb.core.query;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.bson.Document;
+import org.junit.Test;
+import org.springframework.data.geo.Point;
+import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
+import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
+import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
+import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
+
+/**
+ * @author Oliver Gierke
+ * @author Thomas Darimont
+ * @author Christoph Strobl
+ * @author Andreas Zink
+ */
+public class CriteriaUnitTests {
+
+ @Test
+ public void testSimpleCriteria() {
+ Criteria c = new Criteria("name").is("Bubba");
+ assertEquals(Document.parse("{ \"name\" : \"Bubba\"}"), c.getCriteriaObject());
+ }
+
+ @Test
+ public void testNotEqualCriteria() {
+ Criteria c = new Criteria("name").ne("Bubba");
+ assertEquals(Document.parse("{ \"name\" : { \"$ne\" : \"Bubba\"}}"), c.getCriteriaObject());
+ }
+
+ @Test
+ public void buildsIsNullCriteriaCorrectly() {
+
+ Document reference = new Document("name", null);
+
+ Criteria criteria = new Criteria("name").is(null);
+ assertThat(criteria.getCriteriaObject(), is(reference));
+ }
+
+ @Test
+ public void testChainedCriteria() {
+ Criteria c = new Criteria("name").is("Bubba").and("age").lt(21);
+ assertEquals(Document.parse("{ \"name\" : \"Bubba\" , \"age\" : { \"$lt\" : 21}}"), c.getCriteriaObject());
+ }
+
+ @Test(expected = InvalidMongoDbApiUsageException.class)
+ public void testCriteriaWithMultipleConditionsForSameKey() {
+ Criteria c = new Criteria("name").gte("M").and("name").ne("A");
+ c.getCriteriaObject();
+ }
+
+ @Test
+ public void equalIfCriteriaMatches() {
+
+ Criteria left = new Criteria("name").is("Foo").and("lastname").is("Bar");
+ Criteria right = new Criteria("name").is("Bar").and("lastname").is("Bar");
+
+ assertThat(left, is(not(right)));
+ assertThat(right, is(not(left)));
+ }
+
+ @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
+ public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
+
+ new Criteria() //
+ .not() //
+ .andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
+ }
+
+ @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
+ public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
+
+ new Criteria() //
+ .not() //
+ .orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
+ }
+
+ @Test(expected = IllegalArgumentException.class) // DATAMONGO-507
+ public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
+
+ new Criteria() //
+ .not() //
+ .norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
+ }
+
+ @Test // DATAMONGO-507
+ public void shouldNegateFollowingSimpleExpression() {
+
+ Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
+ Document co = c.getCriteriaObject();
+
+ assertThat(co, is(notNullValue()));
+ assertThat(co, is(Document.parse("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}")));
+ }
+
+ @Test // DATAMONGO-1068
+ public void getCriteriaObjectShouldReturnEmptyDocumentWhenNoCriteriaSpecified() {
+
+ Document document = new Criteria().getCriteriaObject();
+
+ assertThat(document, equalTo(new Document()));
+ }
+
+ @Test // DATAMONGO-1068
+ public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresent() {
+
+ Document document = new Criteria().lt("foo").getCriteriaObject();
+
+ assertThat(document, equalTo(new Document().append("$lt", "foo")));
+ }
+
+ @Test // DATAMONGO-1068
+ public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresentButMultipleCriteriasPresent() {
+
+ Document document = new Criteria().lt("foo").gt("bar").getCriteriaObject();
+
+ assertThat(document, equalTo(new Document().append("$lt", "foo").append("$gt", "bar")));
+ }
+
+ @Test // DATAMONGO-1068
+ public void getCriteriaObjectShouldRespectNotWhenNoKeyPresent() {
+
+ Document document = new Criteria().lt("foo").not().getCriteriaObject();
+
+ assertThat(document, equalTo(new Document().append("$not", new Document("$lt", "foo"))));
+ }
+
+ @Test // DATAMONGO-1135
+ public void geoJsonTypesShouldBeWrappedInGeometry() {
+
+ Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$near.$geometry", new GeoJsonPoint(100, 200)));
+ }
+
+ @Test // DATAMONGO-1135
+ public void legacyCoordinateTypesShouldNotBeWrappedInGeometry() {
+
+ Document document = new Criteria("foo").near(new Point(100, 200)).getCriteriaObject();
+
+ assertThat(document, isBsonObject().notContaining("foo.$near.$geometry"));
+ }
+
+ @Test // DATAMONGO-1135
+ public void maxDistanceShouldBeMappedInsideNearWhenUsedAlongWithGeoJsonType() {
+
+ Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).maxDistance(50D).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$near.$maxDistance", 50D));
+ }
+
+ @Test // DATAMONGO-1135
+ public void maxDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
+
+ Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).maxDistance(50D).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$nearSphere.$maxDistance", 50D));
+ }
+
+ @Test // DATAMONGO-1110
+ public void minDistanceShouldBeMappedInsideNearWhenUsedAlongWithGeoJsonType() {
+
+ Document document = new Criteria("foo").near(new GeoJsonPoint(100, 200)).minDistance(50D).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$near.$minDistance", 50D));
+ }
+
+ @Test // DATAMONGO-1110
+ public void minDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
+
+ Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).minDistance(50D).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$nearSphere.$minDistance", 50D));
+ }
+
+ @Test // DATAMONGO-1110
+ public void minAndMaxDistanceShouldBeMappedInsideNearSphereWhenUsedAlongWithGeoJsonType() {
+
+ Document document = new Criteria("foo").nearSphere(new GeoJsonPoint(100, 200)).minDistance(50D).maxDistance(100D)
+ .getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$nearSphere.$minDistance", 50D));
+ assertThat(document, isBsonObject().containing("foo.$nearSphere.$maxDistance", 100D));
+ }
+
+ @Test(expected = IllegalArgumentException.class) // DATAMONGO-1134
+ public void intersectsShouldThrowExceptionWhenCalledWihtNullValue() {
+ new Criteria("foo").intersects(null);
+ }
+
+ @Test // DATAMONGO-1134
+ public void intersectsShouldWrapGeoJsonTypeInGeometryCorrectly() {
+
+ GeoJsonLineString lineString = new GeoJsonLineString(new Point(0, 0), new Point(10, 10));
+ Document document = new Criteria("foo").intersects(lineString).getCriteriaObject();
+
+ assertThat(document, isBsonObject().containing("foo.$geoIntersects.$geometry", lineString));
+ }
+
+ @Test // DATAMONGO-1835
+ public void extractsJsonSchemaInChainCorrectly() {
+
+ MongoJsonSchema schema = MongoJsonSchema.builder().required("name").build();
+ Criteria criteria = Criteria.where("foo").is("bar").andDocumentStructureMatches(schema);
+
+ assertThat(criteria.getCriteriaObject(), is(equalTo(new Document("foo", "bar").append("$jsonSchema",
+ new Document("type", "object").append("required", Collections.singletonList("name"))))));
+ }
+
+ @Test // DATAMONGO-1835
+ public void extractsJsonSchemaFromFactoryMethodCorrectly() {
+
+ MongoJsonSchema schema = MongoJsonSchema.builder().required("name").build();
+ Criteria criteria = Criteria.matchingDocumentStructure(schema);
+
+ assertThat(criteria.getCriteriaObject(), is(equalTo(new Document("$jsonSchema",
+ new Document("type", "object").append("required", Collections.singletonList("name"))))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAllClearWithIntBitmaskCorrectly() {
+
+ Criteria numericBitmaskCriteria = new Criteria("field").bits().allClear(0b101);
+
+ assertThat(numericBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAllClear\" : 5} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAllClearWithPositionListCorrectly() {
+
+ Criteria bitPositionsBitmaskCriteria = new Criteria("field").bits().allClear(Arrays.asList(0, 2));
+
+ assertThat(bitPositionsBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAllClear\" : [ 0, 2 ]} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAllSetWithIntBitmaskCorrectly() {
+
+ Criteria numericBitmaskCriteria = new Criteria("field").bits().allSet(0b101);
+
+ assertThat(numericBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAllSet\" : 5} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAllSetWithPositionListCorrectly() {
+
+ Criteria bitPositionsBitmaskCriteria = new Criteria("field").bits().allSet(Arrays.asList(0, 2));
+
+ assertThat(bitPositionsBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAllSet\" : [ 0, 2 ]} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAnyClearWithIntBitmaskCorrectly() {
+
+ Criteria numericBitmaskCriteria = new Criteria("field").bits().anyClear(0b101);
+
+ assertThat(numericBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : 5} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAnyClearWithPositionListCorrectly() {
+
+ Criteria bitPositionsBitmaskCriteria = new Criteria("field").bits().anyClear(Arrays.asList(0, 2));
+
+ assertThat(bitPositionsBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : [ 0, 2 ]} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAnySetWithIntBitmaskCorrectly() {
+
+ Criteria numericBitmaskCriteria = new Criteria("field").bits().anySet(0b101);
+
+ assertThat(numericBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAnySet\" : 5} }"))));
+ }
+
+ @Test // DATAMONGO-1808
+ public void shouldAppendBitsAnySetWithPositionListCorrectly() {
+
+ Criteria bitPositionsBitmaskCriteria = new Criteria("field").bits().anySet(Arrays.asList(0, 2));
+
+ assertThat(bitPositionsBitmaskCriteria.getCriteriaObject(),
+ is(equalTo(Document.parse("{ \"field\" : { \"$bitsAnySet\" : [ 0, 2 ]} }"))));
+ }
+}
diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc
index ed4241552..07ecdc9fd 100644
--- a/src/main/asciidoc/reference/mongodb.adoc
+++ b/src/main/asciidoc/reference/mongodb.adoc
@@ -1073,6 +1073,7 @@ As you can see most methods return the `Criteria` object to provide a fluent sty
* `Criteria` *size* `(int s)` Creates a criterion using the `$size` operator
* `Criteria` *type* `(int t)` Creates a criterion using the `$type` operator
* `Criteria` *matchingDocumentStructure* `(MongoJsonSchema schema)` Creates a criterion using the `$jsonSchema` operator for <>. `$jsonSchema` can only be applied on the top level of a query and not property specific. Use the `properties` attribute of the schema to match against nested fields.
+* `Criteria` *bits()* is the gateway to https://docs.mongodb.com/manual/reference/operator/query-bitwise/[MongoDB bitwise query operators] like `$bitsAllClear`.
There are also methods on the Criteria class for geospatial queries. Here is a listing but look at the section on <> to see them in action.