DATACOUCH-504 - Migrate to Couchbase SDK 3
This commit is contained in:
committed by
Michael Nitschinger
parent
690f064cac
commit
c9a19c925e
@@ -1,20 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* This runner initializes container for the container based testing.
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class ContainerResourceRunner extends SpringJUnit4ClassRunner {
|
||||
|
||||
@ClassRule
|
||||
public static final TestContainerResource resource = TestContainerResource.getResource();
|
||||
|
||||
public ContainerResourceRunner(Class<?> clazz) throws InitializationError {
|
||||
super(clazz);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
/**
|
||||
* Helper to check if the Couchbase http endpoints are up.
|
||||
*/
|
||||
public class CouchbaseHttpPortListeningCheck implements Callable<Boolean> {
|
||||
|
||||
private final int port;
|
||||
private final String path;
|
||||
|
||||
public CouchbaseHttpPortListeningCheck(int port, String path) {
|
||||
this.port = port;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
private Boolean executeRequest(URIBuilder builder) throws Exception {
|
||||
try {
|
||||
HttpGet request = new HttpGet(builder.build());
|
||||
HttpClient client = HttpClientBuilder.create().build();
|
||||
HttpResponse response = client.execute(request);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
if (status < 200 || status >= 300) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
Thread.sleep(1000);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
URIBuilder builder = new URIBuilder();
|
||||
builder.setScheme("http").setHost("localhost").setPort(this.port).setPath(this.path);
|
||||
return executeRequest(builder);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Couchbase, Inc.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.rnorth.ducttape.unreliables.Unreliables;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CouchbaseTestHelper {
|
||||
private CouchbaseTestHelper() {
|
||||
throw new AssertionError("not instantiable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a repository instance for the given interface.
|
||||
* <p>
|
||||
* Retry because concurrent index creation throws exception.
|
||||
* See https://issues.couchbase.com/browse/MB-32238
|
||||
*/
|
||||
public static <T> T getRepositoryWithRetry(RepositoryFactorySupport factory, Class<T> repositoryInterface) {
|
||||
return retryUntilSuccess(() -> factory.getRepository(repositoryInterface));
|
||||
}
|
||||
|
||||
private static <T> T retryUntilSuccess(final Callable<T> lambda) {
|
||||
return Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, lambda);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.couchbase.client.java.util.features.Version;
|
||||
import org.rnorth.ducttape.unreliables.Unreliables;
|
||||
import org.testcontainers.containers.Container;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.WaitStrategy;
|
||||
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget;
|
||||
|
||||
/**
|
||||
* WaitStrategy for Couchbase containers which makes the Server node is
|
||||
* initialized, RBAC user and default bucket is created.
|
||||
*/
|
||||
public class CouchbaseWaitStrategy implements WaitStrategy {
|
||||
|
||||
private Duration startupTimeout = Duration.of(60, SECONDS);
|
||||
private final Boolean rbacEnabled;
|
||||
private final Container container;
|
||||
|
||||
public CouchbaseWaitStrategy(String serverVersion, GenericContainer container) {
|
||||
this.container = container;
|
||||
Version version = Version.parseVersion(serverVersion);
|
||||
rbacEnabled = version.major() >= 5;
|
||||
}
|
||||
|
||||
private void checkResult(Container.ExecResult result, String command) throws Exception {
|
||||
if (!result.getStdout().contains("SUCCESS")) {
|
||||
throw new Exception(command + " command failed");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkService(int port, String path) {
|
||||
Callable<Boolean> externalCheck = new CouchbaseHttpPortListeningCheck(port, path);
|
||||
Unreliables.retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () ->
|
||||
externalCheck.call());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitUntilReady(WaitStrategyTarget target) {
|
||||
try {
|
||||
checkService(8091, "/pools");
|
||||
Container.ExecResult result;
|
||||
if (rbacEnabled) {
|
||||
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
|
||||
"cluster-init",
|
||||
"--cluster=127.0.0.1:8091",
|
||||
"--services=data,index,query",
|
||||
"--cluster-name=localcontainer",
|
||||
"--cluster-username=Administrator",
|
||||
"--cluster-password=password",
|
||||
"--cluster-ramsize=512",
|
||||
"--cluster-index-ramsize=512",
|
||||
"--index-storage-setting=default");
|
||||
checkResult(result, "Cluster init");
|
||||
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
|
||||
"user-manage",
|
||||
"--cluster=127.0.0.1:8091",
|
||||
"--username=Administrator",
|
||||
"--password=password",
|
||||
"--set",
|
||||
"--rbac-username=protected",
|
||||
"--rbac-password=password",
|
||||
"--rbac-name=default",
|
||||
"--roles=admin",
|
||||
"--auth-domain=local");
|
||||
checkResult(result, "User manage");
|
||||
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
|
||||
"bucket-create",
|
||||
"--cluster=127.0.0.1:8091",
|
||||
"--username=Administrator",
|
||||
"--password=password",
|
||||
"--bucket=protected",
|
||||
"--bucket-type=couchbase",
|
||||
"--bucket-ramsize=200",
|
||||
"--enable-flush=1",
|
||||
"--wait");
|
||||
} else {
|
||||
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
|
||||
"cluster-init",
|
||||
"--cluster=127.0.0.1:8091",
|
||||
"--services=data,index,query",
|
||||
"-u",
|
||||
"Administrator",
|
||||
"-p",
|
||||
"password",
|
||||
"--cluster-ramsize=512",
|
||||
"--cluster-index-ramsize=512",
|
||||
"--index-storage-setting=default");
|
||||
checkResult(result, "Cluster init");
|
||||
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
|
||||
"bucket-create",
|
||||
"--cluster=127.0.0.1:8091",
|
||||
"-u",
|
||||
"Administrator",
|
||||
"-p",
|
||||
"password",
|
||||
"--bucket=protected",
|
||||
"--bucket-password=password",
|
||||
"--bucket-type=couchbase",
|
||||
"--bucket-ramsize=200",
|
||||
"--enable-flush=1",
|
||||
"--wait");
|
||||
}
|
||||
|
||||
checkResult(result, "Bucket create");
|
||||
checkService(8093, "/query/ping");
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WaitStrategy withStartupTimeout(Duration startupTimeout) {
|
||||
this.startupTimeout = startupTimeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.config.CouchbaseConfigurer;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.WriteResultChecking;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
|
||||
@Configuration
|
||||
public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminUser() {
|
||||
return "Administrator";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getBootstrapHosts() {
|
||||
return Collections.singletonList("127.0.0.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketName() {
|
||||
return "protected";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
//TODO maybe create the bucket if doesn't exist
|
||||
|
||||
@Override
|
||||
protected CouchbaseEnvironment getEnvironment() {
|
||||
return DefaultCouchbaseEnvironment.builder()
|
||||
.connectTimeout(10000)
|
||||
.kvTimeout(10000)
|
||||
.queryTimeout(20000)
|
||||
.viewTimeout(20000)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouchbaseTemplate couchbaseTemplate() throws Exception {
|
||||
CouchbaseTemplate template = super.couchbaseTemplate();
|
||||
template.setWriteResultChecking(WriteResultChecking.LOG);
|
||||
return template;
|
||||
}
|
||||
|
||||
//this is for dev so it is ok to auto-create indexes
|
||||
@Override
|
||||
public IndexManager indexManager() {
|
||||
return new IndexManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Consistency getDefaultConsistency() {
|
||||
return Consistency.READ_YOUR_OWN_WRITES;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CouchbaseConfigurer couchbaseConfigurer() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class IntegrationTestCustomKeySettings extends IntegrationTestApplicationConfig {
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class IntegrationTestCustomTypeKeyConfig extends IntegrationTestApplicationConfig {
|
||||
|
||||
//change the name of the field that will hold type information
|
||||
@Override
|
||||
public String typeKey() {
|
||||
return "javaClass";
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.config.CouchbaseConfigurer;
|
||||
|
||||
/**
|
||||
* Configuration for testing no shutdown
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class IntegrationTestNoShutdownApplicationConfig extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminUser() {
|
||||
return "Administrator";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getBootstrapHosts() {
|
||||
return Collections.singletonList("127.0.0.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketName() {
|
||||
return "protected";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnvironmentManagedBySpring() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CouchbaseConfigurer couchbaseConfigurer() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.config.AbstractReactiveCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.WriteResultChecking;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
|
||||
@Configuration
|
||||
public class ReactiveIntegrationTestApplicationConfig extends AbstractReactiveCouchbaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminUser() {
|
||||
return "Administrator";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getBootstrapHosts() {
|
||||
return Collections.singletonList("127.0.0.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketName() {
|
||||
return "protected";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CouchbaseEnvironment getEnvironment() {
|
||||
return DefaultCouchbaseEnvironment.builder()
|
||||
.connectTimeout(10000)
|
||||
.kvTimeout(10000)
|
||||
.queryTimeout(10000)
|
||||
.viewTimeout(10000)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RxJavaCouchbaseTemplate reactiveCouchbaseTemplate() throws Exception {
|
||||
RxJavaCouchbaseTemplate template = super.reactiveCouchbaseTemplate();
|
||||
template.setWriteResultChecking(WriteResultChecking.LOG);
|
||||
return template;
|
||||
}
|
||||
|
||||
//this is for dev so it is ok to auto-create indexes
|
||||
@Override
|
||||
public IndexManager indexManager() {
|
||||
return new IndexManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Consistency getDefaultConsistency() {
|
||||
return Consistency.READ_YOUR_OWN_WRITES;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.testcontainers.containers.FixedHostPortGenericContainer;
|
||||
|
||||
/**
|
||||
* Testcontainers as external resource. It is recommended to use it as ClassRule.
|
||||
* It also does the internal reference counting, in case if the getResource is called again.
|
||||
*
|
||||
*/
|
||||
public class TestContainerResource extends ExternalResource {
|
||||
|
||||
private static FixedHostPortGenericContainer couchbaseContainer = null;
|
||||
private static final AtomicInteger referenceCount = new AtomicInteger();
|
||||
private static TestContainerResource currentInstance;
|
||||
private static String serverVersion;
|
||||
|
||||
|
||||
public static TestContainerResource getResource() {
|
||||
if (currentInstance == null) {
|
||||
currentInstance = new TestContainerResource();
|
||||
try {
|
||||
Properties properties = new Properties();
|
||||
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("server.properties"));
|
||||
serverVersion = properties.getProperty("server.version");
|
||||
if(!"container".equals(properties.getProperty("server.resource"))) {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
couchbaseContainer = new FixedHostPortGenericContainer("couchbase:" + serverVersion)
|
||||
.withFixedExposedPort(8091, 8091)
|
||||
.withFixedExposedPort(18091, 18091)
|
||||
.withFixedExposedPort(8092, 8092)
|
||||
.withFixedExposedPort(18092, 18092)
|
||||
.withFixedExposedPort(8093, 8093)
|
||||
.withFixedExposedPort(18093, 18093)
|
||||
.withFixedExposedPort(8094, 8094)
|
||||
.withFixedExposedPort(18094, 18094)
|
||||
.withFixedExposedPort(11210, 11210)
|
||||
.withFixedExposedPort(11211, 11211)
|
||||
.withFixedExposedPort(11207, 11207);
|
||||
couchbaseContainer.waitingFor(new CouchbaseWaitStrategy(serverVersion, couchbaseContainer));
|
||||
couchbaseContainer.start();
|
||||
}
|
||||
|
||||
return currentInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void before() {
|
||||
referenceCount.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
if (referenceCount.decrementAndGet() == 0 && couchbaseContainer != null) {
|
||||
if(couchbaseContainer.isRunning()) {
|
||||
couchbaseContainer.close();
|
||||
}
|
||||
currentInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package org.springframework.data.couchbase;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.WriteResultChecking;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.CouchbaseBucket;
|
||||
import com.couchbase.client.java.CouchbaseCluster;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.cluster.DefaultClusterInfo;
|
||||
import com.couchbase.client.java.util.features.CouchbaseFeature;
|
||||
import com.couchbase.client.java.util.features.Version;
|
||||
|
||||
@Configuration
|
||||
public class UnitTestApplicationConfig extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminUser() {
|
||||
return "someLogin";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String couchbaseAdminPassword() {
|
||||
return "somePassword";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getBootstrapHosts() {
|
||||
return Collections.singletonList("192.1.2.3");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketName() {
|
||||
return "someBucket";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBucketPassword() {
|
||||
return "someBucketPassword";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster couchbaseCluster() throws Exception {
|
||||
return Mockito.mock(CouchbaseCluster.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterInfo couchbaseClusterInfo() {
|
||||
DefaultClusterInfo mock = Mockito.mock(DefaultClusterInfo.class);
|
||||
when(mock.checkAvailable(CouchbaseFeature.N1QL)).thenReturn(true);
|
||||
when(mock.getMinVersion()).thenReturn(new Version(4, 0, 0));
|
||||
return mock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bucket couchbaseClient() throws Exception {
|
||||
return Mockito.mock(CouchbaseBucket.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouchbaseTemplate couchbaseTemplate() throws Exception {
|
||||
CouchbaseTemplate template = super.couchbaseTemplate();
|
||||
template.setWriteResultChecking(WriteResultChecking.LOG);
|
||||
return template;
|
||||
}
|
||||
|
||||
//this is for dev so it is ok to auto-create indexes
|
||||
@Override
|
||||
public IndexManager indexManager() {
|
||||
return new IndexManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Consistency getDefaultConsistency() {
|
||||
return Consistency.READ_YOUR_OWN_WRITES;
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
package org.springframework.data.couchbase.config;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.CouchbaseCluster;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.document.JsonDocument;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* This test case demonstrates that the {@link AbstractCouchbaseDataConfiguration} can take its SDK beans
|
||||
* from a sibling {@link Configuration}.
|
||||
*
|
||||
* Tests DATACOUCH-279
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@SuppressWarnings("SpringJavaAutowiringInspection")
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration
|
||||
public class AbstractCouchbaseDataConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ItemRepository repository;
|
||||
|
||||
@Autowired
|
||||
Bucket client;
|
||||
|
||||
@Configuration
|
||||
static class SdkConfig {
|
||||
|
||||
private static final String IP = "127.0.0.1";
|
||||
private static final String BUCKET_NAME = "protected";
|
||||
private static final String BUCKET_PASSWORD = "password";
|
||||
|
||||
public static Bucket bucket;
|
||||
|
||||
@Bean
|
||||
public Cluster couchbaseCluster() {
|
||||
return CouchbaseCluster.create(couchbaseEnv(), IP);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClusterInfo couchbaseClusterInfo() {
|
||||
return couchbaseCluster().clusterManager(BUCKET_NAME, BUCKET_PASSWORD).info();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bucket couchbaseBucket() {
|
||||
Bucket b = couchbaseCluster().openBucket(BUCKET_NAME, BUCKET_PASSWORD);
|
||||
bucket = b;
|
||||
return b;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CouchbaseEnvironment couchbaseEnv() {
|
||||
return DefaultCouchbaseEnvironment.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories(basePackageClasses = AbstractCouchbaseDataConfigurationIntegrationTests.class, considerNestedRepositories = true)
|
||||
static class Config extends AbstractCouchbaseDataConfiguration {
|
||||
|
||||
@Autowired
|
||||
Cluster c;
|
||||
|
||||
@Autowired
|
||||
ClusterInfo ci;
|
||||
|
||||
@Autowired
|
||||
Bucket b;
|
||||
|
||||
@Autowired
|
||||
CouchbaseEnvironment e;
|
||||
|
||||
@Override
|
||||
protected CouchbaseConfigurer couchbaseConfigurer() {
|
||||
return new TestCouchbaseConfigurer(e, c, ci, b);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectedBucketIsFromAdditionalConfig() {
|
||||
assertThat(SdkConfig.bucket).isSameAs(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateIsUsable() {
|
||||
String key = "simpleConfigTest";
|
||||
assertThat(repository).isNotNull();
|
||||
|
||||
Item item = new Item();
|
||||
item.id = key;
|
||||
item.value = "Test if the SimpleCouchbaseConfiguration can correctly get Bucket/Cluster/etc... beans injected";
|
||||
|
||||
repository.save(item);
|
||||
JsonDocument testDoc = client.get(key);
|
||||
|
||||
assertThat(testDoc).isNotNull();
|
||||
assertThat(testDoc.content()).isNotNull();
|
||||
assertThat(testDoc.content().getString("value")).isEqualTo(item.value);
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
@Id
|
||||
public String id;
|
||||
|
||||
public String value;
|
||||
}
|
||||
|
||||
private static class TestCouchbaseConfigurer implements CouchbaseConfigurer {
|
||||
|
||||
private CouchbaseEnvironment env;
|
||||
private Cluster cluster;
|
||||
private ClusterInfo info;
|
||||
private Bucket bucket;
|
||||
|
||||
public TestCouchbaseConfigurer(CouchbaseEnvironment env, Cluster cluster, ClusterInfo info, Bucket bucket) {
|
||||
this.env = env;
|
||||
this.cluster = cluster;
|
||||
this.info = info;
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CouchbaseEnvironment couchbaseEnvironment() throws Exception {
|
||||
return this.env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster couchbaseCluster() throws Exception {
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterInfo couchbaseClusterInfo() throws Exception {
|
||||
return this.info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bucket couchbaseClient() throws Exception {
|
||||
return this.bucket;
|
||||
}
|
||||
}
|
||||
|
||||
@Repository
|
||||
interface ItemRepository extends CouchbaseRepository<Item, String> {}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.config;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CouchbaseBucketParserTest {
|
||||
|
||||
private static DefaultListableBeanFactory factory;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
factory = new DefaultListableBeanFactory();
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
||||
int n = reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseBucket-bean.xml"));
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultBucketNoCluster() {
|
||||
BeanDefinition def = factory.getBeanDefinition("bucketDefaultNoCluster");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, Object.class);
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
|
||||
RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue();
|
||||
|
||||
assertThat(clusterRef.getBeanName()).isEqualTo(BeanNames.COUCHBASE_CLUSTER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultBucket() throws Exception {
|
||||
BeanDefinition def = factory.getBeanDefinition("bucketDefault");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, Object.class);
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
|
||||
RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue();
|
||||
|
||||
assertThat(clusterRef.getBeanName()).isEqualTo("clusterDefault");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBucketWithName() throws Exception {
|
||||
BeanDefinition def = factory.getBeanDefinition("bucketWithName");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(2);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, Object.class);
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
|
||||
RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue();
|
||||
assertThat(clusterRef.getBeanName()).isEqualTo("clusterDefault");
|
||||
|
||||
ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(1, Object.class);
|
||||
assertThat(nameHolder.getValue()).isInstanceOf(String.class);
|
||||
assertThat(nameHolder.getValue()).hasToString("toto");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBucketWithNameAndPassword() throws Exception {
|
||||
BeanDefinition def = factory.getBeanDefinition("bucketWithNameAndPassword");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(4);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, Object.class);
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
|
||||
RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue();
|
||||
assertThat(clusterRef.getBeanName()).isEqualTo("clusterDefault");
|
||||
|
||||
ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(1, Object.class);
|
||||
assertThat(nameHolder.getValue()).isInstanceOf(String.class);
|
||||
assertThat(nameHolder.getValue()).hasToString("test");
|
||||
|
||||
|
||||
ConstructorArgumentValues.ValueHolder usernameHolder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(2, Object.class);
|
||||
assertThat(usernameHolder.getValue()).isInstanceOf(String.class);
|
||||
assertThat(usernameHolder.getValue()).hasToString("testuser");
|
||||
|
||||
|
||||
ConstructorArgumentValues.ValueHolder passwordHolder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(3, Object.class);
|
||||
assertThat(passwordHolder.getValue()).isInstanceOf(String.class);
|
||||
assertThat(passwordHolder.getValue()).hasToString("123");
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CouchbaseClusterParserTest {
|
||||
|
||||
|
||||
private static DefaultListableBeanFactory factory;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
factory = new DefaultListableBeanFactory();
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
||||
int n = reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseCluster-bean.xml"));
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClusterWithoutSpecificEnv() {
|
||||
BeanDefinition def = factory.getBeanDefinition("clusterDefault");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
assertThat(def.getFactoryMethodName()).isEqualTo("create");
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, CouchbaseEnvironment.class);
|
||||
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
RuntimeBeanReference envRef = (RuntimeBeanReference) holder.getValue();
|
||||
|
||||
assertThat(envRef.getBeanName()).isEqualTo("couchbaseEnv");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClusterWithNodes() {
|
||||
BeanDefinition def = factory.getBeanDefinition("clusterWithNodes");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(2);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
assertThat(def.getFactoryMethodName()).isEqualTo("create");
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(1, List.class);
|
||||
assertThat(holder.getValue()).isInstanceOf(List.class);
|
||||
List nodes = (List<String>) holder.getValue();
|
||||
|
||||
assertThat(nodes.size()).isEqualTo(2);
|
||||
assertThat((String) nodes.get(0)).isEqualTo("192.1.2.3");
|
||||
assertThat((String) nodes.get(1)).isEqualTo("192.4.5.6");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClusterWithEnvInline() {
|
||||
BeanDefinition def = factory.getBeanDefinition("clusterWithEnvInline");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, CouchbaseEnvironment.class);
|
||||
GenericBeanDefinition envDef = (GenericBeanDefinition) holder.getValue();
|
||||
|
||||
assertThat(envDef.getBeanClassName())
|
||||
.isEqualTo(CouchbaseEnvironmentFactoryBean.class.getName());
|
||||
assertThat(envDef.getPropertyValues().contains("managementTimeout"))
|
||||
.as("unexpected attribute").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClusterWithEnvRef() {
|
||||
BeanDefinition def = factory.getBeanDefinition("clusterWithEnvRef");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(1);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, CouchbaseEnvironment.class);
|
||||
|
||||
assertThat(holder.getValue()).isInstanceOf(RuntimeBeanReference.class);
|
||||
RuntimeBeanReference envRef = (RuntimeBeanReference) holder.getValue();
|
||||
|
||||
assertThat(envRef.getBeanName()).isEqualTo("someEnv");
|
||||
}
|
||||
@Test
|
||||
public void testClusterConfigurationPrecedence() {
|
||||
BeanDefinition def = factory.getBeanDefinition("clusterWithAll");
|
||||
|
||||
assertThat(def).isNotNull();
|
||||
assertThat(def.getConstructorArgumentValues().getArgumentCount()).isEqualTo(2);
|
||||
assertThat(def.getPropertyValues().size()).isEqualTo(0);
|
||||
assertThat(def.getFactoryMethodName()).isEqualTo("create");
|
||||
|
||||
assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(0)
|
||||
.getValue()).isInstanceOf(GenericBeanDefinition.class);
|
||||
assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(1)
|
||||
.getValue()).isInstanceOf(List.class);
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holderEnv = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(0, CouchbaseEnvironment.class);
|
||||
GenericBeanDefinition envDef = (GenericBeanDefinition) holderEnv.getValue();
|
||||
|
||||
assertThat(envDef.getBeanClassName())
|
||||
.isEqualTo(CouchbaseEnvironmentFactoryBean.class.getName());
|
||||
assertThat(envDef.getPropertyValues().contains("autoreleaseAfter"))
|
||||
.as("unexpected attribute").isTrue();
|
||||
|
||||
ConstructorArgumentValues.ValueHolder holderNodes = def.getConstructorArgumentValues()
|
||||
.getArgumentValue(1, List.class);
|
||||
List nodes = (List<String>) holderNodes.getValue();
|
||||
|
||||
assertThat(nodes.size()).isEqualTo(2);
|
||||
assertThat((String) nodes.get(0)).isEqualTo("2.2.2.2");
|
||||
assertThat((String) nodes.get(1)).isEqualTo("4.4.4.4");
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.springframework.data.couchbase.config;
|
||||
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestNoShutdownApplicationConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Simple test to make sure that environment is not shutdown if not life cycle managed by Spring.
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestNoShutdownApplicationConfig.class)
|
||||
public class CouchbaseEnvironmentNoShutdownProxyIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
public CouchbaseEnvironment environment;
|
||||
|
||||
@Test
|
||||
public void testEnvironmentShutDown() {
|
||||
assertThat(environment.shutdown()).as("Should return false").isEqualTo(false);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.config;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import com.couchbase.client.core.retry.BestEffortRetryStrategy;
|
||||
import com.couchbase.client.core.retry.FailFastRetryStrategy;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CouchbaseEnvironmentParserTest {
|
||||
|
||||
private static GenericApplicationContext context;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseEnv-bean.xml"));
|
||||
context = new GenericApplicationContext(factory);
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingRetryStrategyFailFast() throws Exception {
|
||||
CouchbaseEnvironment env = context.getBean("envWithFailFast", CouchbaseEnvironment.class);
|
||||
|
||||
assertThat(env.retryStrategy()).isInstanceOf(FailFastRetryStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingRetryStrategyBestEffort() throws Exception {
|
||||
CouchbaseEnvironment env = context.getBean("envWithBestEffort", CouchbaseEnvironment.class);
|
||||
|
||||
assertThat(env.retryStrategy()).isInstanceOf(BestEffortRetryStrategy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllDefaultsOverridden() {
|
||||
CouchbaseEnvironment env = context.getBean("envWithNoDefault", CouchbaseEnvironment.class);
|
||||
CouchbaseEnvironment defaultEnv = DefaultCouchbaseEnvironment.create();
|
||||
|
||||
assertThat(env).isInstanceOf(DefaultCouchbaseEnvironment.class);
|
||||
|
||||
assertThat(env.managementTimeout()).isEqualTo(1L);
|
||||
assertThat(env.queryTimeout()).isEqualTo(2L);
|
||||
assertThat(env.viewTimeout()).isEqualTo(3L);
|
||||
assertThat(env.kvTimeout()).isEqualTo(4L);
|
||||
assertThat(env.connectTimeout()).isEqualTo(5L);
|
||||
assertThat(env.disconnectTimeout()).isEqualTo(6L);
|
||||
assertThat(env.dnsSrvEnabled()).isTrue().isNotEqualTo(defaultEnv.dnsSrvEnabled());
|
||||
|
||||
assertThat(env.sslEnabled()).isTrue().isNotEqualTo(defaultEnv.sslEnabled());
|
||||
assertThat(env.sslKeystoreFile()).isEqualTo("test");
|
||||
assertThat(env.sslKeystorePassword()).isEqualTo("test");
|
||||
assertThat(env.bootstrapHttpEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.bootstrapHttpEnabled());
|
||||
assertThat(env.bootstrapCarrierEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.bootstrapCarrierEnabled());
|
||||
assertThat(env.bootstrapHttpDirectPort()).isEqualTo(8);
|
||||
assertThat(env.bootstrapHttpSslPort()).isEqualTo(9);
|
||||
assertThat(env.bootstrapCarrierDirectPort()).isEqualTo(10);
|
||||
assertThat(env.bootstrapCarrierSslPort()).isEqualTo(11);
|
||||
assertThat(env.ioPoolSize()).isEqualTo(12);
|
||||
assertThat(env.computationPoolSize()).isEqualTo(13);
|
||||
assertThat(env.responseBufferSize()).isEqualTo(14);
|
||||
assertThat(env.requestBufferSize()).isEqualTo(15);
|
||||
assertThat(env.kvEndpoints()).isEqualTo(16);
|
||||
assertThat(env.viewEndpoints()).isEqualTo(17);
|
||||
assertThat(env.queryEndpoints()).isEqualTo(18);
|
||||
assertThat(env.retryStrategy()).isInstanceOf(FailFastRetryStrategy.class);
|
||||
assertThat(env.maxRequestLifetime()).isEqualTo(19L);
|
||||
assertThat(env.keepAliveInterval()).isEqualTo(20L);
|
||||
assertThat(env.autoreleaseAfter()).isEqualTo(21L);
|
||||
assertThat(env.bufferPoolingEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.bufferPoolingEnabled());
|
||||
assertThat(env.tcpNodelayEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.tcpNodelayEnabled());
|
||||
assertThat(env.mutationTokensEnabled()).isTrue()
|
||||
.isNotEqualTo(defaultEnv.mutationTokensEnabled());
|
||||
assertThat(env.analyticsTimeout()).isEqualTo(30L);
|
||||
assertThat(env.configPollInterval()).isEqualTo(50L);
|
||||
assertThat(env.configPollFloorInterval()).isEqualTo(30L);
|
||||
assertThat(env.operationTracingEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.operationTracingEnabled());
|
||||
assertThat(env.operationTracingServerDurationEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.operationTracingServerDurationEnabled());
|
||||
assertThat(env.orphanResponseReportingEnabled()).isFalse()
|
||||
.isNotEqualTo(defaultEnv.orphanResponseReportingEnabled());
|
||||
assertThat(env.compressionMinSize()).isEqualTo(100);
|
||||
assertThat(env.compressionMinRatio()).isEqualTo(0.90);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.config;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import com.couchbase.client.core.env.DefaultCoreEnvironment;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Simon Bland
|
||||
*/
|
||||
public class CouchbaseSingleEnvironmentParserTest {
|
||||
|
||||
/**
|
||||
* See DATACOUCH-235
|
||||
*/
|
||||
@Test
|
||||
public void testSingleCouchbaseEnvironment() throws Exception {
|
||||
|
||||
int instanceCounterBefore = DefaultCoreEnvironment.instanceCounter();
|
||||
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseSingleEnv-bean.xml"));
|
||||
GenericApplicationContext context = new GenericApplicationContext(factory);
|
||||
context.refresh();
|
||||
CouchbaseEnvironment env = context.getBean("singleEnv", CouchbaseEnvironment.class);
|
||||
context.close();
|
||||
|
||||
int instanceCounterAfter = DefaultCoreEnvironment.instanceCounter();
|
||||
|
||||
assertThat(env).isInstanceOf(DefaultCouchbaseEnvironment.class);
|
||||
assertThat(instanceCounterAfter).isEqualTo(instanceCounterBefore + 1);
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.config;
|
||||
|
||||
import com.couchbase.client.java.document.JsonDocument;
|
||||
import com.couchbase.client.java.document.json.JsonObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.User;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = CouchbaseTemplateParserIntegrationTests.class)
|
||||
public class CouchbaseTemplateParserIntegrationTests {
|
||||
|
||||
DefaultListableBeanFactory factory;
|
||||
BeanDefinitionReader reader;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
factory = new DefaultListableBeanFactory();
|
||||
reader = new XmlBeanDefinitionReader(factory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readsCouchbaseTemplateAttributesCorrectly() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-bean.xml"));
|
||||
|
||||
BeanDefinition definition = factory.getBeanDefinition(BeanNames.COUCHBASE_TEMPLATE);
|
||||
assertThat(definition.getConstructorArgumentValues().getArgumentCount()).isEqualTo(2);
|
||||
|
||||
factory.getBean(BeanNames.COUCHBASE_TEMPLATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readsCouchbaseTemplateWithTranslationServiceAttributesCorrectly() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-with-translation-service-bean.xml"));
|
||||
|
||||
BeanDefinition definition = factory.getBeanDefinition(BeanNames.COUCHBASE_TEMPLATE);
|
||||
assertThat(definition.getConstructorArgumentValues().getArgumentCount()).isEqualTo(3);
|
||||
|
||||
factory.getBean(BeanNames.COUCHBASE_TEMPLATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for DATACOUCH-47.
|
||||
*/
|
||||
@Test
|
||||
public void allowsMultipleBuckets() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-multi-bucket-bean.xml"));
|
||||
|
||||
factory.getBean("cb-template-first");
|
||||
factory.getBean("cb-template-second");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for DATACOUCH-134 in xml: field for storing type information can be renamed.
|
||||
*/
|
||||
@Test
|
||||
public void testTypeFieldCanBeChosen() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-typekey.xml"));
|
||||
CouchbaseTemplate template = factory.getBean(BeanNames.COUCHBASE_TEMPLATE, CouchbaseTemplate.class);
|
||||
|
||||
assertThat(template.getConverter() instanceof MappingCouchbaseConverter).isTrue();
|
||||
MappingCouchbaseConverter converter = ((MappingCouchbaseConverter) template.getConverter());
|
||||
|
||||
assertThat(converter.getTypeKey()).isEqualTo("javaXmlClass");
|
||||
|
||||
User u = new User("specialSaveUser", "John Locke", 46);
|
||||
template.save(u);
|
||||
JsonDocument uJsonDoc = template.getCouchbaseBucket().get("specialSaveUser");
|
||||
template.getCouchbaseBucket().remove("specialSaveUser");
|
||||
assertThat(uJsonDoc).isNotNull();
|
||||
JsonObject uJson = uJsonDoc.content();
|
||||
assertThat(uJson.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT)).isNull();
|
||||
assertThat(uJson.getString("javaXmlClass"))
|
||||
.isEqualTo("org.springframework.data.couchbase.repository.User");
|
||||
assertThat(uJson.getString("username")).isEqualTo("John Locke");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for DATACOUCH-148, choosing an alternative default for view/N1QL staleness.
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseCustomStaleness() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-consistency.xml"));
|
||||
CouchbaseTemplate template = factory.getBean("template", CouchbaseTemplate.class);
|
||||
|
||||
assertThat(template.getDefaultConsistency())
|
||||
.isEqualTo(Consistency.EVENTUALLY_CONSISTENT);
|
||||
assertThat(template.getDefaultConsistency())
|
||||
.isNotEqualTo(Consistency.DEFAULT_CONSISTENCY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for DATACOUCH-148, choosing an unknown value for view/N1QL staleness.
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreBadCustomStaleness() {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-consistency.xml"));
|
||||
CouchbaseTemplate template = factory.getBean("templateBad", CouchbaseTemplate.class);
|
||||
|
||||
assertThat(template.getDefaultConsistency())
|
||||
.isEqualTo(Consistency.DEFAULT_CONSISTENCY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHaveDefaultsForStaleness() {
|
||||
//use another resource where staleness isn't customized
|
||||
reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-with-translation-service-bean.xml"));
|
||||
CouchbaseTemplate template = factory.getBean(BeanNames.COUCHBASE_TEMPLATE, CouchbaseTemplate.class);
|
||||
|
||||
assertThat(template.getDefaultConsistency())
|
||||
.isEqualTo(Consistency.DEFAULT_CONSISTENCY);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import rx.observers.TestSubscriber;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class AsyncUtils {
|
||||
|
||||
public static void executeConcurrently(int numThreads, Callable<Void> task) throws Exception {
|
||||
ExecutorService pool = Executors.newFixedThreadPool(numThreads);
|
||||
|
||||
Collection<Callable<Void>> tasks = Collections.nCopies(numThreads, task);
|
||||
|
||||
List<Future<Void>> futures = pool.invokeAll(tasks);
|
||||
for (Future future : futures) {
|
||||
future.get(numThreads, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void awaitCompleted(TestSubscriber<T> testSubscriber) {
|
||||
testSubscriber.awaitTerminalEvent();
|
||||
testSubscriber.assertNoErrors();
|
||||
testSubscriber.assertNoValues();
|
||||
testSubscriber.assertCompleted();
|
||||
}
|
||||
|
||||
public static <T> void awaitCompletedWithAnyValue(TestSubscriber<T> testSubscriber) {
|
||||
testSubscriber.awaitTerminalEvent();
|
||||
testSubscriber.assertNoErrors();
|
||||
testSubscriber.assertCompleted();
|
||||
}
|
||||
|
||||
public static <T> void awaitCompletedWithValueCount(TestSubscriber<T> testSubscriber, int count) {
|
||||
testSubscriber.awaitTerminalEvent();
|
||||
testSubscriber.assertNoErrors();
|
||||
testSubscriber.assertValueCount(count);
|
||||
testSubscriber.assertCompleted();
|
||||
}
|
||||
|
||||
public static <T> void awaitError(TestSubscriber<T> testSubscriber, Class<? extends Throwable> throwableClazz) {
|
||||
testSubscriber.awaitTerminalEvent();
|
||||
testSubscriber.assertError(throwableClazz);
|
||||
testSubscriber.assertNoValues();
|
||||
}
|
||||
|
||||
public static <T> void awaitValue(TestSubscriber<T> testSubscriber, T value) {
|
||||
testSubscriber.awaitTerminalEvent();
|
||||
testSubscriber.assertNoErrors();
|
||||
testSubscriber.assertValue(value);
|
||||
testSubscriber.assertCompleted();
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
|
||||
|
||||
/**
|
||||
* Test class for persisting and loading from {@link CouchbaseTemplate}.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class Beer {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Field("is_active")
|
||||
private boolean active = true;
|
||||
|
||||
@Field("desc")
|
||||
private String description;
|
||||
|
||||
public Beer(String id, String name, Boolean active, String description) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.active = active;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Beer [id=" + id + ", name=" + name + ", active=" + active + ", description=" + description + "]";
|
||||
}
|
||||
|
||||
public Beer setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Beer setActive(boolean active) {
|
||||
this.active = active;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public Beer setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
|
||||
/**
|
||||
* Test DTO for projecting from {@link CouchbaseTemplate}.
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class BeerDTO{
|
||||
private String name;
|
||||
|
||||
@Field("desc")
|
||||
private String description;
|
||||
|
||||
public BeerDTO(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public BeerDTO setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
|
||||
public BeerDTO setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() { return description; }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
/**
|
||||
* Test interface for projecting data from {@link CouchbaseTemplate}.
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public interface BeerProjection {
|
||||
String getDescription();
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.core.mapping.id.GenerationStrategy.*;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
|
||||
import org.springframework.data.couchbase.core.mapping.id.IdAttribute;
|
||||
import org.springframework.data.couchbase.core.mapping.id.IdPrefix;
|
||||
import org.springframework.data.couchbase.core.mapping.id.IdSuffix;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class CouchbaseTemplateIdGenerationIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
|
||||
private void removeIfExist(String key) {
|
||||
try {
|
||||
client.remove(key);
|
||||
}
|
||||
catch (DocumentDoesNotExistException e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateIdUsingAtrributes() throws Exception {
|
||||
SimpleClassWithGeneratedIdValueUsingAttributes simpleClass = new SimpleClassWithGeneratedIdValueUsingAttributes();
|
||||
String generatedId = template.getGeneratedId(simpleClass);
|
||||
|
||||
removeIfExist(generatedId);
|
||||
assertThat("prefix1::prefix2::0::1::2.0::3.0::4::Simple::Nested{value:simple}::suffix1::suffix2")
|
||||
.as("Id generation should be correct").isEqualTo(generatedId);
|
||||
template.insert(simpleClass);
|
||||
assertThat(template.exists(generatedId)).as("Exists after insert")
|
||||
.isEqualTo(true);
|
||||
simpleClass.value = "modified";
|
||||
template.save(simpleClass);
|
||||
SimpleClassWithGeneratedIdValueUsingAttributes modifiedClass = template.findById(generatedId,
|
||||
SimpleClassWithGeneratedIdValueUsingAttributes.class);
|
||||
assertThat(modifiedClass.id).as("Get after save id should be correct")
|
||||
.isEqualTo(generatedId);
|
||||
template.update(simpleClass);
|
||||
SimpleClassWithGeneratedIdValueUsingAttributes updatedClass = template.findById(generatedId,
|
||||
SimpleClassWithGeneratedIdValueUsingAttributes.class);
|
||||
assertThat(updatedClass.id).as("Get after update id should be correct")
|
||||
.isEqualTo(generatedId);
|
||||
template.remove(generatedId);
|
||||
assertThat(template.exists(generatedId)).as("Exists after remove")
|
||||
.isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateIdUsingUUID() throws Exception {
|
||||
SimpleClassWithGeneratedIdValueUsingUUID simpleClass = new SimpleClassWithGeneratedIdValueUsingUUID();
|
||||
String generatedId = template.getGeneratedId(simpleClass);
|
||||
simpleClass.id = generatedId;
|
||||
template.insert(simpleClass);
|
||||
assertThat(simpleClass.id).as("Should not regenerate id").isEqualTo(generatedId);
|
||||
template.remove(generatedId);
|
||||
assertThat(template.exists(generatedId)).as("Exists after remove")
|
||||
.isEqualTo(false);
|
||||
}
|
||||
|
||||
|
||||
@Document
|
||||
static class SimpleClassWithGeneratedIdValueUsingAttributes {
|
||||
|
||||
@Id @GeneratedValue(strategy = USE_ATTRIBUTES, delimiter = "::")
|
||||
public String id;
|
||||
|
||||
@IdAttribute(order = 6)
|
||||
public Nested nested = new Nested("simple");
|
||||
|
||||
@IdAttribute(order = 5)
|
||||
public String type = "Simple";
|
||||
|
||||
@IdAttribute(order = 4)
|
||||
public int intNum = 4;
|
||||
|
||||
@IdAttribute(order = 2)
|
||||
public float floatNum = 2F;
|
||||
|
||||
@IdAttribute(order = 3)
|
||||
public double doubleNum = 3;
|
||||
|
||||
@IdAttribute
|
||||
public long longNum = 0L;
|
||||
|
||||
@IdAttribute(order = 1)
|
||||
public short shortNum = 1;
|
||||
|
||||
@IdPrefix(order = 1)
|
||||
public String prefix2 = "prefix2";
|
||||
|
||||
@IdPrefix
|
||||
public String prefix1 = "prefix1";
|
||||
|
||||
@IdSuffix(order = 1)
|
||||
public String suffix2 = "suffix2";
|
||||
|
||||
@IdSuffix
|
||||
public String suffix1 = "suffix1";
|
||||
|
||||
public String value = "new";
|
||||
|
||||
}
|
||||
|
||||
static class Nested {
|
||||
private String value;
|
||||
|
||||
public Nested(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Nested{value:" + value + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimpleClassWithGeneratedIdValueUsingUUID {
|
||||
@Id @GeneratedValue(strategy = UNIQUE)
|
||||
public String id;
|
||||
|
||||
public String value = "new";
|
||||
}
|
||||
}
|
||||
@@ -1,812 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core;
|
||||
|
||||
import static com.couchbase.client.java.query.Select.select;
|
||||
import static com.couchbase.client.java.query.dsl.Expression.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.RawJsonDocument;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import com.couchbase.client.java.query.N1qlParams;
|
||||
import com.couchbase.client.java.query.N1qlQuery;
|
||||
import com.couchbase.client.java.query.N1qlQueryResult;
|
||||
import com.couchbase.client.java.query.consistency.ScanConsistency;
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import com.couchbase.client.java.view.Stale;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
* @author Anastasiia Smirnova
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(CouchbaseTemplateQueryListener.class)
|
||||
public class CouchbaseTemplateIntegrationTests {
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private void removeIfExist(String key) {
|
||||
try {
|
||||
template.remove(key);
|
||||
}
|
||||
catch (DocumentDoesNotExistException e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveSimpleEntityCorrectly() throws Exception {
|
||||
String id = "beers:awesome-stout";
|
||||
removeIfExist(id);
|
||||
|
||||
String name = "The Awesome Stout";
|
||||
boolean active = false;
|
||||
Beer beer = new Beer(id, name, active, "");
|
||||
|
||||
template.save(beer);
|
||||
RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
|
||||
assertThat(resultDoc).isNotNull();
|
||||
String result = resultDoc.content();
|
||||
assertThat(result).isNotNull();
|
||||
Map<String, Object> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
assertThat(resultConv.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT)).isNotNull();
|
||||
assertThat(resultConv.get("javaClass")).isNull();
|
||||
assertThat(resultConv.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT))
|
||||
.isEqualTo("org.springframework.data.couchbase.core.Beer");
|
||||
assertThat(resultConv.get("is_active")).isEqualTo(false);
|
||||
assertThat(resultConv.get("name")).isEqualTo("The Awesome Stout");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveDocumentWithExpiry() throws Exception {
|
||||
String id = "simple-doc-with-expiry";
|
||||
DocumentWithExpiry doc = new DocumentWithExpiry(id);
|
||||
template.save(doc);
|
||||
assertThat(client.get(id)).isNotNull();
|
||||
Thread.sleep(3000);
|
||||
assertThat(client.get(id)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertDoesNotOverride() throws Exception {
|
||||
String id = "double-insert-test";
|
||||
removeIfExist(id);
|
||||
|
||||
SimplePerson doc = new SimplePerson(id, "Mr. A");
|
||||
template.insert(doc);
|
||||
RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
|
||||
assertThat(resultDoc).isNotNull();
|
||||
String result = resultDoc.content();
|
||||
|
||||
Map<String, String> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, String>>() {});
|
||||
assertThat(resultConv.get("name")).isEqualTo("Mr. A");
|
||||
|
||||
doc = new SimplePerson(id, "Mr. B");
|
||||
try {
|
||||
template.insert(doc);
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
//ignore, since this insert should fail
|
||||
}
|
||||
|
||||
resultDoc = client.get(id, RawJsonDocument.class);
|
||||
assertThat(resultDoc).isNotNull();
|
||||
result = resultDoc.content();
|
||||
|
||||
resultConv = MAPPER.readValue(result, new TypeReference<Map<String, String>>() {});
|
||||
assertThat(resultConv.get("name")).isEqualTo("Mr. A");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void updateDoesNotInsert() {
|
||||
String id = "update-does-not-insert";
|
||||
SimplePerson doc = new SimplePerson(id, "Nice Guy");
|
||||
template.update(doc);
|
||||
assertThat(client.get(id)).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void removeDocument() {
|
||||
String id = "beers:to-delete-stout";
|
||||
Beer beer = new Beer(id, "", false, "");
|
||||
|
||||
template.save(beer);
|
||||
Object result = client.get(id);
|
||||
assertThat(result).isNotNull();
|
||||
|
||||
template.remove(beer);
|
||||
result = client.get(id);
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void storeListsAndMaps() {
|
||||
String id = "persons:lots-of-names";
|
||||
List<String> names = new ArrayList<String>();
|
||||
names.add("Michael");
|
||||
names.add("Thomas");
|
||||
names.add(null);
|
||||
List<Integer> votes = new LinkedList<Integer>();
|
||||
Map<String, Boolean> info1 = new HashMap<String, Boolean>();
|
||||
info1.put("foo", true);
|
||||
info1.put("bar", false);
|
||||
info1.put("nullValue", null);
|
||||
Map<String, Integer> info2 = new HashMap<String, Integer>();
|
||||
|
||||
ComplexPerson complex = new ComplexPerson(id, names, votes, info1, info2);
|
||||
|
||||
template.save(complex);
|
||||
assertThat(client.get(id)).isNotNull();
|
||||
|
||||
ComplexPerson response = template.findById(id, ComplexPerson.class);
|
||||
assertThat(response.getFirstnames()).isEqualTo(names);
|
||||
assertThat(response.getVotes()).isEqualTo(votes);
|
||||
assertThat(response.getId()).isEqualTo(id);
|
||||
assertThat(response.getInfo1()).isEqualTo(info1);
|
||||
assertThat(response.getInfo2()).isEqualTo(info2);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void validFindById() {
|
||||
String id = "beers:findme-stout";
|
||||
String name = "The Findme Stout";
|
||||
boolean active = true;
|
||||
Beer beer = new Beer(id, name, active, "");
|
||||
template.save(beer);
|
||||
|
||||
Beer found = template.findById(id, Beer.class);
|
||||
|
||||
assertThat(found).isNotNull();
|
||||
assertThat(found.getId()).isEqualTo(id);
|
||||
assertThat(found.getName()).isEqualTo(name);
|
||||
assertThat(found.getActive()).isEqualTo(active);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadAndMapViewDocs() {
|
||||
ViewQuery query = ViewQuery.from("test_beers", "by_name");
|
||||
query.stale(Stale.FALSE);
|
||||
|
||||
final List<Beer> beers = template.findByView(query, Beer.class);
|
||||
assertThat(beers.size() > 0).isTrue();
|
||||
|
||||
for (Beer beer : beers) {
|
||||
assertThat(beer.getId()).isNotNull();
|
||||
assertThat(beer.getName()).isNotNull();
|
||||
assertThat(beer.getActive()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryRaw() {
|
||||
N1qlQuery query = N1qlQuery.simple(select("name").from(i(client.name()))
|
||||
.where(x("name").isNotMissing()));
|
||||
|
||||
N1qlQueryResult queryResult = template.queryN1QL(query);
|
||||
assertThat(queryResult).isNotNull();
|
||||
assertThat(queryResult.finalSuccess()).as(queryResult.errors().toString())
|
||||
.isTrue();
|
||||
assertThat(queryResult.allRows().isEmpty()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryWithMapping() {
|
||||
FullFragment ff1 = new FullFragment("fullFragment1", 1, "fullFragment", "test1");
|
||||
FullFragment ff2 = new FullFragment("fullFragment2", 2, "fullFragment", "test2");
|
||||
template.save(Arrays.asList(ff1, ff2));
|
||||
|
||||
N1qlQuery query = N1qlQuery.simple(select(i("value")) //"value" is a n1ql keyword apparently
|
||||
.from(i(client.name()))
|
||||
.where(x("type").eq(s("fullFragment"))
|
||||
.and(x("criteria").gt(1))),
|
||||
|
||||
N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS));
|
||||
|
||||
List<Fragment> fragments = template.findByN1QLProjection(query, Fragment.class);
|
||||
assertThat(fragments).isNotNull();
|
||||
assertThat(fragments.isEmpty()).isFalse();
|
||||
assertThat(fragments.size()).isEqualTo(1);
|
||||
assertThat(fragments.get(0).value).isEqualTo("test2");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-159
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserialiseLongsAndInts() {
|
||||
final long longValue = new Date().getTime();
|
||||
final int intValue = new Random().nextInt();
|
||||
|
||||
template.save(new SimpleWithLongAndInt("simpleWithLong:simple", longValue, intValue));
|
||||
SimpleWithLongAndInt document = template.findById("simpleWithLong:simple", SimpleWithLongAndInt.class);
|
||||
assertThat(document).isNotNull();
|
||||
assertThat(document.getLongValue()).isEqualTo(longValue);
|
||||
assertThat(document.getIntValue()).isEqualTo(intValue);
|
||||
|
||||
template.save(new SimpleWithLongAndInt("simpleWithLong:simple:other", intValue, intValue));
|
||||
document = template.findById("simpleWithLong:simple:other", SimpleWithLongAndInt.class);
|
||||
assertThat(document).isNotNull();
|
||||
assertThat(document.getLongValue()).isEqualTo(intValue);
|
||||
assertThat(document.getIntValue()).isEqualTo(intValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeserialiseEnums() {
|
||||
SimpleWithEnum simpleWithEnum = new SimpleWithEnum("simpleWithEnum:enum", SimpleWithEnum.Type.BIG);
|
||||
template.save(simpleWithEnum);
|
||||
simpleWithEnum = template.findById("simpleWithEnum:enum", SimpleWithEnum.class);
|
||||
assertThat(simpleWithEnum).isNotNull();
|
||||
assertThat(SimpleWithEnum.Type.BIG).isEqualTo(simpleWithEnum.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeserialiseClass() {
|
||||
SimpleWithClass simpleWithClass = new SimpleWithClass("simpleWithClass:class", Integer.class);
|
||||
simpleWithClass.setValue("The dish ran away with the spoon.");
|
||||
template.save(simpleWithClass);
|
||||
simpleWithClass = template.findById("simpleWithClass:class", SimpleWithClass.class);
|
||||
assertThat(simpleWithClass).isNotNull();
|
||||
assertThat(simpleWithClass.getValue())
|
||||
.isEqualTo("The dish ran away with the spoon.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleCASVersionOnInsert() throws Exception {
|
||||
removeIfExist("versionedClass:1");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:1", "foobar");
|
||||
assertThat(versionedClass.getVersion()).isEqualTo(0);
|
||||
template.insert(versionedClass);
|
||||
RawJsonDocument rawStored = client.get("versionedClass:1", RawJsonDocument.class);
|
||||
assertThat(versionedClass.getVersion()).isEqualTo(rawStored.cas());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void versionShouldNotUpdateOnSecondInsert() throws Exception {
|
||||
removeIfExist("versionedClass:2");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:2", "foobar");
|
||||
template.insert(versionedClass);
|
||||
long version1 = versionedClass.getVersion();
|
||||
try {
|
||||
template.insert(versionedClass);
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
//ignore, since this insert should fail
|
||||
}
|
||||
long version2 = versionedClass.getVersion();
|
||||
|
||||
assertThat(version1 > 0).isTrue();
|
||||
assertThat(version2 > 0).isTrue();
|
||||
assertThat(version2).isEqualTo(version1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveDocumentOnMatchingVersion() throws Exception {
|
||||
removeIfExist("versionedClass:3");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:3", "foobar");
|
||||
template.insert(versionedClass);
|
||||
long version1 = versionedClass.getVersion();
|
||||
|
||||
versionedClass.setField("foobar2");
|
||||
template.save(versionedClass);
|
||||
long version2 = versionedClass.getVersion();
|
||||
|
||||
assertThat(version1 > 0).isTrue();
|
||||
assertThat(version2 > 0).isTrue();
|
||||
assertThat(version2).isNotEqualTo(version1);
|
||||
|
||||
assertThat(template.findById("versionedClass:3", VersionedClass.class).getField())
|
||||
.isEqualTo("foobar2");
|
||||
}
|
||||
|
||||
@Test(expected = OptimisticLockingFailureException.class)
|
||||
public void shouldNotSaveDocumentOnNotMatchingVersion() throws Exception {
|
||||
removeIfExist("versionedClass:4");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:4", "foobar");
|
||||
template.insert(versionedClass);
|
||||
|
||||
RawJsonDocument toCompare = RawJsonDocument.create("versionedClass:4", "different");
|
||||
assertThat(client.upsert(toCompare)).isNotNull();
|
||||
|
||||
versionedClass.setField("foobar2");
|
||||
//save (aka upsert) won't error in case of CAS mismatch anymore
|
||||
template.update(versionedClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateDocumentOnMatchingVersion() throws Exception {
|
||||
removeIfExist("versionedClass:5");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:5", "foobar");
|
||||
template.insert(versionedClass);
|
||||
long version1 = versionedClass.getVersion();
|
||||
|
||||
versionedClass.setField("foobar2");
|
||||
template.update(versionedClass);
|
||||
long version2 = versionedClass.getVersion();
|
||||
|
||||
assertThat(version1 > 0).isTrue();
|
||||
assertThat(version2 > 0).isTrue();
|
||||
assertThat(version2).isNotEqualTo(version1);
|
||||
|
||||
assertThat(template.findById("versionedClass:5", VersionedClass.class).getField())
|
||||
.isEqualTo("foobar2");
|
||||
}
|
||||
|
||||
@Test(expected = OptimisticLockingFailureException.class)
|
||||
public void shouldNotUpdateDocumentOnNotMatchingVersion() throws Exception {
|
||||
removeIfExist("versionedClass:6");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:6", "foobar");
|
||||
template.insert(versionedClass);
|
||||
|
||||
RawJsonDocument toCompare = RawJsonDocument.create("versionedClass:6", "different");
|
||||
assertThat(client.upsert(toCompare)).isNotNull();
|
||||
|
||||
versionedClass.setField("foobar2");
|
||||
template.update(versionedClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadVersionPropertyOnFind() throws Exception {
|
||||
removeIfExist("versionedClass:7");
|
||||
|
||||
VersionedClass versionedClass = new VersionedClass("versionedClass:7", "foobar");
|
||||
template.insert(versionedClass);
|
||||
assertThat(versionedClass.getVersion() > 0).isTrue();
|
||||
|
||||
VersionedClass foundClass = template.findById("versionedClass:7", VersionedClass.class);
|
||||
assertThat(foundClass.getVersion()).isEqualTo(versionedClass.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateAlreadyExistingDocument() throws Exception {
|
||||
final String key = testName.getMethodName();
|
||||
removeIfExist(key);
|
||||
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
|
||||
VersionedClass initial = new VersionedClass(key, "value-0");
|
||||
template.save(initial);
|
||||
|
||||
AsyncUtils.executeConcurrently(3, new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
boolean saved = false;
|
||||
while(!saved) {
|
||||
long counterValue = counter.incrementAndGet();
|
||||
VersionedClass messageData = template.findById(key, VersionedClass.class);
|
||||
messageData.field = "value-" + counterValue;
|
||||
try {
|
||||
template.save(messageData);
|
||||
saved = true;
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
VersionedClass actual = template.findById(key, VersionedClass.class);
|
||||
|
||||
assertThat(actual.field).isNotEqualTo(initial.field);
|
||||
assertThat(actual.version).isNotEqualTo(initial.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInsertOnlyFirstDocumentAndNextAttemptsShouldFailWithOptimisticLockingException() throws Exception {
|
||||
final String key = testName.getMethodName();
|
||||
removeIfExist(key);
|
||||
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
final AtomicLong optimisticLockCounter = new AtomicLong();
|
||||
AsyncUtils.executeConcurrently(5, new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
long counterValue = counter.incrementAndGet();
|
||||
String data = "value-" + counterValue;
|
||||
VersionedClass messageData = new VersionedClass(key, data);
|
||||
try {
|
||||
template.insert(messageData);
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
optimisticLockCounter.incrementAndGet();
|
||||
}
|
||||
//should save operation throw OptimisticLockingFailureException on next attempts to save?
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assertThat(optimisticLockCounter.intValue()).isEqualTo(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-59
|
||||
*/
|
||||
@Test
|
||||
public void expiryWhenTouchOnReadDocument() throws InterruptedException {
|
||||
String id = "simple-doc-with-update-expiry-for-read";
|
||||
DocumentWithTouchOnRead doc = new DocumentWithTouchOnRead(id);
|
||||
template.save(doc);
|
||||
Thread.sleep(1000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class)).isNotNull();
|
||||
Thread.sleep(1000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class)).isNotNull();
|
||||
Thread.sleep(3000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-227
|
||||
*/
|
||||
@Test
|
||||
public void shouldRetainOrderWhenQueryingViewOrdered() {
|
||||
ViewQuery q = ViewQuery.from("test_beers", "by_name");
|
||||
q.descending().includeDocsOrdered(true);
|
||||
|
||||
String prev = null;
|
||||
List<Beer> beers = template.findByView(q, Beer.class);
|
||||
assertThat(q.isIncludeDocs()).isTrue();
|
||||
assertThat(q.isOrderRetained()).isTrue();
|
||||
assertThat(q.includeDocsTarget()).isEqualTo(RawJsonDocument.class);
|
||||
for (Beer beer : beers) {
|
||||
if (prev != null) {
|
||||
assertThat(beer.getName().compareTo(prev) < 0).describedAs(beer.getName() + " not alphabetically < to " + prev).isTrue();
|
||||
}
|
||||
prev = beer.getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document with just an id and property.
|
||||
*/
|
||||
@Document
|
||||
static class SimplePerson {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
@Field
|
||||
private final String name;
|
||||
|
||||
public SimplePerson(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document that expires in 2 seconds.
|
||||
*/
|
||||
@Document(expiry = 2)
|
||||
static class DocumentWithExpiry {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
public DocumentWithExpiry(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document that expires in 2 seconds and touchOnRead set.
|
||||
*/
|
||||
@Document(expiry = 2, touchOnRead = true)
|
||||
static class DocumentWithTouchOnRead {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
public DocumentWithTouchOnRead(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class ComplexPerson {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
@Field
|
||||
private final List<String> firstnames;
|
||||
@Field
|
||||
private final List<Integer> votes;
|
||||
|
||||
@Field
|
||||
private final Map<String, Boolean> info1;
|
||||
@Field
|
||||
private final Map<String, Integer> info2;
|
||||
|
||||
public ComplexPerson(String id, List<String> firstnames,
|
||||
List<Integer> votes, Map<String, Boolean> info1,
|
||||
Map<String, Integer> info2) {
|
||||
this.id = id;
|
||||
this.firstnames = firstnames;
|
||||
this.votes = votes;
|
||||
this.info1 = info1;
|
||||
this.info2 = info2;
|
||||
}
|
||||
|
||||
List<String> getFirstnames() {
|
||||
return firstnames;
|
||||
}
|
||||
|
||||
List<Integer> getVotes() {
|
||||
return votes;
|
||||
}
|
||||
|
||||
Map<String, Boolean> getInfo1() {
|
||||
return info1;
|
||||
}
|
||||
|
||||
Map<String, Integer> getInfo2() {
|
||||
return info2;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimpleWithLongAndInt {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private long longValue;
|
||||
private int intValue;
|
||||
|
||||
SimpleWithLongAndInt(final String id, final long longValue, int intValue) {
|
||||
this.id = id;
|
||||
this.longValue = longValue;
|
||||
this.intValue = intValue;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
long getLongValue() {
|
||||
return longValue;
|
||||
}
|
||||
|
||||
void setLongValue(final long value) {
|
||||
this.longValue = value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
public void setIntValue(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleWithEnum {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private enum Type {
|
||||
BIG
|
||||
}
|
||||
|
||||
private Type type;
|
||||
|
||||
SimpleWithEnum(final String id, final Type type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
void setType(final Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleWithClass {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private Class<Integer> integerClass;
|
||||
|
||||
private String value;
|
||||
|
||||
SimpleWithClass(final String id, final Class<Integer> integerClass) {
|
||||
this.id = id;
|
||||
this.integerClass = integerClass;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Class<Integer> getIntegerClass() {
|
||||
return integerClass;
|
||||
}
|
||||
|
||||
void setIntegerClass(final Class<Integer> integerClass) {
|
||||
this.integerClass = integerClass;
|
||||
}
|
||||
|
||||
String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static class VersionedClass {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
private String field;
|
||||
|
||||
VersionedClass(String id, String field) {
|
||||
this.id = id;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VersionedClass{" +
|
||||
"id='" + id + '\'' +
|
||||
", version=" + version +
|
||||
", field='" + field + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class FullFragment {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private long criteria;
|
||||
|
||||
private String type;
|
||||
|
||||
private String value;
|
||||
|
||||
public FullFragment(String id, long criteria, String type, String value) {
|
||||
this.id = id;
|
||||
this.criteria = criteria;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setCriteria(long criteria) {
|
||||
this.criteria = criteria;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static class Fragment {
|
||||
public String value;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Id;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestCustomKeySettings;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.core.mapping.KeySettings;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestCustomKeySettings.class)
|
||||
public class CouchbaseTemplateKeySettingsIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
if (template.keySettings() == null) {
|
||||
template.keySettings(KeySettings.build().prefix("MyAppPrefix").suffix("MyAppSuffix").delimiter("::"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAddCustomKeySettings() throws Exception {
|
||||
SimpleClass simpleClass = new SimpleClass();
|
||||
String generatedId = template.getGeneratedId(simpleClass);
|
||||
assertThat(generatedId).as("Id generated should include custom key settings")
|
||||
.isEqualTo("MyAppPrefix::myId::MyAppSuffix");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotAllowKeySettingsToBeChanged() {
|
||||
try {
|
||||
template.keySettings(KeySettings.build().prefix("MyAppPrefix").suffix("MyAppSuffix").delimiter("::"));
|
||||
fail("excepted unsupportedOperationException");
|
||||
} catch(Exception ex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimpleClass {
|
||||
@Id
|
||||
public String id = "myId";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.core;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.data.couchbase.util.ClusterType;
|
||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||
|
||||
class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
private static CouchbaseClientFactory couchbaseClientFactory;
|
||||
private CouchbaseTemplate couchbaseTemplate;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectionString(), authenticator(), bucketName());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws IOException {
|
||||
couchbaseClientFactory.close();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
CouchbaseConverter couchbaseConverter = new MappingCouchbaseConverter();
|
||||
couchbaseTemplate = new CouchbaseTemplate(couchbaseClientFactory, couchbaseConverter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void upsertAndFindById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User modified = couchbaseTemplate.upsertById(User.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertEquals(user, found);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findDocWhichDoesNotExist() {
|
||||
assertThrows(DataRetrievalFailureException.class,
|
||||
() -> couchbaseTemplate.findById(User.class).one(UUID.randomUUID().toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void upsertAndReplaceById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User modified = couchbaseTemplate.upsertById(User.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
|
||||
User toReplace = new User(modified.getId(), "some other", "lastname");
|
||||
couchbaseTemplate.replaceById(User.class).one(toReplace);
|
||||
|
||||
User loaded = couchbaseTemplate.findById(User.class).one(toReplace.getId());
|
||||
assertEquals("some other", loaded.getFirstname());
|
||||
}
|
||||
|
||||
@Test
|
||||
void upsertAndRemoveById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User modified = couchbaseTemplate.upsertById(User.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
|
||||
RemoveResult removeResult = couchbaseTemplate.removeById().one(user.getId());
|
||||
assertEquals(user.getId(), removeResult.getId());
|
||||
assertTrue(removeResult.getCas() != 0);
|
||||
assertTrue(removeResult.getMutationToken().isPresent());
|
||||
|
||||
assertThrows(DataRetrievalFailureException.class, () -> couchbaseTemplate.findById(User.class).one(user.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void insertById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User inserted = couchbaseTemplate.insertById(User.class).one(user);
|
||||
assertEquals(user, inserted);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> couchbaseTemplate.insertById(User.class).one(user));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreWhen(clusterTypes = ClusterType.MOCKED)
|
||||
void existsById() {
|
||||
String id = UUID.randomUUID().toString();
|
||||
assertFalse(couchbaseTemplate.existsById().one(id));
|
||||
|
||||
User user = new User(id, "firstname", "lastname");
|
||||
User inserted = couchbaseTemplate.insertById(User.class).one(user);
|
||||
assertEquals(user, inserted);
|
||||
|
||||
assertTrue(couchbaseTemplate.existsById().one(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.core;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.util.Capabilities;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.data.couchbase.util.ClusterType;
|
||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||
|
||||
import com.couchbase.client.core.error.IndexExistsException;
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
|
||||
@IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED)
|
||||
class CouchbaseTemplateQueryIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
private static CouchbaseClientFactory couchbaseClientFactory;
|
||||
private CouchbaseTemplate couchbaseTemplate;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectionString(), authenticator(), bucketName());
|
||||
|
||||
try {
|
||||
couchbaseClientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName());
|
||||
} catch (IndexExistsException ex) {
|
||||
// ignore, all good.
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws IOException {
|
||||
couchbaseClientFactory.close();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
CouchbaseConverter couchbaseConverter = new MappingCouchbaseConverter();
|
||||
couchbaseTemplate = new CouchbaseTemplate(couchbaseClientFactory, couchbaseConverter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByQuery() {
|
||||
User user1 = new User(UUID.randomUUID().toString(), "user1", "user1");
|
||||
User user2 = new User(UUID.randomUUID().toString(), "user2", "user2");
|
||||
|
||||
couchbaseTemplate.upsertById(User.class).all(Arrays.asList(user1, user2));
|
||||
|
||||
final List<User> foundUsers = couchbaseTemplate.findByQuery(User.class)
|
||||
.consistentWith(QueryScanConsistency.REQUEST_PLUS).all();
|
||||
|
||||
assertEquals(2, foundUsers.size());
|
||||
for (User u : foundUsers) {
|
||||
assertTrue(u.equals(user1) || u.equals(user2));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeByQuery() {
|
||||
User user1 = new User(UUID.randomUUID().toString(), "user1", "user1");
|
||||
User user2 = new User(UUID.randomUUID().toString(), "user2", "user2");
|
||||
|
||||
couchbaseTemplate.upsertById(User.class).all(Arrays.asList(user1, user2));
|
||||
|
||||
assertTrue(couchbaseTemplate.existsById().one(user1.getId()));
|
||||
assertTrue(couchbaseTemplate.existsById().one(user2.getId()));
|
||||
|
||||
couchbaseTemplate.removeByQuery(User.class).consistentWith(QueryScanConsistency.REQUEST_PLUS).all();
|
||||
|
||||
assertThrows(DataRetrievalFailureException.class, () -> couchbaseTemplate.findById(User.class).one(user1.getId()));
|
||||
assertThrows(DataRetrievalFailureException.class, () -> couchbaseTemplate.findById(User.class).one(user2.getId()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.query.Index;
|
||||
import com.couchbase.client.java.query.N1qlQuery;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.View;
|
||||
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class CouchbaseTemplateQueryListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
client.query(N1qlQuery.simple(Index.createPrimaryIndex().on(client.name())));
|
||||
}
|
||||
|
||||
private void populateTestData(Bucket client, ClusterInfo clusterInfo) {
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Beer b = new Beer("testbeer-" + i, "MyBeer" + i, true, "");
|
||||
template.save(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == "
|
||||
+ "\"org.springframework.data.couchbase.core.Beer\") { emit(doc.name, null); } }";
|
||||
View view = DefaultView.create("by_name", mapFunction);
|
||||
DesignDocument designDoc = DesignDocument.create("test_beers", Collections.singletonList(view));
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Beer b = new Beer("testbeer-" + i, "MyBeer" + i, true, "");
|
||||
template.remove(b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.core;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import com.couchbase.client.java.kv.GetResult;
|
||||
|
||||
@SpringJUnitConfig(CustomTypeKeyIntegrationTests.Config.class)
|
||||
public class CustomTypeKeyIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
private static final String CUSTOM_TYPE_KEY = "javaClass";
|
||||
|
||||
@Autowired private CouchbaseOperations operations;
|
||||
|
||||
@Autowired private CouchbaseClientFactory clientFactory;
|
||||
|
||||
@Test
|
||||
void saveSimpleEntityCorrectlyWithDifferentTypeKey() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User modified = operations.upsertById(User.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
|
||||
GetResult getResult = clientFactory.getCollection(null).get(user.getId());
|
||||
assertEquals("org.springframework.data.couchbase.domain.User",
|
||||
getResult.contentAsObject().getString(CUSTOM_TYPE_KEY));
|
||||
assertFalse(getResult.contentAsObject().containsKey(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
public String getConnectionString() {
|
||||
return connectionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return config().adminUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return config().adminPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucketName() {
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String typeKey() {
|
||||
return CUSTOM_TYPE_KEY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
|
||||
|
||||
/**
|
||||
* Test class for persisting and loading from {@link RxJavaCouchbaseTemplate}.
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
* @author Alex Derkach
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class ReactiveBeer {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Field("is_active")
|
||||
private boolean active = true;
|
||||
|
||||
@Field("desc")
|
||||
private String description;
|
||||
|
||||
public ReactiveBeer(String id, String name, Boolean active, String description) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.active = active;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Beer [id=" + id + ", name=" + name + ", active=" + active + ", description=" + description + "]";
|
||||
}
|
||||
|
||||
public ReactiveBeer setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ReactiveBeer setActive(boolean active) {
|
||||
this.active = active;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public ReactiveBeer setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import com.couchbase.client.java.query.Index;
|
||||
import com.couchbase.client.java.query.N1qlQuery;
|
||||
import com.couchbase.client.java.view.*;
|
||||
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class RxCouchbaseTemplateQueryListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
client.query(N1qlQuery.simple(Index.createPrimaryIndex().on(client.name())));
|
||||
}
|
||||
|
||||
private void populateTestData(Bucket client, ClusterInfo clusterInfo) {
|
||||
RxJavaCouchbaseTemplate template = new RxJavaCouchbaseTemplate(clusterInfo, client);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ReactiveBeer b = new ReactiveBeer("testbeer-" + i, "MyBeer" + i, true, "");
|
||||
template.save(b).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == "
|
||||
+ "\"org.springframework.data.couchbase.core.ReactiveBeer\") { emit(doc.name, null); } }";
|
||||
View view = DefaultView.create("by_name", mapFunction);
|
||||
DesignDocument designDoc = DesignDocument.create("reactive_test_beers", Collections.singletonList(view));
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
RxJavaCouchbaseTemplate template = new RxJavaCouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ReactiveBeer b = new ReactiveBeer("testbeer-" + i, "MyBeer" + i, true, "");
|
||||
template.remove(b).subscribe();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,735 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core;
|
||||
|
||||
import static com.couchbase.client.java.query.Select.select;
|
||||
import static com.couchbase.client.java.query.dsl.Expression.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.PersistTo;
|
||||
import com.couchbase.client.java.ReplicateTo;
|
||||
import com.couchbase.client.java.document.RawJsonDocument;
|
||||
import com.couchbase.client.java.query.AsyncN1qlQueryResult;
|
||||
import com.couchbase.client.java.query.N1qlParams;
|
||||
import com.couchbase.client.java.query.N1qlQuery;
|
||||
import com.couchbase.client.java.query.consistency.ScanConsistency;
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import com.couchbase.client.java.view.Stale;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import rx.observers.TestSubscriber;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
* @author Alex Derkach
|
||||
**/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(RxCouchbaseTemplateQueryListener.class)
|
||||
public class RxJavaCouchbaseTemplateIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RxJavaCouchbaseOperations template;
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String DEFAULT_ID = "reactivebeers:awesome-stout";
|
||||
private static final String DEFAULT_NAME = "The Awesome Stout";
|
||||
private static final boolean DEFAULT_ACTIVE = false;
|
||||
private static final String DEFAULT_DESCRIPTION = "";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
removeIfExist(DEFAULT_ID);
|
||||
}
|
||||
|
||||
private void removeIfExist(String key) {
|
||||
TestSubscriber<Object> subscriber = TestSubscriber.create();
|
||||
template.remove(key)
|
||||
.subscribe(subscriber);
|
||||
subscriber.awaitTerminalEvent();
|
||||
}
|
||||
|
||||
private void removeCollectionIfExist(Collection<ReactiveBeer> beers) {
|
||||
TestSubscriber<Object> subscriber = TestSubscriber.create();
|
||||
template.remove(beers, PersistTo.MASTER, ReplicateTo.NONE)
|
||||
.subscribe(subscriber);
|
||||
subscriber.awaitTerminalEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void upsertNonVersionedEntityCorrectlyWhenSaveIsCalled() throws Exception {
|
||||
String newName = DEFAULT_NAME + "Second";
|
||||
ReactiveBeer firstBeer = new ReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
ReactiveBeer secondBeer = new ReactiveBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
TestSubscriber<ReactiveBeer> firstSaveSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> secondSaveSubscriber = TestSubscriber.create();
|
||||
|
||||
template.save(firstBeer).subscribe(firstSaveSubscriber);
|
||||
template.save(secondBeer).subscribe(secondSaveSubscriber);
|
||||
|
||||
AsyncUtils.awaitCompletedWithAnyValue(firstSaveSubscriber);
|
||||
AsyncUtils.awaitCompletedWithAnyValue(secondSaveSubscriber);
|
||||
validateBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, ReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceVersionedEntityCorrectlyWhenSaveIsCalledAndCasIsNotZero() throws Exception {
|
||||
String newName = DEFAULT_NAME + "Second";
|
||||
VersionedReactiveBeer firstBeer = new VersionedReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
VersionedReactiveBeer secondBeer = new VersionedReactiveBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
long version = template.save(firstBeer).toBlocking().single().getVersion();
|
||||
assertThat(version > 0).isTrue();
|
||||
secondBeer.setVersion(version);
|
||||
long newVersion = template.save(secondBeer).toBlocking().single().getVersion();
|
||||
assertThat(newVersion > 0).isTrue();
|
||||
assertThat(newVersion).isNotEqualTo(version);
|
||||
|
||||
validateBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, VersionedReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwExceptionWhenSaveIsCalledAndCasIsMissmatched() throws Exception {
|
||||
String newName = DEFAULT_NAME + "Second";
|
||||
VersionedReactiveBeer firstBeer = new VersionedReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
VersionedReactiveBeer secondBeer = new VersionedReactiveBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
TestSubscriber<VersionedReactiveBeer> secondSaveSubscriber = TestSubscriber.create();
|
||||
|
||||
long version = template.save(firstBeer).toBlocking().single().getVersion();
|
||||
assertThat(version > 0).isTrue();
|
||||
secondBeer.setVersion(version + 1234);
|
||||
template.save(secondBeer).subscribe(secondSaveSubscriber);
|
||||
AsyncUtils.awaitError(secondSaveSubscriber, OptimisticLockingFailureException.class);
|
||||
|
||||
validateBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, VersionedReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwExceptionWhenSaveIsCalledAndCasIsZeroAndEntityAlreadyExists() throws Exception {
|
||||
String newName = DEFAULT_NAME + "Second";
|
||||
VersionedReactiveBeer firstBeer = new VersionedReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
VersionedReactiveBeer secondBeer = new VersionedReactiveBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
TestSubscriber<VersionedReactiveBeer> secondSaveSubscriber = TestSubscriber.create();
|
||||
|
||||
long version = template.save(firstBeer).toBlocking().single().getVersion();
|
||||
assertThat(version > 0).isTrue();
|
||||
template.save(secondBeer).subscribe(secondSaveSubscriber);
|
||||
AsyncUtils.awaitError(secondSaveSubscriber, OptimisticLockingFailureException.class);
|
||||
|
||||
validateBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, VersionedReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveCollectionCorrectly() throws Exception {
|
||||
Collection<ReactiveBeer> beers = new ArrayList<>();
|
||||
TestSubscriber<ReactiveBeer> testSubscriber = TestSubscriber.create();
|
||||
String name = DEFAULT_NAME;
|
||||
int collectionSize = 10000;
|
||||
for (int i = 0; i < collectionSize; i++) {
|
||||
beers.add(new ReactiveBeer("beerCollItem" + i, name + i, false, ""));
|
||||
}
|
||||
removeCollectionIfExist(beers);
|
||||
|
||||
template.save(beers).subscribe(testSubscriber);
|
||||
|
||||
AsyncUtils.awaitCompletedWithValueCount(testSubscriber, collectionSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertSimpleEntityCorrectly() throws Exception {
|
||||
TestSubscriber<ReactiveBeer> testSubscriber = TestSubscriber.create();
|
||||
ReactiveBeer beer = new ReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.insert(beer).subscribe(testSubscriber);
|
||||
|
||||
AsyncUtils.awaitCompletedWithAnyValue(testSubscriber);
|
||||
validateBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, ReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectErrorWhenDocumentExistsAndInsertIsCalled() throws Exception {
|
||||
TestSubscriber<ReactiveBeer> firstInsertSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> secondInsertSubscriber = TestSubscriber.create();
|
||||
ReactiveBeer beer = new ReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.insert(beer).subscribe(firstInsertSubscriber);
|
||||
AsyncUtils.awaitCompletedWithAnyValue(firstInsertSubscriber);
|
||||
|
||||
template.insert(beer).subscribe(secondInsertSubscriber);
|
||||
AsyncUtils.awaitError(secondInsertSubscriber, OptimisticLockingFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertCollectionCorrectly() throws Exception {
|
||||
TestSubscriber<ReactiveBeer> testSubscriber = TestSubscriber.create();
|
||||
Collection<ReactiveBeer> beers = new ArrayList<>();
|
||||
String name = DEFAULT_NAME;
|
||||
int collectionSize = 10000;
|
||||
|
||||
for (int i = 0; i < collectionSize; i++) {
|
||||
beers.add(new ReactiveBeer("beerCollItem" + i, name + i, false, ""));
|
||||
}
|
||||
removeCollectionIfExist(beers);
|
||||
|
||||
template.insert(beers).subscribe(testSubscriber);
|
||||
|
||||
AsyncUtils.awaitCompletedWithValueCount(testSubscriber, collectionSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceSimpleEntityCorrectly() throws Exception {
|
||||
TestSubscriber<VersionedReactiveBeer> firstInsertSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<VersionedReactiveBeer> replaceTestSubscriber = TestSubscriber.create();
|
||||
String newName = DEFAULT_NAME + " New";
|
||||
VersionedReactiveBeer beer = new VersionedReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.insert(beer).subscribe(firstInsertSubscriber);
|
||||
AsyncUtils.awaitCompletedWithAnyValue(firstInsertSubscriber);
|
||||
|
||||
template.findById(DEFAULT_ID, VersionedReactiveBeer.class)
|
||||
.doOnNext(v -> v.setName(newName))
|
||||
.flatMap(v -> template.update(v))
|
||||
.subscribe(replaceTestSubscriber);
|
||||
|
||||
AsyncUtils.awaitCompletedWithAnyValue(replaceTestSubscriber);
|
||||
validateBeer(DEFAULT_ID, newName, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION, VersionedReactiveBeer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectErrorWhenReplacingSimpleEntityWhichDoesNotExist() throws Exception {
|
||||
TestSubscriber<VersionedReactiveBeer> testSubscriber = TestSubscriber.create();
|
||||
VersionedReactiveBeer beer = new VersionedReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.update(beer).subscribe(testSubscriber);
|
||||
AsyncUtils.awaitError(testSubscriber, DataRetrievalFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeDocument() {
|
||||
TestSubscriber<ReactiveBeer> firstInsertSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> firstFindSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> removalTestSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> secondFindSubscriber = TestSubscriber.create();
|
||||
ReactiveBeer beer = new ReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.save(beer).subscribe(firstInsertSubscriber);
|
||||
AsyncUtils.awaitCompletedWithAnyValue(firstInsertSubscriber);
|
||||
|
||||
template.findById(DEFAULT_ID, ReactiveBeer.class).subscribe(firstFindSubscriber);
|
||||
AsyncUtils.awaitCompletedWithValueCount(firstFindSubscriber, 1);
|
||||
|
||||
template.remove(beer).subscribe(removalTestSubscriber);
|
||||
AsyncUtils.awaitCompletedWithValueCount(removalTestSubscriber, 1);
|
||||
|
||||
template.findById(DEFAULT_ID, ReactiveBeer.class).subscribe(secondFindSubscriber);
|
||||
AsyncUtils.awaitValue(secondFindSubscriber, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void storeListsAndMaps() {
|
||||
String id = "persons:lots-of-names";
|
||||
List<String> names = new ArrayList<String>();
|
||||
names.add("Michael");
|
||||
names.add("Thomas");
|
||||
names.add(null);
|
||||
List<Integer> votes = new LinkedList<Integer>();
|
||||
Map<String, Boolean> info1 = new HashMap<String, Boolean>();
|
||||
info1.put("foo", true);
|
||||
info1.put("bar", false);
|
||||
info1.put("nullValue", null);
|
||||
Map<String, Integer> info2 = new HashMap<String, Integer>();
|
||||
|
||||
ComplexPerson complex = new ComplexPerson(id, names, votes, info1, info2);
|
||||
|
||||
template.save(complex).subscribe();
|
||||
assertThat(client.get(id)).isNotNull();
|
||||
|
||||
ComplexPerson response = template.findById(id, ComplexPerson.class).toBlocking().single();
|
||||
assertThat(response.getFirstnames()).isEqualTo(names);
|
||||
assertThat(response.getVotes()).isEqualTo(votes);
|
||||
assertThat(response.getId()).isEqualTo(id);
|
||||
assertThat(response.getInfo1()).isEqualTo(info1);
|
||||
assertThat(response.getInfo2()).isEqualTo(info2);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void validFindById() {
|
||||
TestSubscriber<ReactiveBeer> saveSubscriber = TestSubscriber.create();
|
||||
TestSubscriber<ReactiveBeer> findSubscriber = TestSubscriber.create();
|
||||
|
||||
ReactiveBeer beer = new ReactiveBeer(DEFAULT_ID, DEFAULT_NAME, DEFAULT_ACTIVE, DEFAULT_DESCRIPTION);
|
||||
|
||||
template.save(beer).subscribe(saveSubscriber);
|
||||
AsyncUtils.awaitCompletedWithAnyValue(saveSubscriber);
|
||||
|
||||
template.findById(DEFAULT_ID, ReactiveBeer.class).subscribe(findSubscriber);
|
||||
AsyncUtils.awaitValue(findSubscriber, beer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadAndMapViewDocs() {
|
||||
ViewQuery query = ViewQuery.from("reactive_test_beers", "by_name");
|
||||
query.stale(Stale.FALSE);
|
||||
|
||||
final List<ReactiveBeer> beers = template.findByView(query, ReactiveBeer.class).toList().toBlocking().single();
|
||||
assertThat(beers.size() > 0).isTrue();
|
||||
|
||||
for (ReactiveBeer beer : beers) {
|
||||
assertThat(beer.getId()).isNotNull();
|
||||
assertThat(beer.getName()).isNotNull();
|
||||
assertThat(beer.getActive()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryRaw() {
|
||||
N1qlQuery query = N1qlQuery.simple(select("name").from(i(client.name())).limit(1));
|
||||
|
||||
AsyncN1qlQueryResult queryResult = template.queryN1QL(query).toBlocking().single();
|
||||
assertThat(queryResult.finalSuccess().toBlocking().single()).isTrue();
|
||||
assertThat(queryResult.rows().toList().toBlocking().single().isEmpty()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryWithMapping() {
|
||||
FullFragment ff1 = new FullFragment("fullFragment1", 1, "fullFragment", "test1");
|
||||
FullFragment ff2 = new FullFragment("fullFragment2", 2, "fullFragment", "test2");
|
||||
template.save(Arrays.asList(ff1, ff2)).subscribe();
|
||||
|
||||
N1qlQuery query = N1qlQuery.simple(select(i("value")) //"value" is a n1ql keyword apparently
|
||||
.from(i(client.name()))
|
||||
.where(x("type").eq(s("fullFragment"))
|
||||
.and(x("criteria").gt(1))),
|
||||
|
||||
N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS));
|
||||
|
||||
List<Fragment> fragments = template.findByN1QLProjection(query, Fragment.class).toList().toBlocking().single();
|
||||
assertThat(fragments).isNotNull();
|
||||
assertThat(fragments.isEmpty()).isFalse();
|
||||
assertThat(fragments.size()).isEqualTo(1);
|
||||
assertThat(fragments.get(0).value).isEqualTo("test2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeserialiseLongsAndInts() {
|
||||
final long longValue = new Date().getTime();
|
||||
final int intValue = new Random().nextInt();
|
||||
|
||||
template.save(new SimpleWithLongAndInt("simpleWithLong:simple", longValue, intValue)).toBlocking().single();
|
||||
SimpleWithLongAndInt document = template.findById("simpleWithLong:simple", SimpleWithLongAndInt.class).toBlocking().single();
|
||||
assertThat(document).isNotNull();
|
||||
assertThat(document.getLongValue()).isEqualTo(longValue);
|
||||
assertThat(document.getIntValue()).isEqualTo(intValue);
|
||||
|
||||
template.save(new SimpleWithLongAndInt("simpleWithLong:simple:other", intValue, intValue)).toBlocking().single();
|
||||
document = template.findById("simpleWithLong:simple:other", SimpleWithLongAndInt.class).toBlocking().single();
|
||||
assertThat(document).isNotNull();
|
||||
assertThat(document.getLongValue()).isEqualTo(intValue);
|
||||
assertThat(document.getIntValue()).isEqualTo(intValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeserialiseEnums() {
|
||||
SimpleWithEnum simpleWithEnum = new SimpleWithEnum("simpleWithEnum:enum", SimpleWithEnum.Type.BIG);
|
||||
template.save(simpleWithEnum).toBlocking().single();
|
||||
simpleWithEnum = template.findById("simpleWithEnum:enum", SimpleWithEnum.class).toBlocking().single();
|
||||
assertThat(simpleWithEnum).isNotNull();
|
||||
assertThat(SimpleWithEnum.Type.BIG).isEqualTo(simpleWithEnum.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeserialiseClass() {
|
||||
SimpleWithClass simpleWithClass = new SimpleWithClass("simpleWithClass:class", Integer.class);
|
||||
simpleWithClass.setValue("The dish ran away with the spoon.");
|
||||
template.save(simpleWithClass).toBlocking().single();
|
||||
simpleWithClass = template.findById("simpleWithClass:class", SimpleWithClass.class).toBlocking().single();
|
||||
assertThat(simpleWithClass).isNotNull();
|
||||
assertThat(simpleWithClass.getValue())
|
||||
.isEqualTo("The dish ran away with the spoon.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expiryWhenTouchOnReadDocument() throws InterruptedException {
|
||||
String id = "simple-doc-with-update-expiry-for-read";
|
||||
DocumentWithTouchOnRead doc = new DocumentWithTouchOnRead(id);
|
||||
template.save(doc).subscribe();
|
||||
Thread.sleep(1000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class).toBlocking()
|
||||
.single()).isNotNull();
|
||||
Thread.sleep(1000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class).toBlocking()
|
||||
.single()).isNotNull();
|
||||
Thread.sleep(3000);
|
||||
assertThat(template.findById(id, DocumentWithTouchOnRead.class).toBlocking()
|
||||
.single()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRetainOrderWhenQueryingViewOrdered() {
|
||||
ViewQuery q = ViewQuery.from("reactive_test_beers", "by_name");
|
||||
q.descending().includeDocsOrdered(true);
|
||||
|
||||
String prev = null;
|
||||
List<ReactiveBeer> beers = template.findByView(q, ReactiveBeer.class).toList().toBlocking().single();
|
||||
assertThat(q.isIncludeDocs()).isTrue();
|
||||
assertThat(q.isOrderRetained()).isTrue();
|
||||
assertThat(q.includeDocsTarget()).isEqualTo(RawJsonDocument.class);
|
||||
for (ReactiveBeer beer : beers) {
|
||||
if (prev != null) {
|
||||
assertThat(beer.getName().compareTo(prev) < 0).describedAs(beer.getName() + " not alphabetically < to " + prev).isTrue();
|
||||
}
|
||||
prev = beer.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateBeer(String id, String name, boolean active, String description, Class<?> clazz) throws IOException {
|
||||
RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
|
||||
assertThat(resultDoc).isNotNull();
|
||||
String result = resultDoc.content();
|
||||
assertThat(result).isNotNull();
|
||||
Map<String, Object> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
assertThat(resultConv.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT)).isNotNull();
|
||||
assertThat(resultConv.get("javaClass")).isNull();
|
||||
assertThat(resultConv.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT))
|
||||
.isEqualTo(clazz.getCanonicalName());
|
||||
assertThat(resultConv.get("is_active")).isEqualTo(active);
|
||||
assertThat(resultConv.get("name")).isEqualTo(name);
|
||||
assertThat(resultConv.get("desc")).isEqualTo(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document with just an id and property.
|
||||
*/
|
||||
@Document
|
||||
static class SimplePerson {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
@Field
|
||||
private final String name;
|
||||
|
||||
public SimplePerson(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document that expires in 2 seconds.
|
||||
*/
|
||||
@Document(expiry = 2)
|
||||
static class DocumentWithExpiry {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
public DocumentWithExpiry(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sample document that expires in 2 seconds and touchOnRead set.
|
||||
*/
|
||||
@Document(expiry = 2, touchOnRead = true)
|
||||
static class DocumentWithTouchOnRead {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
public DocumentWithTouchOnRead(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class ComplexPerson {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
@Field
|
||||
private final List<String> firstnames;
|
||||
@Field
|
||||
private final List<Integer> votes;
|
||||
|
||||
@Field
|
||||
private final Map<String, Boolean> info1;
|
||||
@Field
|
||||
private final Map<String, Integer> info2;
|
||||
|
||||
public ComplexPerson(String id, List<String> firstnames,
|
||||
List<Integer> votes, Map<String, Boolean> info1,
|
||||
Map<String, Integer> info2) {
|
||||
this.id = id;
|
||||
this.firstnames = firstnames;
|
||||
this.votes = votes;
|
||||
this.info1 = info1;
|
||||
this.info2 = info2;
|
||||
}
|
||||
|
||||
List<String> getFirstnames() {
|
||||
return firstnames;
|
||||
}
|
||||
|
||||
List<Integer> getVotes() {
|
||||
return votes;
|
||||
}
|
||||
|
||||
Map<String, Boolean> getInfo1() {
|
||||
return info1;
|
||||
}
|
||||
|
||||
Map<String, Integer> getInfo2() {
|
||||
return info2;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimpleWithLongAndInt {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private long longValue;
|
||||
private int intValue;
|
||||
|
||||
SimpleWithLongAndInt(final String id, final long longValue, int intValue) {
|
||||
this.id = id;
|
||||
this.longValue = longValue;
|
||||
this.intValue = intValue;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
long getLongValue() {
|
||||
return longValue;
|
||||
}
|
||||
|
||||
void setLongValue(final long value) {
|
||||
this.longValue = value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
public void setIntValue(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleWithEnum {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private enum Type {
|
||||
BIG
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
SimpleWithEnum(final String id, final Type type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
void setType(final Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleWithClass {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private Class<Integer> integerClass;
|
||||
|
||||
private String value;
|
||||
|
||||
SimpleWithClass(final String id, final Class<Integer> integerClass) {
|
||||
this.id = id;
|
||||
this.integerClass = integerClass;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Class<Integer> getIntegerClass() {
|
||||
return integerClass;
|
||||
}
|
||||
|
||||
void setIntegerClass(final Class<Integer> integerClass) {
|
||||
this.integerClass = integerClass;
|
||||
}
|
||||
|
||||
String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static class VersionedClass {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
private String field;
|
||||
|
||||
VersionedClass(String id, String field) {
|
||||
this.id = id;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VersionedClass{" +
|
||||
"id='" + id + '\'' +
|
||||
", version=" + version +
|
||||
", field='" + field + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class FullFragment {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private long criteria;
|
||||
|
||||
private String type;
|
||||
|
||||
private String value;
|
||||
|
||||
public FullFragment(String id, long criteria, String type, String value) {
|
||||
this.id = id;
|
||||
this.criteria = criteria;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setCriteria(long criteria) {
|
||||
this.criteria = criteria;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static class Fragment {
|
||||
public String value;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.RawJsonDocument;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestCustomTypeKeyConfig;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests the Java Config template around type key modification (DATACOUCH-134)
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestCustomTypeKeyConfig.class)
|
||||
public class TypeKeyIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate template;
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* see DATACOUCH-134
|
||||
*/
|
||||
@Test
|
||||
public void saveSimpleEntityCorrectlyWithDifferentTypeKey() throws Exception {
|
||||
String id = "beers:awesome-stout";
|
||||
String name = "The Awesome Stout";
|
||||
boolean active = false;
|
||||
Beer beer = new Beer(id, name, active, "");
|
||||
|
||||
template.save(beer);
|
||||
RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
|
||||
assertThat(resultDoc).isNotNull();
|
||||
String result = resultDoc.content();
|
||||
assertThat(result).isNotNull();
|
||||
Map<String, Object> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
assertThat(resultConv.get(MappingCouchbaseConverter.TYPEKEY_DEFAULT)).isNull();
|
||||
assertThat(resultConv.get("javaClass")).isNotNull();
|
||||
assertThat(resultConv.get("javaClass"))
|
||||
.isEqualTo("org.springframework.data.couchbase.core.Beer");
|
||||
assertThat(resultConv.get("is_active")).isEqualTo(false);
|
||||
assertThat(resultConv.get("name")).isEqualTo("The Awesome Stout");
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
|
||||
|
||||
/**
|
||||
* Test class for persisting and loading from {@link RxJavaCouchbaseTemplate}.
|
||||
*
|
||||
* @author Alex Derkach
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class VersionedReactiveBeer {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Field("is_active")
|
||||
private boolean active = true;
|
||||
|
||||
@Field("desc")
|
||||
private String description;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
public VersionedReactiveBeer(String id, String name, Boolean active, String description) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.active = active;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Beer [id=" + id + ", name=" + name + ", active=" + active + ", description=" + description + "]";
|
||||
}
|
||||
|
||||
public VersionedReactiveBeer setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public VersionedReactiveBeer setActive(boolean active) {
|
||||
this.active = active;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public VersionedReactiveBeer setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package org.springframework.data.couchbase.core.convert.join;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import com.couchbase.client.java.CouchbaseBucket;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.query.FetchType;
|
||||
import org.springframework.data.couchbase.core.query.HashSide;
|
||||
import org.springframework.data.couchbase.core.query.N1qlJoin;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.data.couchbase.core.convert.join.N1qlJoinResolver.N1qlJoinResolverParameters;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link N1qlJoinResolver}
|
||||
*/
|
||||
public class N1qlJoinResolverTest {
|
||||
static CouchbaseTemplate template;
|
||||
static TypeInformation<Entity> entity;
|
||||
static TypeInformation<Entity> associatedEntity;
|
||||
static String entityClassName;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
template = mock(CouchbaseTemplate.class);
|
||||
CouchbaseBucket bucket = mock(CouchbaseBucket.class);
|
||||
when(bucket.name()).thenReturn("B");
|
||||
when(template.getCouchbaseBucket()).thenReturn(bucket);
|
||||
CouchbaseConverter converter = mock(CouchbaseConverter.class);
|
||||
when(converter.getTypeKey()).thenReturn("_class");
|
||||
when(template.getConverter()).thenReturn(converter);
|
||||
entity = mock(TypeInformation.class);
|
||||
doReturn(Entity.class).when(entity).getType();
|
||||
associatedEntity = mock(TypeInformation.class);
|
||||
doReturn(Entity.class).when(associatedEntity).getType();
|
||||
entityClassName = Entity.class.getName();
|
||||
}
|
||||
|
||||
private static N1qlJoin createAnnotation(String on, String where, String index, String rightIndex, HashSide hashSide, String[] keys) {
|
||||
N1qlJoin joinDefinition = new N1qlJoin() {
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return N1qlJoin.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String on() {
|
||||
return on;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchType fetchType() {
|
||||
return FetchType.IMMEDIATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String where() {
|
||||
return where;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String index() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String rightIndex() {
|
||||
return rightIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSide hashside() {
|
||||
return hashSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] keys() {
|
||||
return keys;
|
||||
}
|
||||
};
|
||||
return joinDefinition;
|
||||
}
|
||||
|
||||
static public class Entity {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithIndex() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "leftIndex", "", HashSide.NONE, new String[0]);
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks USE INDEX(leftIndex) JOIN B rks ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithRightIndex() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "", "rightIndex", HashSide.NONE, new String[0]);
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks JOIN B rks USE INDEX(rightIndex) ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithHashProbe() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "", "", HashSide.PROBE, new String[0]);
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks JOIN B rks USE HASH(probe) ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithHashBuild() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "", "", HashSide.BUILD, new String[0]);
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks JOIN B rks USE HASH(build) ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithKeys() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "", "", HashSide.NONE, new String[]{"x", "y"});
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks JOIN B rks USE KEYS [\"x\",\"y\"] ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithWhere() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "C=D", "", "", HashSide.NONE, new String[0]);
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks JOIN B rks ON A=B" +
|
||||
" AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\" AND C=D";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildQueryWithMultipleHints() {
|
||||
N1qlJoin joinDefinition = createAnnotation("A=B", "", "leftIndex", "rightIndex", HashSide.BUILD, new String[]{"x"});
|
||||
N1qlJoinResolverParameters parameters = new N1qlJoinResolverParameters(joinDefinition, "mydoc", entity, associatedEntity);
|
||||
String statement = N1qlJoinResolver.buildQuery(template, parameters);
|
||||
String expected = "SELECT META(rks).id AS _ID, META(rks).cas AS _CAS, (rks).* FROM `B` lks USE INDEX(leftIndex) JOIN B rks USE INDEX(rightIndex)" +
|
||||
" HASH(build) KEYS [\"x\"] ON A=B AND lks._class = \"" + entityClassName + "\"" + " AND " +
|
||||
"rks._class = \"" + entityClassName + "\" WHERE META(lks).id=\"mydoc\"";
|
||||
assertThat(expected).isEqualTo(statement);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2012-2020 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
|
||||
* 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,
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.springframework.data.couchbase.core.convert.translation;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
|
||||
/**
|
||||
* Verifies the functionality of a {@link JacksonTranslationService}.
|
||||
@@ -29,39 +29,40 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class JacksonTranslationServiceTests {
|
||||
|
||||
private TranslationService service;
|
||||
private static TranslationService service;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
service = new JacksonTranslationService();
|
||||
((JacksonTranslationService) service).afterPropertiesSet();
|
||||
}
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
service = new JacksonTranslationService();
|
||||
((JacksonTranslationService) service).afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEncodeNonASCII() {
|
||||
CouchbaseDocument doc = new CouchbaseDocument("key");
|
||||
doc.put("language", "русский");
|
||||
String expected = "{\"language\":\"русский\"}";
|
||||
assertThat(service.encode(doc)).isEqualTo(expected);
|
||||
}
|
||||
@Test
|
||||
void shouldEncodeNonASCII() {
|
||||
CouchbaseDocument doc = new CouchbaseDocument("key");
|
||||
doc.put("language", "русский");
|
||||
String expected = "{\"language\":\"русский\"}";
|
||||
assertEquals(expected, service.encode(doc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDecodeNonASCII() {
|
||||
String source = "{\"language\":\"русский\"}";
|
||||
CouchbaseDocument target = new CouchbaseDocument();
|
||||
service.decode(source, target);
|
||||
assertThat(target.get("language")).isEqualTo("русский");
|
||||
}
|
||||
@Test
|
||||
void shouldDecodeNonASCII() {
|
||||
String source = "{\"language\":\"русский\"}";
|
||||
CouchbaseDocument target = new CouchbaseDocument();
|
||||
service.decode(source, target);
|
||||
assertEquals("русский", target.get("language"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDecodeAdHocFragment() {
|
||||
String source = "{\"language\":\"french\"}";
|
||||
LanguageFragment f = service.decodeFragment(source, LanguageFragment.class);
|
||||
assertThat(f).isNotNull();
|
||||
assertThat(f.language).isEqualTo("french");
|
||||
}
|
||||
@Test
|
||||
void shouldDecodeAdHocFragment() {
|
||||
String source = "{\"language\":\"french\"}";
|
||||
LanguageFragment f = service.decodeFragment(source, LanguageFragment.class);
|
||||
assertNotNull(f);
|
||||
assertEquals("french", f.language);
|
||||
}
|
||||
|
||||
static class LanguageFragment {
|
||||
public String language;
|
||||
}
|
||||
|
||||
private static class LanguageFragment {
|
||||
public String language;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,305 +16,252 @@
|
||||
|
||||
package org.springframework.data.couchbase.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Verifies the correct behavior of annotation at the class level on persistable objects.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@TestPropertySource(properties = {
|
||||
"valid.document.expiry = 10",
|
||||
"invalid.document.expiry = abc"
|
||||
})
|
||||
@ContextConfiguration(classes = BasicCouchbasePersistentEntityTests.class)
|
||||
@SpringJUnitConfig
|
||||
@TestPropertySource(properties = { "valid.document.expiry = 10", "invalid.document.expiry = abc" })
|
||||
public class BasicCouchbasePersistentEntityTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
@Autowired ConfigurableEnvironment environment;
|
||||
|
||||
@Autowired
|
||||
ConfigurableEnvironment environment;
|
||||
@Test
|
||||
void testNoExpiryByDefault() {
|
||||
CouchbasePersistentEntity<DefaultExpiry> entity = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(DefaultExpiry.class));
|
||||
|
||||
@Test
|
||||
public void testNoExpiryByDefault() {
|
||||
CouchbasePersistentEntity<DefaultExpiry> entity = new BasicCouchbasePersistentEntity<DefaultExpiry>(
|
||||
ClassTypeInformation.from(DefaultExpiry.class));
|
||||
assertThat(entity.getExpiry()).isEqualTo(0);
|
||||
}
|
||||
|
||||
assertThat(entity.getExpiry()).isEqualTo(0);
|
||||
}
|
||||
@Test
|
||||
void testDefaultExpiryUnitIsSeconds() {
|
||||
CouchbasePersistentEntity<DefaultExpiryUnit> entity = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(DefaultExpiryUnit.class));
|
||||
|
||||
@Test
|
||||
public void testDefaultExpiryUnitIsSeconds() {
|
||||
CouchbasePersistentEntity<DefaultExpiryUnit> entity = new BasicCouchbasePersistentEntity<DefaultExpiryUnit>(
|
||||
ClassTypeInformation.from(DefaultExpiryUnit.class));
|
||||
assertThat(entity.getExpiry()).isEqualTo(78);
|
||||
}
|
||||
|
||||
assertThat(entity.getExpiry()).isEqualTo(78);
|
||||
}
|
||||
@Test
|
||||
void testLargeExpiry30DaysStillInSeconds() {
|
||||
CouchbasePersistentEntity<LimitDaysExpiry> entityUnder = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(LimitDaysExpiry.class));
|
||||
assertThat(entityUnder.getExpiry()).isEqualTo(30 * 24 * 60 * 60);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeExpiry30DaysStillInSeconds() {
|
||||
CouchbasePersistentEntity<LimitDaysExpiry> entityUnder = new BasicCouchbasePersistentEntity<LimitDaysExpiry>(
|
||||
ClassTypeInformation.from(LimitDaysExpiry.class));
|
||||
assertThat(entityUnder.getExpiry()).isEqualTo(30 * 24 * 60 * 60);
|
||||
}
|
||||
@Test
|
||||
void testLargeExpiry31DaysIsConvertedToUnixUtcTime() {
|
||||
CouchbasePersistentEntity<OverLimitDaysExpiry> entityOver = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(OverLimitDaysExpiry.class));
|
||||
|
||||
@Test
|
||||
public void testLargeExpiry31DaysIsConvertedToUnixUtcTime() {
|
||||
CouchbasePersistentEntity<OverLimitDaysExpiry> entityOver = new BasicCouchbasePersistentEntity<OverLimitDaysExpiry>(
|
||||
ClassTypeInformation.from(OverLimitDaysExpiry.class));
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
Date dateOver = new Date(expiryOver * 1000L);
|
||||
System.out.println(entityOver + " => " + dateOver);
|
||||
@Test
|
||||
void testLargeExpiryExpression31DaysIsConvertedToUnixUtcTime() {
|
||||
BasicCouchbasePersistentEntity<OverLimitDaysExpiryExpression> entityOver = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(OverLimitDaysExpiryExpression.class));
|
||||
entityOver.setEnvironment(environment);
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH))
|
||||
.isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY))
|
||||
.isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
@Test
|
||||
public void testLargeExpiryExpression31DaysIsConvertedToUnixUtcTime() {
|
||||
BasicCouchbasePersistentEntity<OverLimitDaysExpiryExpression> entityOver = new BasicCouchbasePersistentEntity<OverLimitDaysExpiryExpression>(
|
||||
ClassTypeInformation.from(OverLimitDaysExpiryExpression.class));
|
||||
entityOver.setEnvironment(environment);
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
@Test
|
||||
void testLargeExpiry31DaysInSecondsIsConvertedToUnixUtcTime() {
|
||||
CouchbasePersistentEntity<OverLimitSecondsExpiry> entityOver = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(OverLimitSecondsExpiry.class));
|
||||
|
||||
Date dateOver = new Date(expiryOver * 1000L);
|
||||
System.out.println(entityOver + " => " + dateOver);
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH))
|
||||
.isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY))
|
||||
.isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY)).isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeExpiry31DaysInSecondsIsConvertedToUnixUtcTime() {
|
||||
CouchbasePersistentEntity<OverLimitSecondsExpiry> entityOver = new BasicCouchbasePersistentEntity<OverLimitSecondsExpiry>(
|
||||
ClassTypeInformation.from(OverLimitSecondsExpiry.class));
|
||||
@Test
|
||||
void doesNotUseGetExpiry() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocument.class).getExpiry()).isEqualTo(0);
|
||||
}
|
||||
|
||||
int expiryOver = entityOver.getExpiry();
|
||||
Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
expected.add(Calendar.DAY_OF_YEAR, 31);
|
||||
@Test
|
||||
void usesGetExpiry() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithExpiry.class).getExpiry()).isEqualTo(10);
|
||||
}
|
||||
|
||||
Date dateOver = new Date(expiryOver * 1000L);
|
||||
System.out.println(entityOver + " => " + dateOver);
|
||||
@Test
|
||||
void doesNotUseIsUpdateExpiryForRead() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocument.class).isTouchOnRead()).isFalse();
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithExpiry.class).isTouchOnRead()).isFalse();
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
calendar.add(Calendar.SECOND, expiryOver);
|
||||
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(expected.get(Calendar.YEAR));
|
||||
assertThat(calendar.get(Calendar.MONTH)).isEqualTo(expected.get(Calendar.MONTH));
|
||||
assertThat(calendar.get(Calendar.DAY_OF_MONTH))
|
||||
.isEqualTo(expected.get(Calendar.DAY_OF_MONTH));
|
||||
assertThat(calendar.get(Calendar.HOUR_OF_DAY))
|
||||
.isEqualTo(expected.get(Calendar.HOUR_OF_DAY));
|
||||
assertThat(calendar.get(Calendar.MINUTE)).isEqualTo(expected.get(Calendar.MINUTE));
|
||||
assertThat(calendar.get(Calendar.SECOND)).isEqualTo(expected.get(Calendar.SECOND));
|
||||
}
|
||||
@Test
|
||||
void usesTouchOnRead() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithTouchOnRead.class).isTouchOnRead()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotUseGetExpiry() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocument.class).getExpiry())
|
||||
.isEqualTo(0);
|
||||
}
|
||||
@Test
|
||||
void usesGetExpiryExpression() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(ConstantExpiryExpression.class).getExpiry()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesGetExpiry() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithExpiry.class)
|
||||
.getExpiry()).isEqualTo(10);
|
||||
}
|
||||
@Test
|
||||
void usesGetExpiryFromValidExpression() {
|
||||
assertThat(getBasicCouchbasePersistentEntity(ExpiryWithValidExpression.class).getExpiry()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotUseIsUpdateExpiryForRead() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocument.class).isTouchOnRead())
|
||||
.isFalse();
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithExpiry.class)
|
||||
.isTouchOnRead()).isFalse();
|
||||
}
|
||||
@Test
|
||||
void doesNotAllowUseExpiryFromInvalidExpression() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> getBasicCouchbasePersistentEntity(ExpiryWithInvalidExpression.class).getExpiry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesTouchOnRead() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(SimpleDocumentWithTouchOnRead.class)
|
||||
.isTouchOnRead()).isTrue();
|
||||
}
|
||||
@Test
|
||||
void usesGetExpiryExpressionAndRespectsPropertyUpdates() {
|
||||
BasicCouchbasePersistentEntity entity = getBasicCouchbasePersistentEntity(ExpiryWithValidExpression.class);
|
||||
assertThat(entity.getExpiry()).isEqualTo(10);
|
||||
|
||||
@Test
|
||||
public void usesGetExpiryExpression() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(ConstantExpiryExpression.class)
|
||||
.getExpiry()).isEqualTo(10);
|
||||
}
|
||||
environment.getPropertySources().addFirst(new MockPropertySource().withProperty("valid.document.expiry", "20"));
|
||||
assertThat(entity.getExpiry()).isEqualTo(20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesGetExpiryFromValidExpression() throws Exception {
|
||||
assertThat(getBasicCouchbasePersistentEntity(ExpiryWithValidExpression.class)
|
||||
.getExpiry()).isEqualTo(10);
|
||||
}
|
||||
@Test
|
||||
void failsIfExpiryExpressionMissesRequiredProperty() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> getBasicCouchbasePersistentEntity(ExpiryWithMissingProperty.class).getExpiry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotAllowUseExpiryFromInvalidExpression() throws Exception {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("Invalid Integer value for expiry expression: abc");
|
||||
assertThat(getBasicCouchbasePersistentEntity(ExpiryWithInvalidExpression.class)
|
||||
.getExpiry()).isEqualTo(10);
|
||||
}
|
||||
@Test
|
||||
void doesNotAllowUseExpiryAndExpressionSimultaneously() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> getBasicCouchbasePersistentEntity(ExpiryAndExpression.class).getExpiry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesGetExpiryExpressionAndRespectsPropertyUpdates() throws Exception {
|
||||
BasicCouchbasePersistentEntity entity = getBasicCouchbasePersistentEntity(ExpiryWithValidExpression.class);
|
||||
assertThat(entity.getExpiry()).isEqualTo(10);
|
||||
private BasicCouchbasePersistentEntity getBasicCouchbasePersistentEntity(Class<?> clazz) {
|
||||
BasicCouchbasePersistentEntity basicCouchbasePersistentEntity = new BasicCouchbasePersistentEntity(
|
||||
ClassTypeInformation.from(clazz));
|
||||
basicCouchbasePersistentEntity.setEnvironment(environment);
|
||||
return basicCouchbasePersistentEntity;
|
||||
}
|
||||
|
||||
environment.getPropertySources().addFirst(new MockPropertySource().withProperty("valid.document.expiry", "20"));
|
||||
assertThat(entity.getExpiry()).isEqualTo(20);
|
||||
}
|
||||
@Configuration
|
||||
static class Config {}
|
||||
|
||||
@Test
|
||||
public void failsIfExpiryExpressionMissesRequiredProperty() {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("Could not resolve placeholder 'missing.expiry'");
|
||||
getBasicCouchbasePersistentEntity(ExpiryWithMissingProperty.class).getExpiry();
|
||||
}
|
||||
public static class SimpleDocument {}
|
||||
|
||||
@Test
|
||||
public void doesNotAllowUseExpiryAndExpressionSimultaneously() throws Exception {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("You cannot use 'expiry' and 'expiryExpression' at the same time");
|
||||
expectedException.expectMessage(ExpiryAndExpression.class.getName());
|
||||
getBasicCouchbasePersistentEntity(ExpiryAndExpression.class).getExpiry();
|
||||
}
|
||||
@Document(expiry = 10)
|
||||
public static class SimpleDocumentWithExpiry {}
|
||||
|
||||
private BasicCouchbasePersistentEntity getBasicCouchbasePersistentEntity(Class<?> clazz) {
|
||||
BasicCouchbasePersistentEntity basicCouchbasePersistentEntity = new BasicCouchbasePersistentEntity(ClassTypeInformation.from(clazz));
|
||||
basicCouchbasePersistentEntity.setEnvironment(environment);
|
||||
return basicCouchbasePersistentEntity;
|
||||
}
|
||||
@Document(expiry = 10, touchOnRead = true)
|
||||
public static class SimpleDocumentWithTouchOnRead {}
|
||||
|
||||
public static class SimpleDocument {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test default expiry.
|
||||
*/
|
||||
@Document
|
||||
private class DefaultExpiry {}
|
||||
|
||||
@Document(expiry = 10)
|
||||
public static class SimpleDocumentWithExpiry {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test default expiry unit.
|
||||
*/
|
||||
@Document(expiry = 78)
|
||||
private class DefaultExpiryUnit {}
|
||||
|
||||
@Document(expiry = 10, touchOnRead = true)
|
||||
public static class SimpleDocumentWithTouchOnRead {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test limit expiry.
|
||||
*/
|
||||
@Document(expiry = 30, expiryUnit = TimeUnit.DAYS)
|
||||
private class LimitDaysExpiry {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test default expiry.
|
||||
*/
|
||||
@Document
|
||||
private class DefaultExpiry {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry.
|
||||
*/
|
||||
@Document(expiry = 31, expiryUnit = TimeUnit.DAYS)
|
||||
public class OverLimitDaysExpiry {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test default expiry unit.
|
||||
*/
|
||||
@Document(expiry = 78)
|
||||
private class DefaultExpiryUnit {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry defined as an expression
|
||||
*/
|
||||
@Document(expiryExpression = "${document.expiry.larger.than.30days:31}", expiryUnit = TimeUnit.DAYS)
|
||||
public class OverLimitDaysExpiryExpression {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test limit expiry.
|
||||
*/
|
||||
@Document(expiry = 30, expiryUnit = TimeUnit.DAYS)
|
||||
private class LimitDaysExpiry {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry, when expressed in default time unit (SECONDS).
|
||||
*/
|
||||
@Document(expiry = 31 * 24 * 60 * 60)
|
||||
public class OverLimitSecondsExpiry {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry.
|
||||
*/
|
||||
@Document(expiry = 31, expiryUnit = TimeUnit.DAYS)
|
||||
public class OverLimitDaysExpiry {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test constant expiry expression
|
||||
*/
|
||||
@Document(expiryExpression = "10")
|
||||
private class ConstantExpiryExpression {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry defined as an expression
|
||||
*/
|
||||
@Document(expiryExpression = "${document.expiry.larger.than.30days:31}", expiryUnit = TimeUnit.DAYS)
|
||||
public class OverLimitDaysExpiryExpression {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test valid expiry expression by resolving simple property from environment
|
||||
*/
|
||||
@Document(expiryExpression = "${valid.document.expiry}")
|
||||
private class ExpiryWithValidExpression {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test larger than 30 days expiry, when expressed in default time unit (SECONDS).
|
||||
*/
|
||||
@Document(expiry = 31 * 24 * 60 * 60)
|
||||
public class OverLimitSecondsExpiry {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test invalid expiry expression
|
||||
*/
|
||||
@Document(expiryExpression = "${invalid.document.expiry}")
|
||||
private class ExpiryWithInvalidExpression {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test constant expiry expression
|
||||
*/
|
||||
@Document(expiryExpression = "10")
|
||||
private class ConstantExpiryExpression {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test expiry expression logic failure to resolve property placeholder
|
||||
*/
|
||||
@Document(expiryExpression = "${missing.expiry}")
|
||||
private class ExpiryWithMissingProperty {}
|
||||
|
||||
/**
|
||||
* Simple POJO to test valid expiry expression by resolving simple property from environment
|
||||
*/
|
||||
@Document(expiryExpression = "${valid.document.expiry}")
|
||||
private class ExpiryWithValidExpression {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO to test invalid expiry expression
|
||||
*/
|
||||
@Document(expiryExpression = "${invalid.document.expiry}")
|
||||
private class ExpiryWithInvalidExpression {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO to test expiry expression logic failure to resolve property placeholder
|
||||
*/
|
||||
@Document(expiryExpression = "${missing.expiry}")
|
||||
private class ExpiryWithMissingProperty {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO to test that expiry and expiry expression cannot be used simultaneously
|
||||
*/
|
||||
@Document(expiry = 10, expiryExpression = "10")
|
||||
private class ExpiryAndExpression {
|
||||
}
|
||||
/**
|
||||
* Simple POJO to test that expiry and expiry expression cannot be used simultaneously
|
||||
*/
|
||||
@Document(expiry = 10, expiryExpression = "10")
|
||||
private class ExpiryAndExpression {}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.data.couchbase.core.mapping;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
@@ -28,8 +29,6 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Verifies the correct behavior of properties on persistable objects.
|
||||
*
|
||||
@@ -38,133 +37,77 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class BasicCouchbasePersistentPropertyTests {
|
||||
|
||||
/**
|
||||
* Holds the entity to test against (contains the properties).
|
||||
*/
|
||||
CouchbasePersistentEntity<Beer> entity;
|
||||
/**
|
||||
* Holds the entity to test against (contains the properties).
|
||||
*/
|
||||
CouchbasePersistentEntity<Beer> entity;
|
||||
|
||||
/**
|
||||
* Create an instance of the demo entity.
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
entity = new BasicCouchbasePersistentEntity<Beer>(
|
||||
ClassTypeInformation.from(Beer.class));
|
||||
}
|
||||
/**
|
||||
* Create an instance of the demo entity.
|
||||
*/
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
entity = new BasicCouchbasePersistentEntity<>(ClassTypeInformation.from(Beer.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the name of the property without annotations.
|
||||
*/
|
||||
@Test
|
||||
public void usesPropertyFieldName() {
|
||||
Field field = ReflectionUtils.findField(Beer.class, "description");
|
||||
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("description");
|
||||
}
|
||||
/**
|
||||
* Verifies the name of the property without annotations.
|
||||
*/
|
||||
@Test
|
||||
void usesPropertyFieldName() {
|
||||
Field field = ReflectionUtils.findField(Beer.class, "description");
|
||||
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("description");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the name of the property with custom name annotation.
|
||||
*/
|
||||
@Test
|
||||
public void usesAnnotatedFieldName() {
|
||||
Field field = ReflectionUtils.findField(Beer.class, "name");
|
||||
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("foobar");
|
||||
}
|
||||
/**
|
||||
* Verifies the name of the property with custom name annotation.
|
||||
*/
|
||||
@Test
|
||||
void usesAnnotatedFieldName() {
|
||||
Field field = ReflectionUtils.findField(Beer.class, "name");
|
||||
assertThat(getPropertyFor(field).getFieldName()).isEqualTo("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefersSpringIdAnnotation() {
|
||||
BasicCouchbasePersistentEntity<Beer> test = new BasicCouchbasePersistentEntity<Beer>(
|
||||
ClassTypeInformation.from(Beer.class));
|
||||
@Test
|
||||
void testSdkIdAnnotationEvaluatedAfterSpringIdAnnotationIsIgnored() {
|
||||
BasicCouchbasePersistentEntity<Beer> test = new BasicCouchbasePersistentEntity<>(
|
||||
ClassTypeInformation.from(Beer.class));
|
||||
Field springIdField = ReflectionUtils.findField(Beer.class, "springId");
|
||||
CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField);
|
||||
|
||||
Field sdkIdField = ReflectionUtils.findField(Beer.class, "sdkId");
|
||||
CouchbasePersistentProperty sdkIdProperty = getPropertyFor(sdkIdField);
|
||||
Field springIdField = ReflectionUtils.findField(Beer.class, "springId");
|
||||
CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField);
|
||||
test.addPersistentProperty(sdkIdProperty);
|
||||
test.addPersistentProperty(springIdProperty);
|
||||
// here this simulates the order in which the annotations would be found
|
||||
// when "overriding" Spring @Id with SDK's @Id...
|
||||
test.addPersistentProperty(springIdProperty);
|
||||
|
||||
assertThat(sdkIdProperty.getFieldName()).isEqualTo("sdkId");
|
||||
assertThat(springIdProperty.getFieldName()).isEqualTo("springId");
|
||||
assertThat(test.getIdProperty()).isEqualTo(springIdProperty);
|
||||
}
|
||||
|
||||
assertThat(sdkIdProperty.isIdProperty()).isTrue();
|
||||
assertThat(springIdProperty.isIdProperty()).isTrue();
|
||||
|
||||
CouchbasePersistentProperty property = test.getIdProperty();
|
||||
assertThat(property).isEqualTo(springIdProperty);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptsSdkIdAnnotation() {
|
||||
BasicCouchbasePersistentEntity<SdkIdentified> test = new BasicCouchbasePersistentEntity<SdkIdentified>(
|
||||
ClassTypeInformation.from(SdkIdentified.class));
|
||||
Field id = ReflectionUtils.findField(SdkIdentified.class, "id");
|
||||
CouchbasePersistentProperty idProperty = getPropertyFor(id);
|
||||
test.addPersistentProperty(idProperty);
|
||||
|
||||
CouchbasePersistentProperty property = test.getIdProperty();
|
||||
assertThat(property).isEqualTo(idProperty);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSdkIdAnnotationEvaluatedAfterSpringIdAnnotationIsIgnored() {
|
||||
BasicCouchbasePersistentEntity<Beer> test = new BasicCouchbasePersistentEntity<Beer>(
|
||||
ClassTypeInformation.from(Beer.class));
|
||||
Field sdkIdField = ReflectionUtils.findField(Beer.class, "sdkId");
|
||||
CouchbasePersistentProperty sdkIdProperty = getPropertyFor(sdkIdField);
|
||||
Field springIdField = ReflectionUtils.findField(Beer.class, "springId");
|
||||
CouchbasePersistentProperty springIdProperty = getPropertyFor(springIdField);
|
||||
|
||||
//here this simulates the order in which the annotations would be found
|
||||
// when "overriding" Spring @Id with SDK's @Id...
|
||||
test.addPersistentProperty(springIdProperty);
|
||||
|
||||
assertThat(test.getIdProperty()).isEqualTo(springIdProperty);
|
||||
|
||||
test.addPersistentProperty(sdkIdProperty);
|
||||
assertThat(test.getIdProperty()).isEqualTo(springIdProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a property out of the field.
|
||||
*
|
||||
* @param field the field to retrieve the properties from.
|
||||
* @return the actual BasicCouchbasePersistentProperty instance.
|
||||
*/
|
||||
private CouchbasePersistentProperty getPropertyFor(Field field) {
|
||||
/**
|
||||
* Helper method to create a property out of the field.
|
||||
*
|
||||
* @param field the field to retrieve the properties from.
|
||||
* @return the actual BasicCouchbasePersistentProperty instance.
|
||||
*/
|
||||
private CouchbasePersistentProperty getPropertyFor(Field field) {
|
||||
|
||||
ClassTypeInformation<?> type = ClassTypeInformation.from(field.getDeclaringClass());
|
||||
|
||||
return new BasicCouchbasePersistentProperty(Property.of(type, field), entity, SimpleTypeHolder.DEFAULT,
|
||||
PropertyNameFieldNamingStrategy.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO to test attribute properties and annotations.
|
||||
*/
|
||||
public class Beer {
|
||||
/**
|
||||
* Simple POJO to test attribute properties and annotations.
|
||||
*/
|
||||
public class Beer {
|
||||
|
||||
@com.couchbase.client.java.repository.annotation.Id
|
||||
private String sdkId;
|
||||
@org.springframework.data.couchbase.core.mapping.Field String name;
|
||||
String description;
|
||||
@Id private String springId;
|
||||
|
||||
@Id
|
||||
private String springId;
|
||||
public String getId() {
|
||||
return springId;
|
||||
}
|
||||
}
|
||||
|
||||
@com.couchbase.client.java.repository.annotation.Field("foobar")
|
||||
String name;
|
||||
|
||||
String description;
|
||||
|
||||
public String getId() {
|
||||
return springId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO to test that a single ID property from the SDK is taken into account.
|
||||
*/
|
||||
public class SdkIdentified {
|
||||
@com.couchbase.client.java.repository.annotation.Id
|
||||
private String id;
|
||||
|
||||
String value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core.mapping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.TestContainerResource;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class CustomConverterIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private MappingCouchbaseConverter converter;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
|
||||
private TestUUIDRepository repository;
|
||||
|
||||
@WritingConverter
|
||||
public enum UUIDToStringConverter implements Converter<UUID, String> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String convert(UUID source) {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
public enum StringToUUIDConverter implements Converter<String, UUID> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public UUID convert(String source) {
|
||||
return UUID.fromString(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(Arrays.asList(UUIDToStringConverter.INSTANCE, StringToUUIDConverter.INSTANCE)));
|
||||
converter.afterPropertiesSet();
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, TestUUIDRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdConversion() {
|
||||
TestUUID doc = new TestUUID();
|
||||
doc.id = UUID.randomUUID();
|
||||
repository.save(doc);
|
||||
repository.findById(doc.id);
|
||||
}
|
||||
}
|
||||
@@ -16,30 +16,20 @@
|
||||
|
||||
package org.springframework.data.couchbase.core.mapping;
|
||||
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.couchbase.UnitTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import com.couchbase.client.java.repository.annotation.Id;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests to verify custom mapping logic.
|
||||
@@ -47,142 +37,130 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Michael Nitschinger
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = UnitTestApplicationConfig.class)
|
||||
public class CustomConvertersTests {
|
||||
|
||||
@Autowired
|
||||
private MappingCouchbaseConverter converter;
|
||||
private MappingCouchbaseConverter converter;
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(Collections.emptyList()));
|
||||
}
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
converter = new MappingCouchbaseConverter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldWriteWithCustomConverter() {
|
||||
List<Object> converters = new ArrayList<Object>();
|
||||
converters.add(DateToStringConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
@Test
|
||||
void shouldWriteWithCustomConverter() {
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.add(DateToStringConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
Date date = new Date();
|
||||
BlogPost post = new BlogPost();
|
||||
post.created = date;
|
||||
Date date = new Date();
|
||||
BlogPost post = new BlogPost();
|
||||
post.created = date;
|
||||
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
converter.write(post, doc);
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
converter.write(post, doc);
|
||||
|
||||
assertThat(doc.getPayload().get("created")).isEqualTo(date.toString());
|
||||
}
|
||||
assertThat(doc.getPayload().get("created")).isEqualTo(date.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReadWithCustomConverter() {
|
||||
List<Object> converters = new ArrayList<Object>();
|
||||
converters.add(IntegerToStringConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
@Test
|
||||
void shouldReadWithCustomConverter() {
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.add(IntegerToStringConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
doc.getPayload().put("content", 10);
|
||||
Counter loaded = converter.read(Counter.class, doc);
|
||||
assertThat(loaded.content).isEqualTo("even");
|
||||
}
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
doc.getPayload().put("content", 10);
|
||||
Counter loaded = converter.read(Counter.class, doc);
|
||||
assertThat(loaded.content).isEqualTo("even");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldWriteConvertFullDocument() {
|
||||
List<Object> converters = new ArrayList<Object>();
|
||||
converters.add(BlogPostToCouchbaseDocumentConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
@Test
|
||||
void shouldWriteConvertFullDocument() {
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.add(BlogPostToCouchbaseDocumentConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
BlogPost post = new BlogPost();
|
||||
post.id = "foobar";
|
||||
post.title = "The Foo of the Bar";
|
||||
BlogPost post = new BlogPost();
|
||||
post.id = "foobar";
|
||||
post.title = "The Foo of the Bar";
|
||||
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
converter.write(post, doc);
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
converter.write(post, doc);
|
||||
|
||||
assertThat(doc.getPayload().get("title")).isEqualTo("The Foo of the Bar");
|
||||
assertThat(doc.getPayload().get("slug")).isEqualTo("the_foo_of_the_bar");
|
||||
}
|
||||
assertThat(doc.getPayload().get("title")).isEqualTo("The Foo of the Bar");
|
||||
assertThat(doc.getPayload().get("slug")).isEqualTo("the_foo_of_the_bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReadConvertFullDocument() {
|
||||
List<Object> converters = new ArrayList<Object>();
|
||||
converters.add(CouchbaseDocumentToBlogPostConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
@Test
|
||||
void shouldReadConvertFullDocument() {
|
||||
List<Object> converters = new ArrayList<>();
|
||||
converters.add(CouchbaseDocumentToBlogPostConverter.INSTANCE);
|
||||
converter.setCustomConversions(new CouchbaseCustomConversions(converters));
|
||||
converter.afterPropertiesSet();
|
||||
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
doc.getPayload().put("title", "My Title");
|
||||
CouchbaseDocument doc = new CouchbaseDocument();
|
||||
doc.getPayload().put("title", "My Title");
|
||||
|
||||
BlogPost loaded = converter.read(BlogPost.class, doc);
|
||||
assertThat(loaded.id).isEqualTo("modified");
|
||||
assertThat(loaded.title).isEqualTo("My Title!!");
|
||||
}
|
||||
BlogPost loaded = converter.read(BlogPost.class, doc);
|
||||
assertThat(loaded.id).isEqualTo("modified");
|
||||
assertThat(loaded.title).isEqualTo("My Title!!");
|
||||
}
|
||||
|
||||
public static class BlogPost {
|
||||
@Id //also tests DATACOUCH-145 (this is SDK's @Id)
|
||||
public String id = "key";
|
||||
public enum IntegerToStringConverter implements Converter<Integer, String> {
|
||||
INSTANCE;
|
||||
|
||||
@Field
|
||||
public Date created;
|
||||
@Override
|
||||
public String convert(Integer source) {
|
||||
return source % 2 == 0 ? "even" : "odd";
|
||||
}
|
||||
}
|
||||
|
||||
@Field
|
||||
public String title;
|
||||
public enum DateToStringConverter implements Converter<Date, String> {
|
||||
INSTANCE;
|
||||
|
||||
}
|
||||
@Override
|
||||
public String convert(Date source) {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public class Counter {
|
||||
@Field
|
||||
public String content;
|
||||
}
|
||||
@WritingConverter
|
||||
public enum BlogPostToCouchbaseDocumentConverter implements Converter<BlogPost, CouchbaseDocument> {
|
||||
INSTANCE;
|
||||
|
||||
public static enum IntegerToStringConverter implements Converter<Integer, String> {
|
||||
INSTANCE;
|
||||
@Override
|
||||
public CouchbaseDocument convert(BlogPost source) {
|
||||
return new CouchbaseDocument().setId(source.id).put("title", source.title).put("slug",
|
||||
source.title.toLowerCase().replaceAll(" ", "_"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convert(Integer source) {
|
||||
return source % 2 == 0 ? "even" : "odd";
|
||||
}
|
||||
}
|
||||
@ReadingConverter
|
||||
public enum CouchbaseDocumentToBlogPostConverter implements Converter<CouchbaseDocument, BlogPost> {
|
||||
INSTANCE;
|
||||
|
||||
public static enum DateToStringConverter implements Converter<Date, String> {
|
||||
INSTANCE;
|
||||
@Override
|
||||
public BlogPost convert(CouchbaseDocument source) {
|
||||
BlogPost post = new BlogPost();
|
||||
post.id = "modified";
|
||||
post.title = source.getPayload().get("title") + "!!";
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
public static Format FORMATTER = new SimpleDateFormat("yyyy HH");
|
||||
public static class BlogPost {
|
||||
@Id public String id = "key";
|
||||
|
||||
@Override
|
||||
public String convert(Date source) {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
@Field public Date created;
|
||||
|
||||
@WritingConverter
|
||||
public static enum BlogPostToCouchbaseDocumentConverter implements Converter<BlogPost, CouchbaseDocument> {
|
||||
INSTANCE;
|
||||
@Field public String title;
|
||||
|
||||
@Override
|
||||
public CouchbaseDocument convert(BlogPost source) {
|
||||
return new CouchbaseDocument()
|
||||
.setId(source.id)
|
||||
.put("title", source.title)
|
||||
.put("slug", source.title.toLowerCase().replaceAll(" ", "_"));
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
public static enum CouchbaseDocumentToBlogPostConverter implements Converter<CouchbaseDocument, BlogPost> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public BlogPost convert(CouchbaseDocument source) {
|
||||
BlogPost post = new BlogPost();
|
||||
post.id = "modified";
|
||||
post.title = source.getPayload().get("title") + "!!";
|
||||
return post;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Counter {
|
||||
@Field public String content;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core.mapping;
|
||||
|
||||
import java.util.UUID;
|
||||
import com.couchbase.client.java.repository.annotation.Id;
|
||||
import org.springframework.data.couchbase.core.query.ViewIndexed;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@ViewIndexed(designDoc = "testUUID", viewName = "all")
|
||||
public class TestUUID {
|
||||
@Id
|
||||
public UUID id;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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.core.mapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public interface TestUUIDRepository extends CouchbaseRepository<TestUUID, UUID> {
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core.mapping.event;
|
||||
|
||||
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.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = EventContextConfiguration.class)
|
||||
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
|
||||
public class AbstractCouchbaseEventListenerTests {
|
||||
|
||||
@Autowired
|
||||
private CouchbaseTemplate couchbaseTemplate;
|
||||
|
||||
@Autowired
|
||||
private SimpleMappingEventListener eventListener;
|
||||
|
||||
@Test
|
||||
public void shouldEmitEvents() {
|
||||
int beforeSave = eventListener.onBeforeSaveEvents.size();
|
||||
int afterSave = eventListener.onAfterSaveEvents.size();
|
||||
int beforeConvert = eventListener.onBeforeConvertEvents.size();
|
||||
|
||||
couchbaseTemplate.save(new User("john smith", 18));
|
||||
|
||||
assertThat(eventListener.onBeforeSaveEvents.size()).isEqualTo(beforeSave + 1);
|
||||
assertThat(eventListener.onAfterSaveEvents.size()).isEqualTo(afterSave + 1);
|
||||
assertThat(eventListener.onBeforeConvertEvents.size()).isEqualTo(beforeConvert + 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core.mapping.event;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.UnitTestApplicationConfig;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@Configuration
|
||||
public class EventContextConfiguration extends UnitTestApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public LocalValidatorFactoryBean validator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ValidatingCouchbaseEventListener validatingCouchbaseEventListener() {
|
||||
return new ValidatingCouchbaseEventListener(validator());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleMappingEventListener simpleMappingEventListener() {
|
||||
return new SimpleMappingEventListener();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core.mapping.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class SimpleMappingEventListener extends AbstractCouchbaseEventListener<Object> {
|
||||
|
||||
public final ArrayList<BeforeConvertEvent<Object>> onBeforeConvertEvents = new ArrayList<BeforeConvertEvent<Object>>();
|
||||
public final ArrayList<BeforeSaveEvent<Object>> onBeforeSaveEvents = new ArrayList<BeforeSaveEvent<Object>>();
|
||||
public final ArrayList<AfterSaveEvent<Object>> onAfterSaveEvents = new ArrayList<AfterSaveEvent<Object>>();
|
||||
|
||||
@Override
|
||||
public void onBeforeConvert(Object source) {
|
||||
onBeforeConvertEvents.add(new BeforeConvertEvent<Object>(source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeSave(Object source, CouchbaseDocument doc) {
|
||||
onBeforeSaveEvents.add(new BeforeSaveEvent<Object>(source, doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterSave(Object source, CouchbaseDocument doc) {
|
||||
onAfterSaveEvents.add(new AfterSaveEvent<Object>(source, doc));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core.mapping.event;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Size(min = 10)
|
||||
private String name;
|
||||
|
||||
@Min(18)
|
||||
private Integer age;
|
||||
|
||||
public User(String name, Integer age) {
|
||||
id = "id";
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.core.mapping.event;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
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.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = EventContextConfiguration.class)
|
||||
public class ValidatingCouchbaseEventListenerTests {
|
||||
|
||||
@Autowired
|
||||
CouchbaseTemplate template;
|
||||
|
||||
@Test
|
||||
public void shouldThrowConstraintViolationException() {
|
||||
User user = new User("john", 17);
|
||||
|
||||
try {
|
||||
template.save(user);
|
||||
fail("Expected ConstraintViolationException");
|
||||
}
|
||||
catch (ConstraintViolationException e) {
|
||||
assertThat(e.getConstraintViolations().size()).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotThrowAnyExceptions() {
|
||||
template.save(new User("john smith", 18));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2017-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.core.query;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.data.couchbase.core.query.QueryCriteria.*;
|
||||
|
||||
class QueryCriteriaTests {
|
||||
|
||||
@Test
|
||||
void testSimpleCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba");
|
||||
assertEquals("`name` = \"Bubba\"", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullValue() {
|
||||
QueryCriteria c = where("name").is(null);
|
||||
assertEquals("`name` = null", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleNumber() {
|
||||
QueryCriteria c = where("name").is(5);
|
||||
assertEquals("`name` = 5", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotEqualCriteria() {
|
||||
QueryCriteria c = where("name").ne("Bubba");
|
||||
assertEquals("`name` != \"Bubba\"", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChainedCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba").and("age").lt(21).or("country").is("Austria");
|
||||
assertEquals("`name` = \"Bubba\" and `age` < 21 or `country` = \"Austria\"", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedAndCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba").and(where("age").gt(12).or("country").is("Austria"));
|
||||
assertEquals("`name` = \"Bubba\" and (`age` > 12 or `country` = \"Austria\")", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedOrCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba").or(where("age").gt(12).or("country").is("Austria"));
|
||||
assertEquals("`name` = \"Bubba\" or (`age` > 12 or `country` = \"Austria\")", c.export());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2020 the original author or authors.
|
||||
* Copyright 2017-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.
|
||||
@@ -14,40 +14,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.couchbase.repository.cdi;
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class Person {
|
||||
@Document
|
||||
public class Airport {
|
||||
@Id String id;
|
||||
|
||||
@Id private String id;
|
||||
String iata;
|
||||
|
||||
@Field private String name;
|
||||
String icao;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String id, String name) {
|
||||
@PersistenceConstructor
|
||||
public Airport(String id, String iata, String icao) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.iata = iata;
|
||||
this.icao = icao;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
public String getIata() {
|
||||
return iata;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
public String getIcao() {
|
||||
return icao;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2017-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.domain;
|
||||
|
||||
import org.springframework.data.couchbase.repository.ScanConsistency;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface AirportRepository extends PagingAndSortingRepository<Airport, String> {
|
||||
|
||||
@Override
|
||||
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
|
||||
Iterable<Airport> findAll();
|
||||
|
||||
List<Airport> findAllByIata(String iata);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.domain;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
public class User {
|
||||
|
||||
@Id private String id;
|
||||
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
|
||||
@PersistenceConstructor
|
||||
public User(final String id, final String firstname, final String lastname) {
|
||||
this.id = id;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id) && Objects.equals(firstname, user.firstname)
|
||||
&& Objects.equals(lastname, user.lastname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, firstname, lastname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" + "id='" + id + '\'' + ", firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + '}';
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.repository.join;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
package org.springframework.data.couchbase.domain;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends PagingAndSortingRepository<User, String> {
|
||||
|
||||
List<User> findByFirstname(String firstname);
|
||||
|
||||
List<User> findByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
|
||||
@N1qlSecondaryIndexed(indexName = "bookIndex")
|
||||
interface BookRepository extends CouchbaseRepository<Book, String> {
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.monitor;
|
||||
|
||||
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class ClientInfoIntegrationTests {
|
||||
|
||||
/**
|
||||
* Contains a reference to the actual CouchbaseClient.
|
||||
*/
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
private ClientInfo ci;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ci = new ClientInfo(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostNames() {
|
||||
String hostnames = ci.getHostNames();
|
||||
assertThat(hostnames).isNotEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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.monitor;
|
||||
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
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.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@Ignore(value = "Cant run get cluster info on test container")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class ClusterInfoIntegrationTests {
|
||||
|
||||
/**
|
||||
* Contains a reference to the actual CouchbaseClient.
|
||||
*/
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
private ClusterInfo ci;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ci = new ClusterInfo(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void totalDiskAssigned() {
|
||||
assertThat(ci.getTotalDiskAssigned()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void totalRAMUsed() {
|
||||
assertThat(ci.getTotalRAMUsed()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.core.mapping.id.GenerationStrategy.UNIQUE;
|
||||
|
||||
/**
|
||||
* @author Maxence Labusquiere
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class CouchbaseIdGenerationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
private CrudRepository<SimpleClassWithGeneratedIdValueUsingUUID, String> entityRepository;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
entityRepository = new CouchbaseRepositoryFactory(operationsMapping, indexManager).getRepository(EntityRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void idFieldEntityIsFillWithGeneratedValueOnSave() {
|
||||
SimpleClassWithGeneratedIdValueUsingUUID entity = new SimpleClassWithGeneratedIdValueUsingUUID();
|
||||
SimpleClassWithGeneratedIdValueUsingUUID savedEntity = entityRepository.save(entity);
|
||||
assertThat(savedEntity.id != null).as("Expected generated value").isTrue();
|
||||
if (entityRepository.existsById(savedEntity.id)) {
|
||||
entityRepository.existsById(savedEntity.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void ifIdFieldIsAlreadySetNothingIsDone() {
|
||||
String id = "AnId";
|
||||
SimpleClassWithGeneratedIdValueUsingUUID entity = new SimpleClassWithGeneratedIdValueUsingUUID();
|
||||
entity.setId(id);
|
||||
SimpleClassWithGeneratedIdValueUsingUUID savedEntity = entityRepository.save(entity);
|
||||
assertThat(savedEntity.id == id).as("Expected same id instance").isTrue();
|
||||
if (entityRepository.existsById(savedEntity.id)) {
|
||||
entityRepository.existsById(savedEntity.id);
|
||||
}
|
||||
}
|
||||
|
||||
@Document
|
||||
static class SimpleClassWithGeneratedIdValueUsingUUID {
|
||||
@Id
|
||||
@GeneratedValue(strategy = UNIQUE)
|
||||
public String id;
|
||||
|
||||
public String value = "new";
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Repository
|
||||
interface EntityRepository extends CrudRepository<SimpleClassWithGeneratedIdValueUsingUUID, String> {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.UserRepository;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
@SpringJUnitConfig(CouchbaseRepositoryKeyValueIntegrationTests.Config.class)
|
||||
public class CouchbaseRepositoryKeyValueIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
@Autowired UserRepository userRepository;
|
||||
|
||||
@Test
|
||||
void saveAndFindById() {
|
||||
User user = new User(UUID.randomUUID().toString(), "f", "l");
|
||||
|
||||
assertFalse(userRepository.existsById(user.getId()));
|
||||
|
||||
userRepository.save(user);
|
||||
|
||||
Optional<User> found = userRepository.findById(user.getId());
|
||||
assertTrue(found.isPresent());
|
||||
found.ifPresent(u -> assertEquals(user, u));
|
||||
|
||||
assertTrue(userRepository.existsById(user.getId()));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
public String getConnectionString() {
|
||||
return connectionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return config().adminUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return config().adminPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucketName() {
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2017-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;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
|
||||
import org.springframework.data.couchbase.domain.Airport;
|
||||
import org.springframework.data.couchbase.domain.AirportRepository;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import com.couchbase.client.core.error.IndexExistsException;
|
||||
|
||||
@SpringJUnitConfig(CouchbaseRepositoryQueryIntegrationTests.Config.class)
|
||||
public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegrationTests {
|
||||
|
||||
@Autowired CouchbaseClientFactory clientFactory;
|
||||
|
||||
@Autowired AirportRepository airportRepository;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
try {
|
||||
clientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName());
|
||||
} catch (IndexExistsException ex) {
|
||||
// ignore, all good.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveAndFindAll() {
|
||||
Airport vie = new Airport("airports::vie", "vie", "loww");
|
||||
airportRepository.save(vie);
|
||||
|
||||
List<Airport> all = StreamSupport.stream(airportRepository.findAll().spliterator(), false)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertFalse(all.isEmpty());
|
||||
assertTrue(all.stream().anyMatch(a -> a.getId().equals("airports::vie")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findBySimpleProperty() {
|
||||
List<Airport> airports = airportRepository.findAllByIata("vie");
|
||||
// TODO
|
||||
System.err.println(airports);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
|
||||
static class Config extends AbstractCouchbaseConfiguration {
|
||||
|
||||
@Override
|
||||
public String getConnectionString() {
|
||||
return connectionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return config().adminUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return config().adminPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucketName() {
|
||||
return bucketName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.json.JsonObject;
|
||||
import com.couchbase.client.java.view.Stale;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
import com.couchbase.client.java.view.ViewResult;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Matchers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.mapping.PropertyReferenceException;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author David Harrigan
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(CouchbaseRepositoryViewListener.class)
|
||||
public class CouchbaseRepositoryViewIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private CustomUserRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
repository = new CouchbaseRepositoryFactory(operationsMapping, indexManager).getRepository(CustomUserRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindAllWithCustomView() {
|
||||
client.query(ViewQuery.from("user", "customFindAllView").stale(Stale.FALSE));
|
||||
Iterable<User> allUsers = repository.findAll();
|
||||
assertThat(allUsers).hasSize(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCountWithCustomView() {
|
||||
ViewResult clientResult = client.query(ViewQuery.from("userCustom", "customCountView")
|
||||
.reduce().stale(Stale.FALSE));
|
||||
final Object clientRowValue = clientResult.allRows().get(0).value();
|
||||
final long value = repository.count();
|
||||
assertThat(value).isEqualTo(100L);
|
||||
assertThat(clientRowValue).isInstanceOf(Number.class);
|
||||
assertThat(((Number) clientRowValue).longValue()).isEqualTo(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectMethodNameWithoutPropertyAndIssueGenericQueryOnView() {
|
||||
Iterable<User> users = repository.findRandomMethodName();
|
||||
assertThat(users).isNotNull();
|
||||
assertThat(users.iterator().hasNext()).isTrue();
|
||||
|
||||
try {
|
||||
repository.findIncorrectExplicitView();
|
||||
fail("Expected InvalidDataAccessResourceException");
|
||||
} catch (InvalidDataAccessResourceUsageException e) {
|
||||
assertThat(e.getMessage().startsWith("View user/allSomething does not exist"))
|
||||
.as(e.getMessage()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = PropertyReferenceException.class)
|
||||
public void shouldFailDeriveOnBadProperty() {
|
||||
repository.findAllByUsernameEqualAndUserblablaIs("uname-1", "blabla");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveViewParametersAndReduce() {
|
||||
long count = repository.countByUsernameGreaterThanEqualAndUsernameLessThan("uname-8", "uname-9");
|
||||
assertThat(count).isEqualTo(12);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveViewParametersAndReduceNonNumerical() {
|
||||
JsonObject reduceResult = repository.findByAgeLessThan(50);
|
||||
|
||||
assertThat(reduceResult).isNotNull();
|
||||
assertThat((long) reduceResult.getLong("count")).isEqualTo(51);
|
||||
assertThat((long) reduceResult.getLong("max")).isEqualTo(50);
|
||||
assertThat((long) reduceResult.getLong("min")).isEqualTo(0);
|
||||
assertThat((long) reduceResult.getLong("sum")).isEqualTo(1275);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveViewParameters() {
|
||||
String lowKey = "uname-1";
|
||||
String middleKey = "uname-10";
|
||||
String highKey = "uname-11";
|
||||
List<String> keys = Arrays.asList(lowKey, middleKey, highKey);
|
||||
|
||||
User u1 = repository.findByUsernameIs(lowKey).get(0);
|
||||
User u2 = repository.findByUsernameIs(middleKey).get(0);
|
||||
User u3 = repository.findByUsernameIs(highKey).get(0);
|
||||
|
||||
assertThat(u1.getUsername()).isEqualTo(lowKey);
|
||||
assertThat(u2.getUsername()).isEqualTo(middleKey);
|
||||
assertThat(u3.getUsername()).isEqualTo(highKey);
|
||||
|
||||
List<User> in = repository.findAllByUsernameIn(keys);
|
||||
List<User> gteLte = repository.findByUsernameGreaterThanEqualAndUsernameLessThanEqual(lowKey, highKey);
|
||||
List<User> between = repository.findByUsernameBetween(lowKey, highKey);
|
||||
List<User> gteLimited = repository.findTop3ByUsernameGreaterThanEqual(lowKey);
|
||||
|
||||
// the results are unordered, so compare using Set
|
||||
Set<User> expected = new HashSet<>(Arrays.asList(u1, u2, u3));
|
||||
assertThat(new HashSet<>(in)).isEqualTo(expected);
|
||||
assertThat(new HashSet<>(gteLte)).isEqualTo(expected);
|
||||
assertThat(new HashSet<>(between)).isEqualTo(expected);
|
||||
assertThat(new HashSet<>(gteLimited)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveToEmptyClause() {
|
||||
List<User> users = repository.findAllByUsername();
|
||||
assertThat(users).isNotNull();
|
||||
assertThat(users.size()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetermineViewNameFromMethodPrefix() {
|
||||
try {
|
||||
repository.findByIncorrectView();
|
||||
fail("Expected InvalidDataAccessResourceException");
|
||||
} catch (InvalidDataAccessResourceUsageException e) {
|
||||
assertThat(e.getMessage().startsWith("View user/byIncorrectView does not exist"))
|
||||
.as(e.getMessage()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetermineViewNameFromCountPrefixAndReduce() {
|
||||
long count = repository.countCustomFindAllView();
|
||||
assertThat(count).isEqualTo(100);
|
||||
|
||||
try {
|
||||
repository.countCustomFindInvalid();
|
||||
fail("Expected InvalidDataAccessResourceException");
|
||||
} catch (InvalidDataAccessResourceUsageException e) {
|
||||
assertThat(e.getMessage().startsWith("View user/customFindInvalid does not exist"))
|
||||
.as(e.getMessage()).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.PersistTo;
|
||||
import com.couchbase.client.java.ReplicateTo;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.View;
|
||||
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class CouchbaseRepositoryViewListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
}
|
||||
|
||||
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, i), PersistTo.MASTER, ReplicateTo.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(final Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository.User\") { emit(null, null); } }";
|
||||
String mapFunctionName = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository.User\") { emit(doc.username, null); } }";
|
||||
String mapFunctionAge = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository.User\") { emit(doc.age, doc.age); } }";
|
||||
View view = DefaultView.create("customFindAllView", mapFunction, "_count");
|
||||
View customFindByNameView = DefaultView.create("customFindByNameView", mapFunctionName, "_count");
|
||||
View customFindByAgeStatsView = DefaultView.create("customFindByAgeStatsView", mapFunctionAge, "_stats");
|
||||
List<View> views = Arrays.asList(view, customFindByNameView, customFindByAgeStatsView);
|
||||
DesignDocument designDoc = DesignDocument.create("user", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
|
||||
view = DefaultView.create("customCountView", mapFunction, "_count");
|
||||
views = Collections.singletonList(view);
|
||||
designDoc = DesignDocument.create("userCustom", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.document.json.JsonObject;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.View;
|
||||
|
||||
/**
|
||||
* @author David Harrigan
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public interface CustomUserRepository extends CouchbaseRepository<User, String> {
|
||||
|
||||
@Override
|
||||
@View(designDocument = "user", viewName = "customFindAllView")
|
||||
Iterable<User> findAll();
|
||||
|
||||
@Override
|
||||
@View(designDocument = "userCustom", viewName = "customCountView")
|
||||
long count();
|
||||
|
||||
@View(viewName = "allSomething")
|
||||
Iterable<User> findIncorrectExplicitView();
|
||||
|
||||
@View(viewName = "customFindAllView")
|
||||
Iterable<User> findRandomMethodName();
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
long countByUsernameGreaterThanEqualAndUsernameLessThan(String lowBound, String highBound);
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
List<User> findByUsernameIs(String lowKey);
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
List<User> findAllByUsernameIn(List<String> keys);
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
List<User> findByUsernameGreaterThanEqualAndUsernameLessThanEqual(String lowKey, String highKey);
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
List<User> findByUsernameBetween(String lowKey, String highKey);
|
||||
|
||||
@View(viewName = "customFindByNameView")
|
||||
List<User> findTop3ByUsernameGreaterThanEqual(String lowKey);
|
||||
|
||||
@View(viewName = "customFindAllView")
|
||||
List<User> findAllByUsername();
|
||||
|
||||
@View(viewName = "customFindAllView")
|
||||
List<User> findAllByUsernameEqualAndUserblablaIs(String s, String blabla);
|
||||
|
||||
@View
|
||||
List<User> findByIncorrectView();
|
||||
|
||||
@View
|
||||
long countCustomFindAllView();
|
||||
|
||||
@View
|
||||
long countCustomFindInvalid();
|
||||
|
||||
@View(viewName = "customFindByAgeStatsView", reduce = true)
|
||||
JsonObject findByAgeLessThan(int maxAge);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.document.json.JsonArray;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.Dimensional;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface DimensionalPartyRepository extends CrudRepository<Party, String> {
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationNear(Point p, Distance d);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(Box boundingBox);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(Polygon zone);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(Point[] points);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(Point point);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(JsonArray range);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation")
|
||||
List<Party> findByLocationWithin(Point lowerLeft, Point upperRight);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocationAndAttendees", dimensions = 3)
|
||||
List<Party> findByLocationWithin(Circle zone);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocationAndAttendees", dimensions = 3)
|
||||
List<Party> findByLocationWithinAndAttendeesGreaterThan(Polygon zone, double minAttendees);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocationAndAttendees", dimensions = 3)
|
||||
List<Party> findByLocationWithin(JsonArray startRange, JsonArray endRange);
|
||||
|
||||
//TODO more coverage of operators?
|
||||
|
||||
@IndexedByLocation
|
||||
List<Party> findByLocationIsWithin(Point a, Point b);
|
||||
|
||||
@Dimensional(designDocument = "partyGeo", spatialViewName = "byLocation", dimensions = 2)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface IndexedByLocation { }
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.couchbase.client.java.document.json.JsonArray;
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(PartyPopulatorListener.class)
|
||||
public class DimensionalQueryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping templateMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private DimensionalPartyRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(templateMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, DimensionalPartyRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindWithingPolygon() {
|
||||
Set<String> expectedKeys = new HashSet<String>();
|
||||
expectedKeys.add("testparty-2");
|
||||
expectedKeys.add("testparty-3");
|
||||
expectedKeys.add("testparty-4");
|
||||
expectedKeys.add("testparty-5");
|
||||
//a zone that engulfs parties 2, 3, 4 and 5, in the shape of a downward arrow pointing right
|
||||
Polygon zone = new Polygon(new Point(1, -2),
|
||||
new Point(3, -1.5),
|
||||
new Point(6, -4),
|
||||
new Point(5.5, -5.5),
|
||||
new Point(3, -5));
|
||||
|
||||
List<Party> parties = repository.findByLocationWithin(zone);
|
||||
|
||||
assertThat(parties.size()).isEqualTo(4);
|
||||
for (Party party : parties) {
|
||||
assertThat(expectedKeys.contains(party.getKey())).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationNear() {
|
||||
Set<String> expectedKeys = new HashSet<String>();
|
||||
expectedKeys.add("testparty-0");
|
||||
expectedKeys.add("testparty-1");
|
||||
|
||||
List<Party> parties = repository.findByLocationNear(new Point(0, 0), new Distance(1.5));
|
||||
assertThat(parties.size()).isEqualTo(2);
|
||||
for (Party party : parties) {
|
||||
assertThat(expectedKeys.contains(party.getKey())).isTrue();
|
||||
}
|
||||
|
||||
//with this one, testparty-2 is within the bounding box but not in correct distance
|
||||
parties = repository.findByLocationNear(new Point(0, 0), new Distance(2.5));
|
||||
assertThat(parties.size()).isEqualTo(2);
|
||||
for (Party party : parties) {
|
||||
assertThat(expectedKeys.contains(party.getKey())).isTrue();
|
||||
}
|
||||
|
||||
//here we adjust the distance so that testparty-2 falls just on the edge
|
||||
parties = repository.findByLocationNear(new Point(0, 0), new Distance(2.8284271247461903));
|
||||
expectedKeys.add("testparty-2");
|
||||
assertThat(parties.size()).isEqualTo(3);
|
||||
for (Party party : parties) {
|
||||
assertThat(expectedKeys.contains(party.getKey())).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationAndSparseAttendees() {
|
||||
Set<String> expectedKeys = new HashSet<String>();
|
||||
expectedKeys.add("testparty-4");
|
||||
expectedKeys.add("testparty-5");
|
||||
//a zone that engulfs parties 2, 3, 4 and 5 (with resp. 120, 130, 140 and 150 attendees)
|
||||
//in the shape of a downward arrow pointing right
|
||||
Polygon zone = new Polygon(new Point(1, -2),
|
||||
new Point(3, -1.5),
|
||||
new Point(6, -4),
|
||||
new Point(5.5, -5.5),
|
||||
new Point(3, -5));
|
||||
|
||||
//first check the zone contains 4 parties
|
||||
List<Party> allPartiesInZone = repository.findByLocationWithinAndAttendeesGreaterThan(zone, -1);
|
||||
List<Party> allPartiesInZoneWithoutAttendeeCriteria = repository.findByLocationWithin(zone);
|
||||
assertThat(allPartiesInZone.size()).as(allPartiesInZone.toString()).isEqualTo(4);
|
||||
assertThat(allPartiesInZone).isEqualTo(allPartiesInZoneWithoutAttendeeCriteria);
|
||||
|
||||
//check parties are limited by the attendees
|
||||
List<Party> parties = repository.findByLocationWithinAndAttendeesGreaterThan(zone, 140);
|
||||
for (Party party : parties) {
|
||||
System.out.println(party.getKey() + " : " + party.getLocation() + " " + party.getAttendees());
|
||||
}
|
||||
|
||||
assertThat(parties.size()).as(parties.toString()).isEqualTo(2);
|
||||
for (Party party : parties) {
|
||||
assertThat(party.getAttendees() >= 140).isTrue();
|
||||
assertThat(expectedKeys.contains(party.getKey())).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationInCircle() {
|
||||
Circle zoneBboxFalse = new Circle(new Point(-5,5), new Distance(5.5));
|
||||
Circle zoneEdge = new Circle(new Point(-5, 0), new Distance(5));
|
||||
Circle zoneInside = new Circle(new Point(6, -6), new Distance(10));
|
||||
Circle zoneEmpty = new Circle(new Point(6,6), new Distance(3));
|
||||
|
||||
List<Party> parties = repository.findByLocationWithin(zoneBboxFalse);
|
||||
assertThat(parties.size()).isEqualTo(0);
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEdge);
|
||||
assertThat(parties.size()).isEqualTo(1);
|
||||
assertThat(parties.get(0).getKey()).isEqualTo("testparty-0");
|
||||
|
||||
parties = repository.findByLocationWithin(zoneInside);
|
||||
assertThat(parties.size()).isEqualTo(12); //all the parties except the special one at 100, 100
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEmpty);
|
||||
assertThat(parties.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationInBox() {
|
||||
Box zone1 = new Box(new Point(-10.5, -0.5), new Point(0.5, 10.5));
|
||||
Box zone2 = new Box(new Point(-4, -16), new Point(16, 4));
|
||||
Box zoneEmpty = new Box(new Point(3, 3), new Point(9, 9));
|
||||
|
||||
List<Party> parties = repository.findByLocationWithin(zone1);
|
||||
|
||||
assertThat(parties.size()).isEqualTo(1);
|
||||
assertThat(parties.get(0).getKey()).isEqualTo("testparty-0");
|
||||
|
||||
parties = repository.findByLocationWithin(zone2);
|
||||
|
||||
assertThat(parties.size()).isEqualTo(12); //all the parties except the special one at 100, 100
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEmpty);
|
||||
assertThat(parties.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationInPolygon() {
|
||||
//slightly skewed square triangle that cuts just short of (0,0)
|
||||
//bounding box of (-1,-1),(0.5,1)
|
||||
Polygon zoneFalsePositive = new Polygon(
|
||||
new Point(-1, 1),
|
||||
new Point(0.5, 1),
|
||||
new Point(-1, -1)
|
||||
);
|
||||
//square triangle that comes through (0,0)
|
||||
//bounding box of (-1,-1),(1,1)
|
||||
Polygon zoneEdge = new Polygon(
|
||||
new Point(-1, 1),
|
||||
new Point(1, 1),
|
||||
new Point(-1, -1)
|
||||
);
|
||||
//bounding box of (-4, -16),(16,4)
|
||||
Polygon zoneWithin = new Polygon(
|
||||
new Point(-4, -10),
|
||||
new Point(-3, 4),
|
||||
new Point(14, 2),
|
||||
new Point(16, -16));
|
||||
//bounding box of (3,3)(9,9)
|
||||
Polygon zoneEmpty = new Polygon(
|
||||
new Point(3, 3),
|
||||
new Point(3, 7),
|
||||
new Point(6, 7),
|
||||
new Point(6, 9),
|
||||
new Point(9, 9),
|
||||
new Point(9, 5),
|
||||
new Point(6, 5),
|
||||
new Point(6, 3));
|
||||
|
||||
List<Party> parties = repository.findByLocationWithin(zoneFalsePositive);
|
||||
assertThat(parties.size())
|
||||
.as("points outside a polygon but within bounding box shouldn't be considered within")
|
||||
.isEqualTo(0);
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEdge);
|
||||
assertThat(parties.size())
|
||||
.as("point on edge of a polygon shouldn't be considered within").isEqualTo(0);
|
||||
|
||||
parties = repository.findByLocationWithin(zoneWithin);
|
||||
assertThat(parties.size()).isEqualTo(12); //all the parties except the special one at 100, 100
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEmpty);
|
||||
assertThat(parties.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByLocationWithinTwoPoints() {
|
||||
Point zone1LowerLeft = new Point(-10.5, -0.5);
|
||||
Point zone1UpperRight = new Point(0.5, 10.5);
|
||||
Point zone2LowerLeft = new Point(-4, -16);
|
||||
Point zone2UpperRight = new Point(16, 4);
|
||||
Point zoneEmptyLowerLeft = new Point(3, 3);
|
||||
Point zoneEmptyUpperRight = new Point(9, 9);
|
||||
|
||||
List<Party> parties = repository.findByLocationWithin(zone1LowerLeft, zone1UpperRight);
|
||||
|
||||
assertThat(parties.size()).isEqualTo(1);
|
||||
assertThat(parties.get(0).getKey()).isEqualTo("testparty-0");
|
||||
|
||||
parties = repository.findByLocationWithin(zone2LowerLeft, zone2UpperRight);
|
||||
|
||||
assertThat(parties.size()).isEqualTo(12); //all the parties except the special one at 100, 100
|
||||
|
||||
parties = repository.findByLocationWithin(zoneEmptyLowerLeft, zoneEmptyUpperRight);
|
||||
assertThat(parties.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPolygonAndArrayOfPointsProduceSameResult() {
|
||||
Set<String> expectedKeys = new HashSet<String>();
|
||||
expectedKeys.add("testparty-2");
|
||||
expectedKeys.add("testparty-3");
|
||||
expectedKeys.add("testparty-4");
|
||||
expectedKeys.add("testparty-5");
|
||||
//a zone that engulfs parties 2, 3, 4 and 5, in the shape of a downward arrow pointing right
|
||||
Polygon zone = new Polygon(new Point(1, -2),
|
||||
new Point(3, -1.5),
|
||||
new Point(6, -4),
|
||||
new Point(5.5, -5.5),
|
||||
new Point(3, -5));
|
||||
Point[] points = zone.getPoints().toArray(new Point[5]);
|
||||
|
||||
List<Party> fromZone = repository.findByLocationWithin(zone);
|
||||
List<Party> fromPoints = repository.findByLocationWithin(points);
|
||||
|
||||
assertThat(fromZone.size()).isEqualTo(4);
|
||||
assertThat(fromPoints).isEqualTo(fromZone);
|
||||
Set<String> keys = new HashSet<String>();
|
||||
for (Party party : fromZone) {
|
||||
keys.add(party.getKey());
|
||||
}
|
||||
assertThat(keys).isEqualTo(expectedKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvidingOnePointIsRejected() {
|
||||
try {
|
||||
repository.findByLocationWithin(new Point(0, 0));
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage())
|
||||
.isEqualTo("Cannot compute a bounding box for within, 2 Point needed, missing parameter");
|
||||
}
|
||||
|
||||
try {
|
||||
repository.findByLocationWithin(new Point(0, 0), null);
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage())
|
||||
.isEqualTo("Cannot compute a bounding box for within, 2 Point needed, got null");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvidingOneJsonArrayIsRejected() {
|
||||
try {
|
||||
List<Party> parties = repository.findByLocationWithin(JsonArray.from(0,0));
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage())
|
||||
.isEqualTo("2 JsonArray required for within: startRange and endRange, missing parameter");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = CouchbaseQueryExecutionException.class)
|
||||
public void testJsonArrayWithNonNumericalValueProducesServerSideError() {
|
||||
repository.findByLocationWithin(JsonArray.from("toto", -2), JsonArray.from(4, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithinJsonArrayRangesFiltersLocationAndAttendees() {
|
||||
List<Party> parties = repository.findByLocationWithin(JsonArray.from(0, -4, 115), JsonArray.from(4, 1, 132));
|
||||
assertThat(parties.size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDimensionalAnnotationCanBeUsedAsMeta() {
|
||||
try {
|
||||
//will trigger a specific message if parsed by SpatialViewQueryCreator
|
||||
repository.findByLocationIsWithin(new Point(0,0), null);
|
||||
fail("expected IllegalArgumentException from SpatialViewQueryCreator");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage())
|
||||
.isEqualTo("Cannot compute a bounding box for within, 2 Point needed, got null");
|
||||
}
|
||||
|
||||
//when it is correctly formed, it actually returns data
|
||||
assertThat(repository
|
||||
.findByLocationIsWithin(new Point(-10.5, -0.5), new Point(0.5, 10.5)).size())
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindWithinBoxCornerOrderDoesMatter() {
|
||||
Point a = new Point(0, -4);
|
||||
Point b = new Point(6, -2);
|
||||
Box box1 = new Box(a, b);
|
||||
Box box2 = new Box(b, a);
|
||||
|
||||
final List<Party> parties1 = repository.findByLocationWithin(box1);
|
||||
final List<Party> parties2 = repository.findByLocationWithin(box2);
|
||||
|
||||
assertThat(parties1.size()).isEqualTo(3);
|
||||
assertThat(parties2).isNotEqualTo(parties1);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
public class Item {
|
||||
|
||||
@Id
|
||||
public String id;
|
||||
|
||||
@Field("desc")
|
||||
public String description;
|
||||
|
||||
public Item(String id, String description) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Item item = (Item) o;
|
||||
|
||||
if (!id.equals(item.id)) return false;
|
||||
return !(description != null ? !description.equals(item.description) : item.description != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id.hashCode();
|
||||
result = 31 * result + (description != null ? description.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
@N1qlPrimaryIndexed
|
||||
public interface ItemRepository extends CrudRepository<Item, String> {
|
||||
|
||||
List<Object> findAllByDescriptionNotNull();
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
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.mapping.model.MappingInstantiationException;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This tests PaginAndSortingRepository features in the Couchbase connector.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(PartyPopulatorListener.class)
|
||||
public class N1qlCouchbaseRepositoryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private PartyPagingRepository repository;
|
||||
|
||||
private PartyRepository partyRepository;
|
||||
|
||||
private ItemRepository itemRepository;
|
||||
|
||||
private final String KEY_PARTY = "Party1";
|
||||
private final String KEY_ITEM = "Item1";
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, PartyPagingRepository.class);
|
||||
partyRepository = getRepositoryWithRetry(factory, PartyRepository.class);
|
||||
itemRepository = getRepositoryWithRetry(factory, ItemRepository.class);
|
||||
|
||||
partyRepository.save(new Party(KEY_PARTY, "partyName", "MatchingDescription", null, 1, null));
|
||||
itemRepository.save(new Item(KEY_ITEM, "MatchingDescription"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
try { itemRepository.deleteById(KEY_ITEM); } catch (DataRetrievalFailureException e) {}
|
||||
try { partyRepository.deleteById(KEY_PARTY); } catch (DataRetrievalFailureException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeThreadsafe() {
|
||||
// This doesn't guarantee it, but we should catch most thread issues without
|
||||
// taking too long here...
|
||||
int runs = 50;
|
||||
for (int i=0; i<runs; i++) {
|
||||
doShouldBeThreadsafe();
|
||||
}
|
||||
}
|
||||
public void doShouldBeThreadsafe() {
|
||||
int threads = 50;
|
||||
ExecutorService service = Executors.newFixedThreadPool(threads);
|
||||
List<Callable<Boolean>> callables = new ArrayList<>();
|
||||
for (int thread = 0; thread < threads; ++thread) {
|
||||
final int counter = thread;
|
||||
Callable<Boolean> booleanSupplier = () -> {
|
||||
String expectedName = "party like it's 199" + counter%12;
|
||||
String foundName = partyRepository.findByName(expectedName).get(0).getName();
|
||||
return expectedName.equals(foundName); //should never get false
|
||||
};
|
||||
callables.add(booleanSupplier);
|
||||
}
|
||||
try {
|
||||
List<Future<Boolean>> futures = service.invokeAll(callables);
|
||||
service.shutdown();
|
||||
service.awaitTermination(5, TimeUnit.SECONDS);
|
||||
for (Future<Boolean> future: futures) {
|
||||
assertThat(future.get()).isTrue();
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
fail("Threads failed to run " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindAllWithSort() {
|
||||
Iterable<Party> allByAttendanceDesc = repository.findAll(Sort.by(Sort.Direction.DESC, "attendees"));
|
||||
long previousAttendance = Long.MAX_VALUE;
|
||||
for (Party party : allByAttendanceDesc) {
|
||||
assertThat(party.getAttendees() <= previousAttendance).isTrue();
|
||||
previousAttendance = party.getAttendees();
|
||||
}
|
||||
assertThat(previousAttendance == Long.MAX_VALUE)
|
||||
.as("Expected to find several parties").isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSortOnRenamedFieldIfJsonNameIsProvidedInSort() {
|
||||
Iterable<Party> parties = repository.findAll(Sort.by(Sort.Direction.DESC, "desc"));
|
||||
String previousDesc = null;
|
||||
for (Party party : parties) {
|
||||
if (previousDesc != null) {
|
||||
assertThat(party.getDescription().compareTo(previousDesc) <= 0).isTrue();
|
||||
}
|
||||
previousDesc = party.getDescription();
|
||||
}
|
||||
assertThat(previousDesc).as("Expected to find several parties").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSortWithoutCaseSensitivity() {
|
||||
Iterable<Party> parties = repository.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC, "desc").ignoreCase()));
|
||||
String previousDesc = null;
|
||||
for (Party party : parties) {
|
||||
if (previousDesc != null) {
|
||||
assertThat(party.getDescription().compareToIgnoreCase(previousDesc) <= 0)
|
||||
.isTrue();
|
||||
}
|
||||
previousDesc = party.getDescription();
|
||||
}
|
||||
assertThat(previousDesc).as("Expected to find several parties").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPageThroughEntities() {
|
||||
Pageable pageable = PageRequest.of(0, 8);
|
||||
|
||||
Page<Party> page1 = repository.findAll(pageable);
|
||||
assertThat(page1.getTotalElements() >= 12)
|
||||
.as("Query for parties should be atleast 12").isTrue();
|
||||
assertThat(page1.getNumberOfElements()).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPageThroughSortedEntities() {
|
||||
Pageable pageable = PageRequest.of(0, 8, Sort.Direction.DESC, "attendees");
|
||||
|
||||
Page<Party> page1 = repository.findAll(pageable);
|
||||
assertThat(page1.getTotalElements() >= 12)
|
||||
.as("Query for parties should be atleast 12").isTrue();
|
||||
assertThat(page1.getNumberOfElements()).isEqualTo(8);
|
||||
|
||||
List<Party> parties = page1.getContent();
|
||||
Long previousAttendees = null;
|
||||
for (Party party : parties) {
|
||||
if (previousAttendees != null) {
|
||||
assertThat(party.getAttendees() <= previousAttendees).isTrue();
|
||||
}
|
||||
previousAttendees = party.getAttendees();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapWhereCriteria() {
|
||||
List<Party> partyList = partyRepository.findByDescriptionOrName("MatchingDescription", "partyName");
|
||||
assertThat(partyList.size() == 1).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPageWithStringBasedQuery() {
|
||||
Pageable pageable = PageRequest.of(0, 8, Sort.Direction.DESC, "attendees");
|
||||
Page<Party> page1 = partyRepository.findPartiesWithAttendee(1, pageable);
|
||||
assertThat(page1.getTotalElements() >= 12)
|
||||
.as("Query for parties with attendees should be atleast 12").isTrue();
|
||||
assertThat(page1.getNumberOfElements()).isEqualTo(8);
|
||||
|
||||
List<Party> parties = page1.getContent();
|
||||
Long previousAttendees = null;
|
||||
for (Party party : parties) {
|
||||
if (previousAttendees != null) {
|
||||
assertThat(party.getAttendees() <= previousAttendees).isTrue();
|
||||
}
|
||||
previousAttendees = party.getAttendees();
|
||||
}
|
||||
Page<Party> page2 = partyRepository.findPartiesWithAttendee(1, page1.nextPageable());
|
||||
assertThat(page2.getNumberOfElements()).isEqualTo(8);
|
||||
parties = page2.getContent();
|
||||
for (Party party : parties) {
|
||||
if (previousAttendees != null) {
|
||||
assertThat(party.getAttendees() <= previousAttendees).isTrue();
|
||||
}
|
||||
previousAttendees = party.getAttendees();
|
||||
}
|
||||
}
|
||||
|
||||
//Fails on deserialization as a different entity item is also present
|
||||
@Test(expected = MappingInstantiationException.class)
|
||||
public void shouldFailWithMissingFilterStringBasedQuery() {
|
||||
Sort sort = Sort.by(Sort.Direction.DESC, "attendees");
|
||||
partyRepository.findParties(sort);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteQuery() {
|
||||
partyRepository.save(new Party("testDeleteQuery", "delete", "delete", null, 0, null));
|
||||
List<Party> partyList = partyRepository.removeByDescriptionOrName("delete", "delete");
|
||||
assertThat(partyList.size() == 1).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpelDateConvertion() {
|
||||
final String key = "testSpelDateConvertion";
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
cal.set(2018, Calendar.SEPTEMBER, 10);
|
||||
Date date = cal.getTime();
|
||||
partyRepository.save(new Party(key, "", "", date, 0, null));
|
||||
List<Party> partyList = partyRepository.getByEventDate(date);
|
||||
assertThat(partyList.size() == 1).isTrue();
|
||||
assertThat(key).as("Key mismatch").isEqualTo(partyList.get(0).getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testN1qlQueryWithInvalidValue() {
|
||||
partyRepository.save(new Party("testN1qlQueryWithInvalidValue", "", "testN1qlQueryWithInvalidValue", null, 0, null));
|
||||
final String description = "testN1qlQueryWithInvalidValue* OR `description` LIKE \"\"";
|
||||
List<Party> partyList = partyRepository.findByDescriptionStartingWith(description);
|
||||
assertThat(partyList.size() == 0).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
public class N1qlCrudRepositoryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private PartyRepository partyRepository;
|
||||
private ItemRepository itemRepository;
|
||||
|
||||
private static final String KEY_ITEM = "itemNotParty";
|
||||
private static final String KEY_PARTY = "partyNotItem";
|
||||
private static final String KEY_PARTY_KEYWORD = "partyHasKeyword";
|
||||
|
||||
private static final Item item = new Item(KEY_ITEM, "short description");
|
||||
private static final Party party = new Party(KEY_PARTY, "partyName", "short description", new Date(), 120, new Point(500, 500));
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
CouchbaseRepositoryFactory factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
|
||||
partyRepository = getRepositoryWithRetry(factory, PartyRepository.class);
|
||||
itemRepository = getRepositoryWithRetry(factory, ItemRepository.class);
|
||||
|
||||
itemRepository.save(item);
|
||||
partyRepository.save(party);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
try { itemRepository.deleteById(KEY_ITEM); } catch (DataRetrievalFailureException e) {}
|
||||
try { partyRepository.deleteById(KEY_PARTY); } catch (DataRetrievalFailureException e) {}
|
||||
try { partyRepository.deleteById(KEY_PARTY_KEYWORD); } catch (DataRetrievalFailureException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDistinguishBetweenItemsAndParties() {
|
||||
List<Object> items = itemRepository.findAllByDescriptionNotNull();
|
||||
List<Object> parties = partyRepository.findAllByDescriptionNotNull();
|
||||
|
||||
assertThat(items.contains(item)).isTrue();
|
||||
assertThat(parties.contains(party)).isTrue();
|
||||
|
||||
assertThat(items.contains(party)).isFalse();
|
||||
assertThat(parties.contains(item)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveObjectWithN1qlKeywordField() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "desc is a N1QL keyword", new Date(), 40, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
List<Object> parties = partyRepository.findAllByDescriptionNotNull();
|
||||
|
||||
assertThat(client.exists(KEY_PARTY_KEYWORD)).isTrue();
|
||||
assertThat(parties.contains(partyHasKeyword)).isTrue();
|
||||
for (Object o : parties) {
|
||||
if (!(o instanceof Party)) {
|
||||
fail("expected only Party objects");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGenerateCountProjection() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", null, new Date(), 40, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
long countTotal = partyRepository.count();
|
||||
long countCustom = partyRepository.countAllByDescriptionNotNull();
|
||||
assertThat(countCustom).isEqualTo(countTotal - 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCountWhenReturningLongAndUsingStringSelectFromSpEL() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "second party", new Date(), 40, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
|
||||
long countTotal = partyRepository.count();
|
||||
long countCustom = partyRepository.countCustom();
|
||||
assertThat(countCustom).isEqualTo(countTotal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCustomCountWhenReturningLongAndUsingStringWithoutSpEL() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "second party", new Date(), 40, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
|
||||
long countTotal = partyRepository.count();
|
||||
long countCustom = partyRepository.countCustomPlusFive();
|
||||
assertThat(countCustom).isEqualTo(countTotal + 5);
|
||||
}
|
||||
|
||||
@Test(expected = CouchbaseQueryExecutionException.class)
|
||||
public void shouldFailConversionWithStringReturnType() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "desc is a N1QL keyword", new Date(), 40, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
|
||||
String someString = partyRepository.findSomeString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDoNumericProjectionWithStringBasedQuery() {
|
||||
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "desc is a N1QL keyword", new Date(), 4000000, new Point(500, 500));
|
||||
partyRepository.save(partyHasKeyword);
|
||||
|
||||
long max = partyRepository.findMaxAttendees();
|
||||
assertThat(max).isEqualTo(4000000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDoBooleanProjectionWithStringBasedQuery() {
|
||||
boolean someBoolean = partyRepository.justABoolean();
|
||||
assertThat(someBoolean).isEqualTo(true);
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.query.Query;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(PartyPopulatorListener.class)
|
||||
public class N1qlPlaceholderIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private CouchbaseRepositoryFactory factory;
|
||||
private PartyRepository partyRepository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
partyRepository = getRepositoryWithRetry(factory, PartyRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindUsingNamedParameters() {
|
||||
String included = "90";
|
||||
String excluded = "New Year";
|
||||
int min = 200;
|
||||
List<Party> result = partyRepository.findAllWithNamedParams(excluded, included, min);
|
||||
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
for (Party party : result) {
|
||||
assertThat(party.getDescription().contains(included)).isTrue();
|
||||
assertThat(party.getDescription().contains(excluded)).isFalse();
|
||||
assertThat(party.getAttendees() >= min).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindUsingPositionalParameters() {
|
||||
String included = "90";
|
||||
String excluded = "New Year";
|
||||
int min = 200;
|
||||
List<Party> result = partyRepository.findAllWithPositionalParams(excluded, included, min);
|
||||
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
for (Party party : result) {
|
||||
assertThat(party.getDescription().contains(included)).isTrue();
|
||||
assertThat(party.getDescription().contains(excluded)).isFalse();
|
||||
assertThat(party.getAttendees() >= min).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreQuotedNamedParamsAndParamAnnotationIfPosUsed() {
|
||||
String included = "90";
|
||||
String excluded = "New Year";
|
||||
int min = 200;
|
||||
List<Party> result = partyRepository.findAllWithPositionalParamsAndQuotedNamedParams(excluded, included, min);
|
||||
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
for (Party party : result) {
|
||||
assertThat(party.getDescription().contains(included)).isTrue();
|
||||
assertThat(party.getDescription().contains(excluded)).isFalse();
|
||||
assertThat(party.getAttendees() >= min).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
private interface BadRepository extends CrudRepository<Party, String> {
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" +
|
||||
" AND `desc` NOT LIKE '%' || $included || '%'")
|
||||
List<Party> findAllWithMixedParamsInQuery(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long min);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailUsingMixedParameters() {
|
||||
try {
|
||||
factory.getRepository(BadRepository.class);
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).as(e.toString())
|
||||
.isEqualTo("Using both named (1) and positional (2) placeholders is not supported, please choose " +
|
||||
"one over the other in findAllWithMixedParamsInQuery");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteQueryTest() {
|
||||
String included = "90";
|
||||
String excluded = "New Year";
|
||||
int max = 200;
|
||||
List<Party> result = partyRepository.removeWithPositionalParams(excluded, included, max);
|
||||
|
||||
assertThat(result.size()).isEqualTo(10);
|
||||
for (Party party : result) {
|
||||
assertThat(party.getDescription().contains(included)).isTrue();
|
||||
assertThat(party.getDescription().contains(excluded)).isFalse();
|
||||
assertThat(party.getAttendees() < max).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
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;
|
||||
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
|
||||
public class PageAndSliceIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private UserRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, UserRepository.class);
|
||||
}
|
||||
@Test
|
||||
public void shouldPageThroughResults() {
|
||||
Page<User> page1 = repository.findByAgeGreaterThan(9, PageRequest.of(0, 40)); //there are 90 matching users
|
||||
Page<User> page2 = repository.findByAgeGreaterThan(9, page1.nextPageable());
|
||||
Page<User> page3 = repository.findByAgeGreaterThan(9, page2.nextPageable());
|
||||
|
||||
assertThat(page1.getTotalElements()).isEqualTo(90);
|
||||
assertThat(page1.getTotalPages()).isEqualTo(3);
|
||||
assertThat(page1.hasContent()).isTrue();
|
||||
assertThat(page1.hasNext()).isTrue();
|
||||
assertThat(page1.getNumberOfElements()).isEqualTo(40);
|
||||
|
||||
assertThat(page2.hasContent()).isTrue();
|
||||
assertThat(page2.hasNext()).isTrue();
|
||||
assertThat(page2.getNumberOfElements()).isEqualTo(40);
|
||||
|
||||
assertThat(page3.hasContent()).isTrue();
|
||||
assertThat(page3.hasNext()).isFalse();
|
||||
assertThat(page3.getNumberOfElements()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.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, PageRequest.of(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());
|
||||
assertThat(slice.getContent().size()).isEqualTo(3);
|
||||
}
|
||||
assertThat(allMatching.size()).isEqualTo(9);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void shouldThrowWhenPageableIsNullSliceQuery() {
|
||||
repository.findByAgeLessThan(9, null);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
|
||||
/**
|
||||
* An entity used to test conversion of parameters in query derivations.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class Party {
|
||||
|
||||
@Id
|
||||
private final String key;
|
||||
|
||||
private final String name;
|
||||
|
||||
@Field("desc")
|
||||
private final String description;
|
||||
|
||||
private final Date eventDate;
|
||||
|
||||
private final long attendees;
|
||||
|
||||
private final Point location;
|
||||
|
||||
public Party(String key, String name, String description, Date eventDate, long attendees, Point location) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.eventDate = eventDate;
|
||||
this.attendees = attendees;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Date getEventDate() {
|
||||
return eventDate;
|
||||
}
|
||||
|
||||
public long getAttendees() {
|
||||
return attendees;
|
||||
}
|
||||
|
||||
public Point getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Party party = (Party) o;
|
||||
|
||||
return key.equals(party.key);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Party{" +
|
||||
"name='" + name + '\'' +
|
||||
", eventDate=" + eventDate +
|
||||
", location=" + location +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
public interface PartyPagingRepository extends CouchbasePagingAndSortingRepository<Party, String> {
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.PersistTo;
|
||||
import com.couchbase.client.java.ReplicateTo;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.SpatialView;
|
||||
import com.couchbase.client.java.view.View;
|
||||
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class PartyPopulatorListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
}
|
||||
|
||||
private void populateTestData(Bucket client, ClusterInfo clusterInfo) {
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
cal.set(Calendar.YEAR, 2015);
|
||||
cal.set(Calendar.DAY_OF_MONTH, 10);
|
||||
cal.set(Calendar.MONTH, Calendar.JANUARY);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
Party p = new Party("testparty-" + i, "party like it's 199" + i,
|
||||
"An awesome party, 90's themed, every 10 of the month",
|
||||
cal.getTime(), 100 + i * 10,
|
||||
new Point(i, -i));
|
||||
template.save(p, PersistTo.MASTER, ReplicateTo.NONE);
|
||||
cal.roll(Calendar.MONTH, true);
|
||||
}
|
||||
|
||||
cal.clear();
|
||||
cal.set(Calendar.YEAR, 1990);
|
||||
cal.set(Calendar.MONTH, Calendar.JANUARY);
|
||||
cal.set(Calendar.DAY_OF_MONTH, 01);
|
||||
template.save(new Party("aTestParty", "New Year's Eve 90", "Happy New Year", cal.getTime(), 1230000, new Point(100, 100)));
|
||||
template.save(new Party("lowercaseParty", "lowercase party", "lowercase party", cal.getTime(), 1000, new Point(100, 100)));
|
||||
template.save(new Party("uppercaseParty", "Uppercase party", "Uppercase party", cal.getTime(), 1000, new Point(100, 100)));
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
//standard views
|
||||
List<View> views = new ArrayList<View>();
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == \"" + Party.class.getName() + "\") " +
|
||||
"{ emit(doc.eventDate, null); } }";
|
||||
views.add(DefaultView.create("byDate", mapFunction, "_count"));
|
||||
|
||||
//create the view design document
|
||||
DesignDocument designDoc = DesignDocument.create("party", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
|
||||
//geo views
|
||||
List<View> geoViews = new ArrayList<View>();
|
||||
mapFunction = "function (doc, meta) { if(doc._class == \"" + Party.class.getName() + "\") " +
|
||||
"{ emit([doc.location.x, doc.location.y], null); } }";
|
||||
geoViews.add(SpatialView.create("byLocation", mapFunction));
|
||||
|
||||
mapFunction = "function (doc, meta) { if(doc._class == \"" + Party.class.getName() + "\") " +
|
||||
"{ emit([doc.location.x, doc.location.y, doc.attendees], null); } }";
|
||||
geoViews.add(SpatialView.create("byLocationAndAttendees", mapFunction));
|
||||
|
||||
//create the geo views design document
|
||||
DesignDocument geoDesignDoc = DesignDocument.create("partyGeo", geoViews);
|
||||
client.bucketManager().upsertDesignDocument(geoDesignDoc);
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import com.couchbase.client.java.query.consistency.ScanConsistency;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
|
||||
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;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@ViewIndexed(designDoc = "party", viewName = "all")
|
||||
@N1qlPrimaryIndexed
|
||||
@N1qlSecondaryIndexed(indexName = "party")
|
||||
public interface PartyRepository extends CouchbaseRepository<Party, String> {
|
||||
|
||||
List<Party> findByAttendeesGreaterThanEqual(int minAttendees);
|
||||
|
||||
List<Party> findByName(String name);
|
||||
|
||||
List<Party> findByEventDateIs(Date targetDate);
|
||||
|
||||
@View(designDocument = "party", viewName = "byDate")
|
||||
List<Party> findFirst3ByEventDateGreaterThanEqual(Date targetDate);
|
||||
|
||||
List<Object> findAllByDescriptionNotNull();
|
||||
|
||||
long countAllByDescriptionNotNull();
|
||||
|
||||
@WithConsistency(ScanConsistency.NOT_BOUNDED)
|
||||
@Query("SELECT MAX(attendees) FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
long findMaxAttendees();
|
||||
|
||||
@Query("SELECT `desc` FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
String findSomeString();
|
||||
|
||||
@Query("SELECT count(*) + 5 FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
long countCustomPlusFive();
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter}")
|
||||
long countCustom();
|
||||
|
||||
@Query("SELECT 1 = 1")
|
||||
boolean justABoolean();
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `attendees` >= $1")
|
||||
Page<Party> findPartiesWithAttendee(int count, Pageable pageable);
|
||||
|
||||
@Query("#{#n1ql.selectEntity}")
|
||||
List<Party> findParties(Sort sort);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $included || '%' AND attendees >= $min" +
|
||||
" AND `desc` NOT LIKE '%' || $excluded || '%'")
|
||||
List<Party> findAllWithNamedParams(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long minimumAttendees);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" +
|
||||
" AND `desc` NOT LIKE '%' || $1 || '%'")
|
||||
List<Party> findAllWithPositionalParams(String ex, String inc, long minimumAttendees);
|
||||
|
||||
@Query("#{#n1ql.delete} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees < $3" +
|
||||
" AND `desc` NOT LIKE '%' || $1 || '%' #{#n1ql.returning}")
|
||||
List<Party> removeWithPositionalParams(String ex, String inc, long minimumAttendees);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" +
|
||||
" AND `desc` NOT LIKE '%' || $1 || '%' AND `desc` != \"this is \\\"$excluded\\\"\"")
|
||||
List<Party> findAllWithPositionalParamsAndQuotedNamedParams(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long min);
|
||||
|
||||
List<Party> findByDescriptionOrName(String description, String name);
|
||||
|
||||
List<Party> removeByDescriptionOrName(String description, String name);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and eventDate = $1")
|
||||
List<Party> getByEventDate(Date eventDate);
|
||||
|
||||
List<Party> findByDescriptionStartingWith(String description);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.JsonDocument;
|
||||
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.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(PartyPopulatorListener.class)
|
||||
public class QueryDerivationConversionIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private PartyRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = factory.getRepository(PartyRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertsDateParameterInN1qlQuery() {
|
||||
Optional<Party> partyApril = repository.findById("testparty-3");
|
||||
assertThat(partyApril.isPresent()).isTrue();
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
cal.set(2015, Calendar.APRIL, 10);
|
||||
Date find = cal.getTime();
|
||||
|
||||
List<Party> parties = repository.findByEventDateIs(find);
|
||||
assertThat(parties).isNotNull();
|
||||
assertThat(parties.size()).isEqualTo(1);
|
||||
assertThat(parties.get(0).getEventDate()).isEqualTo(find);
|
||||
|
||||
JsonDocument doc = client.get(parties.get(0).getKey());
|
||||
assertThat(doc.content().get("eventDate")).isEqualTo(find.getTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptLongParameterInN1qlQuery() {
|
||||
List<Party> newYear90 = repository.findByAttendeesGreaterThanEqual(1200000);
|
||||
assertThat(newYear90).isNotNull();
|
||||
assertThat(newYear90.size()).isEqualTo(1);
|
||||
assertThat(newYear90.get(0).getKey()).isEqualTo("aTestParty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertDateParameterInViewQuery() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
cal.set(2015, Calendar.AUGUST, 12);
|
||||
Date find = cal.getTime();
|
||||
|
||||
List<Party> afterSummerParties = repository.findFirst3ByEventDateGreaterThanEqual(find);
|
||||
assertThat(afterSummerParties).isNotNull();
|
||||
assertThat(afterSummerParties.size()).isEqualTo(3);
|
||||
for (Party afterSummerParty : afterSummerParties) {
|
||||
assert(afterSummerParty.getEventDate().after(find));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
/**
|
||||
* This tests ReactiveSortingRepository features in the Couchbase connector.
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(PartyPopulatorListener.class)
|
||||
public class ReactiveN1qlCouchbaseRepositoryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private ReactivePartySortingRepository repository;
|
||||
|
||||
private ReactivePartyRepository partyRepository;
|
||||
|
||||
private ItemRepository itemRepository;
|
||||
|
||||
private final String KEY_PARTY = "ReactiveParty1";
|
||||
private final String KEY_ITEM = "ReactiveItem1";
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ReactiveRepositoryFactorySupport factory = new ReactiveCouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, ReactivePartySortingRepository.class);
|
||||
partyRepository = getRepositoryWithRetry(factory, ReactivePartyRepository.class);
|
||||
itemRepository = getRepositoryWithRetry(factory, ItemRepository.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
try { itemRepository.deleteById(KEY_ITEM); } catch (DataRetrievalFailureException e) {}
|
||||
try { partyRepository.deleteById(KEY_PARTY); } catch (DataRetrievalFailureException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindAllWithSort() {
|
||||
Iterable<Party> allByAttendanceDesc = repository.findAll(Sort.by(Sort.Direction.DESC, "attendees")).collectList().block();
|
||||
long previousAttendance = Long.MAX_VALUE;
|
||||
for (Party party : allByAttendanceDesc) {
|
||||
assertThat(party.getAttendees() <= previousAttendance).isTrue();
|
||||
previousAttendance = party.getAttendees();
|
||||
}
|
||||
assertThat(previousAttendance == Long.MAX_VALUE)
|
||||
.as("Expected to find several parties").isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSortOnRenamedFieldIfJsonNameIsProvidedInSort() {
|
||||
Iterable<Party> parties = repository.findAll(Sort.by(Sort.Direction.DESC, "desc")).collectList().block();
|
||||
String previousDesc = null;
|
||||
for (Party party : parties) {
|
||||
if (previousDesc != null) {
|
||||
assertThat(party.getDescription().compareTo(previousDesc) <= 0).isTrue();
|
||||
}
|
||||
previousDesc = party.getDescription();
|
||||
}
|
||||
assertThat(previousDesc).as("Expected to find several parties").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSortWithoutCaseSensitivity() {
|
||||
Iterable<Party> parties = repository.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC, "desc").ignoreCase())).collectList().block();
|
||||
String previousDesc = null;
|
||||
for(Party party : parties) {
|
||||
if (previousDesc != null) {
|
||||
assertThat(party.getDescription().compareToIgnoreCase(previousDesc) <= 0)
|
||||
.isTrue();
|
||||
}
|
||||
previousDesc = party.getDescription();
|
||||
}
|
||||
assertThat(previousDesc).as("Expected to find several parties").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomSpelCountQuery() {
|
||||
long count = partyRepository.countCustom().block();
|
||||
assertThat(count >= 12).as("Count query for parties should be atleast 12")
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartTreeQuery() {
|
||||
long count = partyRepository.countAllByDescriptionNotNull().block();
|
||||
assertThat(count >= 12)
|
||||
.as("Count query for parties with description not null should be atleast 12")
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpelDateConvertion() {
|
||||
final String key = "testReactiveSpelDateConvertion";
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
cal.set(2018, Calendar.SEPTEMBER, 15);
|
||||
Date date = cal.getTime();
|
||||
partyRepository.save(new Party(key, "", "", date, 0, null)).block();
|
||||
List<Party> partyList = partyRepository.getByEventDate(date).collectList().block();
|
||||
assertThat(partyList.size() == 1).isTrue();
|
||||
assertThat(key).as("Key mismatch").isEqualTo(partyList.get(0).getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testN1qlQueryWithInvalidValue() {
|
||||
partyRepository.save(new Party("testReactiveN1qlQueryWithInvalidValue", "", "testReactiveN1qlQueryWithInvalidValue", null, 0, null));
|
||||
final String description = "testReactiveN1qlQueryWithInvalidValue* OR `description` LIKE \"\"";
|
||||
List<Party> partyList = partyRepository.findByDescriptionStartingWith(description).collectList().block();
|
||||
assertThat(partyList.size() == 0).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
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.repository.query.Param;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@ViewIndexed(designDoc = "reactiveParty", viewName = "all")
|
||||
@N1qlSecondaryIndexed(indexName = "reactiveParty")
|
||||
public interface ReactivePartyRepository extends ReactiveCouchbaseRepository<Party, String> {
|
||||
|
||||
Flux<Party> findByAttendeesGreaterThanEqual(int minAttendees);
|
||||
|
||||
Flux<Party> findByEventDateIs(Date targetDate);
|
||||
|
||||
@View(designDocument = "reactiveParty", viewName = "byDate")
|
||||
Flux<Party> findFirst3ByEventDateGreaterThanEqual(Date targetDate);
|
||||
|
||||
Flux<Object> findAllByDescriptionNotNull();
|
||||
|
||||
Mono<Long> countAllByDescriptionNotNull();
|
||||
|
||||
@Query("SELECT MAX(attendees) FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
Mono<Long> findMaxAttendees();
|
||||
|
||||
@Query("SELECT `desc` FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
Mono<String> findSomeString();
|
||||
|
||||
@Query("SELECT count(*) + 5 FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
Mono<Long> countCustomPlusFive();
|
||||
|
||||
@Query("SELECT count(*) FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
|
||||
Mono<Long> countCustom();
|
||||
|
||||
@Query("SELECT 1 = 1")
|
||||
Mono<Boolean> justABoolean();
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $included || '%' AND attendees >= $min" +
|
||||
" AND `desc` NOT LIKE '%' || $excluded || '%'")
|
||||
Flux<Party> findAllWithNamedParams(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long minimumAttendees);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" +
|
||||
" AND `desc` NOT LIKE '%' || $1 || '%'")
|
||||
Flux<Party> findAllWithPositionalParams(String ex, String inc, long minimumAttendees);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" +
|
||||
" AND `desc` NOT LIKE '%' || $1 || '%' AND `desc` != \"this is \\\"$excluded\\\"\"")
|
||||
Flux<Party> findAllWithPositionalParamsAndQuotedNamedParams(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long min);
|
||||
|
||||
Flux<Party> findByDescriptionOrName(String description, String name);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and eventDate = $1")
|
||||
Flux<Party> getByEventDate(Date eventDate);
|
||||
|
||||
Flux<Party> findByDescriptionStartingWith(String description);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public interface ReactivePartySortingRepository extends ReactiveCouchbaseSortingRepository<Party, String> {
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import com.couchbase.client.java.repository.annotation.Id;
|
||||
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
|
||||
import org.springframework.data.couchbase.core.mapping.id.GenerationStrategy;
|
||||
|
||||
/**
|
||||
* @author David Kelly
|
||||
*/
|
||||
public class ReactivePlace {
|
||||
@Id
|
||||
@GeneratedValue(strategy= GenerationStrategy.UNIQUE)
|
||||
public String id;
|
||||
|
||||
@Field("name")
|
||||
public String name;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ReactivePlace(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactory;
|
||||
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
/**
|
||||
* @author David Kelly
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleReactiveCouchbaseRepositoryListener.class)
|
||||
public class ReactivePlaceIntegrationTests {
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private ReactivePlaceRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ReactiveRepositoryFactorySupport factory = new ReactiveCouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, ReactivePlaceRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnGeneratedId() {
|
||||
ReactivePlace place = new ReactivePlace("somePlace");
|
||||
assertNull(place.getId());
|
||||
ReactivePlace returned = repository.save(place).block();
|
||||
assertThat(returned.getId()).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
|
||||
import org.springframework.data.couchbase.core.query.Query;
|
||||
import org.springframework.data.couchbase.core.query.ViewIndexed;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author David Kelly
|
||||
*/
|
||||
@N1qlPrimaryIndexed
|
||||
public interface ReactivePlaceRepository extends ReactiveCouchbaseRepository<ReactivePlace, String> {
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE name = $1")
|
||||
Flux<ReactivePlace> findByName(String name);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class ReactiveUser {
|
||||
|
||||
@Id
|
||||
private final String key;
|
||||
|
||||
private final String username;
|
||||
|
||||
private final int age;
|
||||
|
||||
public ReactiveUser(String key, String username, int age) {
|
||||
this.key = key;
|
||||
this.username = username;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ReactiveUser user = (ReactiveUser) o;
|
||||
return key.equals(user.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import com.couchbase.client.java.query.consistency.ScanConsistency;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@ViewIndexed(designDoc = "reactiveUser", viewName = "all")
|
||||
@N1qlSecondaryIndexed(indexName = "reactiveUser")
|
||||
public interface ReactiveUserRepository extends ReactiveCouchbaseRepository<ReactiveUser, String> {
|
||||
|
||||
@View(designDocument = "user", viewName = "all")
|
||||
Flux<ReactiveUser> customViewQuery(ViewQuery query);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE username = $1 and #{#n1ql.filter}")
|
||||
Flux<ReactiveUser> findByUsername(String username);
|
||||
|
||||
@Query("SELECT * FROM #{#n1ql.bucket} WHERE username = $1 and #{#n1ql.filter}")
|
||||
Flux<ReactiveUser> findByUsernameBadSelect(String username);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE username LIKE '%-#{3 + 1}' and #{#n1ql.filter}")
|
||||
Flux<ReactiveUser> findByUsernameWithSpelAndPlaceholder();
|
||||
|
||||
@Query
|
||||
Flux<ReactiveUser> findByUsernameRegexAndUsernameIn(String regex, List<String> sample);
|
||||
|
||||
Flux<ReactiveUser> findByUsernameContains(String contains);
|
||||
|
||||
Flux<ReactiveUser> findByUsernameNear(String place);//this is to check that there's a N1QL derivation AND it fails
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.domain.Sort.Direction;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
|
||||
import org.springframework.data.couchbase.repository.support.N1qlCouchbaseRepository;
|
||||
import org.springframework.data.couchbase.repository.support.ViewMetadataProvider;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.json.JsonObject;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import com.couchbase.client.java.query.N1qlQuery;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
import com.couchbase.client.java.view.ViewResult;
|
||||
import com.couchbase.client.java.view.ViewRow;
|
||||
|
||||
public class RepositoryIndexUsageTest {
|
||||
|
||||
private static final org.springframework.data.couchbase.core.query.Consistency CONSISTENCY = Consistency.STRONGLY_CONSISTENT;
|
||||
|
||||
private CouchbaseOperations couchbaseOperations;
|
||||
private N1qlCouchbaseRepository<String, String> repository;
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
ViewRow mockCountRow1 = mock(ViewRow.class);
|
||||
when(mockCountRow1.value()).thenReturn("100");
|
||||
when(mockCountRow1.id()).thenReturn("id1");
|
||||
ViewRow mockCountRow2 = mock(ViewRow.class);
|
||||
when(mockCountRow2.value()).thenReturn("200");
|
||||
when(mockCountRow2.id()).thenReturn("id2");
|
||||
List<ViewRow> allCountRows = Arrays.asList(mockCountRow1, mockCountRow2);
|
||||
|
||||
ViewResult mockCountResult = mock(ViewResult.class);
|
||||
when(mockCountResult.iterator()).thenReturn(allCountRows.iterator());
|
||||
|
||||
Bucket mockBucket = mock(Bucket.class);
|
||||
when(mockBucket.name()).thenReturn("mockBucket");
|
||||
|
||||
CouchbaseConverter mockConverter = mock(CouchbaseConverter.class);
|
||||
when(mockConverter.getTypeKey()).thenReturn("mockType");
|
||||
when(mockConverter.convertForWriteIfNeeded(any(Object.class))).thenAnswer(
|
||||
invocation -> invocation.getArgument(0));
|
||||
|
||||
couchbaseOperations = mock(CouchbaseOperations.class);
|
||||
when(couchbaseOperations.getDefaultConsistency()).thenReturn(CONSISTENCY);
|
||||
when(couchbaseOperations.getCouchbaseBucket()).thenReturn(mockBucket);
|
||||
when(couchbaseOperations.getConverter()).thenReturn(mockConverter);
|
||||
when(couchbaseOperations.findByView(any(ViewQuery.class), any(Class.class))).thenReturn(allCountRows);
|
||||
when(couchbaseOperations.findByN1QL(any(N1qlQuery.class), any(Class.class))).thenReturn(Collections.emptyList());
|
||||
when(couchbaseOperations.queryView(any(ViewQuery.class))).thenReturn(mockCountResult);
|
||||
when(couchbaseOperations.queryN1QL(any(N1qlQuery.class))).thenReturn(null);
|
||||
|
||||
CouchbaseEntityInformation metadata = mock(CouchbaseEntityInformation.class);
|
||||
when(metadata.getJavaType()).thenReturn(String.class);
|
||||
|
||||
repository = new N1qlCouchbaseRepository<String, String>(metadata, couchbaseOperations);
|
||||
repository.setViewMetadataProvider(mock(ViewMetadataProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllUsesViewWithConfiguredConsistency() {
|
||||
String expectedQueryParams = "ViewQuery(string/all){params=\"reduce=false&stale=false\"}";
|
||||
repository.findAll();
|
||||
|
||||
verify(couchbaseOperations, never()).queryView(any(ViewQuery.class));
|
||||
verify(couchbaseOperations, never()).findByN1QL(any(N1qlQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<ViewQuery> queryCaptor = ArgumentCaptor.forClass(ViewQuery.class);
|
||||
verify(couchbaseOperations).findByView(queryCaptor.capture(), any(Class.class));
|
||||
String sQuery = queryCaptor.getValue().toString();
|
||||
assertThat(sQuery).isEqualTo(expectedQueryParams);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllKeysUsesViewWithConfiguredConsistency() {
|
||||
String expectedQueryParams = "ViewQuery(string/all){params=\"reduce=false&stale=false\", keys=\"[\"someKey\"]\"}";
|
||||
repository.findAllById(Collections.singleton("someKey"));
|
||||
|
||||
verify(couchbaseOperations, never()).queryView(any(ViewQuery.class));
|
||||
verify(couchbaseOperations, never()).findByN1QL(any(N1qlQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<ViewQuery> queryCaptor = ArgumentCaptor.forClass(ViewQuery.class);
|
||||
verify(couchbaseOperations).findByView(queryCaptor.capture(), any(Class.class));
|
||||
String sQuery = queryCaptor.getValue().toString();
|
||||
assertThat(sQuery).isEqualTo(expectedQueryParams);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountUsesViewWithConfiguredConsistencyAndReduces() {
|
||||
String expectedQueryParams = "ViewQuery(string/all){params=\"reduce=true&stale=false\"}";
|
||||
repository.count();
|
||||
|
||||
verify(couchbaseOperations, never()).findByView(any(ViewQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).findByN1QL(any(N1qlQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<ViewQuery> queryCaptor = ArgumentCaptor.forClass(ViewQuery.class);
|
||||
verify(couchbaseOperations).queryView(queryCaptor.capture());
|
||||
String sQuery = queryCaptor.getValue().toString();
|
||||
assertThat(sQuery).isEqualTo(expectedQueryParams);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountParsesAndAddsLongValuesFromRows() {
|
||||
long count = repository.count();
|
||||
assertThat(count).isEqualTo(300L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAllUsesViewWithConfiguredConsistency() {
|
||||
String expectedQueryParams = "ViewQuery(string/all){params=\"reduce=false&stale=false\"}";
|
||||
repository.deleteAll();
|
||||
|
||||
verify(couchbaseOperations, never()).findByView(any(ViewQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).findByN1QL(any(N1qlQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<ViewQuery> queryCaptor = ArgumentCaptor.forClass(ViewQuery.class);
|
||||
verify(couchbaseOperations).queryView(queryCaptor.capture());
|
||||
String sQuery = queryCaptor.getValue().toString();
|
||||
assertThat(sQuery).isEqualTo(expectedQueryParams);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllSortedUsesN1qlWithConfiguredConsistencyAndOrderBy() {
|
||||
String expectedOrderClause = "ORDER BY `length` ASC";
|
||||
Sort sort = Sort.by(Direction.ASC, "length");
|
||||
repository.findAll(sort);
|
||||
|
||||
verify(couchbaseOperations, never()).findByView(any(ViewQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryView(any(ViewQuery.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<N1qlQuery> queryCaptor = ArgumentCaptor.forClass(N1qlQuery.class);
|
||||
verify(couchbaseOperations).findByN1QL(queryCaptor.capture(), any(Class.class));
|
||||
|
||||
JsonObject query = queryCaptor.getValue().n1ql();
|
||||
assertThat(query.getString("scan_consistency"))
|
||||
.isEqualTo(CONSISTENCY.n1qlConsistency().n1ql());
|
||||
String statement = query.getString("statement");
|
||||
assertThat(statement.contains(expectedOrderClause))
|
||||
.as("Expected " + expectedOrderClause + " in " + statement).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAllPagedUsesUsesN1qlConfiguredConsistencyAndLimitOffset() {
|
||||
String expectedLimitClause = "LIMIT 10 OFFSET 0";
|
||||
repository.findAll(PageRequest.of(0, 10));
|
||||
|
||||
verify(couchbaseOperations, never()).findByView(any(ViewQuery.class), any(Class.class));
|
||||
verify(couchbaseOperations, never()).queryView(any(ViewQuery.class));
|
||||
verify(couchbaseOperations, never()).queryN1QL(any(N1qlQuery.class));
|
||||
ArgumentCaptor<N1qlQuery> queryCaptor = ArgumentCaptor.forClass(N1qlQuery.class);
|
||||
verify(couchbaseOperations).findByN1QL(queryCaptor.capture(), any(Class.class));
|
||||
|
||||
JsonObject query = queryCaptor.getValue().n1ql();
|
||||
assertThat(query.getString("scan_consistency"))
|
||||
.isEqualTo(CONSISTENCY.n1qlConsistency().n1ql());
|
||||
String statement = query.getString("statement");
|
||||
assertThat(statement.contains(expectedLimitClause))
|
||||
.as("Expected " + expectedLimitClause + " in " + statement).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAllSwallowsDocumentDoesNotExistException() {
|
||||
doThrow(new DataRetrievalFailureException("ignored", new DocumentDoesNotExistException())).when(couchbaseOperations).remove("id1");
|
||||
doThrow(new DataRetrievalFailureException("thrown")).when(couchbaseOperations).remove("id2");
|
||||
try {
|
||||
repository.deleteAll();
|
||||
fail("Expected DataRetrievalFailureException on id2");
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
if (!"thrown".equals(e.getMessage())) {
|
||||
fail("DataRetrievalFailureException caused by DocumentDoesNotExistException should have been ignored");
|
||||
}
|
||||
}
|
||||
verify(couchbaseOperations).remove("id1");
|
||||
verify(couchbaseOperations).remove("id2");
|
||||
}
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.AsyncUtils;
|
||||
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.document.JsonDocument;
|
||||
import com.couchbase.client.java.error.CASMismatchException;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import com.couchbase.client.java.view.Stale;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
|
||||
public class SimpleCouchbaseRepositoryIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private RepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private UserRepository repository;
|
||||
private VersionedDataRepository versionedDataRepository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, UserRepository.class);
|
||||
versionedDataRepository = getRepositoryWithRetry(factory, VersionedDataRepository.class);
|
||||
}
|
||||
|
||||
private void remove(String key) {
|
||||
try {
|
||||
client.remove(key);
|
||||
} catch (DocumentDoesNotExistException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCrud() {
|
||||
String key = "my_unique_user_key";
|
||||
User instance = new User(key, "foobar", 22);
|
||||
repository.save(instance);
|
||||
|
||||
Optional<User> found = repository.findById(key);
|
||||
assertThat(found.isPresent()).isTrue();
|
||||
|
||||
found.ifPresent(actual -> {
|
||||
assertThat(actual.getKey()).isEqualTo(instance.getKey());
|
||||
assertThat(actual.getUsername()).isEqualTo(instance.getUsername());
|
||||
|
||||
assertThat(repository.existsById(key)).isTrue();
|
||||
repository.delete(actual);
|
||||
});
|
||||
|
||||
assertThat(repository.findById(key).isPresent()).isFalse();
|
||||
assertThat(repository.existsById(key)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* This test uses/assumes a default viewName called "all" that is configured on Couchbase.
|
||||
*/
|
||||
public void shouldFindAll() {
|
||||
// do a non-stale query to populate data for testing.
|
||||
client.query(ViewQuery.from("user", "all").stale(Stale.FALSE));
|
||||
|
||||
Iterable<User> allUsers = repository.findAll();
|
||||
int size = 0;
|
||||
for (User u : allUsers) {
|
||||
size++;
|
||||
assertThat(u.getKey()).isNotNull();
|
||||
assertThat(u.getUsername()).isNotNull();
|
||||
}
|
||||
assertThat(size).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCount() {
|
||||
// do a non-stale query to populate data for testing.
|
||||
client.query(ViewQuery.from("user", "all").stale(Stale.FALSE));
|
||||
|
||||
assertThat(repository.count()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("View based query with copy of params from a ViewQuery in the method parameter not implemented")
|
||||
//TODO re-enable test once ViewQuery parameters other than designDoc/viewName can be copied
|
||||
public void shouldFindCustom() {
|
||||
Iterable<User> users = repository.customViewQuery(ViewQuery.from("", "").limit(2).stale(Stale.FALSE));
|
||||
int size = 0;
|
||||
for (User u : users) {
|
||||
size++;
|
||||
assertThat(u.getKey()).isNotNull();
|
||||
assertThat(u.getUsername()).isNotNull();
|
||||
}
|
||||
assertThat(size).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindByUsernameUsingN1ql() {
|
||||
User user = repository.findByUsername("uname-1");
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getKey()).isEqualTo("testuser-1");
|
||||
assertThat(user.getUsername()).isEqualTo("uname-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailFindByUsernameWithNoIdOrCas() {
|
||||
try {
|
||||
User user = repository.findByUsernameBadSelect("uname-1");
|
||||
fail("shouldFailFindByUsernameWithNoIdOrCas");
|
||||
} catch (CouchbaseQueryExecutionException e) {
|
||||
assertThat(e.getMessage().contains("_ID")).as("_ID expected in exception " + e)
|
||||
.isTrue();
|
||||
assertThat(e.getMessage().contains("_CAS")).as("_CAS expected in exception " + e)
|
||||
.isTrue();
|
||||
} catch (Exception e) {
|
||||
fail("CouchbaseQueryExecutionException expected");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindFromUsernameInlineWithSpelParsing() {
|
||||
User user = repository.findByUsernameWithSpelAndPlaceholder();
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getKey()).isEqualTo("testuser-4");
|
||||
assertThat(user.getUsername()).isEqualTo("uname-4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindFromDeriveQueryWithRegexpAndIn() {
|
||||
User user = repository.findByUsernameRegexAndUsernameIn("uname-[123]", Arrays.asList("uname-2", "uname-4"));
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getKey()).isEqualTo("testuser-2");
|
||||
assertThat(user.getUsername()).isEqualTo("uname-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindContainsWithoutAnnotation() {
|
||||
List<User> users = repository.findByUsernameContains("-9");
|
||||
assertThat(users).isNotNull();
|
||||
assertThat(users.isEmpty()).isFalse();
|
||||
for (User user : users) {
|
||||
assertThat(user.getUsername().startsWith("uname-9")).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDefaultToN1qlQueryDerivation() {
|
||||
try {
|
||||
User u = repository.findByUsernameNear("london");
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (!e.getMessage().contains("N1QL")) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTakeVersionIntoAccountWhenDoingMultipleUpdates() {
|
||||
final String key = "versionedUserTest";
|
||||
VersionedData initial = new VersionedData(key, "ABCD");
|
||||
versionedDataRepository.save(initial);
|
||||
assertThat(initial.version).isNotEqualTo(0L);
|
||||
|
||||
Optional<VersionedData> fetch1 = versionedDataRepository.findById(key);
|
||||
|
||||
assertThat(fetch1.isPresent()).isTrue();
|
||||
fetch1.ifPresent(actual -> {
|
||||
assertThat(actual).isNotSameAs(initial);
|
||||
assertThat(initial.version).isEqualTo(actual.version);
|
||||
});
|
||||
|
||||
VersionedData versionedData = fetch1.get();
|
||||
|
||||
JsonDocument bypass = client.get(key);
|
||||
bypass.content().put("data", "BBBB");
|
||||
JsonDocument bypassed = client.upsert(bypass);
|
||||
|
||||
assertThat(versionedData.version).isNotEqualTo(bypassed.cas());
|
||||
System.out.println(bypassed.cas());
|
||||
|
||||
try {
|
||||
versionedData.setData("ZZZZ");
|
||||
versionedDataRepository.save(versionedData);
|
||||
fail("Expected CAS failure");
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
//success
|
||||
assertThat(e.getCause() instanceof CASMismatchException)
|
||||
.as("optimistic locking should have CASMismatchException as cause, got " + e
|
||||
.getCause()).isTrue();
|
||||
} finally {
|
||||
client.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: investigate cause of intermittent failure
|
||||
@Ignore("Fails intermittently (see DATACOUCH-452)")
|
||||
@Test
|
||||
public void shouldUpdateDocumentConcurrently() throws Exception {
|
||||
final String key = testName.getMethodName();
|
||||
remove(key);
|
||||
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
final AtomicLong updatedCounter = new AtomicLong();
|
||||
VersionedData initial = new VersionedData(key, "value-initial");
|
||||
versionedDataRepository.save(initial);
|
||||
assertThat(initial.version).isNotEqualTo(0L);
|
||||
|
||||
Callable<Void> task = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
boolean updated = false;
|
||||
while(!updated) {
|
||||
long counterValue = counter.incrementAndGet();
|
||||
VersionedData messageData = versionedDataRepository.findById(key).get();
|
||||
messageData.data = "value-" + counterValue;
|
||||
try {
|
||||
versionedDataRepository.save(messageData);
|
||||
updated = true;
|
||||
updatedCounter.incrementAndGet();
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AsyncUtils.executeConcurrently(5, task);
|
||||
|
||||
assertThat(versionedDataRepository.findById(key).get().data)
|
||||
.isNotEqualTo(initial.data);
|
||||
assertThat(updatedCounter.intValue()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailOnMultipleConcurrentSaves() throws Exception {
|
||||
final String key = testName.getMethodName();
|
||||
remove(key);
|
||||
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
final AtomicLong optimisticLockCounter = new AtomicLong();
|
||||
|
||||
Callable<Void> task = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
long counterValue = counter.incrementAndGet();
|
||||
VersionedData messageData = new VersionedData(key, "value-" + counterValue);
|
||||
try {
|
||||
versionedDataRepository.save(messageData);
|
||||
} catch (OptimisticLockingFailureException e) {
|
||||
optimisticLockCounter.incrementAndGet();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
AsyncUtils.executeConcurrently(5, task);
|
||||
|
||||
assertThat(optimisticLockCounter.intValue()).isEqualTo(4);
|
||||
}
|
||||
|
||||
|
||||
public interface VersionedDataRepository extends CouchbaseRepository<VersionedData, String> { }
|
||||
|
||||
@Document
|
||||
public static class VersionedData {
|
||||
|
||||
@Id
|
||||
private final String key;
|
||||
|
||||
@Version
|
||||
public long version = 0L;
|
||||
|
||||
private String data;
|
||||
|
||||
public VersionedData(String key, String data) {
|
||||
this.key = key;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.key + " " + this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
VersionedData vd = (VersionedData) o;
|
||||
return key.equals(vd.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.PersistTo;
|
||||
import com.couchbase.client.java.ReplicateTo;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.View;
|
||||
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class SimpleCouchbaseRepositoryListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
}
|
||||
|
||||
private void populateTestData(Bucket client, ClusterInfo clusterInfo) {
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
User u = new User("testuser-" + i, "uname-" + i, i);
|
||||
template.save(u, PersistTo.MASTER, ReplicateTo.NONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository." +
|
||||
"User\") { emit(null, null); } }";
|
||||
View view = DefaultView.create("all", mapFunction, "_count");
|
||||
List<View> views = Collections.singletonList(view);
|
||||
DesignDocument designDoc = DesignDocument.create("user", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactory;
|
||||
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
/**
|
||||
* @author David Kelly
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleReactiveCouchbaseRepositoryListener.class)
|
||||
public class SimpleReactiveCouchbaseRepositoryDeleteAllIntegrationTests {
|
||||
// We do these tests here, rather in the simple crud tests, so we don't interact
|
||||
// with those tests that make assumptions about what documents should be
|
||||
// in the repo.
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private ReactiveUserRepository repository;
|
||||
|
||||
private long getCount() {
|
||||
return repository.count().block().longValue();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ReactiveRepositoryFactorySupport factory = new ReactiveCouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, ReactiveUserRepository.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleDeleteAll() {
|
||||
String key = "my_unique_user_key";
|
||||
|
||||
// in case there are other tests later, lets insure there is at least one
|
||||
// User in the repository
|
||||
ReactiveUser instance = new ReactiveUser(key, "foobar", 22);
|
||||
repository.save(instance).block();
|
||||
|
||||
// we put a user in, lets be sure the count reflects that.
|
||||
assertThat(getCount() > 0L).isTrue();
|
||||
|
||||
repository.deleteAll().block();
|
||||
|
||||
// after deleteAll, we should have a count of 0
|
||||
assertThat(getCount()).isEqualTo(0L);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
|
||||
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactory;
|
||||
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.error.DocumentDoesNotExistException;
|
||||
import com.couchbase.client.java.view.Stale;
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
|
||||
@TestExecutionListeners(SimpleReactiveCouchbaseRepositoryListener.class)
|
||||
public class SimpleReactiveCouchbaseRepositoryIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Autowired
|
||||
private Bucket client;
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepositoryOperationsMapping operationsMapping;
|
||||
|
||||
@Autowired
|
||||
private IndexManager indexManager;
|
||||
|
||||
private ReactiveUserRepository repository;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
ReactiveRepositoryFactorySupport factory = new ReactiveCouchbaseRepositoryFactory(operationsMapping, indexManager);
|
||||
repository = getRepositoryWithRetry(factory, ReactiveUserRepository.class);
|
||||
}
|
||||
|
||||
private void remove(String key) {
|
||||
try {
|
||||
client.remove(key);
|
||||
} catch (DocumentDoesNotExistException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCrud() {
|
||||
String key = "my_unique_user_key";
|
||||
ReactiveUser instance = new ReactiveUser(key, "foobar", 22);
|
||||
repository.save(instance).block();
|
||||
|
||||
ReactiveUser found = repository.findById(key).block();
|
||||
assertThat(found.getKey()).isEqualTo(instance.getKey());
|
||||
assertThat(found.getUsername()).isEqualTo(instance.getUsername());
|
||||
|
||||
assertThat(repository.existsById(key).block()).isTrue();
|
||||
repository.delete(found).block();
|
||||
|
||||
assertThat(repository.findById(key).block()).isNull();
|
||||
assertThat(repository.existsById(key).block()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* This test uses/assumes a default viewName called "all" that is configured on Couchbase.
|
||||
*/
|
||||
public void shouldFindAll() {
|
||||
// do a non-stale query to populate data for testing.
|
||||
client.query(ViewQuery.from("reactiveUser", "all").stale(Stale.FALSE));
|
||||
|
||||
List<ReactiveUser> allUsers = repository.findAll().collectList().block();
|
||||
int size = 0;
|
||||
for (ReactiveUser u : allUsers) {
|
||||
size++;
|
||||
assertThat(u.getKey()).isNotNull();
|
||||
assertThat(u.getUsername()).isNotNull();
|
||||
}
|
||||
assertThat(size).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCount() {
|
||||
// do a non-stale query to populate data for testing.
|
||||
client.query(ViewQuery.from("reactiveUser", "all").stale(Stale.FALSE));
|
||||
|
||||
assertThat(repository.count().block().toString()).isEqualTo("100");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindByUsernameUsingN1ql() {
|
||||
ReactiveUser user = repository.findByUsername("reactiveuname-1").single().block();
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getKey()).isEqualTo("reactivetestuser-1");
|
||||
assertThat(user.getUsername()).isEqualTo("reactiveuname-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailFindByUsernameWithNoIdOrCas() {
|
||||
try {
|
||||
ReactiveUser user = repository.findByUsernameBadSelect("reactiveuname-1").single().block();
|
||||
fail("shouldFailFindByUsernameWithNoIdOrCas");
|
||||
} catch (CouchbaseQueryExecutionException e) {
|
||||
assertThat(e.getMessage().contains("_ID"))
|
||||
.as("_ID expected in exception " + e).isTrue();
|
||||
assertThat(e.getMessage().contains("_CAS"))
|
||||
.as("_CAS expected in exception " + e).isTrue();
|
||||
} catch (Exception e) {
|
||||
fail("CouchbaseQueryExecutionException expected");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindFromUsernameInlineWithSpelParsing() {
|
||||
ReactiveUser user = repository.findByUsernameWithSpelAndPlaceholder().take(1).blockLast();
|
||||
assertThat(user).isNotNull();
|
||||
assert(user.getUsername().startsWith("reactive"));
|
||||
assert(user.getUsername().startsWith("reactive"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindFromDeriveQueryWithRegexpAndIn() {
|
||||
ReactiveUser user = repository.findByUsernameRegexAndUsernameIn("reactiveuname-[123]", Arrays.asList("reactiveuname-2", "reactiveuname-4")).take(1).blockLast();
|
||||
assertThat(user).isNotNull();
|
||||
assertThat(user.getKey()).isEqualTo("reactivetestuser-2");
|
||||
assertThat(user.getUsername()).isEqualTo("reactiveuname-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindContainsWithoutAnnotation() {
|
||||
List<ReactiveUser> users = repository.findByUsernameContains("reactive").collectList().block();
|
||||
assertThat(users).isNotNull();
|
||||
assertThat(users.isEmpty()).isFalse();
|
||||
for (ReactiveUser user : users) {
|
||||
assertThat(user.getUsername().startsWith("reactive")).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDefaultToN1qlQueryDerivation() {
|
||||
try {
|
||||
ReactiveUser u = repository.findByUsernameNear("london").single().block();
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (!e.getMessage().contains("N1QL")) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.PersistTo;
|
||||
import com.couchbase.client.java.ReplicateTo;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.View;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
*/
|
||||
public class SimpleReactiveCouchbaseRepositoryListener extends DependencyInjectionTestExecutionListener {
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
Bucket client = (Bucket) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_BUCKET);
|
||||
ClusterInfo clusterInfo = (ClusterInfo) testContext.getApplicationContext().getBean(BeanNames.COUCHBASE_CLUSTER_INFO);
|
||||
populateTestData(client, clusterInfo);
|
||||
createAndWaitForDesignDocs(client);
|
||||
}
|
||||
|
||||
private void populateTestData(Bucket client, ClusterInfo clusterInfo) {
|
||||
RxJavaCouchbaseTemplate template = new RxJavaCouchbaseTemplate(clusterInfo, client);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ReactiveUser u = new ReactiveUser("reactivetestuser-" + i, "reactiveuname-" + i, i);
|
||||
template.save(u, PersistTo.MASTER, ReplicateTo.NONE).subscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository." +
|
||||
"ReactiveUser\") { emit(null, null); } }";
|
||||
View view = DefaultView.create("all", mapFunction, "_count");
|
||||
List<View> views = Collections.singletonList(view);
|
||||
DesignDocument designDoc = DesignDocument.create("reactiveUser", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private final String key;
|
||||
|
||||
private final 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() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
User user = (User) o;
|
||||
return key.equals(user.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.view.ViewQuery;
|
||||
|
||||
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.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
/**
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
@ViewIndexed(designDoc = "user", viewName = "all")
|
||||
@N1qlSecondaryIndexed(indexName = "User")
|
||||
public interface UserRepository extends CouchbaseRepository<User, String> {
|
||||
|
||||
@View(designDocument = "user", viewName = "all")
|
||||
Iterable<User> customViewQuery(ViewQuery query);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE username = $1 and #{#n1ql.filter}")
|
||||
User findByUsername(String username);
|
||||
|
||||
@Query("SELECT * FROM #{#n1ql.bucket} WHERE username = $1 and #{#n1ql.filter} ")
|
||||
User findByUsernameBadSelect(String username);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE username LIKE '%-4' and #{#n1ql.filter}")
|
||||
User findByUsernameWithSpelAndPlaceholder();
|
||||
|
||||
@Query
|
||||
User findByUsernameRegexAndUsernameIn(String regex, List<String> sample);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
|
||||
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
|
||||
|
||||
@Configuration
|
||||
@EnableCouchbaseRepositories
|
||||
@EnableCouchbaseAuditing(modifyOnCreate = false)
|
||||
public class AuditedApplicationConfig extends IntegrationTestApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public AuditedAuditorAware couchbaseAuditorAware() {
|
||||
return new AuditedAuditorAware();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class AuditedAuditorAware implements AuditorAware<String> {
|
||||
|
||||
private Optional<String> auditor = Optional.of("auditor");
|
||||
|
||||
@Override
|
||||
public Optional<String> getCurrentAuditor() {
|
||||
return auditor;
|
||||
}
|
||||
|
||||
public void setAuditor(String auditor) {
|
||||
this.auditor = Optional.of(auditor);
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
public class AuditedItem {
|
||||
|
||||
@Id
|
||||
private final String id;
|
||||
|
||||
private String value;
|
||||
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@LastModifiedBy
|
||||
private String lastModifiedBy;
|
||||
|
||||
@LastModifiedDate
|
||||
private Date lastModification;
|
||||
|
||||
@CreatedDate
|
||||
private Date creationDate;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
public AuditedItem(String id, String value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public void setLastModifiedBy(String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
public Date getLastModification() {
|
||||
return lastModification;
|
||||
}
|
||||
|
||||
public void setLastModification(Date lastModification) {
|
||||
this.lastModification = lastModification;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuditedItem{" +
|
||||
"id='" + id + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
", creator='" + creator + '\'' +
|
||||
", lastModifiedBy='" + lastModifiedBy + '\'' +
|
||||
", lastModification=" + lastModification +
|
||||
", creationDate=" + creationDate +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AuditedItem that = (AuditedItem) o;
|
||||
|
||||
if (!id.equals(that.id)) return false;
|
||||
if (!value.equals(that.value)) return false;
|
||||
if (creator != null ? !creator.equals(that.creator) : that.creator != null) return false;
|
||||
if (lastModifiedBy != null ? !lastModifiedBy.equals(that.lastModifiedBy) : that.lastModifiedBy != null)
|
||||
return false;
|
||||
if (lastModification != null ? !lastModification.equals(that.lastModification) : that.lastModification != null)
|
||||
return false;
|
||||
return creationDate != null ? creationDate.equals(that.creationDate) : that.creationDate == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id.hashCode();
|
||||
result = 31 * result + value.hashCode();
|
||||
result = 31 * result + (creator != null ? creator.hashCode() : 0);
|
||||
result = 31 * result + (lastModifiedBy != null ? lastModifiedBy.hashCode() : 0);
|
||||
result = 31 * result + (lastModification != null ? lastModification.hashCode() : 0);
|
||||
result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
|
||||
public interface AuditedRepository extends CouchbaseRepository<AuditedItem, String> {
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package org.springframework.data.couchbase.repository.auditing;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.data.couchbase.TestContainerResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Simon Baslé
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = AuditedApplicationConfig.class)
|
||||
public class AuditingIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private AuditedRepository repository;
|
||||
|
||||
@Autowired
|
||||
private AuditedAuditorAware auditorAware;
|
||||
|
||||
private static final String KEY = "auditedTest";
|
||||
|
||||
@After
|
||||
public void cleanupAuditedEntity() {
|
||||
repository.getCouchbaseOperations().getCouchbaseBucket().remove(KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreationEventIsRegistered() {
|
||||
assertThat(repository.existsById(KEY)).isFalse();
|
||||
Date start = new Date();
|
||||
AuditedItem item = new AuditedItem(KEY, "creation");
|
||||
|
||||
auditorAware.setAuditor("auditor");
|
||||
repository.save(item);
|
||||
Optional<AuditedItem> persisted = repository.findById(KEY);
|
||||
|
||||
assertThat(persisted.isPresent()).isTrue();
|
||||
|
||||
persisted.ifPresent(actual -> {
|
||||
|
||||
assertThat(actual.getCreationDate()).as("expected creation date audit trail")
|
||||
.isNotNull();
|
||||
assertThat(actual.getCreator()).as("expected creation user audit trail")
|
||||
.isEqualTo("auditor");
|
||||
|
||||
assertThat(actual.getCreationDate().after(start)).as("creation date is too early")
|
||||
.isTrue();
|
||||
assertThat(actual.getCreationDate().before(new Date()))
|
||||
.as("creation date is too late").isTrue();
|
||||
|
||||
assertThat(actual.getLastModification())
|
||||
.as("expected modification date to be empty").isNull();
|
||||
assertThat(actual.getLastModifiedBy()).as("expected modification user to be empty")
|
||||
.isNull();
|
||||
|
||||
assertThat(actual.getVersion()).as("expected version to be non null").isNotNull();
|
||||
assertThat(actual.getVersion() > 0L).as("expected version to be greater than 0")
|
||||
.isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateEventIsRegistered() {
|
||||
assertThat(repository.existsById(KEY)).isFalse();
|
||||
|
||||
String expectedCreator = "user1";
|
||||
String expectedUpdater = "user2";
|
||||
AuditedItem item = new AuditedItem(KEY, "creation");
|
||||
auditorAware.setAuditor(expectedCreator);
|
||||
|
||||
repository.save(item);
|
||||
AuditedItem created = repository.findById(KEY).orElse(null);
|
||||
|
||||
auditorAware.setAuditor(expectedUpdater);
|
||||
repository.save(item);
|
||||
AuditedItem updated = repository.findById(KEY).orElse(null);
|
||||
|
||||
assertThat(updated).as("expected entity to be persisted").isNotNull();
|
||||
assertThat(updated.getCreationDate()).as("expected creation date audit trail")
|
||||
.isNotNull();
|
||||
assertThat(updated.getCreator()).as("expected creation user audit trail")
|
||||
.isEqualTo(expectedCreator);
|
||||
|
||||
assertThat(updated.getLastModification()).as("expected modification date audit trail")
|
||||
.isNotNull();
|
||||
assertThat(updated.getCreationDate().before(updated.getLastModification()))
|
||||
.as("expected modification date to be after creation date").isTrue();
|
||||
assertThat(updated.getLastModifiedBy())
|
||||
.as("expected modification user to be the modifier")
|
||||
.isEqualTo(expectedUpdater);
|
||||
|
||||
assertThat(updated.getVersion()).as("expected version to be non null").isNotNull();
|
||||
assertThat(updated.getVersion() > 0L).as("expected version to be greater than 0")
|
||||
.isTrue();
|
||||
assertThat(created.getVersion() != updated.getVersion())
|
||||
.as("expected updated version to be different from the one at creation")
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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.cdi;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CdiPersonFragmentImpl implements CdiPersonFragment {
|
||||
|
||||
@Override
|
||||
public int returnTwo() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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.cdi;
|
||||
|
||||
import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface CdiPersonRepository extends CouchbaseRepository<Person, String>, CdiPersonFragment {
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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.cdi;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class CdiRepositoryClient {
|
||||
|
||||
@Inject
|
||||
private CdiPersonRepository cdiPersonRepository;
|
||||
|
||||
@Inject
|
||||
@OtherQualifier
|
||||
@PersonDB
|
||||
private QualifiedPersonRepository qualifiedPersonRepository;
|
||||
|
||||
@Inject
|
||||
private Bucket couchbaseClient;
|
||||
|
||||
public CdiPersonRepository getCdiPersonRepository() {
|
||||
return cdiPersonRepository;
|
||||
}
|
||||
|
||||
public QualifiedPersonRepository getQualifiedPersonRepository() {
|
||||
return qualifiedPersonRepository;
|
||||
}
|
||||
|
||||
public Bucket getCouchbaseClient() {
|
||||
return couchbaseClient;
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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.cdi;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.view.DefaultView;
|
||||
import com.couchbase.client.java.view.DesignDocument;
|
||||
import com.couchbase.client.java.view.View;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.data.couchbase.ContainerResourceRunner;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.enterprise.inject.se.SeContainer;
|
||||
import javax.enterprise.inject.se.SeContainerInitializer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SuppressWarnings("SpringJavaAutowiringInspection")
|
||||
@RunWith(ContainerResourceRunner.class)
|
||||
@ContextConfiguration(classes = CdiRepositoryIntegrationTests.class)
|
||||
public class CdiRepositoryIntegrationTests {
|
||||
|
||||
private static SeContainer cdiContainer;
|
||||
private CdiPersonRepository repository;
|
||||
private QualifiedPersonRepository qualifiedPersonRepository;
|
||||
private Bucket couchbaseClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
cdiContainer = SeContainerInitializer.newInstance() //
|
||||
.disableDiscovery() //
|
||||
.addPackages(CdiRepositoryClient.class) //
|
||||
.initialize();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
cdiContainer.close();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
CdiRepositoryClient repositoryClient = cdiContainer.select(CdiRepositoryClient.class).get();
|
||||
repository = repositoryClient.getCdiPersonRepository();
|
||||
qualifiedPersonRepository = repositoryClient.getQualifiedPersonRepository();
|
||||
|
||||
couchbaseClient = repositoryClient.getCouchbaseClient();
|
||||
createAndWaitForDesignDocs(couchbaseClient);
|
||||
|
||||
}
|
||||
|
||||
private void createAndWaitForDesignDocs(Bucket client) {
|
||||
String mapFunction = "function (doc, meta) { if(doc._class == \"" + Person.class.getName()
|
||||
+ "\") { emit(null, null); } }";
|
||||
View view = DefaultView.create("all", mapFunction, "_count");
|
||||
List<View> views = Collections.singletonList(view);
|
||||
DesignDocument designDoc = DesignDocument.create("person", views);
|
||||
client.bucketManager().upsertDesignDocument(designDoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-109
|
||||
*/
|
||||
@Test
|
||||
public void testCdiRepository() {
|
||||
assertThat(repository).isNotNull();
|
||||
repository.deleteAll();
|
||||
|
||||
Person bean = new Person("key", "username");
|
||||
|
||||
repository.save(bean);
|
||||
|
||||
assertThat(repository.existsById(bean.getId())).isTrue();
|
||||
|
||||
Optional<Person> retrieved = repository.findById(bean.getId());
|
||||
assertThat(retrieved.isPresent()).isTrue();
|
||||
retrieved.ifPresent(actual -> {
|
||||
assertThat(actual.getName()).isEqualTo(bean.getName());
|
||||
assertThat(actual.getId()).isEqualTo(bean.getId());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-203
|
||||
*/
|
||||
@Test
|
||||
public void testQualifiedCdiRepository() {
|
||||
assertThat(qualifiedPersonRepository).isNotNull();
|
||||
qualifiedPersonRepository.deleteAll();
|
||||
|
||||
Person bean = new Person("key", "username");
|
||||
|
||||
qualifiedPersonRepository.save(bean);
|
||||
|
||||
assertThat(qualifiedPersonRepository.existsById(bean.getId())).isTrue();
|
||||
|
||||
Optional<Person> retrieved = qualifiedPersonRepository.findById(bean.getId());
|
||||
assertThat(retrieved.isPresent()).isTrue();
|
||||
retrieved.ifPresent(actual -> {
|
||||
assertThat(actual.getName()).isEqualTo(bean.getName());
|
||||
assertThat(actual.getId()).isEqualTo(bean.getId());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACOUCH-109
|
||||
*/
|
||||
@Test
|
||||
public void testCustomRepository() {
|
||||
|
||||
assertThat(repository.returnTwo()).isEqualTo(2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 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.cdi;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.inject.Disposes;
|
||||
import javax.enterprise.inject.Produces;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.CouchbaseCluster;
|
||||
|
||||
import org.springframework.data.couchbase.config.CouchbaseBucketFactoryBean;
|
||||
|
||||
/**
|
||||
* Producer for {@link Bucket}. A default {@link CouchbaseCluster} with defaults
|
||||
* from {@link CouchbaseBucketFactoryBean} are sufficient for our test.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
class CouchbaseClientProducer {
|
||||
|
||||
@Produces
|
||||
@ApplicationScoped
|
||||
public Cluster cluster() {
|
||||
return CouchbaseCluster.create();
|
||||
}
|
||||
|
||||
@Produces
|
||||
public Bucket createCouchbaseClient(Cluster cluster) throws Exception {
|
||||
CouchbaseBucketFactoryBean couchbaseFactoryBean = new CouchbaseBucketFactoryBean(cluster, "protected", "protected", "password");
|
||||
couchbaseFactoryBean.afterPropertiesSet();
|
||||
return couchbaseFactoryBean.getObject();
|
||||
}
|
||||
|
||||
public void close(@Disposes Bucket couchbaseClient) {
|
||||
couchbaseClient.close();
|
||||
}
|
||||
|
||||
public void close(@Disposes Cluster cluster) {
|
||||
cluster.disconnect();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user