Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import org.jspecify.annotations.Nullable;

import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.annotation.Id;
import org.springframework.data.core.TypeInformation;
import org.springframework.data.expression.ValueEvaluationContext;
Expand Down Expand Up @@ -96,13 +97,24 @@ public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
this.collection = StringUtils.hasText(document.collection()) ? document.collection() : fallback;
this.language = StringUtils.hasText(document.language()) ? document.language() : "";
this.expression = detectExpression(document.collection());
this.collation = document.collation();
this.collationExpression = detectExpression(document.collation());
} else {

this.collection = fallback;
this.language = "";
this.expression = null;
}

// Pick up the standalone @Collation annotation independently of @Document. @Document.collation
// remains supported because @Document is meta-annotated with @Collation and Document#collation
// is declared as @AliasFor(annotation = Collation.class, attribute = "value"), so the merged
// lookup returns the same value in either case.
org.springframework.data.mongodb.core.annotation.Collation collationAnnotation = AnnotatedElementUtils
.findMergedAnnotation(rawType, org.springframework.data.mongodb.core.annotation.Collation.class);

if (collationAnnotation != null && StringUtils.hasText(collationAnnotation.value())) {
this.collation = collationAnnotation.value();
this.collationExpression = detectExpression(collationAnnotation.value());
} else {
this.collation = null;
this.collationExpression = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public Optional<T> findById(ID id) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);

return Optional.ofNullable(
Expand All @@ -136,6 +137,7 @@ public boolean existsById(ID id) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);

return mongoOperations.exists(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
Expand All @@ -158,6 +160,7 @@ public List<T> findAllById(Iterable<ID> ids) {
public long count() {

Query query = new Query();
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.count(query, entityInformation.getCollectionName());
}
Expand All @@ -168,6 +171,7 @@ public void deleteById(ID id) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
mongoOperations.remove(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}
Expand All @@ -193,6 +197,7 @@ public void deleteAllById(Iterable<? extends ID> ids) {
Assert.notNull(ids, "The given Iterable of ids must not be null");

Query query = getIdQuery(ids);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
mongoOperations.remove(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}
Expand All @@ -209,6 +214,7 @@ public void deleteAll(Iterable<? extends T> entities) {
public void deleteAll() {

Query query = new Query();
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);

mongoOperations.remove(query, entityInformation.getCollectionName());
Expand Down Expand Up @@ -385,6 +391,7 @@ private Criteria getIdCriteria(Object id) {
private Query getIdQuery(Iterable<? extends ID> ids) {

Query query = new Query(new Criteria(entityInformation.getIdAttribute()).in(toCollection(ids)));
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return query;
}
Expand All @@ -400,10 +407,18 @@ private List<T> findAll(@Nullable Query query) {
return Collections.emptyList();
}

applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.find(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}

private void applyDefaultCollation(Query query) {

if (entityInformation.hasCollation() && !query.getCollation().isPresent()) {
query.collation(entityInformation.getCollation());
}
}

/**
* {@link org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery} using {@link Example}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public Mono<T> findById(ID id) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.findOne(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}
Expand All @@ -142,6 +143,7 @@ public Mono<T> findById(Publisher<ID> publisher) {

return Mono.from(publisher).flatMap(id -> {
Query query = getIdQuery(id);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);
return mongoOperations.findOne(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
});
Expand All @@ -153,6 +155,7 @@ public Mono<Boolean> existsById(ID id) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.exists(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}
Expand All @@ -165,6 +168,7 @@ public Mono<Boolean> existsById(Publisher<ID> publisher) {

return Mono.from(publisher).flatMap(id -> {
Query query = getIdQuery(id);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);
return mongoOperations.exists(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
});
Expand All @@ -191,6 +195,7 @@ public Flux<T> findAllById(Publisher<ID> ids) {
Optional<ReadPreference> readPreference = getReadPreference();
return Flux.from(ids).buffer().flatMapSequential(listOfIds -> {
Query query = getIdQuery(listOfIds);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);
return mongoOperations.find(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
});
Expand All @@ -200,6 +205,7 @@ public Flux<T> findAllById(Publisher<ID> ids) {
public Mono<Long> count() {

Query query = new Query();
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.count(query, entityInformation.getCollectionName());
}
Expand All @@ -217,6 +223,7 @@ private Mono<Void> deleteById(ID id, Optional<ReadPreference> readPreference) {
Assert.notNull(id, "The given id must not be null");

Query query = getIdQuery(id);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);
return mongoOperations.remove(query, entityInformation.getJavaType(), entityInformation.getCollectionName()).then();
}
Expand All @@ -230,6 +237,7 @@ public Mono<Void> deleteById(Publisher<ID> publisher) {

return Mono.from(publisher).flatMap(id -> {
Query query = getIdQuery(id);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);
return mongoOperations.remove(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}).then();
Expand Down Expand Up @@ -272,6 +280,7 @@ public Mono<Void> deleteAllById(Iterable<? extends ID> ids) {
private Mono<Void> deleteAllById(Iterable<? extends ID> ids, Optional<ReadPreference> readPreference) {

Query query = getIdQuery(ids);
applyDefaultCollation(query);
readPreference.ifPresent(query::withReadPreference);

return mongoOperations.remove(query, entityInformation.getJavaType(), entityInformation.getCollectionName()).then();
Expand Down Expand Up @@ -302,6 +311,7 @@ public Mono<Void> deleteAll(Publisher<? extends T> entityStream) {
@Override
public Mono<Void> deleteAll() {
Query query = new Query();
applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.remove(query, entityInformation.getCollectionName()).then(Mono.empty());
}
Expand Down Expand Up @@ -444,10 +454,18 @@ void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {

private Flux<T> findAll(Query query) {

applyDefaultCollation(query);
getReadPreference().ifPresent(query::withReadPreference);
return mongoOperations.find(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
}

private void applyDefaultCollation(Query query) {

if (entityInformation.hasCollation() && !query.getCollation().isPresent()) {
query.collation(entityInformation.getCollation());
}
}

private Optional<ReadPreference> getReadPreference() {

if (crudMethodMetadata == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,24 @@ void usesCorrectExpressionsForCollectionAndCollation() {
assertThat(entity.getCollation()).isEqualTo(Collation.of("en_US"));
}

@Test // GH-4535
void readsStandaloneCollationAnnotation() {

BasicMongoPersistentEntity<WithStandaloneCollation> entity = new BasicMongoPersistentEntity<>(
TypeInformation.of(WithStandaloneCollation.class));

assertThat(entity.getCollation()).isEqualTo(Collation.of("en_US"));
}

@Test // GH-4535
void readsStandaloneCollationAnnotationWithoutDocumentAnnotation() {

BasicMongoPersistentEntity<WithStandaloneCollationOnly> entity = new BasicMongoPersistentEntity<>(
TypeInformation.of(WithStandaloneCollationOnly.class));

assertThat(entity.getCollation()).isEqualTo(Collation.of("en_US"));
}

@Test // DATAMONGO-2341
void detectsShardedEntityCorrectly() {

Expand Down Expand Up @@ -398,6 +416,13 @@ class WithSimpleCollation {}
@Document(collation = "{ 'locale' : 'en_US' }")
class WithDocumentCollation {}

@Document
@org.springframework.data.mongodb.core.annotation.Collation("en_US")
class WithStandaloneCollation {}

@org.springframework.data.mongodb.core.annotation.Collation("en_US")
class WithStandaloneCollationOnly {}

@Sharded
private class WithDefaultShardKey {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,105 @@ public void shouldAddDefaultCollationToFindOneForExampleIfPresent() {
assertThat(query.getValue().getCollation()).contains(collation);
}

@ParameterizedTest // GH-4535
@MethodSource("findCallsThatAcceptDefaultCollation")
void shouldAddDefaultCollationToFindMethods(
Consumer<SimpleMongoRepository<Object, Object>> findCall) {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);

findCall.accept(repository);

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).find(query.capture(), any(), any());

assertThat(query.getValue().getCollation()).contains(collation);
}

@Test // GH-4535
void shouldAddDefaultCollationToFindById() {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);
when(entityInformation.getIdAttribute()).thenReturn("id");

repository.findById("42");

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).findOne(query.capture(), any(), any());

assertThat(query.getValue().getCollation()).contains(collation);
}

@Test // GH-4535
void shouldAddDefaultCollationToExistsById() {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);
when(entityInformation.getIdAttribute()).thenReturn("id");

repository.existsById("42");

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).exists(query.capture(), any(), any());

assertThat(query.getValue().getCollation()).contains(collation);
}

@Test // GH-4535
void shouldAddDefaultCollationToCount() {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);
when(entityInformation.getCollectionName()).thenReturn("documents");

repository.count();

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).count(query.capture(), any(String.class));

assertThat(query.getValue().getCollation()).contains(collation);
}

@Test // GH-4535
void shouldAddDefaultCollationToDeleteById() {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);
when(entityInformation.getIdAttribute()).thenReturn("id");
when(entityInformation.getJavaType()).thenReturn(Object.class);
when(entityInformation.getCollectionName()).thenReturn("documents");

repository.deleteById("42");

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).remove(query.capture(), any(Class.class), any(String.class));

assertThat(query.getValue().getCollation()).contains(collation);
}

@Test // GH-4535
void shouldAddDefaultCollationToDeleteAll() {

Collation collation = Collation.of("en_US");
when(entityInformation.hasCollation()).thenReturn(true);
when(entityInformation.getCollation()).thenReturn(collation);
when(entityInformation.getCollectionName()).thenReturn("documents");

repository.deleteAll();

ArgumentCaptor<Query> query = ArgumentCaptor.forClass(Query.class);
verify(mongoOperations).remove(query.capture(), any(String.class));

assertThat(query.getValue().getCollation()).contains(collation);
}

@ParameterizedTest // GH-2971
@MethodSource("findAllCalls")
void shouldAddReadPreferenceToFindAllMethods(Consumer<SimpleMongoRepository<Object, Object>> findCall)
Expand Down Expand Up @@ -219,6 +318,16 @@ private static Stream<Arguments> findAllCalls() {
Arguments.of(findAllWithExampleAndPage));
}

private static Stream<Arguments> findCallsThatAcceptDefaultCollation() {

Consumer<SimpleMongoRepository<Object, Object>> findAll = SimpleMongoRepository::findAll;
Consumer<SimpleMongoRepository<Object, Object>> findAllWithSort = repo -> repo.findAll(Sort.by("age"));
Consumer<SimpleMongoRepository<Object, Object>> findAllWithPage = repo -> repo
.findAll(PageRequest.of(1, 20, Sort.by("age")));

return Stream.of(Arguments.of(findAll), Arguments.of(findAllWithSort), Arguments.of(findAllWithPage));
}

static class TestDummy {

}
Expand Down
Loading