diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java index 2b2727bda..b0e997c43 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java @@ -33,6 +33,7 @@ import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.mapping.Association; @@ -41,13 +42,13 @@ import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PropertyHandler; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.CycleGuard.Path; import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.TextIndexIncludeOptions.IncludeStrategy; import org.springframework.data.mongodb.core.index.TextIndexDefinition.TextIndexDefinitionBuilder; import org.springframework.data.mongodb.core.index.TextIndexDefinition.TextIndexedFieldSpec; import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.Document; -import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.spel.EvaluationContextProvider; @@ -80,7 +81,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { private static final Logger LOGGER = LoggerFactory.getLogger(MongoPersistentEntityIndexResolver.class); private static final SpelExpressionParser PARSER = new SpelExpressionParser(); - private final MongoMappingContext mappingContext; + private final MappingContext, MongoPersistentProperty> mappingContext; private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT; /** @@ -88,7 +89,8 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { * * @param mappingContext must not be {@literal null}. */ - public MongoPersistentEntityIndexResolver(MongoMappingContext mappingContext) { + public MongoPersistentEntityIndexResolver( + MappingContext, MongoPersistentProperty> mappingContext) { Assert.notNull(mappingContext, "Mapping context must not be null in order to resolve index definitions"); this.mappingContext = mappingContext; @@ -261,6 +263,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { LOGGER.info(e.getMessage()); } + if (root.hasCollation()) { + indexDefinitionBuilder.withSimpleCollation(); + } + TextIndexDefinition indexDefinition = indexDefinitionBuilder.build(); if (!indexDefinition.hasFieldSpec()) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexDefinition.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexDefinition.java index d573110a0..59d55dd4a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexDefinition.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexDefinition.java @@ -21,6 +21,7 @@ import java.util.Set; import org.bson.Document; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.mongodb.core.query.Collation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -40,9 +41,10 @@ public class TextIndexDefinition implements IndexDefinition { private @Nullable String defaultLanguage; private @Nullable String languageOverride; private @Nullable IndexFilter filter; + private @Nullable Collation collation; TextIndexDefinition() { - fieldSpecs = new LinkedHashSet(); + fieldSpecs = new LinkedHashSet<>(); } /** @@ -116,6 +118,10 @@ public class TextIndexDefinition implements IndexDefinition { options.put("default_language", defaultLanguage); } + if (collation != null) { + options.put("collation", collation.toDocument()); + } + Document weightsDocument = new Document(); for (TextIndexedFieldSpec fieldSpec : fieldSpecs) { if (fieldSpec.isWeighted()) { @@ -348,6 +354,17 @@ public class TextIndexDefinition implements IndexDefinition { return this; } + /** + * Configure to use simple {@link Collation}. Required if the collection uses a non-simple collation. + * + * @since 2.2 + */ + public TextIndexDefinitionBuilder withSimpleCollation() { + + this.instance.collation = Collation.simple(); + return this; + } + public TextIndexDefinition build() { return this.instance; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java index e8c1263b6..89e5081e1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java @@ -744,16 +744,28 @@ public class MongoPersistentEntityIndexResolverUnitTests { assertThat(indexDefinitions).hasSize(1); assertIndexPathAndCollection("bar", "textIndexOnSinglePropertyInRoot", indexDefinitions.get(0)); + assertThat(indexDefinitions.get(0).getIndexOptions()).doesNotContainKey("collation"); + } + + @Test // DATAMONGO-2316 + public void shouldEnforceSimpleCollationOnTextIndex() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType( + TextIndexWithCollation.class); + + assertThat(indexDefinitions).hasSize(1); + assertThat(indexDefinitions.get(0).getIndexOptions()).containsEntry("collation", + new org.bson.Document("locale", "simple")); } @Test // DATAMONGO-937 public void shouldResolveMultiFieldTextIndexCorrectly() { List indexDefinitions = prepareMappingContextAndResolveIndexForType( - TextIndexOnMutiplePropertiesInRoot.class); + TextIndexOnMultiplePropertiesInRoot.class); assertThat(indexDefinitions).hasSize(1); - assertIndexPathAndCollection(new String[] { "foo", "bar" }, "textIndexOnMutiplePropertiesInRoot", + assertIndexPathAndCollection(new String[] { "foo", "bar" }, "textIndexOnMultiplePropertiesInRoot", indexDefinitions.get(0)); } @@ -862,8 +874,14 @@ public class MongoPersistentEntityIndexResolverUnitTests { @TextIndexed String bar; } + @Document(collation = "de_AT") + static class TextIndexWithCollation { + + @TextIndexed String foo; + } + @Document - static class TextIndexOnMutiplePropertiesInRoot { + static class TextIndexOnMultiplePropertiesInRoot { @TextIndexed String foo; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/TextIndexTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/TextIndexTests.java index 1b65f7fdb..e0ffc0b89 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/TextIndexTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/TextIndexTests.java @@ -22,12 +22,15 @@ import java.util.List; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.mongodb.config.AbstractIntegrationTests; +import org.springframework.data.mongodb.core.CollectionOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Language; +import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.test.util.MongoVersionRule; import org.springframework.data.util.Version; @@ -35,6 +38,7 @@ import com.mongodb.WriteConcern; /** * @author Christoph Strobl + * @author Mark Paluch */ public class TextIndexTests extends AbstractIntegrationTests { @@ -48,11 +52,21 @@ public class TextIndexTests extends AbstractIntegrationTests { template.setWriteConcern(WriteConcern.JOURNALED); this.indexOps = template.indexOps(TextIndexedDocumentRoot.class); + + template.dropCollection(TextIndexedDocumentRoot.class); + template.createCollection(TextIndexedDocumentRoot.class, + CollectionOptions.empty().collation(Collation.of("de_AT"))); } - @Test // DATAMONGO-937 + @Test // DATAMONGO-937, DATAMONGO-2316 public void indexInfoShouldHaveBeenCreatedCorrectly() { + IndexResolver indexResolver = IndexResolver.create(template.getConverter().getMappingContext()); + + for (IndexDefinition indexDefinition : indexResolver.resolveIndexFor(TextIndexedDocumentRoot.class)) { + indexOps.ensureIndex(indexDefinition); + } + List indexInfos = indexOps.getIndexInfo(); assertThat(indexInfos.size()).isEqualTo(2); @@ -69,16 +83,16 @@ public class TextIndexTests extends AbstractIntegrationTests { assertThat(textIndexInfo.getLanguage()).isEqualTo("spanish"); } - @Document(language = "spanish") + @Document(language = "spanish", collation = "de_AT") static class TextIndexedDocumentRoot { @TextIndexed String textIndexedPropertyWithDefaultWeight; @TextIndexed(weight = 5) String textIndexedPropertyWithWeight; - TextIndexedDocumentWihtLanguageOverride nestedDocument; + TextIndexedDocumentWithLanguageOverride nestedDocument; } - static class TextIndexedDocumentWihtLanguageOverride { + static class TextIndexedDocumentWithLanguageOverride { @Language String lang;