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 df8336285..502aeb408 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 @@ -56,6 +56,7 @@ import com.mongodb.BasicDBList; * @author Thomas Darimont * @author Christoph Strobl * @author Mark Paluch + * @author Andreas Zink */ public class Criteria implements CriteriaDefinition { @@ -663,6 +664,118 @@ 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) { 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 9aa7990b5..eab9e1d50 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,6 +3361,61 @@ 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 542911261..1bbcd28fb 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 @@ -19,6 +19,7 @@ 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; @@ -236,4 +237,46 @@ public class CriteriaTests { assertThat(critera.getCriteriaObject(), is(equalTo(new Document("$jsonSchema", new Document("type", "object").append("required", Collections.singletonList("name")))))); } + + @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()); + } + + @Test // DATAMONGO-1808 + public void testBitsAllSet() { + Criteria numericBitmaskCriteria = new Criteria("field").bitsAllSet(0b101); + assertEquals(Document.parse("{ \"field\" : { \"$bitsAllSet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject()); + + Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAllSet(Arrays.asList(0, 2)); + assertEquals(Document.parse("{ \"field\" : { \"$bitsAllSet\" : [ 0, 2 ]} }"), + bitPositionsBitmaskCriteria.getCriteriaObject()); + } + + @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()); + } + + @Test // DATAMONGO-1808 + public void testBitsAnySet() { + Criteria numericBitmaskCriteria = new Criteria("field").bitsAnySet(0b101); + assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject()); + + Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAnySet(Arrays.asList(0, 2)); + assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : [ 0, 2 ]} }"), + bitPositionsBitmaskCriteria.getCriteriaObject()); + } }