Skip to content

Commit

Permalink
add docker compose and jdbc test
Browse files Browse the repository at this point in the history
  • Loading branch information
gianluca-sabena committed Dec 22, 2023
1 parent 532dfa2 commit 93e842a
Show file tree
Hide file tree
Showing 13 changed files with 379 additions and 159 deletions.
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ An opinionated spring template based on a "clean architecture". (See credits)
└─────────────────────────────────────┘
```

## Requirements
## 1. Setup Environment

Java 17 or higher is required

Linux/WSL2
- Install sdkman <https://sdkman.io/>
Expand All @@ -38,37 +40,42 @@ Windows
- Install java `scoop install openjdk20`
- Install git with bash `scoop install main/git`

## Run
## 2. Run

Open a bash (on windows use `git-bash.exe` or similar)

Use `devel.sh -h` to run main actions

- Run `./gradlew bootRun`
- Build (include tests) `./gradlew build`
- Test
- Framework servlet see [frameworks/servlet/README.md](./frameworks/servlet/README.md)
Start with
- Start docker compose with postgreSQL `devel.sh du`
- `devel.sh test` -> execute `./gradlew build`
- `devel.sh buid` -> execute `./gradlew build`
- `devel.sh run` -> execute `./gradlew bootRun`

## Configure
Framework servlet see [frameworks/servlet/README.md](./frameworks/servlet/README.md)

## 3. Setup Project

In order to switch adapter from memory to jdbc

Simple approach is to use `devel.sh -c`
Short answer: use `devel.sh -c`

Long description:
Long answer:
- 1) edit [settings.gradle](./settings.gradle) and comment `include 'adapters:memory'` and uncomment `include 'adapters:jdbc'`
- 2) In folder: frameworks / servlet edit file [build.gradle](./frameworks/servlet/build.gradle) and comment `implementation project(':adapters:memory')` and uncomment `implementation project(':adapters:jdbc')`
- 3) Repeat step 2 for all other frameworks...


## Source

- Generate spring servlet from spring boot initializr
- Add example from official guide <https://github.com/spring-guides/tut-rest>
- Add code from <https://github.com/microservices-demo/orders>

## TODO
- Experiments with application properties
- JDBC with postgresql and oracle with
- JDBC with postgresql and oracle with ucp
- Add tests to adapter
- Tescontainers
- Buid jar
- Add more entities (item, order)
- Integrate lombok for entities
- Add a serialization adapter

## Credits

Expand All @@ -83,8 +90,10 @@ This project was inspired by:
- Example with ArchUnit <https://reflectoring.io/java-components-clean-boundaries/>

## Resources
- Generate spring servlet from spring boot initializr
- Spring Boot rest <https://github.com/spring-guides/tut-rest>
- Microservice example <https://github.com/microservices-demo/orders>
- Baeldung - Rest with pagination <https://www.baeldung.com/rest-api-pagination-in-spring>
- Spring multi module <https://spring.io/guides/gs/multi-module/>
- Blog <https://www.arhohuttunen.com/hexagonal-architecture-spring-boot/>
- Blog <https://betterprogramming.pub/hexagonal-architecture-with-spring-boot-74e93030eba3>

25 changes: 23 additions & 2 deletions adapters/jdbc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,31 @@ dependencyManagement {
dependencies {
implementation project(':entities')
implementation project(':usecases')
//implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
//runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
implementation 'org.liquibase:liquibase-core'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//testImplementation 'org.testcontainers:junit-jupiter'
//testImplementation 'org.testcontainers:postgresql'
}

tasks.named('test') {
useJUnitPlatform()
}

tasks.withType(Test).configureEach {
useJUnitPlatform()
testLogging {
// show success log in console
events "passed", "skipped", "failed"
// events "failed"
// print stack trace from tested code
exceptionFormat = 'full'
}
// https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html
// some messages may be logged two times...
// testLogging.showStandardStreams = true
// always execute tests
outputs.upToDateWhen { false }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,74 @@
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;


// TODO: Verify, Since we marged multiple modules, we need to have properties separated
// This is probably a problem with the IoC of spring, if we use application.properties
// h2 works, but postgresql doesn't
@PropertySource("classpath:jdbc.properties")
@Repository
// Required to autowire jdbctemplate
@EnableAutoConfiguration
public class DbCustomerRepository implements CustomerRepository {
Logger logger = LoggerFactory.getLogger(DbCustomerRepository.class);

private JdbcTemplate jdbcTemplate;
@Autowired
JdbcTemplate jdbcTemplate;

private final Map<String, Customer> inMemoryDb = new HashMap<>();

public DbCustomerRepository(JdbcTemplate jdbcTemplate) {
logger.info("-------> DbCustomerRepository JDBC - {}", jdbcTemplate.toString());
this.jdbcTemplate = jdbcTemplate;
@Autowired
public DbCustomerRepository() {
logger.info("-------> DbCustomerRepository JDBC");
}

@Override
public Optional<Customer> findByEmail(final String email) {
return inMemoryDb.values().stream()
.filter(customer -> customer.getEmail().equals(email))
.findAny();

List<Customer> customer = jdbcTemplate.query(
"SELECT id, email, lastname, firstname FROM CUSTOMER WHERE email = ?",
(rs, rowNum) -> Customer.builder().id(rs.getString("id")).email(rs.getString("email"))
.lastName(rs.getString("lastname"))
.firstName(rs.getString("firstname")).build(),email);
if (customer.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(customer.get(0));
}

}

@Override
public Customer create(final Customer customer) {
logger.info("JDBC adapter - Create customer: {}", customer.getId());
jdbcTemplate.update("INSERT INTO customer(id, email, lastName, firstName) VALUES (?,?,?,?)", customer.getId(), customer.getEmail(), customer.getLastName(), customer.getFirstName());
//inMemoryDb.put(customer.getId(), customer);
jdbcTemplate.update("INSERT INTO CUSTOMER(id, email, lastname, firstname) VALUES (?,?,?,?)", customer.getId(), customer.getEmail(), customer.getLastName(), customer.getFirstName());
return customer;
}

@Override
public Optional<Customer> findById(final String id) {
return Optional.ofNullable(inMemoryDb.get(id));
List<Customer> customer = jdbcTemplate.query(
"SELECT id, email, lastname, firstname FROM CUSTOMER WHERE id = ?",
(rs, rowNum) -> Customer.builder().id(rs.getString("id")).email(rs.getString("email"))
.lastName(rs.getString("lastname"))
.firstName(rs.getString("firstname")).build(),id);
if (customer.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(customer.get(0));
}
}

@Override
public List<Customer> findAllCustomers() {
return jdbcTemplate.query(
"SELECT id, email, lastName, firstName FROM customer",
"SELECT id, email, lastname, firstname FROM CUSTOMER",
(rs, rowNum) -> Customer.builder().id(rs.getString("id")).email(rs.getString("email"))
.lastName(rs.getString("lastName"))
.firstName(rs.getString("firstName")).build());
.lastName(rs.getString("lastname"))
.firstName(rs.getString("firstname")).build());
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
databaseChangeLog:
- changeSet:
id: "1"
author: default
changes:
- createTable:
tableName: customer
columns:
- column:
name: id
type: uuid
constraints:
primaryKey: true
nullable: false
- column:
name: email
type: varchar(50)
- column:
name: lastName
type: varchar(50)
- column:
name: firstName
type: varchar(50)
- changeSet:
id: "2"
author: default
changes:
- insert:
tableName: customer
columns:
- column:
name: id
value: 00000000-0000-0000-0000-000000000000
- column:
name: email
value: [email protected]
- column:
name: firstName
value: First Name
- column:
name: lastName
value: Last Name
databaseChangeLog:
- changeSet:
id: "1"
author: default
changes:
- createTable:
tableName: customer
columns:
- column:
name: id
type: varchar(50)
constraints:
primaryKey: true
nullable: false
- column:
name: email
type: varchar(50)
- column:
name: lastname
type: varchar(50)
- column:
name: firstname
type: varchar(50)
- changeSet:
id: "2"
author: default
changes:
- insert:
tableName: customer
columns:
- column:
name: id
value: 00000000-0000-0000-0000-000000000000
- column:
name: email
value: [email protected]
- column:
name: firstname
value: First Name
- column:
name: lastname
value: Last Name
4 changes: 4 additions & 0 deletions adapters/jdbc/src/main/resources/jdbc.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
spring.datasource.url=jdbc:postgresql://localhost/spring-clean
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=example
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.clean.adapter;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Repository;

import com.example.clean.entities.Customer;

import org.junit.jupiter.api.Test;

import org.springframework.context.annotation.PropertySource;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.UUID;

@SpringBootTest(classes = {DbCustomerRepository.class})
@PropertySource("classpath:jdbc.properties")
@Repository
class DbCustomerRepositoryTest {
//@Autowired
//private JdbcTemplate jdbcTemplate;
@Autowired
DbCustomerRepository dbCustomerRepository;

@Test
void createOne() {
//DbCustomerRepository dbCustomerRepository = new DbCustomerRepository(jdbcTemplate);
String id = UUID.randomUUID().toString();
Customer testOne = dbCustomerRepository.create(Customer.builder().id(id).email("test-1@test-1").firstName("Test 1").lastName("Test 1").build());
assertEquals(testOne.getId(), id);
}
}
Loading

0 comments on commit 93e842a

Please sign in to comment.