Skip to content
This repository has been archived by the owner on Jul 26, 2024. It is now read-only.

introduce database access (in progress) #12

Merged
merged 4 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ target/
!**/src/main/**/target/
!**/src/test/**/target/

# DB
.local-db

### STS ###
.apt_generated
.classpath
Expand Down
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
Expand All @@ -32,6 +33,7 @@ public Optional<BlogPost> findById(UUID id) {
}

public void create(@Valid @NotNull BlogPost blogPost) {
blogPost.setTimestamp(LocalDateTime.now());
this.sink.create(blogPost);
this.eventPublisher.publishEvent(new BlogPostCreatedEvent(blogPost));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.sample.schulung.spring.blog.domain;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -20,7 +19,6 @@ public long count() {
public void create(BlogPost post) {
final var id = UUID.randomUUID();
post.setId(id);
post.setTimestamp(LocalDateTime.now());
this.blogPosts.put(id, post);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.sample.schulung.spring.blog.persistence;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.UUID;

@Getter
@Setter
@Entity(name = "BlogPost") // Name der Entity (JPQL)
@Table(name = "BLOG_POSTS")
public class BlogPostEntity {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Size(min = 3)
@NotNull
private String title;
@Size(min = 10)
@NotNull
private String content;
@Column(name = "TIME_STAMP")
private LocalDateTime timestamp;

/*
@PrePersist
public void updateTimestamp() {
this.timestamp = LocalDateTime.now();
}
*/

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.sample.schulung.spring.blog.persistence;

import de.sample.schulung.spring.blog.domain.BlogPost;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

@Mapper(componentModel = "spring")
public interface BlogPostEntityMapper {

BlogPost map(BlogPostEntity source);

BlogPostEntity map(BlogPost source);

void copy(BlogPostEntity source, @MappingTarget BlogPost target);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.sample.schulung.spring.blog.persistence;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.UUID;
import java.util.stream.Stream;

@Repository
public interface BlogPostRepository
extends JpaRepository<BlogPostEntity, UUID> {

// oder @Query("...")
Stream<BlogPostEntity> streamBlogPostEntitiesByTitleContainingIgnoreCaseOrderByTimestampDesc(String title);

@Query("select p from BlogPost p where p.title = :title")
Stream<BlogPostEntity> streamIrgendwie(@Param("title") String title);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.sample.schulung.spring.blog.persistence;

import de.sample.schulung.spring.blog.domain.BlogPost;
import de.sample.schulung.spring.blog.domain.BlogPostSink;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;

@RequiredArgsConstructor
@Component
public class JpaBlogPostSink implements BlogPostSink {

private final BlogPostRepository repo;
private final BlogPostEntityMapper mapper;

@Override
public long count() {
return repo.count();
}

@Override
public void create(BlogPost post) {
final var entity = mapper.map(post);
final var savedEntity = repo.save(entity);
//post.setId(savedEntity.getId());
mapper.copy(savedEntity, post);
}

@Override
public Stream<BlogPost> findAll() {
return repo.findAll()
.stream()
.map(mapper::map);
}

@Override
public Optional<BlogPost> findById(UUID id) {
return repo.findById(id)
.map(mapper::map);
}
}
16 changes: 16 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,19 @@ application:
cors:
allow:
origins: ${CORS_ALLOW_ORIGINS:*}
spring:
datasource:
url: jdbc:h2:./.local-db/data
h2:
console:
enabled: true
path: /h2-console # http://localhost:9080/h2-console (leave username and password empty)
jpa:
generate-ddl: true
show-sql: true
open-in-view: false
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
Expand All @@ -15,6 +16,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureTestDatabase
@AutoConfigureMockMvc
@ActiveProfiles("no-initialization")
class BlogPostApiTests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

Expand All @@ -21,7 +22,8 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@WebMvcTest
@ComponentScan(basePackageClasses = BlogPostApiWithMockedServiceTests.class)
@AutoConfigureMockMvc
class BlogPostApiWithMockedServiceTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;

import static org.assertj.core.api.Assertions.assertThat;

// SO NICHT!
@SpringBootTest
@AutoConfigureTestDatabase
public class BlogPostControllerIntegrationTests {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.validation.ConstraintViolationException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.event.ApplicationEvents;
Expand All @@ -12,6 +13,7 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@SpringBootTest
@AutoConfigureTestDatabase // TODO: wie ohne Datenbank?
@RecordApplicationEvents
@ActiveProfiles("test-domain")
public class BlogPostEventsTests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;

Expand All @@ -13,6 +14,7 @@
* THIS WILL LEAD TO A SEPARATE CONTEXT !!!
*/
@SpringBootTest
@AutoConfigureTestDatabase
// komplette Anwendung -> Test der Konfiguration in application.yml
@TestPropertySource(properties = {
"application.initialization.enabled=true",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@AutoConfigureTestDatabase
// komplette Anwendung -> Test der Konfiguration in application.yml
public class BlogPostServiceTests {

Expand Down