diff --git a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java index 82653a52..eeada094 100644 --- a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java +++ b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java @@ -230,7 +230,7 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO public QueryOptions buildOptions(QueryOptions options) { QueryScanConsistency qsc = scanConsistency != null ? scanConsistency : template.getConsistency(); - return query.buildQueryOptions(options, qsc); + return query.buildQueryOptions(options, qsc).readonly(query.isReadonly()); } private TransactionQueryOptions buildTransactionOptions(QueryOptions options) { diff --git a/src/main/java/org/springframework/data/couchbase/core/query/N1QLQuery.java b/src/main/java/org/springframework/data/couchbase/core/query/N1QLQuery.java index c7ac5687..dcdf29c6 100644 --- a/src/main/java/org/springframework/data/couchbase/core/query/N1QLQuery.java +++ b/src/main/java/org/springframework/data/couchbase/core/query/N1QLQuery.java @@ -48,6 +48,11 @@ public class N1QLQuery extends Query { return query; } + @Override + public boolean isReadonly() { + return options.build().readonly(); + } + @Override public String toN1qlSelectString(CouchbaseConverter template, String bucketName, String scopeName, String collectionName, Class domainClass, Class returnClass, boolean isCount, String[] distinctFields, diff --git a/src/main/java/org/springframework/data/couchbase/core/query/Query.java b/src/main/java/org/springframework/data/couchbase/core/query/Query.java index e9d44992..4b8dcbc5 100644 --- a/src/main/java/org/springframework/data/couchbase/core/query/Query.java +++ b/src/main/java/org/springframework/data/couchbase/core/query/Query.java @@ -421,6 +421,10 @@ public class Query { return meta; } + public boolean isReadonly() { + return true; + } + public boolean equals(Object o) { if (!o.getClass().isAssignableFrom(getClass())) { return false; diff --git a/src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java b/src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java index 2f4a7643..264a9a2c 100644 --- a/src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java +++ b/src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java @@ -134,6 +134,14 @@ public class StringQuery extends Query { return sbnqp; } + @Override + public boolean isReadonly() { + if (this.queryMethod.hasN1qlAnnotation()) { + return this.queryMethod.getN1qlAnnotation().readonly(); + } + return false; + } + /** * toN1qlRemoveString - use toN1qlSelectString * diff --git a/src/main/java/org/springframework/data/couchbase/repository/Query.java b/src/main/java/org/springframework/data/couchbase/repository/Query.java index 46d417de..bf9234cf 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/Query.java +++ b/src/main/java/org/springframework/data/couchbase/repository/Query.java @@ -58,4 +58,11 @@ public @interface Query { */ String value() default ""; + /** + * Mark query as readonly + * + * @see com.couchbase.client.java.query.QueryOptions#readonly(boolean) + */ + boolean readonly() default false; + } diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/BasicQuery.java b/src/main/java/org/springframework/data/couchbase/repository/support/BasicQuery.java index d3294d38..419eee03 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/BasicQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/BasicQuery.java @@ -104,6 +104,11 @@ public class BasicQuery extends Query { return super.equals(that); } + @Override + public boolean isReadonly() { + return true; + } + /* * (non-Javadoc) */ diff --git a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateQueryCollectionIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateQueryCollectionIntegrationTests.java index b3f3fbec..0e130c93 100644 --- a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateQueryCollectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateQueryCollectionIntegrationTests.java @@ -700,7 +700,7 @@ class CouchbaseTemplateQueryCollectionIntegrationTests extends CollectionAwareIn @Test public void findByQueryOptions() { // 4 QueryOptions options = QueryOptions.queryOptions().timeout(Duration.ofNanos(10)); - assertThrows(AmbiguousTimeoutException.class, () -> couchbaseTemplate.findByQuery(Airport.class) + assertThrows(UnambiguousTimeoutException.class, () -> couchbaseTemplate.findByQuery(Airport.class) .withConsistency(REQUEST_PLUS).inScope(otherScope).inCollection(otherCollection).withOptions(options).all()); } diff --git a/src/test/java/org/springframework/data/couchbase/core/query/ReactiveCouchbaseTemplateQueryCollectionIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/core/query/ReactiveCouchbaseTemplateQueryCollectionIntegrationTests.java index 990301a2..c2cdc837 100644 --- a/src/test/java/org/springframework/data/couchbase/core/query/ReactiveCouchbaseTemplateQueryCollectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/query/ReactiveCouchbaseTemplateQueryCollectionIntegrationTests.java @@ -693,7 +693,7 @@ class ReactiveCouchbaseTemplateQueryCollectionIntegrationTests extends Collectio @Test public void findByQueryOptions() { // 4 QueryOptions options = QueryOptions.queryOptions().timeout(Duration.ofNanos(10)); - assertThrows(AmbiguousTimeoutException.class, + assertThrows(UnambiguousTimeoutException.class, () -> template.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).inScope(otherScope) .inCollection(otherCollection).withOptions(options).all().collectList().block()); } diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java index 5604be60..f67fbcc8 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java @@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMPLATE; +import com.couchbase.client.core.error.UnambiguousTimeoutException; import jakarta.validation.ConstraintViolationException; import junit.framework.AssertionFailedError; @@ -662,7 +663,7 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr try { Airport saved = airportRepository.save(vie); // Duration of 1 nano-second will cause timeout - assertThrows(AmbiguousTimeoutException.class, + assertThrows(UnambiguousTimeoutException.class, () -> airportRepository.withOptions(queryOptions().timeout(Duration.ofNanos(1))).iata(vie.getIata())); Airport airport3 = airportRepository