DATAMONGO-1768 - Introduce UntypedExampleMatcher.
Introducing UntypedExampleMatcher allows creation of QBE criteria that does not infer a strict type match. Original pull request: #496.
This commit is contained in:
committed by
Mark Paluch
parent
5fedbe9598
commit
2d825bed41
@@ -29,7 +29,6 @@ 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;
|
||||
@@ -40,6 +39,7 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.query.MongoRegexCreator;
|
||||
import org.springframework.data.mongodb.core.query.MongoRegexCreator.MatchMode;
|
||||
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||
import org.springframework.data.mongodb.core.query.UntypedExampleMatcher;
|
||||
import org.springframework.data.support.ExampleMatcherAccessor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -293,7 +293,7 @@ public class MongoExampleMapper {
|
||||
|
||||
Document result = new Document();
|
||||
|
||||
if (isTypeRestricting(example.getMatcher())) {
|
||||
if (isTypeRestricting(example)) {
|
||||
|
||||
result.putAll(query);
|
||||
this.converter.getTypeMapper().writeTypeRestrictions(result, getTypesToMatch(example));
|
||||
@@ -309,13 +309,17 @@ public class MongoExampleMapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isTypeRestricting(ExampleMatcher matcher) {
|
||||
private boolean isTypeRestricting(Example example) {
|
||||
|
||||
if (matcher.getIgnoredPaths().isEmpty()) {
|
||||
if (example.getMatcher() instanceof UntypedExampleMatcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (example.getMatcher().getIgnoredPaths().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String path : matcher.getIgnoredPaths()) {
|
||||
for (String path : example.getMatcher().getIgnoredPaths()) {
|
||||
if (this.converter.getTypeMapper().isTypeKey(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2017 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 lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ExampleMatcher} implementation for query by example (QBE). Unlike plain {@link ExampleMatcher} this untyped
|
||||
* counterpart does not enforce a strict type match when executing the query. This allows to use totally unrelated
|
||||
* example documents as references for querying collections as long as the used field/property names match.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class UntypedExampleMatcher implements ExampleMatcher {
|
||||
|
||||
private final ExampleMatcher delegate;
|
||||
|
||||
/**
|
||||
* Creates new {@link UntypedExampleMatcher}.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
private UntypedExampleMatcher(ExampleMatcher delegate) {
|
||||
|
||||
Assert.notNull(delegate, "Delegate must not be null!");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#matching()
|
||||
*/
|
||||
public static UntypedExampleMatcher matching() {
|
||||
return new UntypedExampleMatcher(ExampleMatcher.matching());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#matchingAny()
|
||||
*/
|
||||
public static UntypedExampleMatcher matchingAny() {
|
||||
return new UntypedExampleMatcher(ExampleMatcher.matchingAny());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#matchingAll()
|
||||
*/
|
||||
public static UntypedExampleMatcher matchingAll() {
|
||||
return new UntypedExampleMatcher(ExampleMatcher.matchingAll());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIgnorePaths(java.lang.String...)
|
||||
*/
|
||||
public UntypedExampleMatcher withIgnorePaths(String... ignoredPaths) {
|
||||
return new UntypedExampleMatcher(delegate.withIgnorePaths(ignoredPaths));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withStringMatcher(java.lang.String)
|
||||
*/
|
||||
public UntypedExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher) {
|
||||
return new UntypedExampleMatcher(delegate.withStringMatcher(defaultStringMatcher));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIgnoreCase()
|
||||
*/
|
||||
public UntypedExampleMatcher withIgnoreCase() {
|
||||
return new UntypedExampleMatcher(delegate.withIgnoreCase());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIgnoreCase(boolean)
|
||||
*/
|
||||
public UntypedExampleMatcher withIgnoreCase(boolean defaultIgnoreCase) {
|
||||
return new UntypedExampleMatcher(delegate.withIgnoreCase(defaultIgnoreCase));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withMatcher(java.lang.String, org.springframework.data.domain.ExampleMatcher.MatcherConfigurer)
|
||||
*/
|
||||
public UntypedExampleMatcher withMatcher(String propertyPath,
|
||||
MatcherConfigurer<GenericPropertyMatcher> matcherConfigurer) {
|
||||
return new UntypedExampleMatcher(delegate.withMatcher(propertyPath, matcherConfigurer));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withMatcher(java.lang.String, org.springframework.data.domain.ExampleMatcher.GenericPropertyMatcher)
|
||||
*/
|
||||
public UntypedExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher) {
|
||||
return new UntypedExampleMatcher(delegate.withMatcher(propertyPath, genericPropertyMatcher));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withTransformer(java.lang.String, org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer)
|
||||
*/
|
||||
public UntypedExampleMatcher withTransformer(String propertyPath, PropertyValueTransformer propertyValueTransformer) {
|
||||
return new UntypedExampleMatcher(delegate.withTransformer(propertyPath, propertyValueTransformer));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIgnoreCase(java.lang.String...)
|
||||
*/
|
||||
public UntypedExampleMatcher withIgnoreCase(String... propertyPaths) {
|
||||
return new UntypedExampleMatcher(delegate.withIgnoreCase(propertyPaths));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIncludeNullValues()
|
||||
*/
|
||||
public UntypedExampleMatcher withIncludeNullValues() {
|
||||
return new UntypedExampleMatcher(delegate.withIncludeNullValues());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withIgnoreNullValues()
|
||||
*/
|
||||
public UntypedExampleMatcher withIgnoreNullValues() {
|
||||
return new UntypedExampleMatcher(delegate.withIgnoreNullValues());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#withNullHandler(org.springframework.data.domain.ExampleMatcher.NullHandler)
|
||||
*/
|
||||
public UntypedExampleMatcher withNullHandler(NullHandler nullHandler) {
|
||||
return new UntypedExampleMatcher(delegate.withNullHandler(nullHandler));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#getNullHandler()
|
||||
*/
|
||||
public NullHandler getNullHandler() {
|
||||
return delegate.getNullHandler();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#getDefaultStringMatcher()
|
||||
*/
|
||||
public StringMatcher getDefaultStringMatcher() {
|
||||
return delegate.getDefaultStringMatcher();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#isIgnoreCaseEnabled()
|
||||
*/
|
||||
public boolean isIgnoreCaseEnabled() {
|
||||
return delegate.isIgnoreCaseEnabled();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#isIgnoredPath()
|
||||
*/
|
||||
public boolean isIgnoredPath(String path) {
|
||||
return delegate.isIgnoredPath(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#getIgnoredPaths()
|
||||
*/
|
||||
public Set<String> getIgnoredPaths() {
|
||||
return delegate.getIgnoredPaths();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#getPropertySpecifiers()
|
||||
*/
|
||||
public PropertySpecifiers getPropertySpecifiers() {
|
||||
return delegate.getPropertySpecifiers();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#isAllMatching()
|
||||
*/
|
||||
public boolean isAllMatching() {
|
||||
return delegate.isAllMatching();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#isAnyMatching()
|
||||
*/
|
||||
public boolean isAnyMatching() {
|
||||
return delegate.isAnyMatching();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.ExampleMatcher#getMatchMode()
|
||||
*/
|
||||
public MatchMode getMatchMode() {
|
||||
return delegate.getMatchMode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.UntypedExampleMatcher;
|
||||
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
@@ -179,7 +180,7 @@ public class QueryByExampleTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void untypedExampleMatchesCorrectly() {
|
||||
public void exampleIgnoringClassTypeKeyMatchesCorrectly() {
|
||||
|
||||
NotAPersonButStillMatchingFields probe = new NotAPersonButStillMatchingFields();
|
||||
probe.lastname = "stark";
|
||||
@@ -192,6 +193,19 @@ public class QueryByExampleTests {
|
||||
assertThat(result, hasItems(p1, p3));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void untypedExampleMatchesCorrectly() {
|
||||
|
||||
NotAPersonButStillMatchingFields probe = new NotAPersonButStillMatchingFields();
|
||||
probe.lastname = "stark";
|
||||
|
||||
Query query = new Query(new Criteria().alike(Example.of(probe, UntypedExampleMatcher.matching())));
|
||||
List<Person> result = operations.find(query, Person.class);
|
||||
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result, hasItems(p1, p3));
|
||||
}
|
||||
|
||||
@Document(collection = "dramatis-personae")
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
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.core.query.UntypedExampleMatcher;
|
||||
import org.springframework.data.mongodb.test.util.IsBsonObject;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
@@ -470,7 +471,7 @@ public class MongoExampleMapperUnitTests {
|
||||
|
||||
@Override
|
||||
public void writeType(TypeInformation<?> info, Bson sink) {
|
||||
((org.bson.Document) sink).put("_foo", "bar");
|
||||
((org.bson.Document) sink).put("_foo", "bar");
|
||||
|
||||
}
|
||||
});
|
||||
@@ -482,6 +483,17 @@ public class MongoExampleMapperUnitTests {
|
||||
assertThat(document, isBsonObject().notContaining("_class").notContaining("_foo"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void untypedExampleShouldNotInfereTypeRestriction() {
|
||||
|
||||
WrapperDocument probe = new WrapperDocument();
|
||||
probe.flatDoc = new FlatDocument();
|
||||
probe.flatDoc.stringValue = "conflux";
|
||||
|
||||
org.bson.Document document = mapper.getMappedExample(Example.of(probe, UntypedExampleMatcher.matching()));
|
||||
assertThat(document, isBsonObject().notContaining("_class"));
|
||||
}
|
||||
|
||||
static class FlatDocument {
|
||||
|
||||
@Id String id;
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2017 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.assertj.core.api.Assertions.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.data.domain.ExampleMatcher.NullHandler;
|
||||
import org.springframework.data.domain.ExampleMatcher.StringMatcher;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class UntypedExampleMatcherUnitTests {
|
||||
|
||||
ExampleMatcher matcher;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
matcher = UntypedExampleMatcher.matching();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void defaultStringMatcherShouldReturnDefault() {
|
||||
assertThat(matcher.getDefaultStringMatcher()).isEqualTo(StringMatcher.DEFAULT);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoreCaseShouldReturnFalseByDefault() {
|
||||
assertThat(matcher.isIgnoreCaseEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoredPathsIsEmptyByDefault() {
|
||||
assertThat(matcher.getIgnoredPaths()).isEmpty();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void nullHandlerShouldReturnIgnoreByDefault() {
|
||||
assertThat(matcher.getNullHandler()).isEqualTo(NullHandler.IGNORE);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class) // DATAMONGO-1768
|
||||
public void ignoredPathsIsNotModifiable() throws Exception {
|
||||
matcher.getIgnoredPaths().add("¯\\_(ツ)_/¯");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoreCaseShouldReturnTrueWhenIgnoreCaseEnabled() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnoreCase();
|
||||
|
||||
assertThat(matcher.isIgnoreCaseEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoreCaseShouldReturnTrueWhenIgnoreCaseSet() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnoreCase(true);
|
||||
|
||||
assertThat(matcher.isIgnoreCaseEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void nullHandlerShouldReturnInclude() throws Exception {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIncludeNullValues();
|
||||
|
||||
assertThat(matcher.getNullHandler()).isEqualTo(NullHandler.INCLUDE);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void nullHandlerShouldReturnIgnore() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnoreNullValues();
|
||||
|
||||
assertThat(matcher.getNullHandler()).isEqualTo(NullHandler.IGNORE);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void nullHandlerShouldReturnConfiguredValue() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withNullHandler(NullHandler.INCLUDE);
|
||||
|
||||
assertThat(matcher.getNullHandler()).isEqualTo(NullHandler.INCLUDE);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoredPathsShouldReturnCorrectProperties() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnorePaths("foo", "bar", "baz");
|
||||
|
||||
assertThat(matcher.getIgnoredPaths()).contains("foo", "bar", "baz");
|
||||
assertThat(matcher.getIgnoredPaths()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void ignoredPathsShouldReturnUniqueProperties() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnorePaths("foo", "bar", "foo");
|
||||
|
||||
assertThat(matcher.getIgnoredPaths()).contains("foo", "bar");
|
||||
assertThat(matcher.getIgnoredPaths()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void withCreatesNewInstance() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching().withIgnorePaths("foo", "bar", "foo");
|
||||
ExampleMatcher configuredExampleSpec = matcher.withIgnoreCase();
|
||||
|
||||
assertThat(matcher).isNotEqualTo(sameInstance(configuredExampleSpec));
|
||||
assertThat(matcher.getIgnoredPaths()).hasSize(2);
|
||||
assertThat(matcher.isIgnoreCaseEnabled()).isFalse();
|
||||
|
||||
assertThat(configuredExampleSpec.getIgnoredPaths()).hasSize(2);
|
||||
assertThat(configuredExampleSpec.isIgnoreCaseEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void defaultMatcherRequiresAllMatching() {
|
||||
|
||||
assertThat(UntypedExampleMatcher.matching().isAllMatching()).isTrue();
|
||||
assertThat(UntypedExampleMatcher.matching().isAnyMatching()).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void allMatcherRequiresAllMatching() {
|
||||
|
||||
assertThat(UntypedExampleMatcher.matchingAll().isAllMatching()).isTrue();
|
||||
assertThat(UntypedExampleMatcher.matchingAll().isAnyMatching()).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void anyMatcherYieldsAnyMatching() {
|
||||
|
||||
assertThat(UntypedExampleMatcher.matchingAny().isAnyMatching()).isTrue();
|
||||
assertThat(UntypedExampleMatcher.matchingAny().isAllMatching()).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1768
|
||||
public void shouldCompareUsingHashCodeAndEquals() {
|
||||
|
||||
matcher = UntypedExampleMatcher.matching() //
|
||||
.withIgnorePaths("foo", "bar", "baz") //
|
||||
.withNullHandler(NullHandler.IGNORE) //
|
||||
.withIgnoreCase("ignored-case") //
|
||||
.withMatcher("hello", ExampleMatcher.GenericPropertyMatchers.contains().caseSensitive()) //
|
||||
.withMatcher("world", matcher -> matcher.endsWith());
|
||||
|
||||
ExampleMatcher sameAsMatcher = UntypedExampleMatcher.matching() //
|
||||
.withIgnorePaths("foo", "bar", "baz") //
|
||||
.withNullHandler(NullHandler.IGNORE) //
|
||||
.withIgnoreCase("ignored-case") //
|
||||
.withMatcher("hello", ExampleMatcher.GenericPropertyMatchers.contains().caseSensitive()) //
|
||||
.withMatcher("world", matcher -> matcher.endsWith());
|
||||
|
||||
ExampleMatcher different = UntypedExampleMatcher.matching() //
|
||||
.withIgnorePaths("foo", "bar", "baz") //
|
||||
.withNullHandler(NullHandler.IGNORE) //
|
||||
.withMatcher("hello", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase());
|
||||
|
||||
assertThat(matcher.hashCode()).isEqualTo(sameAsMatcher.hashCode());
|
||||
assertThat(matcher.hashCode()).isNotEqualTo(different.hashCode());
|
||||
assertThat(matcher).isEqualTo(sameAsMatcher);
|
||||
assertThat(matcher).isNotEqualTo(different);
|
||||
}
|
||||
}
|
||||
@@ -69,3 +69,29 @@ Spring Data MongoDB provides support for the following matching options:
|
||||
| `{"firstname" : { $regex: /firstname/, $options: 'i'}}`
|
||||
|
||||
|===
|
||||
|
||||
[[query-by-example.untyped]]
|
||||
== Untyped Example
|
||||
|
||||
By default `Example` is strictly typed. This means the mapped query will have a type match included restricting it to probe assignable types. Eg. when sticking with the default type key `_class` the query has restrictions like `_class : { $in : [ com.acme.Person] }`.
|
||||
|
||||
By using the `UntypedExampleMatcher` it is possible bypasses the default behavior and skip the type restriction. So as long as field names match nearly any domain type can be used as the probe for creating the reference.
|
||||
|
||||
.Untyped Example Query
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
|
||||
class JustAnArbitraryClassWithMatchingFieldName {
|
||||
@Field("lastname") String value;
|
||||
}
|
||||
|
||||
JustAnArbitraryClassWithMatchingFieldNames probe = new JustAnArbitraryClassWithMatchingFieldNames();
|
||||
probe.value = "stark";
|
||||
|
||||
Example example = Example.of(probe, UntypedExampleMatcher.matching());
|
||||
|
||||
Query query = new Query(new Criteria().alike(example));
|
||||
List<Person> result = template.find(query, Person.class);
|
||||
----
|
||||
====
|
||||
Reference in New Issue
Block a user