Support ReadConcern and ReadPreference via NearQuery.
Implement ReadConcernAware and ReadPreferenceAware for NearQuery and make sure those get applied when working with the template API. Original Pull Request: #4288
This commit is contained in:
@@ -948,10 +948,13 @@ public class MongoTemplate
|
||||
String distanceField = operations.nearQueryDistanceFieldName(domainType);
|
||||
|
||||
Builder optionsBuilder = AggregationOptions.builder().collation(near.getCollation());
|
||||
Query query = near.getQuery();
|
||||
|
||||
if (query != null && query.hasReadPreference()) {
|
||||
optionsBuilder.readPreference(query.getReadPreference());
|
||||
if (near.hasReadPreference()) {
|
||||
optionsBuilder.readPreference(near.getReadPreference());
|
||||
}
|
||||
|
||||
if(near.hasReadConcern()) {
|
||||
optionsBuilder.readConcern(near.getReadConcern());
|
||||
}
|
||||
|
||||
Aggregation $geoNear = TypedAggregation.newAggregation(domainType, Aggregation.geoNear(near, distanceField))
|
||||
|
||||
@@ -81,6 +81,7 @@ import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions.Builder;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
|
||||
import org.springframework.data.mongodb.core.aggregation.PrefixingDelegatingAggregationOperationContext;
|
||||
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
|
||||
@@ -998,8 +999,19 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
GeoNearResultDocumentCallback<T> callback = new GeoNearResultDocumentCallback<>(distanceField,
|
||||
new ProjectingReadCallback<>(mongoConverter, projection, collection), near.getMetric());
|
||||
|
||||
Builder optionsBuilder = AggregationOptions.builder();
|
||||
if (near.hasReadPreference()) {
|
||||
optionsBuilder.readPreference(near.getReadPreference());
|
||||
}
|
||||
|
||||
if(near.hasReadConcern()) {
|
||||
optionsBuilder.readConcern(near.getReadConcern());
|
||||
}
|
||||
|
||||
optionsBuilder.collation(near.getCollation());
|
||||
|
||||
Aggregation $geoNear = TypedAggregation.newAggregation(entityClass, Aggregation.geoNear(near, distanceField))
|
||||
.withOptions(AggregationOptions.builder().collation(near.getCollation()).build());
|
||||
.withOptions(optionsBuilder.build());
|
||||
|
||||
return aggregate($geoNear, collection, Document.class) //
|
||||
.concatMap(callback::doWith);
|
||||
|
||||
@@ -24,11 +24,16 @@ import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.ReadConcernAware;
|
||||
import org.springframework.data.mongodb.core.ReadPreferenceAware;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.ReadConcern;
|
||||
import com.mongodb.ReadPreference;
|
||||
|
||||
/**
|
||||
* Builder class to build near-queries. <br />
|
||||
* MongoDB {@code $geoNear} operator allows usage of a {@literal GeoJSON Point} or legacy coordinate pair. Though
|
||||
@@ -171,7 +176,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public final class NearQuery {
|
||||
public final class NearQuery implements ReadConcernAware, ReadPreferenceAware {
|
||||
|
||||
private final Point point;
|
||||
private @Nullable Query query;
|
||||
@@ -181,6 +186,8 @@ public final class NearQuery {
|
||||
private boolean spherical;
|
||||
private @Nullable Long limit;
|
||||
private @Nullable Long skip;
|
||||
private @Nullable ReadConcern readConcern;
|
||||
private @Nullable ReadPreference readPreference;
|
||||
|
||||
/**
|
||||
* Creates a new {@link NearQuery}.
|
||||
@@ -536,11 +543,6 @@ public final class NearQuery {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Query getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of elements to skip.
|
||||
*/
|
||||
@@ -560,6 +562,74 @@ public final class NearQuery {
|
||||
return query != null ? query.getCollation().orElse(null) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the query to use the given {@link ReadConcern} unless the underlying {@link #query(Query)}
|
||||
* {@link Query#hasReadConcern() specifies} another one.
|
||||
*
|
||||
* @param readConcern must not be {@literal null}.
|
||||
* @return this.
|
||||
* @since 4.1
|
||||
*/
|
||||
public NearQuery withReadConcern(ReadConcern readConcern) {
|
||||
|
||||
Assert.notNull(readConcern, "ReadConcern must not be null");
|
||||
this.readConcern = readConcern;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the query to use the given {@link ReadPreference} unless the underlying {@link #query(Query)}
|
||||
* {@link Query#hasReadPreference() specifies} another one.
|
||||
*
|
||||
* @param readPreference must not be {@literal null}.
|
||||
* @return this.
|
||||
* @since 4.1
|
||||
*/
|
||||
public NearQuery withReadPreference(ReadPreference readPreference) {
|
||||
|
||||
Assert.notNull(readPreference, "ReadPreference must not be null");
|
||||
this.readPreference = readPreference;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ReadConcern} to use. Will return the underlying {@link #query(Query) queries}
|
||||
* {@link Query#getReadConcern() ReadConcern} if present or the one defined on the {@link NearQuery#readConcern}
|
||||
* itself.
|
||||
*
|
||||
* @return can be {@literal null} if none set.
|
||||
* @since 4.1
|
||||
* @see ReadConcernAware
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public ReadConcern getReadConcern() {
|
||||
|
||||
if (query != null && query.hasReadConcern()) {
|
||||
return query.getReadConcern();
|
||||
}
|
||||
return readConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ReadPreference} to use. Will return the underlying {@link #query(Query) queries}
|
||||
* {@link Query#getReadPreference() ReadPreference} if present or the one defined on the
|
||||
* {@link NearQuery#readPreference} itself.
|
||||
*
|
||||
* @return can be {@literal null} if none set.
|
||||
* @since 4.1
|
||||
* @see ReadPreferenceAware
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public ReadPreference getReadPreference() {
|
||||
|
||||
if (query != null && query.hasReadPreference()) {
|
||||
return query.getReadPreference();
|
||||
}
|
||||
return readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Document} built by the {@link NearQuery}.
|
||||
*
|
||||
|
||||
@@ -583,15 +583,24 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
|
||||
void geoNearShouldHonorReadPreferenceFromQuery() {
|
||||
|
||||
NearQuery query = NearQuery.near(new Point(1, 1));
|
||||
query.withReadPreference(ReadPreference.secondary());
|
||||
|
||||
Query inner = new Query();
|
||||
inner.withReadPreference(ReadPreference.secondary());
|
||||
query.query(inner);
|
||||
template.geoNear(query, Wrapper.class);
|
||||
|
||||
verify(collection).withReadPreference(eq(ReadPreference.secondary()));
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void geoNearShouldHonorReadConcernFromQuery() {
|
||||
|
||||
NearQuery query = NearQuery.near(new Point(1, 1));
|
||||
query.withReadConcern(ReadConcern.SNAPSHOT);
|
||||
|
||||
template.geoNear(query, Wrapper.class);
|
||||
|
||||
verify(collection).withReadConcern(eq(ReadConcern.SNAPSHOT));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1166, DATAMONGO-2264
|
||||
void geoNearShouldIgnoreReadPreferenceWhenNotSet() {
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -384,6 +385,28 @@ public class ReactiveMongoTemplateUnitTests {
|
||||
verify(aggregatePublisher).collation(eq(com.mongodb.client.model.Collation.builder().locale("fr").build()));
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void geoNearShouldHonorReadPreferenceFromQuery() {
|
||||
|
||||
NearQuery query = NearQuery.near(new Point(1, 1));
|
||||
query.withReadPreference(ReadPreference.secondary());
|
||||
|
||||
template.geoNear(query, Wrapper.class).subscribe();
|
||||
|
||||
verify(collection).withReadPreference(eq(ReadPreference.secondary()));
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void geoNearShouldHonorReadConcernFromQuery() {
|
||||
|
||||
NearQuery query = NearQuery.near(new Point(1, 1));
|
||||
query.withReadConcern(ReadConcern.SNAPSHOT);
|
||||
|
||||
template.geoNear(query, Wrapper.class).subscribe();
|
||||
|
||||
verify(collection).withReadConcern(eq(ReadConcern.SNAPSHOT));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1719
|
||||
void appliesFieldsWhenInterfaceProjectionIsClosedAndQueryDoesNotDefineFields() {
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.mongodb.ReadConcern;
|
||||
import com.mongodb.ReadPreference;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link NearQuery}.
|
||||
@@ -229,4 +233,58 @@ public class NearQueryUnitTests {
|
||||
|
||||
assertThat(query.toDocument()).containsEntry("maxDistance", 1000D).containsEntry("distanceMultiplier", 0.00062137D);
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void fetchesReadPreferenceFromUnderlyingQueryObject() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0))
|
||||
.query(new Query().withReadPreference(ReadPreference.nearest()));
|
||||
|
||||
assertThat(nearQuery.getReadPreference()).isEqualTo(ReadPreference.nearest());
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void fetchesReadConcernFromUnderlyingQueryObject() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0)).query(new Query().withReadConcern(ReadConcern.SNAPSHOT));
|
||||
|
||||
assertThat(nearQuery.getReadConcern()).isEqualTo(ReadConcern.SNAPSHOT);
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void usesReadPreferenceFromNearQueryIfUnderlyingQueryDoesNotDefineAny() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0)).withReadPreference(ReadPreference.nearest())
|
||||
.query(new Query());
|
||||
|
||||
assertThat(((Query) ReflectionTestUtils.getField(nearQuery, "query")).getReadPreference()).isNull();
|
||||
assertThat(nearQuery.getReadPreference()).isEqualTo(ReadPreference.nearest());
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void usesReadConcernFromNearQueryIfUnderlyingQueryDoesNotDefineAny() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0)).withReadConcern(ReadConcern.SNAPSHOT).query(new Query());
|
||||
|
||||
assertThat(((Query) ReflectionTestUtils.getField(nearQuery, "query")).getReadConcern()).isNull();
|
||||
assertThat(nearQuery.getReadConcern()).isEqualTo(ReadConcern.SNAPSHOT);
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void readPreferenceFromUnderlyingQueryOverridesNearQueryOne() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0)).withReadPreference(ReadPreference.nearest())
|
||||
.query(new Query().withReadPreference(ReadPreference.primary()));
|
||||
|
||||
assertThat(nearQuery.getReadPreference()).isEqualTo(ReadPreference.primary());
|
||||
}
|
||||
|
||||
@Test // GH-4277
|
||||
void readConcernFromUnderlyingQueryOverridesNearQueryOne() {
|
||||
|
||||
NearQuery nearQuery = NearQuery.near(new Point(0, 0)).withReadConcern(ReadConcern.SNAPSHOT)
|
||||
.query(new Query().withReadConcern(ReadConcern.MAJORITY));
|
||||
|
||||
assertThat(nearQuery.getReadConcern()).isEqualTo(ReadConcern.MAJORITY);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user