Skip to content

Commit

Permalink
Polishing.
Browse files Browse the repository at this point in the history
Reformat code. Tweak javadoc. Reject wildcard projection usage on properties with a MappingException. Omit wildcard projections when declared on document types that are used as subdocument.

See #3225
Original pull request: #3671.
  • Loading branch information
mp911de committed Jul 14, 2021
1 parent d57c5a9 commit f3b90c2
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private static Converter<IndexDefinition, IndexOptions> getIndexDefinitionIndexO
ops = ops.collation(fromDocument(indexOptions.get("collation", Document.class)));
}

if(indexOptions.containsKey("wildcardProjection")) {
if (indexOptions.containsKey("wildcardProjection")) {
ops.wildcardProjection(indexOptions.get("wildcardProjection", Document.class));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@
public final class IndexField {

enum Type {
GEO, TEXT, DEFAULT, HASH, WILDCARD;
GEO, TEXT, DEFAULT,

/**
* @since 2.2
*/
HASH,

/**
* @since 3.3
*/
WILDCARD;
}

private final String key;
Expand Down Expand Up @@ -78,7 +88,8 @@ static IndexField hashed(String key) {
}

/**
* Creates a {@literal wildcard} {@link IndexField} for the given key.
* Creates a {@literal wildcard} {@link IndexField} for the given key. The {@code key} must follow the
* {@code fieldName.$**} notation.
*
* @param key must not be {@literal null} or empty.
* @return new instance of {@link IndexField}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static IndexInfo indexInfoOf(Document sourceDocument) {

if (ObjectUtils.nullSafeEquals("hashed", value)) {
indexFields.add(IndexField.hashed(key));
} else if (key.contains("$**")) {
} else if (key.endsWith("$**")) {
indexFields.add(IndexField.wildcard(key));
} else {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public List<IndexDefinitionHolder> resolveIndexForEntity(MongoPersistentEntity<?
Assert.notNull(document, () -> String
.format("Entity %s is not a collection root. Make sure to annotate it with @Document!", root.getName()));

verifyWildcardIndexedProjection(root);

List<IndexDefinitionHolder> indexInformation = new ArrayList<>();
String collection = root.getCollection();
indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions("", collection, root));
Expand All @@ -133,6 +135,24 @@ public List<IndexDefinitionHolder> resolveIndexForEntity(MongoPersistentEntity<?
return indexInformation;
}

private void verifyWildcardIndexedProjection(MongoPersistentEntity<?> entity) {

entity.doWithAll(it -> {

if (it.isAnnotationPresent(WildcardIndexed.class)) {

WildcardIndexed indexed = it.getRequiredAnnotation(WildcardIndexed.class);

if (!ObjectUtils.isEmpty(indexed.wildcardProjection())) {

throw new MappingException(String.format(
"WildcardIndexed.wildcardProjection cannot be used on nested paths. Offending property: %s.%s",
entity.getName(), it.getName()));
}
}
});
}

private void potentiallyAddIndexForProperty(MongoPersistentEntity<?> root, MongoPersistentProperty persistentProperty,
List<IndexDefinitionHolder> indexes, CycleGuard guard) {

Expand Down Expand Up @@ -257,7 +277,7 @@ private List<IndexDefinitionHolder> potentiallyCreateCompoundIndexDefinitions(St
private List<IndexDefinitionHolder> potentiallyCreateWildcardIndexDefinitions(String dotPath, String collection,
MongoPersistentEntity<?> entity) {

if (entity.findAnnotation(WildcardIndexed.class) == null) {
if (!entity.isAnnotationPresent(WildcardIndexed.class)) {
return Collections.emptyList();
}

Expand Down Expand Up @@ -429,7 +449,7 @@ protected IndexDefinitionHolder createWildcardIndexDefinition(String dotPath, St

WildcardIndex indexDefinition = new WildcardIndex(dotPath);

if (StringUtils.hasText(index.wildcardProjection())) {
if (StringUtils.hasText(index.wildcardProjection()) && ObjectUtils.isEmpty(dotPath)) {
indexDefinition.wildcardProjection(evaluateWildcardProjection(index.wildcardProjection(), entity));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
public class WildcardIndex extends Index {

private @Nullable String fieldName;
private Map<String, Object> wildcardProjection = new LinkedHashMap<>();
private final Map<String, Object> wildcardProjection = new LinkedHashMap<>();

/**
* Create a new instance of {@link WildcardIndex} using {@code $**}.
Expand Down Expand Up @@ -97,7 +97,7 @@ public WildcardIndex named(String name) {
/**
* Unique option is not supported.
*
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException not supported for wildcard indexes.
*/
@Override
public Index unique() {
Expand All @@ -107,7 +107,7 @@ public Index unique() {
/**
* ttl option is not supported.
*
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException not supported for wildcard indexes.
*/
@Override
public Index expire(long seconds) {
Expand All @@ -117,7 +117,7 @@ public Index expire(long seconds) {
/**
* ttl option is not supported.
*
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException not supported for wildcard indexes.
*/
@Override
public Index expire(long value, TimeUnit timeUnit) {
Expand All @@ -127,7 +127,7 @@ public Index expire(long value, TimeUnit timeUnit) {
/**
* ttl option is not supported.
*
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException not supported for wildcard indexes.
*/
@Override
public Index expire(Duration duration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*
* db.product.createIndex({ "$**" : 1 } , {})
* </pre>
*
*
* {@literal wildcardProjection} can be used to specify keys to in-/exclude in the index.
*
* <pre class="code">
Expand All @@ -65,7 +65,7 @@
* <pre class="code">
* &#64;Document
* public class User {
*
*
* private &#64;Id String id;
*
* &#64;WildcardIndexed
Expand All @@ -89,9 +89,9 @@
* expression}. <br />
* <br />
* The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
* provided name will be prefixed with the path leading to the entity. <br />
*
* @return
* provided name will be prefixed with the path leading to the entity.
*
* @return empty by default.
*/
String name() default "";

Expand All @@ -115,8 +115,8 @@
/**
* Explicitly specify sub fields to be in-/excluded as a {@link org.bson.Document#parse(String) prasable} String.
* <br />
* <strong>NOTE: </strong>Can only be done on root level documents.
*
* <strong>NOTE: </strong>Can only be applied on root level documents.
*
* @return empty by default.
*/
String wildcardProjection() default "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

import org.springframework.core.annotation.AliasFor;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mongodb.core.DocumentTestUtils;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolverUnitTests.CompoundIndexResolutionTests;
Expand Down Expand Up @@ -1333,6 +1335,20 @@ public void resolvesWildcardOnRoot() {
assertThat(indices).hasSize(1);
assertThat(indices.get(0)).satisfies(it -> {
assertThat(it.getIndexKeys()).containsEntry("$**", 1);
assertThat(it.getIndexOptions()).isEmpty();
});
}

@Test // GH-3225
public void resolvesWildcardWithProjectionOnRoot() {

List<IndexDefinitionHolder> indices = prepareMappingContextAndResolveIndexForType(
WithWildCardIndexHavingProjectionOnEntity.class);
assertThat(indices).hasSize(1);
assertThat(indices.get(0)).satisfies(it -> {
assertThat(it.getIndexKeys()).containsEntry("$**", 1);
assertThat(it.getIndexOptions()).containsEntry("wildcardProjection",
org.bson.Document.parse("{'_id' : 1, 'value' : 0}"));
});
}

Expand Down Expand Up @@ -1365,6 +1381,15 @@ public void resolvesWildcardTypeOfNestedProperty() {
assertThat(indices).hasSize(1);
assertThat(indices.get(0)).satisfies(it -> {
assertThat(it.getIndexKeys()).containsEntry("value.$**", 1);
assertThat(it.getIndexOptions()).hasSize(1).containsKey("name");
});
}

@Test // GH-3225
public void rejectsWildcardProjectionOnNestedPaths() {

assertThatExceptionOfType(MappingException.class).isThrownBy(() -> {
prepareMappingContextAndResolveIndexForType(WildcardIndexedProjectionOnNestedPath.class);
});
}

Expand Down Expand Up @@ -1647,10 +1672,16 @@ class WithWildCardIndexOnProperty {

}

@Document
class WildcardIndexedProjectionOnNestedPath {

@WildcardIndexed(wildcardProjection = "{}") String foo;
}

@Document
class WithWildCardOnEntityOfNested {

WithWildCardIndexOnEntity value;
WithWildCardIndexHavingProjectionOnEntity value;

}

Expand Down
1 change: 1 addition & 0 deletions src/main/asciidoc/new-features.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

* Extended support for <<mapping-usage.document-references, referencing>> entities.
* Include/exclude `null` properties on write to `Document` through `@Field(write=…)`.
* Support for <<mapping-usage-indexes.wildcard-index>>.

[[new-features.3.2]]
== What's New in Spring Data MongoDB 3.2
Expand Down
9 changes: 5 additions & 4 deletions src/main/asciidoc/reference/mapping.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -782,9 +782,9 @@ db.user.createIndex({ "userMetadata.$**" : 1 }, {})
----
====

The `@WildcardIndex` annotation allows a declarative index setup an can be added on either a type or property.
The `@WildcardIndex` annotation allows a declarative index setup that can used either with a document type or property.

If placed on a type that is a root level domain entity (one having an `@Document` annotation) will advise the index creator to create a
If placed on a type that is a root level domain entity (one annotated with `@Document`) , the index resolver will create a
wildcard index for it.

.Wildcard index on domain type
Expand All @@ -794,7 +794,7 @@ wildcard index for it.
@Document
@WildcardIndexed
public class Product {
...
// …
}
----
[source,javascript]
Expand Down Expand Up @@ -828,7 +828,8 @@ db.user.createIndex(
====

Wildcard indexes can also be expressed by adding the annotation directly to the field.
Please note that `wildcardProjection` is not allowed on nested paths.
Please note that `wildcardProjection` is not allowed on nested paths such as properties.
Projections on types annotated with `@WildcardIndexed` are omitted during index creation.

.Wildcard index on property
====
Expand Down

0 comments on commit f3b90c2

Please # to comment.