Skip to content

Commit 1413f43

Browse files
christophstroblmp911de
authored andcommitted
Switch Meta.allowDiskUse from boolean to String.
Closes: #4667 Original pull request: #5035
1 parent d6308ec commit 1413f43

File tree

9 files changed

+156
-28
lines changed

9 files changed

+156
-28
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.data.mongodb.core.ReadConcernAware;
2424
import org.springframework.data.mongodb.core.ReadPreferenceAware;
2525
import org.springframework.data.mongodb.core.query.Collation;
26+
import org.springframework.data.mongodb.core.query.DiskUse;
2627
import org.springframework.data.mongodb.util.BsonUtils;
2728
import org.springframework.lang.Contract;
2829
import org.springframework.util.Assert;
@@ -60,7 +61,7 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware
6061
private static final String MAX_TIME = "maxTimeMS";
6162
private static final String HINT = "hint";
6263

63-
private final Optional<Boolean> allowDiskUse;
64+
private final DiskUse diskUse;
6465
private final boolean explain;
6566
private final Optional<Document> cursor;
6667
private final Optional<Collation> collation;
@@ -85,6 +86,15 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
8586
this(allowDiskUse, explain, cursor, null);
8687
}
8788

89+
public AggregationOptions(DiskUse diskUse, boolean explain, @Nullable Document cursor) {
90+
this(diskUse, explain, cursor, null);
91+
}
92+
93+
public AggregationOptions(DiskUse allowDiskUse, boolean explain, @Nullable Document cursor,
94+
@Nullable Collation collation) {
95+
this(allowDiskUse, explain, cursor, collation, null);
96+
}
97+
8898
/**
8999
* Creates a new {@link AggregationOptions}.
90100
*
@@ -97,7 +107,7 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
97107
*/
98108
public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Document cursor,
99109
@Nullable Collation collation) {
100-
this(allowDiskUse, explain, cursor, collation, null, null);
110+
this(DiskUse.of(allowDiskUse), explain, cursor, collation, null, null);
101111
}
102112

103113
/**
@@ -113,13 +123,18 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
113123
*/
114124
public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Document cursor,
115125
@Nullable Collation collation, @Nullable String comment) {
126+
this(allowDiskUse ? DiskUse.ALLOW : DiskUse.DENY, explain, cursor, collation, comment, null);
127+
}
128+
129+
public AggregationOptions(DiskUse allowDiskUse, boolean explain, @Nullable Document cursor,
130+
@Nullable Collation collation, @Nullable String comment) {
116131
this(allowDiskUse, explain, cursor, collation, comment, null);
117132
}
118133

119134
/**
120135
* Creates a new {@link AggregationOptions}.
121136
*
122-
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
137+
* @param diskUse whether to off-load intensive sort-operations to disk.
123138
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
124139
* @param cursor can be {@literal null}, used to pass additional options (such as {@code batchSize}) to the
125140
* aggregation.
@@ -128,10 +143,10 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
128143
* @param hint can be {@literal null}, used to provide an index that would be forcibly used by query optimizer.
129144
* @since 3.1
130145
*/
131-
private AggregationOptions(@Nullable Boolean allowDiskUse, boolean explain, @Nullable Document cursor,
146+
private AggregationOptions(DiskUse diskUse, boolean explain, @Nullable Document cursor,
132147
@Nullable Collation collation, @Nullable String comment, @Nullable Object hint) {
133148

134-
this.allowDiskUse = Optional.ofNullable(allowDiskUse);
149+
this.diskUse = diskUse;
135150
this.explain = explain;
136151
this.cursor = Optional.ofNullable(cursor);
137152
this.collation = Optional.ofNullable(collation);
@@ -172,7 +187,7 @@ public static AggregationOptions fromDocument(Document document) {
172187
String comment = document.getString(COMMENT);
173188
Document hint = document.get(HINT, Document.class);
174189

175-
AggregationOptions options = new AggregationOptions(allowDiskUse, explain, cursor, collation, comment, hint);
190+
AggregationOptions options = new AggregationOptions(DiskUse.of(allowDiskUse) , explain, cursor, collation, comment, hint);
176191
if (document.containsKey(MAX_TIME)) {
177192
options.maxTime = Duration.ofMillis(document.getLong(MAX_TIME));
178193
}
@@ -196,7 +211,7 @@ public static Builder builder() {
196211
* @return {@literal true} if enabled; {@literal false} otherwise (or if not set).
197212
*/
198213
public boolean isAllowDiskUse() {
199-
return allowDiskUse.orElse(false);
214+
return diskUse.equals(DiskUse.ALLOW);
200215
}
201216

202217
/**
@@ -206,7 +221,7 @@ public boolean isAllowDiskUse() {
206221
* @since 4.2.5
207222
*/
208223
public boolean isAllowDiskUseSet() {
209-
return allowDiskUse.isPresent();
224+
return !diskUse.equals(DiskUse.DEFAULT);
210225
}
211226

212227
/**
@@ -427,7 +442,7 @@ static Document createCursor(int cursorBatchSize) {
427442
*/
428443
public static class Builder {
429444

430-
private @Nullable Boolean allowDiskUse;
445+
private @Nullable DiskUse diskUse = DiskUse.DEFAULT;
431446
private boolean explain;
432447
private @Nullable Document cursor;
433448
private @Nullable Collation collation;
@@ -447,8 +462,19 @@ public static class Builder {
447462
*/
448463
@Contract("_ -> this")
449464
public Builder allowDiskUse(boolean allowDiskUse) {
465+
return diskUse(DiskUse.of(allowDiskUse));
466+
}
467+
468+
/**
469+
* Defines whether to off-load intensive sort-operations to disk.
470+
*
471+
* @param diskUse use {@literal true} to allow disk use during the aggregation.
472+
* @return this.
473+
*/
474+
@Contract("_ -> this")
475+
public Builder diskUse(DiskUse diskUse) {
450476

451-
this.allowDiskUse = allowDiskUse;
477+
this.diskUse = diskUse;
452478
return this;
453479
}
454480

@@ -655,7 +681,7 @@ public Builder noMapping() {
655681
@Contract("-> new")
656682
public AggregationOptions build() {
657683

658-
AggregationOptions options = new AggregationOptions(allowDiskUse, explain, cursor, collation, comment, hint);
684+
AggregationOptions options = new AggregationOptions(diskUse, explain, cursor, collation, comment, hint);
659685
if (maxTime != null) {
660686
options.maxTime = maxTime;
661687
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2025-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.query;
17+
18+
import org.jspecify.annotations.Nullable;
19+
import org.springframework.util.StringUtils;
20+
21+
/**
22+
* Disk use indicates if the MongoDB server is allowed to write temporary files to disk during query/aggregation
23+
* execution. MongoDB 6.0 server (and later) default for {@literal allowDiskUseByDefault} is {@literal true} on server
24+
* side.
25+
*
26+
* @author Christoph Strobl
27+
* @since 5.0
28+
*/
29+
public enum DiskUse {
30+
31+
/**
32+
* Go with the server default value and do not specify any override.
33+
*/
34+
DEFAULT,
35+
36+
/**
37+
* Override server default value and explicitly allow disk writes.
38+
*/
39+
ALLOW,
40+
41+
/**
42+
* Override server default value and explicitly deny disk writes.
43+
*/
44+
DENY;
45+
46+
/**
47+
* Obtain the {@link DiskUse} corresponding to the given Boolean flag. {@literal null} is considered {@link #DEFAULT},
48+
* {@literal true} as {@link #ALLOW}, {@literal false} as {@link #DENY}.
49+
*
50+
* @param value can be {@literal null}.
51+
* @return the {@link DiskUse} corresponding to the given value.
52+
*/
53+
public static DiskUse of(@Nullable Boolean value) {
54+
return value != null ? (value ? ALLOW : DENY) : DEFAULT;
55+
}
56+
57+
/**
58+
* Obtain the {@link DiskUse} referred to by the given value. Considers {@literal null} or empty Strings as
59+
* {@link #DEFAULT}, {@literal true} as {@link #ALLOW}, {@literal false} as {@link #DENY} and delegates other values
60+
* to {@link #valueOf(String)}.
61+
*
62+
* @param value can be {@literal null}.
63+
* @return the {@link DiskUse} corresponding to the given value.
64+
* @throws IllegalArgumentException if not matching {@link DiskUse} found.
65+
*/
66+
public static DiskUse of(@Nullable String value) {
67+
68+
if (!StringUtils.hasText(value)) {
69+
return DEFAULT;
70+
}
71+
72+
return switch (value) {
73+
case "true" -> ALLOW;
74+
case "false" -> DENY;
75+
default -> valueOf(value.toUpperCase());
76+
};
77+
}
78+
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private enum MetaKey {
5151
private Map<String, Object> values = Collections.emptyMap();
5252
private Set<CursorOption> flags = Collections.emptySet();
5353
private @Nullable Integer cursorBatchSize;
54-
private @Nullable Boolean allowDiskUse;
54+
private DiskUse diskUse = DiskUse.DEFAULT;
5555

5656
public Meta() {}
5757

@@ -66,7 +66,7 @@ public Meta() {}
6666
this.values = new LinkedHashMap<>(source.values);
6767
this.flags = new LinkedHashSet<>(source.flags);
6868
this.cursorBatchSize = source.cursorBatchSize;
69-
this.allowDiskUse = source.allowDiskUse;
69+
this.diskUse = source.diskUse;
7070
}
7171

7272
/**
@@ -230,7 +230,7 @@ public Set<CursorOption> getFlags() {
230230
*/
231231
@Nullable
232232
public Boolean getAllowDiskUse() {
233-
return allowDiskUse;
233+
return diskUse.equals(DiskUse.DEFAULT) ? null : diskUse.equals(DiskUse.ALLOW);
234234
}
235235

236236
/**
@@ -244,14 +244,18 @@ public Boolean getAllowDiskUse() {
244244
* @since 3.0
245245
*/
246246
public void setAllowDiskUse(@Nullable Boolean allowDiskUse) {
247-
this.allowDiskUse = allowDiskUse;
247+
setDiskUse(DiskUse.of(allowDiskUse));
248+
}
249+
250+
public void setDiskUse(DiskUse diskUse) {
251+
this.diskUse = diskUse;
248252
}
249253

250254
/**
251255
* @return
252256
*/
253257
public boolean hasValues() {
254-
return !this.values.isEmpty() || !this.flags.isEmpty() || this.cursorBatchSize != null || this.allowDiskUse != null;
258+
return !this.values.isEmpty() || !this.flags.isEmpty() || this.cursorBatchSize != null || !this.diskUse.equals(DiskUse.DEFAULT);
255259
}
256260

257261
/**

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,13 @@ public Query comment(String comment) {
582582
*/
583583
@Contract("_ -> this")
584584
public Query allowDiskUse(boolean allowDiskUse) {
585+
return diskUse(DiskUse.of(allowDiskUse));
586+
}
587+
588+
@Contract("_ -> this")
589+
public Query diskUse(DiskUse diskUse) {
585590

586-
meta.setAllowDiskUse(allowDiskUse);
591+
meta.setDiskUse(diskUse);
587592
return this;
588593
}
589594

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,17 @@
6969

7070
/**
7171
* When set to {@literal true}, aggregation stages can write data to disk.
72+
* Valid arguments are:
73+
* <dl>
74+
* <dt>""</dt><dd>DiskUse#DEFAULT</dd>
75+
* <dt>true|allow</dt><dd>DiskUse#ALLOW</dd>
76+
* <dt>false|deny</dt><dd>DiskUse#DENY</dd>
77+
* </dl>
7278
*
7379
* @return {@literal false} by default.
7480
* @since 3.0
75-
* @see Aggregation
81+
* @see org.springframework.data.mongodb.core.query.DiskUse
7682
*/
77-
boolean allowDiskUse() default false;
83+
String allowDiskUse() default "";
7884

7985
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.data.mongodb.core.MongoOperations;
2727
import org.springframework.data.mongodb.core.annotation.Collation;
2828
import org.springframework.data.mongodb.core.query.BasicQuery;
29+
import org.springframework.data.mongodb.core.query.DiskUse;
2930
import org.springframework.data.mongodb.repository.Hint;
3031
import org.springframework.data.mongodb.repository.Meta;
3132
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
@@ -292,6 +293,12 @@ CodeBlock build() {
292293
if (StringUtils.hasText(comment)) {
293294
builder.addStatement("$L.comment($S)", queryVariableName, comment);
294295
}
296+
297+
String allowDiskUse = metaAnnotation.getString("allowDiskUse");
298+
if (StringUtils.hasText(allowDiskUse)) {
299+
DiskUse diskUse = DiskUse.of(allowDiskUse);
300+
builder.addStatement("$L.diskUse($T.$L)", queryVariableName, DiskUse.class, diskUse.name());
301+
}
295302
}
296303

297304
MergedAnnotation<Collation> collationAnnotation = context.getAnnotation(Collation.class);

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.data.mongodb.core.annotation.Collation;
2828
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
2929
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
30+
import org.springframework.data.mongodb.core.query.DiskUse;
3031
import org.springframework.data.mongodb.core.query.UpdateDefinition;
3132
import org.springframework.data.mongodb.repository.Aggregation;
3233
import org.springframework.data.mongodb.repository.Hint;
@@ -272,8 +273,9 @@ public org.springframework.data.mongodb.core.query.Meta getQueryMetaAttributes()
272273
}
273274
}
274275

275-
if (meta.allowDiskUse()) {
276-
metaAttributes.setAllowDiskUse(meta.allowDiskUse());
276+
DiskUse diskUse = DiskUse.of(meta.allowDiskUse());
277+
if (!diskUse.equals(DiskUse.DEFAULT)) {
278+
metaAttributes.setAllowDiskUse(diskUse.equals(DiskUse.ALLOW));
277279
}
278280

279281
return metaAttributes;

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
*/
1616
package org.springframework.data.mongodb.repository.aot;
1717

18-
import static org.mockito.Mockito.*;
19-
import static org.springframework.data.mongodb.test.util.Assertions.*;
18+
import static org.mockito.Mockito.mock;
19+
import static org.springframework.data.mongodb.test.util.Assertions.assertThat;
2020

2121
import example.aot.User;
2222
import example.aot.UserRepository;
@@ -25,7 +25,6 @@
2525
import java.nio.charset.StandardCharsets;
2626

2727
import org.junit.jupiter.api.Test;
28-
2928
import org.springframework.aot.generate.GeneratedFiles;
3029
import org.springframework.aot.test.generate.TestGenerationContext;
3130
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,8 +41,8 @@
4241
* Unit tests for the {@link UserRepository} fragment sources via {@link MongoRepositoryContributor}.
4342
*
4443
* @author Mark Paluch
44+
* @author Christoph Strobl
4545
*/
46-
4746
@SpringJUnitConfig(classes = MongoRepositoryContributorUnitTests.MongoRepositoryContributorConfiguration.class)
4847
class MongoRepositoryContributorUnitTests {
4948

@@ -63,7 +62,7 @@ MongoOperations mongoOperations() {
6362

6463
@Autowired TestGenerationContext generationContext;
6564

66-
@Test // GH-4970
65+
@Test // GH-4970, GH-4667
6766
void shouldConsiderMetaAnnotation() throws IOException {
6867

6968
InputStreamSource aotFragment = generationContext.getGeneratedFiles().getGeneratedFile(GeneratedFiles.Kind.SOURCE,
@@ -74,14 +73,15 @@ void shouldConsiderMetaAnnotation() throws IOException {
7473
assertThat(content).contains("filterQuery.maxTimeMsec(555)");
7574
assertThat(content).contains("filterQuery.cursorBatchSize(1234)");
7675
assertThat(content).contains("filterQuery.comment(\"foo\")");
76+
assertThat(content).contains("filterQuery.diskUse(DiskUse.DENY)");
7777
}
7878

7979
interface MetaUserRepository extends CrudRepository<User, String> {
8080

8181
@Meta
8282
User findAllByLastname(String lastname);
8383

84-
@Meta(cursorBatchSize = 1234, comment = "foo", maxExecutionTimeMs = 555)
84+
@Meta(cursorBatchSize = 1234, comment = "foo", maxExecutionTimeMs = 555, allowDiskUse = "false")
8585
User findWithMetaAllByLastname(String lastname);
8686
}
8787

0 commit comments

Comments
 (0)