Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b069279f9d | ||
|
|
70c9a44382 | ||
|
|
6a9163da08 | ||
|
|
a21fca78dd | ||
|
|
a35c4f2717 | ||
|
|
8803e0383d | ||
|
|
0b4c8fd780 | ||
|
|
53c56f6e20 | ||
|
|
6af9b562f6 | ||
|
|
a5f73850af | ||
|
|
68b4a09273 | ||
|
|
7290d78053 | ||
|
|
4acbb1282f | ||
|
|
b89c4cd231 | ||
|
|
8d650ca1d2 | ||
|
|
b9a23baf16 | ||
|
|
d1326a45fc | ||
|
|
ca24950014 | ||
|
|
f157560d1c | ||
|
|
4aa12fd24b | ||
|
|
c4a99370d8 |
4
.mvn/wrapper/maven-wrapper.properties
vendored
4
.mvn/wrapper/maven-wrapper.properties
vendored
@@ -1,2 +1,2 @@
|
||||
#Mon Feb 20 11:59:26 CET 2023
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip
|
||||
#Thu Apr 06 16:17:30 CEST 2023
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.1/apache-maven-3.9.1-bin.zip
|
||||
|
||||
90
Jenkinsfile
vendored
90
Jenkinsfile
vendored
@@ -18,69 +18,7 @@ pipeline {
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Docker images") {
|
||||
parallel {
|
||||
stage('Publish JDK (Java 17) + MongoDB 4.4') {
|
||||
when {
|
||||
anyOf {
|
||||
changeset "ci/openjdk17-mongodb-4.4/**"
|
||||
changeset "ci/pipeline.properties"
|
||||
}
|
||||
}
|
||||
agent { label 'data' }
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
steps {
|
||||
script {
|
||||
def image = docker.build("springci/spring-data-with-mongodb-4.4:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.4.4.version']} ci/openjdk17-mongodb-4.4/")
|
||||
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
|
||||
image.push()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish JDK (Java 17) + MongoDB 5.0') {
|
||||
when {
|
||||
anyOf {
|
||||
changeset "ci/openjdk17-mongodb-5.0/**"
|
||||
changeset "ci/pipeline.properties"
|
||||
}
|
||||
}
|
||||
agent { label 'data' }
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
steps {
|
||||
script {
|
||||
def image = docker.build("springci/spring-data-with-mongodb-5.0:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.5.0.version']} ci/openjdk17-mongodb-5.0/")
|
||||
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
|
||||
image.push()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish JDK (Java 17) + MongoDB 6.0') {
|
||||
when {
|
||||
anyOf {
|
||||
changeset "ci/openjdk17-mongodb-6.0/**"
|
||||
changeset "ci/pipeline.properties"
|
||||
}
|
||||
}
|
||||
agent { label 'data' }
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
steps {
|
||||
script {
|
||||
def image = docker.build("springci/spring-data-with-mongodb-6.0:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.6.0.version']} ci/openjdk17-mongodb-6.0/")
|
||||
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
|
||||
image.push()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage("test: baseline (Java 17)") {
|
||||
stage("test: baseline (main)") {
|
||||
when {
|
||||
beforeAgent(true)
|
||||
anyOf {
|
||||
@@ -119,7 +57,7 @@ pipeline {
|
||||
}
|
||||
parallel {
|
||||
|
||||
stage("test: MongoDB 5.0 (Java 17)") {
|
||||
stage("test: MongoDB 5.0 (main)") {
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
@@ -141,7 +79,7 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
stage("test: MongoDB 6.0 (Java 17)") {
|
||||
stage("test: MongoDB 6.0 (main)") {
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
@@ -162,6 +100,28 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage("test: MongoDB 6.0 (next)") {
|
||||
agent {
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
environment {
|
||||
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-6.0:${p['java.next.tag']}").inside(p['docker.java.inside.basic']) {
|
||||
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
||||
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
|
||||
sh 'sleep 10'
|
||||
sh 'mongosh --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
|
||||
sh 'sleep 15'
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
ARG BASE
|
||||
FROM ${BASE}
|
||||
# Any ARG statements before FROM are cleared.
|
||||
ARG MONGODB
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN set -eux; \
|
||||
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
|
||||
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 && \
|
||||
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 && \
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list && \
|
||||
echo ${TZ} > /etc/timezone
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,24 +0,0 @@
|
||||
ARG BASE
|
||||
FROM ${BASE}
|
||||
# Any ARG statements before FROM are cleared.
|
||||
ARG MONGODB
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN set -eux; \
|
||||
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
|
||||
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
|
||||
# MongoDB 5.0 release signing key
|
||||
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv B00A0BD1E2C63C11 && \
|
||||
# Needed when MongoDB creates a 5.0 folder.
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list && \
|
||||
echo ${TZ} > /etc/timezone
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,24 +0,0 @@
|
||||
ARG BASE
|
||||
FROM ${BASE}
|
||||
# Any ARG statements before FROM are cleared.
|
||||
ARG MONGODB
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN set -eux; \
|
||||
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
|
||||
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
|
||||
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
|
||||
# MongoDB 6.0 release signing key
|
||||
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | apt-key add - && \
|
||||
# Needed when MongoDB creates a 6.0 folder.
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list && \
|
||||
echo ${TZ} > /etc/timezone
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,8 +1,10 @@
|
||||
# Java versions
|
||||
java.main.tag=17.0.6_10-jdk-focal
|
||||
java.next.tag=20-jdk-jammy
|
||||
|
||||
# Docker container images - standard
|
||||
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
|
||||
docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.next.tag}
|
||||
|
||||
# Supported versions of MongoDB
|
||||
docker.mongodb.4.4.version=4.4.18
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.0.4</version>
|
||||
<version>4.0.6</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>3.0.4</version>
|
||||
<version>3.0.6</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -26,7 +26,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>3.0.4</springdata.commons>
|
||||
<springdata.commons>3.0.6</springdata.commons>
|
||||
<mongo>4.8.2</mongo>
|
||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.0.4</version>
|
||||
<version>4.0.6</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.0.4</version>
|
||||
<version>4.0.6</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>4.0.4</version>
|
||||
<version>4.0.6</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.aot;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -25,7 +26,6 @@ import java.util.Set;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
@@ -33,7 +33,6 @@ import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory;
|
||||
import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory.LazyLoadingInterceptor;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
import org.springframework.data.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -66,9 +65,7 @@ public class LazyLoadingProxyAotProcessor {
|
||||
if (field.getType().isInterface()) {
|
||||
|
||||
List<Class<?>> interfaces = new ArrayList<>(
|
||||
TypeUtils.resolveTypesInSignature(ResolvableType.forField(field, type)));
|
||||
|
||||
interfaces.add(0, org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class);
|
||||
Arrays.asList(LazyLoadingProxyFactory.prepareFactory(field.getType()).getProxiedInterfaces()));
|
||||
interfaces.add(org.springframework.aop.SpringProxy.class);
|
||||
interfaces.add(org.springframework.aop.framework.Advised.class);
|
||||
interfaces.add(org.springframework.core.DecoratingProxy.class);
|
||||
@@ -77,7 +74,7 @@ public class LazyLoadingProxyAotProcessor {
|
||||
} else {
|
||||
|
||||
Class<?> proxyClass = LazyLoadingProxyFactory.resolveProxyType(field.getType(),
|
||||
() -> LazyLoadingInterceptor.none());
|
||||
LazyLoadingInterceptor::none);
|
||||
|
||||
// see: spring-projects/spring-framework/issues/29309
|
||||
generationContext.getRuntimeHints().reflection().registerType(proxyClass,
|
||||
|
||||
@@ -1818,7 +1818,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
if (query.getLimit() > 0 && mapReduceOptions != null && mapReduceOptions.getLimit() == null) {
|
||||
mapReduce = mapReduce.limit(query.getLimit());
|
||||
}
|
||||
if (query.getMeta().getMaxTimeMsec() != null) {
|
||||
if (query.getMeta().hasMaxTime()) {
|
||||
mapReduce = mapReduce.maxTime(query.getMeta().getMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@@ -3159,12 +3159,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
|
||||
if (meta.hasValues()) {
|
||||
|
||||
if (StringUtils.hasText(meta.getComment())) {
|
||||
cursorToUse = cursorToUse.comment(meta.getComment());
|
||||
if (meta.hasComment()) {
|
||||
cursorToUse = cursorToUse.comment(meta.getRequiredComment());
|
||||
}
|
||||
|
||||
if (meta.getMaxTimeMsec() != null) {
|
||||
cursorToUse = cursorToUse.maxTime(meta.getMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
if (meta.hasMaxTime()) {
|
||||
cursorToUse = cursorToUse.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (meta.getCursorBatchSize() != null) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -52,6 +53,7 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.ShardKey;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.mongodb.core.query.Meta;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
|
||||
@@ -388,7 +390,7 @@ class QueryOperations {
|
||||
|
||||
for (Entry<String, Object> entry : fields.entrySet()) {
|
||||
|
||||
if (entry.getValue() instanceof MongoExpression) {
|
||||
if (entry.getValue()instanceof MongoExpression) {
|
||||
|
||||
AggregationOperationContext ctx = entity == null ? Aggregation.DEFAULT_CONTEXT
|
||||
: new RelaxedTypeBasedAggregationOperationContext(entity.getType(), mappingContext, queryMapper);
|
||||
@@ -564,9 +566,23 @@ class QueryOperations {
|
||||
if (query.getLimit() > 0) {
|
||||
options.limit(query.getLimit());
|
||||
}
|
||||
|
||||
if (query.getSkip() > 0) {
|
||||
options.skip((int) query.getSkip());
|
||||
}
|
||||
|
||||
Meta meta = query.getMeta();
|
||||
if (meta.hasValues()) {
|
||||
|
||||
if (meta.hasMaxTime()) {
|
||||
options.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (meta.hasComment()) {
|
||||
options.comment(meta.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
|
||||
String hint = query.getHint();
|
||||
|
||||
@@ -1971,8 +1971,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
publisher.sort(mappedSort);
|
||||
}
|
||||
|
||||
if (filterQuery.getMeta().getMaxTimeMsec() != null) {
|
||||
publisher.maxTime(filterQuery.getMeta().getMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
Meta meta = filterQuery.getMeta();
|
||||
if (meta.hasMaxTime()) {
|
||||
publisher.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (filterQuery.getLimit() > 0 || (options.getLimit() != null)) {
|
||||
@@ -3062,12 +3063,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
if (meta.hasValues()) {
|
||||
|
||||
if (StringUtils.hasText(meta.getComment())) {
|
||||
findPublisherToUse = findPublisherToUse.comment(meta.getComment());
|
||||
if (meta.hasComment()) {
|
||||
findPublisherToUse = findPublisherToUse.comment(meta.getRequiredComment());
|
||||
}
|
||||
|
||||
if (meta.getMaxTimeMsec() != null) {
|
||||
findPublisherToUse = findPublisherToUse.maxTime(meta.getMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
if (meta.hasMaxTime()) {
|
||||
findPublisherToUse = findPublisherToUse.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (meta.getCursorBatchSize() != null) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class LazyLoadingProxyFactory {
|
||||
/**
|
||||
* Predict the proxy target type. This will advice the infrastructure to resolve as many pieces as possible in a
|
||||
* potential AOT scenario without necessarily resolving the entire object.
|
||||
*
|
||||
*
|
||||
* @param propertyType the type to proxy
|
||||
* @param interceptor the interceptor to be added.
|
||||
* @return the proxy type.
|
||||
@@ -90,16 +90,30 @@ public final class LazyLoadingProxyFactory {
|
||||
.getProxyClass(LazyLoadingProxy.class.getClassLoader());
|
||||
}
|
||||
|
||||
private ProxyFactory prepareProxyFactory(Class<?> propertyType, Supplier<LazyLoadingInterceptor> interceptor) {
|
||||
/**
|
||||
* Create the {@link ProxyFactory} for the given type, already adding required additional interfaces.
|
||||
*
|
||||
* @param targetType the type to proxy.
|
||||
* @return the prepared {@link ProxyFactory}.
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public static ProxyFactory prepareFactory(Class<?> targetType) {
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
|
||||
for (Class<?> type : propertyType.getInterfaces()) {
|
||||
for (Class<?> type : targetType.getInterfaces()) {
|
||||
proxyFactory.addInterface(type);
|
||||
}
|
||||
|
||||
proxyFactory.addInterface(LazyLoadingProxy.class);
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addInterface(targetType);
|
||||
|
||||
return proxyFactory;
|
||||
}
|
||||
|
||||
private ProxyFactory prepareProxyFactory(Class<?> propertyType, Supplier<LazyLoadingInterceptor> interceptor) {
|
||||
|
||||
ProxyFactory proxyFactory = prepareFactory(propertyType);
|
||||
proxyFactory.addAdvice(interceptor.get());
|
||||
|
||||
return proxyFactory;
|
||||
|
||||
@@ -2147,7 +2147,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*
|
||||
* @since 3.4.3
|
||||
*/
|
||||
interface ConversionContext {
|
||||
protected interface ConversionContext {
|
||||
|
||||
/**
|
||||
* Converts a source object into {@link TypeInformation target}.
|
||||
@@ -2315,8 +2315,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
if (source instanceof Collection) {
|
||||
|
||||
Class<?> rawType = typeHint.getType();
|
||||
if (!Object.class.equals(rawType)) {
|
||||
if (!Object.class.equals(rawType) && !String.class.equals(rawType)) {
|
||||
|
||||
if (!rawType.isArray() && !ClassUtils.isAssignable(Iterable.class, rawType)) {
|
||||
|
||||
throw new MappingException(
|
||||
String.format(INCOMPATIBLE_TYPES, source, source.getClass(), rawType, getPath()));
|
||||
}
|
||||
@@ -2345,11 +2347,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return (S) dbRefConverter.convert(context, (DBRef) source, typeHint);
|
||||
}
|
||||
|
||||
if (source instanceof Collection) {
|
||||
throw new MappingException(
|
||||
String.format(INCOMPATIBLE_TYPES, source, BasicDBList.class, typeHint.getType(), getPath()));
|
||||
}
|
||||
|
||||
if (BsonUtils.supportsBson(source)) {
|
||||
return (S) documentConverter.convert(context, BsonUtils.asBson(source), typeHint);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,19 @@ public class Meta {
|
||||
this.allowDiskUse = source.allowDiskUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the maximum time limit for processing operations is set.
|
||||
*
|
||||
* @return {@code true} if set; {@code false} otherwise.
|
||||
* @since 4.0.6
|
||||
*/
|
||||
public boolean hasMaxTime() {
|
||||
|
||||
Long maxTimeMsec = getMaxTimeMsec();
|
||||
|
||||
return maxTimeMsec != null && maxTimeMsec > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
@@ -77,6 +90,26 @@ public class Meta {
|
||||
return getValue(MetaKey.MAX_TIME_MS.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required maximum time limit in milliseconds or throws {@link IllegalStateException} if the maximum time
|
||||
* limit is not set.
|
||||
*
|
||||
* @return the maximum time limit in milliseconds for processing operations.
|
||||
* @throws IllegalStateException if the maximum time limit is not set
|
||||
* @see #hasMaxTime()
|
||||
* @since 4.0.6
|
||||
*/
|
||||
public Long getRequiredMaxTimeMsec() {
|
||||
|
||||
Long maxTimeMsec = getMaxTimeMsec();
|
||||
|
||||
if (maxTimeMsec == null) {
|
||||
throw new IllegalStateException("Maximum time limit in milliseconds not set");
|
||||
}
|
||||
|
||||
return maxTimeMsec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum time limit in milliseconds for processing operations.
|
||||
*
|
||||
@@ -99,12 +132,13 @@ public class Meta {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to the query that is propagated to the profile log.
|
||||
* Return whether the comment is set.
|
||||
*
|
||||
* @param comment
|
||||
* @return {@code true} if set; {@code false} otherwise.
|
||||
* @since 4.0.6
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
setValue(MetaKey.COMMENT.key, comment);
|
||||
public boolean hasComment() {
|
||||
return StringUtils.hasText(getComment());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,6 +149,34 @@ public class Meta {
|
||||
return getValue(MetaKey.COMMENT.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the required comment or throws {@link IllegalStateException} if the comment is not set.
|
||||
*
|
||||
* @return the comment.
|
||||
* @throws IllegalStateException if the comment is not set
|
||||
* @see #hasComment()
|
||||
* @since 4.0.6
|
||||
*/
|
||||
public String getRequiredComment() {
|
||||
|
||||
String comment = getComment();
|
||||
|
||||
if (comment == null) {
|
||||
throw new IllegalStateException("Comment not set");
|
||||
}
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to the query that is propagated to the profile log.
|
||||
*
|
||||
* @param comment
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
setValue(MetaKey.COMMENT.key, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
* @since 2.1
|
||||
|
||||
@@ -127,6 +127,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
* @param accessor for providing invocation arguments. Never {@literal null}.
|
||||
* @param typeToRead the desired component target type. Can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected Object doExecute(MongoQueryMethod method, ResultProcessor processor, ConvertingParameterAccessor accessor,
|
||||
@Nullable Class<?> typeToRead) {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
import java.util.function.LongUnaryOperator;
|
||||
@@ -25,8 +24,8 @@ import org.bson.Document;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.mongodb.core.query.Meta;
|
||||
@@ -36,7 +35,6 @@ import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Internal utility class to help avoid duplicate code required in both the reactive and the sync {@link Aggregation}
|
||||
@@ -83,7 +81,7 @@ abstract class AggregationUtils {
|
||||
|
||||
Meta meta = queryMethod.getQueryMetaAttributes();
|
||||
|
||||
if (StringUtils.hasText(meta.getComment())) {
|
||||
if (meta.hasComment()) {
|
||||
builder.comment(meta.getComment());
|
||||
}
|
||||
|
||||
@@ -91,8 +89,8 @@ abstract class AggregationUtils {
|
||||
builder.cursorBatchSize(meta.getCursorBatchSize());
|
||||
}
|
||||
|
||||
if (meta.getMaxTimeMsec() != null && meta.getMaxTimeMsec() > 0) {
|
||||
builder.maxTime(Duration.ofMillis(meta.getMaxTimeMsec()));
|
||||
if (meta.hasMaxTime()) {
|
||||
builder.maxTime(Duration.ofMillis(meta.getRequiredMaxTimeMsec()));
|
||||
}
|
||||
|
||||
if (meta.getAllowDiskUse() != null) {
|
||||
@@ -109,7 +107,7 @@ abstract class AggregationUtils {
|
||||
* @param accessor
|
||||
* @param targetType
|
||||
*/
|
||||
static void appendSortIfPresent(List<AggregationOperation> aggregationPipeline, ConvertingParameterAccessor accessor,
|
||||
static void appendSortIfPresent(AggregationPipeline aggregationPipeline, ConvertingParameterAccessor accessor,
|
||||
Class<?> targetType) {
|
||||
|
||||
if (accessor.getSort().isUnsorted()) {
|
||||
@@ -134,7 +132,7 @@ abstract class AggregationUtils {
|
||||
* @param aggregationPipeline
|
||||
* @param accessor
|
||||
*/
|
||||
static void appendLimitAndOffsetIfPresent(List<AggregationOperation> aggregationPipeline,
|
||||
static void appendLimitAndOffsetIfPresent(AggregationPipeline aggregationPipeline,
|
||||
ConvertingParameterAccessor accessor) {
|
||||
appendLimitAndOffsetIfPresent(aggregationPipeline, accessor, LongUnaryOperator.identity(),
|
||||
IntUnaryOperator.identity());
|
||||
@@ -150,7 +148,7 @@ abstract class AggregationUtils {
|
||||
* @param limitOperator
|
||||
* @since 3.3
|
||||
*/
|
||||
static void appendLimitAndOffsetIfPresent(List<AggregationOperation> aggregationPipeline,
|
||||
static void appendLimitAndOffsetIfPresent(AggregationPipeline aggregationPipeline,
|
||||
ConvertingParameterAccessor accessor, LongUnaryOperator offsetOperator, IntUnaryOperator limitOperator) {
|
||||
|
||||
Pageable pageable = accessor.getPageable();
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -55,6 +56,7 @@ import com.mongodb.client.result.DeleteResult;
|
||||
@FunctionalInterface
|
||||
interface MongoQueryExecution {
|
||||
|
||||
@Nullable
|
||||
Object execute(Query query);
|
||||
|
||||
/**
|
||||
@@ -291,7 +293,6 @@ interface MongoQueryExecution {
|
||||
final class UpdateExecution implements MongoQueryExecution {
|
||||
|
||||
private final ExecutableUpdate<?> updateOps;
|
||||
private final MongoQueryMethod method;
|
||||
private Supplier<UpdateDefinition> updateDefinitionSupplier;
|
||||
private final MongoParameterAccessor accessor;
|
||||
|
||||
@@ -299,7 +300,6 @@ interface MongoQueryExecution {
|
||||
MongoParameterAccessor accessor) {
|
||||
|
||||
this.updateOps = updateOps;
|
||||
this.method = method;
|
||||
this.updateDefinitionSupplier = updateSupplier;
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ interface ReactiveMongoQueryExecution {
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class GeoNearExecution implements ReactiveMongoQueryExecution {
|
||||
final class GeoNearExecution implements ReactiveMongoQueryExecution {
|
||||
|
||||
private final ReactiveMongoOperations operations;
|
||||
private final MongoParameterAccessor accessor;
|
||||
@@ -83,7 +83,7 @@ interface ReactiveMongoQueryExecution {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected Flux<GeoResult<Object>> doExecuteQuery(@Nullable Query query, Class<?> type, String collection) {
|
||||
private Flux<GeoResult<Object>> doExecuteQuery(@Nullable Query query, Class<?> type, String collection) {
|
||||
|
||||
Point nearLocation = accessor.getGeoNearLocation();
|
||||
NearQuery nearQuery = NearQuery.near(nearLocation);
|
||||
@@ -154,7 +154,6 @@ interface ReactiveMongoQueryExecution {
|
||||
final class UpdateExecution implements ReactiveMongoQueryExecution {
|
||||
|
||||
private final ReactiveUpdate<?> updateOps;
|
||||
private final MongoQueryMethod method;
|
||||
private final MongoParameterAccessor accessor;
|
||||
private Mono<UpdateDefinition> update;
|
||||
|
||||
@@ -162,7 +161,6 @@ interface ReactiveMongoQueryExecution {
|
||||
Mono<UpdateDefinition> update) {
|
||||
|
||||
this.updateOps = updateOps;
|
||||
this.method = method;
|
||||
this.accessor = accessor;
|
||||
this.update = update;
|
||||
}
|
||||
|
||||
@@ -26,12 +26,15 @@ import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
|
||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -68,10 +71,6 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#doExecute(org.springframework.data.mongodb.repository.query.ReactiveMongoQueryMethod, org.springframework.data.repository.query.ResultProcessor, org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected Publisher<Object> doExecute(ReactiveMongoQueryMethod method, ResultProcessor processor,
|
||||
ConvertingParameterAccessor accessor, Class<?> typeToRead) {
|
||||
@@ -81,7 +80,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
|
||||
Class<?> sourceType = method.getDomainClass();
|
||||
Class<?> targetType = typeToRead;
|
||||
|
||||
List<AggregationOperation> pipeline = it;
|
||||
AggregationPipeline pipeline = new AggregationPipeline(it);
|
||||
|
||||
AggregationUtils.appendSortIfPresent(pipeline, accessor, typeToRead);
|
||||
AggregationUtils.appendLimitAndOffsetIfPresent(pipeline, accessor);
|
||||
@@ -93,10 +92,13 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
|
||||
targetType = Document.class;
|
||||
}
|
||||
|
||||
AggregationOptions options = computeOptions(method, accessor);
|
||||
TypedAggregation<?> aggregation = new TypedAggregation<>(sourceType, pipeline, options);
|
||||
AggregationOptions options = computeOptions(method, accessor, pipeline);
|
||||
TypedAggregation<?> aggregation = new TypedAggregation<>(sourceType, pipeline.getOperations(), options);
|
||||
|
||||
Flux<?> flux = reactiveMongoOperations.aggregate(aggregation, targetType);
|
||||
if (ReflectionUtils.isVoid(typeToRead)) {
|
||||
return flux.then();
|
||||
}
|
||||
|
||||
if (isSimpleReturnType && !isRawReturnType) {
|
||||
flux = flux.handle((item, sink) -> {
|
||||
@@ -121,7 +123,8 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
|
||||
return parseAggregationPipeline(getQueryMethod().getAnnotatedAggregation(), accessor);
|
||||
}
|
||||
|
||||
private AggregationOptions computeOptions(MongoQueryMethod method, ConvertingParameterAccessor accessor) {
|
||||
private AggregationOptions computeOptions(MongoQueryMethod method, ConvertingParameterAccessor accessor,
|
||||
AggregationPipeline pipeline) {
|
||||
|
||||
AggregationOptions.Builder builder = Aggregation.newAggregationOptions();
|
||||
|
||||
@@ -129,49 +132,37 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
|
||||
expressionParser, evaluationContextProvider);
|
||||
AggregationUtils.applyMeta(builder, method);
|
||||
|
||||
TypeInformation<?> returnType = method.getReturnType();
|
||||
if (returnType.getComponentType() != null) {
|
||||
returnType = returnType.getRequiredComponentType();
|
||||
}
|
||||
if (ReflectionUtils.isVoid(returnType.getType()) && pipeline.isOutOrMerge()) {
|
||||
builder.skipOutput();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#createQuery(org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor)
|
||||
*/
|
||||
@Override
|
||||
protected Mono<Query> createQuery(ConvertingParameterAccessor accessor) {
|
||||
throw new UnsupportedOperationException("No query support for aggregation");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isCountQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isCountQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isExistsQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isDeleteQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isDeleteQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isLimiting()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isLimiting() {
|
||||
return false;
|
||||
|
||||
@@ -21,14 +21,13 @@ import java.util.function.LongUnaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
@@ -36,7 +35,9 @@ import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -60,8 +61,8 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param mongoOperations must not be {@literal null}.
|
||||
* @param expressionParser
|
||||
* @param evaluationContextProvider
|
||||
* @param expressionParser must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
*/
|
||||
public StringBasedAggregation(MongoQueryMethod method, MongoOperations mongoOperations,
|
||||
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
@@ -79,18 +80,15 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#doExecute(org.springframework.data.mongodb.repository.query.MongoQueryMethod, org.springframework.data.repository.query.ResultProcessor, org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
protected Object doExecute(MongoQueryMethod method, ResultProcessor resultProcessor,
|
||||
ConvertingParameterAccessor accessor, Class<?> typeToRead) {
|
||||
|
||||
Class<?> sourceType = method.getDomainClass();
|
||||
Class<?> targetType = typeToRead;
|
||||
|
||||
List<AggregationOperation> pipeline = computePipeline(method, accessor);
|
||||
AggregationPipeline pipeline = computePipeline(method, accessor);
|
||||
AggregationUtils.appendSortIfPresent(pipeline, accessor, typeToRead);
|
||||
|
||||
if (method.isSliceQuery()) {
|
||||
@@ -111,8 +109,8 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
targetType = method.getReturnType().getRequiredActualType().getRequiredComponentType().getType();
|
||||
}
|
||||
|
||||
AggregationOptions options = computeOptions(method, accessor);
|
||||
TypedAggregation<?> aggregation = new TypedAggregation<>(sourceType, pipeline, options);
|
||||
AggregationOptions options = computeOptions(method, accessor, pipeline);
|
||||
TypedAggregation<?> aggregation = new TypedAggregation<>(sourceType, pipeline.getOperations(), options);
|
||||
|
||||
if (method.isStreamQuery()) {
|
||||
|
||||
@@ -126,6 +124,9 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
}
|
||||
|
||||
AggregationResults<Object> result = (AggregationResults<Object>) mongoOperations.aggregate(aggregation, targetType);
|
||||
if (ReflectionUtils.isVoid(typeToRead)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isRawAggregationResult) {
|
||||
return result;
|
||||
@@ -167,11 +168,12 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
return MongoSimpleTypes.HOLDER.isSimpleType(targetType);
|
||||
}
|
||||
|
||||
List<AggregationOperation> computePipeline(MongoQueryMethod method, ConvertingParameterAccessor accessor) {
|
||||
return parseAggregationPipeline(method.getAnnotatedAggregation(), accessor);
|
||||
AggregationPipeline computePipeline(MongoQueryMethod method, ConvertingParameterAccessor accessor) {
|
||||
return new AggregationPipeline(parseAggregationPipeline(method.getAnnotatedAggregation(), accessor));
|
||||
}
|
||||
|
||||
private AggregationOptions computeOptions(MongoQueryMethod method, ConvertingParameterAccessor accessor) {
|
||||
private AggregationOptions computeOptions(MongoQueryMethod method, ConvertingParameterAccessor accessor,
|
||||
AggregationPipeline pipeline) {
|
||||
|
||||
AggregationOptions.Builder builder = Aggregation.newAggregationOptions();
|
||||
|
||||
@@ -179,49 +181,33 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
expressionParser, evaluationContextProvider);
|
||||
AggregationUtils.applyMeta(builder, method);
|
||||
|
||||
if (ReflectionUtils.isVoid(method.getReturnType().getType()) && pipeline.isOutOrMerge()) {
|
||||
builder.skipOutput();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#createQuery(org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor)
|
||||
*/
|
||||
@Override
|
||||
protected Query createQuery(ConvertingParameterAccessor accessor) {
|
||||
throw new UnsupportedOperationException("No query support for aggregation");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isCountQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isCountQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isExistsQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isDeleteQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isDeleteQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javascript)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isLimiting()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isLimiting() {
|
||||
return false;
|
||||
|
||||
@@ -1425,7 +1425,8 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
|
||||
// Spring Data Customization START
|
||||
|
||||
if (patternToken.getType() == JsonTokenType.STRING || patternToken.getType() == JsonTokenType.UNQUOTED_STRING) {
|
||||
return bindableValueFor(patternToken).getValue().toString();
|
||||
Object value = bindableValueFor(patternToken).getValue();
|
||||
return value != null ? value.toString() : null;
|
||||
}
|
||||
|
||||
throw new JsonParseException("JSON reader expected a string but found '%s'.", patternToken.getValue());
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2023 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.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aot.generate.ClassNameGenerator;
|
||||
import org.springframework.aot.generate.DefaultGenerationContext;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.InMemoryGeneratedFiles;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LazyLoadingProxyAotProcessor}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class LazyLoadingProxyAotProcessorUnitTests {
|
||||
|
||||
@Test // GH-4351
|
||||
void registersProxyForLazyDbRefCorrectlyWhenTypeIsCollectionInterface() {
|
||||
|
||||
GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(ClassName.get(this.getClass())),
|
||||
new InMemoryGeneratedFiles());
|
||||
|
||||
new LazyLoadingProxyAotProcessor().registerLazyLoadingProxyIfNeeded(A.class, ctx);
|
||||
|
||||
assertThat(ctx.getRuntimeHints())
|
||||
.satisfies(RuntimeHintsPredicates.proxies().forInterfaces(java.util.Collection.class,
|
||||
org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class, java.util.List.class,
|
||||
org.springframework.aop.SpringProxy.class, org.springframework.aop.framework.Advised.class,
|
||||
org.springframework.core.DecoratingProxy.class)::test);
|
||||
}
|
||||
|
||||
static class A {
|
||||
|
||||
String id;
|
||||
|
||||
@DBRef(lazy = true) //
|
||||
List<B> listRef;
|
||||
}
|
||||
|
||||
static class B {
|
||||
String id;
|
||||
}
|
||||
}
|
||||
@@ -2300,6 +2300,26 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
|
||||
verify(collection).countDocuments(any(Document.class), any());
|
||||
}
|
||||
|
||||
@Test // GH-4374
|
||||
void countConsidersMaxTimeMs() {
|
||||
|
||||
template.count(new BasicQuery("{ 'spring' : 'data-mongodb' }").maxTimeMsec(5000), Human.class);
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(Document.class), options.capture());
|
||||
assertThat(options.getValue().getMaxTime(TimeUnit.MILLISECONDS)).isEqualTo(5000);
|
||||
}
|
||||
|
||||
@Test // GH-4374
|
||||
void countPassesOnComment() {
|
||||
|
||||
template.count(new BasicQuery("{ 'spring' : 'data-mongodb' }").comment("rocks!"), Human.class);
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(Document.class), options.capture());
|
||||
assertThat(options.getValue().getComment()).isEqualTo(BsonUtils.simpleToBsonValue("rocks!"));
|
||||
}
|
||||
|
||||
@Test // GH-3984
|
||||
void templatePassesOnTimeSeriesOptionsWhenNoTypeGiven() {
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.springframework.data.mongodb.test.util.Assertions.assertThat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -1456,6 +1457,26 @@ public class ReactiveMongoTemplateUnitTests {
|
||||
verify(collection).countDocuments(any(Document.class), any());
|
||||
}
|
||||
|
||||
@Test // GH-4374
|
||||
void countConsidersMaxTimeMs() {
|
||||
|
||||
template.count(new BasicQuery("{ 'spring' : 'data-mongodb' }").maxTimeMsec(5000), Person.class).subscribe();
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(Document.class), options.capture());
|
||||
assertThat(options.getValue().getMaxTime(TimeUnit.MILLISECONDS)).isEqualTo(5000);
|
||||
}
|
||||
|
||||
@Test // GH-4374
|
||||
void countPassesOnComment() {
|
||||
|
||||
template.count(new BasicQuery("{ 'spring' : 'data-mongodb' }").comment("rocks!"), Person.class).subscribe();
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(Document.class), options.capture());
|
||||
assertThat(options.getValue().getComment()).isEqualTo(BsonUtils.simpleToBsonValue("rocks!"));
|
||||
}
|
||||
|
||||
@Test // GH-2911
|
||||
void insertErrorsOnPublisher() {
|
||||
|
||||
|
||||
@@ -2831,6 +2831,18 @@ class MappingMongoConverterUnitTests {
|
||||
assertThat(converter.read(Cyclic.class, source).cycle.value).isEqualTo("v2");
|
||||
}
|
||||
|
||||
@Test // GH-4371
|
||||
void shouldConvertTypesToStringTargetType() {
|
||||
|
||||
org.bson.Document source = org.bson.Document.parse("""
|
||||
{
|
||||
city : ["Gotham", "Metropolis"]
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(converter.read(Address.class, source).city).isEqualTo("Gotham,Metropolis");
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
|
||||
@@ -274,7 +274,8 @@ public class MongoQueryMethodUnitTests {
|
||||
void queryCreationForUpdateMethodFailsOnInvalidReturnType() throws Exception {
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException.class) //
|
||||
.isThrownBy(() -> queryMethod(InvalidUpdateMethodRepo.class, "findAndIncrementVisitsByFirstname", String.class).verify()) //
|
||||
.isThrownBy(() -> queryMethod(InvalidUpdateMethodRepo.class, "findAndIncrementVisitsByFirstname", String.class)
|
||||
.verify()) //
|
||||
.withMessageContaining("Update") //
|
||||
.withMessageContaining("numeric") //
|
||||
.withMessageContaining("findAndIncrementVisitsByFirstname");
|
||||
@@ -283,7 +284,8 @@ public class MongoQueryMethodUnitTests {
|
||||
@Test // GH-3002
|
||||
void readsCollationFromAtCollationAnnotation() throws Exception {
|
||||
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtCollationByFirstname", String.class);
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtCollationByFirstname",
|
||||
String.class);
|
||||
|
||||
assertThat(method.hasAnnotatedCollation()).isTrue();
|
||||
assertThat(method.getAnnotatedCollation()).isEqualTo("en_US");
|
||||
@@ -292,7 +294,8 @@ public class MongoQueryMethodUnitTests {
|
||||
@Test // GH-3002
|
||||
void readsCollationFromAtQueryAnnotation() throws Exception {
|
||||
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtQueryByFirstname", String.class);
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtQueryByFirstname",
|
||||
String.class);
|
||||
|
||||
assertThat(method.hasAnnotatedCollation()).isTrue();
|
||||
assertThat(method.getAnnotatedCollation()).isEqualTo("en_US");
|
||||
@@ -301,7 +304,8 @@ public class MongoQueryMethodUnitTests {
|
||||
@Test // GH-3002
|
||||
void annotatedCollationClashSelectsAtCollationAnnotationValue() throws Exception {
|
||||
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithMultipleCollationsFromAtQueryAndAtCollationByFirstname", String.class);
|
||||
MongoQueryMethod method = queryMethod(PersonRepository.class,
|
||||
"findWithMultipleCollationsFromAtQueryAndAtCollationByFirstname", String.class);
|
||||
|
||||
assertThat(method.hasAnnotatedCollation()).isTrue();
|
||||
assertThat(method.getAnnotatedCollation()).isEqualTo("de_AT");
|
||||
|
||||
@@ -78,6 +78,7 @@ public class ReactiveStringBasedAggregationUnitTests {
|
||||
|
||||
private static final String RAW_SORT_STRING = "{ '$sort' : { 'lastname' : -1 } }";
|
||||
private static final String RAW_GROUP_BY_LASTNAME_STRING = "{ '$group': { '_id' : '$lastname', 'names' : { '$addToSet' : '$firstname' } } }";
|
||||
private static final String RAW_OUT = "{ '$out' : 'authors' }";
|
||||
private static final String GROUP_BY_LASTNAME_STRING_WITH_PARAMETER_PLACEHOLDER = "{ '$group': { '_id' : '$lastname', names : { '$addToSet' : '$?0' } } }";
|
||||
private static final String GROUP_BY_LASTNAME_STRING_WITH_SPEL_PARAMETER_PLACEHOLDER = "{ '$group': { '_id' : '$lastname', 'names' : { '$addToSet' : '$?#{[0]}' } } }";
|
||||
|
||||
@@ -188,6 +189,22 @@ public class ReactiveStringBasedAggregationUnitTests {
|
||||
return new AggregationInvocation(aggregationCaptor.getValue(), targetTypeCaptor.getValue(), result);
|
||||
}
|
||||
|
||||
@Test // GH-4088
|
||||
void aggregateWithVoidReturnTypeSkipsResultOnOutStage() {
|
||||
|
||||
AggregationInvocation invocation = executeAggregation("outSkipResult");
|
||||
|
||||
assertThat(skipResultsOf(invocation)).isTrue();
|
||||
}
|
||||
|
||||
@Test // GH-4088
|
||||
void aggregateWithOutStageDoesNotSkipResults() {
|
||||
|
||||
AggregationInvocation invocation = executeAggregation("outDoNotSkipResult");
|
||||
|
||||
assertThat(skipResultsOf(invocation)).isFalse();
|
||||
}
|
||||
|
||||
private ReactiveStringBasedAggregation createAggregationForMethod(String name, Class<?>... parameters) {
|
||||
|
||||
Method method = ClassUtils.getMethod(SampleRepository.class, name, parameters);
|
||||
@@ -216,6 +233,11 @@ public class ReactiveStringBasedAggregationUnitTests {
|
||||
: null;
|
||||
}
|
||||
|
||||
private Boolean skipResultsOf(AggregationInvocation invocation) {
|
||||
return invocation.aggregation.getOptions() != null ? invocation.aggregation.getOptions().isSkipResults()
|
||||
: false;
|
||||
}
|
||||
|
||||
private Class<?> targetTypeOf(AggregationInvocation invocation) {
|
||||
return invocation.getTargetType();
|
||||
}
|
||||
@@ -243,6 +265,12 @@ public class ReactiveStringBasedAggregationUnitTests {
|
||||
|
||||
@Aggregation(pipeline = RAW_GROUP_BY_LASTNAME_STRING, collation = "de_AT")
|
||||
Mono<PersonAggregate> aggregateWithCollation(Collation collation);
|
||||
|
||||
@Aggregation(pipeline = { RAW_GROUP_BY_LASTNAME_STRING, RAW_OUT })
|
||||
Flux<Person> outDoNotSkipResult();
|
||||
|
||||
@Aggregation(pipeline = { RAW_GROUP_BY_LASTNAME_STRING, RAW_OUT })
|
||||
Mono<Void> outSkipResult();
|
||||
}
|
||||
|
||||
static class PersonAggregate {
|
||||
|
||||
@@ -91,6 +91,7 @@ public class StringBasedAggregationUnitTests {
|
||||
|
||||
private static final String RAW_SORT_STRING = "{ '$sort' : { 'lastname' : -1 } }";
|
||||
private static final String RAW_GROUP_BY_LASTNAME_STRING = "{ '$group': { '_id' : '$lastname', 'names' : { '$addToSet' : '$firstname' } } }";
|
||||
private static final String RAW_OUT = "{ '$out' : 'authors' }";
|
||||
private static final String GROUP_BY_LASTNAME_STRING_WITH_PARAMETER_PLACEHOLDER = "{ '$group': { '_id' : '$lastname', names : { '$addToSet' : '$?0' } } }";
|
||||
private static final String GROUP_BY_LASTNAME_STRING_WITH_SPEL_PARAMETER_PLACEHOLDER = "{ '$group': { '_id' : '$lastname', 'names' : { '$addToSet' : '$?#{[0]}' } } }";
|
||||
|
||||
@@ -260,6 +261,22 @@ public class StringBasedAggregationUnitTests {
|
||||
.withMessageContaining("Page");
|
||||
}
|
||||
|
||||
@Test // GH-4088
|
||||
void aggregateWithVoidReturnTypeSkipsResultOnOutStage() {
|
||||
|
||||
AggregationInvocation invocation = executeAggregation("outSkipResult");
|
||||
|
||||
assertThat(skipResultsOf(invocation)).isTrue();
|
||||
}
|
||||
|
||||
@Test // GH-4088
|
||||
void aggregateWithOutStageDoesNotSkipResults() {
|
||||
|
||||
AggregationInvocation invocation = executeAggregation("outDoNotSkipResult");
|
||||
|
||||
assertThat(skipResultsOf(invocation)).isFalse();
|
||||
}
|
||||
|
||||
private AggregationInvocation executeAggregation(String name, Object... args) {
|
||||
|
||||
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
|
||||
@@ -302,6 +319,11 @@ public class StringBasedAggregationUnitTests {
|
||||
: null;
|
||||
}
|
||||
|
||||
private Boolean skipResultsOf(AggregationInvocation invocation) {
|
||||
return invocation.aggregation.getOptions() != null ? invocation.aggregation.getOptions().isSkipResults()
|
||||
: false;
|
||||
}
|
||||
|
||||
private Class<?> targetTypeOf(AggregationInvocation invocation) {
|
||||
return invocation.getTargetType();
|
||||
}
|
||||
@@ -350,6 +372,12 @@ public class StringBasedAggregationUnitTests {
|
||||
|
||||
@Aggregation(RAW_GROUP_BY_LASTNAME_STRING)
|
||||
String simpleReturnType();
|
||||
|
||||
@Aggregation(pipeline = { RAW_GROUP_BY_LASTNAME_STRING, RAW_OUT })
|
||||
List<Person> outDoNotSkipResult();
|
||||
|
||||
@Aggregation(pipeline = { RAW_GROUP_BY_LASTNAME_STRING, RAW_OUT })
|
||||
void outSkipResult();
|
||||
}
|
||||
|
||||
private interface UnsupportedRepository extends Repository<Person, Long> {
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
@@ -43,8 +42,6 @@ import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
|
||||
class SimpleReactiveMongoRepositoryUnitTests {
|
||||
|
||||
private SimpleReactiveMongoRepository<Object, String> repository;
|
||||
@Mock Mono mono;
|
||||
@Mock Flux flux;
|
||||
@Mock ReactiveMongoOperations mongoOperations;
|
||||
@Mock MongoEntityInformation<Object, String> entityInformation;
|
||||
|
||||
@@ -56,7 +53,7 @@ class SimpleReactiveMongoRepositoryUnitTests {
|
||||
@Test // DATAMONGO-1854
|
||||
void shouldAddDefaultCollationToCountForExampleIfPresent() {
|
||||
|
||||
when(mongoOperations.count(any(), any(), any())).thenReturn(mono);
|
||||
when(mongoOperations.count(any(), any(), any())).thenReturn(Mono.just(0L));
|
||||
|
||||
Collation collation = Collation.of("en_US");
|
||||
|
||||
@@ -72,7 +69,7 @@ class SimpleReactiveMongoRepositoryUnitTests {
|
||||
@Test // DATAMONGO-1854
|
||||
void shouldAddDefaultCollationToExistsForExampleIfPresent() {
|
||||
|
||||
when(mongoOperations.exists(any(), any(), any())).thenReturn(mono);
|
||||
when(mongoOperations.exists(any(), any(), any())).thenReturn(Mono.just(false));
|
||||
|
||||
Collation collation = Collation.of("en_US");
|
||||
|
||||
@@ -88,7 +85,7 @@ class SimpleReactiveMongoRepositoryUnitTests {
|
||||
@Test // DATAMONGO-1854
|
||||
void shouldAddDefaultCollationToFindForExampleIfPresent() {
|
||||
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(flux);
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(Flux.empty());
|
||||
|
||||
Collation collation = Collation.of("en_US");
|
||||
|
||||
@@ -104,7 +101,7 @@ class SimpleReactiveMongoRepositoryUnitTests {
|
||||
@Test // DATAMONGO-1854
|
||||
void shouldAddDefaultCollationToFindWithSortForExampleIfPresent() {
|
||||
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(flux);
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(Flux.empty());
|
||||
|
||||
Collation collation = Collation.of("en_US");
|
||||
|
||||
@@ -120,7 +117,7 @@ class SimpleReactiveMongoRepositoryUnitTests {
|
||||
@Test // DATAMONGO-1854
|
||||
void shouldAddDefaultCollationToFindOneForExampleIfPresent() {
|
||||
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(flux);
|
||||
when(mongoOperations.find(any(), any(), any())).thenReturn(Flux.empty());
|
||||
|
||||
Collation collation = Collation.of("en_US");
|
||||
|
||||
|
||||
@@ -209,6 +209,13 @@ class ParameterBindingJsonReaderUnitTests {
|
||||
assertThat(target).isEqualTo(Document.parse("{ 'end_date' : { $gte : { $date : " + time + " } } } "));
|
||||
}
|
||||
|
||||
@Test // GH-4282
|
||||
public void shouldReturnNullAsSuch() {
|
||||
|
||||
String json = "{ 'value' : ObjectId(?0) }";
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> parse(json, new Object[] { null }));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2418
|
||||
void shouldNotAccessSpElEvaluationContextWhenNoSpElPresentInBindableTarget() {
|
||||
|
||||
|
||||
@@ -37,6 +37,12 @@ public interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
@Aggregation("{ '$project': { '_id' : '$lastname' } }")
|
||||
List<String> findAllLastnames(); <9>
|
||||
|
||||
@Aggregation(pipeline = {
|
||||
"{ $group : { _id : '$author', books: { $push: '$title' } } }",
|
||||
"{ $out : 'authors' }"
|
||||
})
|
||||
void groupAndOutSkippingOutput(); <10>
|
||||
}
|
||||
----
|
||||
[source,java]
|
||||
@@ -75,6 +81,7 @@ Therefore, the `Sort` properties are mapped against the methods return type `Per
|
||||
To gain more control, you might consider `AggregationResult` as method return type as shown in <7>.
|
||||
<8> Obtain the raw `AggregationResults` mapped to the generic target wrapper type `SumValue` or `org.bson.Document`.
|
||||
<9> Like in <6>, a single value can be directly obtained from multiple result ``Document``s.
|
||||
<10> Skips the output of the `$out` stage when return type is `void`.
|
||||
====
|
||||
|
||||
In some scenarios, aggregations might require additional options, such as a maximum run time, additional log comments, or the permission to temporarily write data to disk.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 4.0.4 (2022.0.4)
|
||||
Spring Data MongoDB 4.0.6 (2022.0.6)
|
||||
Copyright (c) [2010-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -43,6 +43,8 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user