From 49e36c72c5098a4043060d23d09595ee1d02be2f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:00:59 +0300 Subject: [PATCH 001/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/Review.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Review.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Review.java b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java new file mode 100644 index 00000000..9c0977d5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Review { + private long reviewId; + private String content; + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From fb23b56aff8187ff35949a60db384c2522b214ab Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:01:07 +0300 Subject: [PATCH 002/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dto/ReviewDto.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java new file mode 100644 index 00000000..7edbff53 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReviewDto { + private long reviewId; + @NotBlank(message = "Отзыв не может быть пустой.") + private String content; + @NotBlank(message = "Не указана полезность отзыва.") + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From 64caaca7d2fd88073c15f9ea852a4ce9999b1d76 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:03:55 +0300 Subject: [PATCH 003/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewMapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/mapper/ReviewMapper.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java new file mode 100644 index 00000000..e5256f4a --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -0,0 +1,31 @@ +package ru.yandex.practicum.filmorate.mapper; + +import lombok.experimental.UtilityClass; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; + +@UtilityClass +public class ReviewMapper { + + public static ReviewDto toDto(Review review) { + return ReviewDto.builder() + .reviewId(review.getReviewId()) + .content(review.getContent()) + .isPositive(review.isPositive()) + .useful(review.getUseful()) + .filmId(review.getFilmId()) + .userId(review.getUserId()) + .build(); + } + + public static Review toModel(ReviewDto reviewDto) { + return Review.builder() + .reviewId(reviewDto.getReviewId()) + .content(reviewDto.getContent()) + .isPositive(reviewDto.isPositive()) + .useful(reviewDto.getUseful()) + .filmId(reviewDto.getFilmId()) + .userId(reviewDto.getUserId()) + .build(); + } +} From a052ee1c2067732435c0984f07f3f4ca0b098768 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:29:47 +0300 Subject: [PATCH 004/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20wrapper=20cl?= =?UTF-8?q?ass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dto/ReviewDto.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 7edbff53..731e61cb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; @Data @AllArgsConstructor @@ -13,11 +14,13 @@ @Builder public class ReviewDto { private long reviewId; - @NotBlank(message = "Отзыв не может быть пустой.") + @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; - @NotBlank(message = "Не указана полезность отзыва.") + @NotNull(message = "Не указана полезность отзыва.") private boolean isPositive; private long useful; - private long userId; - private long filmId; + @NotNull(message = "Не указан идентификатор пользователя.") + private Long userId; + @NotNull(message = "Не указан идентификатор фильма.") + private Long filmId; } From 2f84fdd285ebf9f4f8d339ee815a61f53bb40390 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:30:08 +0300 Subject: [PATCH 005/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ReviewValidationTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java new file mode 100644 index 00000000..e97dcfe0 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java @@ -0,0 +1,106 @@ +package ru.yandex.practicum.filmorate.validation; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.VALIDATOR; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.dtoHasErrorMessage; + +public class ReviewValidationTest { + + @Test + @DisplayName("Проверка возможности добавить отзыв с корректными полями") + public void createReview() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(VALIDATOR.validate(reviewDto).isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", " "}) + @DisplayName("Проверка невозможности добавить отзыв с пустым полем content") + public void createReviewWithoutContent(String content) { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(content) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если content == null") + public void createReviewWithNullContent() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(null) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан filmId") + public void createReviewWithNullFilmId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(null) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор фильма.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан userId") + public void createReviewWithNullUserId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(null) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор пользователя.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указана полезность") + public void createReviewWithNullIsPositive() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(null) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указана полезность отзыва.")); + } +} From cf48bfb2ecd9bc8f7f1e58c855454465e53b6ddb Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:35:07 +0300 Subject: [PATCH 006/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20Boolean=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20isPositive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java | 2 +- .../java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 731e61cb..200676ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -17,7 +17,7 @@ public class ReviewDto { @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; @NotNull(message = "Не указана полезность отзыва.") - private boolean isPositive; + private Boolean isPositive; private long useful; @NotNull(message = "Не указан идентификатор пользователя.") private Long userId; diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java index e5256f4a..d61c233f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -22,7 +22,7 @@ public static Review toModel(ReviewDto reviewDto) { return Review.builder() .reviewId(reviewDto.getReviewId()) .content(reviewDto.getContent()) - .isPositive(reviewDto.isPositive()) + .isPositive(reviewDto.getIsPositive()) .useful(reviewDto.getUseful()) .filmId(reviewDto.getFilmId()) .userId(reviewDto.getUserId()) From c1b9153060b4da5c1fda4ca304ec10383587e193 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:12 +0300 Subject: [PATCH 007/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index d6a6e230..ac4a2ccf 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -59,4 +59,15 @@ CREATE TABLE IF NOT EXISTS FILM_LIKE( CONSTRAINT pk_film_like PRIMARY KEY (FILM_ID, USER_ID), FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) +); + +CREATE TABLE IF NOT EXISTS REVIEW( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, + REVIEW_CONTENT CHARACTER VARYING(255) NOT NULL, + IS_POSITIVE BOOLEAN NOT NULL, + USEFUL INTEGER, + USER_ID INTEGER NOT NULL, + FILM_ID INTEGER NOT NULL, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ); \ No newline at end of file From 8b549ddfd4417488f759e254a0979c5aec12c2db Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:56 +0300 Subject: [PATCH 008/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dao/ReviewStorage.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java new file mode 100644 index 00000000..441e2b3c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -0,0 +1,6 @@ +package ru.yandex.practicum.filmorate.dao; + +import ru.yandex.practicum.filmorate.model.Review; + +public interface ReviewStorage extends Dao{ +} From 9ab12f5f0df66c232aff5abb20b1244fdbd5ee4c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:14 +0300 Subject: [PATCH 009/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java new file mode 100644 index 00000000..23705f20 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -0,0 +1,82 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Review; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Objects; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewDbStorage implements ReviewStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public Review add(final Review review) { + final KeyHolder keyHolder = new GeneratedKeyHolder(); + final String sql = "INSERT INTO review (review_content, is_positive, useful, user_id, film_id) VALUES (?, ?, ?, ?, ?)"; + jdbcTemplate.update(con -> { + PreparedStatement stmt = con.prepareStatement(sql, new String[]{"id"}); + stmt.setString(1, review.getContent()); + stmt.setBoolean(2, review.isPositive()); + stmt.setLong(3, review.getUseful()); + stmt.setLong(4, review.getUserId()); + stmt.setLong(5, review.getFilmId()); + return stmt; + }, keyHolder); + + review.setReviewId(Objects.requireNonNull(keyHolder.getKey(), "Не удалось добавить отзыв.").longValue()); + + return review; + } + + @Override + public void remove(final long id) { + + } + + @Override + public void update(final Review review) { + + } + + @Override + public Collection findAll() { + return null; + } + + @Override + public Review findById(final long id) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE ID = ?"; + try { + return jdbcTemplate.queryForObject(sql, this::mapReview, id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } + } + + private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + return Review.builder() + .reviewId(rs.getLong("id")) + .content(rs.getString("review_content")) + .isPositive(rs.getBoolean("is_positive")) + .useful(rs.getLong("useful")) + .userId(rs.getLong("user_id")) + .filmId(rs.getLong("film_id")) + .build(); + } +} From 4783c657b0937299d69e1033aaf1cde0fff53e6a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:31 +0300 Subject: [PATCH 010/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/ReviewService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java new file mode 100644 index 00000000..c84d3780 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -0,0 +1,10 @@ +package ru.yandex.practicum.filmorate.service; + + +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +public interface ReviewService { + ReviewDto addReview(ReviewDto reviewDto); + + ReviewDto getReviewById(long id); +} From 7c8f4cf0f58bd266f6c1210e4d4e89924e92d4bc Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:44 +0300 Subject: [PATCH 011/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java new file mode 100644 index 00000000..beb330f4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ReviewServiceImpl implements ReviewService { + + private final ReviewStorage reviewStorage; + private final UserStorage userStorage; + private final FilmStorage filmStorage; + + + @Override + public ReviewDto addReview(final ReviewDto reviewDto) { + final Review review = toModel(reviewDto); + userStorage.findById(review.getUserId()); + filmStorage.findById(review.getFilmId()); + final Review addedReview = reviewStorage.add(review); + log.info("Добавлен новый отзыв: {}.", addedReview); + return toDto(reviewStorage.findById(addedReview.getReviewId())); + } + + @Override + public ReviewDto getReviewById(final long id) { + final Review review = reviewStorage.findById(id); + log.info("Найден отзыв с id '{}'.", id); + return toDto(review); + } + + +} From b31165197eb048486490b7126623decde2372ca7 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:26:00 +0300 Subject: [PATCH 012/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java new file mode 100644 index 00000000..0ede3d93 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -0,0 +1,65 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import javax.validation.Valid; +import java.util.List; + +@RestController +@RequestMapping("/reviews") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { + return reviewService.addReview(reviewDto); + } + +// @PutMapping +// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { +// return reviewService.updateReview(updatedReviewDto); +// } +// +// @DeleteMapping("/{id}") +// public void deleteReview(@PathVariable long id) { +// reviewService.deleteReview(id); +// } +// + @GetMapping("/{id}") + public ReviewDto getReviewById(@PathVariable long id) { + return reviewService.getReviewById(id); + } +// +// @GetMapping +// public List getReviewsByFilmId(@RequestParam long filmId, +// @RequestParam(required = false, defaultValue = "10") int count) { +// return reviewService.getReviewsByFilmId(filmId, count); +// } +// +// @PutMapping("/{id}/like/{userId}") +// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addLikeToReview(id, userId); +// } +// +// @PutMapping("/{id}/dislike/{userId}") +// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addDislikeToReview(id, userId); +// } +// +// @DeleteMapping("/{id}/like/{userId}") +// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteLikeFromReview(id, userId); +// } +// +// @DeleteMapping("/{id}/dislike/{userId}") +// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteDislikeFromReview(id, userId); +// } +} From 3c41f3d722664451f4070a81aafddc7c2355ba99 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:30 +0300 Subject: [PATCH 013/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ON=20DELETE=20CASCADE=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index ac4a2ccf..5c6180e9 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -68,6 +68,6 @@ CREATE TABLE IF NOT EXISTS REVIEW( USEFUL INTEGER, USER_ID INTEGER NOT NULL, FILM_ID INTEGER NOT NULL, - FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE ); \ No newline at end of file From aa85a1fb6ae4c4d1d3bdf74a3584eabdf6039d08 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:45 +0300 Subject: [PATCH 014/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 0ede3d93..b468f1be 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -22,10 +22,10 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { return reviewService.addReview(reviewDto); } -// @PutMapping -// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { -// return reviewService.updateReview(updatedReviewDto); -// } + @PutMapping + public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { + return reviewService.updateReview(updatedReviewDto); + } // // @DeleteMapping("/{id}") // public void deleteReview(@PathVariable long id) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 23705f20..002db3ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -50,7 +50,13 @@ public void remove(final long id) { @Override public void update(final Review review) { - + final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + + "WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), + review.getReviewId()); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); + } } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c84d3780..c5b6e422 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -7,4 +7,6 @@ public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); ReviewDto getReviewById(long id); + + ReviewDto updateReview(ReviewDto updatedReviewDto); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index beb330f4..6aa530d8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -25,9 +25,8 @@ public class ReviewServiceImpl implements ReviewService { @Override public ReviewDto addReview(final ReviewDto reviewDto) { + findUserAndFilmInDb(reviewDto); final Review review = toModel(reviewDto); - userStorage.findById(review.getUserId()); - filmStorage.findById(review.getFilmId()); final Review addedReview = reviewStorage.add(review); log.info("Добавлен новый отзыв: {}.", addedReview); return toDto(reviewStorage.findById(addedReview.getReviewId())); @@ -40,5 +39,20 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { + findUserAndFilmInDb(updatedReviewDto); + final Review updatedReview = toModel(updatedReviewDto); + reviewStorage.update(updatedReview); + final long reviewId = updatedReview.getReviewId(); + log.info("Обновление отзыва с id '{}': {}", reviewId, updatedReview); + return toDto(reviewStorage.findById(reviewId)); + } + + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { + userStorage.findById(updatedReviewDto.getUserId()); + filmStorage.findById(updatedReviewDto.getFilmId()); + } + } From cc725241786cbb28ab70c5eceacc066206e53d92 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 13:18:41 +0300 Subject: [PATCH 015/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 12 ++++++------ .../filmorate/dao/impl/ReviewDbStorage.java | 3 ++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 7 +++++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index b468f1be..920618de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -26,12 +26,12 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { return reviewService.updateReview(updatedReviewDto); } -// -// @DeleteMapping("/{id}") -// public void deleteReview(@PathVariable long id) { -// reviewService.deleteReview(id); -// } -// + + @DeleteMapping("/{id}") + public void deleteReview(@PathVariable long id) { + reviewService.deleteReview(id); + } + @GetMapping("/{id}") public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 002db3ed..9c1c3fa1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -45,7 +45,8 @@ public Review add(final Review review) { @Override public void remove(final long id) { - + final String sql = "DELETE FROM review WHERE id = ?"; + jdbcTemplate.update(sql, id); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c5b6e422..64a2329c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -9,4 +9,6 @@ public interface ReviewService { ReviewDto getReviewById(long id); ReviewDto updateReview(ReviewDto updatedReviewDto); + + void deleteReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6aa530d8..2184e3ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -49,6 +49,13 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + @Override + public void deleteReview(long id) { + reviewStorage.findById(id); + reviewStorage.remove(id); + log.info("Отзыв с id '{}' был удален.", id); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From c64df2d1217197404fb3850a86b7eef495f932e3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:00:49 +0300 Subject: [PATCH 016/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20getReviewsByFilmId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 14 +++++++------- .../practicum/filmorate/dao/ReviewStorage.java | 5 ++++- .../filmorate/dao/impl/ReviewDbStorage.java | 10 +++++++++- .../practicum/filmorate/service/ReviewService.java | 4 ++++ .../filmorate/service/impl/ReviewServiceImpl.java | 14 +++++++++++++- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 920618de..f7571ae9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -36,13 +36,13 @@ public void deleteReview(@PathVariable long id) { public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); } -// -// @GetMapping -// public List getReviewsByFilmId(@RequestParam long filmId, -// @RequestParam(required = false, defaultValue = "10") int count) { -// return reviewService.getReviewsByFilmId(filmId, count); -// } -// + + @GetMapping + public List getReviewsByFilmId(@RequestParam long filmId, + @RequestParam(required = false, defaultValue = "10") int count) { + return reviewService.getReviewsByFilmId(filmId, count); + } + // @PutMapping("/{id}/like/{userId}") // public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { // return reviewService.addLikeToReview(id, userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 441e2b3c..5c198946 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -2,5 +2,8 @@ import ru.yandex.practicum.filmorate.model.Review; -public interface ReviewStorage extends Dao{ +import java.util.List; + +public interface ReviewStorage extends Dao { + List findByFilmIdLimitBy(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 9c1c3fa1..829980fd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -15,6 +15,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import java.util.Objects; @Repository @@ -76,7 +77,7 @@ public Review findById(final long id) { } } - private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) .content(rs.getString("review_content")) @@ -86,4 +87,11 @@ private Review mapReview(ResultSet rs, int rowNum) throws SQLException { .filmId(rs.getLong("film_id")) .build(); } + + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 64a2329c..3ede2c4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -3,6 +3,8 @@ import ru.yandex.practicum.filmorate.dto.ReviewDto; +import java.util.List; + public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); @@ -11,4 +13,6 @@ public interface ReviewService { ReviewDto updateReview(ReviewDto updatedReviewDto); void deleteReview(long id); + + List getReviewsByFilmId(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 2184e3ee..fb25ee4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -7,9 +7,13 @@ import ru.yandex.practicum.filmorate.dao.ReviewStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.service.ReviewService; +import java.util.List; +import java.util.stream.Collectors; + import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; @@ -50,12 +54,20 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { } @Override - public void deleteReview(long id) { + public void deleteReview(final long id) { reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } + @Override + public List getReviewsByFilmId(final long filmId, final int count) { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From aab721a5bc7fb32bb05abb0e47408831c86ca026 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:15:37 +0300 Subject: [PATCH 017/188] =?UTF-8?q?fix:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?useful=20=D0=BF=D1=80=D0=B8=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 829980fd..f47dd04c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -52,10 +52,8 @@ public void remove(final long id) { @Override public void update(final Review review) { - final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + - "WHERE id = ?"; - final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), - review.getReviewId()); + final String sql = "UPDATE review SET review_content = ?, is_positive = ? WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getReviewId()); if (update != 1) { throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); } From 1ea1dc38259ff137263901a6f8313badd7436dcc Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:21 +0300 Subject: [PATCH 018/188] =?UTF-8?q?refactor:=20=D0=97=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C=20filmId=20=D0=BD=D0=B0=20Long?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/ReviewController.java | 2 +- .../ru/yandex/practicum/filmorate/service/ReviewService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index f7571ae9..a9ad48ea 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -38,7 +38,7 @@ public ReviewDto getReviewById(@PathVariable long id) { } @GetMapping - public List getReviewsByFilmId(@RequestParam long filmId, + public List getReviewsByFilmId(@RequestParam(required = false) Long filmId, @RequestParam(required = false, defaultValue = "10") int count) { return reviewService.getReviewsByFilmId(filmId, count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 3ede2c4d..65117fd4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -14,5 +14,5 @@ public interface ReviewService { void deleteReview(long id); - List getReviewsByFilmId(long filmId, int count); + List getReviewsByFilmId(Long filmId, int count); } From 692172204d2b542aa1831cc646bb6ae45879936a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:46 +0300 Subject: [PATCH 019/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20findAllLimitBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 21 ++++++++++++------- .../service/impl/ReviewServiceImpl.java | 16 +++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 5c198946..f7569ae3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -6,4 +6,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); + + List findAllLimitBy(int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index f47dd04c..8e89dac1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -75,6 +75,20 @@ public Review findById(final long id) { } } + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } + + @Override + public List findAllLimitBy(int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, count); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) @@ -85,11 +99,4 @@ private Review mapReview(final ResultSet rs, final int rowNum) throws SQLExcepti .filmId(rs.getLong("film_id")) .build(); } - - @Override - public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; - return jdbcTemplate.query(sql, this::mapReview, filmId, count); - } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index fb25ee4d..6e86573c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -61,11 +61,17 @@ public void deleteReview(final long id) { } @Override - public List getReviewsByFilmId(final long filmId, final int count) { - filmStorage.findById(filmId); - final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); - log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); - return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + public List getReviewsByFilmId(final Long filmId, final int count) { + if (filmId == null) { + final List reviews = reviewStorage.findAllLimitBy(count); + log.info("Запрос на получение отзывов."); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } else { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } } private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { From 5b11817a29338a0536af0ba2ae1a49c8bf319de3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:27:36 +0300 Subject: [PATCH 020/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addLikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../yandex/practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 11 +++++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index a9ad48ea..97e2aede 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -43,10 +43,10 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f return reviewService.getReviewsByFilmId(filmId, count); } -// @PutMapping("/{id}/like/{userId}") -// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addLikeToReview(id, userId); -// } + @PutMapping("/{id}/like/{userId}") + public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addLikeToReview(id, userId); + } // // @PutMapping("/{id}/dislike/{userId}") // public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index f7569ae3..e534405e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -8,4 +8,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); List findAllLimitBy(int count); + + void addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8e89dac1..8091fad2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -83,12 +83,18 @@ public List findByFilmIdLimitBy(final long filmId, final int count) { } @Override - public List findAllLimitBy(int count) { + public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + "FROM REVIEW LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } + @Override + public void addLikeToReview(final long id, final long userId) { + final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 65117fd4..e2ae9acc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -15,4 +15,6 @@ public interface ReviewService { void deleteReview(long id); List getReviewsByFilmId(Long filmId, int count); + + ReviewDto addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6e86573c..57b15d64 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -74,10 +74,17 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + @Override + public ReviewDto addLikeToReview(final long id, final long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); } - - } From 6c411aa9d7cc3fdbb474321b76da92a104d675f3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:29:22 +0300 Subject: [PATCH 021/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D1=80=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D1=82=D0=B7=D1=8B?= =?UTF-8?q?=D0=B2=D1=8B=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B7?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8091fad2..95c160ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -78,14 +78,14 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW LIMIT ?"; + "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From 2fc382a1a8f733eb61eafec1308b9841a76748ef Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:33:16 +0300 Subject: [PATCH 022/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addDislikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 10 +++++----- .../practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 6 ++++++ .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 16 ++++++++++++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 97e2aede..d403d135 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -47,11 +47,11 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addLikeToReview(id, userId); } -// -// @PutMapping("/{id}/dislike/{userId}") -// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addDislikeToReview(id, userId); -// } + + @PutMapping("/{id}/dislike/{userId}") + public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addDislikeToReview(id, userId); + } // // @DeleteMapping("/{id}/like/{userId}") // public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index e534405e..670325b5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -10,4 +10,6 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); void addLikeToReview(long id, long userId); + + void addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 95c160ff..97eeba6a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,6 +95,12 @@ public void addLikeToReview(final long id, final long userId) { jdbcTemplate.update(sql, id); } + @Override + public void addDislikeToReview(long id, long userId) { + final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index e2ae9acc..afdd9099 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -17,4 +17,6 @@ public interface ReviewService { List getReviewsByFilmId(Long filmId, int count); ReviewDto addLikeToReview(long id, long userId); + + ReviewDto addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 57b15d64..4f447606 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -76,13 +76,25 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { - reviewStorage.findById(id); - userStorage.findById(userId); + findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } + @Override + public ReviewDto addDislikeToReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + private void findReviewAndUserInDb(long id, long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From 2592f5b1fe3ff6978c4ee3a5f92d12b497dbeaa7 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:37:08 +0300 Subject: [PATCH 023/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=B4=D0=B8=D0=B7=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 20 +++++++++---------- .../filmorate/service/ReviewService.java | 4 ++++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index d403d135..c8a31fb5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -52,14 +52,14 @@ public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userI public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addDislikeToReview(id, userId); } -// -// @DeleteMapping("/{id}/like/{userId}") -// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteLikeFromReview(id, userId); -// } -// -// @DeleteMapping("/{id}/dislike/{userId}") -// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteDislikeFromReview(id, userId); -// } + + @DeleteMapping("/{id}/like/{userId}") + public ReviewDto deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteLikeFromReview(id, userId); + } + + @DeleteMapping("/{id}/dislike/{userId}") + public ReviewDto deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteDislikeFromReview(id, userId); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index afdd9099..71f1acc7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -19,4 +19,8 @@ public interface ReviewService { ReviewDto addLikeToReview(long id, long userId); ReviewDto addDislikeToReview(long id, long userId); + + ReviewDto deleteLikeFromReview(long id, long userId); + + ReviewDto deleteDislikeFromReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 4f447606..b10e843c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -86,7 +86,23 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); - log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteLikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteDislikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 3047e39095709545a93ec9abde4848e2b786c229 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:09 +0300 Subject: [PATCH 024/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D1=83=20=D0=BF=D0=BE=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 97eeba6a..1929eca8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -61,13 +61,15 @@ public void update(final Review review) { @Override public Collection findAll() { - return null; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id"; + return jdbcTemplate.query(sql, this::mapReview); } @Override public Review findById(final long id) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE ID = ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE id = ?"; try { return jdbcTemplate.queryForObject(sql, this::mapReview, id); } catch (EmptyResultDataAccessException e) { @@ -77,15 +79,15 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE film_id = ? ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From 5f2f5f5d5ce473edb6a37e6df682d7e813c1db31 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:30 +0300 Subject: [PATCH 025/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20ReviewDbStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/ReviewDbStorageTest.java | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java new file mode 100644 index 00000000..015d97e4 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -0,0 +1,305 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmGenreDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.ReviewDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@JdbcTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class ReviewDbStorageTest { + + private final JdbcTemplate jdbcTemplate; + + private ReviewStorage reviewStorage; + private FilmStorage filmStorage; + private UserStorage userStorage; + private Review review1; + private Review review2; + private Review review3; + private Review updatedReview; + private Film film; + private User user; + + @BeforeEach + public void setUp() { + reviewStorage = new ReviewDbStorage(jdbcTemplate); + FilmGenreStorage filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); + filmStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + userStorage = new UserDbStorage(jdbcTemplate); + Mpa mpa = new Mpa(1, "G"); + + film = Film.builder() + .id(1) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + user = User.builder() + .id(1) + .email("email") + .login("login") + .name("name") + .birthday(LocalDate.now()) + .build(); + filmStorage.add(film); + userStorage.add(user); + + + review1 = Review.builder() + .reviewId(1) + .content("review 2") + .isPositive(true) + .useful(1) + .userId(1) + .filmId(1) + .build(); + + review2 = Review.builder() + .reviewId(2) + .content("review 1") + .isPositive(false) + .useful(2) + .userId(1) + .filmId(1) + .build(); + + review3 = Review.builder() + .reviewId(3) + .content("review 3") + .isPositive(true) + .useful(3) + .userId(1) + .filmId(1) + .build(); + + updatedReview = Review.builder() + .reviewId(1) + .content("updated review 1") + .isPositive(true) + .useful(13) + .userId(4) + .filmId(4) + .build(); + } + + @Test + @DisplayName("Тест добавления отзыва и получения по id.") + public void addAndGetByIdTest() { + reviewStorage.add(review1); + + Review savedReview = reviewStorage.findById(1); + + assertThat(savedReview) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест получения всех отзывов (сортировка по полезности).") + public void getAllReviews() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест получения всех отзывов без оценок полезности.") + public void getAllReviewsWithZeroUseful() { + review1.setUseful(0); + review2.setUseful(0); + review3.setUseful(0); + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review1, review2, review3)); + } + + @Test + @DisplayName("Тест получения всех отзывов при пустой базе данных.") + public void getAllReviewsEmptyDb() { + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(2); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2)); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 1); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3)); + } + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест удаления отзыва.") + public void deleteReview() { + reviewStorage.add(review1); + reviewStorage.remove(1); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест обновления отзыва. Обновиться должны только поля content, isPositive.") + public void updateReview() { + reviewStorage.add(review1); + reviewStorage.update(updatedReview); + + Review storedReview = reviewStorage.findById(1); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("content", "isPositive") + .isEqualTo(updatedReview); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("useful", "filmId", "userId") + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест добавления лайка отзыву.") + public void addLikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(2, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления лайка отзыву c отрицательным рейтингом.") + public void addLikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву.") + public void addDislikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву c отрицательным рейтингом.") + public void addDislikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(-2, storedReview.getUseful()); + } + +} \ No newline at end of file From 9d4cecf34a7bfaa865e50b0877255bdd1a5b380c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:45:05 +0300 Subject: [PATCH 026/188] javadoc --- .../service/impl/ReviewServiceImpl.java | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index b10e843c..451cac2f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -26,7 +26,12 @@ public class ReviewServiceImpl implements ReviewService { private final UserStorage userStorage; private final FilmStorage filmStorage; - + /** + * Добавление отзыва в БД. + * + * @param reviewDto отзыв. + * @return отзыв с присвоенным идентификатором. + */ @Override public ReviewDto addReview(final ReviewDto reviewDto) { findUserAndFilmInDb(reviewDto); @@ -36,6 +41,12 @@ public ReviewDto addReview(final ReviewDto reviewDto) { return toDto(reviewStorage.findById(addedReview.getReviewId())); } + /** + * Получение отзыва по идентификатору. + * + * @param id идентификатор отзыва. + * @return найденный отзыв. + */ @Override public ReviewDto getReviewById(final long id) { final Review review = reviewStorage.findById(id); @@ -43,6 +54,12 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + /** + * Обновление данных отзыва. Происходит обновление только полей content и isPositive. + * + * @param updatedReviewDto отзыв с обновленными полями. + * @return обновленный отзыв. + */ @Override public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); @@ -53,6 +70,11 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + /** + * Удаление отзыва из БД. + * + * @param id идентификатор отзыва. + */ @Override public void deleteReview(final long id) { reviewStorage.findById(id); @@ -60,6 +82,13 @@ public void deleteReview(final long id) { log.info("Отзыв с id '{}' был удален.", id); } + /** + * Получение списка отзывов о фильме. Если идентификатор фильма не был передан, то выводится список всех отзывов. + * + * @param filmId идентификатор фильма. + * @param count количество отзывов, которое требуется вывести. По умолчанию 10. + * @return список отзывов. + */ @Override public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { @@ -74,6 +103,13 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + /** + * Добавление лайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит лайк. + * @return отзыв с добавленным лайком. + */ @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); @@ -82,6 +118,13 @@ public ReviewDto addLikeToReview(final long id, final long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Добавление дизлайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит дизлайк. + * @return отзыв с добавленным дизлайком. + */ @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -90,6 +133,13 @@ public ReviewDto addDislikeToReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление лайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет лайк. + * @return отзыв с удаленным лайком. + */ @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -98,6 +148,13 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление дизлайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет дизлайк. + * @return отзыв с удаленным дизлайком. + */ @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); From 69fc1587ebd019aa5cf1bbeefd39469761d9d41f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:46:41 +0300 Subject: [PATCH 027/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20review=5Flike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 5c6180e9..0dd39d0f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -70,4 +70,12 @@ CREATE TABLE IF NOT EXISTS REVIEW( FILM_ID INTEGER NOT NULL, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS REVIEW_LIKE( + REVIEW_ID INTEGER NOT NULL, + USER_ID INTEGER NOT NULL, + LIKE_TYPE CHARACTER VARYING(7) NOT NULL, + FOREIGN KEY (REVIEW_ID) REFERENCES REVIEW(ID) ON DELETE CASCADE, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE +); From 81c47a077c4435d021c72ab1a7be19937a0209fa Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:05 +0300 Subject: [PATCH 028/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java new file mode 100644 index 00000000..01d7ddac --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.dao; + +public interface ReviewLikeStorage { + void add(long reviewId, long userId, String type); + + void delete(long userId, String type); +} From 13955597ad73ec17b71a7e812de2bc7d1b522f0e Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:16 +0300 Subject: [PATCH 029/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/impl/ReviewLikeDbStorage.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java new file mode 100644 index 00000000..36c52158 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewLikeDbStorage implements ReviewLikeStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public void add(final long reviewId, final long userId, final String type) { + final String sql = "INSERT INTO review_like VALUES (?, ?, ?)"; + jdbcTemplate.update(sql, reviewId, userId, type); + } + + @Override + public void delete(final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId); + } +} From 353fcf8d33d414709bccf2f92e89fe86f03b7a23 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:30 +0300 Subject: [PATCH 030/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20enum=20ReviewLike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java new file mode 100644 index 00000000..09b2d9e6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.model; + +public enum ReviewLike { + LIKE("like"), + DISLIKE("dislike"); + + private final String type; + + ReviewLike(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} From d6ce899bd66d8856073753c5e8cdaa79cb41e0dd Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:52 +0300 Subject: [PATCH 031/188] =?UTF-8?q?feat:=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 451cac2f..88564f6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,12 +3,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -25,6 +24,7 @@ public class ReviewServiceImpl implements ReviewService { private final ReviewStorage reviewStorage; private final UserStorage userStorage; private final FilmStorage filmStorage; + private final ReviewLikeStorage reviewLikeStorage; /** * Добавление отзыва в БД. @@ -114,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,6 +130,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -144,6 +146,7 @@ public ReviewDto addDislikeToReview(long id, long userId) { public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -159,6 +162,7 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From f4b5e18db42076eb375de58763d5c5a6e1223c83 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:21 +0300 Subject: [PATCH 032/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D0=BF=D1=80=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 1929eca8..04b42d1a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -47,7 +47,10 @@ public Review add(final Review review) { @Override public void remove(final long id) { final String sql = "DELETE FROM review WHERE id = ?"; - jdbcTemplate.update(sql, id); + int update = jdbcTemplate.update(sql, id); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } } @Override From 6e6813f72fdbc3b092f01b7b8c063d8e4a2ea946 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:56 +0300 Subject: [PATCH 033/188] =?UTF-8?q?refactor:=20=D0=A3=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B8=D0=B7=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2=20userId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 04b42d1a..f57f25a8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,13 +95,13 @@ public List findAllLimitBy(final int count) { } @Override - public void addLikeToReview(final long id, final long userId) { + public void addLikeToReview(final long id) { final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } @Override - public void addDislikeToReview(long id, long userId) { + public void addDislikeToReview(long id) { final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } From 54b39fe00e29436d20f2458ee1c793e4de6b201a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:13:25 +0300 Subject: [PATCH 034/188] =?UTF-8?q?refactor:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java index 09b2d9e6..814fd757 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -1,17 +1,6 @@ package ru.yandex.practicum.filmorate.model; public enum ReviewLike { - LIKE("like"), - DISLIKE("dislike"); - - private final String type; - - ReviewLike(String type) { - this.type = type; - } - - @Override - public String toString() { - return type; - } + LIKE, + DISLIKE; } From d2de9997c74fd71379a466bc459c9977727eeab1 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:01 +0300 Subject: [PATCH 035/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20reviewId=20=D0=B2=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 2 +- .../practicum/filmorate/dao/impl/ReviewLikeDbStorage.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java index 01d7ddac..90d6f0a0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -3,5 +3,5 @@ public interface ReviewLikeStorage { void add(long reviewId, long userId, String type); - void delete(long userId, String type); + void delete(long reviewId, long userId, String type); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java index 36c52158..26cd5a6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -20,8 +20,8 @@ public void add(final long reviewId, final long userId, final String type) { } @Override - public void delete(final long userId, final String type) { - final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; - jdbcTemplate.update(sql, userId); + public void delete(final long reviewId, final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE review_id = ? AND user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId, type); } } From c0a096bf25c780e8b2eb3505ecd5ef8e18e45780 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:35 +0300 Subject: [PATCH 036/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20userId=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 4 ++-- .../service/impl/ReviewServiceImpl.java | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 670325b5..a220dbfe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -9,7 +9,7 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); - void addLikeToReview(long id, long userId); + void addLikeToReview(long id); - void addDislikeToReview(long id, long userId); + void addDislikeToReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 88564f6f..560c8d99 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -15,6 +15,7 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; +import static ru.yandex.practicum.filmorate.model.ReviewLike.*; @Service @RequiredArgsConstructor @@ -61,6 +62,7 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -77,7 +79,6 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { */ @Override public void deleteReview(final long id) { - reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } @@ -113,8 +114,8 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.add(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,8 +130,8 @@ public ReviewDto addLikeToReview(final long id, final long userId) { @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.add(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -145,8 +146,8 @@ public ReviewDto addDislikeToReview(long id, long userId) { @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.delete(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -161,8 +162,8 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.delete(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 0a194d72bb28a521502ad2fa6ea03d18007d3844 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:15:00 +0300 Subject: [PATCH 037/188] =?UTF-8?q?refactor:=20=D0=9F=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D1=8B=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 015d97e4..2168ed14 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From 08f4044ede70ad4806ef960d6439294fa29e0d8a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:16:26 +0300 Subject: [PATCH 038/188] =?UTF-8?q?style:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=B8=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 560c8d99..10decebe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,11 +3,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; -import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -15,7 +17,8 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; -import static ru.yandex.practicum.filmorate.model.ReviewLike.*; +import static ru.yandex.practicum.filmorate.model.ReviewLike.DISLIKE; +import static ru.yandex.practicum.filmorate.model.ReviewLike.LIKE; @Service @RequiredArgsConstructor From de4f098564ba6ad4f1a6844488d6a199b29b6650 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:19:55 +0300 Subject: [PATCH 039/188] checkstyle --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 2168ed14..1224a75c 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From 8efe73524c1c87db96a527b03600923af8084711 Mon Sep 17 00:00:00 2001 From: Elena Date: Wed, 31 Jan 2024 09:40:18 +0400 Subject: [PATCH 040/188] feat: added film recommendations to users controller and tests for this new feature --- .../filmorate/controller/UserController.java | 6 ++ .../practicum/filmorate/dao/UserStorage.java | 3 + .../filmorate/dao/impl/UserDbStorage.java | 40 +++++++++++++ .../filmorate/service/UserService.java | 3 + .../service/impl/UserServiceImpl.java | 8 +++ .../filmorate/storage/FilmDbStorageTest.java | 2 +- .../filmorate/storage/UserDbStorageTest.java | 60 +++++++++++++++++-- 7 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index cc57d70b..6fa88faf 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.dto.FilmDto; import ru.yandex.practicum.filmorate.dto.UserDto; import ru.yandex.practicum.filmorate.service.UserService; @@ -58,4 +59,9 @@ public void removeFriend(@PathVariable long id, @PathVariable long friendId) { userService.removeFriend(id, friendId); } + @GetMapping("/{id}/recommendations") + public Collection showRecommendations(@PathVariable long id) { + return userService.showRecommendations(id); + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java index 1b989bb9..d710fbc7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.dao; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import java.util.Collection; @@ -9,4 +10,6 @@ public interface UserStorage extends Dao { Collection findFriendsByUserId(long userId); Collection findCommonFriends(long userId, long anotherUserId); + + Collection showRecommendations(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java index a9b9d9ef..b5303324 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java @@ -7,8 +7,10 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.User; @@ -24,6 +26,7 @@ public class UserDbStorage implements UserStorage { private final JdbcTemplate jdbcTemplate; + private final FilmStorage filmDbStorage; @Override public User add(final User user) { @@ -109,6 +112,43 @@ public Collection findCommonFriends(final long userId, final long anotherU return jdbcTemplate.query(sql, this::extractToUserList, userId, anotherUserId); } + @Override + public Collection showRecommendations(long id) { + String filmsIdsSql = "SELECT film_id FROM film_like WHERE user_id = ?"; + Set userLikedFilms = Set.copyOf(jdbcTemplate.query(filmsIdsSql, new Object[]{id}, + (rs, rowNum) -> Long.valueOf(rs.getInt("film_id")))); + Collection allUsers = findAll(); + int maxLikes = 0; + + Set recommendations = new HashSet<>(); + + for (User user : allUsers) { + if (user.getId() != id) { + final String idsSql = "SELECT film_id FROM film_like WHERE user_id = ?"; + Set likedFilms = new HashSet<>(Set.copyOf(jdbcTemplate.query(idsSql, new Object[]{user.getId()}, + (rs, rowNum) -> Long.valueOf(rs.getInt("film_id"))))); + Set currentUserLikedFilms = new HashSet<>(userLikedFilms); + currentUserLikedFilms.retainAll(likedFilms); + + if (currentUserLikedFilms.size() > maxLikes) { + if (currentUserLikedFilms.size() < likedFilms.size()) { + recommendations.clear(); + maxLikes = currentUserLikedFilms.size(); + likedFilms.removeAll(currentUserLikedFilms); + recommendations.addAll(likedFilms); + } + } else if (currentUserLikedFilms.size() == maxLikes) { + likedFilms.removeAll(currentUserLikedFilms); + recommendations.addAll(likedFilms); + } + } + } + Collection filmsRecommendation = new ArrayList<>(); + for (Long filmId : recommendations) { + filmsRecommendation.add(filmDbStorage.findById(filmId)); + } + return filmsRecommendation; + } private User extractToUser(ResultSet rs) throws SQLException, DataAccessException { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 3c172db2..094a0491 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.service; +import ru.yandex.practicum.filmorate.dto.FilmDto; import ru.yandex.practicum.filmorate.dto.UserDto; import java.util.Collection; @@ -21,4 +22,6 @@ public interface UserService { Collection findCommonFriends(long userId, long otherUserId); void removeFriend(long userId, long friendId); + + Collection showRecommendations(long id); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index c5abaae8..38ddccd8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -5,7 +5,9 @@ import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.dao.FriendshipStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dto.FilmDto; import ru.yandex.practicum.filmorate.dto.UserDto; +import ru.yandex.practicum.filmorate.mapper.FilmMapper; import ru.yandex.practicum.filmorate.mapper.UserMapper; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.User; @@ -151,6 +153,12 @@ public void removeFriend(final long userId, final long friendId) { log.info("Пользователи с id {} и {} перестали быть друзьями", userId, friendId); } + @Override + public Collection showRecommendations(long id) { + log.info("Получение списка рекомендаций фильмов для пользователя с id {}.", id); + return userStorage.showRecommendations(id).stream().map(FilmMapper::toDto).collect(Collectors.toList()); + } + private UserDto validateUserName(final UserDto userDto) { final String validatedName = userDto.getName() == null || userDto.getName().isBlank() ? userDto.getLogin() : userDto.getName(); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 846692ea..dc0b4f96 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -50,7 +50,7 @@ public void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); - userStorage = new UserDbStorage(jdbcTemplate); + userStorage = new UserDbStorage(jdbcTemplate, filmDbStorage); Mpa mpa = new Mpa(1, "G"); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 5b506415..441f3d86 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -8,12 +8,12 @@ import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.annotation.DirtiesContext; -import ru.yandex.practicum.filmorate.dao.FriendshipStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; -import ru.yandex.practicum.filmorate.dao.impl.FriendshipDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; +import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.model.User; import java.time.LocalDate; @@ -35,6 +35,9 @@ class UserDbStorageTest { private final JdbcTemplate jdbcTemplate; private UserStorage userStorage; private FriendshipStorage friendshipStorage; + private FilmGenreStorage filmGenreStorage; + private FilmLikeStorage filmLikeStorage; + private FilmStorage filmDbStorage; private User user; private User updatedUser; private User anotherUser; @@ -42,7 +45,10 @@ class UserDbStorageTest { @BeforeEach void setUp() { - userStorage = new UserDbStorage(jdbcTemplate); + filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); + filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); + filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + userStorage = new UserDbStorage(jdbcTemplate, filmDbStorage); friendshipStorage = new FriendshipDbStorage(jdbcTemplate); user = User.builder() .id(1) @@ -314,4 +320,48 @@ void testGetEmptyFriendsList() { .isNotNull() .isEmpty(); } + + @Test + @DisplayName("Тест получения списка рекомендаций фильмов") + void testGetRecommendationsList() { + userStorage.add(user); + userStorage.add(anotherUser); + + Mpa mpa = new Mpa(1, "G"); + + + Film filmOne = Film.builder() + .id(1) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + Film filmTwo = Film.builder() + .id(2) + .name("film two") + .description("film two description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + filmDbStorage.add(filmOne); + filmDbStorage.add(filmTwo); + + filmLikeStorage.add(filmOne.getId(), user.getId()); + filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); + filmLikeStorage.add(filmTwo.getId(), anotherUser.getId()); + + Collection filmRecommendations = userStorage.showRecommendations(user.getId()); + + filmTwo.setLikes(1); + + assertThat(filmRecommendations) + .isNotNull() + .isNotEmpty() + .containsExactlyElementsOf(List.of(filmTwo)); + } } \ No newline at end of file From 59f1783b5b9adfd7be9e8d7fd1749281f30d47f5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 08:55:59 +0300 Subject: [PATCH 041/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Transactional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 10decebe..f2d08926 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,10 +3,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import org.springframework.transaction.annotation.Transactional; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; @@ -65,7 +63,6 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override - public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -81,6 +78,7 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { * @param id идентификатор отзыва. */ @Override + @Transactional public void deleteReview(final long id) { reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); @@ -94,6 +92,7 @@ public void deleteReview(final long id) { * @return список отзывов. */ @Override + @Transactional public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { final List reviews = reviewStorage.findAllLimitBy(count); @@ -115,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { * @return отзыв с добавленным лайком. */ @Override + @Transactional public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); @@ -131,6 +131,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { * @return отзыв с добавленным дизлайком. */ @Override + @Transactional public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -142,11 +143,12 @@ public ReviewDto addDislikeToReview(long id, long userId) { /** * Удаление лайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет лайк. * @return отзыв с удаленным лайком. */ @Override + @Transactional public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -158,11 +160,12 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { /** * Удаление дизлайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет дизлайк. * @return отзыв с удаленным дизлайком. */ @Override + @Transactional public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); From 8e15aa2dc130e4c53b26b4a04a8740c6bebcec7a Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 08:24:50 +0100 Subject: [PATCH 042/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=89=D0=B8=D1=85=20=D1=81=20=D0=B4=D1=80=D1=83?= =?UTF-8?q?=D0=B3=D0=BE=D0=BC=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=81=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=20=D0=BF=D0=BE=20=D0=B8=D1=85=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BF=D1=83=D0=BB=D1=8F=D1=80=D0=BD=D0=BE=D1=81=D1=82=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен новый метод getCommonFilms в класс FilmServiceImpl и соответствующий обработчик запросов в FilmController для вывода списка общих фильмов двух пользователей с сортировкой по популярности. Основные моменты изменений: 1. В FilmServiceImpl реализован метод getCommonFilms, который: - Использует filmLikeStorage.findLikedFilmsByUser для получения фильмов, лайкнутых каждым из пользователей. - Находит пересечение этих списков для определения общих фильмов. - Сортирует общие фильмы по количеству лайков с помощью Comparator.comparingLong(FilmDto::getLikes).reversed(). 2. В FilmController добавлен обработчик GET-запросов на путь '/common', принимающий параметры userId и friendId. --- .../filmorate/controller/FilmController.java | 8 +++++ .../filmorate/dao/FilmLikeStorage.java | 4 +++ .../filmorate/dao/impl/FilmLikeDbStorage.java | 8 +++++ .../filmorate/service/FilmService.java | 2 ++ .../service/impl/FilmServiceImpl.java | 29 +++++++++++++++++-- 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index e813df7b..f05f7b9c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -48,6 +48,14 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { return filmService.removeLike(id, userId); } + @GetMapping("/common") + public Collection getCommonFilms( + @RequestParam long userId, + @RequestParam long friendId){ + return filmService.getCommonFilms(userId, friendId); + + } + @GetMapping("/popular") public Collection getMostPopularFilms(@RequestParam(required = false, defaultValue = "10") int count) { return filmService.getMostPopularFilms(count); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java index 2e8202e1..94a5bbf4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao; import java.util.Map; +import java.util.Set; public interface FilmLikeStorage { void add(long filmId, long userId); @@ -10,4 +11,7 @@ public interface FilmLikeStorage { Map findAll(); void remove(long filmId, long userId); + + Set findLikedFilmsByUser(long userId); + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 07d0a770..316fc562 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -9,8 +9,10 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; @Repository @RequiredArgsConstructor @@ -49,6 +51,12 @@ public void remove(long filmId, long userId) { jdbcTemplate.update(sql, filmId, userId); } + @Override + public Set findLikedFilmsByUser(long userId) { + final String sql = "SELECT film_id FROM film_like WHERE user_id = ?"; + return new HashSet<>(jdbcTemplate.queryForList(sql, Long.class, userId)); + } + private Map mapRowToIdCount(ResultSet rs) throws SQLException { final Map result = new LinkedHashMap<>(); while (rs.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index c4724356..29f13aa8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -18,4 +18,6 @@ public interface FilmService { FilmDto removeLike(long filmId, long userId); Collection getMostPopularFilms(final int count); + + Collection getCommonFilms(long userId, long friendId); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 028192ee..8904d987 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -11,8 +11,7 @@ import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.service.FilmService; -import java.util.ArrayList; -import java.util.Collection; +import java.util.*; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.mapper.FilmMapper.toDto; @@ -125,4 +124,30 @@ public FilmDto removeLike(final long filmId, final long userId) { public Collection getMostPopularFilms(final int count) { return filmStorage.findMostLikedFilmsLimitBy(count).stream().map(FilmMapper::toDto).collect(Collectors.toList()); } + + /** + * Получение списка общих понравившихся фильмов между двумя пользователями. + * Метод ищет фильмы, которые нравятся обоим пользователям, и возвращает их + * в порядке убывания популярности, определяемой количеством лайков. + * + * @param userId идентификатор первого пользователя. + * @param friendId идентификатор второго пользователя. + * @return список фильмов, которые нравятся обоим пользователям, упорядоченный + * по убыванию популярности. + */ + @Override + public Collection getCommonFilms(long userId, long friendId) { + + Set userFilms = filmLikeStorage.findLikedFilmsByUser(userId); + Set friendFilms = filmLikeStorage.findLikedFilmsByUser(friendId); + + userFilms.retainAll(friendFilms); + + return userFilms.stream() + .map(filmId -> filmStorage.findById(filmId)) + .filter(Objects::nonNull) + .map(FilmMapper::toDto) + .sorted(Comparator.comparingLong(FilmDto::getLikes).reversed()) + .collect(Collectors.toList()); + } } \ No newline at end of file From 196e6fac7543cb66bbbbc42d028ed14804e6cfdd Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 08:32:30 +0100 Subject: [PATCH 043/188] checkstyle --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index f05f7b9c..f19aebe8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -51,7 +51,7 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { @GetMapping("/common") public Collection getCommonFilms( @RequestParam long userId, - @RequestParam long friendId){ + @RequestParam long friendId) { return filmService.getCommonFilms(userId, friendId); } From 55226c2ff2e072502144c50e35645c98835bdf78 Mon Sep 17 00:00:00 2001 From: Elena Date: Wed, 31 Jan 2024 16:09:59 +0400 Subject: [PATCH 044/188] fix: refractored methods to move business logic into UserService --- .../practicum/filmorate/dao/UserStorage.java | 5 +- .../filmorate/dao/impl/UserDbStorage.java | 54 ++++-------- .../service/impl/UserServiceImpl.java | 43 ++++++++- .../filmorate/storage/UserDbStorageTest.java | 88 ++++++++++++++----- 4 files changed, 127 insertions(+), 63 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java index d710fbc7..0f94cb99 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java @@ -1,9 +1,10 @@ package ru.yandex.practicum.filmorate.dao; -import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import java.util.Collection; +import java.util.Map; +import java.util.Set; public interface UserStorage extends Dao { @@ -11,5 +12,5 @@ public interface UserStorage extends Dao { Collection findCommonFriends(long userId, long anotherUserId); - Collection showRecommendations(long id); + Map> showRecommendations(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java index b5303324..ca8e75a8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java @@ -10,10 +10,8 @@ import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.User; - import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -113,41 +111,27 @@ public Collection findCommonFriends(final long userId, final long anotherU } @Override - public Collection showRecommendations(long id) { - String filmsIdsSql = "SELECT film_id FROM film_like WHERE user_id = ?"; - Set userLikedFilms = Set.copyOf(jdbcTemplate.query(filmsIdsSql, new Object[]{id}, - (rs, rowNum) -> Long.valueOf(rs.getInt("film_id")))); - Collection allUsers = findAll(); - int maxLikes = 0; - - Set recommendations = new HashSet<>(); - - for (User user : allUsers) { - if (user.getId() != id) { - final String idsSql = "SELECT film_id FROM film_like WHERE user_id = ?"; - Set likedFilms = new HashSet<>(Set.copyOf(jdbcTemplate.query(idsSql, new Object[]{user.getId()}, - (rs, rowNum) -> Long.valueOf(rs.getInt("film_id"))))); - Set currentUserLikedFilms = new HashSet<>(userLikedFilms); - currentUserLikedFilms.retainAll(likedFilms); - - if (currentUserLikedFilms.size() > maxLikes) { - if (currentUserLikedFilms.size() < likedFilms.size()) { - recommendations.clear(); - maxLikes = currentUserLikedFilms.size(); - likedFilms.removeAll(currentUserLikedFilms); - recommendations.addAll(likedFilms); - } - } else if (currentUserLikedFilms.size() == maxLikes) { - likedFilms.removeAll(currentUserLikedFilms); - recommendations.addAll(likedFilms); - } + public Map> showRecommendations() { + String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; + List> userLikedFilms = jdbcTemplate.query(filmsIdsSql, (resultSet, rowNum) -> { + List likes = new ArrayList<>(); + likes.add(resultSet.getLong("user_id")); + likes.add(resultSet.getLong("film_id")); + return likes; + }); + Map> result = new HashMap<>(); + for (List userLikes : userLikedFilms) { + if (result.get(userLikes.get(0)) == null) { + Set films = new HashSet<>(); + films.add((Long) userLikes.get(1)); + result.put((Long) userLikes.get(0), films); + } else { + Set films = result.get(userLikes.get(0)); + films.add((Long) userLikes.get(1)); + result.put((Long) userLikes.get(0), films); } } - Collection filmsRecommendation = new ArrayList<>(); - for (Long filmId : recommendations) { - filmsRecommendation.add(filmDbStorage.findById(filmId)); - } - return filmsRecommendation; + return result; } private User extractToUser(ResultSet rs) throws SQLException, DataAccessException { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index 38ddccd8..ca2f0c78 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -3,18 +3,19 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.FriendshipStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.FilmDto; import ru.yandex.practicum.filmorate.dto.UserDto; import ru.yandex.practicum.filmorate.mapper.FilmMapper; import ru.yandex.practicum.filmorate.mapper.UserMapper; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserService; -import java.util.ArrayList; -import java.util.Collection; +import java.util.*; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.model.FriendshipStatus.ACKNOWLEDGED; @@ -26,6 +27,7 @@ public class UserServiceImpl implements UserService { private final UserStorage userStorage; + private final FilmStorage filmDbStorage; private final FriendshipStorage friendshipStorage; @@ -153,10 +155,45 @@ public void removeFriend(final long userId, final long friendId) { log.info("Пользователи с id {} и {} перестали быть друзьями", userId, friendId); } + /** + * Создание рекомендаций пользователю фильмов, которые ему могут понравиться. Для подготовки рекомендаций + * выгружаем данные из таблицы film_like, находим пользователей с максимальным количеством одинаковых с нашим + * пользователем лайков и выбираем у них для рекомендации, которые они тоже залайкали, но наш пользователь + * в запросе их еще не видел + * + * @param id идентификатор пользователя + * @return коллекцию FilmDto + */ + @Override public Collection showRecommendations(long id) { log.info("Получение списка рекомендаций фильмов для пользователя с id {}.", id); - return userStorage.showRecommendations(id).stream().map(FilmMapper::toDto).collect(Collectors.toList()); + + Map> usersLikes = userStorage.showRecommendations(); + int maxLikes = 0; + Set recommendations = new HashSet<>(); + Set userLikedFilms = usersLikes.get(id); + for (Long user : usersLikes.keySet()) { + if (user != id) { + Set likedFilms = usersLikes.get(user); + Set currentUserLikedFilms = new HashSet<>(userLikedFilms); + currentUserLikedFilms.retainAll(likedFilms); + if (currentUserLikedFilms.size() > maxLikes && currentUserLikedFilms.size() < likedFilms.size()) { + recommendations.clear(); + maxLikes = currentUserLikedFilms.size(); + likedFilms.removeAll(currentUserLikedFilms); + recommendations.addAll(likedFilms); + } else if (currentUserLikedFilms.size() == maxLikes) { + likedFilms.removeAll(currentUserLikedFilms); + recommendations.addAll(likedFilms); + } + } + } + Collection filmsRecommendation = new ArrayList<>(); + for (Long filmId : recommendations) { + filmsRecommendation.add(filmDbStorage.findById(filmId)); + } + return filmsRecommendation.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } private UserDto validateUserName(final UserDto userDto) { diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 441f3d86..ade1b589 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -11,14 +11,17 @@ import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.mapper.FilmMapper; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.impl.UserServiceImpl; import java.time.LocalDate; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -34,6 +37,7 @@ class UserDbStorageTest { private final JdbcTemplate jdbcTemplate; private UserStorage userStorage; + private UserServiceImpl userService; private FriendshipStorage friendshipStorage; private FilmGenreStorage filmGenreStorage; private FilmLikeStorage filmLikeStorage; @@ -41,6 +45,8 @@ class UserDbStorageTest { private User user; private User updatedUser; private User anotherUser; + private Film filmOne; + private Film filmTwo; @BeforeEach @@ -50,6 +56,7 @@ void setUp() { filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); userStorage = new UserDbStorage(jdbcTemplate, filmDbStorage); friendshipStorage = new FriendshipDbStorage(jdbcTemplate); + userService = new UserServiceImpl(userStorage, filmDbStorage, friendshipStorage); user = User.builder() .id(1) .email("email") @@ -71,6 +78,26 @@ void setUp() { .name("another_name") .birthday(LocalDate.now()) .build(); + + Mpa mpa = new Mpa(1, "G"); + + filmOne = Film.builder() + .id(1) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + filmTwo = Film.builder() + .id(2) + .name("film two") + .description("film two description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); } @Test @@ -322,32 +349,11 @@ void testGetEmptyFriendsList() { } @Test - @DisplayName("Тест получения списка рекомендаций фильмов") + @DisplayName("Тест получения списка рекомендаций фильмов, когда рекомендации есть.") void testGetRecommendationsList() { userStorage.add(user); userStorage.add(anotherUser); - Mpa mpa = new Mpa(1, "G"); - - - Film filmOne = Film.builder() - .id(1) - .name("film") - .description("film description") - .releaseDate(LocalDate.of(2020, 12, 12)) - .duration(123) - .mpa(mpa) - .build(); - - Film filmTwo = Film.builder() - .id(2) - .name("film two") - .description("film two description") - .releaseDate(LocalDate.of(2020, 12, 12)) - .duration(123) - .mpa(mpa) - .build(); - filmDbStorage.add(filmOne); filmDbStorage.add(filmTwo); @@ -355,7 +361,8 @@ void testGetRecommendationsList() { filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); filmLikeStorage.add(filmTwo.getId(), anotherUser.getId()); - Collection filmRecommendations = userStorage.showRecommendations(user.getId()); + Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() + .map(FilmMapper::toModel).collect(Collectors.toList()); filmTwo.setLikes(1); @@ -364,4 +371,39 @@ void testGetRecommendationsList() { .isNotEmpty() .containsExactlyElementsOf(List.of(filmTwo)); } + + @Test + @DisplayName("Тест получения списка рекомендаций фильмов, когда лайки совпадают.") + void testGetRecommendationsListSimilarLikes() { + userStorage.add(user); + userStorage.add(anotherUser); + + filmDbStorage.add(filmOne); + + filmLikeStorage.add(filmOne.getId(), user.getId()); + filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); + + Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() + .map(FilmMapper::toModel).collect(Collectors.toList()); + + assertThat(filmRecommendations) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест получения списка рекомендаций фильмов, когда лайков еще нет.") + void testGetRecommendationsListNoLikes() { + userStorage.add(user); + userStorage.add(anotherUser); + + filmDbStorage.add(filmOne); + + Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() + .map(FilmMapper::toModel).collect(Collectors.toList()); + + assertThat(filmRecommendations) + .isNotNull() + .isEmpty(); + } } \ No newline at end of file From 1cf30fd93b2fb78a6d8c462944bfd01cd630100f Mon Sep 17 00:00:00 2001 From: Ayzat Murtazin Date: Wed, 31 Jan 2024 16:46:23 +0300 Subject: [PATCH 045/188] =?UTF-8?q?feat:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 ++- .../filmorate/controller/FilmController.java | 5 +++++ .../filmorate/controller/UserController.java | 5 +++++ .../filmorate/dao/impl/FilmDbStorage.java | 6 ++++-- .../filmorate/dao/impl/FilmLikeDbStorage.java | 1 + .../filmorate/service/FilmService.java | 2 ++ .../filmorate/service/UserService.java | 2 ++ .../service/impl/FilmServiceImpl.java | 12 +++++++++++ .../service/impl/UserServiceImpl.java | 10 ++++++++++ src/main/resources/schema.sql | 6 +++--- .../filmorate/storage/FilmDbStorageTest.java | 20 +++++++++++++++++++ .../filmorate/storage/UserDbStorageTest.java | 20 +++++++++++++++++++ 12 files changed, 86 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c0f548b6..dae45abc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.14 + 2.7.17 ru.yandex.practicum @@ -54,6 +54,7 @@ com.h2database h2 + 2.2.220 runtime diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index e813df7b..e1066545 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -52,5 +52,10 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { public Collection getMostPopularFilms(@RequestParam(required = false, defaultValue = "10") int count) { return filmService.getMostPopularFilms(count); } + + @DeleteMapping("/{id}") + public void removeFilm(@PathVariable long id) { + filmService.removeFilm(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index cc57d70b..eb1285d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -58,4 +58,9 @@ public void removeFriend(@PathVariable long id, @PathVariable long friendId) { userService.removeFriend(id, friendId); } + @DeleteMapping("/{id}") + public void removeUser(@PathVariable long id) { + userService.removeUser(id); + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 976544b8..89a86370 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -53,7 +53,10 @@ public Film add(final Film film) { @Override public void remove(final long id) { final String sql = "DELETE FROM film WHERE id = ?"; - jdbcTemplate.update(sql, id); + int amount = jdbcTemplate.update(sql, id); + if (amount != 1) { + throw new NotFoundException("Фильм с id '" + id + "' не найден."); + } } @Override @@ -66,7 +69,6 @@ public void update(final Film film) { } filmGenreStorage.deleteAllById(film.getId()); - filmGenreStorage.batchUpdate(film.getId(), film.getGenres()); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 07d0a770..7b2707e5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -49,6 +49,7 @@ public void remove(long filmId, long userId) { jdbcTemplate.update(sql, filmId, userId); } + private Map mapRowToIdCount(ResultSet rs) throws SQLException { final Map result = new LinkedHashMap<>(); while (rs.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index c4724356..88ea93e9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -17,5 +17,7 @@ public interface FilmService { FilmDto removeLike(long filmId, long userId); + void removeFilm(long filmId); + Collection getMostPopularFilms(final int count); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 3c172db2..3a4475f5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -21,4 +21,6 @@ public interface UserService { Collection findCommonFriends(long userId, long otherUserId); void removeFriend(long userId, long friendId); + + void removeUser(long userId); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 028192ee..cd11f346 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import ru.yandex.practicum.filmorate.dao.FilmLikeStorage; import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; @@ -114,6 +115,17 @@ public FilmDto removeLike(final long filmId, final long userId) { return toDto(filmStorage.findById(filmId)); } + /** + * Удаление фильма. + * + * @param filmId идентификатор фильма, который будет удален + */ + @Override + @Transactional + public void removeFilm(long filmId) { + filmStorage.remove(filmId); + } + /** * Получение списка самых популярных фильмов. Под популярностью понимается количество лайков у фильма. Чем больше * лайков, тем популярнее фильм. diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index c5abaae8..482bd1c3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -151,6 +151,16 @@ public void removeFriend(final long userId, final long friendId) { log.info("Пользователи с id {} и {} перестали быть друзьями", userId, friendId); } + /** + * Удаление пользователя. + * + * @param userId идентификатор пользователя, который будет удален + */ + @Override + public void removeUser(long userId) { + userStorage.remove(userId); + } + private UserDto validateUserName(final UserDto userDto) { final String validatedName = userDto.getName() == null || userDto.getName().isBlank() ? userDto.getLogin() : userDto.getName(); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0dd39d0f..a2cd383f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; +-- DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS FILM_GENRE( FILM_ID INTEGER NOT NULL, GENRE_ID INTEGER NOT NULL, CONSTRAINT pk_film_genre PRIMARY KEY (FILM_ID, GENRE_ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE, FOREIGN KEY (GENRE_ID) REFERENCES GENRE(ID) ); @@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS FILM_LIKE( FILM_ID INTEGER NOT NULL, USER_ID INTEGER NOT NULL, CONSTRAINT pk_film_like PRIMARY KEY (FILM_ID, USER_ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 846692ea..6ef7b22b 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -286,4 +286,24 @@ void testFindByIdWithAllFields() { .usingRecursiveComparison() .isEqualTo(film); } + + @Test + @DisplayName("Тест удаление фильма") + void testDeleteFilm() { + Film newFilm = filmDbStorage.add(film); + filmDbStorage.remove(newFilm.getId()); + + String formattedResponse = String.format("Фильм с id '%s' не найден.", newFilm.getId()); + NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.findById(newFilm.getId())); + assertEquals(formattedResponse, e.getMessage()); + } + + @Test + @DisplayName("Тест удаление несуществующего фильма") + void testDeleteNotExistingUser() { + int filmId = 999; + String formattedResponse = String.format("Фильм с id '%s' не найден.", filmId); + NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.findById(filmId)); + assertEquals(formattedResponse, e.getMessage()); + } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 5b506415..dd3cb6ec 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -314,4 +314,24 @@ void testGetEmptyFriendsList() { .isNotNull() .isEmpty(); } + + @Test + @DisplayName("Тест удаление пользователя") + void testDeleteUser() { + User newUser = userStorage.add(user); + userStorage.remove(newUser.getId()); + + String formattedResponse = String.format("Пользователь с id '%s' не найден.", newUser.getId()); + NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.findById(newUser.getId())); + assertEquals(formattedResponse, e.getMessage()); + } + + @Test + @DisplayName("Тест удаление несуществующего пользователя") + void testDeleteNotExistingUser() { + int userId = 999; + String formattedResponse = String.format("Пользователь с id '%s' не найден.", userId); + NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.findById(userId)); + assertEquals(formattedResponse, e.getMessage()); + } } \ No newline at end of file From eb17e6293d93aa3940b4cf68a1c797c4ec9c9bd1 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:42:58 +0300 Subject: [PATCH 046/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20findGenre?= =?UTF-8?q?sInIdList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/FilmGenreStorage.java | 4 +++ .../dao/impl/FilmGenreDbStorage.java | 28 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java index 98f6be09..9d7228bc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java @@ -3,12 +3,16 @@ import ru.yandex.practicum.filmorate.model.Genre; import java.util.List; +import java.util.Map; +import java.util.Set; public interface FilmGenreStorage { void add(long filmId, long genreId); List findAllById(long filmId); + Map> findGenresInIdList(Set filmIds); + void deleteAllById(long filmId); void batchUpdate(long filmId, List genres); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java index ec9e1b2e..5f247333 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao.impl; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -10,7 +11,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.List; +import java.util.*; @Repository @RequiredArgsConstructor @@ -31,6 +32,16 @@ public List findAllById(final long filmId) { return jdbcTemplate.query(sql, this::mapRowToLong, filmId); } + @Override + public Map> findGenresInIdList(Set filmIds) { + final String ids = String.join(",", Collections.nCopies(filmIds.size(), "?")); + final String sql = String.format( + "SELECT fg.film_id, fg.genre_id, g.genre_name FROM film_genre fg JOIN genre g ON fg.genre_id = g.id" + + " WHERE fg.film_id IN (%s)", ids); + + return jdbcTemplate.query(sql, this::extractToMap, filmIds.toArray()); + } + @Override public void deleteAllById(final long filmId) { final String sql = "DELETE FROM film_genre WHERE film_id = ?"; @@ -57,4 +68,19 @@ public int getBatchSize() { private Genre mapRowToLong(ResultSet rs, int rowNum) throws SQLException { return new Genre(rs.getInt("genre_id"), rs.getString("genre_name")); } + + private Map> extractToMap(ResultSet rs) throws SQLException, DataAccessException { + final Map> filmIdGenreMap = new HashMap<>(); + while (rs.next()) { + final Long filmId = rs.getLong(1); + List genres = filmIdGenreMap.get(filmId); + if (genres == null) { + genres = new ArrayList<>(); + } + final Genre genre = new Genre(rs.getInt("genre_id"), rs.getString("genre_name")); + genres.add(genre); + filmIdGenreMap.put(filmId, genres); + } + return filmIdGenreMap; + } } From 722ea422d20e5c210a5a07b3b08e019d62ae19b1 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:45:11 +0300 Subject: [PATCH 047/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20extractToFilmListWithoutGenres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 99 +++++++++---------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 976544b8..53406c73 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -19,6 +19,9 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; +import java.util.stream.Collectors; + +import static java.util.function.Function.identity; @Repository @RequiredArgsConstructor @@ -126,32 +129,8 @@ private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessExceptio final Map filmIdMap = new HashMap<>(); while (rs.next()) { - - Long filmId = rs.getLong(1); - film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } - - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - continue; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); + film = resultSetToFilm(rs, filmIdMap); + setGenresToFilm(rs, film); } return film; @@ -162,34 +141,52 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException, Da final Map filmIdMap = new LinkedHashMap<>(); while (rs.next()) { + Film film = resultSetToFilm(rs, filmIdMap); + setGenresToFilm(rs, film); + } + + return filmIdMap.values(); + } - Long filmId = rs.getLong(1); - Film film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } - - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - continue; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); + private void setGenresToFilm(ResultSet rs, Film film) throws SQLException { + final int genre_id = rs.getInt("genre_id"); + if (genre_id == 0) { + film.getGenres().addAll(Collections.emptyList()); + return; + } + + final Genre genre = new Genre(); + genre.setId(genre_id); + genre.setName(rs.getString("genre_name")); + film.getGenres().add(genre); + } + + private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { + + final Map filmIdMap = new LinkedHashMap<>(); + + while (rs.next()) { + resultSetToFilm(rs, filmIdMap); } return filmIdMap.values(); } + + private Film resultSetToFilm(ResultSet rs, Map filmIdMap) throws SQLException { + Long filmId = rs.getLong(1); + Film film = filmIdMap.get(filmId); + if (film == null) { + film = Film.builder() + .id(filmId) + .name(rs.getString("title")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) + .build(); + film.setLikes(rs.getLong("likes")); + filmIdMap.put(filmId, film); + } + return film; + } } From dcc6e717c2607efd2d434f38ca8e12d70326b2f7 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:45:42 +0300 Subject: [PATCH 048/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20findMostLikedFilmsLimitBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/FilmDbStorage.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 53406c73..6d4ab93d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -110,17 +110,19 @@ public Film findById(final long filmId) { public Collection findMostLikedFilmsLimitBy(final int count) { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + + "GROUP BY f.id, m.rating_name " + "ORDER BY COUNT(fl.USER_ID) DESC " + "LIMIT ?"; - return jdbcTemplate.query(sql, this::extractToFilmList, count); + Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); + Map> filmIdGenreMap = filmGenreStorage.findGenresInIdList(filmMap.keySet()); + filmIdGenreMap.forEach((id, genres) -> filmMap.get(id).getGenres().addAll(genres)); + return new ArrayList<>(filmMap.values()); } private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessException { From 1d5a347ca977bd0321cac791c6f9444596738ab5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:29:45 +0300 Subject: [PATCH 049/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20LinkedHashSe?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java | 5 ++--- src/main/java/ru/yandex/practicum/filmorate/model/Film.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java index d0be3ce7..ef3586f6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java @@ -13,8 +13,7 @@ import javax.validation.constraints.Positive; import javax.validation.constraints.Size; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; @Data @AllArgsConstructor @@ -31,6 +30,6 @@ public class FilmDto { @Positive(message = "Продолжительность должна быть больше нуля") private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг - private final List genres = new ArrayList<>(); //жанры + private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры private long likes; //количество лайков от пользователей } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 84932083..8d8afe8d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -7,8 +7,7 @@ import lombok.NoArgsConstructor; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; @Data @AllArgsConstructor @@ -21,6 +20,6 @@ public class Film { private LocalDate releaseDate; //дата релиза private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг - private final List genres = new ArrayList<>(); //жанры + private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры private long likes; //количество лайков от пользователей } From 2cd09446baf36ede893ca61c141022c7f24bfafd Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:30:23 +0300 Subject: [PATCH 050/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=B0=20Set=20=D0=B2=D0=BC?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=20List?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/FilmGenreStorage.java | 2 +- .../practicum/filmorate/dao/impl/FilmGenreDbStorage.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java index 9d7228bc..109292ab 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java @@ -15,5 +15,5 @@ public interface FilmGenreStorage { void deleteAllById(long filmId); - void batchUpdate(long filmId, List genres); + void batchUpdate(long filmId, Set genres); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java index 5f247333..e9c49b0f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java @@ -49,13 +49,14 @@ public void deleteAllById(final long filmId) { } @Override - public void batchUpdate(final long filmId, final List genres) { - final String sql = "MERGE INTO film_genre (film_id, genre_id) VALUES (?, ?)"; + public void batchUpdate(final long filmId, final Set genres) { + final List genreList = new ArrayList<>(genres); + final String sql = "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)"; jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setLong(1, filmId); - ps.setLong(2, genres.get(i).getId()); + ps.setLong(2, genreList.get(i).getId()); } @Override From 98a3d206dc14f3acd4c7c287bcc7003358383d9f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:32:08 +0300 Subject: [PATCH 051/188] =?UTF-8?q?refactor:=20=D0=9C=D0=B0=D0=BF=D0=BF?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B6=D0=B0=D0=BD=D1=80=D1=8B=20=D0=BE?= =?UTF-8?q?=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=BC=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 47 +++++-------------- .../filmorate/storage/FilmDbStorageTest.java | 25 ++++++++++ 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 6d4ab93d..aa17a600 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -76,16 +76,14 @@ public void update(final Film film) { @Override public Collection findAll() { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name"; - - return jdbcTemplate.query(sql, this::extractToFilmList); + "GROUP BY f.id, m.rating_name"; + Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres); + return setGenresForFilms(films); } @Override @@ -100,11 +98,14 @@ public Film findById(final long filmId) { "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + "HAVING f.ID = ?"; - final Film film = jdbcTemplate.query(sql, this::extractToFilm, filmId); + final Film film = jdbcTemplate.query(sql, this::extractToFilmWithoutGenres, filmId); if (film == null) { throw new NotFoundException("Фильм с id '" + filmId + "' не найден."); } + + List genres = filmGenreStorage.findAllById(filmId); + film.getGenres().addAll(genres); return film; } @@ -119,50 +120,28 @@ public Collection findMostLikedFilmsLimitBy(final int count) { "LIMIT ?"; Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + return setGenresForFilms(films); + } + + private List setGenresForFilms(Collection films) { Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); Map> filmIdGenreMap = filmGenreStorage.findGenresInIdList(filmMap.keySet()); filmIdGenreMap.forEach((id, genres) -> filmMap.get(id).getGenres().addAll(genres)); return new ArrayList<>(filmMap.values()); } - private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessException { + private Film extractToFilmWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { Film film = null; final Map filmIdMap = new HashMap<>(); while (rs.next()) { film = resultSetToFilm(rs, filmIdMap); - setGenresToFilm(rs, film); } return film; } - private Collection extractToFilmList(ResultSet rs) throws SQLException, DataAccessException { - - final Map filmIdMap = new LinkedHashMap<>(); - - while (rs.next()) { - Film film = resultSetToFilm(rs, filmIdMap); - setGenresToFilm(rs, film); - } - - return filmIdMap.values(); - } - - private void setGenresToFilm(ResultSet rs, Film film) throws SQLException { - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - return; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); - } - private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { final Map filmIdMap = new LinkedHashMap<>(); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 846692ea..ea975e1e 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -286,4 +286,29 @@ void testFindByIdWithAllFields() { .usingRecursiveComparison() .isEqualTo(film); } + + @Test + @DisplayName("Тест на получение самых популярных фильмов с несколькими жанрами") + void testMostPopularFilmsWithSeveralGenres() { + Genre genre1 = new Genre(1, "Комедия"); + Genre genre2 = new Genre(6, "Боевик"); + Genre genre3 = new Genre(2, "Драма"); + + userStorage.add(user); + film.getGenres().add(genre1); + film.getGenres().add(genre2); + film.getGenres().add(genre3); + filmDbStorage.add(film); + filmLikeStorage.add(film.getId(),user.getId()); + filmDbStorage.add(updatedFilm); + + film.setLikes(1); + + Collection popularFilms = filmDbStorage.findMostLikedFilmsLimitBy(1); + + assertThat(popularFilms) + .isNotNull() + .isNotEmpty() + .isEqualTo(List.of(film)); + } } From ae2b7bec6cf824aa915394ed0dfa172c7dae8169 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:43:02 +0300 Subject: [PATCH 052/188] =?UTF-8?q?feat:=20=D0=98=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20mapToFilm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 73 ++++++------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index aa17a600..7ba8ef3f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; @@ -82,31 +82,28 @@ public Collection findAll() { "LEFT JOIN film_like fl on f.id = fl.film_id " + "GROUP BY f.id, m.rating_name"; - Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres); + Collection films = jdbcTemplate.query(sql, this::mapToFilm); return setGenresForFilms(films); } @Override public Film findById(final long filmId) { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + + "GROUP BY f.id, m.rating_name " + "HAVING f.ID = ?"; - final Film film = jdbcTemplate.query(sql, this::extractToFilmWithoutGenres, filmId); - - if (film == null) { + try { + final Film film = jdbcTemplate.queryForObject(sql, this::mapToFilm, filmId); + List genres = filmGenreStorage.findAllById(filmId); + film.getGenres().addAll(genres); + return film; + } catch (EmptyResultDataAccessException e) { throw new NotFoundException("Фильм с id '" + filmId + "' не найден."); } - - List genres = filmGenreStorage.findAllById(filmId); - film.getGenres().addAll(genres); - return film; } public Collection findMostLikedFilmsLimitBy(final int count) { @@ -119,7 +116,7 @@ public Collection findMostLikedFilmsLimitBy(final int count) { "ORDER BY COUNT(fl.USER_ID) DESC " + "LIMIT ?"; - Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + Collection films = jdbcTemplate.query(sql, this::mapToFilm, count); return setGenresForFilms(films); } @@ -130,44 +127,16 @@ private List setGenresForFilms(Collection films) { return new ArrayList<>(filmMap.values()); } - private Film extractToFilmWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { - - Film film = null; - final Map filmIdMap = new HashMap<>(); - - while (rs.next()) { - film = resultSetToFilm(rs, filmIdMap); - } - - return film; - } - - private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { - - final Map filmIdMap = new LinkedHashMap<>(); - - while (rs.next()) { - resultSetToFilm(rs, filmIdMap); - } - - return filmIdMap.values(); - } - - private Film resultSetToFilm(ResultSet rs, Map filmIdMap) throws SQLException { - Long filmId = rs.getLong(1); - Film film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } + private Film mapToFilm(ResultSet rs, int rowNum) throws SQLException { + Film film = Film.builder() + .id(rs.getLong(1)) + .name(rs.getString("title")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) + .build(); + film.setLikes(rs.getLong("likes")); return film; } } From 8a722845803a30eaf55963096177904609c504ca Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 23:13:03 +0300 Subject: [PATCH 053/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ID=20=D0=B4=D0=BB=D1=8F=20FILM=5FGENRE=20?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D1=82=D1=8C=20=D1=83?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=B8?= =?UTF-8?q?=D0=BD=D0=B4=D0=B5=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0dd39d0f..ac2b7abe 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -22,13 +22,15 @@ CREATE TABLE IF NOT EXISTS FILM( CREATE TABLE IF NOT EXISTS FILM_GENRE( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, FILM_ID INTEGER NOT NULL, GENRE_ID INTEGER NOT NULL, - CONSTRAINT pk_film_genre PRIMARY KEY (FILM_ID, GENRE_ID), FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), FOREIGN KEY (GENRE_ID) REFERENCES GENRE(ID) ); +CREATE UNIQUE INDEX FILM_GENRE_IDX ON FILM_GENRE (ID, FILM_ID, GENRE_ID); + CREATE TABLE IF NOT EXISTS FILMORATE_USER( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, EMAIL CHARACTER VARYING(255) NOT NULL, From 701e81b76bf75ba5f790355f0543c2bc1ddc882b Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:00:59 +0300 Subject: [PATCH 054/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/Review.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Review.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Review.java b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java new file mode 100644 index 00000000..9c0977d5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Review { + private long reviewId; + private String content; + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From 2a1dc27e9ad10da1b7c30c4693cafc0e10465c50 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:01:07 +0300 Subject: [PATCH 055/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dto/ReviewDto.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java new file mode 100644 index 00000000..7edbff53 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReviewDto { + private long reviewId; + @NotBlank(message = "Отзыв не может быть пустой.") + private String content; + @NotBlank(message = "Не указана полезность отзыва.") + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From 8844abd6496b540019a5853ec48713ce3eb73d4e Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:03:55 +0300 Subject: [PATCH 056/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewMapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/mapper/ReviewMapper.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java new file mode 100644 index 00000000..e5256f4a --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -0,0 +1,31 @@ +package ru.yandex.practicum.filmorate.mapper; + +import lombok.experimental.UtilityClass; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; + +@UtilityClass +public class ReviewMapper { + + public static ReviewDto toDto(Review review) { + return ReviewDto.builder() + .reviewId(review.getReviewId()) + .content(review.getContent()) + .isPositive(review.isPositive()) + .useful(review.getUseful()) + .filmId(review.getFilmId()) + .userId(review.getUserId()) + .build(); + } + + public static Review toModel(ReviewDto reviewDto) { + return Review.builder() + .reviewId(reviewDto.getReviewId()) + .content(reviewDto.getContent()) + .isPositive(reviewDto.isPositive()) + .useful(reviewDto.getUseful()) + .filmId(reviewDto.getFilmId()) + .userId(reviewDto.getUserId()) + .build(); + } +} From 2ae3b389bc4e410458a12e4617be357f3157f7d3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:29:47 +0300 Subject: [PATCH 057/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20wrapper=20cl?= =?UTF-8?q?ass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dto/ReviewDto.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 7edbff53..731e61cb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; @Data @AllArgsConstructor @@ -13,11 +14,13 @@ @Builder public class ReviewDto { private long reviewId; - @NotBlank(message = "Отзыв не может быть пустой.") + @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; - @NotBlank(message = "Не указана полезность отзыва.") + @NotNull(message = "Не указана полезность отзыва.") private boolean isPositive; private long useful; - private long userId; - private long filmId; + @NotNull(message = "Не указан идентификатор пользователя.") + private Long userId; + @NotNull(message = "Не указан идентификатор фильма.") + private Long filmId; } From e617e533dfd1c799481a31dee3e8fcbfe5773f22 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:30:08 +0300 Subject: [PATCH 058/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ReviewValidationTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java new file mode 100644 index 00000000..e97dcfe0 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java @@ -0,0 +1,106 @@ +package ru.yandex.practicum.filmorate.validation; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.VALIDATOR; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.dtoHasErrorMessage; + +public class ReviewValidationTest { + + @Test + @DisplayName("Проверка возможности добавить отзыв с корректными полями") + public void createReview() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(VALIDATOR.validate(reviewDto).isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", " "}) + @DisplayName("Проверка невозможности добавить отзыв с пустым полем content") + public void createReviewWithoutContent(String content) { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(content) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если content == null") + public void createReviewWithNullContent() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(null) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан filmId") + public void createReviewWithNullFilmId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(null) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор фильма.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан userId") + public void createReviewWithNullUserId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(null) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор пользователя.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указана полезность") + public void createReviewWithNullIsPositive() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(null) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указана полезность отзыва.")); + } +} From 3b79221e6c4c96808fc4054bcd027857ac1679b4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:35:07 +0300 Subject: [PATCH 059/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20Boolean=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20isPositive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java | 2 +- .../java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 731e61cb..200676ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -17,7 +17,7 @@ public class ReviewDto { @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; @NotNull(message = "Не указана полезность отзыва.") - private boolean isPositive; + private Boolean isPositive; private long useful; @NotNull(message = "Не указан идентификатор пользователя.") private Long userId; diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java index e5256f4a..d61c233f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -22,7 +22,7 @@ public static Review toModel(ReviewDto reviewDto) { return Review.builder() .reviewId(reviewDto.getReviewId()) .content(reviewDto.getContent()) - .isPositive(reviewDto.isPositive()) + .isPositive(reviewDto.getIsPositive()) .useful(reviewDto.getUseful()) .filmId(reviewDto.getFilmId()) .userId(reviewDto.getUserId()) From 6f693d30ed5a57826e15deba9eeec0fd1dc8f3f8 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:12 +0300 Subject: [PATCH 060/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index d6a6e230..ac4a2ccf 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -59,4 +59,15 @@ CREATE TABLE IF NOT EXISTS FILM_LIKE( CONSTRAINT pk_film_like PRIMARY KEY (FILM_ID, USER_ID), FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) +); + +CREATE TABLE IF NOT EXISTS REVIEW( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, + REVIEW_CONTENT CHARACTER VARYING(255) NOT NULL, + IS_POSITIVE BOOLEAN NOT NULL, + USEFUL INTEGER, + USER_ID INTEGER NOT NULL, + FILM_ID INTEGER NOT NULL, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ); \ No newline at end of file From 26ac111d1818b3095619334994f5bcae7f6da6a5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:56 +0300 Subject: [PATCH 061/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dao/ReviewStorage.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java new file mode 100644 index 00000000..441e2b3c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -0,0 +1,6 @@ +package ru.yandex.practicum.filmorate.dao; + +import ru.yandex.practicum.filmorate.model.Review; + +public interface ReviewStorage extends Dao{ +} From 94166cb1b19f1c998a8a42e579d3588b70ba1523 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:14 +0300 Subject: [PATCH 062/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java new file mode 100644 index 00000000..23705f20 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -0,0 +1,82 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Review; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Objects; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewDbStorage implements ReviewStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public Review add(final Review review) { + final KeyHolder keyHolder = new GeneratedKeyHolder(); + final String sql = "INSERT INTO review (review_content, is_positive, useful, user_id, film_id) VALUES (?, ?, ?, ?, ?)"; + jdbcTemplate.update(con -> { + PreparedStatement stmt = con.prepareStatement(sql, new String[]{"id"}); + stmt.setString(1, review.getContent()); + stmt.setBoolean(2, review.isPositive()); + stmt.setLong(3, review.getUseful()); + stmt.setLong(4, review.getUserId()); + stmt.setLong(5, review.getFilmId()); + return stmt; + }, keyHolder); + + review.setReviewId(Objects.requireNonNull(keyHolder.getKey(), "Не удалось добавить отзыв.").longValue()); + + return review; + } + + @Override + public void remove(final long id) { + + } + + @Override + public void update(final Review review) { + + } + + @Override + public Collection findAll() { + return null; + } + + @Override + public Review findById(final long id) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE ID = ?"; + try { + return jdbcTemplate.queryForObject(sql, this::mapReview, id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } + } + + private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + return Review.builder() + .reviewId(rs.getLong("id")) + .content(rs.getString("review_content")) + .isPositive(rs.getBoolean("is_positive")) + .useful(rs.getLong("useful")) + .userId(rs.getLong("user_id")) + .filmId(rs.getLong("film_id")) + .build(); + } +} From 9a5d4608913520283608add9691ad480e2d93ca2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:31 +0300 Subject: [PATCH 063/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/ReviewService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java new file mode 100644 index 00000000..c84d3780 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -0,0 +1,10 @@ +package ru.yandex.practicum.filmorate.service; + + +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +public interface ReviewService { + ReviewDto addReview(ReviewDto reviewDto); + + ReviewDto getReviewById(long id); +} From 28c1d678234f20f62025272b5b9ffa5813e219b9 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:44 +0300 Subject: [PATCH 064/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java new file mode 100644 index 00000000..beb330f4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ReviewServiceImpl implements ReviewService { + + private final ReviewStorage reviewStorage; + private final UserStorage userStorage; + private final FilmStorage filmStorage; + + + @Override + public ReviewDto addReview(final ReviewDto reviewDto) { + final Review review = toModel(reviewDto); + userStorage.findById(review.getUserId()); + filmStorage.findById(review.getFilmId()); + final Review addedReview = reviewStorage.add(review); + log.info("Добавлен новый отзыв: {}.", addedReview); + return toDto(reviewStorage.findById(addedReview.getReviewId())); + } + + @Override + public ReviewDto getReviewById(final long id) { + final Review review = reviewStorage.findById(id); + log.info("Найден отзыв с id '{}'.", id); + return toDto(review); + } + + +} From 8e8d8a3c3336dcdff994f4898f54185b9b9372f2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:26:00 +0300 Subject: [PATCH 065/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java new file mode 100644 index 00000000..0ede3d93 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -0,0 +1,65 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import javax.validation.Valid; +import java.util.List; + +@RestController +@RequestMapping("/reviews") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { + return reviewService.addReview(reviewDto); + } + +// @PutMapping +// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { +// return reviewService.updateReview(updatedReviewDto); +// } +// +// @DeleteMapping("/{id}") +// public void deleteReview(@PathVariable long id) { +// reviewService.deleteReview(id); +// } +// + @GetMapping("/{id}") + public ReviewDto getReviewById(@PathVariable long id) { + return reviewService.getReviewById(id); + } +// +// @GetMapping +// public List getReviewsByFilmId(@RequestParam long filmId, +// @RequestParam(required = false, defaultValue = "10") int count) { +// return reviewService.getReviewsByFilmId(filmId, count); +// } +// +// @PutMapping("/{id}/like/{userId}") +// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addLikeToReview(id, userId); +// } +// +// @PutMapping("/{id}/dislike/{userId}") +// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addDislikeToReview(id, userId); +// } +// +// @DeleteMapping("/{id}/like/{userId}") +// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteLikeFromReview(id, userId); +// } +// +// @DeleteMapping("/{id}/dislike/{userId}") +// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteDislikeFromReview(id, userId); +// } +} From 341d62b4edd2ad0e9dc615dea35d1dfc47546bd0 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:30 +0300 Subject: [PATCH 066/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ON=20DELETE=20CASCADE=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index ac4a2ccf..5c6180e9 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -68,6 +68,6 @@ CREATE TABLE IF NOT EXISTS REVIEW( USEFUL INTEGER, USER_ID INTEGER NOT NULL, FILM_ID INTEGER NOT NULL, - FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE ); \ No newline at end of file From ca851c0552c5a6ed9d78d3258295376d721fe7a2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:45 +0300 Subject: [PATCH 067/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 0ede3d93..b468f1be 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -22,10 +22,10 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { return reviewService.addReview(reviewDto); } -// @PutMapping -// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { -// return reviewService.updateReview(updatedReviewDto); -// } + @PutMapping + public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { + return reviewService.updateReview(updatedReviewDto); + } // // @DeleteMapping("/{id}") // public void deleteReview(@PathVariable long id) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 23705f20..002db3ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -50,7 +50,13 @@ public void remove(final long id) { @Override public void update(final Review review) { - + final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + + "WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), + review.getReviewId()); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); + } } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c84d3780..c5b6e422 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -7,4 +7,6 @@ public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); ReviewDto getReviewById(long id); + + ReviewDto updateReview(ReviewDto updatedReviewDto); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index beb330f4..6aa530d8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -25,9 +25,8 @@ public class ReviewServiceImpl implements ReviewService { @Override public ReviewDto addReview(final ReviewDto reviewDto) { + findUserAndFilmInDb(reviewDto); final Review review = toModel(reviewDto); - userStorage.findById(review.getUserId()); - filmStorage.findById(review.getFilmId()); final Review addedReview = reviewStorage.add(review); log.info("Добавлен новый отзыв: {}.", addedReview); return toDto(reviewStorage.findById(addedReview.getReviewId())); @@ -40,5 +39,20 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { + findUserAndFilmInDb(updatedReviewDto); + final Review updatedReview = toModel(updatedReviewDto); + reviewStorage.update(updatedReview); + final long reviewId = updatedReview.getReviewId(); + log.info("Обновление отзыва с id '{}': {}", reviewId, updatedReview); + return toDto(reviewStorage.findById(reviewId)); + } + + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { + userStorage.findById(updatedReviewDto.getUserId()); + filmStorage.findById(updatedReviewDto.getFilmId()); + } + } From f65d0f90e4987e7c9656e1ad16a6bb12386991f3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 13:18:41 +0300 Subject: [PATCH 068/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 12 ++++++------ .../filmorate/dao/impl/ReviewDbStorage.java | 3 ++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 7 +++++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index b468f1be..920618de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -26,12 +26,12 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { return reviewService.updateReview(updatedReviewDto); } -// -// @DeleteMapping("/{id}") -// public void deleteReview(@PathVariable long id) { -// reviewService.deleteReview(id); -// } -// + + @DeleteMapping("/{id}") + public void deleteReview(@PathVariable long id) { + reviewService.deleteReview(id); + } + @GetMapping("/{id}") public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 002db3ed..9c1c3fa1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -45,7 +45,8 @@ public Review add(final Review review) { @Override public void remove(final long id) { - + final String sql = "DELETE FROM review WHERE id = ?"; + jdbcTemplate.update(sql, id); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c5b6e422..64a2329c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -9,4 +9,6 @@ public interface ReviewService { ReviewDto getReviewById(long id); ReviewDto updateReview(ReviewDto updatedReviewDto); + + void deleteReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6aa530d8..2184e3ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -49,6 +49,13 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + @Override + public void deleteReview(long id) { + reviewStorage.findById(id); + reviewStorage.remove(id); + log.info("Отзыв с id '{}' был удален.", id); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From 7d8f437dff003bd7529284407e96c75aff47a725 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:00:49 +0300 Subject: [PATCH 069/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20getReviewsByFilmId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 14 +++++++------- .../practicum/filmorate/dao/ReviewStorage.java | 5 ++++- .../filmorate/dao/impl/ReviewDbStorage.java | 10 +++++++++- .../practicum/filmorate/service/ReviewService.java | 4 ++++ .../filmorate/service/impl/ReviewServiceImpl.java | 14 +++++++++++++- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 920618de..f7571ae9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -36,13 +36,13 @@ public void deleteReview(@PathVariable long id) { public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); } -// -// @GetMapping -// public List getReviewsByFilmId(@RequestParam long filmId, -// @RequestParam(required = false, defaultValue = "10") int count) { -// return reviewService.getReviewsByFilmId(filmId, count); -// } -// + + @GetMapping + public List getReviewsByFilmId(@RequestParam long filmId, + @RequestParam(required = false, defaultValue = "10") int count) { + return reviewService.getReviewsByFilmId(filmId, count); + } + // @PutMapping("/{id}/like/{userId}") // public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { // return reviewService.addLikeToReview(id, userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 441e2b3c..5c198946 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -2,5 +2,8 @@ import ru.yandex.practicum.filmorate.model.Review; -public interface ReviewStorage extends Dao{ +import java.util.List; + +public interface ReviewStorage extends Dao { + List findByFilmIdLimitBy(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 9c1c3fa1..829980fd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -15,6 +15,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import java.util.Objects; @Repository @@ -76,7 +77,7 @@ public Review findById(final long id) { } } - private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) .content(rs.getString("review_content")) @@ -86,4 +87,11 @@ private Review mapReview(ResultSet rs, int rowNum) throws SQLException { .filmId(rs.getLong("film_id")) .build(); } + + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 64a2329c..3ede2c4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -3,6 +3,8 @@ import ru.yandex.practicum.filmorate.dto.ReviewDto; +import java.util.List; + public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); @@ -11,4 +13,6 @@ public interface ReviewService { ReviewDto updateReview(ReviewDto updatedReviewDto); void deleteReview(long id); + + List getReviewsByFilmId(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 2184e3ee..fb25ee4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -7,9 +7,13 @@ import ru.yandex.practicum.filmorate.dao.ReviewStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.service.ReviewService; +import java.util.List; +import java.util.stream.Collectors; + import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; @@ -50,12 +54,20 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { } @Override - public void deleteReview(long id) { + public void deleteReview(final long id) { reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } + @Override + public List getReviewsByFilmId(final long filmId, final int count) { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From 2f579983a1b49329dd9dd2f32ef30305d30ae0a4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:15:37 +0300 Subject: [PATCH 070/188] =?UTF-8?q?fix:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?useful=20=D0=BF=D1=80=D0=B8=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 829980fd..f47dd04c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -52,10 +52,8 @@ public void remove(final long id) { @Override public void update(final Review review) { - final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + - "WHERE id = ?"; - final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), - review.getReviewId()); + final String sql = "UPDATE review SET review_content = ?, is_positive = ? WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getReviewId()); if (update != 1) { throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); } From cea22e16bbc445681cc19c4e01b656fb5c21e214 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:21 +0300 Subject: [PATCH 071/188] =?UTF-8?q?refactor:=20=D0=97=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C=20filmId=20=D0=BD=D0=B0=20Long?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/ReviewController.java | 2 +- .../ru/yandex/practicum/filmorate/service/ReviewService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index f7571ae9..a9ad48ea 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -38,7 +38,7 @@ public ReviewDto getReviewById(@PathVariable long id) { } @GetMapping - public List getReviewsByFilmId(@RequestParam long filmId, + public List getReviewsByFilmId(@RequestParam(required = false) Long filmId, @RequestParam(required = false, defaultValue = "10") int count) { return reviewService.getReviewsByFilmId(filmId, count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 3ede2c4d..65117fd4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -14,5 +14,5 @@ public interface ReviewService { void deleteReview(long id); - List getReviewsByFilmId(long filmId, int count); + List getReviewsByFilmId(Long filmId, int count); } From 56a95dcf3b5dd3ef54bcbb6ad4468a90b1b89388 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:46 +0300 Subject: [PATCH 072/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20findAllLimitBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 21 ++++++++++++------- .../service/impl/ReviewServiceImpl.java | 16 +++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 5c198946..f7569ae3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -6,4 +6,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); + + List findAllLimitBy(int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index f47dd04c..8e89dac1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -75,6 +75,20 @@ public Review findById(final long id) { } } + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } + + @Override + public List findAllLimitBy(int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, count); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) @@ -85,11 +99,4 @@ private Review mapReview(final ResultSet rs, final int rowNum) throws SQLExcepti .filmId(rs.getLong("film_id")) .build(); } - - @Override - public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; - return jdbcTemplate.query(sql, this::mapReview, filmId, count); - } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index fb25ee4d..6e86573c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -61,11 +61,17 @@ public void deleteReview(final long id) { } @Override - public List getReviewsByFilmId(final long filmId, final int count) { - filmStorage.findById(filmId); - final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); - log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); - return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + public List getReviewsByFilmId(final Long filmId, final int count) { + if (filmId == null) { + final List reviews = reviewStorage.findAllLimitBy(count); + log.info("Запрос на получение отзывов."); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } else { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } } private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { From 8961325b1313b260776f8e2857acde8cb417cc35 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:27:36 +0300 Subject: [PATCH 073/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addLikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../yandex/practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 11 +++++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index a9ad48ea..97e2aede 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -43,10 +43,10 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f return reviewService.getReviewsByFilmId(filmId, count); } -// @PutMapping("/{id}/like/{userId}") -// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addLikeToReview(id, userId); -// } + @PutMapping("/{id}/like/{userId}") + public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addLikeToReview(id, userId); + } // // @PutMapping("/{id}/dislike/{userId}") // public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index f7569ae3..e534405e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -8,4 +8,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); List findAllLimitBy(int count); + + void addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8e89dac1..8091fad2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -83,12 +83,18 @@ public List findByFilmIdLimitBy(final long filmId, final int count) { } @Override - public List findAllLimitBy(int count) { + public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + "FROM REVIEW LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } + @Override + public void addLikeToReview(final long id, final long userId) { + final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 65117fd4..e2ae9acc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -15,4 +15,6 @@ public interface ReviewService { void deleteReview(long id); List getReviewsByFilmId(Long filmId, int count); + + ReviewDto addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6e86573c..57b15d64 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -74,10 +74,17 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + @Override + public ReviewDto addLikeToReview(final long id, final long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); } - - } From f9f76e3a4ace32dab4e60cfdb69b9bc54ed518c5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:29:22 +0300 Subject: [PATCH 074/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D1=80=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D1=82=D0=B7=D1=8B?= =?UTF-8?q?=D0=B2=D1=8B=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B7?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8091fad2..95c160ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -78,14 +78,14 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW LIMIT ?"; + "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From 85262cdd34a8b94122a7828bd48cdae8038ef0c9 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:33:16 +0300 Subject: [PATCH 075/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addDislikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 10 +++++----- .../practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 6 ++++++ .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 16 ++++++++++++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 97e2aede..d403d135 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -47,11 +47,11 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addLikeToReview(id, userId); } -// -// @PutMapping("/{id}/dislike/{userId}") -// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addDislikeToReview(id, userId); -// } + + @PutMapping("/{id}/dislike/{userId}") + public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addDislikeToReview(id, userId); + } // // @DeleteMapping("/{id}/like/{userId}") // public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index e534405e..670325b5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -10,4 +10,6 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); void addLikeToReview(long id, long userId); + + void addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 95c160ff..97eeba6a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,6 +95,12 @@ public void addLikeToReview(final long id, final long userId) { jdbcTemplate.update(sql, id); } + @Override + public void addDislikeToReview(long id, long userId) { + final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index e2ae9acc..afdd9099 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -17,4 +17,6 @@ public interface ReviewService { List getReviewsByFilmId(Long filmId, int count); ReviewDto addLikeToReview(long id, long userId); + + ReviewDto addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 57b15d64..4f447606 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -76,13 +76,25 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { - reviewStorage.findById(id); - userStorage.findById(userId); + findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } + @Override + public ReviewDto addDislikeToReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + private void findReviewAndUserInDb(long id, long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From bbaf3db8b1cd6c1ce38a351f093356fcbb6813a3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:37:08 +0300 Subject: [PATCH 076/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=B4=D0=B8=D0=B7=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 20 +++++++++---------- .../filmorate/service/ReviewService.java | 4 ++++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index d403d135..c8a31fb5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -52,14 +52,14 @@ public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userI public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addDislikeToReview(id, userId); } -// -// @DeleteMapping("/{id}/like/{userId}") -// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteLikeFromReview(id, userId); -// } -// -// @DeleteMapping("/{id}/dislike/{userId}") -// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteDislikeFromReview(id, userId); -// } + + @DeleteMapping("/{id}/like/{userId}") + public ReviewDto deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteLikeFromReview(id, userId); + } + + @DeleteMapping("/{id}/dislike/{userId}") + public ReviewDto deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteDislikeFromReview(id, userId); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index afdd9099..71f1acc7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -19,4 +19,8 @@ public interface ReviewService { ReviewDto addLikeToReview(long id, long userId); ReviewDto addDislikeToReview(long id, long userId); + + ReviewDto deleteLikeFromReview(long id, long userId); + + ReviewDto deleteDislikeFromReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 4f447606..b10e843c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -86,7 +86,23 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); - log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteLikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteDislikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From bede5bdfed8b997463e573ed1a615c12cd623027 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:09 +0300 Subject: [PATCH 077/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D1=83=20=D0=BF=D0=BE=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 97eeba6a..1929eca8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -61,13 +61,15 @@ public void update(final Review review) { @Override public Collection findAll() { - return null; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id"; + return jdbcTemplate.query(sql, this::mapReview); } @Override public Review findById(final long id) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE ID = ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE id = ?"; try { return jdbcTemplate.queryForObject(sql, this::mapReview, id); } catch (EmptyResultDataAccessException e) { @@ -77,15 +79,15 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE film_id = ? ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From 21389331255882e8a1a69a99a63e3aafee8b892c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:30 +0300 Subject: [PATCH 078/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20ReviewDbStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/ReviewDbStorageTest.java | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java new file mode 100644 index 00000000..015d97e4 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -0,0 +1,305 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmGenreDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.ReviewDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@JdbcTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class ReviewDbStorageTest { + + private final JdbcTemplate jdbcTemplate; + + private ReviewStorage reviewStorage; + private FilmStorage filmStorage; + private UserStorage userStorage; + private Review review1; + private Review review2; + private Review review3; + private Review updatedReview; + private Film film; + private User user; + + @BeforeEach + public void setUp() { + reviewStorage = new ReviewDbStorage(jdbcTemplate); + FilmGenreStorage filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); + filmStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + userStorage = new UserDbStorage(jdbcTemplate); + Mpa mpa = new Mpa(1, "G"); + + film = Film.builder() + .id(1) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + user = User.builder() + .id(1) + .email("email") + .login("login") + .name("name") + .birthday(LocalDate.now()) + .build(); + filmStorage.add(film); + userStorage.add(user); + + + review1 = Review.builder() + .reviewId(1) + .content("review 2") + .isPositive(true) + .useful(1) + .userId(1) + .filmId(1) + .build(); + + review2 = Review.builder() + .reviewId(2) + .content("review 1") + .isPositive(false) + .useful(2) + .userId(1) + .filmId(1) + .build(); + + review3 = Review.builder() + .reviewId(3) + .content("review 3") + .isPositive(true) + .useful(3) + .userId(1) + .filmId(1) + .build(); + + updatedReview = Review.builder() + .reviewId(1) + .content("updated review 1") + .isPositive(true) + .useful(13) + .userId(4) + .filmId(4) + .build(); + } + + @Test + @DisplayName("Тест добавления отзыва и получения по id.") + public void addAndGetByIdTest() { + reviewStorage.add(review1); + + Review savedReview = reviewStorage.findById(1); + + assertThat(savedReview) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест получения всех отзывов (сортировка по полезности).") + public void getAllReviews() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест получения всех отзывов без оценок полезности.") + public void getAllReviewsWithZeroUseful() { + review1.setUseful(0); + review2.setUseful(0); + review3.setUseful(0); + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review1, review2, review3)); + } + + @Test + @DisplayName("Тест получения всех отзывов при пустой базе данных.") + public void getAllReviewsEmptyDb() { + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(2); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2)); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 1); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3)); + } + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест удаления отзыва.") + public void deleteReview() { + reviewStorage.add(review1); + reviewStorage.remove(1); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест обновления отзыва. Обновиться должны только поля content, isPositive.") + public void updateReview() { + reviewStorage.add(review1); + reviewStorage.update(updatedReview); + + Review storedReview = reviewStorage.findById(1); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("content", "isPositive") + .isEqualTo(updatedReview); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("useful", "filmId", "userId") + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест добавления лайка отзыву.") + public void addLikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(2, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления лайка отзыву c отрицательным рейтингом.") + public void addLikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву.") + public void addDislikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву c отрицательным рейтингом.") + public void addDislikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(-2, storedReview.getUseful()); + } + +} \ No newline at end of file From 74dea04faf0131ab00384866bade2e35a0a419a4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:45:05 +0300 Subject: [PATCH 079/188] javadoc --- .../service/impl/ReviewServiceImpl.java | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index b10e843c..451cac2f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -26,7 +26,12 @@ public class ReviewServiceImpl implements ReviewService { private final UserStorage userStorage; private final FilmStorage filmStorage; - + /** + * Добавление отзыва в БД. + * + * @param reviewDto отзыв. + * @return отзыв с присвоенным идентификатором. + */ @Override public ReviewDto addReview(final ReviewDto reviewDto) { findUserAndFilmInDb(reviewDto); @@ -36,6 +41,12 @@ public ReviewDto addReview(final ReviewDto reviewDto) { return toDto(reviewStorage.findById(addedReview.getReviewId())); } + /** + * Получение отзыва по идентификатору. + * + * @param id идентификатор отзыва. + * @return найденный отзыв. + */ @Override public ReviewDto getReviewById(final long id) { final Review review = reviewStorage.findById(id); @@ -43,6 +54,12 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + /** + * Обновление данных отзыва. Происходит обновление только полей content и isPositive. + * + * @param updatedReviewDto отзыв с обновленными полями. + * @return обновленный отзыв. + */ @Override public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); @@ -53,6 +70,11 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + /** + * Удаление отзыва из БД. + * + * @param id идентификатор отзыва. + */ @Override public void deleteReview(final long id) { reviewStorage.findById(id); @@ -60,6 +82,13 @@ public void deleteReview(final long id) { log.info("Отзыв с id '{}' был удален.", id); } + /** + * Получение списка отзывов о фильме. Если идентификатор фильма не был передан, то выводится список всех отзывов. + * + * @param filmId идентификатор фильма. + * @param count количество отзывов, которое требуется вывести. По умолчанию 10. + * @return список отзывов. + */ @Override public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { @@ -74,6 +103,13 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + /** + * Добавление лайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит лайк. + * @return отзыв с добавленным лайком. + */ @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); @@ -82,6 +118,13 @@ public ReviewDto addLikeToReview(final long id, final long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Добавление дизлайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит дизлайк. + * @return отзыв с добавленным дизлайком. + */ @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -90,6 +133,13 @@ public ReviewDto addDislikeToReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление лайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет лайк. + * @return отзыв с удаленным лайком. + */ @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -98,6 +148,13 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление дизлайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет дизлайк. + * @return отзыв с удаленным дизлайком. + */ @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); From 18997e38b52dfac8aeef5ea49e6d7e7af3d73b5c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:46:41 +0300 Subject: [PATCH 080/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20review=5Flike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 5c6180e9..0dd39d0f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -70,4 +70,12 @@ CREATE TABLE IF NOT EXISTS REVIEW( FILM_ID INTEGER NOT NULL, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS REVIEW_LIKE( + REVIEW_ID INTEGER NOT NULL, + USER_ID INTEGER NOT NULL, + LIKE_TYPE CHARACTER VARYING(7) NOT NULL, + FOREIGN KEY (REVIEW_ID) REFERENCES REVIEW(ID) ON DELETE CASCADE, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE +); From fb5a9407fc5ad2f43fc153f8d28523e162850c8f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:05 +0300 Subject: [PATCH 081/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java new file mode 100644 index 00000000..01d7ddac --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.dao; + +public interface ReviewLikeStorage { + void add(long reviewId, long userId, String type); + + void delete(long userId, String type); +} From 155a2b24ddd9d9f2612ffeb650a68f98f12c8817 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:16 +0300 Subject: [PATCH 082/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/impl/ReviewLikeDbStorage.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java new file mode 100644 index 00000000..36c52158 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewLikeDbStorage implements ReviewLikeStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public void add(final long reviewId, final long userId, final String type) { + final String sql = "INSERT INTO review_like VALUES (?, ?, ?)"; + jdbcTemplate.update(sql, reviewId, userId, type); + } + + @Override + public void delete(final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId); + } +} From b14c72fb7305d719981098cb348bc18bcbe99449 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:30 +0300 Subject: [PATCH 083/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20enum=20ReviewLike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java new file mode 100644 index 00000000..09b2d9e6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.model; + +public enum ReviewLike { + LIKE("like"), + DISLIKE("dislike"); + + private final String type; + + ReviewLike(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} From 9daf150b0f1640f5af7eac03518af245fcf26d2d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:52 +0300 Subject: [PATCH 084/188] =?UTF-8?q?feat:=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 451cac2f..88564f6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,12 +3,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -25,6 +24,7 @@ public class ReviewServiceImpl implements ReviewService { private final ReviewStorage reviewStorage; private final UserStorage userStorage; private final FilmStorage filmStorage; + private final ReviewLikeStorage reviewLikeStorage; /** * Добавление отзыва в БД. @@ -114,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,6 +130,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -144,6 +146,7 @@ public ReviewDto addDislikeToReview(long id, long userId) { public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -159,6 +162,7 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From c7e8cb042e6e677afdc4c4489df65a7e4402b91e Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:21 +0300 Subject: [PATCH 085/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D0=BF=D1=80=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 1929eca8..04b42d1a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -47,7 +47,10 @@ public Review add(final Review review) { @Override public void remove(final long id) { final String sql = "DELETE FROM review WHERE id = ?"; - jdbcTemplate.update(sql, id); + int update = jdbcTemplate.update(sql, id); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } } @Override From 2da3bc0fa9b7337fd66465a61ce6e8ab0e74a553 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:56 +0300 Subject: [PATCH 086/188] =?UTF-8?q?refactor:=20=D0=A3=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B8=D0=B7=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2=20userId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 04b42d1a..f57f25a8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,13 +95,13 @@ public List findAllLimitBy(final int count) { } @Override - public void addLikeToReview(final long id, final long userId) { + public void addLikeToReview(final long id) { final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } @Override - public void addDislikeToReview(long id, long userId) { + public void addDislikeToReview(long id) { final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } From 747fc306aafec7dd3f68084a9a86bed184202cd4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:13:25 +0300 Subject: [PATCH 087/188] =?UTF-8?q?refactor:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java index 09b2d9e6..814fd757 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -1,17 +1,6 @@ package ru.yandex.practicum.filmorate.model; public enum ReviewLike { - LIKE("like"), - DISLIKE("dislike"); - - private final String type; - - ReviewLike(String type) { - this.type = type; - } - - @Override - public String toString() { - return type; - } + LIKE, + DISLIKE; } From f64bd8d98ad957e0a07d5f0a4b0662fd0465d37c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:01 +0300 Subject: [PATCH 088/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20reviewId=20=D0=B2=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 2 +- .../practicum/filmorate/dao/impl/ReviewLikeDbStorage.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java index 01d7ddac..90d6f0a0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -3,5 +3,5 @@ public interface ReviewLikeStorage { void add(long reviewId, long userId, String type); - void delete(long userId, String type); + void delete(long reviewId, long userId, String type); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java index 36c52158..26cd5a6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -20,8 +20,8 @@ public void add(final long reviewId, final long userId, final String type) { } @Override - public void delete(final long userId, final String type) { - final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; - jdbcTemplate.update(sql, userId); + public void delete(final long reviewId, final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE review_id = ? AND user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId, type); } } From eee2fb543e9993c4c414c9c7c9f2c48371e59c62 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:35 +0300 Subject: [PATCH 089/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20userId=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 4 ++-- .../service/impl/ReviewServiceImpl.java | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 670325b5..a220dbfe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -9,7 +9,7 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); - void addLikeToReview(long id, long userId); + void addLikeToReview(long id); - void addDislikeToReview(long id, long userId); + void addDislikeToReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 88564f6f..560c8d99 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -15,6 +15,7 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; +import static ru.yandex.practicum.filmorate.model.ReviewLike.*; @Service @RequiredArgsConstructor @@ -61,6 +62,7 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -77,7 +79,6 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { */ @Override public void deleteReview(final long id) { - reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } @@ -113,8 +114,8 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.add(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,8 +130,8 @@ public ReviewDto addLikeToReview(final long id, final long userId) { @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.add(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -145,8 +146,8 @@ public ReviewDto addDislikeToReview(long id, long userId) { @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.delete(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -161,8 +162,8 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.delete(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 0babcb7e9ff2e50d27f1ca3d416daba59456a27b Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:15:00 +0300 Subject: [PATCH 090/188] =?UTF-8?q?refactor:=20=D0=9F=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D1=8B=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 015d97e4..2168ed14 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From 5604cdb28162ef5edca79e67c32cd772657c5aae Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:16:26 +0300 Subject: [PATCH 091/188] =?UTF-8?q?style:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=B8=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 560c8d99..10decebe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,11 +3,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; -import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -15,7 +17,8 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; -import static ru.yandex.practicum.filmorate.model.ReviewLike.*; +import static ru.yandex.practicum.filmorate.model.ReviewLike.DISLIKE; +import static ru.yandex.practicum.filmorate.model.ReviewLike.LIKE; @Service @RequiredArgsConstructor From 060d430720c88cc07138c09fa28a2e956cd22431 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:19:55 +0300 Subject: [PATCH 092/188] checkstyle --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 2168ed14..1224a75c 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From d9306f06b183b0b7012b1a4aae465b4be2e3d646 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 08:55:59 +0300 Subject: [PATCH 093/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Transactional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 10decebe..f2d08926 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,10 +3,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import org.springframework.transaction.annotation.Transactional; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; @@ -65,7 +63,6 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override - public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -81,6 +78,7 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { * @param id идентификатор отзыва. */ @Override + @Transactional public void deleteReview(final long id) { reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); @@ -94,6 +92,7 @@ public void deleteReview(final long id) { * @return список отзывов. */ @Override + @Transactional public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { final List reviews = reviewStorage.findAllLimitBy(count); @@ -115,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { * @return отзыв с добавленным лайком. */ @Override + @Transactional public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); @@ -131,6 +131,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { * @return отзыв с добавленным дизлайком. */ @Override + @Transactional public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -142,11 +143,12 @@ public ReviewDto addDislikeToReview(long id, long userId) { /** * Удаление лайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет лайк. * @return отзыв с удаленным лайком. */ @Override + @Transactional public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -158,11 +160,12 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { /** * Удаление дизлайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет дизлайк. * @return отзыв с удаленным дизлайком. */ @Override + @Transactional public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); From 3da9f7791f08fc597cf141ae57eb903edbfe56d2 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 23:59:16 +0100 Subject: [PATCH 094/188] =?UTF-8?q?feat:=20=D0=9C=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=20getCommonFilms=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D1=82=20?= =?UTF-8?q?findFilmsByIds=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D0=B7=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D0=BD=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE=20=D1=84=D0=B8?= =?UTF-8?q?=D0=BB=D1=8C=D0=BC=D0=B0=D1=85=20=D0=B7=D0=B0=20=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81,=20=D1=87?= =?UTF-8?q?=D1=82=D0=BE=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B8=D0=B7=D0=B2=D0=BE=D0=B4=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=B1=D0=B5=D0=B3=D0=B0=D0=B5=D1=82=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B1=D0=BB=D0=B5=D0=BC=D1=8B=20N+1=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/FilmStorage.java | 3 ++ .../filmorate/dao/impl/FilmDbStorage.java | 36 +++++++++++++++++++ .../filmorate/dao/impl/FilmLikeDbStorage.java | 10 +++--- .../service/impl/FilmServiceImpl.java | 32 +++++++++-------- 4 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index 19d28a99..ec3d1735 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -3,7 +3,10 @@ import ru.yandex.practicum.filmorate.model.Film; import java.util.Collection; +import java.util.List; +import java.util.Set; public interface FilmStorage extends Dao { Collection findMostLikedFilmsLimitBy(int count); + List findFilmsByIds(Set filmIds); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 976544b8..d44b0613 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; @@ -192,4 +193,39 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException, Da return filmIdMap.values(); } + @Override + public List findFilmsByIds(Set filmIds) { + if (filmIds.isEmpty()) { + return Collections.emptyList(); + } + + String placeholders = String.join(",", Collections.nCopies(filmIds.size(), "?")); + + String sql = "SELECT f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, " + + "m.RATING_NAME, COUNT(fl.USER_ID) AS LIKES " + + "FROM FILM f " + + "LEFT JOIN MPA m ON f.MPA_ID = m.ID " + + "LEFT JOIN film_like fl ON f.ID = fl.FILM_ID " + + "WHERE f.ID IN (" + placeholders + ") " + + "GROUP BY f.ID, m.RATING_NAME " + + "ORDER BY LIKES DESC"; + + Object[] idsArray = filmIds.toArray(new Object[0]); + + return jdbcTemplate.query(sql, idsArray, new RowMapper() { + @Override + public Film mapRow(ResultSet rs, int rowNum) throws SQLException { + Film film = new Film(); + film.setId(rs.getLong("ID")); + film.setName(rs.getString("TITLE")); + film.setDescription(rs.getString("DESCRIPTION")); + film.setReleaseDate(rs.getDate("RELEASE_DATE").toLocalDate()); + film.setDuration(rs.getInt("DURATION")); + film.setMpa(new Mpa(rs.getInt("MPA_ID"), rs.getString("RATING_NAME"))); + film.setLikes(rs.getLong("LIKES")); + return film; + } + }); + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 316fc562..12371026 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -9,10 +9,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; @Repository @RequiredArgsConstructor @@ -54,9 +51,11 @@ public void remove(long filmId, long userId) { @Override public Set findLikedFilmsByUser(long userId) { final String sql = "SELECT film_id FROM film_like WHERE user_id = ?"; - return new HashSet<>(jdbcTemplate.queryForList(sql, Long.class, userId)); + List filmIds = jdbcTemplate.queryForList(sql, Long.class, userId); + return new HashSet<>(filmIds); } + private Map mapRowToIdCount(ResultSet rs) throws SQLException { final Map result = new LinkedHashMap<>(); while (rs.next()) { @@ -64,4 +63,5 @@ private Map mapRowToIdCount(ResultSet rs) throws SQLException { } return result; } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 8904d987..c0e36ac1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -127,27 +127,29 @@ public Collection getMostPopularFilms(final int count) { /** * Получение списка общих понравившихся фильмов между двумя пользователями. - * Метод ищет фильмы, которые нравятся обоим пользователям, и возвращает их - * в порядке убывания популярности, определяемой количеством лайков. + * Этот метод идентифицирует фильмы, которые были отмечены как понравившиеся обоим пользователям, + * и возвращает их список, отсортированный по убыванию количества лайков * - * @param userId идентификатор первого пользователя. - * @param friendId идентификатор второго пользователя. - * @return список фильмов, которые нравятся обоим пользователям, упорядоченный - * по убыванию популярности. + * @param userId идентификатор первого пользователя. + * @param friendId идентификатор второго пользователя + * @return список DTO фильмов, которые лайкнуты обоими пользователями. . + * Если общих лайкнутых фильмов нет, возвращается пустой список. */ @Override public Collection getCommonFilms(long userId, long friendId) { + Set userLikedFilmIds = filmLikeStorage.findLikedFilmsByUser(userId); + Set friendLikedFilmIds = filmLikeStorage.findLikedFilmsByUser(friendId); - Set userFilms = filmLikeStorage.findLikedFilmsByUser(userId); - Set friendFilms = filmLikeStorage.findLikedFilmsByUser(friendId); + userLikedFilmIds.retainAll(friendLikedFilmIds); - userFilms.retainAll(friendFilms); + if (userLikedFilmIds.isEmpty()) { + return Collections.emptyList(); + } - return userFilms.stream() - .map(filmId -> filmStorage.findById(filmId)) - .filter(Objects::nonNull) - .map(FilmMapper::toDto) - .sorted(Comparator.comparingLong(FilmDto::getLikes).reversed()) - .collect(Collectors.toList()); + List commonFilms = filmStorage.findFilmsByIds(userLikedFilmIds); + return commonFilms.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } + + + } \ No newline at end of file From d864974c912d494626bb1936308f2bc6108d5e97 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Thu, 1 Feb 2024 00:09:03 +0100 Subject: [PATCH 095/188] Checkstyle --- src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index ec3d1735..05b0ed66 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -9,4 +9,5 @@ public interface FilmStorage extends Dao { Collection findMostLikedFilmsLimitBy(int count); List findFilmsByIds(Set filmIds); + } From 3edfc80e2a024d84123a1ec98b47c42902de45f0 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Thu, 1 Feb 2024 00:13:23 +0100 Subject: [PATCH 096/188] Checkstyle --- .../java/ru/yandex/practicum/filmorate/dao/FilmStorage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index 05b0ed66..f2df5d53 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -7,7 +7,9 @@ import java.util.Set; public interface FilmStorage extends Dao { + Collection findMostLikedFilmsLimitBy(int count); + List findFilmsByIds(Set filmIds); - + } From 3969fb4f4b60be621d31dc8987754b21be17b652 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Thu, 1 Feb 2024 00:23:51 +0100 Subject: [PATCH 097/188] Checkstyle --- .../ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index d44b0613..2c77a4cd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -193,6 +193,7 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException, Da return filmIdMap.values(); } + @Override public List findFilmsByIds(Set filmIds) { if (filmIds.isEmpty()) { From 15e048e0eee9a88c55c9ae471b8112f011beb5c8 Mon Sep 17 00:00:00 2001 From: Ayzat Murtazin Date: Wed, 31 Jan 2024 16:46:23 +0300 Subject: [PATCH 098/188] =?UTF-8?q?feat:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 ++- .../filmorate/controller/FilmController.java | 5 +++++ .../filmorate/controller/UserController.java | 5 +++++ .../filmorate/dao/impl/FilmDbStorage.java | 6 ++++-- .../filmorate/dao/impl/FilmLikeDbStorage.java | 1 + .../filmorate/service/FilmService.java | 2 ++ .../filmorate/service/UserService.java | 2 ++ .../service/impl/FilmServiceImpl.java | 10 ++++++++++ .../service/impl/UserServiceImpl.java | 10 ++++++++++ src/main/resources/schema.sql | 6 +++--- .../filmorate/storage/FilmDbStorageTest.java | 20 +++++++++++++++++++ .../filmorate/storage/UserDbStorageTest.java | 20 +++++++++++++++++++ 12 files changed, 84 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c0f548b6..dae45abc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.14 + 2.7.17 ru.yandex.practicum @@ -54,6 +54,7 @@ com.h2database h2 + 2.2.220 runtime diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index e813df7b..e1066545 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -52,5 +52,10 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { public Collection getMostPopularFilms(@RequestParam(required = false, defaultValue = "10") int count) { return filmService.getMostPopularFilms(count); } + + @DeleteMapping("/{id}") + public void removeFilm(@PathVariable long id) { + filmService.removeFilm(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index cc57d70b..eb1285d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -58,4 +58,9 @@ public void removeFriend(@PathVariable long id, @PathVariable long friendId) { userService.removeFriend(id, friendId); } + @DeleteMapping("/{id}") + public void removeUser(@PathVariable long id) { + userService.removeUser(id); + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 976544b8..89a86370 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -53,7 +53,10 @@ public Film add(final Film film) { @Override public void remove(final long id) { final String sql = "DELETE FROM film WHERE id = ?"; - jdbcTemplate.update(sql, id); + int amount = jdbcTemplate.update(sql, id); + if (amount != 1) { + throw new NotFoundException("Фильм с id '" + id + "' не найден."); + } } @Override @@ -66,7 +69,6 @@ public void update(final Film film) { } filmGenreStorage.deleteAllById(film.getId()); - filmGenreStorage.batchUpdate(film.getId(), film.getGenres()); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 07d0a770..7b2707e5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -49,6 +49,7 @@ public void remove(long filmId, long userId) { jdbcTemplate.update(sql, filmId, userId); } + private Map mapRowToIdCount(ResultSet rs) throws SQLException { final Map result = new LinkedHashMap<>(); while (rs.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index c4724356..88ea93e9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -17,5 +17,7 @@ public interface FilmService { FilmDto removeLike(long filmId, long userId); + void removeFilm(long filmId); + Collection getMostPopularFilms(final int count); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 3c172db2..3a4475f5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -21,4 +21,6 @@ public interface UserService { Collection findCommonFriends(long userId, long otherUserId); void removeFriend(long userId, long friendId); + + void removeUser(long userId); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 028192ee..5b29e3ca 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -114,6 +114,16 @@ public FilmDto removeLike(final long filmId, final long userId) { return toDto(filmStorage.findById(filmId)); } + /** + * Удаление фильма. + * + * @param filmId идентификатор фильма, который будет удален + */ + @Override + public void removeFilm(long filmId) { + filmStorage.remove(filmId); + } + /** * Получение списка самых популярных фильмов. Под популярностью понимается количество лайков у фильма. Чем больше * лайков, тем популярнее фильм. diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index c5abaae8..482bd1c3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -151,6 +151,16 @@ public void removeFriend(final long userId, final long friendId) { log.info("Пользователи с id {} и {} перестали быть друзьями", userId, friendId); } + /** + * Удаление пользователя. + * + * @param userId идентификатор пользователя, который будет удален + */ + @Override + public void removeUser(long userId) { + userStorage.remove(userId); + } + private UserDto validateUserName(final UserDto userDto) { final String validatedName = userDto.getName() == null || userDto.getName().isBlank() ? userDto.getLogin() : userDto.getName(); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0dd39d0f..a2cd383f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; +-- DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS FILM_GENRE( FILM_ID INTEGER NOT NULL, GENRE_ID INTEGER NOT NULL, CONSTRAINT pk_film_genre PRIMARY KEY (FILM_ID, GENRE_ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE, FOREIGN KEY (GENRE_ID) REFERENCES GENRE(ID) ); @@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS FILM_LIKE( FILM_ID INTEGER NOT NULL, USER_ID INTEGER NOT NULL, CONSTRAINT pk_film_like PRIMARY KEY (FILM_ID, USER_ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 846692ea..6ef7b22b 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -286,4 +286,24 @@ void testFindByIdWithAllFields() { .usingRecursiveComparison() .isEqualTo(film); } + + @Test + @DisplayName("Тест удаление фильма") + void testDeleteFilm() { + Film newFilm = filmDbStorage.add(film); + filmDbStorage.remove(newFilm.getId()); + + String formattedResponse = String.format("Фильм с id '%s' не найден.", newFilm.getId()); + NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.findById(newFilm.getId())); + assertEquals(formattedResponse, e.getMessage()); + } + + @Test + @DisplayName("Тест удаление несуществующего фильма") + void testDeleteNotExistingUser() { + int filmId = 999; + String formattedResponse = String.format("Фильм с id '%s' не найден.", filmId); + NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.findById(filmId)); + assertEquals(formattedResponse, e.getMessage()); + } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 5b506415..dd3cb6ec 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -314,4 +314,24 @@ void testGetEmptyFriendsList() { .isNotNull() .isEmpty(); } + + @Test + @DisplayName("Тест удаление пользователя") + void testDeleteUser() { + User newUser = userStorage.add(user); + userStorage.remove(newUser.getId()); + + String formattedResponse = String.format("Пользователь с id '%s' не найден.", newUser.getId()); + NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.findById(newUser.getId())); + assertEquals(formattedResponse, e.getMessage()); + } + + @Test + @DisplayName("Тест удаление несуществующего пользователя") + void testDeleteNotExistingUser() { + int userId = 999; + String formattedResponse = String.format("Пользователь с id '%s' не найден.", userId); + NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.findById(userId)); + assertEquals(formattedResponse, e.getMessage()); + } } \ No newline at end of file From e90a3944b94c113a4f67bb9fe1552a511dec17d9 Mon Sep 17 00:00:00 2001 From: Ayzat Murtazin Date: Thu, 1 Feb 2024 10:47:16 +0300 Subject: [PATCH 099/188] refactor: fix tests --- .../yandex/practicum/filmorate/storage/FilmDbStorageTest.java | 2 +- .../yandex/practicum/filmorate/storage/UserDbStorageTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 3270b194..f388ec09 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -303,7 +303,7 @@ void testDeleteFilm() { void testDeleteNotExistingUser() { int filmId = 999; String formattedResponse = String.format("Фильм с id '%s' не найден.", filmId); - NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.findById(filmId)); + NotFoundException e = assertThrows(NotFoundException.class, () -> filmDbStorage.remove(filmId)); assertEquals(formattedResponse, e.getMessage()); } diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index dd3cb6ec..1c02084f 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -331,7 +331,7 @@ void testDeleteUser() { void testDeleteNotExistingUser() { int userId = 999; String formattedResponse = String.format("Пользователь с id '%s' не найден.", userId); - NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.findById(userId)); + NotFoundException e = assertThrows(NotFoundException.class, () -> userStorage.remove(userId)); assertEquals(formattedResponse, e.getMessage()); } } \ No newline at end of file From e3a0a74f2e14480093790c06778871661ea6a4d6 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:00:59 +0300 Subject: [PATCH 100/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/Review.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Review.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Review.java b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java new file mode 100644 index 00000000..9c0977d5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Review { + private long reviewId; + private String content; + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From 054f65596fa98157389521bc3889cf12d7040436 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:01:07 +0300 Subject: [PATCH 101/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dto/ReviewDto.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java new file mode 100644 index 00000000..7edbff53 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReviewDto { + private long reviewId; + @NotBlank(message = "Отзыв не может быть пустой.") + private String content; + @NotBlank(message = "Не указана полезность отзыва.") + private boolean isPositive; + private long useful; + private long userId; + private long filmId; +} From 439a1b1f65f13b8988c665b623afde8d9fa03ed6 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:03:55 +0300 Subject: [PATCH 102/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewMapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/mapper/ReviewMapper.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java new file mode 100644 index 00000000..e5256f4a --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -0,0 +1,31 @@ +package ru.yandex.practicum.filmorate.mapper; + +import lombok.experimental.UtilityClass; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; + +@UtilityClass +public class ReviewMapper { + + public static ReviewDto toDto(Review review) { + return ReviewDto.builder() + .reviewId(review.getReviewId()) + .content(review.getContent()) + .isPositive(review.isPositive()) + .useful(review.getUseful()) + .filmId(review.getFilmId()) + .userId(review.getUserId()) + .build(); + } + + public static Review toModel(ReviewDto reviewDto) { + return Review.builder() + .reviewId(reviewDto.getReviewId()) + .content(reviewDto.getContent()) + .isPositive(reviewDto.isPositive()) + .useful(reviewDto.getUseful()) + .filmId(reviewDto.getFilmId()) + .userId(reviewDto.getUserId()) + .build(); + } +} From 7ecb974a04f75f556f471fc3c69a9c559dc6eeeb Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:29:47 +0300 Subject: [PATCH 103/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20wrapper=20cl?= =?UTF-8?q?ass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dto/ReviewDto.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 7edbff53..731e61cb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; @Data @AllArgsConstructor @@ -13,11 +14,13 @@ @Builder public class ReviewDto { private long reviewId; - @NotBlank(message = "Отзыв не может быть пустой.") + @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; - @NotBlank(message = "Не указана полезность отзыва.") + @NotNull(message = "Не указана полезность отзыва.") private boolean isPositive; private long useful; - private long userId; - private long filmId; + @NotNull(message = "Не указан идентификатор пользователя.") + private Long userId; + @NotNull(message = "Не указан идентификатор фильма.") + private Long filmId; } From 29268290da426d593b26ef983f0f6a14abfcfff3 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:30:08 +0300 Subject: [PATCH 104/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20ReviewDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ReviewValidationTest.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java new file mode 100644 index 00000000..e97dcfe0 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/validation/ReviewValidationTest.java @@ -0,0 +1,106 @@ +package ru.yandex.practicum.filmorate.validation; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.VALIDATOR; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.dtoHasErrorMessage; + +public class ReviewValidationTest { + + @Test + @DisplayName("Проверка возможности добавить отзыв с корректными полями") + public void createReview() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(VALIDATOR.validate(reviewDto).isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", " "}) + @DisplayName("Проверка невозможности добавить отзыв с пустым полем content") + public void createReviewWithoutContent(String content) { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(content) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если content == null") + public void createReviewWithNullContent() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content(null) + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Содержание отзыва не может быть пустым.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан filmId") + public void createReviewWithNullFilmId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(null) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор фильма.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указан userId") + public void createReviewWithNullUserId() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(true) + .useful(1) + .filmId(1L) + .userId(null) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указан идентификатор пользователя.")); + } + + @Test + @DisplayName("Проверка невозможности добавить отзыв, если не указана полезность") + public void createReviewWithNullIsPositive() { + ReviewDto reviewDto = ReviewDto.builder() + .reviewId(1) + .content("content") + .isPositive(null) + .useful(1) + .filmId(1L) + .userId(1L) + .build(); + + assertTrue(dtoHasErrorMessage(reviewDto, "Не указана полезность отзыва.")); + } +} From 958704f973b3afcbb3908a2429ad9b6d9f79f8b8 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 09:35:07 +0300 Subject: [PATCH 105/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20Boolean=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20isPositive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java | 2 +- .../java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java index 731e61cb..200676ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/ReviewDto.java @@ -17,7 +17,7 @@ public class ReviewDto { @NotBlank(message = "Содержание отзыва не может быть пустым.") private String content; @NotNull(message = "Не указана полезность отзыва.") - private boolean isPositive; + private Boolean isPositive; private long useful; @NotNull(message = "Не указан идентификатор пользователя.") private Long userId; diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java index e5256f4a..d61c233f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/ReviewMapper.java @@ -22,7 +22,7 @@ public static Review toModel(ReviewDto reviewDto) { return Review.builder() .reviewId(reviewDto.getReviewId()) .content(reviewDto.getContent()) - .isPositive(reviewDto.isPositive()) + .isPositive(reviewDto.getIsPositive()) .useful(reviewDto.getUseful()) .filmId(reviewDto.getFilmId()) .userId(reviewDto.getUserId()) From beebd65119d79cc4d19e505effec80c5c7564b56 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:12 +0300 Subject: [PATCH 106/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index d6a6e230..ac4a2ccf 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -59,4 +59,15 @@ CREATE TABLE IF NOT EXISTS FILM_LIKE( CONSTRAINT pk_film_like PRIMARY KEY (FILM_ID, USER_ID), FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) +); + +CREATE TABLE IF NOT EXISTS REVIEW( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, + REVIEW_CONTENT CHARACTER VARYING(255) NOT NULL, + IS_POSITIVE BOOLEAN NOT NULL, + USEFUL INTEGER, + USER_ID INTEGER NOT NULL, + FILM_ID INTEGER NOT NULL, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ); \ No newline at end of file From def799778a8052aa6ca4470709192f6a81591ed0 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:24:56 +0300 Subject: [PATCH 107/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dao/ReviewStorage.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java new file mode 100644 index 00000000..441e2b3c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -0,0 +1,6 @@ +package ru.yandex.practicum.filmorate.dao; + +import ru.yandex.practicum.filmorate.model.Review; + +public interface ReviewStorage extends Dao{ +} From 4d1cea8e3b438aa297d2592ee31df754a77ac027 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:14 +0300 Subject: [PATCH 108/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java new file mode 100644 index 00000000..23705f20 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -0,0 +1,82 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Review; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Objects; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewDbStorage implements ReviewStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public Review add(final Review review) { + final KeyHolder keyHolder = new GeneratedKeyHolder(); + final String sql = "INSERT INTO review (review_content, is_positive, useful, user_id, film_id) VALUES (?, ?, ?, ?, ?)"; + jdbcTemplate.update(con -> { + PreparedStatement stmt = con.prepareStatement(sql, new String[]{"id"}); + stmt.setString(1, review.getContent()); + stmt.setBoolean(2, review.isPositive()); + stmt.setLong(3, review.getUseful()); + stmt.setLong(4, review.getUserId()); + stmt.setLong(5, review.getFilmId()); + return stmt; + }, keyHolder); + + review.setReviewId(Objects.requireNonNull(keyHolder.getKey(), "Не удалось добавить отзыв.").longValue()); + + return review; + } + + @Override + public void remove(final long id) { + + } + + @Override + public void update(final Review review) { + + } + + @Override + public Collection findAll() { + return null; + } + + @Override + public Review findById(final long id) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE ID = ?"; + try { + return jdbcTemplate.queryForObject(sql, this::mapReview, id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } + } + + private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + return Review.builder() + .reviewId(rs.getLong("id")) + .content(rs.getString("review_content")) + .isPositive(rs.getBoolean("is_positive")) + .useful(rs.getLong("useful")) + .userId(rs.getLong("user_id")) + .filmId(rs.getLong("film_id")) + .build(); + } +} From 70d374fee77c61c94e93c5817a8565ca75c02cd2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:31 +0300 Subject: [PATCH 109/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/ReviewService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java new file mode 100644 index 00000000..c84d3780 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -0,0 +1,10 @@ +package ru.yandex.practicum.filmorate.service; + + +import ru.yandex.practicum.filmorate.dto.ReviewDto; + +public interface ReviewService { + ReviewDto addReview(ReviewDto reviewDto); + + ReviewDto getReviewById(long id); +} From d7dedd4ed8dfeb21622eeeb6f0397d77e81915e7 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:25:44 +0300 Subject: [PATCH 110/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java new file mode 100644 index 00000000..beb330f4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; +import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ReviewServiceImpl implements ReviewService { + + private final ReviewStorage reviewStorage; + private final UserStorage userStorage; + private final FilmStorage filmStorage; + + + @Override + public ReviewDto addReview(final ReviewDto reviewDto) { + final Review review = toModel(reviewDto); + userStorage.findById(review.getUserId()); + filmStorage.findById(review.getFilmId()); + final Review addedReview = reviewStorage.add(review); + log.info("Добавлен новый отзыв: {}.", addedReview); + return toDto(reviewStorage.findById(addedReview.getReviewId())); + } + + @Override + public ReviewDto getReviewById(final long id) { + final Review review = reviewStorage.findById(id); + log.info("Найден отзыв с id '{}'.", id); + return toDto(review); + } + + +} From 1eab287fb493c893a26570342d63baf7953886e5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:26:00 +0300 Subject: [PATCH 111/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java new file mode 100644 index 00000000..0ede3d93 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -0,0 +1,65 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.service.ReviewService; + +import javax.validation.Valid; +import java.util.List; + +@RestController +@RequestMapping("/reviews") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { + return reviewService.addReview(reviewDto); + } + +// @PutMapping +// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { +// return reviewService.updateReview(updatedReviewDto); +// } +// +// @DeleteMapping("/{id}") +// public void deleteReview(@PathVariable long id) { +// reviewService.deleteReview(id); +// } +// + @GetMapping("/{id}") + public ReviewDto getReviewById(@PathVariable long id) { + return reviewService.getReviewById(id); + } +// +// @GetMapping +// public List getReviewsByFilmId(@RequestParam long filmId, +// @RequestParam(required = false, defaultValue = "10") int count) { +// return reviewService.getReviewsByFilmId(filmId, count); +// } +// +// @PutMapping("/{id}/like/{userId}") +// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addLikeToReview(id, userId); +// } +// +// @PutMapping("/{id}/dislike/{userId}") +// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { +// return reviewService.addDislikeToReview(id, userId); +// } +// +// @DeleteMapping("/{id}/like/{userId}") +// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteLikeFromReview(id, userId); +// } +// +// @DeleteMapping("/{id}/dislike/{userId}") +// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { +// reviewService.deleteDislikeFromReview(id, userId); +// } +} From e4f9596ca740681402b2b7ed00db55d100ef5854 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:30 +0300 Subject: [PATCH 112/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ON=20DELETE=20CASCADE=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20Review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index ac4a2ccf..5c6180e9 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -68,6 +68,6 @@ CREATE TABLE IF NOT EXISTS REVIEW( USEFUL INTEGER, USER_ID INTEGER NOT NULL, FILM_ID INTEGER NOT NULL, - FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID), - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE ); \ No newline at end of file From fc1e24203aeba4d3dec59d3398becb8324cba98a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 12:47:45 +0300 Subject: [PATCH 113/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 0ede3d93..b468f1be 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -22,10 +22,10 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { return reviewService.addReview(reviewDto); } -// @PutMapping -// public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { -// return reviewService.updateReview(updatedReviewDto); -// } + @PutMapping + public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { + return reviewService.updateReview(updatedReviewDto); + } // // @DeleteMapping("/{id}") // public void deleteReview(@PathVariable long id) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 23705f20..002db3ed 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -50,7 +50,13 @@ public void remove(final long id) { @Override public void update(final Review review) { - + final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + + "WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), + review.getReviewId()); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); + } } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c84d3780..c5b6e422 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -7,4 +7,6 @@ public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); ReviewDto getReviewById(long id); + + ReviewDto updateReview(ReviewDto updatedReviewDto); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index beb330f4..6aa530d8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -25,9 +25,8 @@ public class ReviewServiceImpl implements ReviewService { @Override public ReviewDto addReview(final ReviewDto reviewDto) { + findUserAndFilmInDb(reviewDto); final Review review = toModel(reviewDto); - userStorage.findById(review.getUserId()); - filmStorage.findById(review.getFilmId()); final Review addedReview = reviewStorage.add(review); log.info("Добавлен новый отзыв: {}.", addedReview); return toDto(reviewStorage.findById(addedReview.getReviewId())); @@ -40,5 +39,20 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { + findUserAndFilmInDb(updatedReviewDto); + final Review updatedReview = toModel(updatedReviewDto); + reviewStorage.update(updatedReview); + final long reviewId = updatedReview.getReviewId(); + log.info("Обновление отзыва с id '{}': {}", reviewId, updatedReview); + return toDto(reviewStorage.findById(reviewId)); + } + + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { + userStorage.findById(updatedReviewDto.getUserId()); + filmStorage.findById(updatedReviewDto.getFilmId()); + } + } From 9e020897432f021bff2347ef3e540c91ca27d783 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 13:18:41 +0300 Subject: [PATCH 114/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 12 ++++++------ .../filmorate/dao/impl/ReviewDbStorage.java | 3 ++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 7 +++++++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index b468f1be..920618de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -26,12 +26,12 @@ public ReviewDto addReview(@Valid @RequestBody ReviewDto reviewDto) { public ReviewDto updateReview(@Valid @RequestBody ReviewDto updatedReviewDto) { return reviewService.updateReview(updatedReviewDto); } -// -// @DeleteMapping("/{id}") -// public void deleteReview(@PathVariable long id) { -// reviewService.deleteReview(id); -// } -// + + @DeleteMapping("/{id}") + public void deleteReview(@PathVariable long id) { + reviewService.deleteReview(id); + } + @GetMapping("/{id}") public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 002db3ed..9c1c3fa1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -45,7 +45,8 @@ public Review add(final Review review) { @Override public void remove(final long id) { - + final String sql = "DELETE FROM review WHERE id = ?"; + jdbcTemplate.update(sql, id); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index c5b6e422..64a2329c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -9,4 +9,6 @@ public interface ReviewService { ReviewDto getReviewById(long id); ReviewDto updateReview(ReviewDto updatedReviewDto); + + void deleteReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6aa530d8..2184e3ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -49,6 +49,13 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + @Override + public void deleteReview(long id) { + reviewStorage.findById(id); + reviewStorage.remove(id); + log.info("Отзыв с id '{}' был удален.", id); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From e8285c167c667d39bbc64c3a888c43cb34ac193c Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:00:49 +0300 Subject: [PATCH 115/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20getReviewsByFilmId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 14 +++++++------- .../practicum/filmorate/dao/ReviewStorage.java | 5 ++++- .../filmorate/dao/impl/ReviewDbStorage.java | 10 +++++++++- .../practicum/filmorate/service/ReviewService.java | 4 ++++ .../filmorate/service/impl/ReviewServiceImpl.java | 14 +++++++++++++- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 920618de..f7571ae9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -36,13 +36,13 @@ public void deleteReview(@PathVariable long id) { public ReviewDto getReviewById(@PathVariable long id) { return reviewService.getReviewById(id); } -// -// @GetMapping -// public List getReviewsByFilmId(@RequestParam long filmId, -// @RequestParam(required = false, defaultValue = "10") int count) { -// return reviewService.getReviewsByFilmId(filmId, count); -// } -// + + @GetMapping + public List getReviewsByFilmId(@RequestParam long filmId, + @RequestParam(required = false, defaultValue = "10") int count) { + return reviewService.getReviewsByFilmId(filmId, count); + } + // @PutMapping("/{id}/like/{userId}") // public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { // return reviewService.addLikeToReview(id, userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 441e2b3c..5c198946 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -2,5 +2,8 @@ import ru.yandex.practicum.filmorate.model.Review; -public interface ReviewStorage extends Dao{ +import java.util.List; + +public interface ReviewStorage extends Dao { + List findByFilmIdLimitBy(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 9c1c3fa1..829980fd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -15,6 +15,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import java.util.Objects; @Repository @@ -76,7 +77,7 @@ public Review findById(final long id) { } } - private Review mapReview(ResultSet rs, int rowNum) throws SQLException { + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) .content(rs.getString("review_content")) @@ -86,4 +87,11 @@ private Review mapReview(ResultSet rs, int rowNum) throws SQLException { .filmId(rs.getLong("film_id")) .build(); } + + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 64a2329c..3ede2c4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -3,6 +3,8 @@ import ru.yandex.practicum.filmorate.dto.ReviewDto; +import java.util.List; + public interface ReviewService { ReviewDto addReview(ReviewDto reviewDto); @@ -11,4 +13,6 @@ public interface ReviewService { ReviewDto updateReview(ReviewDto updatedReviewDto); void deleteReview(long id); + + List getReviewsByFilmId(long filmId, int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 2184e3ee..fb25ee4d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -7,9 +7,13 @@ import ru.yandex.practicum.filmorate.dao.ReviewStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; +import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.service.ReviewService; +import java.util.List; +import java.util.stream.Collectors; + import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; @@ -50,12 +54,20 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { } @Override - public void deleteReview(long id) { + public void deleteReview(final long id) { reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } + @Override + public List getReviewsByFilmId(final long filmId, final int count) { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From 4e00d153689f9fde35635722dae29fffdb64e450 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:15:37 +0300 Subject: [PATCH 116/188] =?UTF-8?q?fix:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?useful=20=D0=BF=D1=80=D0=B8=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 829980fd..f47dd04c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -52,10 +52,8 @@ public void remove(final long id) { @Override public void update(final Review review) { - final String sql = "UPDATE review SET review_content = ?, is_positive = ?, useful = ? " + - "WHERE id = ?"; - final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getUseful(), - review.getReviewId()); + final String sql = "UPDATE review SET review_content = ?, is_positive = ? WHERE id = ?"; + final int update = jdbcTemplate.update(sql, review.getContent(), review.isPositive(), review.getReviewId()); if (update != 1) { throw new NotFoundException("Отзыв с id '" + review.getReviewId() + "' не найден."); } From daabff353a4be2e8de72ef2a0ac1126bd050ce60 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:21 +0300 Subject: [PATCH 117/188] =?UTF-8?q?refactor:=20=D0=97=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C=20filmId=20=D0=BD=D0=B0=20Long?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/ReviewController.java | 2 +- .../ru/yandex/practicum/filmorate/service/ReviewService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index f7571ae9..a9ad48ea 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -38,7 +38,7 @@ public ReviewDto getReviewById(@PathVariable long id) { } @GetMapping - public List getReviewsByFilmId(@RequestParam long filmId, + public List getReviewsByFilmId(@RequestParam(required = false) Long filmId, @RequestParam(required = false, defaultValue = "10") int count) { return reviewService.getReviewsByFilmId(filmId, count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 3ede2c4d..65117fd4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -14,5 +14,5 @@ public interface ReviewService { void deleteReview(long id); - List getReviewsByFilmId(long filmId, int count); + List getReviewsByFilmId(Long filmId, int count); } From 6d2691bfc074f3706a4f9bca1e3a3ae88a869974 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:16:46 +0300 Subject: [PATCH 118/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20findAllLimitBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 21 ++++++++++++------- .../service/impl/ReviewServiceImpl.java | 16 +++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 5c198946..f7569ae3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -6,4 +6,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); + + List findAllLimitBy(int count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index f47dd04c..8e89dac1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -75,6 +75,20 @@ public Review findById(final long id) { } } + @Override + public List findByFilmIdLimitBy(final long filmId, final int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, filmId, count); + } + + @Override + public List findAllLimitBy(int count) { + final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + + "FROM REVIEW LIMIT ?"; + return jdbcTemplate.query(sql, this::mapReview, count); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) @@ -85,11 +99,4 @@ private Review mapReview(final ResultSet rs, final int rowNum) throws SQLExcepti .filmId(rs.getLong("film_id")) .build(); } - - @Override - public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; - return jdbcTemplate.query(sql, this::mapReview, filmId, count); - } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index fb25ee4d..6e86573c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -61,11 +61,17 @@ public void deleteReview(final long id) { } @Override - public List getReviewsByFilmId(final long filmId, final int count) { - filmStorage.findById(filmId); - final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); - log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); - return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + public List getReviewsByFilmId(final Long filmId, final int count) { + if (filmId == null) { + final List reviews = reviewStorage.findAllLimitBy(count); + log.info("Запрос на получение отзывов."); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } else { + filmStorage.findById(filmId); + final List reviews = reviewStorage.findByFilmIdLimitBy(filmId, count); + log.info("Запрос на получение отзывов по фильму с id '{}'.", filmId); + return reviews.stream().map(ReviewMapper::toDto).collect(Collectors.toList()); + } } private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { From c7a2035a3b7750dfc446a0148eb67a97ba48d684 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:27:36 +0300 Subject: [PATCH 119/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addLikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 8 ++++---- .../yandex/practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../practicum/filmorate/dao/impl/ReviewDbStorage.java | 8 +++++++- .../practicum/filmorate/service/ReviewService.java | 2 ++ .../filmorate/service/impl/ReviewServiceImpl.java | 11 +++++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index a9ad48ea..97e2aede 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -43,10 +43,10 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f return reviewService.getReviewsByFilmId(filmId, count); } -// @PutMapping("/{id}/like/{userId}") -// public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addLikeToReview(id, userId); -// } + @PutMapping("/{id}/like/{userId}") + public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addLikeToReview(id, userId); + } // // @PutMapping("/{id}/dislike/{userId}") // public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index f7569ae3..e534405e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -8,4 +8,6 @@ public interface ReviewStorage extends Dao { List findByFilmIdLimitBy(long filmId, int count); List findAllLimitBy(int count); + + void addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8e89dac1..8091fad2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -83,12 +83,18 @@ public List findByFilmIdLimitBy(final long filmId, final int count) { } @Override - public List findAllLimitBy(int count) { + public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + "FROM REVIEW LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } + @Override + public void addLikeToReview(final long id, final long userId) { + final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index 65117fd4..e2ae9acc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -15,4 +15,6 @@ public interface ReviewService { void deleteReview(long id); List getReviewsByFilmId(Long filmId, int count); + + ReviewDto addLikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 6e86573c..57b15d64 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -74,10 +74,17 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + @Override + public ReviewDto addLikeToReview(final long id, final long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); } - - } From 1db8e6dc43931eb4ccce76f09f18b08eedee1f84 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:29:22 +0300 Subject: [PATCH 120/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D1=80=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D1=82=D0=B7=D1=8B?= =?UTF-8?q?=D0=B2=D1=8B=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B7?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 8091fad2..95c160ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -78,14 +78,14 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? LIMIT ?"; + "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW LIMIT ?"; + "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From f268b0383710c014d0ef2a1f6048f5df4644c5bc Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:33:16 +0300 Subject: [PATCH 121/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20addDislikeToReview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/ReviewController.java | 10 +++++----- .../practicum/filmorate/dao/ReviewStorage.java | 2 ++ .../filmorate/dao/impl/ReviewDbStorage.java | 6 ++++++ .../filmorate/service/ReviewService.java | 2 ++ .../service/impl/ReviewServiceImpl.java | 16 ++++++++++++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index 97e2aede..d403d135 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -47,11 +47,11 @@ public List getReviewsByFilmId(@RequestParam(required = false) Long f public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addLikeToReview(id, userId); } -// -// @PutMapping("/{id}/dislike/{userId}") -// public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { -// return reviewService.addDislikeToReview(id, userId); -// } + + @PutMapping("/{id}/dislike/{userId}") + public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.addDislikeToReview(id, userId); + } // // @DeleteMapping("/{id}/like/{userId}") // public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index e534405e..670325b5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -10,4 +10,6 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); void addLikeToReview(long id, long userId); + + void addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 95c160ff..97eeba6a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,6 +95,12 @@ public void addLikeToReview(final long id, final long userId) { jdbcTemplate.update(sql, id); } + @Override + public void addDislikeToReview(long id, long userId) { + final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + private Review mapReview(final ResultSet rs, final int rowNum) throws SQLException { return Review.builder() .reviewId(rs.getLong("id")) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index e2ae9acc..afdd9099 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -17,4 +17,6 @@ public interface ReviewService { List getReviewsByFilmId(Long filmId, int count); ReviewDto addLikeToReview(long id, long userId); + + ReviewDto addDislikeToReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 57b15d64..4f447606 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -76,13 +76,25 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { - reviewStorage.findById(id); - userStorage.findById(userId); + findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } + @Override + public ReviewDto addDislikeToReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + private void findReviewAndUserInDb(long id, long userId) { + reviewStorage.findById(id); + userStorage.findById(userId); + } + private void findUserAndFilmInDb(ReviewDto updatedReviewDto) { userStorage.findById(updatedReviewDto.getUserId()); filmStorage.findById(updatedReviewDto.getFilmId()); From c860ab1ab4c9c4ff3e3dcff8896355fa1b7741eb Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 14:37:08 +0300 Subject: [PATCH 122/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=B4=D0=B8=D0=B7=D0=BB=D0=B0=D0=B9=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 20 +++++++++---------- .../filmorate/service/ReviewService.java | 4 ++++ .../service/impl/ReviewServiceImpl.java | 18 ++++++++++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java index d403d135..c8a31fb5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -52,14 +52,14 @@ public ReviewDto addLikeToReview(@PathVariable long id, @PathVariable long userI public ReviewDto addDislikeToReview(@PathVariable long id, @PathVariable long userId) { return reviewService.addDislikeToReview(id, userId); } -// -// @DeleteMapping("/{id}/like/{userId}") -// public void deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteLikeFromReview(id, userId); -// } -// -// @DeleteMapping("/{id}/dislike/{userId}") -// public void deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { -// reviewService.deleteDislikeFromReview(id, userId); -// } + + @DeleteMapping("/{id}/like/{userId}") + public ReviewDto deleteLikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteLikeFromReview(id, userId); + } + + @DeleteMapping("/{id}/dislike/{userId}") + public ReviewDto deleteDislikeFromReview(@PathVariable long id, @PathVariable long userId) { + return reviewService.deleteDislikeFromReview(id, userId); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java index afdd9099..71f1acc7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -19,4 +19,8 @@ public interface ReviewService { ReviewDto addLikeToReview(long id, long userId); ReviewDto addDislikeToReview(long id, long userId); + + ReviewDto deleteLikeFromReview(long id, long userId); + + ReviewDto deleteDislikeFromReview(long id, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 4f447606..b10e843c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -86,7 +86,23 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); - log.info("Пользователь с id '{}' поставил дислайк отзыву с id '{}'", userId, id); + log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteLikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addDislikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); + return toDto(reviewStorage.findById(id)); + } + + @Override + public ReviewDto deleteDislikeFromReview(long id, long userId) { + findReviewAndUserInDb(id, userId); + reviewStorage.addLikeToReview(id, userId); + log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 4fd9b7e8d549679db32bb3ea5fe97b7d29dcfdcd Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:09 +0300 Subject: [PATCH 123/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D1=83=20=D0=BF=D0=BE=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/ReviewDbStorage.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 97eeba6a..1929eca8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -61,13 +61,15 @@ public void update(final Review review) { @Override public Collection findAll() { - return null; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id"; + return jdbcTemplate.query(sql, this::mapReview); } @Override public Review findById(final long id) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE ID = ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE id = ?"; try { return jdbcTemplate.queryForObject(sql, this::mapReview, id); } catch (EmptyResultDataAccessException e) { @@ -77,15 +79,15 @@ public Review findById(final long id) { @Override public List findByFilmIdLimitBy(final long filmId, final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW WHERE FILM_ID = ? ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review WHERE film_id = ? ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, filmId, count); } @Override public List findAllLimitBy(final int count) { - final String sql = "SELECT ID, REVIEW_CONTENT, IS_POSITIVE, USEFUL, USER_ID, FILM_ID " + - "FROM REVIEW ORDER BY USEFUL DESC LIMIT ?"; + final String sql = "SELECT id, review_content, is_positive, useful, user_id, film_id " + + "FROM review ORDER BY useful DESC, id LIMIT ?"; return jdbcTemplate.query(sql, this::mapReview, count); } From 40ebb6b8fbf9e2874d9a7f7b8de6712dbda23f6d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:26:30 +0300 Subject: [PATCH 124/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20ReviewDbStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/ReviewDbStorageTest.java | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java new file mode 100644 index 00000000..015d97e4 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -0,0 +1,305 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.FilmGenreDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.ReviewDbStorage; +import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@JdbcTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class ReviewDbStorageTest { + + private final JdbcTemplate jdbcTemplate; + + private ReviewStorage reviewStorage; + private FilmStorage filmStorage; + private UserStorage userStorage; + private Review review1; + private Review review2; + private Review review3; + private Review updatedReview; + private Film film; + private User user; + + @BeforeEach + public void setUp() { + reviewStorage = new ReviewDbStorage(jdbcTemplate); + FilmGenreStorage filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); + filmStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + userStorage = new UserDbStorage(jdbcTemplate); + Mpa mpa = new Mpa(1, "G"); + + film = Film.builder() + .id(1) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2020, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + + user = User.builder() + .id(1) + .email("email") + .login("login") + .name("name") + .birthday(LocalDate.now()) + .build(); + filmStorage.add(film); + userStorage.add(user); + + + review1 = Review.builder() + .reviewId(1) + .content("review 2") + .isPositive(true) + .useful(1) + .userId(1) + .filmId(1) + .build(); + + review2 = Review.builder() + .reviewId(2) + .content("review 1") + .isPositive(false) + .useful(2) + .userId(1) + .filmId(1) + .build(); + + review3 = Review.builder() + .reviewId(3) + .content("review 3") + .isPositive(true) + .useful(3) + .userId(1) + .filmId(1) + .build(); + + updatedReview = Review.builder() + .reviewId(1) + .content("updated review 1") + .isPositive(true) + .useful(13) + .userId(4) + .filmId(4) + .build(); + } + + @Test + @DisplayName("Тест добавления отзыва и получения по id.") + public void addAndGetByIdTest() { + reviewStorage.add(review1); + + Review savedReview = reviewStorage.findById(1); + + assertThat(savedReview) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест получения всех отзывов (сортировка по полезности).") + public void getAllReviews() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест получения всех отзывов без оценок полезности.") + public void getAllReviewsWithZeroUseful() { + review1.setUseful(0); + review2.setUseful(0); + review3.setUseful(0); + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review1, review2, review3)); + } + + @Test + @DisplayName("Тест получения всех отзывов при пустой базе данных.") + public void getAllReviewsEmptyDb() { + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(2); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2)); + } + + @Test + @DisplayName("Тест получения отзывов с ограничением по количеству.") + public void getAllReviewsLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findAllLimitBy(10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 1); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3)); + } + + @Test + @DisplayName("Тест получения отзывов по фильму с ограничением по количеству.") + public void getAllReviewsFromFilmLimitBy10() { + reviewStorage.add(review1); + reviewStorage.add(review2); + reviewStorage.add(review3); + Collection reviews = reviewStorage.findByFilmIdLimitBy(1, 10); + + assertThat(reviews) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(review3, review2, review1)); + } + + @Test + @DisplayName("Тест удаления отзыва.") + public void deleteReview() { + reviewStorage.add(review1); + reviewStorage.remove(1); + Collection reviews = reviewStorage.findAll(); + + assertThat(reviews) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Тест обновления отзыва. Обновиться должны только поля content, isPositive.") + public void updateReview() { + reviewStorage.add(review1); + reviewStorage.update(updatedReview); + + Review storedReview = reviewStorage.findById(1); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("content", "isPositive") + .isEqualTo(updatedReview); + + assertThat(storedReview) + .isNotNull() + .usingRecursiveComparison() + .comparingOnlyFields("useful", "filmId", "userId") + .isEqualTo(review1); + } + + @Test + @DisplayName("Тест добавления лайка отзыву.") + public void addLikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(2, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления лайка отзыву c отрицательным рейтингом.") + public void addLikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addLikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву.") + public void addDislikeToReview() { + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(0, storedReview.getUseful()); + } + + @Test + @DisplayName("Тест добавления дизлайка отзыву c отрицательным рейтингом.") + public void addDislikeToReviewNegativeUseful() { + review1.setUseful(-1); + reviewStorage.add(review1); + + reviewStorage.addDislikeToReview(1, 1); + Review storedReview = reviewStorage.findById(1); + assertEquals(-2, storedReview.getUseful()); + } + +} \ No newline at end of file From 051d3dccaa1831fc3b91fc158db06eef07a7d8ee Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 16:45:05 +0300 Subject: [PATCH 125/188] javadoc --- .../service/impl/ReviewServiceImpl.java | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index b10e843c..451cac2f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -26,7 +26,12 @@ public class ReviewServiceImpl implements ReviewService { private final UserStorage userStorage; private final FilmStorage filmStorage; - + /** + * Добавление отзыва в БД. + * + * @param reviewDto отзыв. + * @return отзыв с присвоенным идентификатором. + */ @Override public ReviewDto addReview(final ReviewDto reviewDto) { findUserAndFilmInDb(reviewDto); @@ -36,6 +41,12 @@ public ReviewDto addReview(final ReviewDto reviewDto) { return toDto(reviewStorage.findById(addedReview.getReviewId())); } + /** + * Получение отзыва по идентификатору. + * + * @param id идентификатор отзыва. + * @return найденный отзыв. + */ @Override public ReviewDto getReviewById(final long id) { final Review review = reviewStorage.findById(id); @@ -43,6 +54,12 @@ public ReviewDto getReviewById(final long id) { return toDto(review); } + /** + * Обновление данных отзыва. Происходит обновление только полей content и isPositive. + * + * @param updatedReviewDto отзыв с обновленными полями. + * @return обновленный отзыв. + */ @Override public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); @@ -53,6 +70,11 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { return toDto(reviewStorage.findById(reviewId)); } + /** + * Удаление отзыва из БД. + * + * @param id идентификатор отзыва. + */ @Override public void deleteReview(final long id) { reviewStorage.findById(id); @@ -60,6 +82,13 @@ public void deleteReview(final long id) { log.info("Отзыв с id '{}' был удален.", id); } + /** + * Получение списка отзывов о фильме. Если идентификатор фильма не был передан, то выводится список всех отзывов. + * + * @param filmId идентификатор фильма. + * @param count количество отзывов, которое требуется вывести. По умолчанию 10. + * @return список отзывов. + */ @Override public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { @@ -74,6 +103,13 @@ public List getReviewsByFilmId(final Long filmId, final int count) { } } + /** + * Добавление лайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит лайк. + * @return отзыв с добавленным лайком. + */ @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); @@ -82,6 +118,13 @@ public ReviewDto addLikeToReview(final long id, final long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Добавление дизлайка отзыву. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который ставит дизлайк. + * @return отзыв с добавленным дизлайком. + */ @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -90,6 +133,13 @@ public ReviewDto addDislikeToReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление лайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет лайк. + * @return отзыв с удаленным лайком. + */ @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); @@ -98,6 +148,13 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { return toDto(reviewStorage.findById(id)); } + /** + * Удаление дизлайка у отзыва. + * + * @param id идентификатор отзыва. + * @param userId идентификатор пользователя, который удаляет дизлайк. + * @return отзыв с удаленным дизлайком. + */ @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); From 6dea36e8b360b2fd89fd8eff0de35160403bb1c4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:46:41 +0300 Subject: [PATCH 126/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20review=5Flike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 5c6180e9..0dd39d0f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -70,4 +70,12 @@ CREATE TABLE IF NOT EXISTS REVIEW( FILM_ID INTEGER NOT NULL, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE, FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS REVIEW_LIKE( + REVIEW_ID INTEGER NOT NULL, + USER_ID INTEGER NOT NULL, + LIKE_TYPE CHARACTER VARYING(7) NOT NULL, + FOREIGN KEY (REVIEW_ID) REFERENCES REVIEW(ID) ON DELETE CASCADE, + FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE +); From eb59e2bec650e01da978ca38b3615453648c2cc5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:05 +0300 Subject: [PATCH 127/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java new file mode 100644 index 00000000..01d7ddac --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.dao; + +public interface ReviewLikeStorage { + void add(long reviewId, long userId, String type); + + void delete(long userId, String type); +} From 25e7e860a9c85d698c64e3cc0386e7c39782e2b5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:16 +0300 Subject: [PATCH 128/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/impl/ReviewLikeDbStorage.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java new file mode 100644 index 00000000..36c52158 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class ReviewLikeDbStorage implements ReviewLikeStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public void add(final long reviewId, final long userId, final String type) { + final String sql = "INSERT INTO review_like VALUES (?, ?, ?)"; + jdbcTemplate.update(sql, reviewId, userId, type); + } + + @Override + public void delete(final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId); + } +} From d4da16ff827f5e68dbd770756bf86bddba5f884b Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:30 +0300 Subject: [PATCH 129/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20enum=20ReviewLike?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java new file mode 100644 index 00000000..09b2d9e6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.model; + +public enum ReviewLike { + LIKE("like"), + DISLIKE("dislike"); + + private final String type; + + ReviewLike(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} From f760b0439649b570198c574d06a49f07c52635b6 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 17:47:52 +0300 Subject: [PATCH 130/188] =?UTF-8?q?feat:=20=D0=92=D0=BD=D0=B5=D0=B4=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ReviewLikeStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 451cac2f..88564f6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,12 +3,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -25,6 +24,7 @@ public class ReviewServiceImpl implements ReviewService { private final ReviewStorage reviewStorage; private final UserStorage userStorage; private final FilmStorage filmStorage; + private final ReviewLikeStorage reviewLikeStorage; /** * Добавление отзыва в БД. @@ -114,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,6 +130,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -144,6 +146,7 @@ public ReviewDto addDislikeToReview(long id, long userId) { public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -159,6 +162,7 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id, userId); + reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 3b01b62fb0a8d2f31555fa8f9e783fcd90ccc367 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:21 +0300 Subject: [PATCH 131/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D0=BF=D1=80=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 1929eca8..04b42d1a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -47,7 +47,10 @@ public Review add(final Review review) { @Override public void remove(final long id) { final String sql = "DELETE FROM review WHERE id = ?"; - jdbcTemplate.update(sql, id); + int update = jdbcTemplate.update(sql, id); + if (update != 1) { + throw new NotFoundException("Отзыв с id '" + id + "' не найден."); + } } @Override From e85bc8dce1a500c204b4b9275689362b6ecabb08 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:12:56 +0300 Subject: [PATCH 132/188] =?UTF-8?q?refactor:=20=D0=A3=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B8=D0=B7=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2=20userId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java index 04b42d1a..f57f25a8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewDbStorage.java @@ -95,13 +95,13 @@ public List findAllLimitBy(final int count) { } @Override - public void addLikeToReview(final long id, final long userId) { + public void addLikeToReview(final long id) { final String sql = "UPDATE review SET useful = useful + 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } @Override - public void addDislikeToReview(long id, long userId) { + public void addDislikeToReview(long id) { final String sql = "UPDATE review SET useful = useful - 1 WHERE id = ?"; jdbcTemplate.update(sql, id); } From 49cf73a50ac529dfa2d0a727c82aeeb30a507bdd Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:13:25 +0300 Subject: [PATCH 133/188] =?UTF-8?q?refactor:=20=D0=9D=D0=B5=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/model/ReviewLike.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java index 09b2d9e6..814fd757 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ReviewLike.java @@ -1,17 +1,6 @@ package ru.yandex.practicum.filmorate.model; public enum ReviewLike { - LIKE("like"), - DISLIKE("dislike"); - - private final String type; - - ReviewLike(String type) { - this.type = type; - } - - @Override - public String toString() { - return type; - } + LIKE, + DISLIKE; } From 1573821a2e139846f58db7c4181f55af116e252d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:01 +0300 Subject: [PATCH 134/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20reviewId=20=D0=B2=20delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/ReviewLikeStorage.java | 2 +- .../practicum/filmorate/dao/impl/ReviewLikeDbStorage.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java index 01d7ddac..90d6f0a0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewLikeStorage.java @@ -3,5 +3,5 @@ public interface ReviewLikeStorage { void add(long reviewId, long userId, String type); - void delete(long userId, String type); + void delete(long reviewId, long userId, String type); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java index 36c52158..26cd5a6f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/ReviewLikeDbStorage.java @@ -20,8 +20,8 @@ public void add(final long reviewId, final long userId, final String type) { } @Override - public void delete(final long userId, final String type) { - final String sql = "DELETE FROM review_like WHERE user_id = ? AND like_type = ?"; - jdbcTemplate.update(sql, userId); + public void delete(final long reviewId, final long userId, final String type) { + final String sql = "DELETE FROM review_like WHERE review_id = ? AND user_id = ? AND like_type = ?"; + jdbcTemplate.update(sql, userId, type); } } From 57df2301983280878a0a9ccf6ae222d68cff7002 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:14:35 +0300 Subject: [PATCH 135/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=20userId=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=20=D0=BB=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/ReviewStorage.java | 4 ++-- .../service/impl/ReviewServiceImpl.java | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java index 670325b5..a220dbfe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/ReviewStorage.java @@ -9,7 +9,7 @@ public interface ReviewStorage extends Dao { List findAllLimitBy(int count); - void addLikeToReview(long id, long userId); + void addLikeToReview(long id); - void addDislikeToReview(long id, long userId); + void addDislikeToReview(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 88564f6f..560c8d99 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -15,6 +15,7 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; +import static ru.yandex.practicum.filmorate.model.ReviewLike.*; @Service @RequiredArgsConstructor @@ -61,6 +62,7 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override + public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -77,7 +79,6 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { */ @Override public void deleteReview(final long id) { - reviewStorage.findById(id); reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); } @@ -113,8 +114,8 @@ public List getReviewsByFilmId(final Long filmId, final int count) { @Override public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.LIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.add(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' поставил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -129,8 +130,8 @@ public ReviewDto addLikeToReview(final long id, final long userId) { @Override public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.add(id, userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.add(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' поставил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -145,8 +146,8 @@ public ReviewDto addDislikeToReview(long id, long userId) { @Override public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addDislikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.LIKE.toString()); + reviewStorage.addDislikeToReview(id); + reviewLikeStorage.delete(id, userId, LIKE.toString()); log.info("Пользователь с id '{}' удалил лайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } @@ -161,8 +162,8 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { @Override public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); - reviewStorage.addLikeToReview(id, userId); - reviewLikeStorage.delete(userId, ReviewLike.DISLIKE.toString()); + reviewStorage.addLikeToReview(id); + reviewLikeStorage.delete(id, userId, DISLIKE.toString()); log.info("Пользователь с id '{}' удалил дизлайк отзыву с id '{}'", userId, id); return toDto(reviewStorage.findById(id)); } From 5143a1b6ddd39f6e43e4aa598f167271aa811b8d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:15:00 +0300 Subject: [PATCH 136/188] =?UTF-8?q?refactor:=20=D0=9F=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D1=8B=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 015d97e4..2168ed14 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview(1, 1); + reviewStorage.addLikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview(1, 1); + reviewStorage.addDislikeToReview( 1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From 001122f096cfdd8f3112b8e36ccee813c5f7c648 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:16:26 +0300 Subject: [PATCH 137/188] =?UTF-8?q?style:=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=B8=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/impl/ReviewServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 560c8d99..10decebe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,11 +3,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.FilmStorage; +import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; +import ru.yandex.practicum.filmorate.dao.ReviewStorage; +import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; -import ru.yandex.practicum.filmorate.model.ReviewLike; import ru.yandex.practicum.filmorate.service.ReviewService; import java.util.List; @@ -15,7 +17,8 @@ import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toDto; import static ru.yandex.practicum.filmorate.mapper.ReviewMapper.toModel; -import static ru.yandex.practicum.filmorate.model.ReviewLike.*; +import static ru.yandex.practicum.filmorate.model.ReviewLike.DISLIKE; +import static ru.yandex.practicum.filmorate.model.ReviewLike.LIKE; @Service @RequiredArgsConstructor From eb8a580c9c6274ac06890c1b2528be86a1ae9212 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Tue, 30 Jan 2024 22:19:55 +0300 Subject: [PATCH 138/188] checkstyle --- .../practicum/filmorate/storage/ReviewDbStorageTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 2168ed14..1224a75c 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -265,7 +265,7 @@ public void updateReview() { public void addLikeToReview() { reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(2, storedReview.getUseful()); } @@ -276,7 +276,7 @@ public void addLikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addLikeToReview( 1); + reviewStorage.addLikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -286,7 +286,7 @@ public void addLikeToReviewNegativeUseful() { public void addDislikeToReview() { reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(0, storedReview.getUseful()); } @@ -297,7 +297,7 @@ public void addDislikeToReviewNegativeUseful() { review1.setUseful(-1); reviewStorage.add(review1); - reviewStorage.addDislikeToReview( 1); + reviewStorage.addDislikeToReview(1); Review storedReview = reviewStorage.findById(1); assertEquals(-2, storedReview.getUseful()); } From 57925e0331d7ea4fd46b0e61a619473c5c8ec24d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 08:55:59 +0300 Subject: [PATCH 139/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Transactional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ReviewServiceImpl.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java index 10decebe..f2d08926 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/ReviewServiceImpl.java @@ -3,10 +3,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewLikeStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; +import org.springframework.transaction.annotation.Transactional; +import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dto.ReviewDto; import ru.yandex.practicum.filmorate.mapper.ReviewMapper; import ru.yandex.practicum.filmorate.model.Review; @@ -65,7 +63,6 @@ public ReviewDto getReviewById(final long id) { * @return обновленный отзыв. */ @Override - public ReviewDto updateReview(final ReviewDto updatedReviewDto) { findUserAndFilmInDb(updatedReviewDto); final Review updatedReview = toModel(updatedReviewDto); @@ -81,6 +78,7 @@ public ReviewDto updateReview(final ReviewDto updatedReviewDto) { * @param id идентификатор отзыва. */ @Override + @Transactional public void deleteReview(final long id) { reviewStorage.remove(id); log.info("Отзыв с id '{}' был удален.", id); @@ -94,6 +92,7 @@ public void deleteReview(final long id) { * @return список отзывов. */ @Override + @Transactional public List getReviewsByFilmId(final Long filmId, final int count) { if (filmId == null) { final List reviews = reviewStorage.findAllLimitBy(count); @@ -115,6 +114,7 @@ public List getReviewsByFilmId(final Long filmId, final int count) { * @return отзыв с добавленным лайком. */ @Override + @Transactional public ReviewDto addLikeToReview(final long id, final long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); @@ -131,6 +131,7 @@ public ReviewDto addLikeToReview(final long id, final long userId) { * @return отзыв с добавленным дизлайком. */ @Override + @Transactional public ReviewDto addDislikeToReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -142,11 +143,12 @@ public ReviewDto addDislikeToReview(long id, long userId) { /** * Удаление лайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет лайк. * @return отзыв с удаленным лайком. */ @Override + @Transactional public ReviewDto deleteLikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addDislikeToReview(id); @@ -158,11 +160,12 @@ public ReviewDto deleteLikeFromReview(long id, long userId) { /** * Удаление дизлайка у отзыва. * - * @param id идентификатор отзыва. + * @param id идентификатор отзыва. * @param userId идентификатор пользователя, который удаляет дизлайк. * @return отзыв с удаленным дизлайком. */ @Override + @Transactional public ReviewDto deleteDislikeFromReview(long id, long userId) { findReviewAndUserInDb(id, userId); reviewStorage.addLikeToReview(id); From 1dc80d4e8a81c314e751563856238ca03dc585f2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:42:58 +0300 Subject: [PATCH 140/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20findGenre?= =?UTF-8?q?sInIdList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/FilmGenreStorage.java | 4 +++ .../dao/impl/FilmGenreDbStorage.java | 28 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java index 98f6be09..9d7228bc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java @@ -3,12 +3,16 @@ import ru.yandex.practicum.filmorate.model.Genre; import java.util.List; +import java.util.Map; +import java.util.Set; public interface FilmGenreStorage { void add(long filmId, long genreId); List findAllById(long filmId); + Map> findGenresInIdList(Set filmIds); + void deleteAllById(long filmId); void batchUpdate(long filmId, List genres); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java index ec9e1b2e..5f247333 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao.impl; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -10,7 +11,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.List; +import java.util.*; @Repository @RequiredArgsConstructor @@ -31,6 +32,16 @@ public List findAllById(final long filmId) { return jdbcTemplate.query(sql, this::mapRowToLong, filmId); } + @Override + public Map> findGenresInIdList(Set filmIds) { + final String ids = String.join(",", Collections.nCopies(filmIds.size(), "?")); + final String sql = String.format( + "SELECT fg.film_id, fg.genre_id, g.genre_name FROM film_genre fg JOIN genre g ON fg.genre_id = g.id" + + " WHERE fg.film_id IN (%s)", ids); + + return jdbcTemplate.query(sql, this::extractToMap, filmIds.toArray()); + } + @Override public void deleteAllById(final long filmId) { final String sql = "DELETE FROM film_genre WHERE film_id = ?"; @@ -57,4 +68,19 @@ public int getBatchSize() { private Genre mapRowToLong(ResultSet rs, int rowNum) throws SQLException { return new Genre(rs.getInt("genre_id"), rs.getString("genre_name")); } + + private Map> extractToMap(ResultSet rs) throws SQLException, DataAccessException { + final Map> filmIdGenreMap = new HashMap<>(); + while (rs.next()) { + final Long filmId = rs.getLong(1); + List genres = filmIdGenreMap.get(filmId); + if (genres == null) { + genres = new ArrayList<>(); + } + final Genre genre = new Genre(rs.getInt("genre_id"), rs.getString("genre_name")); + genres.add(genre); + filmIdGenreMap.put(filmId, genres); + } + return filmIdGenreMap; + } } From 55693b23a180bb1d502536db903f7fcb9dc9cdbe Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:45:11 +0300 Subject: [PATCH 141/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20extractToFilmListWithoutGenres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 99 +++++++++---------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 976544b8..53406c73 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -19,6 +19,9 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; +import java.util.stream.Collectors; + +import static java.util.function.Function.identity; @Repository @RequiredArgsConstructor @@ -126,32 +129,8 @@ private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessExceptio final Map filmIdMap = new HashMap<>(); while (rs.next()) { - - Long filmId = rs.getLong(1); - film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } - - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - continue; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); + film = resultSetToFilm(rs, filmIdMap); + setGenresToFilm(rs, film); } return film; @@ -162,34 +141,52 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException, Da final Map filmIdMap = new LinkedHashMap<>(); while (rs.next()) { + Film film = resultSetToFilm(rs, filmIdMap); + setGenresToFilm(rs, film); + } + + return filmIdMap.values(); + } - Long filmId = rs.getLong(1); - Film film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } - - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - continue; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); + private void setGenresToFilm(ResultSet rs, Film film) throws SQLException { + final int genre_id = rs.getInt("genre_id"); + if (genre_id == 0) { + film.getGenres().addAll(Collections.emptyList()); + return; + } + + final Genre genre = new Genre(); + genre.setId(genre_id); + genre.setName(rs.getString("genre_name")); + film.getGenres().add(genre); + } + + private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { + + final Map filmIdMap = new LinkedHashMap<>(); + + while (rs.next()) { + resultSetToFilm(rs, filmIdMap); } return filmIdMap.values(); } + + private Film resultSetToFilm(ResultSet rs, Map filmIdMap) throws SQLException { + Long filmId = rs.getLong(1); + Film film = filmIdMap.get(filmId); + if (film == null) { + film = Film.builder() + .id(filmId) + .name(rs.getString("title")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) + .build(); + film.setLikes(rs.getLong("likes")); + filmIdMap.put(filmId, film); + } + return film; + } } From bfad941a4064448ed735810d67d620b5ea009261 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 20:45:42 +0300 Subject: [PATCH 142/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20findMostLikedFilmsLimitBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/FilmDbStorage.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 53406c73..6d4ab93d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -110,17 +110,19 @@ public Film findById(final long filmId) { public Collection findMostLikedFilmsLimitBy(final int count) { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + + "GROUP BY f.id, m.rating_name " + "ORDER BY COUNT(fl.USER_ID) DESC " + "LIMIT ?"; - return jdbcTemplate.query(sql, this::extractToFilmList, count); + Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); + Map> filmIdGenreMap = filmGenreStorage.findGenresInIdList(filmMap.keySet()); + filmIdGenreMap.forEach((id, genres) -> filmMap.get(id).getGenres().addAll(genres)); + return new ArrayList<>(filmMap.values()); } private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessException { From 3423a2638020047600f5ab222fdfbb264cc479ac Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:29:45 +0300 Subject: [PATCH 143/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20LinkedHashSe?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java | 5 ++--- src/main/java/ru/yandex/practicum/filmorate/model/Film.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java index d0be3ce7..ef3586f6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java @@ -13,8 +13,7 @@ import javax.validation.constraints.Positive; import javax.validation.constraints.Size; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; @Data @AllArgsConstructor @@ -31,6 +30,6 @@ public class FilmDto { @Positive(message = "Продолжительность должна быть больше нуля") private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг - private final List genres = new ArrayList<>(); //жанры + private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры private long likes; //количество лайков от пользователей } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 84932083..8d8afe8d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -7,8 +7,7 @@ import lombok.NoArgsConstructor; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; @Data @AllArgsConstructor @@ -21,6 +20,6 @@ public class Film { private LocalDate releaseDate; //дата релиза private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг - private final List genres = new ArrayList<>(); //жанры + private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры private long likes; //количество лайков от пользователей } From d90922160be2c76f24194c43c17beb05a060d6e2 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:30:23 +0300 Subject: [PATCH 144/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=B0=20Set=20=D0=B2=D0=BC?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=20List?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/dao/FilmGenreStorage.java | 2 +- .../practicum/filmorate/dao/impl/FilmGenreDbStorage.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java index 9d7228bc..109292ab 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmGenreStorage.java @@ -15,5 +15,5 @@ public interface FilmGenreStorage { void deleteAllById(long filmId); - void batchUpdate(long filmId, List genres); + void batchUpdate(long filmId, Set genres); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java index 5f247333..e9c49b0f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmGenreDbStorage.java @@ -49,13 +49,14 @@ public void deleteAllById(final long filmId) { } @Override - public void batchUpdate(final long filmId, final List genres) { - final String sql = "MERGE INTO film_genre (film_id, genre_id) VALUES (?, ?)"; + public void batchUpdate(final long filmId, final Set genres) { + final List genreList = new ArrayList<>(genres); + final String sql = "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)"; jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setLong(1, filmId); - ps.setLong(2, genres.get(i).getId()); + ps.setLong(2, genreList.get(i).getId()); } @Override From a27e02e21ecfd2bd3203fb3477d5f5b7b2ae480a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:32:08 +0300 Subject: [PATCH 145/188] =?UTF-8?q?refactor:=20=D0=9C=D0=B0=D0=BF=D0=BF?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B6=D0=B0=D0=BD=D1=80=D1=8B=20=D0=BE?= =?UTF-8?q?=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=BC=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 47 +++++-------------- .../filmorate/storage/FilmDbStorageTest.java | 25 ++++++++++ 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 6d4ab93d..aa17a600 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -76,16 +76,14 @@ public void update(final Film film) { @Override public Collection findAll() { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name"; - - return jdbcTemplate.query(sql, this::extractToFilmList); + "GROUP BY f.id, m.rating_name"; + Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres); + return setGenresForFilms(films); } @Override @@ -100,11 +98,14 @@ public Film findById(final long filmId) { "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + "HAVING f.ID = ?"; - final Film film = jdbcTemplate.query(sql, this::extractToFilm, filmId); + final Film film = jdbcTemplate.query(sql, this::extractToFilmWithoutGenres, filmId); if (film == null) { throw new NotFoundException("Фильм с id '" + filmId + "' не найден."); } + + List genres = filmGenreStorage.findAllById(filmId); + film.getGenres().addAll(genres); return film; } @@ -119,50 +120,28 @@ public Collection findMostLikedFilmsLimitBy(final int count) { "LIMIT ?"; Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + return setGenresForFilms(films); + } + + private List setGenresForFilms(Collection films) { Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); Map> filmIdGenreMap = filmGenreStorage.findGenresInIdList(filmMap.keySet()); filmIdGenreMap.forEach((id, genres) -> filmMap.get(id).getGenres().addAll(genres)); return new ArrayList<>(filmMap.values()); } - private Film extractToFilm(ResultSet rs) throws SQLException, DataAccessException { + private Film extractToFilmWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { Film film = null; final Map filmIdMap = new HashMap<>(); while (rs.next()) { film = resultSetToFilm(rs, filmIdMap); - setGenresToFilm(rs, film); } return film; } - private Collection extractToFilmList(ResultSet rs) throws SQLException, DataAccessException { - - final Map filmIdMap = new LinkedHashMap<>(); - - while (rs.next()) { - Film film = resultSetToFilm(rs, filmIdMap); - setGenresToFilm(rs, film); - } - - return filmIdMap.values(); - } - - private void setGenresToFilm(ResultSet rs, Film film) throws SQLException { - final int genre_id = rs.getInt("genre_id"); - if (genre_id == 0) { - film.getGenres().addAll(Collections.emptyList()); - return; - } - - final Genre genre = new Genre(); - genre.setId(genre_id); - genre.setName(rs.getString("genre_name")); - film.getGenres().add(genre); - } - private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { final Map filmIdMap = new LinkedHashMap<>(); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index dc0b4f96..d3819e01 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -286,4 +286,29 @@ void testFindByIdWithAllFields() { .usingRecursiveComparison() .isEqualTo(film); } + + @Test + @DisplayName("Тест на получение самых популярных фильмов с несколькими жанрами") + void testMostPopularFilmsWithSeveralGenres() { + Genre genre1 = new Genre(1, "Комедия"); + Genre genre2 = new Genre(6, "Боевик"); + Genre genre3 = new Genre(2, "Драма"); + + userStorage.add(user); + film.getGenres().add(genre1); + film.getGenres().add(genre2); + film.getGenres().add(genre3); + filmDbStorage.add(film); + filmLikeStorage.add(film.getId(),user.getId()); + filmDbStorage.add(updatedFilm); + + film.setLikes(1); + + Collection popularFilms = filmDbStorage.findMostLikedFilmsLimitBy(1); + + assertThat(popularFilms) + .isNotNull() + .isNotEmpty() + .isEqualTo(List.of(film)); + } } From 69894fa9a1a403e1bd692241ffe81842c65b6325 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 22:43:02 +0300 Subject: [PATCH 146/188] =?UTF-8?q?feat:=20=D0=98=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20mapToFilm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 73 ++++++------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index aa17a600..7ba8ef3f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; @@ -82,31 +82,28 @@ public Collection findAll() { "LEFT JOIN film_like fl on f.id = fl.film_id " + "GROUP BY f.id, m.rating_name"; - Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres); + Collection films = jdbcTemplate.query(sql, this::mapToFilm); return setGenresForFilms(films); } @Override public Film findById(final long filmId) { final String sql = "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, fg.GENRE_ID, g.GENRE_NAME, COUNT(fl.USER_ID) AS likes " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + "FROM " + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN FILM_GENRE fg ON f.ID = fg.FILM_ID " + - "LEFT JOIN GENRE g ON fg.GENRE_ID = g.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name, fg.genre_id, g.genre_name " + + "GROUP BY f.id, m.rating_name " + "HAVING f.ID = ?"; - final Film film = jdbcTemplate.query(sql, this::extractToFilmWithoutGenres, filmId); - - if (film == null) { + try { + final Film film = jdbcTemplate.queryForObject(sql, this::mapToFilm, filmId); + List genres = filmGenreStorage.findAllById(filmId); + film.getGenres().addAll(genres); + return film; + } catch (EmptyResultDataAccessException e) { throw new NotFoundException("Фильм с id '" + filmId + "' не найден."); } - - List genres = filmGenreStorage.findAllById(filmId); - film.getGenres().addAll(genres); - return film; } public Collection findMostLikedFilmsLimitBy(final int count) { @@ -119,7 +116,7 @@ public Collection findMostLikedFilmsLimitBy(final int count) { "ORDER BY COUNT(fl.USER_ID) DESC " + "LIMIT ?"; - Collection films = jdbcTemplate.query(sql, this::extractToFilmListWithoutGenres, count); + Collection films = jdbcTemplate.query(sql, this::mapToFilm, count); return setGenresForFilms(films); } @@ -130,44 +127,16 @@ private List setGenresForFilms(Collection films) { return new ArrayList<>(filmMap.values()); } - private Film extractToFilmWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { - - Film film = null; - final Map filmIdMap = new HashMap<>(); - - while (rs.next()) { - film = resultSetToFilm(rs, filmIdMap); - } - - return film; - } - - private Collection extractToFilmListWithoutGenres(ResultSet rs) throws SQLException, DataAccessException { - - final Map filmIdMap = new LinkedHashMap<>(); - - while (rs.next()) { - resultSetToFilm(rs, filmIdMap); - } - - return filmIdMap.values(); - } - - private Film resultSetToFilm(ResultSet rs, Map filmIdMap) throws SQLException { - Long filmId = rs.getLong(1); - Film film = filmIdMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("title")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) - .build(); - film.setLikes(rs.getLong("likes")); - filmIdMap.put(filmId, film); - } + private Film mapToFilm(ResultSet rs, int rowNum) throws SQLException { + Film film = Film.builder() + .id(rs.getLong(1)) + .name(rs.getString("title")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) + .build(); + film.setLikes(rs.getLong("likes")); return film; } } From d833d00aae7cdec1585c5ae9e787ac12f92ef43b Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Wed, 31 Jan 2024 23:13:03 +0300 Subject: [PATCH 147/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ID=20=D0=B4=D0=BB=D1=8F=20FILM=5FGENRE=20?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D1=82=D1=8C=20=D1=83?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=B8?= =?UTF-8?q?=D0=BD=D0=B4=D0=B5=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0dd39d0f..ac2b7abe 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -22,13 +22,15 @@ CREATE TABLE IF NOT EXISTS FILM( CREATE TABLE IF NOT EXISTS FILM_GENRE( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, FILM_ID INTEGER NOT NULL, GENRE_ID INTEGER NOT NULL, - CONSTRAINT pk_film_genre PRIMARY KEY (FILM_ID, GENRE_ID), FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), FOREIGN KEY (GENRE_ID) REFERENCES GENRE(ID) ); +CREATE UNIQUE INDEX FILM_GENRE_IDX ON FILM_GENRE (ID, FILM_ID, GENRE_ID); + CREATE TABLE IF NOT EXISTS FILMORATE_USER( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, EMAIL CHARACTER VARYING(255) NOT NULL, From dccdb3985f8046ea69949c69e50d889e72f9ddb5 Mon Sep 17 00:00:00 2001 From: Elena Date: Thu, 1 Feb 2024 14:26:47 +0400 Subject: [PATCH 148/188] fix: moved extracting users-likes map to FilmLikeStorage, refractored method for users-like map --- .../filmorate/dao/FilmLikeStorage.java | 3 ++ .../practicum/filmorate/dao/FilmStorage.java | 3 ++ .../practicum/filmorate/dao/UserStorage.java | 4 -- .../filmorate/dao/impl/FilmDbStorage.java | 15 ++++++ .../filmorate/dao/impl/FilmLikeDbStorage.java | 24 +++++++++- .../filmorate/dao/impl/UserDbStorage.java | 27 +---------- .../service/impl/UserServiceImpl.java | 13 ++---- .../filmorate/storage/FilmDbStorageTest.java | 2 +- .../filmorate/storage/UserDbStorageTest.java | 46 +++++-------------- 9 files changed, 62 insertions(+), 75 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java index 2e8202e1..2962843e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao; import java.util.Map; +import java.util.Set; public interface FilmLikeStorage { void add(long filmId, long userId); @@ -10,4 +11,6 @@ public interface FilmLikeStorage { Map findAll(); void remove(long filmId, long userId); + + Map> usersAndFilmLikes(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index 19d28a99..d484609a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -3,7 +3,10 @@ import ru.yandex.practicum.filmorate.model.Film; import java.util.Collection; +import java.util.Set; public interface FilmStorage extends Dao { Collection findMostLikedFilmsLimitBy(int count); + + Collection findFilmsByIds(Set filmIds); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java index 0f94cb99..1b989bb9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserStorage.java @@ -3,14 +3,10 @@ import ru.yandex.practicum.filmorate.model.User; import java.util.Collection; -import java.util.Map; -import java.util.Set; public interface UserStorage extends Dao { Collection findFriendsByUserId(long userId); Collection findCommonFriends(long userId, long anotherUserId); - - Map> showRecommendations(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 7ba8ef3f..26717840 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -120,6 +120,21 @@ public Collection findMostLikedFilmsLimitBy(final int count) { return setGenresForFilms(films); } + public Collection findFilmsByIds(Set filmIds) { + final String ids = String.join(",", Collections.nCopies(filmIds.size(), "?")); + final String sql = String.format( + "SELECT " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + + "FROM " + + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + + "LEFT JOIN film_like fl on f.id = fl.film_id " + + "WHERE f.ID IN (%s)" + + "GROUP BY f.id, m.rating_name ", ids); + + Collection films = jdbcTemplate.query(sql, this::mapToFilm, filmIds.toArray()); + return setGenresForFilms(films); + } + private List setGenresForFilms(Collection films) { Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); Map> filmIdGenreMap = filmGenreStorage.findGenresInIdList(filmMap.keySet()); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 07d0a770..21f680f0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -9,8 +10,7 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; @Repository @RequiredArgsConstructor @@ -56,4 +56,24 @@ private Map mapRowToIdCount(ResultSet rs) throws SQLException { } return result; } + + @Override + public Map> usersAndFilmLikes() { + String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; + return jdbcTemplate.query(filmsIdsSql, this::extractToMap); + } + + private Map> extractToMap(ResultSet rs) throws SQLException, DataAccessException { + final Map> userFilmLikesMap = new HashMap<>(); + while (rs.next()) { + final Long userId = rs.getLong("user_id"); + Set filmLikes = userFilmLikesMap.get(userId); + if (filmLikes == null) { + filmLikes = new HashSet<>(); + } + filmLikes.add(rs.getLong("film_id")); + userFilmLikesMap.put(userId, filmLikes); + } + return userFilmLikesMap; + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java index ca8e75a8..16d3fe20 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/UserDbStorage.java @@ -7,11 +7,11 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.User; + import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -24,7 +24,6 @@ public class UserDbStorage implements UserStorage { private final JdbcTemplate jdbcTemplate; - private final FilmStorage filmDbStorage; @Override public User add(final User user) { @@ -110,30 +109,6 @@ public Collection findCommonFriends(final long userId, final long anotherU return jdbcTemplate.query(sql, this::extractToUserList, userId, anotherUserId); } - @Override - public Map> showRecommendations() { - String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; - List> userLikedFilms = jdbcTemplate.query(filmsIdsSql, (resultSet, rowNum) -> { - List likes = new ArrayList<>(); - likes.add(resultSet.getLong("user_id")); - likes.add(resultSet.getLong("film_id")); - return likes; - }); - Map> result = new HashMap<>(); - for (List userLikes : userLikedFilms) { - if (result.get(userLikes.get(0)) == null) { - Set films = new HashSet<>(); - films.add((Long) userLikes.get(1)); - result.put((Long) userLikes.get(0), films); - } else { - Set films = result.get(userLikes.get(0)); - films.add((Long) userLikes.get(1)); - result.put((Long) userLikes.get(0), films); - } - } - return result; - } - private User extractToUser(ResultSet rs) throws SQLException, DataAccessException { User user = null; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index ca2f0c78..916853a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FilmLikeStorage; import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.FriendshipStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; @@ -27,9 +28,9 @@ public class UserServiceImpl implements UserService { private final UserStorage userStorage; - private final FilmStorage filmDbStorage; - + private final FilmStorage filmStorage; private final FriendshipStorage friendshipStorage; + private final FilmLikeStorage filmLikeStorage; /** * Сохранение пользователя в БД. @@ -168,8 +169,7 @@ public void removeFriend(final long userId, final long friendId) { @Override public Collection showRecommendations(long id) { log.info("Получение списка рекомендаций фильмов для пользователя с id {}.", id); - - Map> usersLikes = userStorage.showRecommendations(); + Map> usersLikes = filmLikeStorage.usersAndFilmLikes(); int maxLikes = 0; Set recommendations = new HashSet<>(); Set userLikedFilms = usersLikes.get(id); @@ -189,10 +189,7 @@ public Collection showRecommendations(long id) { } } } - Collection filmsRecommendation = new ArrayList<>(); - for (Long filmId : recommendations) { - filmsRecommendation.add(filmDbStorage.findById(filmId)); - } + Collection filmsRecommendation = filmStorage.findFilmsByIds(recommendations); return filmsRecommendation.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index d3819e01..ea975e1e 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -50,7 +50,7 @@ public void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); - userStorage = new UserDbStorage(jdbcTemplate, filmDbStorage); + userStorage = new UserDbStorage(jdbcTemplate); Mpa mpa = new Mpa(1, "G"); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index ade1b589..876b475e 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -11,7 +11,6 @@ import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.mapper.FilmMapper; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Friendship; import ru.yandex.practicum.filmorate.model.Mpa; @@ -19,9 +18,7 @@ import ru.yandex.practicum.filmorate.service.impl.UserServiceImpl; import java.time.LocalDate; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; +import java.util.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -54,9 +51,9 @@ void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); - userStorage = new UserDbStorage(jdbcTemplate, filmDbStorage); + userStorage = new UserDbStorage(jdbcTemplate); friendshipStorage = new FriendshipDbStorage(jdbcTemplate); - userService = new UserServiceImpl(userStorage, filmDbStorage, friendshipStorage); + userService = new UserServiceImpl(userStorage, filmDbStorage, friendshipStorage, filmLikeStorage); user = User.builder() .id(1) .email("email") @@ -349,7 +346,7 @@ void testGetEmptyFriendsList() { } @Test - @DisplayName("Тест получения списка рекомендаций фильмов, когда рекомендации есть.") + @DisplayName("Тест получения мапы с ключами userId и сетом с списком айдишников залайканных фильмов.") void testGetRecommendationsList() { userStorage.add(user); userStorage.add(anotherUser); @@ -361,46 +358,27 @@ void testGetRecommendationsList() { filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); filmLikeStorage.add(filmTwo.getId(), anotherUser.getId()); - Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() - .map(FilmMapper::toModel).collect(Collectors.toList()); + Map> filmRecommendations = filmLikeStorage.usersAndFilmLikes(); - filmTwo.setLikes(1); - - assertThat(filmRecommendations) + assertThat(filmRecommendations.get(new Long(1))) .isNotNull() .isNotEmpty() - .containsExactlyElementsOf(List.of(filmTwo)); - } - - @Test - @DisplayName("Тест получения списка рекомендаций фильмов, когда лайки совпадают.") - void testGetRecommendationsListSimilarLikes() { - userStorage.add(user); - userStorage.add(anotherUser); - - filmDbStorage.add(filmOne); + .containsExactlyElementsOf(Set.of(filmOne.getId())); - filmLikeStorage.add(filmOne.getId(), user.getId()); - filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); - - Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() - .map(FilmMapper::toModel).collect(Collectors.toList()); - - assertThat(filmRecommendations) + assertThat(filmRecommendations.get(new Long(2))) .isNotNull() - .isEmpty(); + .isNotEmpty() + .containsExactlyElementsOf(Set.of(filmOne.getId(), filmTwo.getId())); } @Test - @DisplayName("Тест получения списка рекомендаций фильмов, когда лайков еще нет.") + @DisplayName("Тест получения мапы с ключами userId и сетом с списком айдишников залайканных фильмов, когда лайков нет.") void testGetRecommendationsListNoLikes() { userStorage.add(user); userStorage.add(anotherUser); - filmDbStorage.add(filmOne); - Collection filmRecommendations = userService.showRecommendations(user.getId()).stream() - .map(FilmMapper::toModel).collect(Collectors.toList()); + Map> filmRecommendations = filmLikeStorage.usersAndFilmLikes(); assertThat(filmRecommendations) .isNotNull() From d6740bf5e4f394bc7ec54450492ae105abcf25d7 Mon Sep 17 00:00:00 2001 From: Elena Date: Thu, 1 Feb 2024 16:08:19 +0400 Subject: [PATCH 149/188] fix: moved extracting users-likes map to FilmLikeStorage, refractored method for users-like map --- .../practicum/filmorate/dao/FilmLikeStorage.java | 2 +- .../filmorate/dao/impl/FilmLikeDbStorage.java | 12 ++++++------ .../filmorate/service/impl/UserServiceImpl.java | 2 +- .../filmorate/storage/UserDbStorageTest.java | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java index 2962843e..7c693e7d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java @@ -12,5 +12,5 @@ public interface FilmLikeStorage { void remove(long filmId, long userId); - Map> usersAndFilmLikes(); + Map> getUsersAndFilmLikes(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 21f680f0..cbdf1c5e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -49,6 +49,12 @@ public void remove(long filmId, long userId) { jdbcTemplate.update(sql, filmId, userId); } + @Override + public Map> getUsersAndFilmLikes() { + String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; + return jdbcTemplate.query(filmsIdsSql, this::extractToMap); + } + private Map mapRowToIdCount(ResultSet rs) throws SQLException { final Map result = new LinkedHashMap<>(); while (rs.next()) { @@ -57,12 +63,6 @@ private Map mapRowToIdCount(ResultSet rs) throws SQLException { return result; } - @Override - public Map> usersAndFilmLikes() { - String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; - return jdbcTemplate.query(filmsIdsSql, this::extractToMap); - } - private Map> extractToMap(ResultSet rs) throws SQLException, DataAccessException { final Map> userFilmLikesMap = new HashMap<>(); while (rs.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java index 916853a7..d8409e99 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/UserServiceImpl.java @@ -169,7 +169,7 @@ public void removeFriend(final long userId, final long friendId) { @Override public Collection showRecommendations(long id) { log.info("Получение списка рекомендаций фильмов для пользователя с id {}.", id); - Map> usersLikes = filmLikeStorage.usersAndFilmLikes(); + Map> usersLikes = filmLikeStorage.getUsersAndFilmLikes(); int maxLikes = 0; Set recommendations = new HashSet<>(); Set userLikedFilms = usersLikes.get(id); diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 876b475e..1f2558ca 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -358,14 +358,14 @@ void testGetRecommendationsList() { filmLikeStorage.add(filmOne.getId(), anotherUser.getId()); filmLikeStorage.add(filmTwo.getId(), anotherUser.getId()); - Map> filmRecommendations = filmLikeStorage.usersAndFilmLikes(); + Map> filmRecommendations = filmLikeStorage.getUsersAndFilmLikes(); - assertThat(filmRecommendations.get(new Long(1))) + assertThat(filmRecommendations.get(1L)) .isNotNull() .isNotEmpty() .containsExactlyElementsOf(Set.of(filmOne.getId())); - assertThat(filmRecommendations.get(new Long(2))) + assertThat(filmRecommendations.get(2L)) .isNotNull() .isNotEmpty() .containsExactlyElementsOf(Set.of(filmOne.getId(), filmTwo.getId())); @@ -378,7 +378,7 @@ void testGetRecommendationsListNoLikes() { userStorage.add(anotherUser); filmDbStorage.add(filmOne); - Map> filmRecommendations = filmLikeStorage.usersAndFilmLikes(); + Map> filmRecommendations = filmLikeStorage.getUsersAndFilmLikes(); assertThat(filmRecommendations) .isNotNull() From f271f6c53b9aadff4ee759fb85184920eee124af Mon Sep 17 00:00:00 2001 From: Elena Date: Thu, 1 Feb 2024 16:17:06 +0400 Subject: [PATCH 150/188] fix: moved extracting users-likes map to FilmLikeStorage, refractored method for users-like map --- .../yandex/practicum/filmorate/storage/UserDbStorageTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index 1f2558ca..34e669af 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -363,12 +363,12 @@ void testGetRecommendationsList() { assertThat(filmRecommendations.get(1L)) .isNotNull() .isNotEmpty() - .containsExactlyElementsOf(Set.of(filmOne.getId())); + .containsExactly(filmOne.getId()); assertThat(filmRecommendations.get(2L)) .isNotNull() .isNotEmpty() - .containsExactlyElementsOf(Set.of(filmOne.getId(), filmTwo.getId())); + .containsExactly(filmOne.getId(), filmTwo.getId()); } @Test From 52341fe0c3fe315293125fde742850d0deafc328 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 10:26:52 +0300 Subject: [PATCH 151/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20Director,=20dto=20=D0=B8=20mapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dto/DirectorDto.java | 19 +++++++++++++++ .../filmorate/mapper/DirectorMapper.java | 23 +++++++++++++++++++ .../practicum/filmorate/model/Director.java | 16 +++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dto/DirectorDto.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Director.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/DirectorDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/DirectorDto.java new file mode 100644 index 00000000..6062a71c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/DirectorDto.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DirectorDto { + + long id; + @NotBlank(message = "Имя режиссера не может быть пустым.") + String name; +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java new file mode 100644 index 00000000..5e69c5ba --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.mapper; + +import lombok.experimental.UtilityClass; +import ru.yandex.practicum.filmorate.dto.DirectorDto; +import ru.yandex.practicum.filmorate.model.Director; + +@UtilityClass +public class DirectorMapper { + + public static DirectorDto toDto(Director director) { + return DirectorDto.builder() + .id(director.getId()) + .name(director.getName()) + .build(); + } + + public static Director toDto(DirectorDto directorDto) { + return Director.builder() + .id(directorDto.getId()) + .name(directorDto.getName()) + .build(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java new file mode 100644 index 00000000..589d535d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -0,0 +1,16 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Director { + + long id; + String name; +} From dd4fa95bee7c44f081dcb3990d2bae6379bbb0c0 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 10:29:42 +0300 Subject: [PATCH 152/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20Director?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/DirectorValidationTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/validation/DirectorValidationTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/validation/DirectorValidationTest.java b/src/test/java/ru/yandex/practicum/filmorate/validation/DirectorValidationTest.java new file mode 100644 index 00000000..106fd51b --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/validation/DirectorValidationTest.java @@ -0,0 +1,50 @@ +package ru.yandex.practicum.filmorate.validation; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.yandex.practicum.filmorate.dto.DirectorDto; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.VALIDATOR; +import static ru.yandex.practicum.filmorate.validation.ValidationTestUtils.dtoHasErrorMessage; + +public class DirectorValidationTest { + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", " "}) + @DisplayName("Проверка невозможности добавить режиссера с пустым именем") + public void createDirectorWithoutName(String name) { + DirectorDto directorDto = DirectorDto.builder() + .id(1) + .name(name) + .build(); + + assertTrue(dtoHasErrorMessage(directorDto, "Имя режиссера не может быть пустым.")); + + } + + @Test + @DisplayName("Проверка невозможности добавить режиссера, если name == null") + public void createDirectorWithNullName() { + DirectorDto directorDto = DirectorDto.builder() + .id(1) + .name(null) + .build(); + + assertTrue(dtoHasErrorMessage(directorDto, "Имя режиссера не может быть пустым.")); + } + + @Test + @DisplayName("Проверка добавления режиссера с валидными полями.") + public void createDirector() { + DirectorDto directorDto = DirectorDto.builder() + .id(1) + .name("Director") + .build(); + assertTrue(VALIDATOR.validate(directorDto).isEmpty()); + } +} + + From 1f3d51fba51c4ca71e9454f1e35f4676963df646 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 10:30:13 +0300 Subject: [PATCH 153/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B8=D1=81=D1=81=D0=B5=D1=80=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java | 2 ++ .../java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java | 2 ++ src/main/java/ru/yandex/practicum/filmorate/model/Film.java | 1 + 3 files changed, 5 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java index ef3586f6..72262ce2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java @@ -5,6 +5,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.validation.PastDate; @@ -31,5 +32,6 @@ public class FilmDto { private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры + private final LinkedHashSet directors = new LinkedHashSet<>(); //режиссеры private long likes; //количество лайков от пользователей } diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java index d39d56c6..be8a94f5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java @@ -18,6 +18,7 @@ public static FilmDto toDto(Film film) { .likes(film.getLikes()) .build(); filmDto.getGenres().addAll(film.getGenres()); + filmDto.getDirectors().addAll(film.getDirectors()); return filmDto; } @@ -32,6 +33,7 @@ public static Film toModel(FilmDto filmDto) { .likes(filmDto.getLikes()) .build(); film.getGenres().addAll(filmDto.getGenres()); + film.getDirectors().addAll(filmDto.getDirectors()); return film; } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 8d8afe8d..f5358805 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -21,5 +21,6 @@ public class Film { private int duration; //продолжительность фильма private Mpa mpa; //возрастной рейтинг private final LinkedHashSet genres = new LinkedHashSet<>(); //жанры + private final LinkedHashSet directors = new LinkedHashSet<>(); //режиссеры private long likes; //количество лайков от пользователей } From dce6ca355425620fface66d59965f308e24d03c5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 10:34:55 +0300 Subject: [PATCH 154/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20Dir?= =?UTF-8?q?ector,=20FILM=5FDIRECTOR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 6a041060..9e7675da 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE; +DROP TABLE IF EXISTS GENRE, MPA, FILM, FILM_GENRE, FILMORATE_USER, FRIENDSHIP_STATUS, FRIENDSHIP, FILM_LIKE, REVIEW, REVIEW_LIKE, DIRECTOR, FILM_DIRECTOR; CREATE TABLE IF NOT EXISTS GENRE( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, @@ -81,3 +81,19 @@ CREATE TABLE IF NOT EXISTS REVIEW_LIKE( FOREIGN KEY (REVIEW_ID) REFERENCES REVIEW(ID) ON DELETE CASCADE, FOREIGN KEY (USER_ID) REFERENCES FILMORATE_USER(ID) ON DELETE CASCADE ); + +CREATE TABLE IF NOT EXISTS DIRECTOR( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, + DIRECTOR_NAME CHARACTER VARYING(255) NOT NULL +); + +CREATE TABLE IF NOT EXISTS FILM_DIRECTOR( + ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, + FILM_ID INTEGER NOT NULL, + DIRECTOR_ID INTEGER NOT NULL, + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), + FOREIGN KEY (DIRECTOR_ID) REFERENCES DIRECTOR(ID) +); + +CREATE UNIQUE INDEX FILM_DIRECTOR_IDX ON FILM_DIRECTOR (ID, FILM_ID, DIRECTOR_ID); + From d70c4d47f56ac2cf2393f5bc1e1a68e5909fa13b Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:25:55 +0300 Subject: [PATCH 155/188] =?UTF-8?q?fix:=20=D0=9F=D0=B5=D1=80=D0=B5=D0=B8?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20toModel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/mapper/DirectorMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java index 5e69c5ba..693e4a76 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/DirectorMapper.java @@ -14,7 +14,7 @@ public static DirectorDto toDto(Director director) { .build(); } - public static Director toDto(DirectorDto directorDto) { + public static Director toModel(DirectorDto directorDto) { return Director.builder() .id(directorDto.getId()) .name(directorDto.getName()) From 21f727e86d72f8cbf79f01b7cad7da9797d2b5dd Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:26:21 +0300 Subject: [PATCH 156/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20DirectorController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DirectorController.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java new file mode 100644 index 00000000..85e0faf4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.dto.DirectorDto; +import ru.yandex.practicum.filmorate.service.DirectorService; + +import javax.validation.Valid; +import java.util.Collection; + +@RestController +@RequestMapping("/directors") +@RequiredArgsConstructor +public class DirectorController { + + private final DirectorService directorService; + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public DirectorDto addDirector(@Valid @RequestBody DirectorDto directorDto) { + return directorService.addDirector(directorDto); + } + + @GetMapping + public Collection getAllDirectors() { + return directorService.findAll(); + } + + @GetMapping("/{id}") + public DirectorDto getDirectorById(@PathVariable long id) { + return directorService.getDirectorById(id); + } + + @PutMapping + public DirectorDto updateDirector(@Valid @RequestBody DirectorDto updatedDirectorDto) { + return directorService.updateDirector(updatedDirectorDto); + } + + @DeleteMapping("/{id}") + public void removeDirector(@PathVariable long id) { + directorService.removeDirector(id); + } +} From 30f925105052098a2ce02fe857bc1094bed7496e Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:26:45 +0300 Subject: [PATCH 157/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B8=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20DirectorService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/DirectorService.java | 17 ++++ .../service/impl/DirectorServiceImpl.java | 91 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/impl/DirectorServiceImpl.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java new file mode 100644 index 00000000..7bdb7976 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.dto.DirectorDto; + +import java.util.Collection; + +public interface DirectorService { + DirectorDto addDirector(DirectorDto directorDto); + + Collection findAll(); + + DirectorDto getDirectorById(long id); + + DirectorDto updateDirector(DirectorDto updatedDirectorDto); + + void removeDirector(long id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/DirectorServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/DirectorServiceImpl.java new file mode 100644 index 00000000..76a15472 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/DirectorServiceImpl.java @@ -0,0 +1,91 @@ +package ru.yandex.practicum.filmorate.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.yandex.practicum.filmorate.dao.DirectorStorage; +import ru.yandex.practicum.filmorate.dto.DirectorDto; +import ru.yandex.practicum.filmorate.mapper.DirectorMapper; +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.service.DirectorService; + +import java.util.Collection; +import java.util.stream.Collectors; + +import static ru.yandex.practicum.filmorate.mapper.DirectorMapper.toDto; +import static ru.yandex.practicum.filmorate.mapper.DirectorMapper.toModel; + +@Service +@RequiredArgsConstructor +@Slf4j +public class DirectorServiceImpl implements DirectorService { + + private final DirectorStorage directorStorage; + + /** + * Добавление режиссера в БД. + * + * @param directorDto режиссер. + * @return режиссер с присвоенным идентификатором. + */ + @Transactional + @Override + public DirectorDto addDirector(final DirectorDto directorDto) { + final Director director = toModel(directorDto); + final Director addedDirector = directorStorage.add(director); + log.info("Добавление нового режиссера: {}.", addedDirector); + return toDto(directorStorage.findById(addedDirector.getId())); + } + + /** + * Получение списка всех режиссеров. + * + * @return список всех, хранящихся в БД. + */ + @Override + public Collection findAll() { + log.info("Получение списка всех режиссеров."); + return directorStorage.findAll().stream().map(DirectorMapper::toDto).collect(Collectors.toList()); + } + + /** + * Получение режиссера по идентификатору. + * + * @param id идентфикатор режиссера. + * @return найденный режиссер. + */ + @Override + public DirectorDto getDirectorById(final long id) { + final Director storedDirector = directorStorage.findById(id); + log.info("Режиисер с id '{}' найден: {}.", id, storedDirector); + return toDto(storedDirector); + } + + /** + * Обновление данных режиссера. + * + * @param updatedDirectorDto режиссер с новыми данными, которые необходимо обновить. + * @return обновленный режиссер. + */ + @Transactional + @Override + public DirectorDto updateDirector(final DirectorDto updatedDirectorDto) { + final Director updatedDirector = toModel(updatedDirectorDto); + long directorId = updatedDirector.getId(); + directorStorage.update(updatedDirector); + log.info("Обновление режиссера с id '{}': {}.", directorId, updatedDirector); + return toDto(directorStorage.findById(directorId)); + } + + /** + * Удаление режиссера из БД. + * + * @param id идентификатор режиссера. + */ + @Override + public void removeDirector(final long id) { + directorStorage.remove(id); + log.info("Удаление режиссера с id '{}'", id); + } +} From c8aa291d8fced55cd87fe5f454b69567ce46e397 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:26:57 +0300 Subject: [PATCH 158/188] =?UTF-8?q?feat:=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20DirectorStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dao/DirectorStorage.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/DirectorStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorStorage.java new file mode 100644 index 00000000..87d2dfd3 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorStorage.java @@ -0,0 +1,6 @@ +package ru.yandex.practicum.filmorate.dao; + +import ru.yandex.practicum.filmorate.model.Director; + +public interface DirectorStorage extends Dao { +} From 1348fba1981bc032e2b31c6113f65211e9122ab9 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:44:48 +0300 Subject: [PATCH 159/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20ON=20DELETE=20CASCADE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 9e7675da..d861bc52 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -91,8 +91,8 @@ CREATE TABLE IF NOT EXISTS FILM_DIRECTOR( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, FILM_ID INTEGER NOT NULL, DIRECTOR_ID INTEGER NOT NULL, - FOREIGN KEY (FILM_ID) REFERENCES FILM(ID), - FOREIGN KEY (DIRECTOR_ID) REFERENCES DIRECTOR(ID) + FOREIGN KEY (FILM_ID) REFERENCES FILM(ID) ON DELETE CASCADE, + FOREIGN KEY (DIRECTOR_ID) REFERENCES DIRECTOR(ID) ON DELETE CASCADE ); CREATE UNIQUE INDEX FILM_DIRECTOR_IDX ON FILM_DIRECTOR (ID, FILM_ID, DIRECTOR_ID); From 54a427431cf6591d71b11d7fbeade3d15709190a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 11:50:17 +0300 Subject: [PATCH 160/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20DirectorDbStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/DirectorDbStorage.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/DirectorDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/DirectorDbStorage.java new file mode 100644 index 00000000..8429ac06 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/DirectorDbStorage.java @@ -0,0 +1,81 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.DirectorStorage; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Director; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Objects; + +@Repository +@RequiredArgsConstructor +public class DirectorDbStorage implements DirectorStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public Director add(final Director director) { + final KeyHolder keyHolder = new GeneratedKeyHolder(); + final String sql = "INSERT INTO director (director_name) VALUES (?)"; + jdbcTemplate.update(con -> { + PreparedStatement stmt = con.prepareStatement(sql, new String[]{"id"}); + stmt.setString(1, director.getName()); + return stmt; + }, keyHolder); + + director.setId(Objects.requireNonNull(keyHolder.getKey(), "Не удалось добавить директора.").longValue()); + + return director; + } + + @Override + public void remove(final long id) { + final String sql = "DELETE FROM director WHERE id = ?"; + final int update = jdbcTemplate.update(sql, id); + if (update != 1) { + throw new NotFoundException("Режиссер с id '" + id + "' не найден."); + } + } + + @Override + public void update(final Director director) { + final String sql = "UPDATE director SET director_name = ? WHERE id = ?"; + final int update = jdbcTemplate.update(sql, director.getName(), director.getId()); + if (update != 1) { + throw new NotFoundException("Режиссер с id '" + director.getId() + "' не найден."); + } + } + + @Override + public Collection findAll() { + final String sql = "SELECT * FROM director"; + return jdbcTemplate.query(sql, this::mapToDirector); + } + + @Override + public Director findById(final long id) { + final String sql = "SELECT * FROM director WHERE id = ?"; + try { + return jdbcTemplate.queryForObject(sql, this::mapToDirector, id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("Режиссер с id '" + id + "' не найден."); + } + } + + private Director mapToDirector(ResultSet rs, int rowNum) throws SQLException { + return Director.builder() + .id(rs.getLong("id")) + .name(rs.getString("director_name")) + .build(); + } + +} From 2f5bd2e458cfbd511dd29ddbc46e4aee9b754e03 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 12:20:53 +0300 Subject: [PATCH 161/188] =?UTF-8?q?test:=20=D0=9D=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20DirectorDbStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/DirectorDbStorageTest.java | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/storage/DirectorDbStorageTest.java diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/DirectorDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/DirectorDbStorageTest.java new file mode 100644 index 00000000..55b76278 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/DirectorDbStorageTest.java @@ -0,0 +1,139 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import ru.yandex.practicum.filmorate.dao.DirectorStorage; +import ru.yandex.practicum.filmorate.dao.impl.DirectorDbStorage; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Director; + +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@JdbcTest +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class DirectorDbStorageTest { + + private final JdbcTemplate jdbcTemplate; + + private DirectorStorage directorStorage; + private Director director1; + private Director director2; + + @BeforeAll + public void init() { + directorStorage = new DirectorDbStorage(jdbcTemplate); + director1 = Director.builder() + .id(1) + .name("Director 1") + .build(); + director2 = Director.builder() + .id(2) + .name("Director 2") + .build(); + } + + @Test + @DisplayName("Получение списка режиссеров при пустой БД.") + public void testFindEmptyDirectors() { + Collection emptyDirectors = directorStorage.findAll(); + + assertThat(emptyDirectors) + .isNotNull() + .isEmpty(); + } + + @Test + @DisplayName("Получение режиссера с несуществующим id.") + public void findDirectorUnknownId() { + + final long unknownId = 1; + NotFoundException e = assertThrows(NotFoundException.class, () -> directorStorage.findById(unknownId)); + + assertEquals("Режиссер с id '" + unknownId + "' не найден.", e.getMessage()); + } + + @Test + @DisplayName("Добавление режиссера и поиск по id.") + public void testAddAndFindById() { + directorStorage.add(director1); + Director storedDirector = directorStorage.findById(director1.getId()); + + assertThat(storedDirector) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(director1); + } + + @Test + @DisplayName("Добавление второго режиссера и поиск всех режиссеров.") + public void testAddAndFindAll() { + directorStorage.add(director1); + directorStorage.add(director2); + Collection directors = directorStorage.findAll(); + + assertThat(directors) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(director1, director2)); + } + + @Test + @DisplayName("Обновление данных режиссера.") + public void testUpdate() { + directorStorage.add(director1); + + director1.setName("Updated director 1"); + directorStorage.update(director1); + Director updatedDirector = directorStorage.findById(director1.getId()); + + assertThat(updatedDirector) + .isNotNull() + .usingRecursiveComparison() + .isEqualTo(director1); + } + + @Test + @DisplayName("Удаление режиссера с неизвестным id.") + public void testDeleteUnknownDirectorId() { + final long unknownId = 1; + + NotFoundException e = assertThrows(NotFoundException.class, () -> directorStorage.remove(unknownId)); + + assertEquals("Режиссер с id '" + unknownId + "' не найден.", e.getMessage()); + } + + @Test + @DisplayName("Удаление единственного режиссера.") + public void testDeleteOnlyDirector() { + directorStorage.add(director1); + directorStorage.remove(director1.getId()); + NotFoundException e = assertThrows(NotFoundException.class, () -> directorStorage.findById(director1.getId())); + + assertEquals("Режиссер с id '" + director1.getId() + "' не найден.", e.getMessage()); + } + + @Test + @DisplayName("Удаление режиссера из списка.") + public void testDeleteDirector() { + directorStorage.add(director1); + directorStorage.add(director2); + directorStorage.remove(director1.getId()); + Collection directors = directorStorage.findAll(); + + assertThat(directors) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(director2)); + } +} \ No newline at end of file From 1b960c8864f1e92ce63301991aec0d15f8c1d140 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 12:51:37 +0300 Subject: [PATCH 162/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20FilmDirectorStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/FilmDirectorStorage.java | 19 ++++ .../dao/impl/FilmDirectorDbStorage.java | 93 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java new file mode 100644 index 00000000..0a09c5b6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.dao; + +import ru.yandex.practicum.filmorate.model.Director; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface FilmDirectorStorage { + void add(long filmId, long directorId); + + void batchUpdate(long filmId, Set directors); + + void deleteAllByFilmId(long filmId); + + Map> findDirectorsInIdList(Set filmIds); + + List findAllById(long filmId); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java new file mode 100644 index 00000000..4a30d971 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java @@ -0,0 +1,93 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.FilmDirectorStorage; +import ru.yandex.practicum.filmorate.model.Director; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Repository +@RequiredArgsConstructor +public class FilmDirectorDbStorage implements FilmDirectorStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public void add(final long filmId, final long directorId) { + final String sql = "INSERT INTO film_director VALUES (?, ?)"; + jdbcTemplate.update(sql, filmId, directorId); + } + + @Override + public void batchUpdate(final long filmId, final Set directors) { + final List directorList = new ArrayList<>(directors); + final String sql = "INSERT INTO film_director (film_id, director_id) VALUES (?, ?)"; + jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setLong(1, filmId); + ps.setLong(2, directorList.get(i).getId()); + } + + @Override + public int getBatchSize() { + return directors.size(); + } + }); + } + + @Override + public void deleteAllByFilmId(final long filmId) { + final String sql = "DELETE FROM film_director WHERE film_id = ?"; + jdbcTemplate.update(sql, filmId); + } + + @Override + public Map> findDirectorsInIdList(Set filmIds) { + final String ids = String.join(",", Collections.nCopies(filmIds.size(), "?")); + final String sql = String.format( + "SELECT fd.film_id, fd.director_id, d.director_name FROM film_director fd JOIN director d ON fd.director_id = d.id" + + " WHERE fd.film_id IN (%s)", ids); + + return jdbcTemplate.query(sql, this::extractToMap, filmIds.toArray()); + } + + @Override + public List findAllById(long filmId) { + final String sql = "SELECT fd.film_id, fd.director_id, d.director_name FROM film_director fd JOIN director d ON fd.director_id = d.id" + + " WHERE fd.film_id = ?"; + return jdbcTemplate.query(sql, this::mapToDirector, filmId); + } + + private Director mapToDirector(ResultSet rs, int i) throws SQLException { + return Director.builder() + .id(rs.getLong("director_id")) + .name(rs.getString("director_name")) + .build(); + } + + private Map> extractToMap(ResultSet rs) throws SQLException, DataAccessException { + final Map> filmIdDirectorMap = new HashMap<>(); + while (rs.next()) { + final Long filmId = rs.getLong(1); + List directors = filmIdDirectorMap.get(filmId); + if (directors == null) { + directors = new ArrayList<>(); + } + final Director director = Director.builder() + .id(rs.getLong("director_id")) + .name(rs.getString("director_name")) + .build(); + directors.add(director); + filmIdDirectorMap.put(filmId, directors); + } + return filmIdDirectorMap; + } +} From 8d5b9bc10dcabca60337d930adbd8a7474bee8fb Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 12:52:15 +0300 Subject: [PATCH 163/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B6=D0=B8=D1=81=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 373905e7..31c94d1b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -7,9 +7,11 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.FilmDirectorStorage; import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; @@ -32,6 +34,8 @@ public class FilmDbStorage implements FilmStorage { private final FilmGenreStorage filmGenreStorage; + private final FilmDirectorStorage filmDirectorStorage; + @Override public Film add(final Film film) { final KeyHolder keyHolder = new GeneratedKeyHolder(); @@ -49,6 +53,7 @@ public Film add(final Film film) { film.setId(Objects.requireNonNull(keyHolder.getKey(), "Не удалось добавить фильм.").longValue()); filmGenreStorage.batchUpdate(film.getId(), film.getGenres()); + filmDirectorStorage.batchUpdate(film.getId(), film.getDirectors()); return film; } @@ -73,6 +78,8 @@ public void update(final Film film) { filmGenreStorage.deleteAllById(film.getId()); filmGenreStorage.batchUpdate(film.getId(), film.getGenres()); + filmDirectorStorage.deleteAllByFilmId(film.getId()); + filmDirectorStorage.batchUpdate(film.getId(), film.getDirectors()); } @Override @@ -85,7 +92,8 @@ public Collection findAll() { "GROUP BY f.id, m.rating_name"; Collection films = jdbcTemplate.query(sql, this::mapToFilm); - return setGenresForFilms(films); + setGenresForFilms(films); + return setDirectorsForFilms(films); } @Override @@ -101,7 +109,9 @@ public Film findById(final long filmId) { try { final Film film = jdbcTemplate.queryForObject(sql, this::mapToFilm, filmId); List genres = filmGenreStorage.findAllById(filmId); + List directors = filmDirectorStorage.findAllById(filmId); film.getGenres().addAll(genres); + film.getDirectors().addAll(directors); return film; } catch (EmptyResultDataAccessException e) { throw new NotFoundException("Фильм с id '" + filmId + "' не найден."); @@ -119,7 +129,8 @@ public Collection findMostLikedFilmsLimitBy(final int count) { "LIMIT ?"; Collection films = jdbcTemplate.query(sql, this::mapToFilm, count); - return setGenresForFilms(films); + setGenresForFilms(films); + return setDirectorsForFilms(films); } public Collection findFilmsByIds(Set filmIds) { @@ -144,6 +155,13 @@ private List setGenresForFilms(Collection films) { return new ArrayList<>(filmMap.values()); } + private List setDirectorsForFilms(Collection films) { + Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, identity())); + Map> filmIdDirectorMap = filmDirectorStorage.findDirectorsInIdList(filmMap.keySet()); + filmIdDirectorMap.forEach((id, directors) -> filmMap.get(id).getDirectors().addAll(directors)); + return new ArrayList<>(filmMap.values()); + } + private Film mapToFilm(ResultSet rs, int rowNum) throws SQLException { Film film = Film.builder() .id(rs.getLong(1)) From 8c5ee3513f51960af6b5939c3a3a951e50f0288f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:33:18 +0300 Subject: [PATCH 164/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20FilmDirectorStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/ReviewDbStorageTest.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java index 1224a75c..252166eb 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/ReviewDbStorageTest.java @@ -8,14 +8,8 @@ import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.annotation.DirtiesContext; -import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.ReviewStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; -import ru.yandex.practicum.filmorate.dao.impl.FilmDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.FilmGenreDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.ReviewDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.model.Review; @@ -49,7 +43,8 @@ class ReviewDbStorageTest { public void setUp() { reviewStorage = new ReviewDbStorage(jdbcTemplate); FilmGenreStorage filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); - filmStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + FilmDirectorStorage filmDirectorStorage = new FilmDirectorDbStorage(jdbcTemplate); + filmStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage, filmDirectorStorage); userStorage = new UserDbStorage(jdbcTemplate); Mpa mpa = new Mpa(1, "G"); From f513ece2b70e3777bcfd0d0e6234534c2d680332 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:34:07 +0300 Subject: [PATCH 165/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20Directors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/FilmController.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index e1066545..2808dbea 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -57,5 +57,10 @@ public Collection getMostPopularFilms(@RequestParam(required = false, d public void removeFilm(@PathVariable long id) { filmService.removeFilm(id); } + + @GetMapping("/director/{directorId}") + public Collection getFilmsFromDirector(@PathVariable long directorId, @RequestParam String sortBy) { + return filmService.getFilmsFromDirector(directorId, sortBy); + } } From 6c6b7c98864642ad2b5afafbeea8d0b3d488276a Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:34:21 +0300 Subject: [PATCH 166/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20getFilmsFromDirector?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/service/FilmService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 88ea93e9..f8b7eea7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -20,4 +20,6 @@ public interface FilmService { void removeFilm(long filmId); Collection getMostPopularFilms(final int count); + + Collection getFilmsFromDirector(long directorId, String sortBy); } \ No newline at end of file From e93ee850de21b75ad6db9010ccdb2310cc852790 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:35:50 +0300 Subject: [PATCH 167/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20getFilmsFromDirector=20?= =?UTF-8?q?=D0=B8=20Transactional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/FilmServiceImpl.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 5b29e3ca..fc19fff7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -3,6 +3,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.yandex.practicum.filmorate.dao.DirectorStorage; import ru.yandex.practicum.filmorate.dao.FilmLikeStorage; import ru.yandex.practicum.filmorate.dao.FilmStorage; import ru.yandex.practicum.filmorate.dao.UserStorage; @@ -29,6 +31,8 @@ public class FilmServiceImpl implements FilmService { private final FilmLikeStorage filmLikeStorage; + private final DirectorStorage directorStorage; + /** * Добавление фильма в БД. * @@ -36,6 +40,7 @@ public class FilmServiceImpl implements FilmService { * @return фильм с присвоенным идентификатором. */ @Override + @Transactional public FilmDto addFilm(final FilmDto filmDto) { final Film film = toModel(filmDto); final Film addedFilm = filmStorage.add(film); @@ -50,6 +55,7 @@ public FilmDto addFilm(final FilmDto filmDto) { * @return обновленный фильм. */ @Override + @Transactional public FilmDto updateFilm(final FilmDto updatedFilmDto) { final Film updatedFilm = toModel(updatedFilmDto); final long filmId = updatedFilmDto.getId(); @@ -76,6 +82,7 @@ public Collection getAllFilms() { * @return найденный фильм. */ @Override + @Transactional public FilmDto getFilmById(final long filmId) { filmStorage.findById(filmId); log.info("Фильм с id {} найден.", filmId); @@ -85,11 +92,12 @@ public FilmDto getFilmById(final long filmId) { /** * Постановка лайка фильму от пользователя. * - * @param filmId идентификатор фильма, которму ставится лайк. + * @param filmId идентификатор фильма, которому ставится лайк. * @param userId идентификатор пользователя, который ставит лайк. * @return фильм, которому поставили лайк. */ @Override + @Transactional public FilmDto likeFilm(final long filmId, final long userId) { filmStorage.findById(filmId); userStorage.findById(userId); @@ -102,10 +110,11 @@ public FilmDto likeFilm(final long filmId, final long userId) { * Удаление лайка у фильма. * * @param filmId идентификатор фильма, у которого требуется удалить лайк. - * @param userId идентфикатор пользователя лайк которого требуется удалить. + * @param userId идентификатор пользователя лайк которого требуется удалить. * @return фильм, у которого удалили лайк. */ @Override + @Transactional public FilmDto removeLike(final long filmId, final long userId) { filmStorage.findById(filmId); userStorage.findById(userId); @@ -135,4 +144,19 @@ public void removeFilm(long filmId) { public Collection getMostPopularFilms(final int count) { return filmStorage.findMostLikedFilmsLimitBy(count).stream().map(FilmMapper::toDto).collect(Collectors.toList()); } + + /** + * Получение списка фильмов режиссера, отсортированных по количеству лайков или году выпуска. + * + * @param directorId идентификатор режиссера. + * @param sortBy поле сортировки. + * @return список фильмов режиссера. + */ + @Override + @Transactional + public Collection getFilmsFromDirector(final long directorId, final String sortBy) { + directorStorage.findById(directorId); + return filmStorage.findFilmsFromDirector(directorId, sortBy).stream() + .map(FilmMapper::toDto).collect(Collectors.toList()); + } } \ No newline at end of file From 9e246b03f1ed2530984a14e9c38a18d71507a854 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:36:16 +0300 Subject: [PATCH 168/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20findFilmsByDirectorId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java index 0a09c5b6..619cd98d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDirectorStorage.java @@ -15,5 +15,7 @@ public interface FilmDirectorStorage { Map> findDirectorsInIdList(Set filmIds); + List findFilmsByDirectorId(long directorId); + List findAllById(long filmId); } From 3ac1aa68fe0e3459e06654c7e8a198bb8f8d193f Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:36:37 +0300 Subject: [PATCH 169/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20findFilmsByDirectorId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDirectorDbStorage.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java index 4a30d971..c2bedba1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java @@ -50,7 +50,7 @@ public void deleteAllByFilmId(final long filmId) { } @Override - public Map> findDirectorsInIdList(Set filmIds) { + public Map> findDirectorsInIdList(final Set filmIds) { final String ids = String.join(",", Collections.nCopies(filmIds.size(), "?")); final String sql = String.format( "SELECT fd.film_id, fd.director_id, d.director_name FROM film_director fd JOIN director d ON fd.director_id = d.id" + @@ -59,6 +59,12 @@ public Map> findDirectorsInIdList(Set filmIds) { return jdbcTemplate.query(sql, this::extractToMap, filmIds.toArray()); } + @Override + public List findFilmsByDirectorId(final long directorId) { + final String sql = "SELECT film_id FROM film_director WHERE director_id = ?"; + return jdbcTemplate.query(sql, (rs, rowNum) -> rs.getLong("film_id"), directorId); + } + @Override public List findAllById(long filmId) { final String sql = "SELECT fd.film_id, fd.director_id, d.director_name FROM film_director fd JOIN director d ON fd.director_id = d.id" + From dd382c06fe38cbb4a72450e7f0bfbc3a632a7084 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:36:54 +0300 Subject: [PATCH 170/188] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20findFilmsFromDirector?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/dao/FilmStorage.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index d484609a..a4fdc81c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -9,4 +9,6 @@ public interface FilmStorage extends Dao { Collection findMostLikedFilmsLimitBy(int count); Collection findFilmsByIds(Set filmIds); + + Collection findFilmsFromDirector(long directorId, String sortBy); } From 5e46f8360b69fd047d93c90d17dc88f01280b3e5 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:37:16 +0300 Subject: [PATCH 171/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20findFilmsFromDirector?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 31c94d1b..f8f59a73 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -93,7 +93,8 @@ public Collection findAll() { Collection films = jdbcTemplate.query(sql, this::mapToFilm); setGenresForFilms(films); - return setDirectorsForFilms(films); + setDirectorsForFilms(films); + return films; } @Override @@ -130,7 +131,38 @@ public Collection findMostLikedFilmsLimitBy(final int count) { Collection films = jdbcTemplate.query(sql, this::mapToFilm, count); setGenresForFilms(films); - return setDirectorsForFilms(films); + setDirectorsForFilms(films); + + return films; + } + + @Override + public Collection findFilmsFromDirector(long directorId, String sortBy) { + final Map allowedSorting = Map.of( + "likes", "COUNT(fl.USER_ID) DESC", + "year", "f.RELEASE_DATE" + ); + + if (!allowedSorting.containsKey(sortBy)) { + throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); + } + + List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); + final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); + final String sql = String.format( + "SELECT " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + + "FROM " + + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + + "LEFT JOIN film_like fl on f.id = fl.film_id " + + "GROUP BY f.id, m.rating_name " + + "HAVING f.id IN (%s)" + + "ORDER BY %s", ids, allowedSorting.get(sortBy)); + List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); + setGenresForFilms(directorFilms); + setDirectorsForFilms(directorFilms); + + return directorFilms; } public Collection findFilmsByIds(Set filmIds) { From 61474a2c6404c14ef1565bdaa76c2cb7085cef86 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 14:37:45 +0300 Subject: [PATCH 172/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20FilmDirectorStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/FilmDbStorageTest.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index f388ec09..2e58f203 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -8,14 +8,8 @@ import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.annotation.DirtiesContext; -import ru.yandex.practicum.filmorate.dao.FilmGenreStorage; -import ru.yandex.practicum.filmorate.dao.FilmLikeStorage; -import ru.yandex.practicum.filmorate.dao.FilmStorage; -import ru.yandex.practicum.filmorate.dao.UserStorage; -import ru.yandex.practicum.filmorate.dao.impl.FilmDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.FilmGenreDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.FilmLikeDbStorage; -import ru.yandex.practicum.filmorate.dao.impl.UserDbStorage; +import ru.yandex.practicum.filmorate.dao.*; +import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; @@ -49,7 +43,8 @@ public class FilmDbStorageTest { public void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); - filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + FilmDirectorStorage filmDirectorStorage = new FilmDirectorDbStorage(jdbcTemplate); + filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage, filmDirectorStorage); userStorage = new UserDbStorage(jdbcTemplate); Mpa mpa = new Mpa(1, "G"); From 56ee82683ee3284609f7f09618c757ffbdb22ef4 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 17:06:22 +0300 Subject: [PATCH 173/188] =?UTF-8?q?fix:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20FilmDirectorStorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/UserDbStorageTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java index a0819dce..ef656507 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDbStorageTest.java @@ -50,7 +50,8 @@ class UserDbStorageTest { void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); - filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage); + FilmDirectorStorage filmDirectorStorage = new FilmDirectorDbStorage(jdbcTemplate); + filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage, filmDirectorStorage); userStorage = new UserDbStorage(jdbcTemplate); friendshipStorage = new FriendshipDbStorage(jdbcTemplate); userService = new UserServiceImpl(userStorage, filmDbStorage, friendshipStorage, filmLikeStorage); From 7aafefb359927dd18217f53eea8ff60e470322a7 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Thu, 1 Feb 2024 17:06:44 +0300 Subject: [PATCH 174/188] =?UTF-8?q?test:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B8?= =?UTF-8?q?=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2=20=D1=80=D0=B5=D0=B6=D0=B8=D1=81?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/FilmDbStorageTest.java | 78 +++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 2e58f203..576bd9de 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -11,10 +11,7 @@ import ru.yandex.practicum.filmorate.dao.*; import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.model.*; import java.time.LocalDate; import java.util.Collection; @@ -33,16 +30,20 @@ public class FilmDbStorageTest { private FilmStorage filmDbStorage; private FilmGenreStorage filmGenreStorage; private FilmLikeStorage filmLikeStorage; + private DirectorStorage directorStorage; private UserStorage userStorage; private Film film; + private Film film2; private Film updatedFilm; private User user; + private Director director; @BeforeEach public void setUp() { filmLikeStorage = new FilmLikeDbStorage(jdbcTemplate); filmGenreStorage = new FilmGenreDbStorage(jdbcTemplate); + directorStorage = new DirectorDbStorage(jdbcTemplate); FilmDirectorStorage filmDirectorStorage = new FilmDirectorDbStorage(jdbcTemplate); filmDbStorage = new FilmDbStorage(jdbcTemplate, filmGenreStorage, filmDirectorStorage); userStorage = new UserDbStorage(jdbcTemplate); @@ -58,6 +59,15 @@ public void setUp() { .mpa(mpa) .build(); + film2 = Film.builder() + .id(2) + .name("film") + .description("film description") + .releaseDate(LocalDate.of(2019, 12, 12)) + .duration(123) + .mpa(mpa) + .build(); + updatedFilm = Film.builder() .id(1) .name("updated film") @@ -68,6 +78,11 @@ public void setUp() { .build(); user = new User(1, "email", "login", "name", LocalDate.now()); + + director = Director.builder() + .id(1) + .name("Director") + .build(); } @Test @@ -314,7 +329,7 @@ void testMostPopularFilmsWithSeveralGenres() { film.getGenres().add(genre2); film.getGenres().add(genre3); filmDbStorage.add(film); - filmLikeStorage.add(film.getId(),user.getId()); + filmLikeStorage.add(film.getId(), user.getId()); filmDbStorage.add(updatedFilm); film.setLikes(1); @@ -326,4 +341,57 @@ void testMostPopularFilmsWithSeveralGenres() { .isNotEmpty() .isEqualTo(List.of(film)); } + + @Test + @DisplayName("Тест получения фильмов режиссера c сортировкой по году.") + public void findFilmsByDirectorSortByYear() { + film.getDirectors().add(director); + film2.getDirectors().add(director); + directorStorage.add(director); + filmDbStorage.add(film); + filmDbStorage.add(film2); + + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "year"); + + assertThat(films) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(film2, film)); + } + + @Test + @DisplayName("Тест получения фильмов режиссера c сортировкой по лайкам.") + public void findFilmsByDirectorSortByLikes() { + film.getDirectors().add(director); + film2.getDirectors().add(director); + film.setLikes(1); + + userStorage.add(user); + directorStorage.add(director); + filmDbStorage.add(film); + filmDbStorage.add(film2); + filmLikeStorage.add(1, 1); + + + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "likes"); + + assertThat(films) + .isNotNull() + .isNotEmpty() + .usingRecursiveComparison() + .isEqualTo(List.of(film, film2)); + } + + @Test + @DisplayName("Тест получения пустого списка, когда у режиссера нет фильмов.") + public void findFilmsByDirectorUnknownId() { + + directorStorage.add(director); + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "year"); + + assertThat(films) + .isNotNull() + .isEmpty(); + } } From 9cf064c2ef83c7778329c60c6bd2a8302b9bc440 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 09:21:00 +0300 Subject: [PATCH 175/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20queryForList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/FilmDirectorDbStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java index c2bedba1..d912872d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDirectorDbStorage.java @@ -62,7 +62,7 @@ public Map> findDirectorsInIdList(final Set filmIds) @Override public List findFilmsByDirectorId(final long directorId) { final String sql = "SELECT film_id FROM film_director WHERE director_id = ?"; - return jdbcTemplate.query(sql, (rs, rowNum) -> rs.getLong("film_id"), directorId); + return jdbcTemplate.queryForList(sql, Long.class, directorId); } @Override From ba996438e5b3d0bcefa806d6c71fe3c6226c6340 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 09:22:00 +0300 Subject: [PATCH 176/188] =?UTF-8?q?refactor:=20=D0=9F=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=B2=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/impl/FilmDbStorage.java | 11 +---------- .../filmorate/service/impl/FilmServiceImpl.java | 11 ++++++++++- .../filmorate/storage/FilmDbStorageTest.java | 10 +++++++--- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index f8f59a73..13f7993a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -138,15 +138,6 @@ public Collection findMostLikedFilmsLimitBy(final int count) { @Override public Collection findFilmsFromDirector(long directorId, String sortBy) { - final Map allowedSorting = Map.of( - "likes", "COUNT(fl.USER_ID) DESC", - "year", "f.RELEASE_DATE" - ); - - if (!allowedSorting.containsKey(sortBy)) { - throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); - } - List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); final String sql = String.format( @@ -157,7 +148,7 @@ public Collection findFilmsFromDirector(long directorId, String sortBy) { "LEFT JOIN film_like fl on f.id = fl.film_id " + "GROUP BY f.id, m.rating_name " + "HAVING f.id IN (%s)" + - "ORDER BY %s", ids, allowedSorting.get(sortBy)); + "ORDER BY %s", ids, sortBy); List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); setGenresForFilms(directorFilms); setDirectorsForFilms(directorFilms); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index fc19fff7..9855976c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Map; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.mapper.FilmMapper.toDto; @@ -24,6 +25,10 @@ @RequiredArgsConstructor @Slf4j public class FilmServiceImpl implements FilmService { + public static final Map ALLOWED_SORTING = Map.of( + "likes", "COUNT(fl.USER_ID) DESC", + "year", "f.RELEASE_DATE" + ); private final FilmStorage filmStorage; @@ -155,8 +160,12 @@ public Collection getMostPopularFilms(final int count) { @Override @Transactional public Collection getFilmsFromDirector(final long directorId, final String sortBy) { + if (!ALLOWED_SORTING.containsKey(sortBy)) { + throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); + } + directorStorage.findById(directorId); - return filmStorage.findFilmsFromDirector(directorId, sortBy).stream() + return filmStorage.findFilmsFromDirector(directorId, ALLOWED_SORTING.get(sortBy)).stream() .map(FilmMapper::toDto).collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 576bd9de..11d7ea9f 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -12,6 +12,7 @@ import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; +import ru.yandex.practicum.filmorate.service.impl.FilmServiceImpl; import java.time.LocalDate; import java.util.Collection; @@ -351,7 +352,8 @@ public void findFilmsByDirectorSortByYear() { filmDbStorage.add(film); filmDbStorage.add(film2); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "year"); + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), + FilmServiceImpl.ALLOWED_SORTING.get("year")); assertThat(films) .isNotNull() @@ -374,7 +376,8 @@ public void findFilmsByDirectorSortByLikes() { filmLikeStorage.add(1, 1); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "likes"); + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), + FilmServiceImpl.ALLOWED_SORTING.get("likes")); assertThat(films) .isNotNull() @@ -388,7 +391,8 @@ public void findFilmsByDirectorSortByLikes() { public void findFilmsByDirectorUnknownId() { directorStorage.add(director); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), "year"); + Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), + FilmServiceImpl.ALLOWED_SORTING.get("year")); assertThat(films) .isNotNull() From 62f63c929acdc22ffe0ceea6a3cddcdd053a9612 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 10:26:30 +0300 Subject: [PATCH 177/188] =?UTF-8?q?refactor:=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B?= =?UTF-8?q?=20=D1=81=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/FilmStorage.java | 4 ++- .../filmorate/dao/impl/FilmDbStorage.java | 28 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index a4fdc81c..f7f876cb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -10,5 +10,7 @@ public interface FilmStorage extends Dao { Collection findFilmsByIds(Set filmIds); - Collection findFilmsFromDirector(long directorId, String sortBy); + Collection findFilmsFromDirectorOrderByLikes(long directorId); + + Collection findFilmsFromDirectorOrderByYear(long directorId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 13f7993a..e28e5774 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -137,8 +137,8 @@ public Collection findMostLikedFilmsLimitBy(final int count) { } @Override - public Collection findFilmsFromDirector(long directorId, String sortBy) { - List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); + public Collection findFilmsFromDirectorOrderByYear(final long directorId) { + final List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); final String sql = String.format( "SELECT " + @@ -148,8 +148,28 @@ public Collection findFilmsFromDirector(long directorId, String sortBy) { "LEFT JOIN film_like fl on f.id = fl.film_id " + "GROUP BY f.id, m.rating_name " + "HAVING f.id IN (%s)" + - "ORDER BY %s", ids, sortBy); - List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); + "ORDER BY f.release_date", ids); + final List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); + setGenresForFilms(directorFilms); + setDirectorsForFilms(directorFilms); + + return directorFilms; + } + + @Override + public Collection findFilmsFromDirectorOrderByLikes(final long directorId) { + final List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); + final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); + final String sql = String.format( + "SELECT " + + "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + + "FROM " + + "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + + "LEFT JOIN film_like fl on f.id = fl.film_id " + + "GROUP BY f.id, m.rating_name " + + "HAVING f.id IN (%s)" + + "ORDER BY likes DESC", ids); + final List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); setGenresForFilms(directorFilms); setDirectorsForFilms(directorFilms); From 47f842f9c737294f5af44fe4604f66715a855066 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 10:26:54 +0300 Subject: [PATCH 178/188] =?UTF-8?q?refactor:=20=D0=9F=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA?= =?UTF-8?q?=D1=83=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=D0=B0=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=B2=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B8=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/FilmServiceImpl.java | 18 ++++++++---------- .../filmorate/storage/FilmDbStorageTest.java | 12 +++++------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 9855976c..e5c3fbfc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Map; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.mapper.FilmMapper.toDto; @@ -25,10 +24,6 @@ @RequiredArgsConstructor @Slf4j public class FilmServiceImpl implements FilmService { - public static final Map ALLOWED_SORTING = Map.of( - "likes", "COUNT(fl.USER_ID) DESC", - "year", "f.RELEASE_DATE" - ); private final FilmStorage filmStorage; @@ -160,12 +155,15 @@ public Collection getMostPopularFilms(final int count) { @Override @Transactional public Collection getFilmsFromDirector(final long directorId, final String sortBy) { - if (!ALLOWED_SORTING.containsKey(sortBy)) { + directorStorage.findById(directorId); + if ("year".equals(sortBy)) { + return filmStorage.findFilmsFromDirectorOrderByYear(directorId).stream() + .map(FilmMapper::toDto).collect(Collectors.toList()); + } else if ("likes".equals(sortBy)) { + return filmStorage.findFilmsFromDirectorOrderByLikes(directorId).stream() + .map(FilmMapper::toDto).collect(Collectors.toList()); + } else { throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); } - - directorStorage.findById(directorId); - return filmStorage.findFilmsFromDirector(directorId, ALLOWED_SORTING.get(sortBy)).stream() - .map(FilmMapper::toDto).collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 11d7ea9f..80e9a50e 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -352,8 +352,7 @@ public void findFilmsByDirectorSortByYear() { filmDbStorage.add(film); filmDbStorage.add(film2); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), - FilmServiceImpl.ALLOWED_SORTING.get("year")); + Collection films = filmDbStorage.findFilmsFromDirectorOrderByYear(director.getId()); assertThat(films) .isNotNull() @@ -374,10 +373,11 @@ public void findFilmsByDirectorSortByLikes() { filmDbStorage.add(film); filmDbStorage.add(film2); filmLikeStorage.add(1, 1); + System.out.println(film.getId()); + System.out.println(film2.getId()); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), - FilmServiceImpl.ALLOWED_SORTING.get("likes")); + Collection films = filmDbStorage.findFilmsFromDirectorOrderByLikes(director.getId()); assertThat(films) .isNotNull() @@ -389,10 +389,8 @@ public void findFilmsByDirectorSortByLikes() { @Test @DisplayName("Тест получения пустого списка, когда у режиссера нет фильмов.") public void findFilmsByDirectorUnknownId() { - directorStorage.add(director); - Collection films = filmDbStorage.findFilmsFromDirector(director.getId(), - FilmServiceImpl.ALLOWED_SORTING.get("year")); + Collection films = filmDbStorage.findFilmsFromDirectorOrderByYear(director.getId()); assertThat(films) .isNotNull() From 5d4e2a362ea2cc785139a4ac27d67ae09c8a187d Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 10:29:54 +0300 Subject: [PATCH 179/188] checkstyle --- .../ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 80e9a50e..8b246188 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -12,7 +12,6 @@ import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; -import ru.yandex.practicum.filmorate.service.impl.FilmServiceImpl; import java.time.LocalDate; import java.util.Collection; From ab14a96f80e0454080ee3dc7c198ee8a9a4ff204 Mon Sep 17 00:00:00 2001 From: vvbakhanovich Date: Fri, 2 Feb 2024 11:33:35 +0300 Subject: [PATCH 180/188] =?UTF-8?q?refactor:=20=D0=98=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BE?= =?UTF-8?q?=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/FilmStorage.java | 4 +-- .../filmorate/dao/impl/FilmDbStorage.java | 30 ++++--------------- .../service/impl/FilmServiceImpl.java | 19 +++++++----- .../filmorate/storage/FilmDbStorageTest.java | 10 +++++-- 4 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index f7f876cb..0e5c4cfc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -10,7 +10,5 @@ public interface FilmStorage extends Dao { Collection findFilmsByIds(Set filmIds); - Collection findFilmsFromDirectorOrderByLikes(long directorId); - - Collection findFilmsFromDirectorOrderByYear(long directorId); + Collection findFilmsFromDirectorOrderBy(long directorId, String sortBy); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index e28e5774..6ab5b7a0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -137,7 +137,7 @@ public Collection findMostLikedFilmsLimitBy(final int count) { } @Override - public Collection findFilmsFromDirectorOrderByYear(final long directorId) { + public Collection findFilmsFromDirectorOrderBy(final long directorId, final String sortBy) { final List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); final String sql = String.format( @@ -147,29 +147,11 @@ public Collection findFilmsFromDirectorOrderByYear(final long directorId) "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + "LEFT JOIN film_like fl on f.id = fl.film_id " + "GROUP BY f.id, m.rating_name " + - "HAVING f.id IN (%s)" + - "ORDER BY f.release_date", ids); - final List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); - setGenresForFilms(directorFilms); - setDirectorsForFilms(directorFilms); - - return directorFilms; - } - - @Override - public Collection findFilmsFromDirectorOrderByLikes(final long directorId) { - final List filmsByDirectorId = filmDirectorStorage.findFilmsByDirectorId(directorId); - final String ids = String.join(",", Collections.nCopies(filmsByDirectorId.size(), "?")); - final String sql = String.format( - "SELECT " + - "f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, m.RATING_NAME, COUNT(fl.USER_ID) AS likes " + - "FROM " + - "FILM f LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN film_like fl on f.id = fl.film_id " + - "GROUP BY f.id, m.rating_name " + - "HAVING f.id IN (%s)" + - "ORDER BY likes DESC", ids); - final List directorFilms = jdbcTemplate.query(sql, this::mapToFilm, filmsByDirectorId.toArray()); + "HAVING f.id IN (%s) " + + "ORDER BY ", ids); + final StringBuilder sb = new StringBuilder(); + String sqlWithSort = sb.append(sql).append(sortBy).toString(); + final List directorFilms = jdbcTemplate.query(sqlWithSort, this::mapToFilm, filmsByDirectorId.toArray()); setGenresForFilms(directorFilms); setDirectorsForFilms(directorFilms); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index e5c3fbfc..368f2c18 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Map; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.mapper.FilmMapper.toDto; @@ -25,6 +26,11 @@ @Slf4j public class FilmServiceImpl implements FilmService { + public static final Map ALLOWED_SORTS = Map.of( + "year", "f.release_date", + "likes", "likes DESC" + ); + private final FilmStorage filmStorage; private final UserStorage userStorage; @@ -155,15 +161,12 @@ public Collection getMostPopularFilms(final int count) { @Override @Transactional public Collection getFilmsFromDirector(final long directorId, final String sortBy) { - directorStorage.findById(directorId); - if ("year".equals(sortBy)) { - return filmStorage.findFilmsFromDirectorOrderByYear(directorId).stream() - .map(FilmMapper::toDto).collect(Collectors.toList()); - } else if ("likes".equals(sortBy)) { - return filmStorage.findFilmsFromDirectorOrderByLikes(directorId).stream() - .map(FilmMapper::toDto).collect(Collectors.toList()); - } else { + if (!ALLOWED_SORTS.containsKey(sortBy)) { throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); } + directorStorage.findById(directorId); + return filmStorage.findFilmsFromDirectorOrderBy(directorId, ALLOWED_SORTS.get(sortBy)).stream() + .map(FilmMapper::toDto) + .collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java index 8b246188..28af267b 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDbStorageTest.java @@ -12,6 +12,7 @@ import ru.yandex.practicum.filmorate.dao.impl.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; +import ru.yandex.practicum.filmorate.service.impl.FilmServiceImpl; import java.time.LocalDate; import java.util.Collection; @@ -351,7 +352,8 @@ public void findFilmsByDirectorSortByYear() { filmDbStorage.add(film); filmDbStorage.add(film2); - Collection films = filmDbStorage.findFilmsFromDirectorOrderByYear(director.getId()); + Collection films = filmDbStorage.findFilmsFromDirectorOrderBy(director.getId(), + FilmServiceImpl.ALLOWED_SORTS.get("year")); assertThat(films) .isNotNull() @@ -376,7 +378,8 @@ public void findFilmsByDirectorSortByLikes() { System.out.println(film2.getId()); - Collection films = filmDbStorage.findFilmsFromDirectorOrderByLikes(director.getId()); + Collection films = filmDbStorage.findFilmsFromDirectorOrderBy(director.getId(), + FilmServiceImpl.ALLOWED_SORTS.get("likes")); assertThat(films) .isNotNull() @@ -389,7 +392,8 @@ public void findFilmsByDirectorSortByLikes() { @DisplayName("Тест получения пустого списка, когда у режиссера нет фильмов.") public void findFilmsByDirectorUnknownId() { directorStorage.add(director); - Collection films = filmDbStorage.findFilmsFromDirectorOrderByYear(director.getId()); + Collection films = filmDbStorage.findFilmsFromDirectorOrderBy(director.getId(), + FilmServiceImpl.ALLOWED_SORTS.get("year")); assertThat(films) .isNotNull() From 84b982e2f4a902876b5fd19ac0e23ed8e5231b1b Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 08:24:50 +0100 Subject: [PATCH 181/188] =?UTF-8?q?feat:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=89=D0=B8=D1=85=20=D1=81=20=D0=B4=D1=80=D1=83?= =?UTF-8?q?=D0=B3=D0=BE=D0=BC=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=81=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=20=D0=BF=D0=BE=20=D0=B8=D1=85=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BF=D1=83=D0=BB=D1=8F=D1=80=D0=BD=D0=BE=D1=81=D1=82=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен новый метод getCommonFilms в класс FilmServiceImpl и соответствующий обработчик запросов в FilmController для вывода списка общих фильмов двух пользователей с сортировкой по популярности. Основные моменты изменений: 1. В FilmServiceImpl реализован метод getCommonFilms, который: - Использует filmLikeStorage.findLikedFilmsByUser для получения фильмов, лайкнутых каждым из пользователей. - Находит пересечение этих списков для определения общих фильмов. - Сортирует общие фильмы по количеству лайков с помощью Comparator.comparingLong(FilmDto::getLikes).reversed(). 2. В FilmController добавлен обработчик GET-запросов на путь '/common', принимающий параметры userId и friendId. --- .../filmorate/controller/FilmController.java | 8 ++++++ .../filmorate/dao/FilmLikeStorage.java | 3 +++ .../filmorate/dao/impl/FilmLikeDbStorage.java | 10 +++++++ .../filmorate/service/FilmService.java | 2 ++ .../service/impl/FilmServiceImpl.java | 27 +++++++++++++++++++ 5 files changed, 50 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 2808dbea..c80ef01f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -48,6 +48,14 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { return filmService.removeLike(id, userId); } + @GetMapping("/common") + public Collection getCommonFilms( + @RequestParam long userId, + @RequestParam long friendId){ + return filmService.getCommonFilms(userId, friendId); + + } + @GetMapping("/popular") public Collection getMostPopularFilms(@RequestParam(required = false, defaultValue = "10") int count) { return filmService.getMostPopularFilms(count); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java index 7c693e7d..bdc2c1b3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmLikeStorage.java @@ -12,5 +12,8 @@ public interface FilmLikeStorage { void remove(long filmId, long userId); + Set findLikedFilmsByUser(long userId); + + Map> getUsersAndFilmLikes(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index cbdf1c5e..293a602d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -10,6 +10,10 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; import java.util.*; @Repository @@ -49,6 +53,12 @@ public void remove(long filmId, long userId) { jdbcTemplate.update(sql, filmId, userId); } + @Override + public Set findLikedFilmsByUser(long userId) { + final String sql = "SELECT film_id FROM film_like WHERE user_id = ?"; + return new HashSet<>(jdbcTemplate.queryForList(sql, Long.class, userId)); + } + @Override public Map> getUsersAndFilmLikes() { String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index f8b7eea7..6289735b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -21,5 +21,7 @@ public interface FilmService { Collection getMostPopularFilms(final int count); + Collection getCommonFilms(long userId, long friendId); + Collection getFilmsFromDirector(long directorId, String sortBy); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 368f2c18..45f3ba22 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import static ru.yandex.practicum.filmorate.mapper.FilmMapper.toDto; @@ -151,6 +152,32 @@ public Collection getMostPopularFilms(final int count) { return filmStorage.findMostLikedFilmsLimitBy(count).stream().map(FilmMapper::toDto).collect(Collectors.toList()); } + /** + * Получение списка общих понравившихся фильмов между двумя пользователями. + * Метод ищет фильмы, которые нравятся обоим пользователям, и возвращает их + * в порядке убывания популярности, определяемой количеством лайков. + * + * @param userId идентификатор первого пользователя. + * @param friendId идентификатор второго пользователя. + * @return список фильмов, которые нравятся обоим пользователям, упорядоченный + * по убыванию популярности. + */ + @Override + public Collection getCommonFilms(long userId, long friendId) { + + Set userFilms = filmLikeStorage.findLikedFilmsByUser(userId); + Set friendFilms = filmLikeStorage.findLikedFilmsByUser(friendId); + + userFilms.retainAll(friendFilms); + + return userFilms.stream() + .map(filmId -> filmStorage.findById(filmId)) + .filter(Objects::nonNull) + .map(FilmMapper::toDto) + .sorted(Comparator.comparingLong(FilmDto::getLikes).reversed()) + .collect(Collectors.toList()); + } + /** * Получение списка фильмов режиссера, отсортированных по количеству лайков или году выпуска. * From 9bdf2d755af826316f84fec8a7729635227750af Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 08:32:30 +0100 Subject: [PATCH 182/188] checkstyle --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index c80ef01f..9bd5ebea 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -51,7 +51,7 @@ public FilmDto removeLike(@PathVariable long id, @PathVariable long userId) { @GetMapping("/common") public Collection getCommonFilms( @RequestParam long userId, - @RequestParam long friendId){ + @RequestParam long friendId) { return filmService.getCommonFilms(userId, friendId); } From 209243d89dbfbe594c6561cccfca0379282f109e Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Wed, 31 Jan 2024 23:59:16 +0100 Subject: [PATCH 183/188] =?UTF-8?q?feat:=20=D0=9C=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=20getCommonFilms=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D1=82=20?= =?UTF-8?q?findFilmsByIds=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D0=B7=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D0=BD=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE=20=D1=84=D0=B8?= =?UTF-8?q?=D0=BB=D1=8C=D0=BC=D0=B0=D1=85=20=D0=B7=D0=B0=20=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BEc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/impl/FilmDbStorage.java | 72 +++++++++++++++++++ .../filmorate/dao/impl/FilmLikeDbStorage.java | 8 +-- .../service/impl/FilmServiceImpl.java | 29 ++++---- 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 6ab5b7a0..d805993a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; @@ -199,4 +200,75 @@ private Film mapToFilm(ResultSet rs, int rowNum) throws SQLException { film.setLikes(rs.getLong("likes")); return film; } + + private Collection extractToFilmList(ResultSet rs) throws SQLException, DataAccessException { + + final Map filmIdMap = new LinkedHashMap<>(); + + while (rs.next()) { + + Long filmId = rs.getLong(1); + Film film = filmIdMap.get(filmId); + if (film == null) { + film = Film.builder() + .id(filmId) + .name(rs.getString("title")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(new Mpa(rs.getInt("mpa_id"), rs.getString("rating_name"))) + .build(); + film.setLikes(rs.getLong("likes")); + filmIdMap.put(filmId, film); + } + + final int genre_id = rs.getInt("genre_id"); + if (genre_id == 0) { + film.getGenres().addAll(Collections.emptyList()); + continue; + } + + final Genre genre = new Genre(); + genre.setId(genre_id); + genre.setName(rs.getString("genre_name")); + film.getGenres().add(genre); + } + + return filmIdMap.values(); + } + @Override + public List findFilmsByIds(Set filmIds) { + if (filmIds.isEmpty()) { + return Collections.emptyList(); + } + + String placeholders = String.join(",", Collections.nCopies(filmIds.size(), "?")); + + String sql = "SELECT f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, " + + "m.RATING_NAME, COUNT(fl.USER_ID) AS LIKES " + + "FROM FILM f " + + "LEFT JOIN MPA m ON f.MPA_ID = m.ID " + + "LEFT JOIN film_like fl ON f.ID = fl.FILM_ID " + + "WHERE f.ID IN (" + placeholders + ") " + + "GROUP BY f.ID, m.RATING_NAME " + + "ORDER BY LIKES DESC"; + + Object[] idsArray = filmIds.toArray(new Object[0]); + + return jdbcTemplate.query(sql, idsArray, new RowMapper() { + @Override + public Film mapRow(ResultSet rs, int rowNum) throws SQLException { + Film film = new Film(); + film.setId(rs.getLong("ID")); + film.setName(rs.getString("TITLE")); + film.setDescription(rs.getString("DESCRIPTION")); + film.setReleaseDate(rs.getDate("RELEASE_DATE").toLocalDate()); + film.setDuration(rs.getInt("DURATION")); + film.setMpa(new Mpa(rs.getInt("MPA_ID"), rs.getString("RATING_NAME"))); + film.setLikes(rs.getLong("LIKES")); + return film; + } + }); + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java index 293a602d..901d3dd7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmLikeDbStorage.java @@ -10,10 +10,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; import java.util.*; @Repository @@ -56,9 +52,11 @@ public void remove(long filmId, long userId) { @Override public Set findLikedFilmsByUser(long userId) { final String sql = "SELECT film_id FROM film_like WHERE user_id = ?"; - return new HashSet<>(jdbcTemplate.queryForList(sql, Long.class, userId)); + List filmIds = jdbcTemplate.queryForList(sql, Long.class, userId); + return new HashSet<>(filmIds); } + @Override public Map> getUsersAndFilmLikes() { String filmsIdsSql = "SELECT user_id, film_id FROM film_like"; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 45f3ba22..5d3f1718 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -154,28 +154,27 @@ public Collection getMostPopularFilms(final int count) { /** * Получение списка общих понравившихся фильмов между двумя пользователями. - * Метод ищет фильмы, которые нравятся обоим пользователям, и возвращает их - * в порядке убывания популярности, определяемой количеством лайков. + * Этот метод идентифицирует фильмы, которые были отмечены как понравившиеся обоим пользователям, + * и возвращает их список, отсортированный по убыванию количества лайков * - * @param userId идентификатор первого пользователя. - * @param friendId идентификатор второго пользователя. - * @return список фильмов, которые нравятся обоим пользователям, упорядоченный - * по убыванию популярности. + * @param userId идентификатор первого пользователя. + * @param friendId идентификатор второго пользователя + * @return список DTO фильмов, которые лайкнуты обоими пользователями. . + * Если общих лайкнутых фильмов нет, возвращается пустой список. */ @Override public Collection getCommonFilms(long userId, long friendId) { + Set userLikedFilmIds = filmLikeStorage.findLikedFilmsByUser(userId); + Set friendLikedFilmIds = filmLikeStorage.findLikedFilmsByUser(friendId); - Set userFilms = filmLikeStorage.findLikedFilmsByUser(userId); - Set friendFilms = filmLikeStorage.findLikedFilmsByUser(friendId); + userLikedFilmIds.retainAll(friendLikedFilmIds); - userFilms.retainAll(friendFilms); + if (userLikedFilmIds.isEmpty()) { + return Collections.emptyList(); + } - return userFilms.stream() - .map(filmId -> filmStorage.findById(filmId)) - .filter(Objects::nonNull) - .map(FilmMapper::toDto) - .sorted(Comparator.comparingLong(FilmDto::getLikes).reversed()) - .collect(Collectors.toList()); + List commonFilms = filmStorage.findFilmsByIds(userLikedFilmIds); + return commonFilms.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } /** From 13d2c6abe12bb3723b9a665159d6ca02dc41ed5b Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Fri, 2 Feb 2024 17:32:04 +0100 Subject: [PATCH 184/188] Rename --- .../java/ru/yandex/practicum/filmorate/dao/FilmStorage.java | 3 +++ .../ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java | 4 ++-- .../practicum/filmorate/service/impl/FilmServiceImpl.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index 0e5c4cfc..887caa55 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -11,4 +11,7 @@ public interface FilmStorage extends Dao { Collection findFilmsByIds(Set filmIds); Collection findFilmsFromDirectorOrderBy(long directorId, String sortBy); + + Collection findFilmsByIdsOrderByLikes (Set filmIds); + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index d805993a..4c307b1a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -201,7 +201,7 @@ private Film mapToFilm(ResultSet rs, int rowNum) throws SQLException { return film; } - private Collection extractToFilmList(ResultSet rs) throws SQLException, DataAccessException { + private Collection extractToFilmList(ResultSet rs) throws SQLException { final Map filmIdMap = new LinkedHashMap<>(); @@ -237,7 +237,7 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException, Da return filmIdMap.values(); } @Override - public List findFilmsByIds(Set filmIds) { + public List findFilmsByIdsOrderByLikes(Set filmIds) { if (filmIds.isEmpty()) { return Collections.emptyList(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 5d3f1718..62999ee9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -173,7 +173,7 @@ public Collection getCommonFilms(long userId, long friendId) { return Collections.emptyList(); } - List commonFilms = filmStorage.findFilmsByIds(userLikedFilmIds); + Collection commonFilms = filmStorage.findFilmsByIdsOrderByLikes(userLikedFilmIds); return commonFilms.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } From 95a0cdc7561c270206156da1cb7947db28fa3624 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Thu, 1 Feb 2024 00:23:51 +0100 Subject: [PATCH 185/188] Checkstyle --- .../ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 4c307b1a..9104e0c7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -236,6 +236,7 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException { return filmIdMap.values(); } + @Override public List findFilmsByIdsOrderByLikes(Set filmIds) { if (filmIds.isEmpty()) { From 57d6a84c3ec195d0440678cede70e0130b15c675 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Fri, 2 Feb 2024 17:50:32 +0100 Subject: [PATCH 186/188] merging --- .../ru/yandex/practicum/filmorate/FilmorateApplication.java | 1 + .../practicum/filmorate/service/impl/FilmServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java index 79171d80..1c73d055 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java +++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java @@ -6,6 +6,7 @@ @SpringBootApplication public class FilmorateApplication { + public static void main(String[] args) { SpringApplication.run(FilmorateApplication.class, args); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 2c006557..0bfa86f6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -170,7 +170,7 @@ public Collection getCommonFilms(long userId, long friendId) { return Collections.emptyList(); } - List commonFilms = filmStorage.findFilmsByIds(userLikedFilmIds); + Collection commonFilms = filmStorage.findFilmsByIds(userLikedFilmIds); return commonFilms.stream().map(FilmMapper::toDto).collect(Collectors.toList()); } From 564f7c5661fdc43903f599a922975e34d401f0e5 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Fri, 2 Feb 2024 17:52:49 +0100 Subject: [PATCH 187/188] check style --- .../java/ru/yandex/practicum/filmorate/dao/FilmStorage.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java index 887caa55..fa71cd33 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmStorage.java @@ -12,6 +12,5 @@ public interface FilmStorage extends Dao { Collection findFilmsFromDirectorOrderBy(long directorId, String sortBy); - Collection findFilmsByIdsOrderByLikes (Set filmIds); - + Collection findFilmsByIdsOrderByLikes(Set filmIds); } From 7b969018d0afbcf497cb4020ba25505ba19c2a86 Mon Sep 17 00:00:00 2001 From: Kazantsev Date: Fri, 2 Feb 2024 18:07:11 +0100 Subject: [PATCH 188/188] fixing --- .../filmorate/dao/impl/FilmDbStorage.java | 39 +------------------ .../service/impl/FilmServiceImpl.java | 18 +++++++++ 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java index 621bfdc6..ee35de06 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FilmDbStorage.java @@ -238,7 +238,7 @@ private Collection extractToFilmList(ResultSet rs) throws SQLException { } @Override - public List findFilmsByIdsOrderByLikes(Set filmIds) { + public Collection findFilmsByIdsOrderByLikes(Set filmIds) { if (filmIds.isEmpty()) { return Collections.emptyList(); } @@ -271,41 +271,4 @@ public Film mapRow(ResultSet rs, int rowNum) throws SQLException { } }); } - - - @Override - public List findFilmsByIds(Set filmIds) { - if (filmIds.isEmpty()) { - return Collections.emptyList(); - } - - String placeholders = String.join(",", Collections.nCopies(filmIds.size(), "?")); - - String sql = "SELECT f.ID, f.TITLE, f.DESCRIPTION, f.RELEASE_DATE, f.DURATION, f.MPA_ID, " + - "m.RATING_NAME, COUNT(fl.USER_ID) AS LIKES " + - "FROM FILM f " + - "LEFT JOIN MPA m ON f.MPA_ID = m.ID " + - "LEFT JOIN film_like fl ON f.ID = fl.FILM_ID " + - "WHERE f.ID IN (" + placeholders + ") " + - "GROUP BY f.ID, m.RATING_NAME " + - "ORDER BY LIKES DESC"; - - Object[] idsArray = filmIds.toArray(new Object[0]); - - return jdbcTemplate.query(sql, idsArray, new RowMapper() { - @Override - public Film mapRow(ResultSet rs, int rowNum) throws SQLException { - Film film = new Film(); - film.setId(rs.getLong("ID")); - film.setName(rs.getString("TITLE")); - film.setDescription(rs.getString("DESCRIPTION")); - film.setReleaseDate(rs.getDate("RELEASE_DATE").toLocalDate()); - film.setDuration(rs.getInt("DURATION")); - film.setMpa(new Mpa(rs.getInt("MPA_ID"), rs.getString("RATING_NAME"))); - film.setLikes(rs.getLong("LIKES")); - return film; - } - }); - } - } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java index 0bfa86f6..9c392831 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/impl/FilmServiceImpl.java @@ -176,4 +176,22 @@ public Collection getCommonFilms(long userId, long friendId) { + /** + * Получение списка фильмов режиссера, отсортированных по количеству лайков или году выпуска. + * + * @param directorId идентификатор режиссера. + * @param sortBy поле сортировки. + * @return список фильмов режиссера. + */ + @Override + @Transactional + public Collection getFilmsFromDirector(final long directorId, final String sortBy) { + if (!ALLOWED_SORTS.containsKey(sortBy)) { + throw new IllegalArgumentException("Поле сортировки '" + sortBy + "' не поддерживается."); + } + directorStorage.findById(directorId); + return filmStorage.findFilmsFromDirectorOrderBy(directorId, ALLOWED_SORTS.get(sortBy)).stream() + .map(FilmMapper::toDto) + .collect(Collectors.toList()); + } } \ No newline at end of file