diff --git a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/controller/ArticleController.java b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/controller/ArticleController.java index 60a7700a5..db9fcc3f0 100644 --- a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/controller/ArticleController.java +++ b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/controller/ArticleController.java @@ -43,14 +43,13 @@ ResponseEntity saveArticle(@RequestBody ArticleDTO articleDTO) { } @DeleteMapping("/{id}") - ResponseEntity deleteArticle(@PathVariable Long id) { - return this.articleService - .findById(id) - .map( - article -> { - articleService.deleteById(article.getId()); - return ResponseEntity.accepted().build(); - }) - .orElseGet(() -> ResponseEntity.notFound().build()); + ResponseEntity deleteArticle(@PathVariable Long id) { + boolean exists = this.articleService.existsById(id); + if (exists) { + this.articleService.deleteById(id); + return ResponseEntity.accepted().build(); + } else { + return ResponseEntity.notFound().build(); + } } } diff --git a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/domain/ArticleDTO.java b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/domain/ArticleDTO.java index 4c480bf5f..272d6d75a 100644 --- a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/domain/ArticleDTO.java +++ b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/domain/ArticleDTO.java @@ -1,9 +1,6 @@ package com.example.demo.readreplica.domain; -import static com.example.demo.readreplica.domain.CommentDTO.convertToComment; - import com.example.demo.readreplica.entities.Article; -import com.example.demo.readreplica.entities.Comment; import java.time.LocalDateTime; import java.util.List; @@ -16,11 +13,7 @@ public record ArticleDTO( public Article convertToArticle() { Article article = new Article().setAuthored(authored).setTitle(title).setPublished(published); - commentDTOs.forEach( - commentDTO -> { - Comment comment = convertToComment(commentDTO); - article.addComment(comment); - }); + commentDTOs.stream().map(CommentDTO::convertToComment).forEach(article::addComment); return article; } } diff --git a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/repository/ArticleRepository.java b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/repository/ArticleRepository.java index 0b735b2df..e675e7a39 100644 --- a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/repository/ArticleRepository.java +++ b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/repository/ArticleRepository.java @@ -5,11 +5,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.transaction.annotation.Transactional; public interface ArticleRepository extends JpaRepository { - @Transactional(readOnly = true) @Query("select a from Article a left join fetch a.comments where a.id = :articleId ") Optional
findByArticleId(@Param("articleId") Long articleId); } diff --git a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/service/ArticleService.java b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/service/ArticleService.java index fa4886afe..e049cd038 100644 --- a/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/service/ArticleService.java +++ b/jpa/boot-read-replica-postgresql/src/main/java/com/example/demo/readreplica/service/ArticleService.java @@ -22,6 +22,10 @@ public Optional findArticleById(Long id) { return this.articleRepository.findByArticleId(id).map(this::convertToArticleDTO); } + public boolean existsById(Long id) { + return articleRepository.existsById(id); + } + @Transactional public Long saveArticle(ArticleDTO articleDTO) { Article article = articleDTO.convertToArticle(); @@ -29,10 +33,6 @@ public Long saveArticle(ArticleDTO articleDTO) { return savedArticle.getId(); } - public Optional
findById(Long id) { - return articleRepository.findById(id); - } - @Transactional public void deleteById(Long id) { articleRepository.deleteById(id); diff --git a/jpa/boot-read-replica-postgresql/src/main/resources/application.yml b/jpa/boot-read-replica-postgresql/src/main/resources/application.yml index 90cbe6ec0..cd0e7d292 100644 --- a/jpa/boot-read-replica-postgresql/src/main/resources/application.yml +++ b/jpa/boot-read-replica-postgresql/src/main/resources/application.yml @@ -45,6 +45,9 @@ spring: fail_on_pagination_over_collection_fetch: true in_clause_parameter_padding: true plan_cache_max_size: 4096 + mvc: + problemdetails: + enabled: true threads: virtual: enabled: true diff --git a/jpa/boot-read-replica-postgresql/src/test/java/com/example/demo/readreplica/controller/ArticleControllerIntTest.java b/jpa/boot-read-replica-postgresql/src/test/java/com/example/demo/readreplica/controller/ArticleControllerIntTest.java index 0b1fcb806..59ae70ef2 100644 --- a/jpa/boot-read-replica-postgresql/src/test/java/com/example/demo/readreplica/controller/ArticleControllerIntTest.java +++ b/jpa/boot-read-replica-postgresql/src/test/java/com/example/demo/readreplica/controller/ArticleControllerIntTest.java @@ -6,6 +6,7 @@ import com.example.demo.readreplica.domain.CommentDTO; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -55,7 +56,12 @@ void findArticleById() { } @Test - void saveArticleRetriveAndDelete() throws JsonProcessingException { + void shouldReturn404WhenFetchingNonExistingArticle() { + mvcTester.get().uri("/articles/99999").assertThat().hasStatus(HttpStatus.NOT_FOUND); + } + + @Test + void saveRetrieveAndDeleteArticle() throws JsonProcessingException { ArticleDTO articleDTO = new ArticleDTO( "junitTitle", @@ -90,9 +96,13 @@ void saveArticleRetriveAndDelete() throws JsonProcessingException { assertThat(response.authored()) .isNotNull() .isInstanceOf(LocalDateTime.class); + assertThat(response.authored().toLocalDate()) + .isEqualTo(LocalDate.now().minusDays(1)); assertThat(response.published()) .isNotNull() .isInstanceOf(LocalDateTime.class); + assertThat(response.published().toLocalDate()) + .isEqualTo(LocalDate.now()); assertThat(response.commentDTOs()) .isNotNull() .hasSize(1) @@ -101,4 +111,9 @@ void saveArticleRetriveAndDelete() throws JsonProcessingException { mvcTester.delete().uri(location.get()).assertThat().hasStatus(HttpStatus.ACCEPTED); } + + @Test + void cantDeleteArticleWhenArticleNotFound() { + mvcTester.delete().uri("/articles/99999").assertThat().hasStatus(HttpStatus.NOT_FOUND); + } }