Skip to content

Commit c5f2abe

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-1563 - Add fluent alternative for MongoOperations.
We now provide an alternative API for MongoOperations that allows defining operations in a fluent way. FluentMongoOperations reduces the number of methods and strips down the interface to a minimum while offering a more readable API. // find all with filter query and projecting return type template.query(Person.class) .matching(query(where("firstname").is("luke"))) .as(Jedi.class) .all(); // insert template.insert(Person.class) .inCollection(STAR_WARS) .one(luke); // update with filter & upsert template.update(Person.class) .apply(new Update().set("firstname", "Han")) .matching(query(where("id").is("han-solo"))) .upsert(); // remove all matching template.remove(Jedi.class) .inCollection(STAR_WARS) .matching(query(where("name").is("luke"))) .all(); // aggregate template.aggregateAndReturn(Jedi.class) .inCollection("star-wars) .by(newAggregation(project("name"))) .all(); Original pull request: #466.
1 parent 6cce164 commit c5f2abe

19 files changed

+2381
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright 2017 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+
* http://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;
17+
18+
import org.springframework.data.mongodb.core.aggregation.Aggregation;
19+
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
20+
import org.springframework.data.util.CloseableIterator;
21+
22+
/**
23+
* {@link ExecutableAggregationOperation} allows creation and execution of MongoDB aggregation operations in a fluent
24+
* API style. <br />
25+
* The starting {@literal domainType} is used for mapping the {@link Aggregation} provided via {@code by} into the
26+
* MongoDB specific representation, as well as mapping back the resulting {@link org.bson.Document}. An alternative
27+
* input type for mapping the {@link Aggregation} can be provided by using
28+
* {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation}.
29+
*
30+
* <pre>
31+
* <code>
32+
* aggregateAndReturn(Jedi.class)
33+
* .by(newAggregation(Human.class, project("These are not the droids you are looking for")))
34+
* .get();
35+
* </code>
36+
* </pre>
37+
*
38+
* @author Christoph Strobl
39+
* @since 2.0
40+
*/
41+
public interface ExecutableAggregationOperation {
42+
43+
/**
44+
* Start creating an aggregation operation that returns results mapped to the given domain type. <br />
45+
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to specify a potentially different
46+
* input type for he aggregation.
47+
*
48+
* @param domainType must not be {@literal null}.
49+
* @return new instance of {@link AggregationOperation}.
50+
* @throws IllegalArgumentException if domainType is {@literal null}.
51+
*/
52+
<T> AggregationOperation<T> aggregateAndReturn(Class<T> domainType);
53+
54+
/**
55+
* Collection override (Optional).
56+
*
57+
* @param <T>
58+
* @author Christoph Strobl
59+
* @since 2.0
60+
*/
61+
interface AggregationOperationWithCollection<T> {
62+
63+
/**
64+
* Explicitly set the name of the collection to perform the query on. <br />
65+
* Skip this step to use the default collection derived from the domain type.
66+
*
67+
* @param collection must not be {@literal null} nor {@literal empty}.
68+
* @return new instance of {@link AggregationOperationWithAggregation}.
69+
* @throws IllegalArgumentException if collection is {@literal null}.
70+
*/
71+
AggregationOperationWithAggregation<T> inCollection(String collection);
72+
}
73+
74+
/**
75+
* Trigger execution by calling one of the terminating methods.
76+
*
77+
* @param <T>
78+
*/
79+
interface TerminatingAggregationOperation<T> {
80+
81+
/**
82+
* Apply pipeline operations as specified.
83+
*
84+
* @return never {@literal null}.
85+
*/
86+
AggregationResults<T> get();
87+
88+
/**
89+
* Apply pipeline operations as specified. <br />
90+
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor}
91+
*
92+
* @return a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor} that needs to be closed.
93+
* Never {@literal null}.
94+
*/
95+
CloseableIterator<T> stream();
96+
}
97+
98+
/**
99+
* Define the aggregation with pipeline stages.
100+
*
101+
* @param <T>
102+
* @author Christoph Strobl
103+
* @since 2.0
104+
*/
105+
interface AggregationOperationWithAggregation<T> {
106+
107+
/**
108+
* Set the aggregation to be used.
109+
*
110+
* @param aggregation must not be {@literal null}.
111+
* @return new instance of {@link TerminatingAggregationOperation}.
112+
* @throws IllegalArgumentException if aggregation is {@literal null}.
113+
*/
114+
TerminatingAggregationOperation<T> by(Aggregation aggregation);
115+
}
116+
117+
/**
118+
* @param <T>
119+
* @author Christoph Strobl
120+
* @since 2.0
121+
*/
122+
interface AggregationOperation<T>
123+
extends AggregationOperationWithCollection<T>, AggregationOperationWithAggregation<T> {}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2017 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+
* http://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;
17+
18+
import lombok.RequiredArgsConstructor;
19+
20+
import org.springframework.data.mongodb.core.aggregation.Aggregation;
21+
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
22+
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
23+
import org.springframework.data.util.CloseableIterator;
24+
import org.springframework.util.Assert;
25+
import org.springframework.util.StringUtils;
26+
27+
/**
28+
* Implementation of {@link ExecutableAggregationOperation} operating directly on {@link MongoTemplate}.
29+
*
30+
* @author Christoph Strobl
31+
* @since 2.0
32+
*/
33+
class ExecutableAggregationOperationSupport implements ExecutableAggregationOperation {
34+
35+
private final MongoTemplate template;
36+
37+
/**
38+
* Create new instance of ExecutableAggregationOperationSupport.
39+
*
40+
* @param template must not be {@literal null}.
41+
* @throws IllegalArgumentException if template is {@literal null}.
42+
*/
43+
ExecutableAggregationOperationSupport(MongoTemplate template) {
44+
45+
Assert.notNull(template, "Template must not be null!");
46+
this.template = template;
47+
}
48+
49+
@Override
50+
public <T> AggregationOperation<T> aggregateAndReturn(Class<T> domainType) {
51+
52+
Assert.notNull(domainType, "DomainType must not be null!");
53+
return new AggregationOperationSupport<T>(template, null, domainType, null);
54+
}
55+
56+
/**
57+
* @param <T>
58+
* @author Christoph Strobl
59+
* @since 2.0
60+
*/
61+
@RequiredArgsConstructor
62+
static class AggregationOperationSupport<T>
63+
implements AggregationOperationWithAggregation<T>, AggregationOperation<T>, TerminatingAggregationOperation<T> {
64+
65+
private final MongoTemplate template;
66+
private final Aggregation aggregation;
67+
private final Class<T> domainType;
68+
private final String collection;
69+
70+
@Override
71+
public AggregationOperationWithAggregation<T> inCollection(String collection) {
72+
73+
Assert.hasText(collection, "Collection must not be null nor empty!");
74+
return new AggregationOperationSupport<T>(template, aggregation, domainType, collection);
75+
}
76+
77+
@Override
78+
public TerminatingAggregationOperation<T> by(Aggregation aggregation) {
79+
80+
Assert.notNull(aggregation, "Aggregation must not be null!");
81+
return new AggregationOperationSupport<T>(template, aggregation, domainType, collection);
82+
}
83+
84+
@Override
85+
public AggregationResults<T> get() {
86+
return template.aggregate(aggregation, getCollectionName(aggregation), domainType);
87+
}
88+
89+
@Override
90+
public CloseableIterator<T> stream() {
91+
return template.aggregateStream(aggregation, getCollectionName(aggregation), domainType);
92+
}
93+
94+
private String getCollectionName(Aggregation aggregation) {
95+
96+
if (StringUtils.hasText(collection)) {
97+
return collection;
98+
}
99+
100+
if (aggregation instanceof TypedAggregation) {
101+
102+
if (((TypedAggregation<?>) aggregation).getInputType() != null) {
103+
return template.determineCollectionName(((TypedAggregation<?>) aggregation).getInputType());
104+
}
105+
}
106+
107+
return template.determineCollectionName(domainType);
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)