Compare commits
4 Commits
issue/DATA
...
issue/DATA
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5f35a3972 | ||
|
|
4b2bc52ffc | ||
|
|
e6d47ce5b5 | ||
|
|
3532c1feae |
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.1.0-DATAMONGO-2574-SNAPSHOT</version>
|
||||
<version>3.1.0-DATAMONGO-1569-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.1.0-DATAMONGO-2574-SNAPSHOT</version>
|
||||
<version>3.1.0-DATAMONGO-1569-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.1.0-DATAMONGO-2574-SNAPSHOT</version>
|
||||
<version>3.1.0-DATAMONGO-1569-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.1.0-DATAMONGO-2574-SNAPSHOT</version>
|
||||
<version>3.1.0-DATAMONGO-1569-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import java.lang.annotation.Target;
|
||||
* @author Philipp Schneider
|
||||
* @author Johno Crawford
|
||||
* @author Christoph Strobl
|
||||
* @author Dave Perryman
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Documented
|
||||
@@ -95,7 +96,8 @@ public @interface CompoundIndex {
|
||||
boolean unique() default false;
|
||||
|
||||
/**
|
||||
* If set to true index will skip over any document that is missing the indexed field.
|
||||
* If set to true index will skip over any document that is missing the indexed field. <br />
|
||||
* Must not be used with {@link #partialFilter()}.
|
||||
*
|
||||
* @return {@literal false} by default.
|
||||
* @see <a href=
|
||||
@@ -170,4 +172,14 @@ public @interface CompoundIndex {
|
||||
*/
|
||||
boolean background() default false;
|
||||
|
||||
/**
|
||||
* Only index the documents in a collection that meet a specified {@link IndexFilter filter expression}. <br />
|
||||
* Must not be used with {@link #sparse() sparse = true}.
|
||||
*
|
||||
* @return empty by default.
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/core/index-partial/">https://docs.mongodb.com/manual/core/index-partial/</a>
|
||||
* @since 3.1
|
||||
*/
|
||||
String partialFilter() default "";
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ public @interface Indexed {
|
||||
IndexDirection direction() default IndexDirection.ASCENDING;
|
||||
|
||||
/**
|
||||
* If set to true index will skip over any document that is missing the indexed field.
|
||||
* If set to true index will skip over any document that is missing the indexed field. <br />
|
||||
* Must not be used with {@link #partialFilter()}.
|
||||
*
|
||||
* @return {@literal false} by default.
|
||||
* @see <a href=
|
||||
@@ -170,4 +171,15 @@ public @interface Indexed {
|
||||
* @since 2.2
|
||||
*/
|
||||
String expireAfter() default "";
|
||||
|
||||
/**
|
||||
* Only index the documents in a collection that meet a specified {@link IndexFilter filter expression}. <br />
|
||||
* Must not be used with {@link #sparse() sparse = true}.
|
||||
*
|
||||
* @return empty by default.
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/core/index-partial/">https://docs.mongodb.com/manual/core/index-partial/</a>
|
||||
* @since 3.1
|
||||
*/
|
||||
String partialFilter() default "";
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -69,6 +70,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Thomas Darimont
|
||||
* @author Martin Macko
|
||||
* @author Mark Paluch
|
||||
* @author Dave Perryman
|
||||
* @since 1.5
|
||||
*/
|
||||
public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
@@ -380,6 +382,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexDefinition.background();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(index.partialFilter())) {
|
||||
indexDefinition.partial(evaluatePartialFilter(index.partialFilter(), entity));
|
||||
}
|
||||
|
||||
return new IndexDefinitionHolder(dotPath, indexDefinition, collection);
|
||||
}
|
||||
|
||||
@@ -469,9 +475,25 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(index.partialFilter())) {
|
||||
indexDefinition.partial(evaluatePartialFilter(index.partialFilter(), persistentProperty.getOwner()));
|
||||
}
|
||||
|
||||
return new IndexDefinitionHolder(dotPath, indexDefinition, collection);
|
||||
}
|
||||
|
||||
private PartialIndexFilter evaluatePartialFilter(String filterExpression, PersistentEntity<?,?> entity) {
|
||||
|
||||
Object result = evaluate(filterExpression, getEvaluationContextForProperty(entity));
|
||||
|
||||
if (result instanceof org.bson.Document) {
|
||||
return PartialIndexFilter.of((org.bson.Document) result);
|
||||
}
|
||||
|
||||
return PartialIndexFilter.of(BsonUtils.parse(filterExpression, null));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates {@link HashedIndex} wrapped in {@link IndexDefinitionHolder} out of {@link HashIndexed} for a given
|
||||
* {@link MongoPersistentProperty}.
|
||||
|
||||
@@ -129,7 +129,7 @@ public interface GridFsOperations extends ResourcePatternResolver {
|
||||
*
|
||||
* @param content must not be {@literal null}.
|
||||
* @param filename must not be {@literal null} or empty.
|
||||
* @param contentType can be {@literal null}. If not empty, may override content type within {@literal metadata}.
|
||||
* @param contentType can be {@literal null}.
|
||||
* @param metadata can be {@literal null}.
|
||||
* @return the {@link ObjectId} of the {@link com.mongodb.client.gridfs.model.GridFSFile} just created.
|
||||
*/
|
||||
@@ -140,12 +140,12 @@ public interface GridFsOperations extends ResourcePatternResolver {
|
||||
if (StringUtils.hasText(filename)) {
|
||||
uploadBuilder.filename(filename);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(metadata)) {
|
||||
uploadBuilder.metadata(metadata);
|
||||
}
|
||||
if (StringUtils.hasText(contentType)) {
|
||||
uploadBuilder.contentType(contentType);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(metadata)) {
|
||||
uploadBuilder.metadata(metadata);
|
||||
}
|
||||
|
||||
return store(uploadBuilder.build());
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public interface ReactiveGridFsOperations {
|
||||
*
|
||||
* @param content must not be {@literal null}.
|
||||
* @param filename must not be {@literal null} or empty.
|
||||
* @param contentType can be {@literal null}. If not empty, may override content type within {@literal metadata}.
|
||||
* @param contentType can be {@literal null}.
|
||||
* @param metadata can be {@literal null}.
|
||||
* @return a {@link Mono} emitting the {@link ObjectId} of the {@link com.mongodb.client.gridfs.model.GridFSFile} just
|
||||
* created.
|
||||
@@ -148,12 +148,12 @@ public interface ReactiveGridFsOperations {
|
||||
if (StringUtils.hasText(filename)) {
|
||||
uploadBuilder.filename(filename);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(metadata)) {
|
||||
uploadBuilder.metadata(metadata);
|
||||
}
|
||||
if (StringUtils.hasText(contentType)) {
|
||||
uploadBuilder.contentType(contentType);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(metadata)) {
|
||||
uploadBuilder.metadata(metadata);
|
||||
}
|
||||
|
||||
return store(uploadBuilder.build());
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
@@ -54,6 +54,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Dave Perryman
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({ IndexResolutionTests.class, GeoSpatialIndexResolutionTests.class, CompoundIndexResolutionTests.class,
|
||||
@@ -270,23 +271,33 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions()).containsEntry("name", "my1st");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1569
|
||||
public void resolvesPartialFilter() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(
|
||||
WithPartialFilter.class);
|
||||
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions()).containsEntry("partialFilterExpression",
|
||||
org.bson.Document.parse("{'value': {'$exists': true}}"));
|
||||
}
|
||||
|
||||
@Document("Zero")
|
||||
static class IndexOnLevelZero {
|
||||
class IndexOnLevelZero {
|
||||
@Indexed String indexedProperty;
|
||||
}
|
||||
|
||||
@Document("One")
|
||||
static class IndexOnLevelOne {
|
||||
class IndexOnLevelOne {
|
||||
IndexOnLevelZero zero;
|
||||
}
|
||||
|
||||
@Document("Two")
|
||||
static class IndexOnLevelTwo {
|
||||
class IndexOnLevelTwo {
|
||||
IndexOnLevelOne one;
|
||||
}
|
||||
|
||||
@Document("WithOptionsOnIndexedProperty")
|
||||
static class WithOptionsOnIndexedProperty {
|
||||
class WithOptionsOnIndexedProperty {
|
||||
|
||||
@Indexed(background = true, direction = IndexDirection.DESCENDING, dropDups = true, expireAfterSeconds = 10,
|
||||
sparse = true, unique = true) //
|
||||
@@ -294,23 +305,23 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class IndexOnLevelOneWithExplicitlyNamedField {
|
||||
class IndexOnLevelOneWithExplicitlyNamedField {
|
||||
|
||||
@Field("customZero") IndexOnLevelZeroWithExplicityNamedField zero;
|
||||
}
|
||||
|
||||
static class IndexOnLevelZeroWithExplicityNamedField {
|
||||
class IndexOnLevelZeroWithExplicityNamedField {
|
||||
|
||||
@Indexed @Field("customFieldName") String namedProperty;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WrapperOfWithDbRef {
|
||||
class WrapperOfWithDbRef {
|
||||
WithDbRef nested;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithDbRef {
|
||||
class WithDbRef {
|
||||
|
||||
@Indexed //
|
||||
@DBRef //
|
||||
@@ -318,12 +329,12 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document("no-index")
|
||||
static class NoIndex {
|
||||
class NoIndex {
|
||||
@Id String id;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class IndexedDocumentWithComposedAnnotations {
|
||||
class IndexedDocumentWithComposedAnnotations {
|
||||
|
||||
@Id String id;
|
||||
@CustomIndexedAnnotation String fieldWithDifferentIndexName;
|
||||
@@ -361,7 +372,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithExpireAfterAsPlainString {
|
||||
class WithExpireAfterAsPlainString {
|
||||
@Indexed(expireAfter = "10m") String withTimeout;
|
||||
}
|
||||
|
||||
@@ -371,12 +382,12 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithExpireAfterAsExpression {
|
||||
class WithExpireAfterAsExpression {
|
||||
@Indexed(expireAfter = "#{10 + 1 + 's'}") String withTimeout;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithExpireAfterAsExpressionResultingInDuration {
|
||||
class WithExpireAfterAsExpressionResultingInDuration {
|
||||
@Indexed(expireAfter = "#{T(java.time.Duration).ofSeconds(100)}") String withTimeout;
|
||||
}
|
||||
|
||||
@@ -391,9 +402,14 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithIndexNameAsExpression {
|
||||
class WithIndexNameAsExpression {
|
||||
@Indexed(name = "#{'my' + 1 + 'st'}") String spelIndexName;
|
||||
}
|
||||
|
||||
@Document
|
||||
class WithPartialFilter {
|
||||
@Indexed(partialFilter = "{'value': {'$exists': true}}") String withPartialFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ ElementType.FIELD })
|
||||
@@ -403,7 +419,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class IndexOnMetaAnnotatedField {
|
||||
class IndexOnMetaAnnotatedField {
|
||||
@Field("_name") @IndexedFieldAnnotation String lastname;
|
||||
}
|
||||
|
||||
@@ -480,29 +496,29 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document("Zero")
|
||||
static class GeoSpatialIndexOnLevelZero {
|
||||
class GeoSpatialIndexOnLevelZero {
|
||||
@GeoSpatialIndexed Point geoIndexedProperty;
|
||||
}
|
||||
|
||||
@Document("One")
|
||||
static class GeoSpatialIndexOnLevelOne {
|
||||
class GeoSpatialIndexOnLevelOne {
|
||||
GeoSpatialIndexOnLevelZero zero;
|
||||
}
|
||||
|
||||
@Document("Two")
|
||||
static class GeoSpatialIndexOnLevelTwo {
|
||||
class GeoSpatialIndexOnLevelTwo {
|
||||
GeoSpatialIndexOnLevelOne one;
|
||||
}
|
||||
|
||||
@Document("WithOptionsOnGeoSpatialIndexProperty")
|
||||
static class WithOptionsOnGeoSpatialIndexProperty {
|
||||
class WithOptionsOnGeoSpatialIndexProperty {
|
||||
|
||||
@GeoSpatialIndexed(bits = 2, max = 100, min = 1, type = GeoSpatialIndexType.GEO_2D) //
|
||||
Point location;
|
||||
}
|
||||
|
||||
@Document("WithComposedAnnotation")
|
||||
static class GeoSpatialIndexedDocumentWithComposedAnnotation {
|
||||
class GeoSpatialIndexedDocumentWithComposedAnnotation {
|
||||
|
||||
@ComposedGeoSpatialIndexed //
|
||||
Point location;
|
||||
@@ -527,7 +543,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class GeoIndexWithNameAsExpression {
|
||||
class GeoIndexWithNameAsExpression {
|
||||
@GeoSpatialIndexed(name = "#{'my' + 1 + 'st'}") Point spelIndexName;
|
||||
}
|
||||
|
||||
@@ -663,14 +679,28 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
indexDefinitions.get(1));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1569
|
||||
public void singleIndexWithPartialFilter() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(
|
||||
SingleCompoundIndexWithPartialFilter.class);
|
||||
|
||||
assertThat(indexDefinitions).hasSize(1);
|
||||
assertThat(indexDefinitions.get(0).getIndexKeys()).containsEntry("foo", 1).containsEntry("bar", -1);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions()).containsEntry("name", "compound_index_with_partial")
|
||||
.containsEntry("unique", true).containsEntry("background", true);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions()).containsEntry("partialFilterExpression",
|
||||
org.bson.Document.parse("{'value': {'$exists': true}}"));
|
||||
}
|
||||
|
||||
@Document("CompoundIndexOnLevelOne")
|
||||
static class CompoundIndexOnLevelOne {
|
||||
class CompoundIndexOnLevelOne {
|
||||
|
||||
CompoundIndexOnLevelZero zero;
|
||||
}
|
||||
|
||||
@Document("CompoundIndexOnLevelZeroWithEmptyIndexDef")
|
||||
static class CompoundIndexOnLevelOneWithEmptyIndexDefinition {
|
||||
class CompoundIndexOnLevelOneWithEmptyIndexDefinition {
|
||||
|
||||
CompoundIndexOnLevelZeroWithEmptyIndexDef zero;
|
||||
}
|
||||
@@ -678,26 +708,26 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
@Document("CompoundIndexOnLevelZero")
|
||||
@CompoundIndexes({ @CompoundIndex(name = "compound_index", def = "{'foo': 1, 'bar': -1}", background = true,
|
||||
sparse = true, unique = true) })
|
||||
static class CompoundIndexOnLevelZero {}
|
||||
class CompoundIndexOnLevelZero {}
|
||||
|
||||
@CompoundIndexes({ @CompoundIndex(name = "compound_index", background = true, sparse = true, unique = true) })
|
||||
static class CompoundIndexOnLevelZeroWithEmptyIndexDef {}
|
||||
class CompoundIndexOnLevelZeroWithEmptyIndexDef {}
|
||||
|
||||
@Document("CompoundIndexOnLevelZero")
|
||||
@CompoundIndex(name = "compound_index", def = "{'foo': 1, 'bar': -1}", background = true, sparse = true,
|
||||
unique = true)
|
||||
static class SingleCompoundIndex {}
|
||||
class SingleCompoundIndex {}
|
||||
|
||||
static class IndexDefinedOnSuperClass extends CompoundIndexOnLevelZero {}
|
||||
class IndexDefinedOnSuperClass extends CompoundIndexOnLevelZero {}
|
||||
|
||||
@Document("ComountIndexWithAutogeneratedName")
|
||||
@CompoundIndexes({ @CompoundIndex(useGeneratedName = true, def = "{'foo': 1, 'bar': -1}", background = true,
|
||||
sparse = true, unique = true) })
|
||||
static class ComountIndexWithAutogeneratedName {}
|
||||
class ComountIndexWithAutogeneratedName {}
|
||||
|
||||
@Document("WithComposedAnnotation")
|
||||
@ComposedCompoundIndex
|
||||
static class CompoundIndexDocumentWithComposedAnnotation {}
|
||||
class CompoundIndexDocumentWithComposedAnnotation {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
@@ -723,16 +753,21 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
|
||||
@Document
|
||||
@CompoundIndex(name = "#{'cmp' + 2 + 'name'}", def = "{'foo': 1, 'bar': -1}")
|
||||
static class CompoundIndexWithNameExpression {}
|
||||
class CompoundIndexWithNameExpression {}
|
||||
|
||||
@Document
|
||||
@CompoundIndex(def = "#{T(org.bson.Document).parse(\"{ 'foo': 1, 'bar': -1 }\")}")
|
||||
static class CompoundIndexWithDefExpression {}
|
||||
class CompoundIndexWithDefExpression {}
|
||||
|
||||
@Document
|
||||
@CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
|
||||
@CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
|
||||
static class RepeatedCompoundIndex {}
|
||||
class RepeatedCompoundIndex {}
|
||||
|
||||
@Document("SingleCompoundIndexWithPartialFilter")
|
||||
@CompoundIndex(name = "compound_index_with_partial", def = "{'foo': 1, 'bar': -1}", background = true,
|
||||
unique = true, partialFilter = "{'value': {'$exists': true}}")
|
||||
class SingleCompoundIndexWithPartialFilter {}
|
||||
}
|
||||
|
||||
public static class TextIndexedResolutionTests {
|
||||
@@ -868,7 +903,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnSinglePropertyInRoot {
|
||||
class TextIndexOnSinglePropertyInRoot {
|
||||
|
||||
String foo;
|
||||
|
||||
@@ -876,13 +911,13 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document(collation = "de_AT")
|
||||
static class TextIndexWithCollation {
|
||||
class TextIndexWithCollation {
|
||||
|
||||
@TextIndexed String foo;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnMultiplePropertiesInRoot {
|
||||
class TextIndexOnMultiplePropertiesInRoot {
|
||||
|
||||
@TextIndexed String foo;
|
||||
|
||||
@@ -890,48 +925,48 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnNestedRoot {
|
||||
class TextIndexOnNestedRoot {
|
||||
|
||||
String bar;
|
||||
|
||||
@TextIndexed TextIndexOnNested nested;
|
||||
}
|
||||
|
||||
static class TextIndexOnNested {
|
||||
class TextIndexOnNested {
|
||||
|
||||
String foo;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnNestedWithWeightRoot {
|
||||
class TextIndexOnNestedWithWeightRoot {
|
||||
|
||||
@TextIndexed(weight = 5) TextIndexOnNested nested;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnNestedWithMostSpecificValueRoot {
|
||||
class TextIndexOnNestedWithMostSpecificValueRoot {
|
||||
@TextIndexed(weight = 5) TextIndexOnNestedWithMostSpecificValue nested;
|
||||
}
|
||||
|
||||
static class TextIndexOnNestedWithMostSpecificValue {
|
||||
class TextIndexOnNestedWithMostSpecificValue {
|
||||
|
||||
String foo;
|
||||
@TextIndexed(weight = 10) String bar;
|
||||
}
|
||||
|
||||
@Document(language = "spanish")
|
||||
static class DocumentWithDefaultLanguage {
|
||||
class DocumentWithDefaultLanguage {
|
||||
@TextIndexed String foo;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithLanguageOverrideOnNestedElement {
|
||||
class DocumentWithLanguageOverrideOnNestedElement {
|
||||
|
||||
DocumentWithLanguageOverride nested;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithLanguageOverride {
|
||||
class DocumentWithLanguageOverride {
|
||||
|
||||
@TextIndexed String foo;
|
||||
|
||||
@@ -939,19 +974,19 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguage {
|
||||
class DocumentWithNoTextIndexPropertyButReservedFieldLanguage {
|
||||
|
||||
String language;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated {
|
||||
class DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated {
|
||||
|
||||
@Field("language") String lang;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithOverlappingLanguageProps {
|
||||
class DocumentWithOverlappingLanguageProps {
|
||||
|
||||
@TextIndexed String foo;
|
||||
String language;
|
||||
@@ -959,7 +994,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexedDocumentWithComposedAnnotation {
|
||||
class TextIndexedDocumentWithComposedAnnotation {
|
||||
|
||||
@ComposedTextIndexedAnnotation String foo;
|
||||
String lang;
|
||||
@@ -1248,104 +1283,104 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class MixedIndexRoot {
|
||||
class MixedIndexRoot {
|
||||
|
||||
@Indexed String first;
|
||||
NestedGeoIndex nestedGeo;
|
||||
}
|
||||
|
||||
static class NestedGeoIndex {
|
||||
class NestedGeoIndex {
|
||||
|
||||
@GeoSpatialIndexed Point location;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class Outer {
|
||||
class Outer {
|
||||
|
||||
@DBRef Inner inner;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class Inner {
|
||||
class Inner {
|
||||
|
||||
@Indexed Outer outer;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class CycleLevelZero {
|
||||
class CycleLevelZero {
|
||||
|
||||
@Indexed String indexedProperty;
|
||||
CycleLevelZero cyclicReference;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class CycleOnLevelOne {
|
||||
class CycleOnLevelOne {
|
||||
|
||||
CycleOnLevelOneReferenced reference;
|
||||
}
|
||||
|
||||
static class CycleOnLevelOneReferenced {
|
||||
class CycleOnLevelOneReferenced {
|
||||
|
||||
@Indexed String indexedProperty;
|
||||
CycleOnLevelOne cyclicReference;
|
||||
}
|
||||
|
||||
@Document
|
||||
public static class CycleStartingInBetween {
|
||||
static class CycleStartingInBetween {
|
||||
|
||||
CycleOnLevelOne referenceToCycleStart;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class NoCycleButIdenticallyNamedProperties {
|
||||
class NoCycleButIdenticallyNamedProperties {
|
||||
|
||||
@Indexed String foo;
|
||||
NoCycleButIdenticallyNamedPropertiesNested reference;
|
||||
}
|
||||
|
||||
static class NoCycleButIdenticallyNamedPropertiesNested {
|
||||
class NoCycleButIdenticallyNamedPropertiesNested {
|
||||
|
||||
@Indexed String foo;
|
||||
NoCycleButIndenticallNamedPropertiesDeeplyNested deep;
|
||||
}
|
||||
|
||||
static class NoCycleButIndenticallNamedPropertiesDeeplyNested {
|
||||
class NoCycleButIndenticallNamedPropertiesDeeplyNested {
|
||||
|
||||
@Indexed String foo;
|
||||
}
|
||||
|
||||
@Document("rules")
|
||||
static class NoCycleManyPathsToDeepValueObject {
|
||||
class NoCycleManyPathsToDeepValueObject {
|
||||
|
||||
private NoCycleLevel3 l3;
|
||||
private NoCycleLevel2 l2;
|
||||
}
|
||||
|
||||
static class NoCycleLevel2 {
|
||||
class NoCycleLevel2 {
|
||||
private NoCycleLevel3 l3;
|
||||
}
|
||||
|
||||
static class NoCycleLevel3 {
|
||||
class NoCycleLevel3 {
|
||||
private ValueObject valueObject;
|
||||
}
|
||||
|
||||
static class ValueObject {
|
||||
class ValueObject {
|
||||
@Indexed private String value;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimilarityHolingBean {
|
||||
class SimilarityHolingBean {
|
||||
|
||||
@Indexed @Field("norm") String normalProperty;
|
||||
@Field("similarityL") private List<SimilaritySibling> listOfSimilarilyNamedEntities = null;
|
||||
}
|
||||
|
||||
static class SimilaritySibling {
|
||||
class SimilaritySibling {
|
||||
@Field("similarity") private String similarThoughNotEqualNamedProperty;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class MultipleObjectsOfSameType {
|
||||
class MultipleObjectsOfSameType {
|
||||
|
||||
SelfCyclingViaCollectionType cycleOne;
|
||||
|
||||
@@ -1353,7 +1388,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SelfCyclingViaCollectionType {
|
||||
class SelfCyclingViaCollectionType {
|
||||
|
||||
List<SelfCyclingViaCollectionType> cyclic;
|
||||
|
||||
@@ -1361,55 +1396,55 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
|
||||
@Document
|
||||
@CompoundIndex(name = "c_index", def = "{ foo:1, bar:1 }")
|
||||
static class DocumentWithNamedCompoundIndex {
|
||||
class DocumentWithNamedCompoundIndex {
|
||||
|
||||
String property;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNamedIndex {
|
||||
class DocumentWithNamedIndex {
|
||||
|
||||
@Indexed(name = "property_index") String property;
|
||||
}
|
||||
|
||||
static class TypeWithNamedIndex {
|
||||
class TypeWithNamedIndex {
|
||||
|
||||
@Indexed(name = "property_index") String property;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNestedDocumentHavingNamedCompoundIndex {
|
||||
class DocumentWithNestedDocumentHavingNamedCompoundIndex {
|
||||
|
||||
DocumentWithNamedCompoundIndex propertyOfTypeHavingNamedCompoundIndex;
|
||||
}
|
||||
|
||||
@CompoundIndex(name = "c_index", def = "{ foo:1, bar:1 }")
|
||||
static class TypeWithNamedCompoundIndex {
|
||||
class TypeWithNamedCompoundIndex {
|
||||
String property;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNestedTypeHavingNamedCompoundIndex {
|
||||
class DocumentWithNestedTypeHavingNamedCompoundIndex {
|
||||
|
||||
TypeWithNamedCompoundIndex propertyOfTypeHavingNamedCompoundIndex;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNestedDocumentHavingNamedIndex {
|
||||
class DocumentWithNestedDocumentHavingNamedIndex {
|
||||
|
||||
DocumentWithNamedIndex propertyOfTypeHavingNamedIndex;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNestedTypeHavingNamedIndex {
|
||||
class DocumentWithNestedTypeHavingNamedIndex {
|
||||
|
||||
TypeWithNamedIndex propertyOfTypeHavingNamedIndex;
|
||||
}
|
||||
|
||||
@Document
|
||||
public class MultiplePropertiesOfSameTypeWithMatchingStartLetters {
|
||||
class MultiplePropertiesOfSameTypeWithMatchingStartLetters {
|
||||
|
||||
public class NameComponent {
|
||||
class NameComponent {
|
||||
|
||||
@Indexed String component;
|
||||
}
|
||||
@@ -1419,9 +1454,9 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
public class MultiplePropertiesOfSameTypeWithMatchingStartLettersOnNestedProperty {
|
||||
class MultiplePropertiesOfSameTypeWithMatchingStartLettersOnNestedProperty {
|
||||
|
||||
public class NameComponent {
|
||||
class NameComponent {
|
||||
|
||||
@Indexed String nameLast;
|
||||
@Indexed String name;
|
||||
@@ -1431,39 +1466,39 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
public static class OuterDocumentReferingToIndexedPropertyViaDifferentNonCyclingPaths {
|
||||
static class OuterDocumentReferingToIndexedPropertyViaDifferentNonCyclingPaths {
|
||||
|
||||
NoCycleButIndenticallNamedPropertiesDeeplyNested path1;
|
||||
AlternatePathToNoCycleButIndenticallNamedPropertiesDeeplyNestedDocument path2;
|
||||
}
|
||||
|
||||
public static class AlternatePathToNoCycleButIndenticallNamedPropertiesDeeplyNestedDocument {
|
||||
static class AlternatePathToNoCycleButIndenticallNamedPropertiesDeeplyNestedDocument {
|
||||
NoCycleButIndenticallNamedPropertiesDeeplyNested propertyWithIndexedStructure;
|
||||
}
|
||||
|
||||
static class GenericEntityWrapper<T> {
|
||||
class GenericEntityWrapper<T> {
|
||||
T entity;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class EntityWithGenericTypeWrapperAsElement {
|
||||
class EntityWithGenericTypeWrapperAsElement {
|
||||
List<GenericEntityWrapper<DocumentWithNamedIndex>> listWithGeneircTypeElement;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithHashedIndexOnId {
|
||||
class WithHashedIndexOnId {
|
||||
|
||||
@HashIndexed @Id String id;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithHashedIndex {
|
||||
class WithHashedIndex {
|
||||
|
||||
@HashIndexed String value;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithHashedIndexAndIndex {
|
||||
class WithHashedIndexAndIndex {
|
||||
|
||||
@Indexed //
|
||||
@HashIndexed //
|
||||
@@ -1471,7 +1506,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithComposedHashedIndexAndIndex {
|
||||
class WithComposedHashedIndexAndIndex {
|
||||
|
||||
@ComposedHashIndexed(name = "idx-name") String value;
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
* https://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.gridfs;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class GridFsTemplateUnitTests {
|
||||
|
||||
private GridFsTemplateStub template;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
template = new GridFsTemplateStub();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2574
|
||||
void contentMetadataDoesNotOverrideContentTypeIfSet() {
|
||||
|
||||
template.onStoreReturn(new ObjectId());
|
||||
template.store(new ByteArrayInputStream(new byte[] {}), "filename", "json", new Document("meta", "data"));
|
||||
|
||||
assertThat(template.capturedUpload().getOptions().getContentType()).isEqualTo("json");
|
||||
assertThat(template.capturedUpload().getOptions().getMetadata()).containsEntry("meta", "data");
|
||||
}
|
||||
|
||||
private static class GridFsTemplateStub extends GridFsTemplate {
|
||||
|
||||
private Object onStoreResult;
|
||||
private GridFsObject<?, InputStream> capturedUpload;
|
||||
|
||||
GridFsTemplateStub() {
|
||||
super(mock(MongoDatabaseFactory.class), mock(MongoConverter.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T store(GridFsObject<T, InputStream> upload) {
|
||||
|
||||
this.capturedUpload = upload;
|
||||
return (T) onStoreResult;
|
||||
}
|
||||
|
||||
GridFsTemplateStub onStoreReturn(Object result) {
|
||||
|
||||
this.onStoreResult = result;
|
||||
return this;
|
||||
}
|
||||
|
||||
GridFsObject<?, InputStream> capturedUpload() {
|
||||
return capturedUpload;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
* https://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.gridfs;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class ReactiveGridFsTemplateUnitTests {
|
||||
|
||||
private ReactiveGridFsTemplateStub template;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
template = new ReactiveGridFsTemplateStub();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2574
|
||||
void contentMetadataDoesNotOverrideContentTypeIfSet() {
|
||||
|
||||
template.onStoreReturn(new ObjectId());
|
||||
template.store(Flux.empty(), "filename", "json", new Document("meta", "data"));
|
||||
|
||||
assertThat(template.capturedUpload().getOptions().getContentType()).isEqualTo("json");
|
||||
assertThat(template.capturedUpload().getOptions().getMetadata()).containsEntry("meta", "data");
|
||||
}
|
||||
|
||||
private static class ReactiveGridFsTemplateStub extends ReactiveGridFsTemplate {
|
||||
|
||||
private Object onStoreResult;
|
||||
private GridFsObject<?, Publisher<DataBuffer>> capturedUpload;
|
||||
|
||||
ReactiveGridFsTemplateStub() {
|
||||
super(mock(ReactiveMongoDatabaseFactory.class), mock(MongoConverter.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> store(GridFsObject<T, Publisher<DataBuffer>> upload) {
|
||||
|
||||
capturedUpload = upload;
|
||||
return Mono.just((T) onStoreResult);
|
||||
}
|
||||
|
||||
ReactiveGridFsTemplateStub onStoreReturn(Object result) {
|
||||
|
||||
this.onStoreResult = result;
|
||||
return this;
|
||||
}
|
||||
|
||||
GridFsObject<?, Publisher<DataBuffer>> capturedUpload() {
|
||||
return capturedUpload;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user