Skip to content

Commit 1d60cd7

Browse files
committed
Polishing.
Tweak wording in the docs. Remove unused code. Fix generics. Rename AggregateContext to AggregationOperation to AggregationDefinition to avoid yet another Context object. See #3542. Original pull request: #3545.
1 parent 4700b4d commit 1d60cd7

File tree

7 files changed

+61
-102
lines changed

7 files changed

+61
-102
lines changed

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

+6-51
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ class AggregationUtil {
6767

6868
AggregationOperationContext createAggregationContext(Aggregation aggregation, @Nullable Class<?> inputType) {
6969

70-
if (aggregation.getOptions().getDomainTypeMapping() == DomainTypeMapping.NONE) {
70+
DomainTypeMapping domainTypeMapping = aggregation.getOptions().getDomainTypeMapping();
71+
72+
if (domainTypeMapping == DomainTypeMapping.NONE) {
7173
return Aggregation.DEFAULT_CONTEXT;
7274
}
7375

@@ -77,16 +79,16 @@ AggregationOperationContext createAggregationContext(Aggregation aggregation, @N
7779
return untypedMappingContext.get();
7880
}
7981

80-
if (aggregation.getOptions().getDomainTypeMapping() == DomainTypeMapping.STRICT
82+
if (domainTypeMapping == DomainTypeMapping.STRICT
8183
&& !aggregation.getPipeline().containsUnionWith()) {
8284
return new TypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
8385
}
8486

8587
return new RelaxedTypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
8688
}
8789

88-
inputType = ((TypedAggregation) aggregation).getInputType();
89-
if (aggregation.getOptions().getDomainTypeMapping() == DomainTypeMapping.STRICT
90+
inputType = ((TypedAggregation<?>) aggregation).getInputType();
91+
if (domainTypeMapping == DomainTypeMapping.STRICT
9092
&& !aggregation.getPipeline().containsUnionWith()) {
9193
return new TypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
9294
}
@@ -130,53 +132,6 @@ Document createCommand(String collection, Aggregation aggregation, AggregationOp
130132
return command;
131133
}
132134

133-
/**
134-
* Create a {@code $count} aggregation for {@link Query} and optionally a {@link Class entity class}.
135-
*
136-
* @param query must not be {@literal null}.
137-
* @param entityClass can be {@literal null} if the {@link Query} object is empty.
138-
* @return the {@link Aggregation} pipeline definition to run a {@code $count} aggregation.
139-
*/
140-
Aggregation createCountAggregation(Query query, @Nullable Class<?> entityClass) {
141-
142-
List<AggregationOperation> pipeline = computeCountAggregationPipeline(query, entityClass);
143-
144-
Aggregation aggregation = entityClass != null ? Aggregation.newAggregation(entityClass, pipeline)
145-
: Aggregation.newAggregation(pipeline);
146-
aggregation.withOptions(AggregationOptions.builder().collation(query.getCollation().orElse(null)).build());
147-
148-
return aggregation;
149-
}
150-
151-
private List<AggregationOperation> computeCountAggregationPipeline(Query query, @Nullable Class<?> entityType) {
152-
153-
CountOperation count = Aggregation.count().as("totalEntityCount");
154-
if (query.getQueryObject().isEmpty()) {
155-
return Collections.singletonList(count);
156-
}
157-
158-
Assert.notNull(entityType, "Entity type must not be null!");
159-
160-
Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(),
161-
mappingContext.getPersistentEntity(entityType));
162-
163-
CriteriaDefinition criteria = new CriteriaDefinition() {
164-
165-
@Override
166-
public Document getCriteriaObject() {
167-
return mappedQuery;
168-
}
169-
170-
@Nullable
171-
@Override
172-
public String getKey() {
173-
return null;
174-
}
175-
};
176-
177-
return Arrays.asList(Aggregation.match(criteria), count);
178-
}
179-
180135
private List<Document> mapAggregationPipeline(List<Document> pipeline) {
181136

182137
return pipeline.stream().map(val -> queryMapper.getMappedObject(val, Optional.empty()))

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
5656
import org.springframework.data.mongodb.core.DefaultBulkOperations.BulkOperationContext;
5757
import org.springframework.data.mongodb.core.EntityOperations.AdaptibleEntity;
58-
import org.springframework.data.mongodb.core.QueryOperations.AggregateContext;
58+
import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
5959
import org.springframework.data.mongodb.core.QueryOperations.CountContext;
6060
import org.springframework.data.mongodb.core.QueryOperations.DeleteContext;
6161
import org.springframework.data.mongodb.core.QueryOperations.DistinctQueryContext;
@@ -1989,7 +1989,7 @@ public <O> AggregationResults<O> aggregate(TypedAggregation<?> aggregation, Stri
19891989
public <O> AggregationResults<O> aggregate(Aggregation aggregation, Class<?> inputType, Class<O> outputType) {
19901990

19911991
return aggregate(aggregation, getCollectionName(inputType), outputType,
1992-
queryOperations.createAggregationContext(aggregation, inputType).getAggregationOperationContext());
1992+
queryOperations.createAggregation(aggregation, inputType).getAggregationOperationContext());
19931993
}
19941994

19951995
/* (non-Javadoc)
@@ -2096,11 +2096,12 @@ protected <O> AggregationResults<O> aggregate(Aggregation aggregation, String co
20962096
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
20972097
Assert.notNull(outputType, "Output type must not be null!");
20982098

2099-
return doAggregate(aggregation, collectionName, outputType, queryOperations.createAggregationContext(aggregation, context));
2099+
return doAggregate(aggregation, collectionName, outputType,
2100+
queryOperations.createAggregation(aggregation, context));
21002101
}
21012102

21022103
private <O> AggregationResults<O> doAggregate(Aggregation aggregation, String collectionName, Class<O> outputType,
2103-
AggregateContext context) {
2104+
AggregationDefinition context) {
21042105
return doAggregate(aggregation, collectionName, outputType, context.getAggregationOperationContext());
21052106
}
21062107

@@ -2189,10 +2190,10 @@ protected <O> CloseableIterator<O> aggregateStream(Aggregation aggregation, Stri
21892190
Assert.notNull(outputType, "Output type must not be null!");
21902191
Assert.isTrue(!aggregation.getOptions().isExplain(), "Can't use explain option with streaming!");
21912192

2192-
AggregateContext aggregateContext = queryOperations.createAggregationContext(aggregation, context);
2193+
AggregationDefinition aggregationDefinition = queryOperations.createAggregation(aggregation, context);
21932194

21942195
AggregationOptions options = aggregation.getOptions();
2195-
List<Document> pipeline = aggregateContext.getAggregationPipeline();
2196+
List<Document> pipeline = aggregationDefinition.getAggregationPipeline();
21962197

21972198
if (LOGGER.isDebugEnabled()) {
21982199
LOGGER.debug("Streaming aggregation: {} in collection {}", serializeToJsonSafely(pipeline), collectionName);

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

+27-27
Original file line numberDiff line numberDiff line change
@@ -200,33 +200,33 @@ DeleteContext deleteSingleContext(Query query) {
200200
}
201201

202202
/**
203-
* Create a new {@link AggregateContext} for the given {@link Aggregation}.
203+
* Create a new {@link AggregationDefinition} for the given {@link Aggregation}.
204204
*
205205
* @param aggregation must not be {@literal null}.
206206
* @param inputType fallback mapping type in case of untyped aggregation. Can be {@literal null}.
207-
* @return new instance of {@link AggregateContext}.
207+
* @return new instance of {@link AggregationDefinition}.
208208
* @since 3.2
209209
*/
210-
AggregateContext createAggregationContext(Aggregation aggregation, @Nullable Class<?> inputType) {
211-
return new AggregateContext(aggregation, inputType);
210+
AggregationDefinition createAggregation(Aggregation aggregation, @Nullable Class<?> inputType) {
211+
return new AggregationDefinition(aggregation, inputType);
212212
}
213213

214214
/**
215-
* Create a new {@link AggregateContext} for the given {@link Aggregation}.
215+
* Create a new {@link AggregationDefinition} for the given {@link Aggregation}.
216216
*
217217
* @param aggregation must not be {@literal null}.
218218
* @param aggregationOperationContext the {@link AggregationOperationContext} to use. Can be {@literal null}.
219-
* @return new instance of {@link AggregateContext}.
219+
* @return new instance of {@link AggregationDefinition}.
220220
* @since 3.2
221221
*/
222-
AggregateContext createAggregationContext(Aggregation aggregation,
222+
AggregationDefinition createAggregation(Aggregation aggregation,
223223
@Nullable AggregationOperationContext aggregationOperationContext) {
224-
return new AggregateContext(aggregation, aggregationOperationContext);
224+
return new AggregationDefinition(aggregation, aggregationOperationContext);
225225
}
226226

227227
/**
228228
* {@link QueryContext} encapsulates common tasks required to convert a {@link Query} into its MongoDB document
229-
* representation, mapping fieldnames, as well as determinging and applying {@link Collation collations}.
229+
* representation, mapping field names, as well as determining and applying {@link Collation collations}.
230230
*
231231
* @author Christoph Strobl
232232
*/
@@ -235,7 +235,7 @@ class QueryContext {
235235
private final Query query;
236236

237237
/**
238-
* Create new a {@link QueryContext} instance from the given {@literal query} (can be eihter a {@link Query} or a
238+
* Create new a {@link QueryContext} instance from the given {@literal query} (can be either a {@link Query} or a
239239
* plain {@link Document}.
240240
*
241241
* @param query can be {@literal null}.
@@ -305,7 +305,7 @@ Document getMappedFields(@Nullable MongoPersistentEntity<?> entity, Class<?> tar
305305
mappingContext.getRequiredPersistentEntity(targetType));
306306
}
307307

308-
if (entity != null && entity.hasTextScoreProperty() && !query.getQueryObject().containsKey("$text")) {
308+
if (entity.hasTextScoreProperty() && !query.getQueryObject().containsKey("$text")) {
309309
mappedFields.remove(entity.getTextScoreProperty().getFieldName());
310310
}
311311

@@ -793,19 +793,19 @@ boolean isMulti() {
793793
}
794794

795795
/**
796-
* A context class that encapsulates common tasks required when running {@literal aggregations}.
796+
* A value object that encapsulates common tasks required when running {@literal aggregations}.
797797
*
798798
* @since 3.2
799799
*/
800-
class AggregateContext {
800+
class AggregationDefinition {
801801

802-
private Aggregation aggregation;
803-
private Lazy<AggregationOperationContext> aggregationOperationContext;
804-
private Lazy<List<Document>> pipeline;
805-
private @Nullable Class<?> inputType;
802+
private final Aggregation aggregation;
803+
private final Lazy<AggregationOperationContext> aggregationOperationContext;
804+
private final Lazy<List<Document>> pipeline;
805+
private final @Nullable Class<?> inputType;
806806

807807
/**
808-
* Creates new instance of {@link AggregateContext} extracting the input type from either the
808+
* Creates new instance of {@link AggregationDefinition} extracting the input type from either the
809809
* {@link org.springframework.data.mongodb.core.aggregation.Aggregation} in case of a {@link TypedAggregation} or
810810
* the given {@literal aggregationOperationContext} if present. <br />
811811
* Creates a new {@link AggregationOperationContext} if none given, based on the {@link Aggregation} input type and
@@ -815,21 +815,25 @@ class AggregateContext {
815815
* @param aggregation the source aggregation.
816816
* @param aggregationOperationContext can be {@literal null}.
817817
*/
818-
AggregateContext(Aggregation aggregation, @Nullable AggregationOperationContext aggregationOperationContext) {
818+
AggregationDefinition(Aggregation aggregation, @Nullable AggregationOperationContext aggregationOperationContext) {
819819

820820
this.aggregation = aggregation;
821+
821822
if (aggregation instanceof TypedAggregation) {
822-
this.inputType = ((TypedAggregation) aggregation).getInputType();
823+
this.inputType = ((TypedAggregation<?>) aggregation).getInputType();
823824
} else if (aggregationOperationContext instanceof TypeBasedAggregationOperationContext) {
824825
this.inputType = ((TypeBasedAggregationOperationContext) aggregationOperationContext).getType();
826+
} else {
827+
this.inputType = null;
825828
}
829+
826830
this.aggregationOperationContext = Lazy.of(() -> aggregationOperationContext != null ? aggregationOperationContext
827831
: aggregationUtil.createAggregationContext(aggregation, getInputType()));
828832
this.pipeline = Lazy.of(() -> aggregationUtil.createPipeline(this.aggregation, getAggregationOperationContext()));
829833
}
830834

831835
/**
832-
* Creates new instance of {@link AggregateContext} extracting the input type from either the
836+
* Creates new instance of {@link AggregationDefinition} extracting the input type from either the
833837
* {@link org.springframework.data.mongodb.core.aggregation.Aggregation} in case of a {@link TypedAggregation} or
834838
* the given {@literal aggregationOperationContext} if present. <br />
835839
* Creates a new {@link AggregationOperationContext} based on the {@link Aggregation} input type and the desired
@@ -839,12 +843,12 @@ class AggregateContext {
839843
* @param aggregation the source aggregation.
840844
* @param inputType can be {@literal null}.
841845
*/
842-
AggregateContext(Aggregation aggregation, @Nullable Class<?> inputType) {
846+
AggregationDefinition(Aggregation aggregation, @Nullable Class<?> inputType) {
843847

844848
this.aggregation = aggregation;
845849

846850
if (aggregation instanceof TypedAggregation) {
847-
this.inputType = ((TypedAggregation) aggregation).getInputType();
851+
this.inputType = ((TypedAggregation<?>) aggregation).getInputType();
848852
} else {
849853
this.inputType = inputType;
850854
}
@@ -887,9 +891,5 @@ AggregationOperationContext getAggregationOperationContext() {
887891
Class<?> getInputType() {
888892
return inputType;
889893
}
890-
891-
Document getAggregationCommand(String collectionName) {
892-
return aggregationUtil.createCommand(collectionName, aggregation, getAggregationOperationContext());
893-
}
894894
}
895895
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
1919

20-
import org.springframework.data.mongodb.core.QueryOperations.AggregateContext;
20+
import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
2121
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
2222
import reactor.core.publisher.Flux;
2323
import reactor.core.publisher.Mono;
@@ -986,7 +986,7 @@ protected <O> Flux<O> doAggregate(Aggregation aggregation, String collectionName
986986
AggregationOptions options = aggregation.getOptions();
987987
Assert.isTrue(!options.isExplain(), "Cannot use explain option with streaming!");
988988

989-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, inputType);
989+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, inputType);
990990

991991
if (LOGGER.isDebugEnabled()) {
992992
LOGGER.debug("Streaming aggregation: {} in collection {}", serializeToJsonSafely(ctx.getAggregationPipeline()), collectionName);

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

+7-5
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ public Builder skipOutput() {
487487

488488
/**
489489
* Apply a strict domain type mapping considering {@link org.springframework.data.mongodb.core.mapping.Field}
490-
* annotations throwing errors for non existing, but referenced fields.
490+
* annotations throwing errors for non-existent, but referenced fields.
491491
*
492492
* @return this.
493493
* @since 3.2
@@ -512,7 +512,7 @@ public Builder relaxedMapping() {
512512
}
513513

514514
/**
515-
* Apply no domain type mapping at all taking the pipeline as is.
515+
* Apply no domain type mapping at all taking the pipeline as-is.
516516
*
517517
* @return this.
518518
* @since 3.2
@@ -568,15 +568,17 @@ private enum ResultOptions {
568568
public enum DomainTypeMapping {
569569

570570
/**
571-
* Mapping throws errors for non existing, but referenced fields.
571+
* Mapping throws errors for non-existent, but referenced fields.
572572
*/
573573
STRICT,
574+
574575
/**
575-
* Fields that do not exist in the model are treated as is.
576+
* Fields that do not exist in the model are treated as-is.
576577
*/
577578
RELAXED,
579+
578580
/**
579-
* Do not attempt to map fields against the model and treat the entire pipeline as is.
581+
* Do not attempt to map fields against the model and treat the entire pipeline as-is.
580582
*/
581583
NONE
582584
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/QueryOperationsUnitTests.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.mockito.junit.jupiter.MockitoExtension;
2626
import org.springframework.data.mapping.context.MappingContext;
2727
import org.springframework.data.mongodb.MongoDatabaseFactory;
28-
import org.springframework.data.mongodb.core.QueryOperations.AggregateContext;
28+
import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
2929
import org.springframework.data.mongodb.core.aggregation.Aggregation;
3030
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
3131
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
@@ -35,8 +35,9 @@
3535
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
3636

3737
/**
38+
* Unit tests for {@link QueryOperations}.
39+
*
3840
* @author Christoph Strobl
39-
* @since 2021/01
4041
*/
4142
@ExtendWith(MockitoExtension.class)
4243
class QueryOperationsUnitTests {
@@ -66,7 +67,7 @@ void beforeEach() {
6667
void createAggregationContextUsesRelaxedOneForUntypedAggregationsWhenNoInputTypeProvided() {
6768

6869
Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("name"));
69-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, (Class<?>) null);
70+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, (Class<?>) null);
7071

7172
assertThat(ctx.getAggregationOperationContext()).isInstanceOf(RelaxedTypeBasedAggregationOperationContext.class);
7273
}
@@ -75,7 +76,7 @@ void createAggregationContextUsesRelaxedOneForUntypedAggregationsWhenNoInputType
7576
void createAggregationContextUsesRelaxedOneForTypedAggregationsWhenNoInputTypeProvided() {
7677

7778
Aggregation aggregation = Aggregation.newAggregation(Person.class, Aggregation.project("name"));
78-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, (Class<?>) null);
79+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, (Class<?>) null);
7980

8081
assertThat(ctx.getAggregationOperationContext()).isInstanceOf(RelaxedTypeBasedAggregationOperationContext.class);
8182
}
@@ -84,7 +85,7 @@ void createAggregationContextUsesRelaxedOneForTypedAggregationsWhenNoInputTypePr
8485
void createAggregationContextUsesRelaxedOneForUntypedAggregationsWhenInputTypeProvided() {
8586

8687
Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("name"));
87-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, Person.class);
88+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, Person.class);
8889

8990
assertThat(ctx.getAggregationOperationContext()).isInstanceOf(RelaxedTypeBasedAggregationOperationContext.class);
9091
}
@@ -93,7 +94,7 @@ void createAggregationContextUsesRelaxedOneForUntypedAggregationsWhenInputTypePr
9394
void createAggregationContextUsesDefaultIfNoMappingDesired() {
9495

9596
Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("name")).withOptions(NO_MAPPING);
96-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, Person.class);
97+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, Person.class);
9798

9899
assertThat(ctx.getAggregationOperationContext()).isEqualTo(Aggregation.DEFAULT_CONTEXT);
99100
}
@@ -103,7 +104,7 @@ void createAggregationContextUsesStrictlyTypedContextForTypedAggregationsWhenReq
103104

104105
Aggregation aggregation = Aggregation.newAggregation(Person.class, Aggregation.project("name"))
105106
.withOptions(STRICT_MAPPING);
106-
AggregateContext ctx = queryOperations.createAggregationContext(aggregation, (Class<?>) null);
107+
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, (Class<?>) null);
107108

108109
assertThat(ctx.getAggregationOperationContext()).isInstanceOf(TypeBasedAggregationOperationContext.class);
109110
}

0 commit comments

Comments
 (0)