DATAMONGO-1459 - Added support for any-match mode in Query-by-example.
MongoExampleMapper now $or-concatenates the predicates derived from the example in case the ExampleMatcher expresses any-match binding to be desired. Moved integration tests for Query-by-example to the appropriate package and polished the code a little. Related ticket: DATACMNS-879.
This commit is contained in:
@@ -92,7 +92,6 @@ public class MongoExampleMapper {
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public DBObject getMappedExample(Example<?> example, MongoPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(example, "Example must not be null!");
|
||||
@@ -108,10 +107,24 @@ public class MongoExampleMapper {
|
||||
|
||||
applyPropertySpecs("", reference, example.getProbeType(), matcherAccessor);
|
||||
|
||||
this.converter.getTypeMapper().writeTypeRestrictions(reference, getTypesToMatch(example));
|
||||
|
||||
return ObjectUtils.nullSafeEquals(NullHandler.INCLUDE, matcherAccessor.getNullHandler()) ? reference
|
||||
DBObject flattened = ObjectUtils.nullSafeEquals(NullHandler.INCLUDE, matcherAccessor.getNullHandler()) ? reference
|
||||
: new BasicDBObject(SerializationUtils.flattenMap(reference));
|
||||
DBObject result = example.getMatcher().isAllMatching() ? flattened : orConcatenate(flattened);
|
||||
|
||||
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DBObject orConcatenate(DBObject source) {
|
||||
|
||||
List<DBObject> foo = new ArrayList<DBObject>(source.keySet().size());
|
||||
|
||||
for (String key : source.keySet()) {
|
||||
foo.add(new BasicDBObject(key, source.get(key)));
|
||||
}
|
||||
|
||||
return new BasicDBObject("$or", foo);
|
||||
}
|
||||
|
||||
private Set<Class<?>> getTypesToMatch(Example<?> example) {
|
||||
|
||||
@@ -13,18 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.temp;
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.core.Is;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
@@ -33,18 +37,39 @@ import org.springframework.data.mongodb.core.query.Query;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Integration tests for Query-by-example.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class QueryByExampleTests {
|
||||
|
||||
MongoTemplate template;
|
||||
MongoOperations operations;
|
||||
Person p1, p2, p3;
|
||||
|
||||
@Before
|
||||
public void setUp() throws UnknownHostException {
|
||||
|
||||
template = new MongoTemplate(new MongoClient(), "query-by-example");
|
||||
template.remove(new Query(), Person.class);
|
||||
operations = new MongoTemplate(new MongoClient(), "query-by-example");
|
||||
operations.remove(new Query(), Person.class);
|
||||
|
||||
p1 = new Person();
|
||||
p1.firstname = "bran";
|
||||
p1.middlename = "a";
|
||||
p1.lastname = "stark";
|
||||
|
||||
p2 = new Person();
|
||||
p2.firstname = "jon";
|
||||
p2.lastname = "snow";
|
||||
|
||||
p3 = new Person();
|
||||
p3.firstname = "arya";
|
||||
p3.lastname = "stark";
|
||||
|
||||
operations.save(p1);
|
||||
operations.save(p2);
|
||||
operations.save(p3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,15 +78,14 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleShouldWorkForSimpleProperty() {
|
||||
|
||||
init();
|
||||
|
||||
Person sample = new Person();
|
||||
sample.lastname = "stark";
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(2));
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(p1, p3));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,16 +94,15 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleShouldWorkForMultipleProperties() {
|
||||
|
||||
init();
|
||||
|
||||
Person sample = new Person();
|
||||
sample.lastname = "stark";
|
||||
sample.firstname = "arya";
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(1));
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result, hasItem(p3));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,18 +111,17 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleShouldWorkForIdProperty() {
|
||||
|
||||
init();
|
||||
|
||||
Person p4 = new Person();
|
||||
template.save(p4);
|
||||
operations.save(p4);
|
||||
|
||||
Person sample = new Person();
|
||||
sample.id = p4.id;
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(1));
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result, hasItem(p4));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,17 +130,14 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleShouldReturnEmptyListIfNotMatching() {
|
||||
|
||||
init();
|
||||
|
||||
Person sample = new Person();
|
||||
sample.firstname = "jon";
|
||||
sample.firstname = "stark";
|
||||
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(0));
|
||||
assertThat(result, is(empty()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,14 +146,13 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleShouldReturnEverythingWhenSampleIsEmpty() {
|
||||
|
||||
init();
|
||||
|
||||
Person sample = new Person();
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(3));
|
||||
assertThat(result, hasSize(3));
|
||||
assertThat(result, hasItems(p1, p2, p3));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,47 +161,39 @@ public class QueryByExampleTests {
|
||||
@Test
|
||||
public void findByExampleWithCriteria() {
|
||||
|
||||
init();
|
||||
|
||||
Person sample = new Person();
|
||||
sample.lastname = "stark";
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(sample)).and("firstname").regex("^ary*"));
|
||||
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
Assert.assertThat(result.size(), Is.is(1));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
assertThat(result.size(), is(1));
|
||||
}
|
||||
|
||||
public void init() {
|
||||
/**
|
||||
* @see DATAMONGO-1459
|
||||
*/
|
||||
@Test
|
||||
public void findsExampleUsingAnyMatch() {
|
||||
|
||||
Person p1 = new Person();
|
||||
p1.firstname = "bran";
|
||||
p1.lastname = "stark";
|
||||
Person probe = new Person();
|
||||
probe.lastname = "snow";
|
||||
probe.middlename = "a";
|
||||
|
||||
Person p2 = new Person();
|
||||
p2.firstname = "jon";
|
||||
p2.lastname = "snow";
|
||||
Query query = Query.query(Criteria.byExample(Example.of(probe, ExampleMatcher.matchingAny())));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
Person p3 = new Person();
|
||||
p3.firstname = "arya";
|
||||
p3.lastname = "stark";
|
||||
|
||||
template.save(p1);
|
||||
template.save(p2);
|
||||
template.save(p3);
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(p1, p2));
|
||||
}
|
||||
|
||||
@Document(collection = "dramatis-personae")
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
static class Person {
|
||||
|
||||
@Id String id;
|
||||
String firstname;
|
||||
|
||||
String firstname, middlename;
|
||||
@Field("last_name") String lastname;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Person [id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers;
|
||||
import org.springframework.data.domain.ExampleMatcher.StringMatcher;
|
||||
import org.springframework.data.geo.Point;
|
||||
@@ -332,7 +333,7 @@ public class MongoExampleMapperUnitTests {
|
||||
DBObject dbo = mapper.getMappedExample(of(probe), context.getPersistentEntity(WithDBRef.class));
|
||||
com.mongodb.DBRef reference = getTypedValue(dbo, "referenceDocument", com.mongodb.DBRef.class);
|
||||
|
||||
assertThat(reference.getId(), Is.<Object> is("200"));
|
||||
assertThat(reference.getId(), Is.<Object>is("200"));
|
||||
assertThat(reference.getCollectionName(), is("refDoc"));
|
||||
}
|
||||
|
||||
@@ -361,8 +362,8 @@ public class MongoExampleMapperUnitTests {
|
||||
|
||||
DBObject dbo = mapper.getMappedExample(of(probe), context.getPersistentEntity(WithDBRef.class));
|
||||
|
||||
assertThat(dbo.get("legacyPoint.x"), Is.<Object> is(10D));
|
||||
assertThat(dbo.get("legacyPoint.y"), Is.<Object> is(20D));
|
||||
assertThat(dbo.get("legacyPoint.x"), Is.<Object>is(10D));
|
||||
assertThat(dbo.get("legacyPoint.y"), Is.<Object>is(20D));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,6 +483,21 @@ public class MongoExampleMapperUnitTests {
|
||||
assertThat(dbo, isBsonObject().containing("anotherStringValue", "calamity"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1459
|
||||
*/
|
||||
@Test
|
||||
public void mapsAnyMatchingExampleCorrectly() {
|
||||
|
||||
FlatDocument probe = new FlatDocument();
|
||||
probe.stringValue = "firefight";
|
||||
probe.customNamedField = "steelheart";
|
||||
|
||||
Example<FlatDocument> example = Example.of(probe, ExampleMatcher.matchingAny());
|
||||
|
||||
assertThat(mapper.getMappedExample(example), isBsonObject().containing("$or").containing("_class"));
|
||||
}
|
||||
|
||||
static class FlatDocument {
|
||||
|
||||
@Id String id;
|
||||
|
||||
Reference in New Issue
Block a user