DATAMONGO-1768 - Allow ignoring type restriction when issuing QBE.
We now allow to remove the type restriction inferred by the QBE mapping via an ignored path expression on the ExampleMatcher. This allows to create untyped QBE expressions returning all entities matching the query without limiting the result to types assignable to the probe itself. Original pull request: #496.
This commit is contained in:
committed by
Mark Paluch
parent
faf7e36311
commit
5fedbe9598
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.data.domain.ExampleMatcher.NullHandler;
|
||||
import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
|
||||
import org.springframework.data.domain.ExampleMatcher.StringMatcher;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||
import org.springframework.data.support.ExampleMatcherAccessor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -91,7 +93,7 @@ public class MongoExampleMapper {
|
||||
|
||||
Document reference = (Document) converter.convertToMongoType(example.getProbe());
|
||||
|
||||
if (entity.getIdProperty() != null) {
|
||||
if (entity.getIdProperty() != null && ClassUtils.isAssignable(entity.getType(), example.getProbeType())) {
|
||||
|
||||
Object identifier = entity.getIdentifierAccessor(example.getProbe()).getIdentifier();
|
||||
if (identifier == null) {
|
||||
@@ -107,9 +109,7 @@ public class MongoExampleMapper {
|
||||
: new Document(SerializationUtils.flattenMap(reference));
|
||||
Document result = example.getMatcher().isAllMatching() ? flattened : orConcatenate(flattened);
|
||||
|
||||
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
|
||||
|
||||
return result;
|
||||
return updateTypeRestrictions(result, example);
|
||||
}
|
||||
|
||||
private static Document orConcatenate(Document source) {
|
||||
@@ -288,4 +288,39 @@ public class MongoExampleMapper {
|
||||
return MatchMode.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
private Document updateTypeRestrictions(Document query, Example example) {
|
||||
|
||||
Document result = new Document();
|
||||
|
||||
if (isTypeRestricting(example.getMatcher())) {
|
||||
|
||||
result.putAll(query);
|
||||
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
|
||||
return result;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Object> entry : query.entrySet()) {
|
||||
if (!this.converter.getTypeMapper().isTypeKey(entry.getKey())) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isTypeRestricting(ExampleMatcher matcher) {
|
||||
|
||||
if (matcher.getIgnoredPaths().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String path : matcher.getIgnoredPaths()) {
|
||||
if (this.converter.getTypeMapper().isTypeKey(path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,32 @@ public class QueryByExampleTests {
|
||||
assertThat(result, hasItems(p1, p2));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void typedExampleMatchesNothingIfTypesDoNotMatch() {
|
||||
|
||||
NotAPersonButStillMatchingFields probe = new NotAPersonButStillMatchingFields();
|
||||
probe.lastname = "stark";
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(probe)));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
assertThat(result, hasSize(0));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void untypedExampleMatchesCorrectly() {
|
||||
|
||||
NotAPersonButStillMatchingFields probe = new NotAPersonButStillMatchingFields();
|
||||
probe.lastname = "stark";
|
||||
|
||||
Query query = new Query(
|
||||
new Criteria().alike(Example.of(probe, ExampleMatcher.matching().withIgnorePaths("_class"))));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(p1, p3));
|
||||
}
|
||||
|
||||
@Document(collection = "dramatis-personae")
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@@ -175,4 +201,12 @@ public class QueryByExampleTests {
|
||||
String firstname, middlename;
|
||||
@Field("last_name") String lastname;
|
||||
}
|
||||
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
static class NotAPersonButStillMatchingFields {
|
||||
|
||||
String firstname, middlename;
|
||||
@Field("last_name") String lastname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bson.conversions.Bson;
|
||||
@@ -36,8 +37,7 @@ import org.mockito.junit.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.domain.ExampleMatcher.*;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapperUnitTests.ClassWithGeoTypes;
|
||||
@@ -47,6 +47,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.test.util.IsBsonObject;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -434,6 +435,53 @@ public class MongoExampleMapperUnitTests {
|
||||
assertThat(mapper.getMappedExample(example), isBsonObject().containing("$or").containing("_class"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void allowIgnoringTypeRestrictionBySettingUpTypeKeyAsAnIgnoredPath() {
|
||||
|
||||
WrapperDocument probe = new WrapperDocument();
|
||||
probe.flatDoc = new FlatDocument();
|
||||
probe.flatDoc.stringValue = "conflux";
|
||||
|
||||
org.bson.Document document = mapper
|
||||
.getMappedExample(Example.of(probe, ExampleMatcher.matching().withIgnorePaths("_class")));
|
||||
|
||||
assertThat(document, isBsonObject().notContaining("_class"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void allowIgnoringTypeRestrictionBySettingUpTypeKeyAsAnIgnoredPathWhenUsingCustomTypeMapper() {
|
||||
|
||||
WrapperDocument probe = new WrapperDocument();
|
||||
probe.flatDoc = new FlatDocument();
|
||||
probe.flatDoc.stringValue = "conflux";
|
||||
|
||||
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(new DefaultDbRefResolver(factory), context);
|
||||
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper() {
|
||||
|
||||
@Override
|
||||
public boolean isTypeKey(String key) {
|
||||
return "_foo".equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeRestrictions(org.bson.Document result, Set<Class<?>> restrictedTypes) {
|
||||
result.put("_foo", "bar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeType(TypeInformation<?> info, Bson sink) {
|
||||
((org.bson.Document) sink).put("_foo", "bar");
|
||||
|
||||
}
|
||||
});
|
||||
mappingMongoConverter.afterPropertiesSet();
|
||||
|
||||
org.bson.Document document = new MongoExampleMapper(mappingMongoConverter)
|
||||
.getMappedExample(Example.of(probe, ExampleMatcher.matching().withIgnorePaths("_foo")));
|
||||
|
||||
assertThat(document, isBsonObject().notContaining("_class").notContaining("_foo"));
|
||||
}
|
||||
|
||||
static class FlatDocument {
|
||||
|
||||
@Id String id;
|
||||
|
||||
Reference in New Issue
Block a user