Browse Source

Add Collation to generated query if present.

See #5004
Original pull request: #5005
pull/5026/head
Christoph Strobl 6 months ago committed by Mark Paluch
parent
commit
66653b9918
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 35
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java
  2. 19
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java
  3. 44
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java

35
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java

@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.aot; @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.aot;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.bson.Document;
@ -31,6 +32,7 @@ import org.springframework.data.mongodb.core.aggregation.AggregationPipeline; @@ -31,6 +32,7 @@ import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.repository.query.MongoParameters;
import org.springframework.data.mongodb.util.json.ParameterBindingContext;
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
@ -106,6 +108,39 @@ public class MongoAotRepositoryFragmentSupport { @@ -106,6 +108,39 @@ public class MongoAotRepositoryFragmentSupport {
return new ParameterBindingDocumentCodec().decode(source, bindingContext);
}
protected Object evaluate(String source, Map<String, Object> parameters) {
ValueEvaluationContext valueEvaluationContext = this.valueExpressionDelegate.getEvaluationContextAccessor()
.create(new NoMongoParameters()).getEvaluationContext(parameters.values());
EvaluationContext evaluationContext = valueEvaluationContext.getEvaluationContext();
parameters.forEach(evaluationContext::setVariable);
ValueExpression parse = valueExpressionDelegate.getValueExpressionParser().parse(source);
return parse.evaluate(valueEvaluationContext);
}
protected Collation collationOf(@Nullable Object source) {
if(source == null) {
return Collation.simple();
}
if (source instanceof String) {
return Collation.parse(source.toString());
}
if (source instanceof Locale locale) {
return Collation.of(locale);
}
if (source instanceof Document document) {
return Collation.from(document);
}
if (source instanceof Collation collation) {
return collation;
}
throw new IllegalArgumentException(
"Unsupported collation source [%s]".formatted(ObjectUtils.nullSafeClassName(source)));
}
protected BasicQuery createQuery(String queryString, Object[] parameters) {
Document queryDocument = bindParameters(queryString, parameters);

19
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java

@ -29,6 +29,7 @@ import org.springframework.data.geo.Circle; @@ -29,6 +29,7 @@ import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Polygon;
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.annotation.Collation;
import org.springframework.data.mongodb.core.geo.GeoJson;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.core.query.BasicQuery;
@ -264,12 +265,26 @@ class QueryBlocks { @@ -264,12 +265,26 @@ class QueryBlocks {
}
String comment = metaAnnotation.getString("comment");
if (StringUtils.hasText("comment")) {
if (StringUtils.hasText(comment)) {
builder.addStatement("$L.comment($S)", queryVariableName, comment);
}
}
// TODO: Meta annotation: Disk usage
MergedAnnotation<Collation> collationAnnotation = context.getAnnotation(Collation.class);
if (collationAnnotation.isPresent()) {
String collationString = collationAnnotation.getString("value");
if(StringUtils.hasText(collationString)) {
if (!MongoCodeBlocks.containsPlaceholder(collationString)) {
builder.addStatement("$L.collation($T.parse($S))", queryVariableName,
org.springframework.data.mongodb.core.query.Collation.class, collationString);
} else {
builder.add("$L.collation(collationOf(evaluate($S, ", queryVariableName, collationString);
builder.add(MongoCodeBlocks.renderArgumentMap(arguments));
builder.add(")));\n");
}
}
}
return builder.build();
}

44
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java

@ -22,6 +22,7 @@ import example.aot.UserRepository; @@ -22,6 +22,7 @@ import example.aot.UserRepository;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import javax.lang.model.element.Modifier;
@ -37,8 +38,10 @@ import org.springframework.data.geo.GeoResults; @@ -37,8 +38,10 @@ import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.annotation.Collation;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.repository.Hint;
import org.springframework.data.mongodb.repository.ReadPreference;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.aot.generate.AotQueryMethodGenerationContext;
@ -211,8 +214,36 @@ public class QueryMethodContributionUnitTests { @@ -211,8 +214,36 @@ public class QueryMethodContributionUnitTests {
MethodSpec methodSpec = codeOf(UserRepository.class, "findByFirstnameRegex", Pattern.class);
assertThat(methodSpec.toString()) //
.contains("createQuery(\"{'firstname':{'$regex':?0}}\"") //
.contains("Object[]{ pattern }");
.contains("createQuery(\"{'firstname':{'$regex':?0}}\"") //
.contains("Object[]{ pattern }");
}
@Test // GH-4939
void rendersHint() throws NoSuchMethodException {
MethodSpec methodSpec = codeOf(UserRepoWithMeta.class, "findByFirstname", String.class);
assertThat(methodSpec.toString()) //
.contains(".withHint(\"fn-idx\")");
}
@Test // GH-4939
void rendersCollation() throws NoSuchMethodException {
MethodSpec methodSpec = codeOf(UserRepoWithMeta.class, "findByFirstname", String.class);
assertThat(methodSpec.toString()) //
.containsPattern(".*\\.collation\\(.*Collation\\.parse\\(\"en_US\"\\)\\)");
}
@Test // GH-4939
void rendersCollationFromExpression() throws NoSuchMethodException {
MethodSpec methodSpec = codeOf(UserRepoWithMeta.class, "findWithCollationByFirstname", String.class, String.class);
assertThat(methodSpec.toString()) //
.containsIgnoringWhitespaces(
"collationOf(evaluate(\"?#{[1]}\", java.util.Map.of(\"firstname\", firstname, \"locale\", locale)))");
}
private static MethodSpec codeOf(Class<?> repository, String methodName, Class<?>... args)
@ -228,7 +259,7 @@ public class QueryMethodContributionUnitTests { @@ -228,7 +259,7 @@ public class QueryMethodContributionUnitTests {
Assertions.fail("No contribution for method %s.%s(%s)".formatted(repository.getSimpleName(), methodName,
Arrays.stream(args).map(Class::getSimpleName).toList()));
}
AotRepositoryFragmentMetadata metadata = new AotRepositoryFragmentMetadata(ClassName.get(UserRepository.class));
AotRepositoryFragmentMetadata metadata = new AotRepositoryFragmentMetadata(ClassName.get(repository));
metadata.addField(
FieldSpec.builder(MongoOperations.class, "mongoOperations", Modifier.PRIVATE, Modifier.FINAL).build());
@ -247,6 +278,13 @@ public class QueryMethodContributionUnitTests { @@ -247,6 +278,13 @@ public class QueryMethodContributionUnitTests {
interface UserRepoWithMeta extends Repository<User, String> {
@Hint("fn-idx")
@Collation("en_US")
List<User> findByFirstname(String firstname);
@Collation("?#{[1]}")
List<User> findWithCollationByFirstname(String firstname, String locale);
@ReadPreference("NEAREST")
GeoResults<User> findByLocationCoordinatesNear(Point point, Distance maxDistance);
}

Loading…
Cancel
Save