diff --git a/couchbase/example/README.md b/couchbase/example/README.md
new file mode 100644
index 00000000..3b7a2f7c
--- /dev/null
+++ b/couchbase/example/README.md
@@ -0,0 +1,7 @@
+# Spring Data Couchbase - Examples
+
+This project contains samples of data access features with Spring Data (Couchbase).
+
+## Prerequisites
+
+The examples require a running [Couchbase Server](https://www.couchbase.com/downloads) server with the travel sample bucket imported. We assume you're running Couchbase 5 and we have `spring.couchbase.bucket.password=…` accordingly to adapt RBAC authentication.
diff --git a/couchbase/example/pom.xml b/couchbase/example/pom.xml
index f384dc3e..ba38ed41 100644
--- a/couchbase/example/pom.xml
+++ b/couchbase/example/pom.xml
@@ -2,27 +2,26 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- spring-data-couchbase-example
- Basic sample for Spring Data Couchbase
-
spring-data-couchbase-examples
org.springframework.data.examples
- 1.0.0.BUILD-SNAPSHOT
+ 2.0.0.BUILD-SNAPSHOT
+ ../pom.xml
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- **/*IntegrationTest*
-
-
-
-
-
+ spring-data-couchbase-example
+ Basic sample for Spring Data Couchbase
+ Small sample project showing the usage of Spring Data Couchbase.
+
+
+
+
+ ${project.groupId}
+ spring-data-couchbase-example-utils
+ ${project.version}
+ test
+
+
+
diff --git a/couchbase/example/src/main/java/example/springdata/couchbase/CouchbaseConfiguration.java b/couchbase/example/src/main/java/example/springdata/couchbase/CouchbaseConfiguration.java
deleted file mode 100644
index f8433a39..00000000
--- a/couchbase/example/src/main/java/example/springdata/couchbase/CouchbaseConfiguration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package example.springdata.couchbase;
-
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
-import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Couchbase Configuration to connect to Couchbase data store
- *
- * @author Chandana Kithalagama
- */
-@SpringBootApplication
-@Configuration
-@EnableCouchbaseRepositories
-public class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
-
- @Override
- protected List getBootstrapHosts() {
- return Collections.singletonList("192.168.99.100");
- }
-
- @Override
- protected String getBucketName() {
- return "travel-sample";
- }
-
- @Override
- protected String getBucketPassword() {
- return "";
- }
-}
diff --git a/couchbase/example/src/main/java/example/springdata/couchbase/model/Airline.java b/couchbase/example/src/main/java/example/springdata/couchbase/model/Airline.java
index 4a13d9e7..2408f0ea 100644
--- a/couchbase/example/src/main/java/example/springdata/couchbase/model/Airline.java
+++ b/couchbase/example/src/main/java/example/springdata/couchbase/model/Airline.java
@@ -1,9 +1,26 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package example.springdata.couchbase.model;
+import lombok.Data;
+
+import org.springframework.data.couchbase.core.mapping.Document;
+
import com.couchbase.client.java.repository.annotation.Field;
import com.couchbase.client.java.repository.annotation.Id;
-import lombok.*;
-import org.springframework.data.couchbase.core.mapping.Document;
/**
* A domain object representing an Airline
@@ -11,13 +28,11 @@ import org.springframework.data.couchbase.core.mapping.Document;
* @author Chandana Kithalagama
*/
@Data
-@AllArgsConstructor
-@NoArgsConstructor
@Document
public class Airline {
@Id
- private int id;
+ private String id;
@Field
private String type;
@@ -36,5 +51,4 @@ public class Airline {
@Field
private String country;
-
}
diff --git a/couchbase/example/src/main/java/example/springdata/couchbase/repository/AirlineRepository.java b/couchbase/example/src/main/java/example/springdata/couchbase/repository/AirlineRepository.java
index 0a5b07e0..b64c179f 100644
--- a/couchbase/example/src/main/java/example/springdata/couchbase/repository/AirlineRepository.java
+++ b/couchbase/example/src/main/java/example/springdata/couchbase/repository/AirlineRepository.java
@@ -1,18 +1,52 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package example.springdata.couchbase.repository;
import example.springdata.couchbase.model.Airline;
-import org.springframework.data.couchbase.core.query.Query;
-import org.springframework.data.repository.CrudRepository;
import java.util.List;
+import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
+import org.springframework.data.couchbase.core.query.View;
+import org.springframework.data.couchbase.core.query.ViewIndexed;
+import org.springframework.data.repository.CrudRepository;
+
/**
* Repository interface to manage {@link Airline} instances.
*
* @author Chandana Kithalagama
+ * @author Mark Paluch
*/
-public interface AirlineRepository extends CrudRepository{
+@N1qlPrimaryIndexed
+@ViewIndexed(designDoc = "airlines")
+public interface AirlineRepository extends CrudRepository {
- @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND name = $1")
- List findAirlineByName(String name);
+ /**
+ * Derived query selecting by {@code iataCode}.
+ *
+ * @param code
+ * @return
+ */
+ Airline findAirlineByIataCode(String code);
+
+ /**
+ * Query method using {@code airlines/all} view.
+ *
+ * @return
+ */
+ @View(designDocument = "airlines", viewName = "all")
+ List findAllBy();
}
diff --git a/couchbase/example/src/main/java/example/springdata/couchbase/repository/CouchbaseConfiguration.java b/couchbase/example/src/main/java/example/springdata/couchbase/repository/CouchbaseConfiguration.java
new file mode 100644
index 00000000..b464332b
--- /dev/null
+++ b/couchbase/example/src/main/java/example/springdata/couchbase/repository/CouchbaseConfiguration.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.couchbase.repository;
+
+import example.springdata.couchbase.model.Airline;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.couchbase.config.BeanNames;
+import org.springframework.data.couchbase.core.CouchbaseOperations;
+import org.springframework.data.couchbase.repository.support.IndexManager;
+
+import com.couchbase.client.java.query.N1qlQuery;
+
+/**
+ * Simple configuration class.
+ *
+ * @author Chandana Kithalagama
+ * @author Mark Paluch
+ */
+@SpringBootApplication
+@RequiredArgsConstructor
+public class CouchbaseConfiguration {
+
+ private final CouchbaseOperations couchbaseOperations;
+
+ /**
+ * Create an {@link IndexManager} that allows index creation.
+ *
+ * @return
+ */
+ @Bean(name = BeanNames.COUCHBASE_INDEX_MANAGER)
+ public IndexManager indexManager() {
+ return new IndexManager(true, true, false);
+ }
+
+ @PostConstruct
+ private void postConstruct() {
+
+ // Need to post-process travel data to add _class attribute
+ List airlinesWithoutClassAttribute = couchbaseOperations.findByN1QL(N1qlQuery.simple( //
+ "SELECT META(`travel-sample`).id AS _ID, META(`travel-sample`).cas AS _CAS, `travel-sample`.* " + //
+ "FROM `travel-sample` " + //
+ "WHERE type = \"airline\" AND _class IS MISSING;"),
+ Airline.class);
+
+ airlinesWithoutClassAttribute.forEach(couchbaseOperations::save);
+ }
+}
diff --git a/couchbase/example/src/main/resources/application.properties b/couchbase/example/src/main/resources/application.properties
new file mode 100644
index 00000000..2d12d619
--- /dev/null
+++ b/couchbase/example/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.couchbase.bucket.name=travel-sample
+spring.couchbase.bootstrap-hosts=localhost
+
+# Required for Couchbase 5
+spring.couchbase.bucket.password=password
+
+# Increased timeout to fit slower environments like TravisCI
+spring.couchbase.env.timeouts.view=15000
+spring.couchbase.env.timeouts.query=15000
diff --git a/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTest.java b/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTest.java
deleted file mode 100644
index 31ae448e..00000000
--- a/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package example.springdata.couchbase.repository;
-
-import example.springdata.couchbase.CouchbaseConfiguration;
-import example.springdata.couchbase.model.Airline;
-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.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Unit tests for basic CRUD operations
- *
- * @author Chandana Kithalagama
- */
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = CouchbaseConfiguration.class)
-public class AirlineRepositoryIntegrationTest {
-
- @Autowired
- AirlineRepository airlineRepository;
- Airline a, b, c;
- List airlineList;
-
- @Before
- public void setup() {
- a = new Airline(20000,"airline", "CK 1", "LK", "CMB", "CLK","Sri Lanka");
- b = new Airline(20001,"airline", "CK 2", "LK", "CMB", "CLK","Sri Lanka");
- c = new Airline(20002,"airline", "CK 3", "LK", "CMB", "CLK","Sri Lanka");
-
- airlineList = Arrays.asList(a, b, b);
- }
-
- @Test
- public void testSaveAirline() {
- Iterable itr = airlineRepository.save(Arrays.asList(a));
- assertThat(itr).isNotNull();
- Airline airline = airlineRepository.findOne(a.getId());
- assertThat(airline).isNotNull();
- assertThat(airline).isEqualTo(a);
- assertThat(airline).isNotEqualTo(b);
- airlineRepository.delete(a.getId());
- }
-
- @Test
- public void testGetAllAirlines() {
- Iterable itr = airlineRepository.save(airlineList);
- assertThat(itr).isNotNull();
- Iterable itr2 = airlineRepository.findAll(Arrays.asList(a.getId(), b.getId(), c.getId()));
- assertThat(itr2).isNotNull();
- airlineRepository.delete(airlineList);
- }
-
- @Test
- public void testDeleteAirlines() {
- Iterable itr = airlineRepository.save(Arrays.asList(a));
- assertThat(itr).isNotNull();
- airlineRepository.delete(a.getId());
- Airline airline = airlineRepository.findOne(a.getId());
- assertThat(airline).isNull();
- }
-
- @Test
- public void testGetByName() {
- Iterable itr = airlineRepository.save(Arrays.asList(a));
- assertThat(itr).isNotNull();
- List airlines = airlineRepository.findAirlineByName(a.getName());
- assertThat(airlines.size()).isGreaterThanOrEqualTo(1);
- assertThat(airlines.get(0)).isEqualTo(a);
- airlineRepository.delete(a.getId());
- }
-
- @After
- public void tearDown() {
- airlineRepository.delete(airlineList);
- }
-}
diff --git a/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTests.java b/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTests.java
new file mode 100644
index 00000000..9e01a102
--- /dev/null
+++ b/couchbase/example/src/test/java/example/springdata/couchbase/repository/AirlineRepositoryIntegrationTests.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.couchbase.repository;
+
+import static org.assertj.core.api.Assertions.*;
+
+import example.springdata.couchbase.model.Airline;
+import example.springdata.couchbase.util.CouchbaseAvailableRule;
+
+import java.util.List;
+
+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.boot.test.context.SpringBootTest;
+import org.springframework.data.couchbase.core.CouchbaseOperations;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Integration tests showing basic CRUD operations through {@link AirlineRepository}.
+ *
+ * @author Chandana Kithalagama
+ * @author Mark Paluch
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class AirlineRepositoryIntegrationTests {
+
+ @ClassRule //
+ public static CouchbaseAvailableRule COUCHBASE = CouchbaseAvailableRule.onLocalhost();
+
+ @Autowired
+ AirlineRepository airlineRepository;
+
+ @Autowired CouchbaseOperations couchbaseOperations;
+
+ @Before
+ public void before() {
+ airlineRepository.findById("LH").ifPresent(couchbaseOperations::remove);
+ }
+
+ /**
+ * The derived query executes a N1QL query emitting a single element.
+ */
+ @Test
+ public void shouldFindAirlineN1ql() {
+
+ Airline airline = airlineRepository.findAirlineByIataCode("TQ");
+
+ assertThat(airline.getCallsign()).isEqualTo("TXW");
+ }
+
+ /**
+ * The derived query executes a N1QL query and the emitted element is used to invoke
+ * {@link org.springframework.data.repository.reactive.ReactiveCrudRepository#findById(Object)} for an Id-based
+ * lookup. Queries without a result do not emit a value.
+ */
+ @Test
+ public void shouldFindById() {
+
+ Airline airline = airlineRepository.findAirlineByIataCode("TQ");
+
+ assertThat(airlineRepository.findById(airline.getId())).contains(airline);
+ assertThat(airlineRepository.findById("unknown")).isEmpty();
+ }
+
+ /**
+ * Find all {@link Airline}s applying the {@code airlines/all} view.
+ */
+ @Test
+ public void shouldFindByView() {
+
+ List airlines = airlineRepository.findAllBy();
+
+ assertThat(airlines).hasSize(187);
+ }
+
+ /**
+ * Created elements are emitted by the
+ * {@link org.springframework.data.repository.reactive.ReactiveCrudRepository#save(Object)} method.
+ */
+ @Test
+ public void shouldCreateAirline() {
+
+ Airline airline = new Airline();
+
+ airline.setId("LH");
+ airline.setIataCode("LH");
+ airline.setIcao("DLH");
+ airline.setCallsign("Lufthansa");
+ airline.setName("Lufthansa");
+ airline.setCountry("Germany");
+
+ airlineRepository.save(airline);
+
+ assertThat(airlineRepository.findById("LH")).contains(airline);
+ }
+}
diff --git a/couchbase/pom.xml b/couchbase/pom.xml
index 9627c0f4..8e218002 100644
--- a/couchbase/pom.xml
+++ b/couchbase/pom.xml
@@ -5,11 +5,11 @@
spring-data-couchbase-examples
pom
-
- spring-data-examples
- org.springframework.data.examples
- 1.0.0.BUILD-SNAPSHOT
-
+
+ org.springframework.data.examples
+ spring-data-examples
+ 2.0.0.BUILD-SNAPSHOT
+
Spring Data Couchbase - Examples
Sample projects for Spring Data Couchbase
@@ -17,14 +17,13 @@
example
+ util
-
org.springframework.boot
spring-boot-starter-data-couchbase
-
diff --git a/couchbase/util/pom.xml b/couchbase/util/pom.xml
new file mode 100644
index 00000000..d93d75e9
--- /dev/null
+++ b/couchbase/util/pom.xml
@@ -0,0 +1,24 @@
+
+ 4.0.0
+
+
+ org.springframework.data.examples
+ spring-data-couchbase-examples
+ 2.0.0.BUILD-SNAPSHOT
+ ../pom.xml
+
+
+ spring-data-couchbase-example-utils
+ Spring Data Couchbase - Example Utilities
+
+
+
+
+ junit
+ junit
+
+
+
+
+
diff --git a/couchbase/util/src/main/java/example/springdata/couchbase/util/CouchbaseAvailableRule.java b/couchbase/util/src/main/java/example/springdata/couchbase/util/CouchbaseAvailableRule.java
new file mode 100644
index 00000000..25279ea3
--- /dev/null
+++ b/couchbase/util/src/main/java/example/springdata/couchbase/util/CouchbaseAvailableRule.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.couchbase.util;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.time.Duration;
+
+import javax.net.SocketFactory;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.ExternalResource;
+
+import com.couchbase.client.core.env.DefaultCoreEnvironment;
+
+/**
+ * Rule to check Couchbase server availability. If Couchbase is not running, tests are skipped.
+ *
+ * @author Mark Paluch
+ */
+public class CouchbaseAvailableRule extends ExternalResource {
+
+ private final String host;
+ private final int port;
+ private final Duration timeout = Duration.ofSeconds(1);
+
+ private CouchbaseAvailableRule(String host, int port) {
+ this.host = host;
+ this.port = port;
+ }
+
+ /**
+ * Create a new rule requiring Couchbase running on {@code localhost} on
+ * {@link DefaultCoreEnvironment#BOOTSTRAP_HTTP_DIRECT_PORT}.
+ *
+ * @return the test rule.
+ */
+ public static CouchbaseAvailableRule onLocalhost() {
+ return new CouchbaseAvailableRule("localhost", DefaultCoreEnvironment.BOOTSTRAP_HTTP_DIRECT_PORT);
+ }
+
+ @Override
+ protected void before() throws Throwable {
+
+ Socket socket = SocketFactory.getDefault().createSocket();
+ try {
+ socket.connect(new InetSocketAddress(host, port), Math.toIntExact(timeout.toMillis()));
+ } catch (IOException e) {
+ throw new AssumptionViolatedException(
+ String.format("Couchbase not available on on %s:%d. Skipping tests.", host, port), e);
+ } finally {
+ socket.close();
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 24fc50f1..7cd25719 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,7 @@
bom
cassandra
+ couchbase
elasticsearch
jpa
ldap
@@ -29,7 +30,6 @@
redis
solr
web
- couchbase