#562 - Upgrading to Spring Data Couchbase 4.

Original pull request: #564.
This commit is contained in:
deniswsrosa
2020-05-14 09:26:52 +02:00
committed by Mark Paluch
parent 6e1abe4869
commit fd52cea0e4
21 changed files with 300 additions and 467 deletions

View File

@@ -4,4 +4,7 @@ This project contains samples of data access features with Spring Data (Couchbas
## 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.
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 6.5 and we have updated the `CouchbaseConfig` class accordingly to adapt RBAC authentication.
For more information, see the [official documentation](https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#reference).

View File

@@ -15,12 +15,14 @@
*/
package example.springdata.couchbase.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.Field;
import com.couchbase.client.java.repository.annotation.Field;
import com.couchbase.client.java.repository.annotation.Id;
/**
* A domain object representing an Airline
@@ -29,19 +31,17 @@ import com.couchbase.client.java.repository.annotation.Id;
*/
@Data
@Document
@JsonIgnoreProperties(ignoreUnknown = true)
public class Airline {
@Id
private String id;
@Field
private String type;
@Field
private String name;
@Field("iata")
private String iataCode;
@Field
private String iata;
@Field
private String icao;

View File

@@ -18,20 +18,17 @@ package example.springdata.couchbase.repository;
import example.springdata.couchbase.model.Airline;
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;
import org.springframework.stereotype.Repository;
/**
* Repository interface to manage {@link Airline} instances.
*
* @author Chandana Kithalagama
* @author Mark Paluch
* @author Denis Rosa
*/
@N1qlPrimaryIndexed
@ViewIndexed(designDoc = "airlines")
@Repository
public interface AirlineRepository extends CrudRepository<Airline, String> {
/**
@@ -40,13 +37,12 @@ public interface AirlineRepository extends CrudRepository<Airline, String> {
* @param code
* @return
*/
Airline findAirlineByIataCode(String code);
List<Airline> findByIata(String code);
/**
* Query method using {@code airlines/all} view.
*
* @return
*/
@View(designDocument = "airlines", viewName = "all")
List<Airline> findAllBy();
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 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
*
* 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 org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
/**
* @author Denis Rosa
* Configuration class to connnect with couchbase
*/
@Configuration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {
@Override
public String getConnectionString() {
return "couchbase://127.0.0.1";
}
@Override
public String getUserName() {
return "Administrator";
}
@Override
public String getPassword() {
return "password";
}
@Override
public String getBucketName() {
return "travel-sample";
}
@Override
protected boolean autoIndexCreation() {
return true;
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2017-2018 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 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<Airline> 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);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 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
*
* 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 com.couchbase.client.java.Cluster;
import com.couchbase.client.java.manager.query.CreatePrimaryQueryIndexOptions;
import example.springdata.couchbase.model.Airline;
import lombok.RequiredArgsConstructor;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
/**
* Main Class of this module
*
* @author Denis Rosa
*/
@SpringBootApplication
@RequiredArgsConstructor
public class CouchbaseMain {
@Autowired
private final CouchbaseTemplate couchbaseTemplate;
@Autowired
private Cluster cluster;
/**
* Add the _class field to all Airline documents
*/
@PostConstruct
private void postConstruct() {
cluster.queryIndexes().createPrimaryIndex(couchbaseTemplate.getBucketName(),
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
// Need to post-process travel data to add _class attribute
cluster.query("update `travel-sample` set _class='"+Airline.class.getName()+"' where type = 'airline'");
}
}

View File

@@ -1,8 +1,3 @@
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

View File

@@ -34,8 +34,7 @@ import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests showing basic CRUD operations through {@link AirlineRepository}.
*
* @author Chandana Kithalagama
* @author Mark Paluch
* @author Denis Rosa
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@@ -49,20 +48,24 @@ public class AirlineRepositoryIntegrationTests {
@Autowired CouchbaseOperations couchbaseOperations;
@Before
public void before() {
airlineRepository.findById("LH").ifPresent(couchbaseOperations::remove);
if( couchbaseOperations.existsById().one("LH")) {
couchbaseOperations.removeById().one("LH");
}
}
/**
* 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");
List<Airline> airlines = airlineRepository.findByIata("TQ");
assertThat(airlines.get(0).getCallsign()).isEqualTo("TXW");
}
/**
@@ -73,10 +76,8 @@ public class AirlineRepositoryIntegrationTests {
@Test
public void shouldFindById() {
Airline airline = airlineRepository.findAirlineByIataCode("TQ");
assertThat(airlineRepository.findById(airline.getId())).contains(airline);
assertThat(airlineRepository.findById("unknown")).isEmpty();
Airline airline = airlineRepository.findByIata("TQ").get(0);
assertThat(airlineRepository.findById(airline.getId()).isPresent());
}
/**
@@ -87,7 +88,7 @@ public class AirlineRepositoryIntegrationTests {
List<Airline> airlines = airlineRepository.findAllBy();
assertThat(airlines).hasSize(187);
assertThat(airlines).hasSize(374);
}
/**
@@ -100,7 +101,7 @@ public class AirlineRepositoryIntegrationTests {
Airline airline = new Airline();
airline.setId("LH");
airline.setIataCode("LH");
airline.setIata("LH");
airline.setIcao("DLH");
airline.setCallsign("Lufthansa");
airline.setName("Lufthansa");

View File

@@ -21,10 +21,11 @@
<module>util</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,51 +1,21 @@
# Spring Data Couchbase 3.0 - Reactive examples
# Spring Data Couchbase 4.0 - Reactive examples
This project contains samples of reactive data access features with Spring Data (Couchbase).
## Reactive Template API usage with `RxJavaCouchbaseOperations`
The main reactive Template API class is `RxJavaCouchbaseTemplate`, ideally used through its interface `RxJavaCouchbaseOperations`. It defines a basic set of reactive data access operations using [RxJava 1](https://github.com/ReactiveX/RxJava/tree/1.x) `Single` and `Observable` reactive types.
```java
Airline airline = new Airline();
Observable<Airline> single = operations.save(airline)
Observable<Airline> airlines = operations.findByView(ViewQuery.from("airlines", "all"), Airline.class);
```
The test cases in `RxJavaCouchbaseOperationsIntegrationTests` show basic Template API usage.
Reactive data access reads and converts individual elements while processing the stream.
## Reactive Repository support
Spring Data Couchbase provides reactive repository support with Project Reactor, RxJava 1 and RxJava 2 reactive types. The reactive API supports reactive type conversion between reactive types.
Spring Data Couchbase provides reactive repository support with Project Reactor:
```java
@N1qlPrimaryIndexed
@ViewIndexed(designDoc = "airlines")
@Repository
public interface ReactiveAirlineRepository extends ReactiveCrudRepository<Airline, String> {
Mono<Airline> findAirlineByIataCode(String code);
Mono<Airline> findByIata(String code);
@View(designDocument = "airlines", viewName = "all")
Flux<Airline> findAllBy();
}
```
```java
@N1qlPrimaryIndexed
@ViewIndexed(designDoc = "airlines")
public interface RxJava1AirlineRepository extends Repository<Airline, String> {
For more information, see the [official documentation](https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#reference).
Single<Airline> findAirlineByIataCode(String code);
@View(designDocument = "airlines", viewName = "all")
Observable<Airline> findAllBy();
Single<Airline> findById(String id);
Single<Airline> save(Airline airline);
}
```

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2017-2018 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 example.springdata.couchbase;
import example.springdata.couchbase.model.Airline;
import lombok.RequiredArgsConstructor;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.ObjectProvider;
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;
/**
* Configuration class to configure reactive repositories.
*
* @author Mark Paluch
*/
@SpringBootApplication
@RequiredArgsConstructor
public class CouchbaseConfiguration {
private final ObjectProvider<CouchbaseOperations> couchbaseOperationsProvider;
/**
* 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
CouchbaseOperations couchbaseOperations = couchbaseOperationsProvider.getIfUnique();
List<Airline> 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);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 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
*
* 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;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.manager.query.CreatePrimaryQueryIndexOptions;
import example.springdata.couchbase.model.Airline;
import lombok.RequiredArgsConstructor;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
/**
* Main Class of the module
*
* @author Denis Rosa
*/
@SpringBootApplication
@RequiredArgsConstructor
public class CouchbaseMain {
@Autowired
private final CouchbaseTemplate couchbaseTemplate;
@Autowired
private Cluster cluster;
@PostConstruct
private void postConstruct() {
cluster.queryIndexes().createPrimaryIndex(couchbaseTemplate.getBucketName(),
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
// Need to post-process travel data to add _class attribute
cluster.query("update `travel-sample` set _class='"+Airline.class.getName()+"' where type = 'airline'");
}
}

View File

@@ -17,16 +17,17 @@ package example.springdata.couchbase.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.Field;
import com.couchbase.client.java.repository.annotation.Field;
import com.couchbase.client.java.repository.annotation.Id;
/**
* A domain object representing an Airline
*
* @author Chandana Kithalagama
* @author Mark Paluch
* @author Denis Rosa
*/
@Data
@Document
@@ -38,7 +39,7 @@ public class Airline {
@Field private String name;
@Field("iata") private String iataCode;
@Field private String iata;
@Field private String icao;

View File

@@ -0,0 +1,55 @@
/*
* Copyright 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
*
* 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 org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
/**
* @author Denis Rosa
* Configuration class to connnect with couchbase
*/
@Configuration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {
@Override
public String getConnectionString() {
return "couchbase://127.0.0.1";
}
@Override
public String getUserName() {
return "Administrator";
}
@Override
public String getPassword() {
return "password";
}
@Override
public String getBucketName() {
return "travel-sample";
}
@Override
protected boolean autoIndexCreation() {
return true;
}
}

View File

@@ -19,27 +19,24 @@ import example.springdata.couchbase.model.Airline;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
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.reactive.ReactiveCrudRepository;
/**
* Repository interface to manage {@link Airline} instances.
*
* @author Mark Paluch
* @author Denis Rosa
*/
@N1qlPrimaryIndexed
@ViewIndexed(designDoc = "airlines")
public interface ReactiveAirlineRepository extends ReactiveCrudRepository<Airline, String> {
/**
* Derived query selecting by {@code iataCode}.
* Derived query selecting by {@code iata}.
*
* @param code
* @return
*/
Mono<Airline> findAirlineByIataCode(String code);
Mono<Airline> findByIata(String code);
/**
* Query method using {@code airlines/all} view.

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2017-2018 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 example.springdata.couchbase.repository;
import example.springdata.couchbase.model.Airline;
import rx.Observable;
import rx.Single;
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.Repository;
/**
* Repository interface to manage {@link Airline} instances.
*
* @author Mark Paluch
*/
@N1qlPrimaryIndexed
@ViewIndexed(designDoc = "airlines")
public interface RxJava1AirlineRepository extends Repository<Airline, String> {
/**
* Derived query selecting by {@code iataCode}.
*
* @param code
* @return
*/
Single<Airline> findAirlineByIataCode(String code);
/**
* Query method using {@code airlines/all} view.
*
* @return
*/
@View(designDocument = "airlines", viewName = "all")
Observable<Airline> findAllBy();
/**
* Overloaded {@link org.springframework.data.repository.reactive.ReactiveCrudRepository#findById(Object)} method
* returning a RxJava 1 {@link Single}.
*
* @param id
* @return
*/
Single<Airline> findById(String id);
/**
* Overloaded {@link org.springframework.data.repository.reactive.ReactiveCrudRepository#save(Object)} method
* returning a RxJava 1 {@link Single}.
*
* @param airline
* @return
*/
Single<Airline> save(Airline airline);
}

View File

@@ -1,9 +1,3 @@
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

View File

@@ -49,11 +49,8 @@ public class ReactiveAirlineRepositoryIntegrationTests {
@Before
public void before() {
Airline toDelete = couchbaseOperations.findById("LH", Airline.class);
if (toDelete != null) {
couchbaseOperations.remove(toDelete);
if (couchbaseOperations.existsById().one("LH")) {
couchbaseOperations.removeById().one("LH");
}
}
@@ -63,8 +60,7 @@ public class ReactiveAirlineRepositoryIntegrationTests {
@Test
public void shouldFindAirlineN1ql() {
StepVerifier.create(airlineRepository.findAirlineByIataCode("TQ")).assertNext(it -> {
StepVerifier.create(airlineRepository.findByIata("TQ")).assertNext(it -> {
assertThat(it.getCallsign()).isEqualTo("TXW");
}).verifyComplete();
}
@@ -77,7 +73,7 @@ public class ReactiveAirlineRepositoryIntegrationTests {
@Test
public void shouldFindById() {
Mono<Airline> airline = airlineRepository.findAirlineByIataCode("TQ") //
Mono<Airline> airline = airlineRepository.findByIata("TQ") //
.map(Airline::getId) //
.flatMap(airlineRepository::findById);
@@ -86,15 +82,14 @@ public class ReactiveAirlineRepositoryIntegrationTests {
assertThat(it.getCallsign()).isEqualTo("TXW");
}).verifyComplete();
StepVerifier.create(airlineRepository.findById("unknown")).verifyComplete();
}
/**
* Find all {@link Airline}s applying the {@code airlines/all} view.
*/
@Test
public void shouldFindByView() {
StepVerifier.create(airlineRepository.findAllBy()).expectNextCount(187).verifyComplete();
public void shouldFindAll() {
StepVerifier.create(airlineRepository.findAllBy()).expectNextCount(374).verifyComplete();
}
/**
@@ -107,7 +102,7 @@ public class ReactiveAirlineRepositoryIntegrationTests {
Airline airline = new Airline();
airline.setId("LH");
airline.setIataCode("LH");
airline.setIata("LH");
airline.setIcao("DLH");
airline.setCallsign("Lufthansa");
airline.setName("Lufthansa");

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2017-2018 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 example.springdata.couchbase.repository;
import static org.assertj.core.api.Assertions.*;
import example.springdata.couchbase.model.Airline;
import example.springdata.couchbase.util.CouchbaseAvailableRule;
import rx.Single;
import rx.observers.AssertableSubscriber;
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 RxJava1AirlineRepository}
*
* @author Mark Paluch
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RxJava1AirlineRepositoryIntegrationTests {
@ClassRule //
public static CouchbaseAvailableRule COUCHBASE = CouchbaseAvailableRule.onLocalhost();
@Autowired RxJava1AirlineRepository airlineRepository;
@Autowired CouchbaseOperations couchbaseOperations;
@Before
public void before() {
Airline toDelete = couchbaseOperations.findById("LH", Airline.class);
if (toDelete != null) {
couchbaseOperations.remove(toDelete);
}
}
/**
* The derived query executes a N1QL query emitting a single element.
*/
@Test
public void shouldFindAirlineN1ql() {
AssertableSubscriber<Airline> subscriber = airlineRepository.findAirlineByIataCode("TQ") //
.test() //
.awaitTerminalEvent() //
.assertCompleted();
assertThat(subscriber.getValueCount()).isEqualTo(1);
assertThat(subscriber.getOnNextEvents().get(0).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() {
Single<Airline> airline = airlineRepository.findAirlineByIataCode("TQ") //
.map(Airline::getId) //
.flatMap(airlineRepository::findById);
AssertableSubscriber<Airline> subscriber = airline.test().awaitTerminalEvent().assertCompleted();
assertThat(subscriber.getValueCount()).isEqualTo(1);
assertThat(subscriber.getOnNextEvents().get(0).getCallsign()).isEqualTo("TXW");
airlineRepository.findById("unknown").test().awaitTerminalEvent().assertNoValues();
}
/**
* Find all {@link Airline}s applying the {@code airlines/all} view.
*/
@Test
public void shouldFindByView() {
airlineRepository.findAllBy().test().awaitTerminalEvent().assertValueCount(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");
Single<Airline> single = airlineRepository.save(airline) //
.map(Airline::getId) //
.flatMap(airlineRepository::findById);
single.test().awaitTerminalEvent().assertResult(airline);
}
}

View File

@@ -19,6 +19,11 @@ import static org.assertj.core.api.Assertions.*;
import example.springdata.couchbase.model.Airline;
import example.springdata.couchbase.util.CouchbaseAvailableRule;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import rx.Observable;
import rx.observers.AssertableSubscriber;
@@ -28,81 +33,62 @@ 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.RxJavaCouchbaseOperations;
import org.springframework.test.context.junit4.SpringRunner;
import com.couchbase.client.java.query.N1qlQuery;
import com.couchbase.client.java.view.ViewQuery;
/**
* Integration tests showing basic CRUD operations through
* {@link org.springframework.data.couchbase.core.RxJavaCouchbaseOperations}.
* {@link org.springframework.data.couchbase.core.ReactiveCouchbaseOperations}.
*
* @author Mark Paluch
* @author Denis Rosa
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RxJavaCouchbaseOperationsIntegrationTests {
public class ReactiveJavaCouchbaseOperationsIntegrationTests {
@ClassRule //
public static CouchbaseAvailableRule COUCHBASE = CouchbaseAvailableRule.onLocalhost();
@Autowired RxJavaCouchbaseOperations operations;
@Autowired
ReactiveCouchbaseOperations operations;
@Autowired
CouchbaseOperations couchbaseOperations;
@Before
public void before() {
operations.findById("LH", Airline.class).flatMap(operations::remove).test().awaitTerminalEvent();
if (couchbaseOperations.existsById().one("LH")) {
couchbaseOperations.removeById().one("LH");
}
}
/**
* The derived query executes a N1QL query emitting a single element.
* Find all {@link Airline}s applying the _class filter .
*/
@Test
public void shouldFindAirlineN1ql() {
String n1ql = "SELECT META(`travel-sample`).id AS _ID, META(`travel-sample`).cas AS _CAS, `travel-sample`.* " + //
"FROM `travel-sample` " + //
"WHERE (`iata` = \"TQ\") AND `_class` = \"example.springdata.couchbase.model.Airline\"";
AssertableSubscriber<Airline> subscriber = operations.findByN1QL(N1qlQuery.simple(n1ql), Airline.class) //
.test() //
.awaitTerminalEvent() //
.assertCompleted();
assertThat(subscriber.getOnNextEvents()).hasSize(1);
assertThat(subscriber.getOnNextEvents().get(0).getCallsign()).isEqualTo("TXW");
public void shouldFindByAll() {
StepVerifier.create( operations.findByQuery( Airline.class).all()).expectNextCount(374).verifyComplete();
}
/**
* Find all {@link Airline}s applying the {@code airlines/all} view.
*/
@Test
public void shouldFindByView() {
Observable<Airline> airlines = operations.findByView(ViewQuery.from("airlines", "all"), Airline.class);
airlines.test().awaitTerminalEvent().assertValueCount(187);
}
/**
* Created elements are emitted by {@link RxJavaCouchbaseOperations#save(Object)}.
* Created elements are emitted by {@link ReactiveCouchbaseOperations#upsertById(Class)} )}.
*/
@Test
public void shouldCreateAirline() {
Airline airline = new Airline();
airline.setId("LH");
airline.setIataCode("LH");
airline.setIata("LH");
airline.setIcao("DLH");
airline.setCallsign("Lufthansa");
airline.setName("Lufthansa");
airline.setCountry("Germany");
Observable<Airline> single = operations.save(airline) //
Mono<Airline> airlineMono = operations.upsertById(Airline.class)
.one(airline) //
.map(Airline::getId) //
.flatMap(id -> operations.findById(id, Airline.class));
.flatMap(id -> operations.findById(Airline.class).one(id));
single.test().awaitTerminalEvent().assertResult(airline);
StepVerifier.create(airlineMono).expectNext(airline).verifyComplete();
}
}

View File

@@ -18,7 +18,7 @@
<modules>
<module>bom</module>
<!-- <module>couchbase</module> -->
<module>couchbase</module>
<module>elasticsearch</module>
<module>jdbc</module>
<module>jpa</module>