DATAMONGO-1808 - Polishing.
Move individual methods under BitwiseCriteriaOperators, update Javadoc and split tests. Original Pull Request: #507
This commit is contained in:
@@ -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 <a href="https://docs.mongodb.com/manual/reference/operator/query/type/">MongoDB Query operator: $type</a>
|
||||
@@ -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
|
||||
* <a href="https://docs.mongodb.com/manual/reference/operator/query-bitwise/">bitwise operators</a> 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
|
||||
* <p>
|
||||
@@ -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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllClear/">MongoDB Query operator:
|
||||
* $bitsAllClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllClear/">MongoDB Query operator:
|
||||
* $bitsAllClear</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public Criteria bitsAllClear(Collection<Integer> bitPositions) {
|
||||
criteria.put("$bitsAllClear", bitPositions);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a criterion using the {@literal $bitsAllSet} operator.
|
||||
*
|
||||
* @param numericBitmask non-negative numeric bitmask
|
||||
* @return
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/">MongoDB Query operator:
|
||||
* $bitsAllSet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/">MongoDB Query operator:
|
||||
* $bitsAllSet</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public Criteria bitsAllSet(Collection<Integer> bitPositions) {
|
||||
criteria.put("$bitsAllSet", bitPositions);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a criterion using the {@literal $bitsAnyClear} operator.
|
||||
*
|
||||
* @param numericBitmask non-negative numeric bitmask
|
||||
* @return
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnyClear/">MongoDB Query operator:
|
||||
* $bitsAnyClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnyClear/">MongoDB Query operator:
|
||||
* $bitsAnyClear</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public Criteria bitsAnyClear(Collection<Integer> bitPositions) {
|
||||
criteria.put("$bitsAnyClear", bitPositions);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a criterion using the {@literal $bitsAnySet} operator.
|
||||
*
|
||||
* @param numericBitmask non-negative numeric bitmask
|
||||
* @return
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnySet/">MongoDB Query operator:
|
||||
* $bitsAnySet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnySet/">MongoDB Query operator:
|
||||
* $bitsAnySet</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public Criteria bitsAnySet(Collection<Integer> 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 <a href="https://docs.mongodb.com/manual/reference/operator/query-bitwise/">bitwise query
|
||||
* operators</a> like {@code $bitsAllClear, $bitsAllSet,...} for usage with {@link Criteria#bits()} and {@link Query}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.1
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/query-bitwise/">https://docs.mongodb.com/manual/reference/operator/query-bitwise/</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllClear/">MongoDB Query operator:
|
||||
* $bitsAllClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllClear/">MongoDB Query operator:
|
||||
* $bitsAllClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllClear/">MongoDB Query operator:
|
||||
* $bitsAllClear</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
Criteria allClear(List<Integer> 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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/">MongoDB Query operator:
|
||||
* $bitsAllSet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/">MongoDB Query operator:
|
||||
* $bitsAllSet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/">MongoDB Query operator:
|
||||
* $bitsAllSet</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
Criteria allSet(List<Integer> 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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnyClear/">MongoDB Query operator:
|
||||
* $bitsAnyClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnyClear/">MongoDB Query operator:
|
||||
* $bitsAnyClear</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnyClear/">MongoDB Query operator:
|
||||
* $bitsAnyClear</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
Criteria anyClear(List<Integer> 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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnySet/">MongoDB Query operator:
|
||||
* $bitsAnySet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnySet/">MongoDB Query operator:
|
||||
* $bitsAnySet</a>
|
||||
* @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 <a href="https://docs.mongodb.com/manual/reference/operator/query/bitsAnySet/">MongoDB Query operator:
|
||||
* $bitsAnySet</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
Criteria anySet(List<Integer> 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<Integer> 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<Integer> 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<Integer> 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<Integer> positions) {
|
||||
return positions("$bitsAnySet", positions);
|
||||
}
|
||||
|
||||
private Criteria positions(String operator, List<Integer> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
MongoOperations ops;
|
||||
MongoClient client;
|
||||
|
||||
@Test
|
||||
public void testNotEqualCriteria() {
|
||||
Criteria c = new Criteria("name").ne("Bubba");
|
||||
assertEquals(Document.parse("{ \"name\" : { \"$ne\" : \"Bubba\"}}"), c.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");
|
||||
|
||||
@Test
|
||||
public void buildsIsNullCriteriaCorrectly() {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
Document reference = new Document("name", null);
|
||||
client = new MongoClient();
|
||||
ops = new MongoTemplate(client, "criteria-tests");
|
||||
|
||||
Criteria criteria = new Criteria("name").is(null);
|
||||
assertThat(criteria.getCriteriaObject(), is(reference));
|
||||
}
|
||||
ops.dropCollection(DocumentWithBitmask.class);
|
||||
|
||||
@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 critera = Criteria.where("foo").is("bar").andDocumentStructureMatches(schema);
|
||||
|
||||
assertThat(critera.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 critera = Criteria.matchingDocumentStructure(schema);
|
||||
|
||||
assertThat(critera.getCriteriaObject(), is(equalTo(new Document("$jsonSchema",
|
||||
new Document("type", "object").append("required", Collections.singletonList("name"))))));
|
||||
ops.insert(FIFTY_FOUR);
|
||||
ops.insert(TWENTY_INT);
|
||||
ops.insert(TWENTY_FLOAT);
|
||||
ops.insert(ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void testBitsAllClear() {
|
||||
Criteria numericBitmaskCriteria = new Criteria("field").bitsAllClear(0b101);
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAllClear\" : 5} }"),
|
||||
numericBitmaskCriteria.getCriteriaObject());
|
||||
public void bitsAllClearWithBitPositions() {
|
||||
|
||||
Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAllClear(Arrays.asList(0, 2));
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAllClear\" : [ 0, 2 ]} }"),
|
||||
bitPositionsBitmaskCriteria.getCriteriaObject());
|
||||
assertThat(ops.find(query(where("value").bits().allClear(Arrays.asList(1, 5))), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void testBitsAllSet() {
|
||||
Criteria numericBitmaskCriteria = new Criteria("field").bitsAllSet(0b101);
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAllSet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject());
|
||||
public void bitsAllClearWithNumericBitmask() {
|
||||
|
||||
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().allClear(35)), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void testBitsAnyClear() {
|
||||
Criteria numericBitmaskCriteria = new Criteria("field").bitsAnyClear(0b101);
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : 5} }"),
|
||||
numericBitmaskCriteria.getCriteriaObject());
|
||||
public void bitsAllClearWithStringBitmask() {
|
||||
|
||||
Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAnyClear(Arrays.asList(0, 2));
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAnyClear\" : [ 0, 2 ]} }"),
|
||||
bitPositionsBitmaskCriteria.getCriteriaObject());
|
||||
assertThat(ops.find(query(where("value").bits().allClear("ID==")), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void testBitsAnySet() {
|
||||
Criteria numericBitmaskCriteria = new Criteria("field").bitsAnySet(0b101);
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : 5} }"), numericBitmaskCriteria.getCriteriaObject());
|
||||
public void bitsAllSetWithBitPositions() {
|
||||
|
||||
Criteria bitPositionsBitmaskCriteria = new Criteria("field").bitsAnySet(Arrays.asList(0, 2));
|
||||
assertEquals(Document.parse("{ \"field\" : { \"$bitsAnySet\" : [ 0, 2 ]} }"),
|
||||
bitPositionsBitmaskCriteria.getCriteriaObject());
|
||||
assertThat(ops.find(query(where("value").bits().allSet(Arrays.asList(1, 5))), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR, ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAllSetWithNumericBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().allSet(50)), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAllSetWithStringBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().allSet("MC==")), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAnyClearWithBitPositions() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().anyClear(Arrays.asList(1, 5))), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAnyClearWithNumericBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().anyClear(35)), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR, TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAnyClearWithStringBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().anyClear("MC==")), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
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 bitsAnySetWithNumericBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().anySet(35)), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR, ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1808
|
||||
public void bitsAnySetWithStringBitmask() {
|
||||
|
||||
assertThat(ops.find(query(where("value").bits().anySet("MC==")), DocumentWithBitmask.class))
|
||||
.containsExactlyInAnyOrder(FIFTY_FOUR, TWENTY_INT, TWENTY_FLOAT, ONE_HUNDRED_TWO);
|
||||
}
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(exclude = "value")
|
||||
@AllArgsConstructor
|
||||
static class DocumentWithBitmask {
|
||||
|
||||
@Id String id;
|
||||
Object value;
|
||||
String binaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ]} }"))));
|
||||
}
|
||||
}
|
||||
@@ -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 <<mongo.jsonSchema,JSON schema criteria>>. `$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 <<mongo.geospatial,GeoSpatial Queries>> to see them in action.
|
||||
|
||||
Reference in New Issue
Block a user