Browse Source

DATAMONGO-976 - Add support for reading $meta projection on textScore into document.

We introduced @TextScore that can be used to mark a property to take { $meta : “textScore” }. In contrast to @Transient the value will be considered when reading documents.
The value can and will only get picked up if the score field is retrieved from the store.

Original pull request: #198.
pull/200/head
Christoph Strobl 12 years ago committed by Thomas Darimont
parent
commit
89a42c5648
  1. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 52
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java
  3. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java
  4. 38
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Calculated.java
  5. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java
  6. 38
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/TextScore.java
  7. 32
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java
  8. 30
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java
  9. 23
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java
  10. 17
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/text/TextQueryTests.java

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -385,7 +385,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -385,7 +385,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
public void doWithPersistentProperty(MongoPersistentProperty prop) {
if (prop.equals(idProperty)) {
if (prop.equals(idProperty) || prop.isCalculatedProperty()) {
return;
}

52
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java

@ -38,6 +38,7 @@ import org.springframework.expression.ParserContext; @@ -38,6 +38,7 @@ import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@ -120,12 +121,22 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong @@ -120,12 +121,22 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
@Override
public void verify() {
verifyFieldUniqueness();
verifyFieldTypes();
}
private void verifyFieldUniqueness() {
AssertFieldNameUniquenessHandler handler = new AssertFieldNameUniquenessHandler();
doWithProperties(handler);
doWithAssociations(handler);
}
private void verifyFieldTypes() {
doWithProperties(new PropertyTypeAssertionHandler());
}
/**
* {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order.
*
@ -240,4 +251,45 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong @@ -240,4 +251,45 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
}
}
/**
* @author Christoph Strobl
* @since 1.6
*/
private static class PropertyTypeAssertionHandler implements PropertyHandler<MongoPersistentProperty> {
@Override
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
potentiallyAssertTextScoreType(persistentProperty);
potentiallyAssertLanguageType(persistentProperty);
}
private void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) {
if (persistentProperty.isLanguageProperty()) {
assertPropertyType(persistentProperty, String.class);
}
}
private void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) {
if (persistentProperty.isTextScoreProperty()) {
assertPropertyType(persistentProperty, Float.class, Double.class);
}
}
private void assertPropertyType(MongoPersistentProperty persistentProperty, Class<?>... validMatches) {
for (Class<?> potentialMatch : validMatches) {
if (ClassUtils.isAssignable(potentialMatch, persistentProperty.getActualType())) {
return;
}
}
throw new MappingException(String.format("Missmatching types for %s. Found %s expected one of %s.",
persistentProperty.getField(), persistentProperty.getActualType(),
StringUtils.arrayToCommaDelimitedString(validMatches)));
}
}
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java

@ -192,4 +192,22 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope @@ -192,4 +192,22 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
public boolean isLanguageProperty() {
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isAnnotationPresent(Language.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isTextScoreProperty()
*/
@Override
public boolean isTextScoreProperty() {
return isAnnotationPresent(TextScore.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isCalculatedProperty()
*/
@Override
public boolean isCalculatedProperty() {
return isAnnotationPresent(Calculated.class);
}
}

38
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Calculated.java

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
/*
* Copyright 2014 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.mapping;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Meta-annotation to be used to annotate {@link java.lang.annotation.Annotation}s that mark properties either
* calculated internally or on server. <br/>
* <b>NOTE</b>: Different to {@link org.springframework.data.annotation.Transient}, {@link Calculated} properties are
* considered when reading from the store.
*
* @author Christoph Strobl
* @since 1.6
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Calculated {
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java

@ -69,6 +69,24 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist @@ -69,6 +69,24 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
*/
boolean isLanguageProperty();
/**
* Returns whether the property holds the documents score calculated by text search. <br/>
* It's marked with {@link TextScore}.
*
* @return
* @since 1.6
*/
boolean isTextScoreProperty();
/**
* Returns wheter the property is calculated eiter internally or on the server and therefore must not be written when
* saved.
*
* @return
* @since 1.6
*/
boolean isCalculatedProperty();
/**
* Returns the {@link DBRef} if the property is a reference.
*

38
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/TextScore.java

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
/*
* Copyright 2014 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.mapping;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* {@link TextScore} marks the property to be considered as the on server calculated {@literal textScore} when doing
* full text search. <br />
* <b>NOTE</b> Property will not be written when saving entity.
*
* @author Christoph Strobl
* @since 1.6
*/
@Calculated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TextScore {
}

32
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

@ -73,6 +73,7 @@ import org.springframework.data.mongodb.core.mapping.Field; @@ -73,6 +73,7 @@ import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.test.util.ReflectionTestUtils;
@ -1807,6 +1808,32 @@ public class MappingMongoConverterUnitTests { @@ -1807,6 +1808,32 @@ public class MappingMongoConverterUnitTests {
assertThat(result.shape, is((Shape) sphere));
}
/**
* @see DATAMONGO-976
*/
@Test
public void shouldIgnoreTextScorePropertyWhenWriting() {
ClassWithTextScoreProperty source = new ClassWithTextScoreProperty();
source.score = Float.MAX_VALUE;
BasicDBObject dbo = new BasicDBObject();
converter.write(source, dbo);
assertThat(dbo.get("score"), nullValue());
}
/**
* @see DATAMONGO-976
*/
@Test
public void shouldIncludeTextScorePropertyWhenReading() {
ClassWithTextScoreProperty entity = converter
.read(ClassWithTextScoreProperty.class, new BasicDBObject("score", 5F));
assertThat(entity.score, equalTo(5F));
}
static class GenericType<T> {
T content;
}
@ -2057,4 +2084,9 @@ public class MappingMongoConverterUnitTests { @@ -2057,4 +2084,9 @@ public class MappingMongoConverterUnitTests {
Shape shape;
}
class ClassWithTextScoreProperty {
@TextScore Float score;
}
}

30
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java

@ -150,6 +150,32 @@ public class BasicMongoPersistentPropertyUnitTests { @@ -150,6 +150,32 @@ public class BasicMongoPersistentPropertyUnitTests {
assertThat(property.isLanguageProperty(), is(true));
}
/**
* @see DATAMONGO-976
*/
@Test
public void shouldDetectTextScorePropertyCorrectly() {
BasicMongoPersistentEntity<DocumentWithTextScoreProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithTextScoreProperty>(
ClassTypeInformation.from(DocumentWithTextScoreProperty.class));
MongoPersistentProperty property = getPropertyFor(persistentEntity, "score");
assertThat(property.isTextScoreProperty(), is(true));
}
/**
* @see DATAMONGO-976
*/
@Test
public void shouldDetectTextScoreAsCalculatedProperty() {
BasicMongoPersistentEntity<DocumentWithTextScoreProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithTextScoreProperty>(
ClassTypeInformation.from(DocumentWithTextScoreProperty.class));
MongoPersistentProperty property = getPropertyFor(persistentEntity, "score");
assertThat(property.isCalculatedProperty(), is(true));
}
private MongoPersistentProperty getPropertyFor(Field field) {
return getPropertyFor(entity, field);
}
@ -200,4 +226,8 @@ public class BasicMongoPersistentPropertyUnitTests { @@ -200,4 +226,8 @@ public class BasicMongoPersistentPropertyUnitTests {
String language;
}
static class DocumentWithTextScoreProperty {
@TextScore Float score;
}
}

23
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/MongoMappingContextUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 by the original author(s).
* Copyright 2011-2014 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -42,6 +42,7 @@ import com.mongodb.DBRef; @@ -42,6 +42,7 @@ import com.mongodb.DBRef;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
*/
@RunWith(MockitoJUnitRunner.class)
public class MongoMappingContextUnitTests {
@ -179,6 +180,21 @@ public class MongoMappingContextUnitTests { @@ -179,6 +180,21 @@ public class MongoMappingContextUnitTests {
context.getPersistentEntity(ClassWithMultipleImplicitIds.class);
}
/**
* @see DATAMONGO-976
*/
@Test
public void shouldRejectClassWithInvalidTextScoreProperty() {
exception.expect(MappingException.class);
exception.expectMessage("score");
exception.expectMessage("Float");
exception.expectMessage("Double");
MongoMappingContext context = new MongoMappingContext();
context.getPersistentEntity(ClassWithInvalidTextScoreProperty.class);
}
public class SampleClass {
Map<String, SampleClass> children;
@ -240,4 +256,9 @@ public class MongoMappingContextUnitTests { @@ -240,4 +256,9 @@ public class MongoMappingContextUnitTests {
String _id;
String id;
}
class ClassWithInvalidTextScoreProperty {
@TextScore Locale score;
}
}

17
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/text/TextQueryTests.java

@ -39,6 +39,7 @@ import org.springframework.data.mongodb.core.index.IndexDefinition; @@ -39,6 +39,7 @@ import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Language;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.query.text.TextQueryTests.FullTextDoc.FullTextDocBuilder;
import org.springframework.data.mongodb.test.util.MongoVersionRule;
import org.springframework.data.util.Version;
@ -183,18 +184,18 @@ public class TextQueryTests extends AbstractIntegrationTests { @@ -183,18 +184,18 @@ public class TextQueryTests extends AbstractIntegrationTests {
}
/**
* @see DATAMONGO-850
* @see DATAMONGO-976
*/
@Test
public void shouldInlcudeScoreCorreclty() {
initWithDefaultDocuments();
List<FullTextDocWithScore> result = template.find(new TextQuery("bake coffee -cake").includeScore().sortByScore(),
FullTextDocWithScore.class);
List<FullTextDoc> result = template.find(new TextQuery("bake coffee -cake").includeScore().sortByScore(),
FullTextDoc.class);
assertThat(result, hasSize(2));
for (FullTextDocWithScore scoredDoc : result) {
for (FullTextDoc scoredDoc : result) {
assertTrue(scoredDoc.score > 0F);
}
}
@ -259,12 +260,6 @@ public class TextQueryTests extends AbstractIntegrationTests { @@ -259,12 +260,6 @@ public class TextQueryTests extends AbstractIntegrationTests {
this.template.save(MILK_AND_SUGAR);
}
static class FullTextDocWithScore extends FullTextDoc {
public Float score;
}
@Document(collection = "fullTextDoc")
static class FullTextDoc {
@ -276,6 +271,8 @@ public class TextQueryTests extends AbstractIntegrationTests { @@ -276,6 +271,8 @@ public class TextQueryTests extends AbstractIntegrationTests {
private String subheadline;
private String body;
private @TextScore Float score;
@Override
public int hashCode() {
final int prime = 31;

Loading…
Cancel
Save