BAEL-5988: Added code for Spring R2DBC flyway migration with tests (#13551)
* BAEL-5988: Added code for Spring R2DBC flyway migration with tests * BAEL-5988: Removed unnecessary logging config * BAEL-5988: Addressed review comments * BAEL-5988: Removed bean loading override config for test * BAEL-5988: Removed unnecessary import * BAEL-5988: Added properties for versions in pom --------- Co-authored-by: Bala <balamurugan.radhakrishnan@yapily.com> Co-authored-by: balasr3 <balamurugan.radhakrishnan@imgarena.com>
This commit is contained in:
parent
5069680b89
commit
b1162d37b9
|
@ -49,6 +49,34 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>r2dbc-postgresql</artifactId>
|
||||||
|
<version>${r2dbc.postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${jdbc.postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-core</artifactId>
|
||||||
|
<version>${flyway.core.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.r2dbc</groupId>
|
||||||
|
<artifactId>r2dbc-h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -60,4 +88,10 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<flyway.core.version>9.14.1</flyway.core.version>
|
||||||
|
<jdbc.postgresql.version>42.5.2</jdbc.postgresql.version>
|
||||||
|
<r2dbc.postgresql.version>1.0.0.RELEASE</r2dbc.postgresql.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringWebfluxFlywayApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringWebfluxFlywayApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.config;
|
||||||
|
|
||||||
|
import org.flywaydb.core.Flyway;
|
||||||
|
import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.r2dbc.R2dbcProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties({ R2dbcProperties.class, FlywayProperties.class })
|
||||||
|
class DatabaseConfig {
|
||||||
|
@Bean(initMethod = "migrate")
|
||||||
|
public Flyway flyway(FlywayProperties flywayProperties, R2dbcProperties r2dbcProperties) {
|
||||||
|
return Flyway.configure()
|
||||||
|
.dataSource(flywayProperties.getUrl(), r2dbcProperties.getUsername(), r2dbcProperties.getPassword())
|
||||||
|
.locations(flywayProperties.getLocations()
|
||||||
|
.stream()
|
||||||
|
.toArray(String[]::new))
|
||||||
|
.baselineOnMigrate(true)
|
||||||
|
.load();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.model;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.domain.Persistable;
|
||||||
|
import org.springframework.data.relational.core.mapping.Table;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Table("department")
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Department implements Persistable<UUID> {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@JsonProperty("uuid")
|
||||||
|
@JsonAlias("id")
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(max = 255, message = "The property 'name' must be less than or equal to 255 characters.")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isNew() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.model;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.domain.Persistable;
|
||||||
|
import org.springframework.data.relational.core.mapping.Table;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Table("student")
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Student implements Persistable<UUID> {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@JsonProperty("uuid")
|
||||||
|
@JsonAlias("id")
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(max = 255, message = "The property 'firstName' must be less than or equal to 255 characters.")
|
||||||
|
private String firstName;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(max = 255, message = "The property 'lastName' must be less than or equal to 255 characters.")
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate dateOfBirth;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private UUID department;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isNew() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.repository;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||||
|
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Department;
|
||||||
|
|
||||||
|
public interface DepartmentRepository extends ReactiveCrudRepository<Department, UUID> {
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.repository;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||||
|
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Student;
|
||||||
|
|
||||||
|
public interface StudentRepository extends ReactiveCrudRepository<Student, UUID> {
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.rest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Department;
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.repository.DepartmentRepository;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DepartmentResource {
|
||||||
|
|
||||||
|
private final DepartmentRepository departmentRepository;
|
||||||
|
|
||||||
|
@GetMapping(path = "/department")
|
||||||
|
public Mono<ResponseEntity<List<Department>>> getDepartments() {
|
||||||
|
return departmentRepository.findAll()
|
||||||
|
.collectList()
|
||||||
|
.map(departments -> new ResponseEntity(departments, HttpStatus.OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.rest;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Student;
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.repository.StudentRepository;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class StudentResource {
|
||||||
|
|
||||||
|
private final StudentRepository studentRepository;
|
||||||
|
|
||||||
|
@PostMapping(path = "/student")
|
||||||
|
public Mono<ResponseEntity<Student>> createStudent(@RequestBody @Valid Mono<Student> createStudentRequest) {
|
||||||
|
return createStudentRequest.flatMap(studentRepository::save)
|
||||||
|
.map(student -> new ResponseEntity(student, HttpStatus.CREATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,13 @@ spring:
|
||||||
application:
|
application:
|
||||||
name: r2dbc-test
|
name: r2dbc-test
|
||||||
|
|
||||||
|
r2dbc:
|
||||||
|
username: local
|
||||||
|
password: local
|
||||||
|
url: r2dbc:postgresql://localhost:8082/flyway-test-db
|
||||||
|
flyway:
|
||||||
|
url: jdbc:postgresql://localhost:8082/flyway-test-db
|
||||||
|
locations: classpath:db/postgres/migration
|
||||||
# R2DBC URL
|
# R2DBC URL
|
||||||
r2dbc:
|
r2dbc:
|
||||||
url: r2dbc:h2:mem://./testdb
|
url: r2dbc:h2:mem://./testdb
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: '3.9'
|
||||||
|
networks:
|
||||||
|
obref:
|
||||||
|
services:
|
||||||
|
postgres_db_service:
|
||||||
|
container_name: postgres_db_service
|
||||||
|
image: postgres:11
|
||||||
|
ports:
|
||||||
|
- "8082:5432"
|
||||||
|
hostname: postgres_db_service
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=local
|
||||||
|
- POSTGRES_USER=local
|
||||||
|
- POSTGRES_DB=flyway-test-db
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS department
|
||||||
|
(
|
||||||
|
id uuid PRIMARY KEY UNIQUE DEFAULT uuid_generate_v4(),
|
||||||
|
name varchar(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS student
|
||||||
|
(
|
||||||
|
id uuid PRIMARY KEY UNIQUE DEFAULT uuid_generate_v4(),
|
||||||
|
first_name varchar(255),
|
||||||
|
last_name varchar(255),
|
||||||
|
date_of_birth DATE NOT NULL,
|
||||||
|
department uuid NOT NULL CONSTRAINT student_foreign_key1 REFERENCES department (id)
|
||||||
|
);
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
insert into department(name) values ('Computer Science');
|
||||||
|
insert into department(name) values ('Biomedical');
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.baeldung.examples.r2dbc.flyway.rest;
|
||||||
|
|
||||||
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Department;
|
||||||
|
import com.baeldung.examples.r2dbc.flyway.model.Student;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||||
|
class StudentResourceUnitTest {
|
||||||
|
|
||||||
|
private static final String DEPARTMENT_ENDPOINT = "/department";
|
||||||
|
private static final String STUDENT_ENDPOINT = "/student";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected WebTestClient webTestClient;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenDepartmentExists_WhenCreateStudentRequestIsSent_ShouldBeProcessedSuccessfully() {
|
||||||
|
|
||||||
|
// Given
|
||||||
|
List<Department> departmentList = webTestClient.get()
|
||||||
|
.uri(DEPARTMENT_ENDPOINT)
|
||||||
|
.exchange()
|
||||||
|
.expectStatus()
|
||||||
|
.isOk()
|
||||||
|
.expectBodyList(Department.class)
|
||||||
|
.returnResult()
|
||||||
|
.getResponseBody();
|
||||||
|
|
||||||
|
Assertions.assertNotNull(departmentList);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Student student = webTestClient.post()
|
||||||
|
.uri(STUDENT_ENDPOINT)
|
||||||
|
.body(BodyInserters.fromPublisher(Mono.just(Student.builder()
|
||||||
|
.firstName("John")
|
||||||
|
.lastName("Doe")
|
||||||
|
.dateOfBirth(LocalDate.of(2015, 12, 1))
|
||||||
|
.department(departmentList.get(0)
|
||||||
|
.getId())
|
||||||
|
.build()), Student.class))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus()
|
||||||
|
.isEqualTo(201)
|
||||||
|
.expectBody(Student.class)
|
||||||
|
.returnResult()
|
||||||
|
.getResponseBody();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
Assertions.assertNotNull(student.getId());
|
||||||
|
Assertions.assertEquals("John", student.getFirstName());
|
||||||
|
Assertions.assertEquals("Doe", student.getLastName());
|
||||||
|
Assertions.assertEquals(LocalDate.of(2015, 12, 1), student.getDateOfBirth());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,5 +2,28 @@
|
||||||
r2dbc:
|
r2dbc:
|
||||||
url: r2dbc:h2:mem://./testdb
|
url: r2dbc:h2:mem://./testdb
|
||||||
|
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
spring:
|
||||||
|
r2dbc:
|
||||||
|
host: localhost
|
||||||
|
port: 8082
|
||||||
|
database: testdb
|
||||||
|
username: local
|
||||||
|
password: local
|
||||||
|
|
||||||
|
h2:
|
||||||
|
console:
|
||||||
|
enabled: true
|
||||||
|
path: h2-console
|
||||||
|
|
||||||
|
|
||||||
|
flyway:
|
||||||
|
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;
|
||||||
|
user: local
|
||||||
|
password: local
|
||||||
|
locations: classpath:db/h2/migration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
CREATE TABLE department
|
||||||
|
(
|
||||||
|
id uuid DEFAULT random_uuid() PRIMARY KEY UNIQUE NOT NULL,
|
||||||
|
name varchar(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE student
|
||||||
|
(
|
||||||
|
id uuid DEFAULT random_uuid() UNIQUE NOT NULL,
|
||||||
|
first_name varchar(255),
|
||||||
|
last_name varchar(255),
|
||||||
|
date_of_birth DATE NOT NULL,
|
||||||
|
department uuid NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE student
|
||||||
|
ADD FOREIGN KEY (department) REFERENCES department(id);
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
insert into department(name) values ('Computer Science');
|
||||||
|
insert into department(name) values ('Biomedical');
|
Loading…
Reference in New Issue