Browse Source

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
pull/4310/head
Christoph Strobl 3 years ago
parent
commit
d73807df1b
No known key found for this signature in database
GPG Key ID: 8CC1AB53391458C8
  1. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  2. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  3. 82
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/NearQuery.java
  4. 15
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java
  5. 23
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java
  6. 58
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/NearQueryUnitTests.java

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

@ -948,10 +948,13 @@ public class MongoTemplate @@ -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))

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

@ -81,6 +81,7 @@ import org.springframework.data.mongodb.core.QueryOperations.UpdateContext; @@ -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 @@ -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);

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

@ -24,11 +24,16 @@ import org.springframework.data.geo.Distance; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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}.
*

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

@ -583,15 +583,24 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { @@ -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() {

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

@ -59,6 +59,7 @@ import org.springframework.context.ApplicationContext; @@ -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 { @@ -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() {

58
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/NearQueryUnitTests.java

@ -29,6 +29,10 @@ import org.springframework.data.geo.Metrics; @@ -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 { @@ -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);
}
}

Loading…
Cancel
Save