DATACOUCH-138 - Add Page/Slice/PagingAndSortingRepo
Add support for Page / Slice in N1QL query derived methods. Add PagingAndSortingRepository support through a N1qlCouchbaseRepository implementation. It will only be used as a base if N1QL is actually available on the cluster. Refactor out some steps of entity related query creation in a N1qlUtils class, so that they can be also done eg. in repository base classes. Add tests for both N1qlUtils and the N1qlCouchbaseRepository. Document that PagingAndSortingRepository is supported provided N1QL is available on the Couchbase cluster.
This commit is contained in:
@@ -92,7 +92,7 @@ public class CouchbaseTemplateParserIntegrationTests {
|
||||
|
||||
assertEquals("javaXmlClass", converter.getTypeKey());
|
||||
|
||||
User u = new User("specialSaveUser", "John Locke");
|
||||
User u = new User("specialSaveUser", "John Locke", 46);
|
||||
template.save(u);
|
||||
JsonDocument uJsonDoc = template.getCouchbaseBucket().get("specialSaveUser");
|
||||
template.getCouchbaseBucket().remove("specialSaveUser");
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CouchbaseRepositoryViewListener extends DependencyInjectionTestExec
|
||||
private void populateTestData(final Bucket client, ClusterInfo clusterInfo) {
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
template.save(new User("testuser-" + i, "uname-" + i), PersistTo.MASTER, ReplicateTo.NONE);
|
||||
template.save(new User("testuser-" + i, "uname-" + i, i), PersistTo.MASTER, ReplicateTo.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2013 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* This tests PaginAndSortingRepository features in the Couchbase connector.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(QueryDerivationConversionListener.class)
|
||||
public class N1qlCouchbaseRepositoryTests {
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
private PartyPagingRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
|
||||
repository = factory.getRepository(PartyPagingRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindAllWithSort() {
|
||||
Iterable<Party> allByAttendanceDesc = repository.findAll(new Sort(Sort.Direction.DESC, "attendees"));
|
||||
long previousAttendance = Long.MAX_VALUE;
|
||||
for (Party party : allByAttendanceDesc) {
|
||||
assertTrue(party.getAttendees() <= previousAttendance);
|
||||
previousAttendance = party.getAttendees();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSortOnRenamedFieldIfJsonNameIsProvidedInSort() {
|
||||
Iterable<Party> parties = repository.findAll(new Sort(Sort.Direction.DESC, "desc"));
|
||||
String previousDesc = null;
|
||||
for (Party party : parties) {
|
||||
if (previousDesc != null) {
|
||||
assertTrue(party.getDescription().compareTo(previousDesc) <= 0);
|
||||
}
|
||||
previousDesc = party.getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPageThroughEntities() {
|
||||
Pageable pageable = new PageRequest(0, 8);
|
||||
|
||||
Page<Party> page1 = repository.findAll(pageable);
|
||||
assertEquals(14, page1.getTotalElements()); //13 generated parties + 1 specifically crafted party
|
||||
assertEquals(8, page1.getNumberOfElements());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
|
||||
public class PageAndSliceTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
private UserRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
|
||||
repository = factory.getRepository(UserRepository.class);
|
||||
}
|
||||
@Test
|
||||
public void shouldPageThroughResults() {
|
||||
Page<User> page1 = repository.findByAgeGreaterThan(9, new PageRequest(0, 40)); //there are 90 matching users
|
||||
Page<User> page2 = repository.findByAgeGreaterThan(9, page1.nextPageable());
|
||||
Page<User> page3 = repository.findByAgeGreaterThan(9, page2.nextPageable());
|
||||
|
||||
assertEquals(90, page1.getTotalElements());
|
||||
assertEquals(3, page1.getTotalPages());
|
||||
assertTrue(page1.hasContent());
|
||||
assertTrue(page1.hasNext());
|
||||
assertEquals(40, page1.getNumberOfElements());
|
||||
|
||||
assertTrue(page2.hasContent());
|
||||
assertTrue(page2.hasNext());
|
||||
assertEquals(40, page2.getNumberOfElements());
|
||||
|
||||
assertTrue(page3.hasContent());
|
||||
assertFalse(page3.hasNext());
|
||||
assertEquals(10, page3.getNumberOfElements());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowWhenPageableIsNullInPageQuery() {
|
||||
repository.findByAgeGreaterThan(9, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSliceThroughResults() {
|
||||
int count = 0;
|
||||
List<User> allMatching = new ArrayList<User>(10);
|
||||
Slice<User> slice = repository.findByAgeLessThan(9, new PageRequest(0, 3)); //9 matching users (ages 0-8)
|
||||
allMatching.addAll(slice.getContent());
|
||||
while(slice.hasNext()) {
|
||||
slice = repository.findByAgeLessThan(9, slice.nextPageable());
|
||||
allMatching.addAll(slice.getContent());
|
||||
assertEquals(3, slice.getContent().size());
|
||||
}
|
||||
assertEquals(9, allMatching.size());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowWhenPageableIsNullSliceQuery() {
|
||||
repository.findByAgeLessThan(9, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
public interface PartyPagingRepository extends CouchbasePagingAndSortingRepository<Party, String> {
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class SimpleCouchbaseRepositoryListener extends DependencyInjectionTestEx
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
User u = new User("testuser-" + i, "uname-" + i);
|
||||
User u = new User("testuser-" + i, "uname-" + i, i);
|
||||
template.save(u, PersistTo.MASTER, ReplicateTo.NONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
@@ -64,7 +66,7 @@ public class SimpleCouchbaseRepositoryTests {
|
||||
@Test
|
||||
public void simpleCrud() {
|
||||
String key = "my_unique_user_key";
|
||||
User instance = new User(key, "foobar");
|
||||
User instance = new User(key, "foobar", 22);
|
||||
repository.save(instance);
|
||||
|
||||
User found = repository.findOne(key);
|
||||
@@ -168,5 +170,4 @@ public class SimpleCouchbaseRepositoryTests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,9 +29,12 @@ public class User {
|
||||
|
||||
private final String username;
|
||||
|
||||
public User(String key, String username) {
|
||||
private final int age;
|
||||
|
||||
public User(String key, String username, int age) {
|
||||
this.key = key;
|
||||
this.username = username;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
@@ -42,6 +45,10 @@ public class User {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.key;
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.couchbase.client.java.view.ViewQuery;
|
||||
|
||||
import org.springframework.data.couchbase.core.view.Query;
|
||||
import org.springframework.data.couchbase.core.view.View;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
@@ -43,4 +46,8 @@ public interface UserRepository extends CouchbaseRepository<User, String> {
|
||||
List<User> findByUsernameContains(String contains);
|
||||
|
||||
User findByUsernameNear(String place);//this is to check that there's a N1QL derivation AND it fails
|
||||
|
||||
Page<User> findByAgeGreaterThan(int minAge, Pageable pageable);
|
||||
|
||||
Slice<User> findByAgeLessThan(int maxAge, Pageable pageable);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user