diff --git a/spring-5-data-reactive/pom.xml b/spring-5-data-reactive/pom.xml index 8c16851de0..056fb37a52 100644 --- a/spring-5-data-reactive/pom.xml +++ b/spring-5-data-reactive/pom.xml @@ -1,9 +1,9 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-5-data-reactive - spring-5-data-reactive + spring-5-data-reactive jar @@ -49,11 +49,11 @@ ${kotlin.version} test - + io.reactivex.rxjava2 rxjava - + org.springframework spring-test @@ -68,6 +68,39 @@ de.flapdoodle.embed.mongo test + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework + spring-tx + 5.2.0.M2 + + + + org.springframework.data + spring-data-r2dbc + 1.0.0.M2 + + + io.r2dbc + r2dbc-h2 + 0.8.0.M8 + + + com.h2database + h2 + 1.4.199 + + + org.springframework.boot + spring-boot-starter-test + test + + @@ -79,7 +112,7 @@ kotlin-maven-plugin ${kotlin-maven-plugin.version} - + compile @@ -123,7 +156,7 @@ - + org.apache.maven.plugins maven-compiler-plugin @@ -131,13 +164,13 @@ ${java.version} - default-compile none - default-testCompile @@ -167,5 +200,21 @@ 1.2.40 + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java new file mode 100644 index 0000000000..557b6ff42a --- /dev/null +++ b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/R2dbcApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.r2dbc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = "com.baeldung.r2dbc") +public class R2dbcApplication { + + public static void main(String[] args) { + SpringApplication.run(R2dbcApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java new file mode 100644 index 0000000000..17eac7fee2 --- /dev/null +++ b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/configuration/R2DBCConfiguration.java @@ -0,0 +1,21 @@ +package com.baeldung.r2dbc.configuration; + +import io.r2dbc.h2.H2ConnectionConfiguration; +import io.r2dbc.h2.H2ConnectionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; + +@Configuration +//@EnableR2dbcRepositories(basePackages = "com.baeldung.r2dbc.repository") +public class R2DBCConfiguration extends AbstractR2dbcConfiguration { + @Bean + public H2ConnectionFactory connectionFactory() { + return new H2ConnectionFactory( + H2ConnectionConfiguration.builder() + .url("mem:testdb;DB_CLOSE_DELAY=-1;TRACE_LEVEL_FILE=4") + .username("sa") + .build()); + } +} \ No newline at end of file diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/model/Player.java b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/model/Player.java new file mode 100644 index 0000000000..1926997e97 --- /dev/null +++ b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/model/Player.java @@ -0,0 +1,16 @@ +package com.baeldung.r2dbc.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Player { + @Id + Integer id; + String name; + Integer age; +} \ No newline at end of file diff --git a/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java new file mode 100644 index 0000000000..33b653140e --- /dev/null +++ b/spring-5-data-reactive/src/main/java/com/baeldung/r2dbc/repository/PlayerRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.r2dbc.repository; + +import com.baeldung.r2dbc.model.Player; +import org.springframework.data.r2dbc.repository.query.Query; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import reactor.core.publisher.Flux; + +public interface PlayerRepository extends ReactiveCrudRepository { + + @Query("select id, name, age from player where name = $1") + Flux findAllByName(String name); + + @Query("select * from player where age = $1") + Flux findByAge(int age); +} \ No newline at end of file diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java new file mode 100644 index 0000000000..a31ef4458d --- /dev/null +++ b/spring-5-data-reactive/src/test/java/com/baeldung/r2dbc/R2dbcApplicationIntegrationTest.java @@ -0,0 +1,125 @@ +package com.baeldung.r2dbc; + + +import com.baeldung.r2dbc.model.Player; +import com.baeldung.r2dbc.repository.PlayerRepository; +import io.r2dbc.h2.H2ConnectionFactory; +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.data.r2dbc.core.DatabaseClient; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Hooks; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Arrays; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class R2dbcApplicationIntegrationTest { + + + @Autowired + PlayerRepository playerRepository; + + @Autowired + DatabaseClient client; + + @Autowired + H2ConnectionFactory factory; + + + @Before + public void setup() { + + Hooks.onOperatorDebug(); + + List statements = Arrays.asList(// + "DROP TABLE IF EXISTS player;", + "CREATE table player (id INT AUTO_INCREMENT NOT NULL, name VARCHAR2, age INT NOT NULL);"); + + statements.forEach(it -> client.execute() // + .sql(it) // + .fetch() // + .rowsUpdated() // + .as(StepVerifier::create) // + .expectNextCount(1) // + .verifyComplete()); + + } + + @Test + public void whenDeleteAll_then0IsExpected() { + + + playerRepository.deleteAll() + .as(StepVerifier::create) + .expectNextCount(0) + .verifyComplete(); + } + + @Test + public void whenInsert6_then6AreExpected() { + + insertPlayers(); + + playerRepository.findAll() + .as(StepVerifier::create) + .expectNextCount(6) + .verifyComplete(); + } + + @Test + public void whenSearchForCR7_then1IsExpected() { + + insertPlayers(); + + playerRepository.findAllByName("CR7") + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + } + + @Test + public void whenSearchFor32YearsOld_then2AreExpected() { + insertPlayers(); + + playerRepository.findByAge(32) + .as(StepVerifier::create) + .expectNextCount(2) + .verifyComplete(); + } + + @Test + public void whenBatchHas2Operations_then2AreExpected() { + Mono.from(factory.create()) + .flatMapMany(connection -> Flux.from(connection + .createBatch() + .add("select * from player") + .add("select * from player") + .execute())) + .as(StepVerifier::create) + .expectNextCount(2) + .verifyComplete(); + + } + + private void insertPlayers() { + List players = Arrays.asList( + new Player(1, "Kaka", 37), + new Player(2, "Messi", 32), + new Player(3, "Mbappé", 20), + new Player(4, "CR7", 34), + new Player(5, "Lewandowski", 30), + new Player(6, "Cavani", 32) + ); + + playerRepository.saveAll(players).subscribe(); + } +} +