DATACOUCH-206 - Provides a way to set distinct consistency on repository methods.

* add @WithConsistency annotation
* evaluate it and set consistency in AbstractN1qlBasedQuery
* evaluate it and set consistency in ReactiveAbstractN1qlBasedQuery
* add documentation on @WithConsistency

Original pull request: #198.
This commit is contained in:
Johannes Jasper
2019-06-24 22:49:44 +02:00
committed by Oliver Drotbohm
parent b7f063ce68
commit 55235b2bc2
9 changed files with 287 additions and 14 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import java.util.Date;
import java.util.List;
@@ -24,6 +25,7 @@ import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.View;
import org.springframework.data.couchbase.core.query.ViewIndexed;
import org.springframework.data.couchbase.core.query.WithConsistency;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -49,6 +51,7 @@ public interface PartyRepository extends CouchbaseRepository<Party, String> {
long countAllByDescriptionNotNull();
@WithConsistency(ScanConsistency.NOT_BOUNDED)
@Query("SELECT MAX(attendees) FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
long findMaxAttendees();

View File

@@ -16,6 +16,7 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import java.util.List;
import com.couchbase.client.java.view.ViewQuery;
@@ -24,6 +25,7 @@ import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.View;
import org.springframework.data.couchbase.core.query.ViewIndexed;
import org.springframework.data.couchbase.core.query.WithConsistency;
import reactor.core.publisher.Flux;
/**

View File

@@ -27,9 +27,14 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Stream;
import com.couchbase.client.java.document.json.JsonValue;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.query.Consistency;
import org.springframework.data.couchbase.core.query.WithConsistency;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@@ -38,6 +43,7 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import com.couchbase.client.java.document.json.JsonArray;
@@ -48,6 +54,7 @@ import com.couchbase.client.java.query.ParameterizedN1qlQuery;
import com.couchbase.client.java.query.SimpleN1qlQuery;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import org.springframework.data.repository.query.ReturnedType;
/**
* Unit tests for {@link AbstractN1qlBasedQuery}.
@@ -266,6 +273,32 @@ public class AbstractN1qlBasedQueryTest {
verify(mock).executeSingleProjection(any(N1qlQuery.class));
}
@Test // DATACOUCH-206
public void shouldPickConsistencyFromAnnotation() throws NoSuchMethodException {
Class<SampleRepository> repositoryClass = SampleRepository.class;
CouchbaseQueryMethod defaultQueryMethod = new CouchbaseQueryMethod(repositoryClass.getMethod("findAll"),
metadata,
projectionFactory,
context);
CouchbaseQueryMethod unboundedQueryMethod = new CouchbaseQueryMethod(repositoryClass.getMethod("streamAll"),
metadata,
projectionFactory,
context);
CouchbaseTemplate template = mock(CouchbaseTemplate.class);
when(template.getDefaultConsistency()).thenReturn(Consistency.STRONGLY_CONSISTENT);
ScanConsistency defaultConsistency = new SampleQuery(defaultQueryMethod, template).getScanConsistency();
assertEquals(defaultConsistency, Consistency.STRONGLY_CONSISTENT.n1qlConsistency());
ScanConsistency unboundedConsistency = new SampleQuery(unboundedQueryMethod, template).getScanConsistency();
assertEquals(unboundedConsistency, ScanConsistency.NOT_BOUNDED);
}
static class Sample {
Integer id;
}
@@ -276,6 +309,7 @@ public class AbstractN1qlBasedQueryTest {
Sample findById(Integer id);
@WithConsistency(ScanConsistency.NOT_BOUNDED)
Stream<Sample> streamAll();
Page<Sample> findAllPaged(Pageable pageable);
@@ -288,4 +322,32 @@ public class AbstractN1qlBasedQueryTest {
long longMethod();
}
class SampleQuery extends AbstractN1qlBasedQuery {
protected SampleQuery(CouchbaseQueryMethod queryMethod,
CouchbaseOperations couchbaseOperations) {
super(queryMethod, couchbaseOperations);
}
@Override
protected Statement getCount(ParameterAccessor accessor, Object[] runtimeParameters) {
return null;
}
@Override
protected boolean useGeneratedCountQuery() {
return false;
}
@Override
protected Statement getStatement(ParameterAccessor accessor, Object[] runtimeParameters, ReturnedType returnedType) {
return null;
}
@Override
protected JsonValue getPlaceholderValues(ParameterAccessor accessor) {
return null;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2015-2019 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
*
* https://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.couchbase.repository.query;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import com.couchbase.client.java.document.json.JsonValue;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.consistency.ScanConsistency;
import org.junit.*;
import org.springframework.data.couchbase.core.RxJavaCouchbaseOperations;
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.query.Consistency;
import org.springframework.data.couchbase.core.query.WithConsistency;
import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.ReturnedType;
import reactor.core.publisher.Flux;
/**
* Unit tests for {@link ReactiveAbstractN1qlBasedQuery}.
*
* @author Johannes Jasper
*/
public class ReactiveAbstractN1qlBasedQueryTest {
CouchbaseMappingContext context = new CouchbaseMappingContext();
ProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
RepositoryMetadata metadata = DefaultRepositoryMetadata.getMetadata(SampleRepository.class);
@Test // DATACOUCH-206
public void shouldPickConsistencyFromAnnotation() throws NoSuchMethodException {
Class<SampleRepository> repositoryClass = SampleRepository.class;
CouchbaseQueryMethod defaultQueryMethod = new CouchbaseQueryMethod(repositoryClass.getMethod("findAll"),
metadata,
projectionFactory,
context);
CouchbaseQueryMethod unboundedQueryMethod = new CouchbaseQueryMethod(repositoryClass.getMethod("findByName"),
metadata,
projectionFactory,
context);
RxJavaCouchbaseTemplate template = mock(RxJavaCouchbaseTemplate.class);
when(template.getDefaultConsistency()).thenReturn(Consistency.STRONGLY_CONSISTENT);
ScanConsistency defaultConsistency = new SampleQuery(defaultQueryMethod, template).getScanConsistency();
assertEquals(defaultConsistency, Consistency.STRONGLY_CONSISTENT.n1qlConsistency());
ScanConsistency unboundedConsistency = new SampleQuery(unboundedQueryMethod, template).getScanConsistency();
assertEquals(unboundedConsistency, ScanConsistency.NOT_BOUNDED);
}
static class Sample {
Integer name;
}
interface SampleRepository extends ReactiveCouchbaseRepository<Sample, Integer> {
Flux<Sample> findAll();
@WithConsistency(ScanConsistency.NOT_BOUNDED)
Flux<Sample> findByName();
}
class SampleQuery extends ReactiveAbstractN1qlBasedQuery {
protected SampleQuery(CouchbaseQueryMethod queryMethod,
RxJavaCouchbaseOperations couchbaseOperations) {
super(queryMethod, couchbaseOperations);
}
@Override
protected Statement getStatement(ParameterAccessor accessor,
Object[] runtimeParameters,
ReturnedType returnedType) {
return null;
}
@Override
protected JsonValue getPlaceholderValues(ParameterAccessor accessor) {
return null;
}
}
}