10 changed files with 1119 additions and 10 deletions
@ -0,0 +1,199 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.ExecutableFind; |
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link ExecutableMapReduceOperation} allows creation and execution of MongoDB mapReduce operations in a fluent API |
||||||
|
* style. The starting {@literal domainType} is used for mapping an optional {@link Query} provided via {@code matching} |
||||||
|
* into the MongoDB specific representation. By default, the originating {@literal domainType} is also used for mapping |
||||||
|
* back the results from the {@link org.bson.Document}. However, it is possible to define an different |
||||||
|
* {@literal returnType} via {@code as} to mapping the result.<br /> |
||||||
|
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there |
||||||
|
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the |
||||||
|
* collection name for the execution. |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* <code> |
||||||
|
* mapReduce(Human.class) |
||||||
|
* .map("function() { emit(this.id, this.firstname) }") |
||||||
|
* .reduce("function(id, name) { return sum(id, name); }") |
||||||
|
* .inCollection("star-wars") |
||||||
|
* .as(Jedi.class) |
||||||
|
* .matching(query(where("lastname").is("skywalker"))) |
||||||
|
* .all(); |
||||||
|
* </code> |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
public interface ExecutableMapReduceOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Start creating a mapReduce operation for the given {@literal domainType}. |
||||||
|
* |
||||||
|
* @param domainType must not be {@literal null}. |
||||||
|
* @return new instance of {@link ExecutableFind}. |
||||||
|
* @throws IllegalArgumentException if domainType is {@literal null}. |
||||||
|
*/ |
||||||
|
<T> MapReduceWithMapFunction<T> mapReduce(Class<T> domainType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Trigger mapReduce execution by calling one of the terminating methods. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface TerminatingMapReduce<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the mapReduce results. |
||||||
|
* |
||||||
|
* @return never {@literal null}. |
||||||
|
*/ |
||||||
|
List<T> all(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Provide the Javascript {@code function()} used to map matching documents. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithMapFunction<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the Javascript map {@code function()}. |
||||||
|
* |
||||||
|
* @param mapFunction must not be {@literal null} nor empty. |
||||||
|
* @return new instance of {@link MapReduceWithReduceFunction}. |
||||||
|
* @throws IllegalArgumentException if {@literal mapFunction} is {@literal null} or empty. |
||||||
|
*/ |
||||||
|
MapReduceWithReduceFunction<T> map(String mapFunction); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Provide the Javascript {@code function()} used to reduce matching documents. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithReduceFunction<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the Javascript map {@code function()}. |
||||||
|
* |
||||||
|
* @param reduceFunction must not be {@literal null} nor empty. |
||||||
|
* @return new instance of {@link ExecutableMapReduce}. |
||||||
|
* @throws IllegalArgumentException if {@literal reduceFunction} is {@literal null} or empty. |
||||||
|
*/ |
||||||
|
ExecutableMapReduce<T> reduce(String reduceFunction); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Collection override (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithCollection<T> extends MapReduceWithQuery<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Explicitly set the name of the collection to perform the mapReduce operation on. <br /> |
||||||
|
* Skip this step to use the default collection derived from the domain type. |
||||||
|
* |
||||||
|
* @param collection must not be {@literal null} nor {@literal empty}. |
||||||
|
* @return new instance of {@link MapReduceWithProjection}. |
||||||
|
* @throws IllegalArgumentException if collection is {@literal null}. |
||||||
|
*/ |
||||||
|
MapReduceWithProjection<T> inCollection(String collection); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Input document filter query (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithQuery<T> extends TerminatingMapReduce<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the filter query to be used. |
||||||
|
* |
||||||
|
* @param query must not be {@literal null}. |
||||||
|
* @return new instance of {@link TerminatingMapReduce}. |
||||||
|
* @throws IllegalArgumentException if query is {@literal null}. |
||||||
|
*/ |
||||||
|
TerminatingMapReduce<T> matching(Query query); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Result type override (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithProjection<T> extends MapReduceWithQuery<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the target type fields should be mapped to. <br /> |
||||||
|
* Skip this step if you are anyway only interested in the original domain type. |
||||||
|
* |
||||||
|
* @param resultType must not be {@literal null}. |
||||||
|
* @param <R> result type. |
||||||
|
* @return new instance of {@link TerminatingMapReduce}. |
||||||
|
* @throws IllegalArgumentException if resultType is {@literal null}. |
||||||
|
*/ |
||||||
|
<R> MapReduceWithQuery<R> as(Class<R> resultType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Additional mapReduce options (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithOptions<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set additional options to apply to the mapReduce operation. |
||||||
|
* |
||||||
|
* @param options must not be {@literal null}. |
||||||
|
* @return new instance of {@link ExecutableMapReduce}. |
||||||
|
* @throws IllegalArgumentException if options is {@literal null}. |
||||||
|
*/ |
||||||
|
ExecutableMapReduce<T> with(MapReduceOptions options); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link ExecutableMapReduce} provides methods for constructing mapReduce operations in a fluent way. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface ExecutableMapReduce<T> extends MapReduceWithMapFunction<T>, MapReduceWithReduceFunction<T>, |
||||||
|
MapReduceWithCollection<T>, MapReduceWithProjection<T>, MapReduceWithOptions<T> { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,184 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
import org.springframework.lang.Nullable; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implementation of {@link ExecutableMapReduceOperation}. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperation { |
||||||
|
|
||||||
|
private static final Query ALL_QUERY = new Query(); |
||||||
|
|
||||||
|
private final MongoTemplate template; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create new {@link ExecutableMapReduceOperationSupport}. |
||||||
|
* |
||||||
|
* @param template must not be {@literal null}. |
||||||
|
* @throws IllegalArgumentException if template is {@literal null}. |
||||||
|
*/ |
||||||
|
ExecutableMapReduceOperationSupport(MongoTemplate template) { |
||||||
|
|
||||||
|
Assert.notNull(template, "Template must not be null!"); |
||||||
|
this.template = template; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation#mapReduce(java.lang.Class) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public <T> ExecutableMapReduceSupport<T> mapReduce(Class<T> domainType) { |
||||||
|
|
||||||
|
Assert.notNull(domainType, "DomainType must not be null!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport(template, domainType, domainType, null, ALL_QUERY, null, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
static class ExecutableMapReduceSupport<T> |
||||||
|
implements ExecutableMapReduce<T>, MapReduceWithOptions<T>, MapReduceWithCollection<T>, |
||||||
|
MapReduceWithProjection<T>, MapReduceWithQuery<T>, MapReduceWithReduceFunction<T>, MapReduceWithMapFunction<T> { |
||||||
|
|
||||||
|
private final MongoTemplate template; |
||||||
|
private final Class<?> domainType; |
||||||
|
private final Class<T> returnType; |
||||||
|
private final @Nullable String collection; |
||||||
|
private final Query query; |
||||||
|
private final @Nullable String mapFunction; |
||||||
|
private final @Nullable String reduceFunction; |
||||||
|
private final @Nullable MapReduceOptions options; |
||||||
|
|
||||||
|
ExecutableMapReduceSupport(MongoTemplate template, Class<?> domainType, Class<T> returnType, String collection, |
||||||
|
Query query, @Nullable String mapFunction, @Nullable String reduceFunction, MapReduceOptions options) { |
||||||
|
|
||||||
|
this.template = template; |
||||||
|
this.domainType = domainType; |
||||||
|
this.returnType = returnType; |
||||||
|
this.collection = collection; |
||||||
|
this.query = query; |
||||||
|
this.mapFunction = mapFunction; |
||||||
|
this.reduceFunction = reduceFunction; |
||||||
|
this.options = options; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.TerminatingMapReduce#all() |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public List<T> all() { |
||||||
|
return template.mapReduce(query, domainType, getCollectionName(), mapFunction, reduceFunction, options, |
||||||
|
returnType); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithCollection#inCollection(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public MapReduceWithProjection<T> inCollection(String collection) { |
||||||
|
|
||||||
|
Assert.hasText(collection, "Collection name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithQuery#query(org.springframework.data.mongodb.core.query.Query) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public TerminatingMapReduce<T> matching(Query query) { |
||||||
|
|
||||||
|
Assert.notNull(query, "Query must not be null!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithProjection#as(java.lang.Class) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public <R> MapReduceWithQuery<R> as(Class<R> resultType) { |
||||||
|
|
||||||
|
Assert.notNull(resultType, "ResultType must not be null!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, resultType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithOptions#with(org.springframework.data.mongodb.core.mapreduce.MapReduceOptions) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ExecutableMapReduce<T> with(MapReduceOptions options) { |
||||||
|
|
||||||
|
Assert.notNull(options, "Options must not be null! Please consider empty MapReduceOptions#options() instead."); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithMapFunction#map(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public MapReduceWithReduceFunction<T> map(String mapFunction) { |
||||||
|
|
||||||
|
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.MapReduceWithReduceFunction#reduce(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ExecutableMapReduce<T> reduce(String reduceFunction) { |
||||||
|
|
||||||
|
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
private String getCollectionName() { |
||||||
|
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,199 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.ExecutableFind; |
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link ReactiveMapReduceOperation} allows creation and execution of MongoDB mapReduce operations in a fluent API |
||||||
|
* style. The starting {@literal domainType} is used for mapping an optional {@link Query} provided via {@code matching} |
||||||
|
* into the MongoDB specific representation. By default, the originating {@literal domainType} is also used for mapping |
||||||
|
* back the results from the {@link org.bson.Document}. However, it is possible to define an different |
||||||
|
* {@literal returnType} via {@code as} to mapping the result.<br /> |
||||||
|
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there |
||||||
|
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the |
||||||
|
* collection name for the execution. |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* <code> |
||||||
|
* mapReduce(Human.class) |
||||||
|
* .map("function() { emit(this.id, this.firstname) }") |
||||||
|
* .reduce("function(id, name) { return sum(id, name); }") |
||||||
|
* .inCollection("star-wars") |
||||||
|
* .as(Jedi.class) |
||||||
|
* .matching(query(where("lastname").is("skywalker"))) |
||||||
|
* .all(); |
||||||
|
* </code> |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
public interface ReactiveMapReduceOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Start creating a mapReduce operation for the given {@literal domainType}. |
||||||
|
* |
||||||
|
* @param domainType must not be {@literal null}. |
||||||
|
* @return new instance of {@link ExecutableFind}. |
||||||
|
* @throws IllegalArgumentException if domainType is {@literal null}. |
||||||
|
*/ |
||||||
|
<T> MapReduceWithMapFunction<T> mapReduce(Class<T> domainType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Trigger mapReduce execution by calling one of the terminating methods. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface TerminatingMapReduce<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the {@link Flux} emitting mapReduce results. |
||||||
|
* |
||||||
|
* @return a {@link Flux} emitting the already mapped operation results. |
||||||
|
*/ |
||||||
|
Flux<T> all(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Provide the Javascript {@code function()} used to map matching documents. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithMapFunction<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the Javascript map {@code function()}. |
||||||
|
* |
||||||
|
* @param mapFunction must not be {@literal null} nor empty. |
||||||
|
* @return new instance of {@link MapReduceWithReduceFunction}. |
||||||
|
* @throws IllegalArgumentException if {@literal mapFunction} is {@literal null} or empty. |
||||||
|
*/ |
||||||
|
MapReduceWithReduceFunction<T> map(String mapFunction); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Provide the Javascript {@code function()} used to reduce matching documents. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithReduceFunction<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the Javascript map {@code function()}. |
||||||
|
* |
||||||
|
* @param reduceFunction must not be {@literal null} nor empty. |
||||||
|
* @return new instance of {@link ReactiveMapReduce}. |
||||||
|
* @throws IllegalArgumentException if {@literal reduceFunction} is {@literal null} or empty. |
||||||
|
*/ |
||||||
|
ReactiveMapReduce<T> reduce(String reduceFunction); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Collection override (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithCollection<T> extends MapReduceWithQuery<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Explicitly set the name of the collection to perform the mapReduce operation on. <br /> |
||||||
|
* Skip this step to use the default collection derived from the domain type. |
||||||
|
* |
||||||
|
* @param collection must not be {@literal null} nor {@literal empty}. |
||||||
|
* @return new instance of {@link MapReduceWithProjection}. |
||||||
|
* @throws IllegalArgumentException if collection is {@literal null}. |
||||||
|
*/ |
||||||
|
MapReduceWithProjection<T> inCollection(String collection); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Input document filter query (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithQuery<T> extends TerminatingMapReduce<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the filter query to be used. |
||||||
|
* |
||||||
|
* @param query must not be {@literal null}. |
||||||
|
* @return new instance of {@link TerminatingMapReduce}. |
||||||
|
* @throws IllegalArgumentException if query is {@literal null}. |
||||||
|
*/ |
||||||
|
TerminatingMapReduce<T> matching(Query query); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Result type override (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithProjection<T> extends MapReduceWithQuery<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the target type fields should be mapped to. <br /> |
||||||
|
* Skip this step if you are anyway only interested in the original domain type. |
||||||
|
* |
||||||
|
* @param resultType must not be {@literal null}. |
||||||
|
* @param <R> result type. |
||||||
|
* @return new instance of {@link TerminatingMapReduce}. |
||||||
|
* @throws IllegalArgumentException if resultType is {@literal null}. |
||||||
|
*/ |
||||||
|
<R> MapReduceWithQuery<R> as(Class<R> resultType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Additional mapReduce options (Optional). |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface MapReduceWithOptions<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Set additional options to apply to the mapReduce operation. |
||||||
|
* |
||||||
|
* @param options must not be {@literal null}. |
||||||
|
* @return new instance of {@link ReactiveMapReduce}. |
||||||
|
* @throws IllegalArgumentException if options is {@literal null}. |
||||||
|
*/ |
||||||
|
ReactiveMapReduce<T> with(MapReduceOptions options); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link ReactiveMapReduce} provides methods for constructing reactive mapReduce operations in a fluent way. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
interface ReactiveMapReduce<T> extends MapReduceWithMapFunction<T>, MapReduceWithReduceFunction<T>, |
||||||
|
MapReduceWithCollection<T>, MapReduceWithProjection<T>, MapReduceWithOptions<T> { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,186 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
|
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
import org.springframework.lang.Nullable; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implementation of {@link ReactiveMapReduceOperation}. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation { |
||||||
|
|
||||||
|
private static final Query ALL_QUERY = new Query(); |
||||||
|
|
||||||
|
private final ReactiveMongoTemplate template; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create new {@link ReactiveMapReduceOperationSupport}. |
||||||
|
* |
||||||
|
* @param template must not be {@literal null}. |
||||||
|
* @throws IllegalArgumentException if template is {@literal null}. |
||||||
|
*/ |
||||||
|
ReactiveMapReduceOperationSupport(ReactiveMongoTemplate template) { |
||||||
|
|
||||||
|
Assert.notNull(template, "Template must not be null!"); |
||||||
|
this.template = template; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation#mapReduce(java.lang.Class) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public <T> ReactiveMapReduceSupport<T> mapReduce(Class<T> domainType) { |
||||||
|
|
||||||
|
Assert.notNull(domainType, "DomainType must not be null!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport(template, domainType, domainType, null, ALL_QUERY, null, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Christoph Strobl |
||||||
|
* @since 2.1 |
||||||
|
*/ |
||||||
|
static class ReactiveMapReduceSupport<T> |
||||||
|
implements ReactiveMapReduce<T>, MapReduceWithOptions<T>, MapReduceWithCollection<T>, MapReduceWithProjection<T>, |
||||||
|
MapReduceWithQuery<T>, MapReduceWithReduceFunction<T>, MapReduceWithMapFunction<T> { |
||||||
|
|
||||||
|
private final ReactiveMongoTemplate template; |
||||||
|
private final Class<?> domainType; |
||||||
|
private final Class<T> returnType; |
||||||
|
private final @Nullable String collection; |
||||||
|
private final Query query; |
||||||
|
private final @Nullable String mapFunction; |
||||||
|
private final @Nullable String reduceFunction; |
||||||
|
private final @Nullable MapReduceOptions options; |
||||||
|
|
||||||
|
ReactiveMapReduceSupport(ReactiveMongoTemplate template, Class<?> domainType, Class<T> returnType, |
||||||
|
String collection, Query query, @Nullable String mapFunction, @Nullable String reduceFunction, |
||||||
|
MapReduceOptions options) { |
||||||
|
|
||||||
|
this.template = template; |
||||||
|
this.domainType = domainType; |
||||||
|
this.returnType = returnType; |
||||||
|
this.collection = collection; |
||||||
|
this.query = query; |
||||||
|
this.mapFunction = mapFunction; |
||||||
|
this.reduceFunction = reduceFunction; |
||||||
|
this.options = options; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ExecutableMapReduceOperation.TerminatingMapReduce#all() |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Flux<T> all() { |
||||||
|
|
||||||
|
return template.mapReduce(query, domainType, getCollectionName(), returnType, mapFunction, reduceFunction, |
||||||
|
options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithCollection#inCollection(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public MapReduceWithProjection<T> inCollection(String collection) { |
||||||
|
|
||||||
|
Assert.hasText(collection, "Collection name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithQuery#query(org.springframework.data.mongodb.core.query.Query) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public TerminatingMapReduce<T> matching(Query query) { |
||||||
|
|
||||||
|
Assert.notNull(query, "Query must not be null!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithProjection#as(java.lang.Class) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public <R> MapReduceWithQuery<R> as(Class<R> resultType) { |
||||||
|
|
||||||
|
Assert.notNull(resultType, "ResultType must not be null!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, resultType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithOptions#with(org.springframework.data.mongodb.core.mapreduce.MapReduceOptions) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ReactiveMapReduce<T> with(MapReduceOptions options) { |
||||||
|
|
||||||
|
Assert.notNull(options, "Options must not be null! Please consider empty MapReduceOptions#options() instead."); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithMapFunction#map(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public MapReduceWithReduceFunction<T> map(String mapFunction) { |
||||||
|
|
||||||
|
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* (non-Javascript) |
||||||
|
* @see in org.springframework.data.mongodb.core.ReactiveMapReduceOperation.MapReduceWithReduceFunction#reduce(java.lang.String) |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ReactiveMapReduce<T> reduce(String reduceFunction) { |
||||||
|
|
||||||
|
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty!"); |
||||||
|
|
||||||
|
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction, |
||||||
|
reduceFunction, options); |
||||||
|
} |
||||||
|
|
||||||
|
private String getCollectionName() { |
||||||
|
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,141 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any; |
||||||
|
import static org.mockito.ArgumentMatchers.eq; |
||||||
|
import static org.mockito.ArgumentMatchers.isNull; |
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.junit.MockitoJUnitRunner; |
||||||
|
import org.springframework.data.annotation.Id; |
||||||
|
import org.springframework.data.mongodb.core.mapping.Field; |
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.BasicQuery; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link ExecutableMapReduceOperationSupport}. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @currentRead Beyond the Shadows - Brent Weeks |
||||||
|
*/ |
||||||
|
@RunWith(MockitoJUnitRunner.class) |
||||||
|
public class ExecutableMapReduceOperationSupportUnitTests { |
||||||
|
|
||||||
|
private static final String STAR_WARS = "star-wars"; |
||||||
|
private static final String MAP_FUNCTION = "function() { emit(this.id, this.firstname) }"; |
||||||
|
private static final String REDUCE_FUNCTION = "function(id, name) { return sum(id, name); }"; |
||||||
|
|
||||||
|
@Mock MongoTemplate template; |
||||||
|
|
||||||
|
ExecutableMapReduceOperationSupport mapReduceOpsSupport; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
|
||||||
|
when(template.determineCollectionName(eq(Person.class))).thenReturn(STAR_WARS); |
||||||
|
|
||||||
|
mapReduceOpsSupport = new ExecutableMapReduceOperationSupport(template); |
||||||
|
} |
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1929
|
||||||
|
public void throwsExceptionOnNullTemplate() { |
||||||
|
new ExecutableMapReduceOperationSupport(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1929
|
||||||
|
public void throwsExceptionOnNullDomainType() { |
||||||
|
mapReduceOpsSupport.mapReduce(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesExtractedCollectionName() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(MAP_FUNCTION), eq(REDUCE_FUNCTION), |
||||||
|
isNull(), eq(Person.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesExplicitCollectionName() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION) |
||||||
|
.inCollection("the-night-angel").all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq("the-night-angel"), eq(MAP_FUNCTION), |
||||||
|
eq(REDUCE_FUNCTION), isNull(), eq(Person.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesMapReduceOptionsWhenPresent() { |
||||||
|
|
||||||
|
MapReduceOptions options = MapReduceOptions.options(); |
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).with(options).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(MAP_FUNCTION), eq(REDUCE_FUNCTION), |
||||||
|
eq(options), eq(Person.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesQueryWhenPresent() { |
||||||
|
|
||||||
|
Query query = new BasicQuery("{ 'lastname' : 'skywalker' }"); |
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).matching(query).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(eq(query), eq(Person.class), eq(STAR_WARS), eq(MAP_FUNCTION), eq(REDUCE_FUNCTION), |
||||||
|
isNull(), eq(Person.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesProjectionWhenPresent() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).as(Jedi.class).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(MAP_FUNCTION), eq(REDUCE_FUNCTION), |
||||||
|
isNull(), eq(Jedi.class)); |
||||||
|
} |
||||||
|
|
||||||
|
interface Contact {} |
||||||
|
|
||||||
|
@Data |
||||||
|
@org.springframework.data.mongodb.core.mapping.Document(collection = STAR_WARS) |
||||||
|
static class Person implements Contact { |
||||||
|
|
||||||
|
@Id String id; |
||||||
|
String firstname; |
||||||
|
String lastname; |
||||||
|
Object ability; |
||||||
|
Person father; |
||||||
|
} |
||||||
|
|
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
static class Jedi { |
||||||
|
|
||||||
|
@Field("firstname") String name; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,141 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 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 |
||||||
|
* |
||||||
|
* http://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.core; |
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any; |
||||||
|
import static org.mockito.ArgumentMatchers.eq; |
||||||
|
import static org.mockito.ArgumentMatchers.isNull; |
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.junit.MockitoJUnitRunner; |
||||||
|
import org.springframework.data.annotation.Id; |
||||||
|
import org.springframework.data.mongodb.core.mapping.Field; |
||||||
|
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; |
||||||
|
import org.springframework.data.mongodb.core.query.BasicQuery; |
||||||
|
import org.springframework.data.mongodb.core.query.Query; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link ReactiveMapReduceOperationSupport}. |
||||||
|
* |
||||||
|
* @author Christoph Strobl |
||||||
|
* @currentRead Beyond the Shadows - Brent Weeks |
||||||
|
*/ |
||||||
|
@RunWith(MockitoJUnitRunner.class) |
||||||
|
public class ReactiveMapReduceOperationSupportUnitTests { |
||||||
|
|
||||||
|
private static final String STAR_WARS = "star-wars"; |
||||||
|
private static final String MAP_FUNCTION = "function() { emit(this.id, this.firstname) }"; |
||||||
|
private static final String REDUCE_FUNCTION = "function(id, name) { return sum(id, name); }"; |
||||||
|
|
||||||
|
@Mock ReactiveMongoTemplate template; |
||||||
|
|
||||||
|
ReactiveMapReduceOperationSupport mapReduceOpsSupport; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
|
||||||
|
when(template.determineCollectionName(eq(Person.class))).thenReturn(STAR_WARS); |
||||||
|
|
||||||
|
mapReduceOpsSupport = new ReactiveMapReduceOperationSupport(template); |
||||||
|
} |
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1929
|
||||||
|
public void throwsExceptionOnNullTemplate() { |
||||||
|
new ExecutableMapReduceOperationSupport(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1929
|
||||||
|
public void throwsExceptionOnNullDomainType() { |
||||||
|
mapReduceOpsSupport.mapReduce(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesExtractedCollectionName() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(Person.class), eq(MAP_FUNCTION), |
||||||
|
eq(REDUCE_FUNCTION), isNull()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesExplicitCollectionName() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION) |
||||||
|
.inCollection("the-night-angel").all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq("the-night-angel"), eq(Person.class), |
||||||
|
eq(MAP_FUNCTION), eq(REDUCE_FUNCTION), isNull()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesMapReduceOptionsWhenPresent() { |
||||||
|
|
||||||
|
MapReduceOptions options = MapReduceOptions.options(); |
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).with(options).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(Person.class), eq(MAP_FUNCTION), |
||||||
|
eq(REDUCE_FUNCTION), eq(options)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesQueryWhenPresent() { |
||||||
|
|
||||||
|
Query query = new BasicQuery("{ 'lastname' : 'skywalker' }"); |
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).matching(query).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(eq(query), eq(Person.class), eq(STAR_WARS), eq(Person.class), eq(MAP_FUNCTION), |
||||||
|
eq(REDUCE_FUNCTION), isNull()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // DATAMONGO-1929
|
||||||
|
public void usesProjectionWhenPresent() { |
||||||
|
|
||||||
|
mapReduceOpsSupport.mapReduce(Person.class).map(MAP_FUNCTION).reduce(REDUCE_FUNCTION).as(Jedi.class).all(); |
||||||
|
|
||||||
|
verify(template).mapReduce(any(Query.class), eq(Person.class), eq(STAR_WARS), eq(Jedi.class), eq(MAP_FUNCTION), |
||||||
|
eq(REDUCE_FUNCTION), isNull()); |
||||||
|
} |
||||||
|
|
||||||
|
interface Contact {} |
||||||
|
|
||||||
|
@Data |
||||||
|
@org.springframework.data.mongodb.core.mapping.Document(collection = STAR_WARS) |
||||||
|
static class Person implements Contact { |
||||||
|
|
||||||
|
@Id String id; |
||||||
|
String firstname; |
||||||
|
String lastname; |
||||||
|
Object ability; |
||||||
|
Person father; |
||||||
|
} |
||||||
|
|
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
static class Jedi { |
||||||
|
|
||||||
|
@Field("firstname") String name; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue