From 10208001f8245129c29f624b40a22b2299f63b2e Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 6 Oct 2016 12:56:03 +0200 Subject: [PATCH] DATAMONGO-1480 - Polishing. Opened up Meta attributes to now allowing usage of more than one cursor option via dedicated enum. new Query().noCursorTimeout(); and interface PersonRepository extends CrudRepository { @Meta(flags = {CursorOptions.NO_TIMEOUT}) Iterable findBy(); } Original Pull Request: #390 --- .../data/mongodb/core/MongoTemplate.java | 21 ++++++- .../data/mongodb/core/query/Meta.java | 61 +++++++++++++++---- .../data/mongodb/core/query/Query.java | 37 ++++++++++- .../data/mongodb/repository/Meta.java | 6 +- .../repository/query/MongoQueryMethod.java | 8 ++- .../query/AbstractMongoQueryUnitTests.java | 2 +- .../query/MongoQueryMethodUnitTests.java | 22 ++++++- 7 files changed, 132 insertions(+), 25 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 9fab32a51..e26cd4d41 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -93,6 +93,7 @@ import org.springframework.data.mongodb.core.mapreduce.GroupByResults; import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions; import org.springframework.data.mongodb.core.mapreduce.MapReduceResults; import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Meta; import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; @@ -2372,8 +2373,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { cursorToUse = cursorToUse.addSpecial(entry.getKey(), entry.getValue()); } - if (query.getMeta().isNoCursorTimeout() != null && query.getMeta().isNoCursorTimeout().booleanValue()) { - cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_NOTIMEOUT); + for (Meta.CursorOption option : query.getMeta().getFlags()) { + + switch (option) { + case EXHAUST: + cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_EXHAUST); + break; + case NO_TIMEOUT: + cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_NOTIMEOUT); + break; + case PARTIAL: + cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_PARTIAL); + break; + case SLAVE_OK: + cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_SLAVEOK); + break; + default: + throw new IllegalArgumentException(String.format("%s is no supported flag.", option)); + } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java index c18481642..0543966d3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java @@ -17,8 +17,10 @@ package org.springframework.data.mongodb.core.query; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.util.Assert; @@ -46,7 +48,7 @@ public class Meta { } private final Map values = new LinkedHashMap(2); - private Boolean noCursorTimeout; + private final Set flags = new LinkedHashSet(); /** * @return {@literal null} if not set. @@ -123,28 +125,31 @@ public class Meta { } /** - * @return {@literal null} if not set. + * Add {@link CursorOption} influencing behavior of the {@link com.mongodb.DBCursor}. + * + * @param option must not be {@literal null}. + * @return * @since 1.10 */ - public Boolean isNoCursorTimeout() { - return this.noCursorTimeout; + public boolean addFlag(CursorOption option) { + + Assert.notNull(option, "CursorOption must not be null!"); + return this.flags.add(option); } /** - * Instructs the server to avoid closing a cursor automatically after a period of inactivity. - * - * @param noCursorTimeout + * @return never {@literal null}. * @since 1.10 */ - public void setNoCursorTimeout(boolean noCursorTimeout) { - this.noCursorTimeout = noCursorTimeout; + public Set getFlags() { + return flags; } /** * @return */ public boolean hasValues() { - return !this.values.isEmpty() || this.noCursorTimeout != null; + return !this.values.isEmpty() || !this.flags.isEmpty(); } /** @@ -189,7 +194,10 @@ public class Meta { */ @Override public int hashCode() { - return ObjectUtils.nullSafeHashCode(this.values); + + int hash = ObjectUtils.nullSafeHashCode(this.values); + hash += ObjectUtils.nullSafeHashCode(this.flags); + return hash; } /* @@ -208,6 +216,35 @@ public class Meta { } Meta other = (Meta) obj; - return ObjectUtils.nullSafeEquals(this.values, other.values); + if (!ObjectUtils.nullSafeEquals(this.values, other.values)) { + return false; + } + return ObjectUtils.nullSafeEquals(this.flags, other.flags); + } + + /** + * {@link CursorOption} represents {@code OP_QUERY} wire protocol flags to change the behavior of queries. + * + * @author Christoph Strobl + * @since 1.10 + */ + public enum CursorOption { + + /** Prevents the server from timing out idle cursors. */ + NO_TIMEOUT, + + /** + * Sets the cursor to return all data returned by the query at once rather than splitting the results into batches. + */ + EXHAUST, + + /** Allows querying of a replica slave. */ + SLAVE_OK, + + /** + * Sets the cursor to return partial data from a query against a sharded cluster in which some shards do not respond + * rather than throwing an error. + */ + PARTIAL } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 02b2ef024..cd2668bae 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -339,12 +339,45 @@ public class Query { /** * @return - * @see Meta#setNoCursorTimeout(boolean) + * @see org.springframework.data.mongodb.core.query.Meta.CursorOption#NO_TIMEOUT * @since 1.10 */ public Query noCursorTimeout() { - meta.setNoCursorTimeout(true); + meta.addFlag(Meta.CursorOption.NO_TIMEOUT); + return this; + } + + /** + * @return + * @see org.springframework.data.mongodb.core.query.Meta.CursorOption#EXHAUST + * @since 1.10 + */ + public Query exhaust() { + + meta.addFlag(Meta.CursorOption.EXHAUST); + return this; + } + + /** + * @return + * @see org.springframework.data.mongodb.core.query.Meta.CursorOption#SLAVE_OK + * @since 1.10 + */ + public Query slaveOk() { + + meta.addFlag(Meta.CursorOption.SLAVE_OK); + return this; + } + + /** + * @return + * @see org.springframework.data.mongodb.core.query.Meta.CursorOption#PARTIAL + * @since 1.10 + */ + public Query partialResults() { + + meta.addFlag(Meta.CursorOption.PARTIAL); return this; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java index c41b50942..c953b7d3c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java @@ -76,11 +76,11 @@ public @interface Meta { boolean snapshot() default false; /** - * Instructs the server to avoid closing a cursor automatically after a period of inactivity. + * Set {@link org.springframework.data.mongodb.core.query.Meta.CursorOption} to be used when executing query. * - * @return + * @return never {@literal null}. * @since 1.10 */ - boolean noCursorTimeout() default false; + org.springframework.data.mongodb.core.query.Meta.CursorOption[] flags() default {}; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java index 1f1c743f2..067928b09 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java @@ -37,6 +37,7 @@ import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -248,8 +249,11 @@ public class MongoQueryMethod extends QueryMethod { metaAttributes.setSnapshot(meta.snapshot()); } - if (meta.noCursorTimeout()) { - metaAttributes.setNoCursorTimeout(meta.noCursorTimeout()); + if (!ObjectUtils.isEmpty(meta.flags())) { + + for (org.springframework.data.mongodb.core.query.Meta.CursorOption option : meta.flags()) { + metaAttributes.addFlag(option); + } } return metaAttributes; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java index 0c6860a46..7406e6334 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java @@ -347,7 +347,7 @@ public class AbstractMongoQueryUnitTests { List findByFirstname(String firstname); - @Meta(comment = "comment", noCursorTimeout = true) + @Meta(comment = "comment", flags = {org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT}) Page findByFirstname(String firstnanme, Pageable pageable); @Meta(comment = "comment") diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java index 6b739144c..bba8388d0 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java @@ -152,7 +152,6 @@ public class MongoQueryMethodUnitTests { assertThat(method.getQueryMetaAttributes().getMaxTimeMsec(), is(100L)); } - /** * @see DATAMONGO-1403 */ @@ -210,7 +209,21 @@ public class MongoQueryMethodUnitTests { MongoQueryMethod method = queryMethod(PersonRepository.class, "metaWithNoCursorTimeout"); assertThat(method.hasQueryMetaAttributes(), is(true)); - assertThat(method.getQueryMetaAttributes().isNoCursorTimeout(), is(true)); + assertThat(method.getQueryMetaAttributes().getFlags(), + containsInAnyOrder(org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT)); + } + + /** + * @see DATAMONGO-1480 + */ + @Test + public void createsMongoQueryMethodWithMultipleFlagsCorrectly() throws Exception { + + MongoQueryMethod method = queryMethod(PersonRepository.class, "metaWithMultipleFlags"); + + assertThat(method.hasQueryMetaAttributes(), is(true)); + assertThat(method.getQueryMetaAttributes().getFlags(), + containsInAnyOrder(org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT, org.springframework.data.mongodb.core.query.Meta.CursorOption.SLAVE_OK)); } /** @@ -262,9 +275,12 @@ public class MongoQueryMethodUnitTests { @Meta(snapshot = true) List metaWithSnapshotUsage(); - @Meta(noCursorTimeout = true) + @Meta(flags = { org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT }) List metaWithNoCursorTimeout(); + @Meta(flags = { org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT, org.springframework.data.mongodb.core.query.Meta.CursorOption.SLAVE_OK }) + List metaWithMultipleFlags(); + /** * @see DATAMONGO-1266 */