DATACOUCH-161 - Allow repositories to use different templates

Added a configuration bean that allows to express what CouchbaseOperations each repository should use, individually or by domain type.

Added documentation for the feature in repository section.
This commit is contained in:
Simon Baslé
2015-10-01 20:18:38 +02:00
parent 46e16d951d
commit 2914f57897
17 changed files with 423 additions and 58 deletions

View File

@@ -33,7 +33,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.test.context.ContextConfiguration;
@@ -53,13 +53,13 @@ public class CouchbaseRepositoryViewTests {
private Bucket client;
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private CustomUserRepository repository;
@Before
public void setup() throws Exception {
repository = new CouchbaseRepositoryFactory(template).getRepository(CustomUserRepository.class);
repository = new CouchbaseRepositoryFactory(operationsMapping).getRepository(CustomUserRepository.class);
}
@Test

View File

@@ -19,14 +19,13 @@ 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.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -48,13 +47,13 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class N1qlCouchbaseRepositoryTests {
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private PartyPagingRepository repository;
@Before
public void setup() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
repository = factory.getRepository(PartyPagingRepository.class);
}

View File

@@ -31,7 +31,7 @@ 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.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -47,7 +47,7 @@ public class N1qlCrudRepositoryTests {
private Bucket client;
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private PartyRepository partyRepository;
private ItemRepository itemRepository;
@@ -57,8 +57,8 @@ public class N1qlCrudRepositoryTests {
@Before
public void setup() throws Exception {
partyRepository = new CouchbaseRepositoryFactory(template).getRepository(PartyRepository.class);
itemRepository = new CouchbaseRepositoryFactory(template).getRepository(ItemRepository.class);
partyRepository = new CouchbaseRepositoryFactory(operationsMapping).getRepository(PartyRepository.class);
itemRepository = new CouchbaseRepositoryFactory(operationsMapping).getRepository(ItemRepository.class);
itemRepository.save(item);
partyRepository.save(party);

View File

@@ -14,7 +14,7 @@ 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.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -33,13 +33,13 @@ public class PageAndSliceTests {
private Bucket client;
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private UserRepository repository;
@Before
public void setup() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
repository = factory.getRepository(UserRepository.class);
}
@Test

View File

@@ -15,7 +15,7 @@ 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.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
@@ -34,13 +34,13 @@ public class QueryDerivationConversionTests {
private Bucket client;
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private PartyRepository repository;
@Before
public void setup() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
repository = factory.getRepository(PartyRepository.class);
}

View File

@@ -32,10 +32,8 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
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.config.RepositoryOperationsMapping;
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;
@@ -53,13 +51,13 @@ public class SimpleCouchbaseRepositoryTests {
private Bucket client;
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
private UserRepository repository;
@Before
public void setup() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
repository = factory.getRepository(UserRepository.class);
}

View File

@@ -30,10 +30,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.UnsupportedCouchbaseFeatureException;
import org.springframework.data.couchbase.repository.User;
import org.springframework.data.couchbase.repository.UserRepository;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
@@ -49,7 +50,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class FeatureDetectionRepositoryTests {
@Autowired
private CouchbaseTemplate template;
private RepositoryOperationsMapping operationsMapping;
@Autowired
private ClusterInfo clusterInfo;
@@ -61,7 +62,7 @@ public class FeatureDetectionRepositoryTests {
@Test
public void testN1qlIncompatibleClusterFailsFastForN1qlBasedRepository() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
try {
factory.getRepository(UserRepository.class);
fail("expected UnsupportedCouchbaseFeatureException");
@@ -72,13 +73,15 @@ public class FeatureDetectionRepositoryTests {
@Test
public void testN1qlIncompatibleClusterDoesntFailForViewBasedRepository() throws Exception {
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(template);
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping);
ViewOnlyUserRepository repository = factory.getRepository(ViewOnlyUserRepository.class);
assertNotNull(repository);
}
@Test
public void testN1qlIncompatibleClusterTemplateFails() {
final CouchbaseOperations template = operationsMapping.getDefault();
N1qlQuery query = N1qlQuery.simple("SELECT * FROM `" + template.getCouchbaseBucket().name() + "`");
try {
template.findByN1QL(query, User.class);

View File

@@ -0,0 +1,160 @@
package org.springframework.data.couchbase.repository.wiring;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.List;
import com.couchbase.client.java.cluster.ClusterInfo;
import com.couchbase.client.java.util.features.CouchbaseFeature;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This test case demonstrates (with a bit of mocking) that the framework will take the
* {@link RepositoryOperationsMapping} into account in its wiring of repositories with
* underlying {@link CouchbaseOperations} beans.
*
* @author Simon Baslé
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class RepositoryTemplateWiringTests {
private static CouchbaseOperations mockOpsA;
private static CouchbaseOperations mockOpsB;
private static CouchbaseOperations mockOpsC;
@BeforeClass
public static void initMocks() {
ClusterInfo info = mock(ClusterInfo.class);
when(info.checkAvailable(any(CouchbaseFeature.class))).thenReturn(true);
mockOpsA = mock(CouchbaseOperations.class);
when(mockOpsA.getCouchbaseClusterInfo()).thenReturn(info);
when(mockOpsA.exists(any(String.class))).thenReturn(true);
mockOpsB = mock(CouchbaseOperations.class);
when(mockOpsB.getCouchbaseClusterInfo()).thenReturn(info);
when(mockOpsB.exists(any(String.class))).thenReturn(false);
mockOpsC = spy(new CouchbaseTemplate(info, null));
Misc cValue = new Misc();
cValue.id = "mock";
cValue.random = true;
doReturn(cValue).when(mockOpsC).findById(any(String.class), any(Class.class));
}
@Autowired
BucketARepository repositoryA;
@Autowired
BucketBRepository repositoryB;
@Autowired
BucketCRepository repositoryC;
@Configuration
@EnableCouchbaseRepositories(basePackageClasses = RepositoryTemplateWiringTests.class, considerNestedRepositories = true)
static class Config extends AbstractCouchbaseConfiguration {
@Override
protected List<String> getBootstrapHosts() {
return Arrays.asList("127.0.0.1");
}
@Override
protected String getBucketName() {
return "default";
}
@Override
protected String getBucketPassword() {
return "";
}
@Bean
public CouchbaseOperations templateA() {
return mockOpsA;
}
@Bean
public CouchbaseOperations templateB() {
return mockOpsB;
}
@Bean
public CouchbaseOperations templateC() {
return mockOpsC;
}
@Override
public RepositoryOperationsMapping repositoryOperationsMapping() throws Exception {
return new RepositoryOperationsMapping(templateC())
.map(BucketBRepository.class, templateB())
.mapEntity(Item.class, templateA());
}
}
@Test
public void testRepositoriesAreInstanciatedWithCorrectTemplates() {
assertNotNull(repositoryA);
assertNotNull(repositoryB);
assertNotNull(repositoryC);
boolean existA = repositoryA.exists("testA");
boolean existB = repositoryB.exists("testB");
Misc valueC = repositoryC.findOne("toto");
assertTrue(existA);
assertFalse(existB);
assertNotNull(valueC);
assertEquals("mock", valueC.id);
assertEquals(true, valueC.random);
verify(mockOpsA).exists("testA");
verify(mockOpsB).exists("testB");
verify(mockOpsC).findById(any(String.class), eq(Misc.class));
}
private static class Item {
@Id
public String id;
public String value;
}
private static class Misc {
@Id
public String id;
public boolean random;
}
@Repository
static interface BucketARepository extends CouchbaseRepository<Item, String> {}
@Repository
static interface BucketBRepository extends CouchbaseRepository<Item, String> {}
@Repository
static interface BucketCRepository extends CouchbaseRepository<Misc, String> {}
}