From ac6f9431a7d8c298e62c4187217b7268984a4722 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 22:28:00 +0300 Subject: [PATCH 01/54] feature: add delete user --- .../filmorate/controller/UserController.java | 6 ++++++ .../filmorate/dal/JdbcUserRepository.java | 9 ++++++++- .../practicum/filmorate/dal/UserRepository.java | 2 ++ .../practicum/filmorate/service/UserService.java | 2 ++ .../filmorate/service/UserServiceImpl.java | 7 +++++++ .../filmorate/dal/JdbcUserRepositoryTest.java | 16 ++++++++++++++++ 6 files changed, 41 insertions(+), 1 deletion(-) 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 7ef3e32..b17a7e8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -43,6 +43,12 @@ public User update(@Valid @RequestBody User newUser) { return userService.update(newUser); } + @DeleteMapping("/{userId}") + @ResponseStatus(HttpStatus.OK) + public void deleteUser(@PathVariable("userId") long userId) { + userService.deleteUser(userId); + } + @PutMapping("/{userId}/friends/{friendId}") @ResponseStatus(HttpStatus.OK) public void addFriend(@PathVariable("userId") long userId, @PathVariable("friendId") long friendId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index d12b04f..d7236e9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -19,6 +19,7 @@ public class JdbcUserRepository implements UserRepository { private static final String CREATE_USER_QUERY = "INSERT INTO users (login, email, name, birthday) VALUES(:login,:email,:name,:birthday)"; private static final String UPDATE_USER_QUERY = "UPDATE users SET login=:login, email=:email, name=:name, birthday=:birthday WHERE user_id=:user_id"; + private static final String DELETE_USER_QUERY = "DELETE FROM users WHERE user_id = :user_id"; private static final String GET_USER_BY_ID_QUERY = "SELECT * FROM users WHERE user_id = :user_id"; private static final String GET_ALL_USERS_QUERY = "SELECT * FROM users"; private static final String ADD_FRIEND_QUERY = "INSERT INTO friends(user_id, friend_id) VALUES(:user_id,:friend_id)"; @@ -43,7 +44,6 @@ public User create(User user) { @Override public User update(User user) { - GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("login", user.getLogin()); params.addValue("email", user.getEmail()); @@ -54,6 +54,13 @@ public User update(User user) { return user; } + @Override + public void deleteUser (long userId){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("user_id", userId); + jdbc.update(DELETE_USER_QUERY, params); + }; + @Override public Optional getUserById(long userId) { MapSqlParameterSource params = new MapSqlParameterSource(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java index 34b78b9..582e7e0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java @@ -16,6 +16,8 @@ public interface UserRepository { User update(User user); + void deleteUser (long userId); + void addFriend(long userId, long friendId); void deleteFriend(long userId, long friendId); 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 6e0a81e..95971a3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -13,6 +13,8 @@ public interface UserService { User update(User user); + void deleteUser(long userId); + void addFriend(long userId, long friendId); void deleteFriend(long userId, long friendId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index 4a88a17..a4c1ddd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -51,6 +51,13 @@ public User update(User user) { throw new NotFoundException("Пользователь с id = " + user.getId() + " не найден"); } + @Override + public void deleteUser(long userId){ + getUserById(userId); + jdbcUserRepository.deleteUser(userId); + log.info("Пользователь удален"); + } + private void checkUsersInTable(List usersIds) { List foundUsers = jdbcUserRepository.getUsersByIds(usersIds); if (foundUsers.size() != usersIds.size()) { diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepositoryTest.java index 271d633..9a16aa0 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepositoryTest.java @@ -153,6 +153,22 @@ void shouldUpdateUser() { .isEqualTo(getTestUserToUpdate()); } + @Test + @DisplayName("Должен удалять пользователя") + void shouldDeleteUser() { + User userBeforeDelete = jdbcUserRepository.getUserById(TEST_USER_ID) + .orElseThrow(() -> new NotFoundException("Не найден пользователь с id = " + TEST_USER_ID)); + + assertThat(jdbcUserRepository.getAllUsers()).hasSize(3); + assertThat(userBeforeDelete) + .usingRecursiveComparison() + .isEqualTo(getTestUser()); + + jdbcUserRepository.deleteUser(TEST_USER_ID); + + assertThat(jdbcUserRepository.getAllUsers()).hasSize(2); + } + @Test @DisplayName("Должен возвращать друзей пользователя") void shouldGetUserFriends() { From 58c50232ae838302c6d1e2024f87233cab71f1f2 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 22:44:42 +0300 Subject: [PATCH 02/54] feature: add delete film --- .../filmorate/controller/FilmController.java | 8 +++++++- .../practicum/filmorate/dal/FilmRepository.java | 2 ++ .../filmorate/dal/JdbcFilmRepository.java | 8 ++++++++ .../filmorate/service/FilmService.java | 4 +++- .../filmorate/service/FilmServiceImpl.java | 14 ++++++++++---- .../filmorate/dal/JdbcFilmRepositoryTest.java | 17 +++++++++++++++++ 6 files changed, 47 insertions(+), 6 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 ddbda8f..e2a89f4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -25,7 +25,7 @@ public Collection findAll() { @GetMapping("/{filmId}") public Film get(@PathVariable long filmId) { - return filmService.getById(filmId); + return filmService.getFilmById(filmId); } @PostMapping @@ -40,6 +40,12 @@ public Film update(@Valid @RequestBody Film newFilm) { return filmService.update(newFilm); } + @DeleteMapping("/{filmId}") + @ResponseStatus(HttpStatus.OK) + public void deleteFilm(@PathVariable("filmId") long filmId) { + filmService.deleteFilm(filmId); + } + @PutMapping("/{filmId}/like/{userId}") @ResponseStatus(HttpStatus.OK) public void addLike(@PathVariable("filmId") long filmId, @PathVariable("userId") long userId) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index 6ba8f3d..3afa2e5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -16,6 +16,8 @@ public interface FilmRepository { Film update(Film film); + void deleteFilm(long filmId); + void addLike(long filmId, long userId); void deleteLike(long filmId, long userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index baa5a73..ce253e0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -25,6 +25,7 @@ public class JdbcFilmRepository implements FilmRepository { private static final String CREATE_FILM_QUERY = "INSERT INTO films (name, description, release_date, duration, mpa_id) VALUES(:name,:description,:release_date,:duration,:mpa_id)"; private static final String CLEAN_GENRES_QUERY = "DELETE FROM film_genres WHERE film_id=:film_id"; private static final String UPDATE_FILM_QUERY = "UPDATE films SET name=:name, description=:description, release_date=:release_date, duration=:duration, mpa_id=:mpa_id WHERE film_id=:film_id"; + private static final String DELETE_FILM_QUERY = "DELETE FROM films WHERE film_id=:film_id"; private static final String GET_BY_ID_QUERY = """ SELECT f.*, r.mpa_name, COUNT(l.*) AS likes_count FROM films f JOIN mpa r ON f.mpa_id = r.mpa_id @@ -102,6 +103,13 @@ public Film update(Film film) { return film; } + @Override + public void deleteFilm(long filmId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("film_id", filmId); + jdbc.update(DELETE_FILM_QUERY, params); + } + @Override public Optional getFilmById(long id) { MapSqlParameterSource params = new MapSqlParameterSource(); 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 89b6f7d..9489df6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -5,7 +5,7 @@ import java.util.List; public interface FilmService { - Film getById(long filmId); + Film getFilmById(long filmId); List getFilms(); @@ -13,6 +13,8 @@ public interface FilmService { Film update(Film film); + void deleteFilm(long filmId); + void addLike(long filmId, long userId); void deleteLike(long filmId, long userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 27b0ded..be1953b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -28,7 +28,7 @@ public class FilmServiceImpl implements FilmService { private final JdbcMpaRepository jdbcMpaRepository; @Override - public Film getById(long filmId) { + public Film getFilmById(long filmId) { return jdbcFilmRepository.getFilmById(filmId) .orElseThrow(() -> new NotFoundException("Фильм с id = " + filmId + " не найден")); } @@ -71,7 +71,7 @@ public Film update(Film film) { } if (jdbcFilmRepository.getAllFilms().stream().anyMatch((oldFilm) -> oldFilm.getId() == film.getId())) { - Film savedFilm = getById(film.getId()); + Film savedFilm = getFilmById(film.getId()); film.setLikesCount(savedFilm.getLikesCount()); Mpa mpa = jdbcMpaRepository.getMpaById(film.getMpa().getId()) .orElseThrow(() -> new NotFoundException("Рейтинг с id " + film.getMpa().getId() + " не найден")); @@ -97,9 +97,15 @@ public Film update(Film film) { throw new NotFoundException("Фильм с id = " + film.getId() + " не найден"); } + public void deleteFilm(long filmId){ + getFilmById(filmId); + jdbcFilmRepository.deleteFilm(filmId); + log.info("Фильм удален"); + } + @Override public void addLike(long filmId, long userId) { - Film film = getById(filmId); + Film film = getFilmById(filmId); jdbcUserRepository.getUserById(userId) .orElseThrow(() -> new NotFoundException("Пользователь с id = " + userId + " не найден")); @@ -112,7 +118,7 @@ public void addLike(long filmId, long userId) { @Override public void deleteLike(long filmId, long userId) { - Film film = getById(filmId); + Film film = getFilmById(filmId); jdbcUserRepository.getUserById(userId) .orElseThrow(() -> new NotFoundException("Пользователь с id = " + userId + " не найден")); diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java index 6fa993f..ae68b8b 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java @@ -12,6 +12,7 @@ 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 java.time.LocalDate; import java.util.ArrayList; @@ -197,6 +198,22 @@ void shouldUpdateFilm() { .isEqualTo(getTestFilmToCreateOrUpdate()); } + @Test + @DisplayName("Должен удалять фильм") + void shouldDeleteFilm() { + Film filmBeforeDelete = jdbcFilmRepository.getFilmById(TEST_FILM_ID) + .orElseThrow(() -> new NotFoundException("Не найден фильм с id = " + TEST_FILM_ID)); + + assertThat(jdbcFilmRepository.getAllFilms()).hasSize(3); + assertThat(filmBeforeDelete) + .usingRecursiveComparison() + .isEqualTo(getTestFilm()); + + jdbcFilmRepository.deleteFilm(TEST_FILM_ID); + + assertThat(jdbcFilmRepository.getAllFilms()).hasSize(2); + } + @Test @DisplayName("Должен добавлять записи о лайках") void shouldAddLike() { From 9ba05f0c8e9e2fcc19bfab00546cbc090a6db46e Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 22:59:01 +0300 Subject: [PATCH 03/54] fix: code styles --- .../ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index d7236e9..b559549 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -55,11 +55,11 @@ public User update(User user) { } @Override - public void deleteUser (long userId){ + public void deleteUser(long userId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("user_id", userId); jdbc.update(DELETE_USER_QUERY, params); - }; + } @Override public Optional getUserById(long userId) { From 8807e6dd6a2068bf23fce65fc36ca97bf5532116 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 23:10:29 +0300 Subject: [PATCH 04/54] fix: code styles --- .../java/ru/yandex/practicum/filmorate/dal/UserRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java index 582e7e0..531de81 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java @@ -16,7 +16,7 @@ public interface UserRepository { User update(User user); - void deleteUser (long userId); + void deleteUser(long userId); void addFriend(long userId, long friendId); From fc97220ef4430b819d22f7739f3eb6ecb0291157 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 23:12:29 +0300 Subject: [PATCH 05/54] fix: code styles --- .../ru/yandex/practicum/filmorate/service/FilmServiceImpl.java | 2 +- .../ru/yandex/practicum/filmorate/service/UserServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index be1953b..14a604a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -97,7 +97,7 @@ public Film update(Film film) { throw new NotFoundException("Фильм с id = " + film.getId() + " не найден"); } - public void deleteFilm(long filmId){ + public void deleteFilm(long filmId) { getFilmById(filmId); jdbcFilmRepository.deleteFilm(filmId); log.info("Фильм удален"); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index a4c1ddd..19c8a55 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -52,7 +52,7 @@ public User update(User user) { } @Override - public void deleteUser(long userId){ + public void deleteUser(long userId) { getUserById(userId); jdbcUserRepository.deleteUser(userId); log.info("Пользователь удален"); From f339dde6dd9596636a437056253eb07e374eab8c Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Tue, 6 May 2025 23:17:07 +0300 Subject: [PATCH 06/54] fix: code styles --- .../yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java index ae68b8b..c7f9ed5 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java @@ -12,7 +12,6 @@ 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 java.time.LocalDate; import java.util.ArrayList; From 90ad9e17c3a053d047cdec078db3117346f7fcc3 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Wed, 7 May 2025 23:27:12 +0300 Subject: [PATCH 07/54] =?UTF-8?q?feature:=20Add=20most=20populars=20-=20?= =?UTF-8?q?=D0=92=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=BF=D0=BE=D0=BF=D1=83=D0=BB?= =?UTF-8?q?=D1=8F=D1=80=D0=BD=D1=8B=D1=85=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BF=D0=BE=20=D0=B6=D0=B0=D0=BD=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=20=D0=B8=20=D0=B3=D0=BE=D0=B4=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/FilmController.java | 6 ++++-- .../ru/yandex/practicum/filmorate/service/FilmService.java | 2 ++ .../yandex/practicum/filmorate/service/FilmServiceImpl.java | 6 ++++++ .../practicum/filmorate/dal/JdbcFilmRepositoryTest.java | 2 ++ 4 files changed, 14 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 e2a89f4..5bbd2eb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -60,7 +60,9 @@ public void deleteLike(@PathVariable("id") long id, @PathVariable("userId") long @GetMapping("/popular") @ResponseStatus(HttpStatus.OK) - public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count) { - return filmService.getPopularFilms(count); + public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count, + @RequestParam(value = "genreId", defaultValue = "all") final Long genreId, + @RequestParam(value = "year", defaultValue = "all") final Integer year) { + return filmService.getPopularFilms(count, genreId, year); } } 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 9489df6..a83136e 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 deleteLike(long filmId, long userId); List getPopularFilms(int count); + + List getPopularFilms(int count, long genreId, int year); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 14a604a..1cbb9ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -134,4 +134,10 @@ public List getPopularFilms(int count) { List popularFilms = jdbcFilmRepository.getPopularFilms(count); return popularFilms; } + + @Override + public List getPopularFilms(int count, long genreId, int year) { + List popularFilms = jdbcFilmRepository.getPopularFilms(count); + return popularFilms; + } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java index c7f9ed5..1145629 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java @@ -204,6 +204,7 @@ void shouldDeleteFilm() { .orElseThrow(() -> new NotFoundException("Не найден фильм с id = " + TEST_FILM_ID)); assertThat(jdbcFilmRepository.getAllFilms()).hasSize(3); + assertThat(jdbcFilmRepository.getPopularFilms(1000)).hasSize(3); assertThat(filmBeforeDelete) .usingRecursiveComparison() .isEqualTo(getTestFilm()); @@ -211,6 +212,7 @@ void shouldDeleteFilm() { jdbcFilmRepository.deleteFilm(TEST_FILM_ID); assertThat(jdbcFilmRepository.getAllFilms()).hasSize(2); + assertThat(jdbcFilmRepository.getPopularFilms(1000)).hasSize(2); } @Test From 585404792586b14150c49733e51f352f7b3335ab Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Wed, 7 May 2025 23:55:11 +0300 Subject: [PATCH 08/54] fix: sql request for popular films --- .../yandex/practicum/filmorate/dal/JdbcFilmRepository.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ce253e0..ee12e2d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -47,10 +47,11 @@ public class JdbcFilmRepository implements FilmRepository { private static final String GET_POPULAR_FILMS_QUERY = """ SELECT f.*, r.mpa_name, COUNT(l.user_id) AS likes_count FROM films f - JOIN likes l ON l.film_id = f.film_id + LEFT JOIN likes l ON l.film_id = f.film_id JOIN mpa r ON r.mpa_id = f.mpa_id - GROUP BY f.film_id - ORDER BY COUNT(l.user_id) DESC + WHERE f.film_id IS NOT NULL + GROUP BY f.film_id, r.mpa_name + ORDER BY likes_count DESC LIMIT :limit """; From 7863706b1a65aa6c67078d36072dbeef580c359a Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 9 May 2025 18:58:20 +0300 Subject: [PATCH 09/54] =?UTF-8?q?feature:=20Add=20most=20populars=20-=20?= =?UTF-8?q?=D0=92=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D0=B0=D0=BC=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BF=D1=83=D0=BB=D1=8F=D1=80=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=B6=D0=B0=D0=BD=D1=80=D0=B0=D0=BC=20=D0=B8=20=D0=B3=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 6 +-- .../filmorate/dal/FilmRepository.java | 2 +- .../filmorate/dal/JdbcFilmRepository.java | 46 +++++++++++++------ .../filmorate/service/FilmService.java | 4 +- .../filmorate/service/FilmServiceImpl.java | 10 +--- .../filmorate/dal/JdbcFilmRepositoryTest.java | 11 ++--- 6 files changed, 43 insertions(+), 36 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 5bbd2eb..c015103 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -60,9 +60,9 @@ public void deleteLike(@PathVariable("id") long id, @PathVariable("userId") long @GetMapping("/popular") @ResponseStatus(HttpStatus.OK) - public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count, - @RequestParam(value = "genreId", defaultValue = "all") final Long genreId, - @RequestParam(value = "year", defaultValue = "all") final Integer year) { + public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") Integer count, + @RequestParam(value = "genreId", required = false) Long genreId, + @RequestParam(value = "year", required = false) Integer year) { return filmService.getPopularFilms(count, genreId, year); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index 3afa2e5..1c254fc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -26,5 +26,5 @@ public interface FilmRepository { LinkedHashSet getFilmGenres(Film film); - List getPopularFilms(int count); + List getPopularFilms(int count, Long genreId, Integer year); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ee12e2d..c71a1b0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -44,16 +44,6 @@ public class JdbcFilmRepository implements FilmRepository { private static final String GET_GENRE_QUERY = "SELECT g.genre_id, g.genre_name FROM film_genres fg JOIN genres g ON fg.genre_id = g.genre_id WHERE fg.film_id = :film_id"; private static final String ADD_LIKE_QUERY = "INSERT INTO likes (user_id, film_id) VALUES(:user_id, :film_id)"; private static final String DELETE_LIKE_QUERY = "DELETE FROM likes WHERE film_id=:film_id AND user_id=:user_id;"; - private static final String GET_POPULAR_FILMS_QUERY = """ - SELECT f.*, r.mpa_name, COUNT(l.user_id) AS likes_count - FROM films f - LEFT JOIN likes l ON l.film_id = f.film_id - JOIN mpa r ON r.mpa_id = f.mpa_id - WHERE f.film_id IS NOT NULL - GROUP BY f.film_id, r.mpa_name - ORDER BY likes_count DESC - LIMIT :limit - """; private static final String SELECT_GENRES_BY_FILM_IDS_QUERY = """ SELECT * @@ -189,11 +179,39 @@ public void deleteLike(long filmId, long userId) { } @Override - public List getPopularFilms(int count) { + public List getPopularFilms(int count, Long genreId, Integer year) { + List popularFilms; MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("limit", count); - List popularFilms = jdbc.query(GET_POPULAR_FILMS_QUERY, params, mapper); - + params.addValue("count", count); + if (genreId != null) params.addValue("genreId", genreId); + if (year != null) params.addValue("year", year); + final String GET_POPULAR_FILMS_PREFIX_QUERY = """ + SELECT f.*, r.mpa_name, COUNT(l.user_id) AS likes_count + FROM films f + LEFT JOIN likes l ON l.film_id = f.film_id + LEFT JOIN film_genres fg ON fg.film_id = f.film_id + JOIN mpa r ON r.mpa_id = f.mpa_id + WHERE f.film_id IS NOT NULL + """; + final String GET_POPULAR_FILMS_POSTFIX_QUERY = """ + GROUP BY f.film_id, r.mpa_name + ORDER BY likes_count DESC + LIMIT :count + """; + String GENRE_SQL = "AND fg.genre_id=:genreId"; + String YEAR_SQL = "AND EXTRACT(YEAR FROM f.release_date)=:year"; + String sql; + + if (genreId == null && year == null) { + sql = GET_POPULAR_FILMS_PREFIX_QUERY + " " + GET_POPULAR_FILMS_POSTFIX_QUERY; + } else if (genreId != null && year == null) { + sql = GET_POPULAR_FILMS_PREFIX_QUERY + " " + GENRE_SQL + " " + GET_POPULAR_FILMS_POSTFIX_QUERY; + } else if (genreId == null && year != null) { + sql = GET_POPULAR_FILMS_PREFIX_QUERY + " " + YEAR_SQL + " " + GET_POPULAR_FILMS_POSTFIX_QUERY; + } else { + sql = GET_POPULAR_FILMS_PREFIX_QUERY + " " + GENRE_SQL + " " + YEAR_SQL + " " + GET_POPULAR_FILMS_POSTFIX_QUERY; + } + popularFilms = jdbc.query(sql, params, mapper); connectGenres(popularFilms); return popularFilms; } 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 a83136e..f47f4f8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -19,7 +19,5 @@ public interface FilmService { void deleteLike(long filmId, long userId); - List getPopularFilms(int count); - - List getPopularFilms(int count, long genreId, int year); + List getPopularFilms(int count, Long genreId, Integer year); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 1cbb9ff..978a237 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -130,14 +130,8 @@ public void deleteLike(long filmId, long userId) { } @Override - public List getPopularFilms(int count) { - List popularFilms = jdbcFilmRepository.getPopularFilms(count); - return popularFilms; - } - - @Override - public List getPopularFilms(int count, long genreId, int year) { - List popularFilms = jdbcFilmRepository.getPopularFilms(count); + public List getPopularFilms(int count, Long genreId, Integer year) { + List popularFilms = jdbcFilmRepository.getPopularFilms(count, genreId, year); return popularFilms; } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java index 1145629..33d6cc3 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java @@ -204,7 +204,7 @@ void shouldDeleteFilm() { .orElseThrow(() -> new NotFoundException("Не найден фильм с id = " + TEST_FILM_ID)); assertThat(jdbcFilmRepository.getAllFilms()).hasSize(3); - assertThat(jdbcFilmRepository.getPopularFilms(1000)).hasSize(3); + assertThat(jdbcFilmRepository.getPopularFilms(1000, 1L, 2000)).hasSize(1); assertThat(filmBeforeDelete) .usingRecursiveComparison() .isEqualTo(getTestFilm()); @@ -212,7 +212,7 @@ void shouldDeleteFilm() { jdbcFilmRepository.deleteFilm(TEST_FILM_ID); assertThat(jdbcFilmRepository.getAllFilms()).hasSize(2); - assertThat(jdbcFilmRepository.getPopularFilms(1000)).hasSize(2); + assertThat(jdbcFilmRepository.getPopularFilms(1000, 1L, 2000)).hasSize(0); } @Test @@ -250,16 +250,13 @@ void shouldDeleteLikeRecord() { @Test @DisplayName("Должен возвращать сортированный список популярных фильмов") void shouldGetPopularFilms() { - List popularFilms = jdbcFilmRepository.getPopularFilms(2); + List popularFilms = jdbcFilmRepository.getPopularFilms(2, 1L, 1950); List filmsTest = getAllTestFilms(); - assertThat(popularFilms).hasSize(2); + assertThat(popularFilms).hasSize(1); assertThat(popularFilms.get(0)) .usingRecursiveComparison() .isEqualTo(filmsTest.get(1)); - assertThat(popularFilms.get(1)) - .usingRecursiveComparison() - .isEqualTo(filmsTest.get(2)); } } \ No newline at end of file From 4eb3718d85d3fb9c4d5ce98ddb89e9adb05deaae Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 9 May 2025 19:13:34 +0300 Subject: [PATCH 10/54] fix: code style errors --- .../ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index c71a1b0..4050798 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -198,8 +198,8 @@ public List getPopularFilms(int count, Long genreId, Integer year) { ORDER BY likes_count DESC LIMIT :count """; - String GENRE_SQL = "AND fg.genre_id=:genreId"; - String YEAR_SQL = "AND EXTRACT(YEAR FROM f.release_date)=:year"; + final String GENRE_SQL = "AND fg.genre_id=:genreId"; + final String YEAR_SQL = "AND EXTRACT(YEAR FROM f.release_date)=:year"; String sql; if (genreId == null && year == null) { From d019cc81b702b3e26f001bfe5c04d88d93f1f466 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 9 May 2025 22:38:22 +0500 Subject: [PATCH 11/54] =?UTF-8?q?=D0=92=D0=B5=D1=82=D0=BA=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B8=20add-revie?= =?UTF-8?q?ws.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 76 +++++++++ .../filmorate/dal/JdbcReviewRepository.java | 160 ++++++++++++++++++ .../filmorate/dal/ReviewRepository.java | 26 +++ .../dal/mappers/ReviewRowMapper.java | 23 +++ .../practicum/filmorate/model/Review.java | 25 +++ .../filmorate/service/ReviewServiceImpl.java | 105 ++++++++++++ src/main/resources/schema.sql | 16 ++ 7 files changed, 431 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ReviewRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Review.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.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 0000000..447e08f --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -0,0 +1,76 @@ +package ru.yandex.practicum.filmorate.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.service.ReviewServiceImpl; + +import java.util.List; +import java.util.Optional; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/reviews") +@Validated +public class ReviewController { + private final ReviewServiceImpl reviewService; + + @GetMapping("/{id}") + @ResponseStatus(HttpStatus.OK) + public Optional getReviewById(@PathVariable long id) { + return reviewService.getReviewById(id); + } + + @GetMapping + @ResponseStatus(HttpStatus.OK) + public List getAllReviewsByFilmId(@RequestParam(value = "filmId") long filmId, + @RequestParam(value = "count", defaultValue = "10") long count) { + return reviewService.getAllReviewsByFilmId(filmId, count); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Review create(@Valid @RequestBody Review review) { + return reviewService.create(review); + } + + @PutMapping + @ResponseStatus(HttpStatus.OK) + public Review update(@Valid @RequestBody Review review) { + return reviewService.update(review); + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.OK) + public void deleteReview(@PathVariable long id) { + reviewService.deleteReview(id); + } + + @PutMapping("/{reviewId}/like/{userId}") + @ResponseStatus(HttpStatus.OK) + public void addLike(@PathVariable long reviewId, @PathVariable long userId) { + reviewService.addLike(reviewId, userId); + } + + @PutMapping("/{reviewId}/dislike/{userId}") + @ResponseStatus(HttpStatus.OK) + public void addDislike(@PathVariable long reviewId, @PathVariable long userId) { + reviewService.addDislike(reviewId, userId); + } + + @DeleteMapping("/{reviewId}/like/{userId}") + @ResponseStatus(HttpStatus.OK) + public void deleteLike(@PathVariable long reviewId, @PathVariable long userId) { + reviewService.deleteLike(reviewId, userId); + } + + @DeleteMapping("/{reviewId}/dislike/{userId}") + @ResponseStatus(HttpStatus.OK) + public void deleteDislike(@PathVariable long reviewId, @PathVariable long userId) { + reviewService.deleteDislike(reviewId, userId); + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java new file mode 100644 index 0000000..2be207c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -0,0 +1,160 @@ +package ru.yandex.practicum.filmorate.dal; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dal.mappers.ReviewRowMapper; +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +@Repository +@RequiredArgsConstructor +public class JdbcReviewRepository implements ReviewRepository { + private final NamedParameterJdbcOperations jdbc; + private final ReviewRowMapper reviewMapper; + + private static final String GET_BY_ID_REVIEW = """ + SELECT + r.reviewId, + r.content, + r.isPositive, + r.userId, + r.filmId, + COALESCE(SUM(rl.reaction_type), 0) AS useful + FROM reviews r + LEFT JOIN reviews_likes rl ON r.reviewId = rl.reviewId + WHERE r.reviewId = :reviewId + GROUP BY r.reviewId, r.content, r.isPositive, r.userId, r.filmId; + """; + + private static final String GET_ALL_REVIEW = """ + SELECT + r.reviewId, + r.content, + r.isPositive, + r.userId, + r.filmId, + COALESCE(SUM(rl.reaction_type), 0) AS useful + FROM reviews r + LEFT JOIN reviews_likes rl ON r.reviewId = rl.reviewId + GROUP BY r.reviewId, r.content, r.isPositive, r.userId, r.filmId; + """; + + private static final String CREATE_REVIEW = """ + INSERT INTO reviews (content, isPositive, userId, filmId, useful) + VALUES(:content,:isPositive,:userId,:filmId,:useful) + """; + private static final String UPDATE_REVIEW = """ + UPDATE reviews + SET content=:content, isPositive=:isPositive, userId=:userId, filmId=:filmId, useful=:useful + WHERE reviewId=:reviewId + """; + private static final String DELETE_REVIEW = """ + DELETE FROM reviews + WHERE reviewId=:reviewId + """; + private static final String ADD_LIKE_REVIEW = """ + INSERT INTO reviews_likes (reviewId, userId, reaction_type) + VALUES(:reviewId, :userId, 1) + """; + private static final String ADD_DISLIKE_REVIEW = """ + INSERT INTO reviews_likes (reviewId, userId, reaction_type) + VALUES(:reviewId, :userId, -1) + """; + private static final String DELETE_LIKE_REVIEW = """ + DELETE FROM reviews_likes + WHERE reviewId=:reviewId AND userId=:userId + """; + + + @Override + public Optional getReviewById(long reviewId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("reviewId", reviewId); + try (Stream stream = jdbc.queryForStream(GET_BY_ID_REVIEW, params, reviewMapper)) { + return stream.findAny(); + } + } + + @Override + public List getAllReviewsByFilmId(long filmId, long count) { + return jdbc.query(GET_ALL_REVIEW, reviewMapper).reversed(); + } + + @Override + public Review create(Review review) { + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + MapSqlParameterSource params = new MapSqlParameterSource(); + + params.addValue("content", review.getContent()); + params.addValue("isPositive", review.getIsPositive()); + params.addValue("userId", review.getUserId()); + params.addValue("filmId", review.getFilmId()); + params.addValue("useful", review.getUseful()); + + jdbc.update(CREATE_REVIEW, params, keyHolder); + review.setReviewId(keyHolder.getKeyAs(Long.class)); + + return review; + } + + @Override + public Review update(Review review) { + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + MapSqlParameterSource params = new MapSqlParameterSource(); + + params.addValue("content", review.getContent()); + params.addValue("isPositive", review.getIsPositive()); + params.addValue("userId", review.getUserId()); + params.addValue("filmId", review.getFilmId()); + params.addValue("useful", review.getUseful()); + params.addValue("reviewId", review.getReviewId()); + + jdbc.update(UPDATE_REVIEW, params, keyHolder); + + return review; + } + + @Override + public void deleteReview(long reviewId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("reviewId", reviewId); + jdbc.update(DELETE_REVIEW, params); + } + + @Override + public void addLike(long reviewId, long userId) { + deleteLike(reviewId, userId); + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("reviewId", reviewId); + params.addValue("userId", userId); + jdbc.update(ADD_LIKE_REVIEW, params); + } + + @Override + public void addDislike(long reviewId, long userId) { + deleteLike(reviewId, userId); + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("reviewId", reviewId); + params.addValue("userId", userId); + jdbc.update(ADD_DISLIKE_REVIEW, params); + } + + @Override + public void deleteLike(long reviewId, long userId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("reviewId", reviewId); + params.addValue("userId", userId); + jdbc.update(DELETE_LIKE_REVIEW, params); + } + + @Override + public void deleteDislike(long reviewId, long userId) { + deleteLike(reviewId, userId); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java new file mode 100644 index 0000000..4c08292 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java @@ -0,0 +1,26 @@ +package ru.yandex.practicum.filmorate.dal; + +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.List; +import java.util.Optional; + +public interface ReviewRepository { + Optional getReviewById(long reviewId); + + List getAllReviewsByFilmId(long filmId, long count); + + Review create(Review review); + + Review update(Review review); + + void deleteReview(long reviewId); + + void addLike(long reviewId, long userId); + + void addDislike(long reviewId, long userId); + + void deleteLike(long reviewId, long userId); + + void deleteDislike(long reviewId, long userId); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ReviewRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ReviewRowMapper.java new file mode 100644 index 0000000..244607e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ReviewRowMapper.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.dal.mappers; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Review; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Component +public class ReviewRowMapper implements RowMapper { + @Override + public Review mapRow(ResultSet rs, int rowNum) throws SQLException { + Review review = new Review(); + review.setReviewId(rs.getLong("reviewId")); + review.setContent(rs.getString("content")); + review.setIsPositive(rs.getBoolean("isPositive")); + review.setUserId(rs.getLong("userId")); + review.setFilmId(rs.getLong("filmId")); + review.setUseful(rs.getLong("useful")); + return review; + } +} 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 0000000..02519f5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -0,0 +1,25 @@ +package ru.yandex.practicum.filmorate.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Review { + private long reviewId; + @NotBlank(message = "Отзыв не может быть пустым") + private String content; + @NotNull + @JsonProperty("isPositive") + private Boolean isPositive; + @NotNull + private Long userId; + @NotNull + private Long filmId; + private long useful; +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java new file mode 100644 index 0000000..623e0cf --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java @@ -0,0 +1,105 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import ru.yandex.practicum.filmorate.dal.JdbcFilmRepository; +import ru.yandex.practicum.filmorate.dal.JdbcReviewRepository; +import ru.yandex.practicum.filmorate.dal.JdbcUserRepository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +@RequiredArgsConstructor +@Validated +public class ReviewServiceImpl { + private final JdbcReviewRepository jdbcReviewRepository; + private final JdbcFilmRepository jdbcFilmRepository; + private final JdbcUserRepository jdbcUserRepository; + + public Optional getReviewById(long reviewId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + return jdbcReviewRepository.getReviewById(reviewId); + } + + public List getAllReviewsByFilmId(long filmId, long count) { + if (jdbcFilmRepository.getFilmById(filmId).isEmpty()) { + throw new NotFoundException("Фильм с id = " + filmId + " не найден"); + } + return jdbcReviewRepository.getAllReviewsByFilmId(filmId, count); + } + + public Review create(Review review) { + if (jdbcUserRepository.getUserById(review.getUserId()).isEmpty()) { + throw new NotFoundException("Пользователь не найден"); + } + if (jdbcFilmRepository.getFilmById(review.getFilmId()).isEmpty()) { + throw new NotFoundException("Фильм не найден"); + } + return jdbcReviewRepository.create(review); + } + + public Review update(Review review) { + if (jdbcUserRepository.getUserById(review.getUserId()).isEmpty()) { + throw new NotFoundException("Пользователь не найден"); + } + if (jdbcFilmRepository.getFilmById(review.getFilmId()).isEmpty()) { + throw new NotFoundException("Фильм не найден"); + } + return jdbcReviewRepository.update(review); + } + + public void deleteReview(long reviewId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + jdbcReviewRepository.deleteReview(reviewId); + } + + public void addLike(long reviewId, long userId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + if (jdbcUserRepository.getUserById(userId).isEmpty()) { + throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); + } + jdbcReviewRepository.addLike(reviewId, userId); + } + + public void addDislike(long reviewId, long userId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + if (jdbcUserRepository.getUserById(userId).isEmpty()) { + throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); + } + jdbcReviewRepository.addDislike(reviewId, userId); + } + + public void deleteLike(long reviewId, long userId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + if (jdbcUserRepository.getUserById(userId).isEmpty()) { + throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); + } + jdbcReviewRepository.deleteLike(reviewId, userId); + } + + public void deleteDislike(long reviewId, long userId) { + if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { + throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); + } + if (jdbcUserRepository.getUserById(userId).isEmpty()) { + throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); + } + jdbcReviewRepository.deleteDislike(reviewId, userId); + } +} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index c446ed6..66f026f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -43,3 +43,19 @@ CREATE TABLE IF NOT EXISTS likes ( user_id BIGINT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, PRIMARY KEY (film_id, user_id) ); + +CREATE TABLE IF NOT EXISTS reviews ( + reviewId BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + content VARCHAR(255) NOT NULL, + isPositive boolean NOT NULL, + userId BIGINT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, + filmId BIGINT NOT NULL REFERENCES films(film_id) ON DELETE CASCADE, + useful INTEGER DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS reviews_likes ( + reviewId BIGINT NOT NULL REFERENCES reviews(reviewId) ON DELETE CASCADE, + userId BIGINT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, + reaction_type SMALLINT NOT NULL CHECK (reaction_type IN (-1, 1)), + PRIMARY KEY (reviewId, userId) +); From 3b32b7ef99e95c390cc2d65874a649f7a2d89bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 15:37:45 +0400 Subject: [PATCH 12/54] =?UTF-8?q?Add=20director=20-=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B6?= =?UTF-8?q?=D0=B8=D1=81=D1=81=D1=91=D1=80=D0=BE=D0=B2=20=D0=B2=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BC=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DirectorController.java | 48 ++++++++ .../filmorate/controller/FilmController.java | 10 ++ .../filmorate/dal/DirectorRepository.java | 18 +++ .../filmorate/dal/FilmRepository.java | 14 +++ .../filmorate/dal/JdbcDirectorRepository.java | 66 +++++++++++ .../filmorate/dal/JdbcFilmRepository.java | 103 +++++++++++++++++- .../dal/mappers/DirectorRowMapper.java | 19 ++++ .../filmorate/dal/mappers/FilmRowMapper.java | 2 + .../practicum/filmorate/model/Director.java | 13 +++ .../practicum/filmorate/model/Film.java | 1 + .../filmorate/service/DirectorService.java | 17 +++ .../service/DirectorServiceImpl.java | 58 ++++++++++ .../filmorate/service/FilmService.java | 4 + .../filmorate/service/FilmServiceImpl.java | 10 ++ src/main/resources/schema.sql | 13 ++- .../filmorate/dal/JdbcFilmRepositoryTest.java | 4 + 16 files changed, 396 insertions(+), 4 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/mappers/DirectorRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Director.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.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 0000000..09e8b2e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -0,0 +1,48 @@ +package ru.yandex.practicum.filmorate.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.service.DirectorServiceImpl; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/directors") +@Validated +public class DirectorController { + + private final DirectorServiceImpl directorService; + + @PostMapping + @ResponseStatus(HttpStatus.OK) + public Director create(@RequestBody Director director){ + return directorService.create(director); + + } + @GetMapping + @ResponseStatus(HttpStatus.OK) + public List getAll(){ + return directorService.getAll(); + } + @GetMapping(path = "/{id}") + @ResponseStatus(HttpStatus.OK) + public Director getById(@PathVariable("id") long id){ + return directorService.getById(id); + + } + @PutMapping + @ResponseStatus(HttpStatus.OK) + public Director updateDirector(@Valid @RequestBody Director director) { + return directorService.update(director); + } + @DeleteMapping(path = "/{id}" ) + @ResponseStatus(HttpStatus.OK) + public void deleteDirector(@PathVariable("id") long id){ + directorService.delete(id); + } +} 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 e2a89f4..f61540b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -5,6 +5,7 @@ import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.service.FilmService; @@ -63,4 +64,13 @@ public void deleteLike(@PathVariable("id") long id, @PathVariable("userId") long public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count) { return filmService.getPopularFilms(count); } + @GetMapping("/director/{directorId}") + @ResponseStatus(HttpStatus.OK) + public Collection getDirectorFilm(@RequestParam(value = "sortBy") final String sort,@PathVariable("directorId") long directorId){ + if (sort.equals("year")){ + return filmService.getDirectorFilmsByYear(directorId); + } else if (sort.equals("likes")) { + return filmService.getDirectorFilmsByLikes(directorId); + } else throw new ValidationException("некорректный запрос"); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java new file mode 100644 index 0000000..a680eb9 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java @@ -0,0 +1,18 @@ +package ru.yandex.practicum.filmorate.dal; + +import ru.yandex.practicum.filmorate.model.Director; + +import java.util.List; +import java.util.Optional; + +public interface DirectorRepository { + Director create(Director director); + + List getAll(); + + Optional getById(Long directorId); + + Director update(Director director); + + void delete(Long id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index 3afa2e5..e798cab 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -1,8 +1,10 @@ package ru.yandex.practicum.filmorate.dal; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -18,13 +20,25 @@ public interface FilmRepository { void deleteFilm(long filmId); + LinkedHashSet getFilmDirectors(Film film); + + void connectGenres(Collection films); + + void connectDirectors(Collection films); + void addLike(long filmId, long userId); void deleteLike(long filmId, long userId); void setFilmGenres(Film film); + void setFilmDirectors(Film film); + LinkedHashSet getFilmGenres(Film film); List getPopularFilms(int count); + + List getDirectorFilmsByYear(long id); + + List getDirectorFilmByLikes(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java new file mode 100644 index 0000000..9393126 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java @@ -0,0 +1,66 @@ +package ru.yandex.practicum.filmorate.dal; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; +import ru.yandex.practicum.filmorate.model.Director; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +@Repository +@RequiredArgsConstructor +public class JdbcDirectorRepository implements DirectorRepository{ + private final NamedParameterJdbcOperations jdbc; + private final DirectorRowMapper mapper; + + private static final String CREATE_DIRECTOR_QUERY = "INSERT INTO directors (director_name) VALUES(:director_name)"; + private static final String GET_ALL_DIRECTORS_QUERY = "SELECT * FROM directors ORDER BY director_id"; + private static final String GET_BY_ID_QUERY = "SELECT * FROM directors WHERE director_id = :director_id"; + private static final String UPDATE_DIRECTOR_QUERY = "UPDATE directors SET director_name=:director_name WHERE director_id=:director_id"; + private static final String DELETE_DIRECTOR_QUERY = "DELETE FROM directors WHERE director_id = :director_id"; + + @Override + public Director create(Director director){ + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + MapSqlParameterSource params = new MapSqlParameterSource(); + + params.addValue("director_name",director.getName()); + jdbc.update(CREATE_DIRECTOR_QUERY, params,keyHolder); + director.setId(keyHolder.getKeyAs(Long.class)); + return director; + } + + @Override + public List getAll(){ + return jdbc.query(GET_ALL_DIRECTORS_QUERY, mapper); + } + @Override + public Optional getById(Long directorId){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("director_id", directorId); + try (Stream stream = jdbc.queryForStream(GET_BY_ID_QUERY, params, mapper)) { + return stream.findAny(); + } + + } + @Override + public Director update(Director director){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("director_name", director.getName()); + params.addValue("director_id", director.getId()); + jdbc.update(UPDATE_DIRECTOR_QUERY,params); + return director; + } + @Override + public void delete(Long id){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("director_id",id); + jdbc.update(DELETE_DIRECTOR_QUERY,params); + + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ee12e2d..c0e6344 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -6,8 +6,10 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.FilmRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.GenreRowMapper; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; @@ -21,9 +23,13 @@ public class JdbcFilmRepository implements FilmRepository { private final NamedParameterJdbcOperations jdbc; private final FilmRowMapper mapper; private final GenreRowMapper genreRowMapper; + private final DirectorRowMapper directorRowMapper; private static final String CREATE_FILM_QUERY = "INSERT INTO films (name, description, release_date, duration, mpa_id) VALUES(:name,:description,:release_date,:duration,:mpa_id)"; + private static final String SET_DIRECTORS_QUERY = "INSERT INTO FILM_DIRECTORS (FILM_ID, DIRECTOR_ID) VALUES(:film_id, :director_id)"; + private static final String GET_DIRECTORS_QUERY = "SELECT d.DIRECTOR_ID, d.DIRECTOR_NAME FROM FILM_DIRECTORS fd JOIN DIRECTORS d ON fd.DIRECTOR_ID = d.DIRECTOR_ID WHERE fd.film_id = :film_id"; private static final String CLEAN_GENRES_QUERY = "DELETE FROM film_genres WHERE film_id=:film_id"; + private static final String CLEAN_DIRECTORS_QUERY = "DELETE FROM film_directors WHERE film_id=:film_id"; private static final String UPDATE_FILM_QUERY = "UPDATE films SET name=:name, description=:description, release_date=:release_date, duration=:duration, mpa_id=:mpa_id WHERE film_id=:film_id"; private static final String DELETE_FILM_QUERY = "DELETE FROM films WHERE film_id=:film_id"; private static final String GET_BY_ID_QUERY = """ @@ -61,6 +67,32 @@ public class JdbcFilmRepository implements FilmRepository { LEFT JOIN genres ON fg.genre_id = genres.genre_id WHERE fg.film_id IN (:film_ids) """; + private static final String SELECT_DIRECTORS_BY_FILM_IDS_QUERY =""" + SELECT * + FROM FILM_DIRECTORS fd + LEFT JOIN DIRECTORS d ON fd.DIRECTOR_ID = d.DIRECTOR_ID + WHERE fd.film_id IN (:film_ids) + """; + private static final String GET_DIRECTOR_FILMS_BY_YEAR = """ + SELECT f.*,r.MPA_NAME,COUNT(l.user_id) AS likes_count + FROM FILMS f + JOIN FILM_DIRECTORS fd ON fd.FILM_ID = f.FILM_ID + JOIN mpa r ON f.mpa_id = r.mpa_id + LEFT JOIN likes l ON l.film_id = f.film_id + WHERE fd.DIRECTOR_ID = :director_id + GROUP BY f.FILM_ID + ORDER BY f.RELEASE_DATE + """; + private static final String GET_DIRECTOR_FILMS_BY_LIKES = """ + SELECT f.*,r.MPA_NAME,COUNT(l.user_id) AS likes_count + FROM FILMS f + JOIN FILM_DIRECTORS fd ON fd.FILM_ID = f.FILM_ID + JOIN mpa r ON f.mpa_id = r.mpa_id + LEFT JOIN likes l ON l.film_id = f.film_id + WHERE fd.DIRECTOR_ID = :director_id + GROUP BY f.FILM_ID + ORDER BY likes_count DESC + """; @Override public Film create(Film film) { @@ -79,6 +111,9 @@ public Film create(Film film) { if (film.getGenres() != null) { setFilmGenres(film); } + if (film.getDirectors() != null) { + setFilmDirectors(film); + } return film; } @@ -94,10 +129,14 @@ public Film update(Film film) { params.addValue("film_id", film.getId()); jdbc.update(CLEAN_GENRES_QUERY, params, keyHolder); + jdbc.update(CLEAN_DIRECTORS_QUERY,params,keyHolder); if (film.getGenres() != null) { setFilmGenres(film); } + if (film.getDirectors() != null) { + setFilmDirectors(film); + } film.setGenres(new LinkedHashSet<>()); jdbc.update(UPDATE_FILM_QUERY, params, keyHolder); @@ -118,6 +157,7 @@ public Optional getFilmById(long id) { try (Stream stream = jdbc.queryForStream(GET_BY_ID_QUERY, params, mapper)) { Optional optionalFilm = stream.findAny(); optionalFilm.ifPresent(film -> film.setGenres(getFilmGenres(film))); + optionalFilm.ifPresent(film -> film.setDirectors(getFilmDirectors(film))); return optionalFilm; } } @@ -125,7 +165,7 @@ public Optional getFilmById(long id) { @Override public List getAllFilms() { List films = jdbc.query(GET_FILMS_QUERY, mapper); - + connectDirectors(films); connectGenres(films); return films; } @@ -144,6 +184,20 @@ public void setFilmGenres(Film film) { jdbc.batchUpdate(SET_GENRE_QUERY, paramsList, keyHolder); } + @Override + public void setFilmDirectors(Film film) { + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("film_id", film.getId()); + jdbc.update(CLEAN_DIRECTORS_QUERY, params); + MapSqlParameterSource[] paramsList = film.getDirectors().stream() + .map(director -> new MapSqlParameterSource() + .addValue("director_id", director.getId()) + .addValue("film_id", film.getId())) + .toArray(MapSqlParameterSource[]::new); + + jdbc.batchUpdate(SET_DIRECTORS_QUERY, paramsList, keyHolder); + } @Override public LinkedHashSet getFilmGenres(Film film) { @@ -154,8 +208,17 @@ public LinkedHashSet getFilmGenres(Film film) { film.setGenres(filmGenres); return filmGenres; } - - private void connectGenres(Collection films) { + @Override + public LinkedHashSet getFilmDirectors(Film film) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("film_id", film.getId()); + List directors = jdbc.query(GET_DIRECTORS_QUERY, params, directorRowMapper); + LinkedHashSet filmDirectors = new LinkedHashSet<>(directors); + film.setDirectors(filmDirectors); + return filmDirectors; + } + @Override + public void connectGenres(Collection films) { List filmIds = films.stream().map(Film::getId).toList(); MapSqlParameterSource params = new MapSqlParameterSource("film_ids", filmIds); SqlRowSet rs = jdbc.queryForRowSet(SELECT_GENRES_BY_FILM_IDS_QUERY, params); @@ -169,6 +232,20 @@ private void connectGenres(Collection films) { filmsMap.get(filmId).getGenres().add(genre); } } + @Override + public void connectDirectors(Collection films){ + List filmIds = films.stream().map(Film::getId).toList(); + MapSqlParameterSource params = new MapSqlParameterSource("film_ids", filmIds); + SqlRowSet rs = jdbc.queryForRowSet(SELECT_DIRECTORS_BY_FILM_IDS_QUERY, params); + Map filmsMap = films.stream() + .collect(Collectors.toMap(Film::getId, film -> film)); + + while (rs.next()) { + long filmId = rs.getLong("film_id"); + Director director = new Director(rs.getLong("director_id"), rs.getString("director_name")); + filmsMap.get(filmId).getDirectors().add(director); + } + } @Override public void addLike(long filmId, long userId) { @@ -195,6 +272,26 @@ public List getPopularFilms(int count) { List popularFilms = jdbc.query(GET_POPULAR_FILMS_QUERY, params, mapper); connectGenres(popularFilms); + connectDirectors(popularFilms); return popularFilms; } + @Override + public List getDirectorFilmsByYear(long id){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("director_id",id); + List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_YEAR,params,mapper); + connectGenres(directorFilmsByYear); + connectDirectors(directorFilmsByYear); + return directorFilmsByYear; + } + @Override + public List getDirectorFilmByLikes(long id){ + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("director_id",id); + List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_LIKES,params,mapper); + connectGenres(directorFilmsByYear); + connectDirectors(directorFilmsByYear); + return directorFilmsByYear; + } + } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/DirectorRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/DirectorRowMapper.java new file mode 100644 index 0000000..0046fbd --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/DirectorRowMapper.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.dal.mappers; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Director; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Component +public class DirectorRowMapper implements RowMapper { + + public Director mapRow(ResultSet resultSet, int rowNum) throws SQLException { + Director director = new Director(); + director.setId(resultSet.getLong("director_id")); + director.setName(resultSet.getString("director_name")); + return director; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java index 0a5d1dc..db99aa5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java @@ -2,6 +2,7 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Mpa; @@ -24,6 +25,7 @@ public Film mapRow(ResultSet resultSet, int rowNum) throws SQLException { film.setDuration(resultSet.getInt("duration")); film.setMpa(mpa); film.setGenres(new LinkedHashSet<>()); + film.setDirectors(new LinkedHashSet<>()); film.setLikesCount(resultSet.getInt("likes_count")); return film; } 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 0000000..2f61b26 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Director { + private Long id; + private String name; +} 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 e05690f..fd8c6fc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -21,6 +21,7 @@ public class Film { private Integer duration; private LinkedHashSet genres; + private LinkedHashSet directors; @NotNull private Mpa mpa; int likesCount; 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 0000000..aa069ce --- /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.model.Director; + +import java.util.List; + +public interface DirectorService { + Director create(Director director); + + List getAll(); + + Director getById(Long directorId); + + Director update(Director director); + + void delete(Long id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java new file mode 100644 index 0000000..b01c3aa --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java @@ -0,0 +1,58 @@ +package ru.yandex.practicum.filmorate.service; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dal.JdbcDirectorRepository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Director; + +import java.util.List; + + +@Service +@Slf4j +@RequiredArgsConstructor +public class DirectorServiceImpl implements DirectorService{ + + private final JdbcDirectorRepository jdbcDirectorRepository; + + @Override + public Director create(Director director){ + if (director.getName() == null || director.getName().isBlank()){ + throw new ValidationException("Некоректное имя режисёра"); + } + log.info("Создан новый режисёр"); + return jdbcDirectorRepository.create(director); + } + @Override + public List getAll(){ + return jdbcDirectorRepository.getAll(); + } + @Override + public Director getById(Long directorId){ + return jdbcDirectorRepository.getById(directorId). + orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); + } + @Override + public Director update(Director director){ + if (director.getId() == -1) { + log.error("Id должен быть указан"); + throw new ValidationException("Id должен быть указан"); + } + if (jdbcDirectorRepository.getAll().stream().anyMatch((oldDirector) -> oldDirector.getId() == director.getId())) { + log.info("Пользователь обновлён"); + return jdbcDirectorRepository.update(director); + } + throw new NotFoundException("Режиссёр с id = " + director.getId() + " не найден"); + } + @Override + public void delete(Long id){ + getById(id); + jdbcDirectorRepository.delete(id); + log.info("Режиссёр удалён"); + } + } + 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 9489df6..1bbec83 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,8 @@ public interface FilmService { void deleteLike(long filmId, long userId); List getPopularFilms(int count); + + List getDirectorFilmsByYear(long id); + + List getDirectorFilmsByLikes(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 14a604a..b86327b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -134,4 +134,14 @@ public List getPopularFilms(int count) { List popularFilms = jdbcFilmRepository.getPopularFilms(count); return popularFilms; } + @Override + public List getDirectorFilmsByYear(long id){ + List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmsByYear(id); + return directorFilmsByYear; + } + @Override + public List getDirectorFilmsByLikes(long id){ + List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmByLikes(id); + return directorFilmsByYear; + } } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index c446ed6..98977dd 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, description VARCHAR(200), - release_date DATE CHECK (release_date <= CURRENT_DATE), + release_date DATE, duration INT CHECK (duration > 0), mpa_id BIGINT REFERENCES mpa(mpa_id) ); @@ -43,3 +43,14 @@ CREATE TABLE IF NOT EXISTS likes ( user_id BIGINT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, PRIMARY KEY (film_id, user_id) ); + +CREATE TABLE IF NOT EXISTS directors ( + director_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + director_name VARCHAR(100) NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS film_directors ( + film_id BIGINT NOT NULL REFERENCES films(film_id) ON DELETE CASCADE, + director_id BIGINT NOT NULL REFERENCES directors(director_id) ON DELETE CASCADE, + PRIMARY KEY (film_id, director_id) +); \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java index c7f9ed5..c449752 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepositoryTest.java @@ -51,6 +51,7 @@ static Film getTestFilm() { genre.setName("Комедия"); film.getGenres().add(genre); film.setLikesCount(1); + film.setDirectors(new LinkedHashSet<>()); return film; } @@ -76,6 +77,7 @@ private static Film getTestFilmToCreateOrUpdate() { film.getGenres().add(genre); film.setLikesCount(1); + film.setDirectors(new LinkedHashSet<>()); return film; } @@ -106,6 +108,7 @@ private static List getAllTestFilms() { film1.setGenres(new LinkedHashSet<>()); film1.getGenres().add(genre1); film1.setLikesCount(3); + film1.setDirectors(new LinkedHashSet<>()); films.add(film1); Film film2 = new Film(); @@ -123,6 +126,7 @@ private static List getAllTestFilms() { film2.getGenres().add(genre1); film2.getGenres().add(genre3); film2.setLikesCount(2); + film2.setDirectors(new LinkedHashSet<>()); films.add(film2); return films; From 61b5386113ec24c4958b9818eb4fde3a0d1fa73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 15:41:03 +0400 Subject: [PATCH 13/54] CheckStyle fix --- .../controller/DirectorController.java | 16 +++++++----- .../filmorate/controller/FilmController.java | 5 ++-- .../filmorate/dal/JdbcDirectorRepository.java | 25 +++++++++++-------- .../filmorate/dal/JdbcFilmRepository.java | 24 +++++++++++------- .../service/DirectorServiceImpl.java | 20 +++++++++------ .../filmorate/service/FilmServiceImpl.java | 6 +++-- 6 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java index 09e8b2e..9dfe46e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -20,29 +20,33 @@ public class DirectorController { @PostMapping @ResponseStatus(HttpStatus.OK) - public Director create(@RequestBody Director director){ - return directorService.create(director); + public Director create(@RequestBody Director director) { + return directorService.create(director); } + @GetMapping @ResponseStatus(HttpStatus.OK) - public List getAll(){ + public List getAll() { return directorService.getAll(); } + @GetMapping(path = "/{id}") @ResponseStatus(HttpStatus.OK) - public Director getById(@PathVariable("id") long id){ + public Director getById(@PathVariable("id") long id) { return directorService.getById(id); } + @PutMapping @ResponseStatus(HttpStatus.OK) public Director updateDirector(@Valid @RequestBody Director director) { return directorService.update(director); } - @DeleteMapping(path = "/{id}" ) + + @DeleteMapping(path = "/{id}") @ResponseStatus(HttpStatus.OK) - public void deleteDirector(@PathVariable("id") long id){ + public void deleteDirector(@PathVariable("id") long id) { directorService.delete(id); } } 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 f61540b..9e427c1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -64,10 +64,11 @@ public void deleteLike(@PathVariable("id") long id, @PathVariable("userId") long public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count) { return filmService.getPopularFilms(count); } + @GetMapping("/director/{directorId}") @ResponseStatus(HttpStatus.OK) - public Collection getDirectorFilm(@RequestParam(value = "sortBy") final String sort,@PathVariable("directorId") long directorId){ - if (sort.equals("year")){ + public Collection getDirectorFilm(@RequestParam(value = "sortBy") final String sort, @PathVariable("directorId") long directorId) { + if (sort.equals("year")) { return filmService.getDirectorFilmsByYear(directorId); } else if (sort.equals("likes")) { return filmService.getDirectorFilmsByLikes(directorId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java index 9393126..7ca9f54 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcDirectorRepository.java @@ -14,7 +14,7 @@ @Repository @RequiredArgsConstructor -public class JdbcDirectorRepository implements DirectorRepository{ +public class JdbcDirectorRepository implements DirectorRepository { private final NamedParameterJdbcOperations jdbc; private final DirectorRowMapper mapper; @@ -25,22 +25,23 @@ public class JdbcDirectorRepository implements DirectorRepository{ private static final String DELETE_DIRECTOR_QUERY = "DELETE FROM directors WHERE director_id = :director_id"; @Override - public Director create(Director director){ + public Director create(Director director) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("director_name",director.getName()); - jdbc.update(CREATE_DIRECTOR_QUERY, params,keyHolder); + params.addValue("director_name", director.getName()); + jdbc.update(CREATE_DIRECTOR_QUERY, params, keyHolder); director.setId(keyHolder.getKeyAs(Long.class)); return director; } @Override - public List getAll(){ + public List getAll() { return jdbc.query(GET_ALL_DIRECTORS_QUERY, mapper); } + @Override - public Optional getById(Long directorId){ + public Optional getById(Long directorId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("director_id", directorId); try (Stream stream = jdbc.queryForStream(GET_BY_ID_QUERY, params, mapper)) { @@ -48,19 +49,21 @@ public Optional getById(Long directorId){ } } + @Override - public Director update(Director director){ + public Director update(Director director) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("director_name", director.getName()); params.addValue("director_id", director.getId()); - jdbc.update(UPDATE_DIRECTOR_QUERY,params); + jdbc.update(UPDATE_DIRECTOR_QUERY, params); return director; } + @Override - public void delete(Long id){ + public void delete(Long id) { MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("director_id",id); - jdbc.update(DELETE_DIRECTOR_QUERY,params); + params.addValue("director_id", id); + jdbc.update(DELETE_DIRECTOR_QUERY, params); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index c0e6344..9771480 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -67,7 +67,7 @@ public class JdbcFilmRepository implements FilmRepository { LEFT JOIN genres ON fg.genre_id = genres.genre_id WHERE fg.film_id IN (:film_ids) """; - private static final String SELECT_DIRECTORS_BY_FILM_IDS_QUERY =""" + private static final String SELECT_DIRECTORS_BY_FILM_IDS_QUERY = """ SELECT * FROM FILM_DIRECTORS fd LEFT JOIN DIRECTORS d ON fd.DIRECTOR_ID = d.DIRECTOR_ID @@ -129,7 +129,7 @@ public Film update(Film film) { params.addValue("film_id", film.getId()); jdbc.update(CLEAN_GENRES_QUERY, params, keyHolder); - jdbc.update(CLEAN_DIRECTORS_QUERY,params,keyHolder); + jdbc.update(CLEAN_DIRECTORS_QUERY, params, keyHolder); if (film.getGenres() != null) { setFilmGenres(film); @@ -184,6 +184,7 @@ public void setFilmGenres(Film film) { jdbc.batchUpdate(SET_GENRE_QUERY, paramsList, keyHolder); } + @Override public void setFilmDirectors(Film film) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -208,6 +209,7 @@ public LinkedHashSet getFilmGenres(Film film) { film.setGenres(filmGenres); return filmGenres; } + @Override public LinkedHashSet getFilmDirectors(Film film) { MapSqlParameterSource params = new MapSqlParameterSource(); @@ -217,6 +219,7 @@ public LinkedHashSet getFilmDirectors(Film film) { film.setDirectors(filmDirectors); return filmDirectors; } + @Override public void connectGenres(Collection films) { List filmIds = films.stream().map(Film::getId).toList(); @@ -232,8 +235,9 @@ public void connectGenres(Collection films) { filmsMap.get(filmId).getGenres().add(genre); } } + @Override - public void connectDirectors(Collection films){ + public void connectDirectors(Collection films) { List filmIds = films.stream().map(Film::getId).toList(); MapSqlParameterSource params = new MapSqlParameterSource("film_ids", filmIds); SqlRowSet rs = jdbc.queryForRowSet(SELECT_DIRECTORS_BY_FILM_IDS_QUERY, params); @@ -275,20 +279,22 @@ public List getPopularFilms(int count) { connectDirectors(popularFilms); return popularFilms; } + @Override - public List getDirectorFilmsByYear(long id){ + public List getDirectorFilmsByYear(long id) { MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("director_id",id); - List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_YEAR,params,mapper); + params.addValue("director_id", id); + List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_YEAR, params, mapper); connectGenres(directorFilmsByYear); connectDirectors(directorFilmsByYear); return directorFilmsByYear; } + @Override - public List getDirectorFilmByLikes(long id){ + public List getDirectorFilmByLikes(long id) { MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("director_id",id); - List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_LIKES,params,mapper); + params.addValue("director_id", id); + List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_LIKES, params, mapper); connectGenres(directorFilmsByYear); connectDirectors(directorFilmsByYear); return directorFilmsByYear; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java index b01c3aa..092a4ac 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java @@ -15,29 +15,32 @@ @Service @Slf4j @RequiredArgsConstructor -public class DirectorServiceImpl implements DirectorService{ +public class DirectorServiceImpl implements DirectorService { private final JdbcDirectorRepository jdbcDirectorRepository; @Override - public Director create(Director director){ - if (director.getName() == null || director.getName().isBlank()){ + public Director create(Director director) { + if (director.getName() == null || director.getName().isBlank()) { throw new ValidationException("Некоректное имя режисёра"); } log.info("Создан новый режисёр"); return jdbcDirectorRepository.create(director); } + @Override - public List getAll(){ + public List getAll() { return jdbcDirectorRepository.getAll(); } + @Override - public Director getById(Long directorId){ + public Director getById(Long directorId) { return jdbcDirectorRepository.getById(directorId). orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); } + @Override - public Director update(Director director){ + public Director update(Director director) { if (director.getId() == -1) { log.error("Id должен быть указан"); throw new ValidationException("Id должен быть указан"); @@ -48,11 +51,12 @@ public Director update(Director director){ } throw new NotFoundException("Режиссёр с id = " + director.getId() + " не найден"); } + @Override - public void delete(Long id){ + public void delete(Long id) { getById(id); jdbcDirectorRepository.delete(id); log.info("Режиссёр удалён"); } - } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index b86327b..b1f037c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -134,13 +134,15 @@ public List getPopularFilms(int count) { List popularFilms = jdbcFilmRepository.getPopularFilms(count); return popularFilms; } + @Override - public List getDirectorFilmsByYear(long id){ + public List getDirectorFilmsByYear(long id) { List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmsByYear(id); return directorFilmsByYear; } + @Override - public List getDirectorFilmsByLikes(long id){ + public List getDirectorFilmsByLikes(long id) { List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmByLikes(id); return directorFilmsByYear; } From da48554eaff2f4ce93755c820513a38c77818698 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Sat, 10 May 2025 16:41:36 +0500 Subject: [PATCH 14/54] 1. add interface ReviewService. 2. add methods: checkUserId, checkFilmId, checkReviewId for class ReviewServiceImpl --- .../filmorate/service/ReviewService.java | 26 ++++++ .../filmorate/service/ReviewServiceImpl.java | 84 +++++++++---------- 2 files changed, 64 insertions(+), 46 deletions(-) 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 0000000..c6dc31d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -0,0 +1,26 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.List; +import java.util.Optional; + +public interface ReviewService { + public Optional getReviewById(long reviewId); + + public List getAllReviewsByFilmId(long filmId, long count); + + public Review create(Review review); + + public Review update(Review review); + + public void deleteReview(long reviewId); + + public void addLike(long reviewId, long userId); + + public void addDislike(long reviewId, long userId); + + public void deleteLike(long reviewId, long userId); + + public void deleteDislike(long reviewId, long userId); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java index 623e0cf..1889884 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java @@ -17,89 +17,81 @@ @Slf4j @RequiredArgsConstructor @Validated -public class ReviewServiceImpl { +public class ReviewServiceImpl implements ReviewService { private final JdbcReviewRepository jdbcReviewRepository; private final JdbcFilmRepository jdbcFilmRepository; private final JdbcUserRepository jdbcUserRepository; + @Override public Optional getReviewById(long reviewId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); return jdbcReviewRepository.getReviewById(reviewId); } + @Override public List getAllReviewsByFilmId(long filmId, long count) { - if (jdbcFilmRepository.getFilmById(filmId).isEmpty()) { - throw new NotFoundException("Фильм с id = " + filmId + " не найден"); - } + checkFilmId(filmId); return jdbcReviewRepository.getAllReviewsByFilmId(filmId, count); } + @Override public Review create(Review review) { - if (jdbcUserRepository.getUserById(review.getUserId()).isEmpty()) { - throw new NotFoundException("Пользователь не найден"); - } - if (jdbcFilmRepository.getFilmById(review.getFilmId()).isEmpty()) { - throw new NotFoundException("Фильм не найден"); - } + checkUserId(review.getUserId()); + checkFilmId(review.getFilmId()); return jdbcReviewRepository.create(review); } + @Override public Review update(Review review) { - if (jdbcUserRepository.getUserById(review.getUserId()).isEmpty()) { - throw new NotFoundException("Пользователь не найден"); - } - if (jdbcFilmRepository.getFilmById(review.getFilmId()).isEmpty()) { - throw new NotFoundException("Фильм не найден"); - } + checkUserId(review.getUserId()); + checkFilmId(review.getFilmId()); return jdbcReviewRepository.update(review); } + @Override public void deleteReview(long reviewId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); jdbcReviewRepository.deleteReview(reviewId); } + @Override public void addLike(long reviewId, long userId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } - if (jdbcUserRepository.getUserById(userId).isEmpty()) { - throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); + checkUserId(userId); jdbcReviewRepository.addLike(reviewId, userId); } + @Override public void addDislike(long reviewId, long userId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } - if (jdbcUserRepository.getUserById(userId).isEmpty()) { - throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); + checkUserId(userId); jdbcReviewRepository.addDislike(reviewId, userId); } + @Override public void deleteLike(long reviewId, long userId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } - if (jdbcUserRepository.getUserById(userId).isEmpty()) { - throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); + checkUserId(userId); jdbcReviewRepository.deleteLike(reviewId, userId); } + @Override public void deleteDislike(long reviewId, long userId) { - if (jdbcReviewRepository.getReviewById(reviewId).isEmpty()) { - throw new NotFoundException("Отзыв с id = " + reviewId + " не найден"); - } - if (jdbcUserRepository.getUserById(userId).isEmpty()) { - throw new NotFoundException("Пользователь с id = " + reviewId + " не найден"); - } + checkReviewId(reviewId); + checkUserId(userId); jdbcReviewRepository.deleteDislike(reviewId, userId); } + + private void checkUserId(long id) { + jdbcUserRepository.getUserById(id).orElseThrow(() -> new NotFoundException("Пользователь не найден")); + } + + private void checkFilmId(long id) { + jdbcFilmRepository.getFilmById(id).orElseThrow(() -> new NotFoundException("Фильм не найден")); + } + + private void checkReviewId(long id) { + jdbcReviewRepository.getReviewById(id).orElseThrow(() -> new NotFoundException("Отзыв не найден")); + } + } From 98d32dc374dff6479a61b7e2fe22f0e9e11a7ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 15:42:09 +0400 Subject: [PATCH 15/54] CheckStyle fix --- .../ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java index db99aa5..864660b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/FilmRowMapper.java @@ -2,7 +2,6 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Mpa; From eac0cc1122f7ccfa4382af260cf829876ab03910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 15:43:30 +0400 Subject: [PATCH 16/54] CheckStyle fix --- .../practicum/filmorate/service/DirectorServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java index 092a4ac..1c30fd8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java @@ -35,8 +35,8 @@ public List getAll() { @Override public Director getById(Long directorId) { - return jdbcDirectorRepository.getById(directorId). - orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); + return jdbcDirectorRepository.getById(directorId) + .orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); } @Override From 16b375814f708270bb3b708a4102c66f435e0a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 18:44:02 +0400 Subject: [PATCH 17/54] =?UTF-8?q?=D0=98=D1=81=D0=BF=D0=BE=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B8=20=D1=80=D0=B5=D0=B6=D0=B8=D1=81=D1=81=D1=91=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B8=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 8 ++------ .../practicum/filmorate/dal/FilmRepository.java | 2 +- .../filmorate/dal/JdbcFilmRepository.java | 2 +- .../practicum/filmorate/model/Director.java | 4 ++++ .../filmorate/service/DirectorServiceImpl.java | 5 +---- .../practicum/filmorate/service/FilmService.java | 4 +--- .../filmorate/service/FilmServiceImpl.java | 16 ++++++++-------- 7 files changed, 18 insertions(+), 23 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 9e427c1..30feecc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -67,11 +67,7 @@ public Collection getPopularFilms(@RequestParam(value = "count", defaultVa @GetMapping("/director/{directorId}") @ResponseStatus(HttpStatus.OK) - public Collection getDirectorFilm(@RequestParam(value = "sortBy") final String sort, @PathVariable("directorId") long directorId) { - if (sort.equals("year")) { - return filmService.getDirectorFilmsByYear(directorId); - } else if (sort.equals("likes")) { - return filmService.getDirectorFilmsByLikes(directorId); - } else throw new ValidationException("некорректный запрос"); + public Collection getDirectorFilms(@RequestParam(value = "sortBy") final String sort, @PathVariable("directorId") long directorId) { + return filmService.getDirectorFilms(directorId,sort); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index e798cab..14572d0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -40,5 +40,5 @@ public interface FilmRepository { List getDirectorFilmsByYear(long id); - List getDirectorFilmByLikes(long id); + List getDirectorFilmsByLikes(long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 9771480..e59215f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -291,7 +291,7 @@ public List getDirectorFilmsByYear(long id) { } @Override - public List getDirectorFilmByLikes(long id) { + public List getDirectorFilmsByLikes(long id) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("director_id", id); List directorFilmsByYear = jdbc.query(GET_DIRECTOR_FILMS_BY_LIKES, params, mapper); diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java index 2f61b26..0b0f972 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -1,5 +1,7 @@ package ru.yandex.practicum.filmorate.model; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -9,5 +11,7 @@ @AllArgsConstructor public class Director { private Long id; + @NotNull(message = "Имя не может быть пустым") + @NotBlank(message = "Имя не может быть пустым") private String name; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java index 1c30fd8..dc324ef 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceImpl.java @@ -21,9 +21,6 @@ public class DirectorServiceImpl implements DirectorService { @Override public Director create(Director director) { - if (director.getName() == null || director.getName().isBlank()) { - throw new ValidationException("Некоректное имя режисёра"); - } log.info("Создан новый режисёр"); return jdbcDirectorRepository.create(director); } @@ -36,7 +33,7 @@ public List getAll() { @Override public Director getById(Long directorId) { return jdbcDirectorRepository.getById(directorId) - .orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); + .orElseThrow(() -> new NotFoundException("Некорректный id = " + directorId)); } @Override 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 1bbec83..10287a6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -21,7 +21,5 @@ public interface FilmService { List getPopularFilms(int count); - List getDirectorFilmsByYear(long id); - - List getDirectorFilmsByLikes(long id); + List getDirectorFilms(long id, String sortBy); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index b1f037c..1a96d46 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -136,14 +136,14 @@ public List getPopularFilms(int count) { } @Override - public List getDirectorFilmsByYear(long id) { - List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmsByYear(id); - return directorFilmsByYear; - } + public List getDirectorFilms(long id, String sortBy) { + if (sortBy.equals("year")) { + return jdbcFilmRepository.getDirectorFilmsByYear(id); + } else if (sortBy.equals("likes")) { + return jdbcFilmRepository.getDirectorFilmsByLikes(id); + } else throw new ValidationException("некорректный запрос"); - @Override - public List getDirectorFilmsByLikes(long id) { - List directorFilmsByYear = jdbcFilmRepository.getDirectorFilmByLikes(id); - return directorFilmsByYear; } + + } From decb1d68c90fee3cc5d6d22867ee8debcc05c508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sat, 10 May 2025 18:46:04 +0400 Subject: [PATCH 18/54] CheckStyle fix --- .../yandex/practicum/filmorate/controller/FilmController.java | 3 +-- 1 file changed, 1 insertion(+), 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 30feecc..e26da05 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -5,7 +5,6 @@ import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.service.FilmService; @@ -68,6 +67,6 @@ public Collection getPopularFilms(@RequestParam(value = "count", defaultVa @GetMapping("/director/{directorId}") @ResponseStatus(HttpStatus.OK) public Collection getDirectorFilms(@RequestParam(value = "sortBy") final String sort, @PathVariable("directorId") long directorId) { - return filmService.getDirectorFilms(directorId,sort); + return filmService.getDirectorFilms(directorId, sort); } } From 602b51e49cdd7256de840591f6f529239e862f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sun, 11 May 2025 05:17:10 +0400 Subject: [PATCH 19/54] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D1=83=D1=81=D1=82=D1=8B=D1=85=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=20=D0=B8=20=D0=BB=D0=B8=D1=88=D0=BD?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/DirectorController.java | 6 ++---- .../yandex/practicum/filmorate/dal/JdbcFilmRepository.java | 1 - .../java/ru/yandex/practicum/filmorate/model/Director.java | 1 - .../yandex/practicum/filmorate/service/FilmServiceImpl.java | 3 --- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java index 9dfe46e..c8f300b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -22,7 +22,6 @@ public class DirectorController { @ResponseStatus(HttpStatus.OK) public Director create(@RequestBody Director director) { return directorService.create(director); - } @GetMapping @@ -31,11 +30,10 @@ public List getAll() { return directorService.getAll(); } - @GetMapping(path = "/{id}") + @GetMapping("/{id}") @ResponseStatus(HttpStatus.OK) public Director getById(@PathVariable("id") long id) { return directorService.getById(id); - } @PutMapping @@ -44,7 +42,7 @@ public Director updateDirector(@Valid @RequestBody Director director) { return directorService.update(director); } - @DeleteMapping(path = "/{id}") + @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.OK) public void deleteDirector(@PathVariable("id") long id) { directorService.delete(id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index e59215f..c389806 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -299,5 +299,4 @@ public List getDirectorFilmsByLikes(long id) { connectDirectors(directorFilmsByYear); return directorFilmsByYear; } - } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java index 0b0f972..8066d21 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -11,7 +11,6 @@ @AllArgsConstructor public class Director { private Long id; - @NotNull(message = "Имя не может быть пустым") @NotBlank(message = "Имя не может быть пустым") private String name; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 1a96d46..e4ae1bc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -142,8 +142,5 @@ public List getDirectorFilms(long id, String sortBy) { } else if (sortBy.equals("likes")) { return jdbcFilmRepository.getDirectorFilmsByLikes(id); } else throw new ValidationException("некорректный запрос"); - } - - } From 638e0e88855273fba13816627c9d524a557fbcf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sun, 11 May 2025 05:18:27 +0400 Subject: [PATCH 20/54] CheckStyle fix --- src/main/java/ru/yandex/practicum/filmorate/model/Director.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java index 8066d21..03d29e6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -1,7 +1,6 @@ package ru.yandex.practicum.filmorate.model; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; From b45b859ca1851acacb1a3aa414f05b5d13712e29 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Sun, 11 May 2025 14:13:35 +0500 Subject: [PATCH 21/54] 1. add interface ReviewService. 2. unification methods: deleteLike, deleteDislike in deleteReaction for class ReviewServiceImpl, class deleteReaction, interface ReviewRepository, interface ReviewService --- .../filmorate/controller/ReviewController.java | 4 ++-- .../practicum/filmorate/dal/JdbcReviewRepository.java | 10 +++------- .../practicum/filmorate/dal/ReviewRepository.java | 3 +-- .../practicum/filmorate/service/ReviewService.java | 3 +-- .../filmorate/service/ReviewServiceImpl.java | 11 ++--------- 5 files changed, 9 insertions(+), 22 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 447e08f..8b53672 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -64,13 +64,13 @@ public void addDislike(@PathVariable long reviewId, @PathVariable long userId) { @DeleteMapping("/{reviewId}/like/{userId}") @ResponseStatus(HttpStatus.OK) public void deleteLike(@PathVariable long reviewId, @PathVariable long userId) { - reviewService.deleteLike(reviewId, userId); + reviewService.deleteReaction(reviewId, userId); } @DeleteMapping("/{reviewId}/dislike/{userId}") @ResponseStatus(HttpStatus.OK) public void deleteDislike(@PathVariable long reviewId, @PathVariable long userId) { - reviewService.deleteDislike(reviewId, userId); + reviewService.deleteReaction(reviewId, userId); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 2be207c..c5229ae 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -129,7 +129,7 @@ public void deleteReview(long reviewId) { @Override public void addLike(long reviewId, long userId) { - deleteLike(reviewId, userId); + deleteReaction(reviewId, userId); MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); params.addValue("userId", userId); @@ -138,7 +138,7 @@ public void addLike(long reviewId, long userId) { @Override public void addDislike(long reviewId, long userId) { - deleteLike(reviewId, userId); + deleteReaction(reviewId, userId); MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); params.addValue("userId", userId); @@ -146,15 +146,11 @@ public void addDislike(long reviewId, long userId) { } @Override - public void deleteLike(long reviewId, long userId) { + public void deleteReaction(long reviewId, long userId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(DELETE_LIKE_REVIEW, params); } - @Override - public void deleteDislike(long reviewId, long userId) { - deleteLike(reviewId, userId); - } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java index 4c08292..e298759 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/ReviewRepository.java @@ -20,7 +20,6 @@ public interface ReviewRepository { void addDislike(long reviewId, long userId); - void deleteLike(long reviewId, long userId); + void deleteReaction(long reviewId, long userId); - void deleteDislike(long reviewId, long 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 c6dc31d..55d8dab 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -20,7 +20,6 @@ public interface ReviewService { public void addDislike(long reviewId, long userId); - public void deleteLike(long reviewId, long userId); + public void deleteReaction(long reviewId, long userId); - public void deleteDislike(long reviewId, long userId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java index 1889884..ecf6c7e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java @@ -69,17 +69,10 @@ public void addDislike(long reviewId, long userId) { } @Override - public void deleteLike(long reviewId, long userId) { + public void deleteReaction(long reviewId, long userId) { checkReviewId(reviewId); checkUserId(userId); - jdbcReviewRepository.deleteLike(reviewId, userId); - } - - @Override - public void deleteDislike(long reviewId, long userId) { - checkReviewId(reviewId); - checkUserId(userId); - jdbcReviewRepository.deleteDislike(reviewId, userId); + jdbcReviewRepository.deleteReaction(reviewId, userId); } private void checkUserId(long id) { From 6d35c4af3f5355d52ab57f2d78dd06bc8dc49b91 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Sun, 11 May 2025 15:16:55 +0300 Subject: [PATCH 22/54] =?UTF-8?q?feature:=20add=20common=20films=20-=20?= =?UTF-8?q?=D0=9E=D0=B1=D1=89=D0=B8=D0=B5=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 7 +++++++ .../filmorate/dal/FilmRepository.java | 2 ++ .../filmorate/dal/JdbcFilmRepository.java | 21 +++++++++++++++++++ .../filmorate/service/FilmService.java | 2 ++ .../filmorate/service/FilmServiceImpl.java | 6 ++++++ 5 files changed, 38 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 e2a89f4..47e64f6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -63,4 +63,11 @@ public void deleteLike(@PathVariable("id") long id, @PathVariable("userId") long public Collection getPopularFilms(@RequestParam(value = "count", defaultValue = "10") final Integer count) { return filmService.getPopularFilms(count); } + + @GetMapping("/common") + @ResponseStatus(HttpStatus.OK) + public Collection getCommonFilms(@RequestParam(value = "userId") Long userId, + @RequestParam(value = "friendId") Long friendId) { + return filmService.getCommonFilms(userId, friendId); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index 3afa2e5..820d5c8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -27,4 +27,6 @@ public interface FilmRepository { LinkedHashSet getFilmGenres(Film film); List getPopularFilms(int count); + + List getCommonFilms(long userId, long friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ee12e2d..cad1357 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -62,6 +62,16 @@ public class JdbcFilmRepository implements FilmRepository { WHERE fg.film_id IN (:film_ids) """; + private static final String GET_COMMON_FILMS_QUERY = """ + SELECT f.*, r.mpa_name, COUNT(l1.user_id) AS likes_count + FROM films f + JOIN mpa r ON r.mpa_id = f.mpa_id + JOIN likes l1 ON l1.film_id = f.film_id AND l1.user_id = :userId + JOIN likes l2 ON l2.film_id = f.film_id AND l2.user_id = :friendId + GROUP BY f.film_id, r.mpa_name + ORDER BY f.name; + """; + @Override public Film create(Film film) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -197,4 +207,15 @@ public List getPopularFilms(int count) { connectGenres(popularFilms); return popularFilms; } + + @Override + public List getCommonFilms(long userId, long friendId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("userId", userId); + params.addValue("friendId", friendId); + List commonFilms = jdbc.query(GET_COMMON_FILMS_QUERY, params, mapper); + + connectGenres(commonFilms); + return commonFilms; + } } \ No newline at end of file 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 9489df6..cab57cf 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 deleteLike(long filmId, long userId); List getPopularFilms(int count); + + List getCommonFilms(long userId, long friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 14a604a..2714f50 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -134,4 +134,10 @@ public List getPopularFilms(int count) { List popularFilms = jdbcFilmRepository.getPopularFilms(count); return popularFilms; } + + @Override + public List getCommonFilms(long userId, long friendId){ + List commonFilms = jdbcFilmRepository.getCommonFilms(userId, friendId); + return commonFilms; + } } From e8ce4e42b92130186f82efd0e320a5c9d73e415c Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Sun, 11 May 2025 15:25:34 +0300 Subject: [PATCH 23/54] fix code styles --- .../ru/yandex/practicum/filmorate/service/FilmServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 437c7c4..eb09bb4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -145,7 +145,7 @@ public List getDirectorFilms(long id, String sortBy) { } @Override - public List getCommonFilms(long userId, long friendId){ + public List getCommonFilms(long userId, long friendId) { List commonFilms = jdbcFilmRepository.getCommonFilms(userId, friendId); return commonFilms; } From 1f661e26fad21834e4f6cc9588beef5cb5fa217e Mon Sep 17 00:00:00 2001 From: Just Roma Date: Sun, 11 May 2025 18:19:53 +0500 Subject: [PATCH 24/54] delete CHECK (release_date <= CURRENT_DATE) for schema in table films --- src/main/resources/schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index eaa6851..8c30e6a 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, description VARCHAR(200), - release_date DATE CHECK (release_date <= CURRENT_DATE), + release_date DATE, duration INT CHECK (duration > 0), mpa_id BIGINT REFERENCES mpa(mpa_id) ); From 9fdb5606bab95ff4e70b582fa92d44c66f3eb333 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Sun, 11 May 2025 16:48:03 +0300 Subject: [PATCH 25/54] resolve conflicts --- .../java/ru/yandex/practicum/filmorate/dal/FilmRepository.java | 2 +- src/main/resources/schema.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index 14572d0..e9b3a6e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -36,7 +36,7 @@ public interface FilmRepository { LinkedHashSet getFilmGenres(Film film); - List getPopularFilms(int count); + List getPopularFilms(int count, Long genreId, Integer year); List getDirectorFilmsByYear(long id); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index eaa6851..3d6528c 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, description VARCHAR(200), - release_date DATE CHECK (release_date <= CURRENT_DATE), + release_date DATE CHECK, duration INT CHECK (duration > 0), mpa_id BIGINT REFERENCES mpa(mpa_id) ); From cc6101e7f4e11a2d6790514206083a1622b17f6a Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Sun, 11 May 2025 16:54:57 +0300 Subject: [PATCH 26/54] resolve conflicts --- src/main/resources/schema.sql | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 3d6528c..696ddca 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -9,11 +9,16 @@ CREATE TABLE IF NOT EXISTS mpa ( PRIMARY KEY (mpa_id) ); +CREATE TABLE IF NOT EXISTS directors ( + director_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + director_name VARCHAR(100) NOT NULL UNIQUE +); + CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, description VARCHAR(200), - release_date DATE CHECK, + release_date DATE, duration INT CHECK (duration > 0), mpa_id BIGINT REFERENCES mpa(mpa_id) ); @@ -24,6 +29,12 @@ CREATE TABLE IF NOT EXISTS film_genres ( PRIMARY KEY (film_id, genre_id) ); +CREATE TABLE IF NOT EXISTS film_directors ( + film_id BIGINT NOT NULL REFERENCES films(film_id) ON DELETE CASCADE, + director_id BIGINT NOT NULL REFERENCES directors(director_id) ON DELETE CASCADE, + PRIMARY KEY (film_id, director_id) +); + CREATE TABLE IF NOT EXISTS users ( user_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, @@ -44,16 +55,6 @@ CREATE TABLE IF NOT EXISTS likes ( PRIMARY KEY (film_id, user_id) ); -CREATE TABLE IF NOT EXISTS directors ( - director_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - director_name VARCHAR(100) NOT NULL UNIQUE -); - -CREATE TABLE IF NOT EXISTS film_directors ( - film_id BIGINT NOT NULL REFERENCES films(film_id) ON DELETE CASCADE, - director_id BIGINT NOT NULL REFERENCES directors(director_id) ON DELETE CASCADE, - PRIMARY KEY (film_id, director_id) -); CREATE TABLE IF NOT EXISTS reviews ( reviewId BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, content VARCHAR(255) NOT NULL, From b9ca135162c6f4c0f0975763046fe5daf0f58f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sun, 11 May 2025 19:12:03 +0400 Subject: [PATCH 27/54] =?UTF-8?q?=D0=A4=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=C2=AB=D0=9F=D0=BE=D0=B8=D1=81=D0=BA=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 6 +++ .../filmorate/dal/FilmRepository.java | 2 + .../filmorate/dal/JdbcFilmRepository.java | 41 +++++++++++++++++++ .../filmorate/service/FilmService.java | 2 + .../filmorate/service/FilmServiceImpl.java | 5 +++ 5 files changed, 56 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 ea4416c..471a419 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -78,4 +78,10 @@ public Collection getCommonFilms(@RequestParam(value = "userId") Long user @RequestParam(value = "friendId") Long friendId) { return filmService.getCommonFilms(userId, friendId); } + + @GetMapping("/search") + @ResponseStatus(HttpStatus.OK) + public Collection getSearch(@RequestParam(value = "query", defaultValue = "defaultSearch") final String query, @RequestParam(value = "by", defaultValue = "defaultSearch") final String by) { + return filmService.getSearch(query, by); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index fd6f1d6..7aa5995 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -42,5 +42,7 @@ public interface FilmRepository { List getDirectorFilmsByLikes(long id); + List getSearch(String query, String searchBy); + List getCommonFilms(long userId, long friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 1dcc118..fdf2389 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -9,6 +9,7 @@ import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.FilmRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.GenreRowMapper; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; @@ -93,6 +94,18 @@ WHERE fd.film_id IN (:film_ids) GROUP BY f.film_id, r.mpa_name ORDER BY f.name; """; + private static final String GET_SEARCH = """ + SELECT f.*, r.mpa_name, COUNT(l.user_id) AS likes_count + FROM films f + LEFT JOIN likes l ON l.film_id = f.film_id + JOIN mpa r ON r.mpa_id = f.mpa_id + LEFT JOIN FILM_DIRECTORS fd ON fd.FILM_ID = f.FILM_ID + LEFT JOIN DIRECTORS d ON d.DIRECTOR_ID = fd.DIRECTOR_ID + WHERE f.NAME LIKE :film_name + OR d.DIRECTOR_NAME LIKE :director_name + GROUP BY f.film_id, r.mpa_name + ORDER BY likes_count DESC + """; @Override public Film create(Film film) { @@ -338,4 +351,32 @@ public List getCommonFilms(long userId, long friendId) { connectGenres(commonFilms); return commonFilms; } + + @Override + public List getSearch(String query, String searchBy) { + MapSqlParameterSource params = new MapSqlParameterSource(); + switch (searchBy) { + case "director" -> { + params.addValue("film_name", ""); + params.addValue("director_name", "%" + query + "%"); + } + case "title" -> { + params.addValue("film_name", "%" + query + "%"); + params.addValue("director_name", ""); + } + case "director,title", "title,director" -> { + params.addValue("film_name", "%" + query + "%"); + params.addValue("director_name", "%" + query + "%"); + } + case "defaultSearch" -> { + params.addValue("film_name", "%%"); + params.addValue("director_name", "%%"); + } + default -> throw new ValidationException("некорректный запрос"); + } + List searchedFilms = jdbc.query(GET_SEARCH, params, mapper); + connectGenres(searchedFilms); + connectDirectors(searchedFilms); + return searchedFilms; + } } \ No newline at end of file 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 4518f27..27343ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -24,4 +24,6 @@ public interface FilmService { List getDirectorFilms(long id, String sortBy); List getCommonFilms(long userId, long friendId); + + List getSearch(String query, String searchBy); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 5132c95..9cac2d2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -149,4 +149,9 @@ public List getCommonFilms(long userId, long friendId) { List commonFilms = jdbcFilmRepository.getCommonFilms(userId, friendId); return commonFilms; } + + @Override + public List getSearch(String query, String searchBy) { + return jdbcFilmRepository.getSearch(query, searchBy); + } } From 52f82209f7a0a9a0b02d25678b564401ffe84be2 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Sun, 11 May 2025 19:07:28 +0300 Subject: [PATCH 28/54] fix: add connectDirectors to common films --- .../ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 1dcc118..ed04b64 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -336,6 +336,7 @@ public List getCommonFilms(long userId, long friendId) { List commonFilms = jdbc.query(GET_COMMON_FILMS_QUERY, params, mapper); connectGenres(commonFilms); + connectDirectors(commonFilms); return commonFilms; } } \ No newline at end of file From 65df69c58796a3d09f058bfae3dea328d50aa6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Mon, 12 May 2025 20:17:07 +0400 Subject: [PATCH 29/54] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B6=D0=B8=D1=81=D1=81=D1=91=D1=80=D0=BE=D0=B2?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/DirectorController.java | 2 +- .../practicum/filmorate/dal/JdbcFilmRepository.java | 1 - .../practicum/filmorate/service/FilmServiceImpl.java | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java index c8f300b..f458cfa 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -20,7 +20,7 @@ public class DirectorController { @PostMapping @ResponseStatus(HttpStatus.OK) - public Director create(@RequestBody Director director) { + public Director create(@Valid @RequestBody Director director) { return directorService.create(director); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 1dcc118..b17edf8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -137,7 +137,6 @@ public Film update(Film film) { if (film.getDirectors() != null) { setFilmDirectors(film); } - film.setGenres(new LinkedHashSet<>()); jdbc.update(UPDATE_FILM_QUERY, params, keyHolder); return film; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 5132c95..cb877cc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -4,10 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import ru.yandex.practicum.filmorate.dal.JdbcFilmRepository; -import ru.yandex.practicum.filmorate.dal.JdbcGenreRepository; -import ru.yandex.practicum.filmorate.dal.JdbcMpaRepository; -import ru.yandex.practicum.filmorate.dal.JdbcUserRepository; +import ru.yandex.practicum.filmorate.dal.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; @@ -26,6 +23,7 @@ public class FilmServiceImpl implements FilmService { private final JdbcUserRepository jdbcUserRepository; private final JdbcGenreRepository jdbcGenreRepository; private final JdbcMpaRepository jdbcMpaRepository; + private final JdbcDirectorRepository jdbcDirectorRepository; @Override public Film getFilmById(long filmId) { @@ -137,6 +135,8 @@ public List getPopularFilms(int count, Long genreId, Integer year) { @Override public List getDirectorFilms(long id, String sortBy) { + jdbcDirectorRepository.getById(id) + .orElseThrow(() -> new NotFoundException("Режиссёр с id = " + id + " не найден")); if (sortBy.equals("year")) { return jdbcFilmRepository.getDirectorFilmsByYear(id); } else if (sortBy.equals("likes")) { From 1a8f0133711f480b993578a435656b8282c7e09b Mon Sep 17 00:00:00 2001 From: Just Roma Date: Tue, 13 May 2025 14:56:27 +0500 Subject: [PATCH 30/54] =?UTF-8?q?=20=D0=92=D0=B5=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B8=20add?= =?UTF-8?q?-feed.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/UserController.java | 8 ++ .../filmorate/dal/JdbcFilmRepository.java | 30 ++++++++ .../filmorate/dal/JdbcReviewRepository.java | 75 +++++++++++++++++++ .../filmorate/dal/JdbcUserRepository.java | 40 +++++++++- .../filmorate/dal/UserRepository.java | 3 + .../dal/mappers/ActivityrRowMapper.java | 23 ++++++ .../practicum/filmorate/model/Activity.java | 23 ++++++ .../filmorate/service/UserService.java | 3 + .../filmorate/service/UserServiceImpl.java | 9 ++- src/main/resources/schema.sql | 9 +++ 10 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Activity.java 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 b17a7e8..488b5ac 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -6,10 +6,12 @@ import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserServiceImpl; import java.util.Collection; +import java.util.List; @RestController @RequiredArgsConstructor @@ -19,6 +21,12 @@ public class UserController { private final UserServiceImpl userService; + @GetMapping("/{userId}/feed") + @ResponseStatus(HttpStatus.OK) + public List getActivityByUserId(@PathVariable long userId) { + return userService.getActivityById(userId); + } + @GetMapping @ResponseStatus(HttpStatus.OK) public Collection findAll() { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ed04b64..b42c0f3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -13,6 +13,7 @@ import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -94,6 +95,23 @@ WHERE fd.film_id IN (:film_ids) ORDER BY f.name; """; + private static final String ACTIVITY_GENERAL = + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp)"; + + private static final String ACTIVITY_FILM_LIKE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'LIKE', 'ADD', + """ + instantOfSecond() + ")"; + + private static final String ACTIVITY_FILM_LIKE_DELETE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'LIKE', 'REMOVE', + """ + instantOfSecond() + ")"; + + private static long instantOfSecond() { + return Instant.now().toEpochMilli(); + } + @Override public Film create(Film film) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -258,6 +276,12 @@ public void addLike(long filmId, long userId) { params.addValue("user_id", userId); params.addValue("film_id", filmId); jdbc.update(ADD_LIKE_QUERY, params, keyHolder); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", filmId); + + jdbc.update(ACTIVITY_FILM_LIKE, params2); } @Override @@ -267,6 +291,12 @@ public void deleteLike(long filmId, long userId) { params.addValue("user_id", userId); params.addValue("film_id", filmId); jdbc.update(DELETE_LIKE_QUERY, params, keyHolder); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", filmId); + + jdbc.update(ACTIVITY_FILM_LIKE_DELETE, params2); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index c5229ae..32d2808 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -8,6 +8,7 @@ import ru.yandex.practicum.filmorate.dal.mappers.ReviewRowMapper; import ru.yandex.practicum.filmorate.model.Review; +import java.time.Instant; import java.util.List; import java.util.Optional; import java.util.stream.Stream; @@ -71,6 +72,43 @@ INSERT INTO reviews_likes (reviewId, userId, reaction_type) WHERE reviewId=:reviewId AND userId=:userId """; + private static final String ACTIVITY_GENERAL = + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp)"; + + private static final String ACTIVITY_REVIEW_CREATE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'REVIEW', 'ADD', + """ + instantOfSecond() + ")"; + + private static final String ACTIVITY_REVIEW_UPDATE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'REVIEW', 'UPDATE', + """ + instantOfSecond() + ")"; + + private static final String ACTIVITY_REVIEW_DELETE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'REVIEW', 'REMOVE', + """ + instantOfSecond() + ")"; + + + private static final String ACTIVITY_REVIEW_ADD_LIKE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'LIKE', 'ADD', + """ + instantOfSecond() + ")"; + + private static final String ACTIVITY_REVIEW_ADD_DISLIKE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'DISLIKE', 'ADD', + """ + instantOfSecond() + ")"; + + private static final String ACTIVITY_REVIEW_DELETE_REACTION = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'LIKE', 'REMOVE', + """ + instantOfSecond() + ")"; + + private static long instantOfSecond() { + return Instant.now().toEpochMilli(); + } @Override public Optional getReviewById(long reviewId) { @@ -100,6 +138,12 @@ public Review create(Review review) { jdbc.update(CREATE_REVIEW, params, keyHolder); review.setReviewId(keyHolder.getKeyAs(Long.class)); + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", review.getUserId()); + params2.addValue("entityId", review.getReviewId()); + + jdbc.update(ACTIVITY_REVIEW_CREATE, params2); + return review; } @@ -117,6 +161,12 @@ public Review update(Review review) { jdbc.update(UPDATE_REVIEW, params, keyHolder); + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", review.getUserId()); + params2.addValue("entityId", review.getReviewId()); + + jdbc.update(ACTIVITY_REVIEW_UPDATE, params2); + return review; } @@ -124,6 +174,13 @@ public Review update(Review review) { public void deleteReview(long reviewId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); + + Optional review = getReviewById(reviewId); + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", review.get().getUserId()); + params2.addValue("entityId", review.get().getReviewId()); + + jdbc.update(ACTIVITY_REVIEW_DELETE, params2); jdbc.update(DELETE_REVIEW, params); } @@ -134,6 +191,12 @@ public void addLike(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(ADD_LIKE_REVIEW, params); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", reviewId); + + jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, params2); } @Override @@ -143,6 +206,12 @@ public void addDislike(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(ADD_DISLIKE_REVIEW, params); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", reviewId); + + jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, params2); } @Override @@ -151,6 +220,12 @@ public void deleteReaction(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(DELETE_LIKE_REVIEW, params); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", reviewId); + + jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, params2); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index b559549..eb037ba 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -6,9 +6,13 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dal.mappers.ActivityrRowMapper; +import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; -import java.util.*; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import java.util.stream.Stream; @Repository @@ -16,6 +20,7 @@ public class JdbcUserRepository implements UserRepository { private final NamedParameterJdbcOperations jdbc; private final RowMapper mapper; + private final ActivityrRowMapper activityrRowMapper; private static final String CREATE_USER_QUERY = "INSERT INTO users (login, email, name, birthday) VALUES(:login,:email,:name,:birthday)"; private static final String UPDATE_USER_QUERY = "UPDATE users SET login=:login, email=:email, name=:name, birthday=:birthday WHERE user_id=:user_id"; @@ -29,6 +34,29 @@ public class JdbcUserRepository implements UserRepository { + "JOIN friends f2 ON u.user_id = f2.friend_id WHERE f1.user_id = :user_id AND f2.user_id = :other_id"; private static final String FIND_USERS_BY_IDS_QUERY = "SELECT * FROM users WHERE user_id IN (:ids)"; + private static final String ACTIVITY_GENERAL = + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp) "; + private static final String ACTIVITY_FRIEND_ADD = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'FRIEND', 'ADD', + """ + instantOfSecond() + ")"; + private static final String ACTIVITY_FRIEND_DELETE = ACTIVITY_GENERAL + + """ + VALUES(:userId, :entityId, 'FRIEND', 'REMOVE', + """ + instantOfSecond() + ")"; + private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId"; + + private static long instantOfSecond() { + return Instant.now().toEpochMilli(); + } + + @Override + public List getActivityById(long userId) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("userId", userId); + return jdbc.query(GET_ACTIVITY_BY_USER_ID, params, activityrRowMapper); + } + @Override public User create(User user) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -83,6 +111,11 @@ public void addFriend(long userId, long friendId) { params.addValue("user_id", userId); params.addValue("friend_id", friendId); jdbc.update(ADD_FRIEND_QUERY, params, keyHolder); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", friendId); + jdbc.update(ACTIVITY_FRIEND_ADD, params2); } @Override @@ -92,6 +125,11 @@ public void deleteFriend(long userId, long friendId) { params.addValue("user_id", userId); params.addValue("friend_id", friendId); jdbc.update(DELETE_FRIEND_QUERY, params, keyHolder); + + MapSqlParameterSource params2 = new MapSqlParameterSource(); + params2.addValue("userId", userId); + params2.addValue("entityId", friendId); + jdbc.update(ACTIVITY_FRIEND_DELETE, params2); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java index 531de81..1d08cf9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java @@ -1,11 +1,14 @@ package ru.yandex.practicum.filmorate.dal; +import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; import java.util.List; import java.util.Optional; public interface UserRepository { + List getActivityById(long activityId); + Optional getUserById(long userId); List getUsersByIds(List userIds); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java new file mode 100644 index 0000000..4a9f8d2 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.dal.mappers; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Activity; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Component +public class ActivityrRowMapper implements RowMapper { + @Override + public Activity mapRow(ResultSet rs, int rowNum) throws SQLException { + Activity activity = new Activity(); + activity.setEventId(rs.getLong("eventId")); + activity.setUserId(rs.getLong("userId")); + activity.setEntityId(rs.getLong("entityId")); + activity.setEventType(rs.getString("eventType")); + activity.setOperation(rs.getString("operation")); + activity.setTimestamp(rs.getLong("timestamp")); + return activity; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Activity.java b/src/main/java/ru/yandex/practicum/filmorate/model/Activity.java new file mode 100644 index 0000000..a6e54f6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Activity.java @@ -0,0 +1,23 @@ +package ru.yandex.practicum.filmorate.model; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Activity { + private long eventId; + @NotNull + private long userId; + @NotNull + private long entityId; + @NotNull + private String eventType; + @NotNull + private String operation; + @NotNull + private long timestamp; +} 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 95971a3..0b68c8a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,10 +1,13 @@ package ru.yandex.practicum.filmorate.service; +import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; import java.util.List; public interface UserService { + List getActivityById(long activityId); + User getUserById(long userId); List getUsers(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index 19c8a55..5357699 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -7,9 +7,11 @@ import ru.yandex.practicum.filmorate.dal.JdbcUserRepository; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; -import java.util.*; +import java.util.ArrayList; +import java.util.List; @Service @Slf4j @@ -18,6 +20,11 @@ public class UserServiceImpl implements UserService { private final JdbcUserRepository jdbcUserRepository; + @Override + public List getActivityById(long userId) { + return jdbcUserRepository.getActivityById(userId); + } + @Override public User getUserById(long userId) { return jdbcUserRepository.getUserById(userId) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 696ddca..26525b5 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -70,3 +70,12 @@ CREATE TABLE IF NOT EXISTS reviews_likes ( reaction_type SMALLINT NOT NULL CHECK (reaction_type IN (-1, 1)), PRIMARY KEY (reviewId, userId) ); + +CREATE TABLE IF NOT EXISTS activity ( + eventId BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + userId BIGINT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, + entityId INT NOT NULL, + eventType VARCHAR(20) NOT NULL, + operation VARCHAR(20) NOT NULL, + timestamp BIGINT NOT NULL +); From 2418a7f3073c0f5902fc371ac3ffc0c1a14313cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Sun, 11 May 2025 19:12:03 +0400 Subject: [PATCH 31/54] =?UTF-8?q?=D0=A4=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=C2=AB=D0=9F=D0=BE=D0=B8=D1=81=D0=BA=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 6 +++ .../filmorate/dal/FilmRepository.java | 2 + .../filmorate/dal/JdbcFilmRepository.java | 41 +++++++++++++++++++ .../filmorate/service/FilmService.java | 2 + .../filmorate/service/FilmServiceImpl.java | 5 +++ 5 files changed, 56 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 ea4416c..471a419 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -78,4 +78,10 @@ public Collection getCommonFilms(@RequestParam(value = "userId") Long user @RequestParam(value = "friendId") Long friendId) { return filmService.getCommonFilms(userId, friendId); } + + @GetMapping("/search") + @ResponseStatus(HttpStatus.OK) + public Collection getSearch(@RequestParam(value = "query", defaultValue = "defaultSearch") final String query, @RequestParam(value = "by", defaultValue = "defaultSearch") final String by) { + return filmService.getSearch(query, by); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java index fd6f1d6..7aa5995 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java @@ -42,5 +42,7 @@ public interface FilmRepository { List getDirectorFilmsByLikes(long id); + List getSearch(String query, String searchBy); + List getCommonFilms(long userId, long friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index ae65f2b..d2ae10a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -9,6 +9,7 @@ import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.FilmRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.GenreRowMapper; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; @@ -93,6 +94,18 @@ WHERE fd.film_id IN (:film_ids) GROUP BY f.film_id, r.mpa_name ORDER BY f.name; """; + private static final String GET_SEARCH = """ + SELECT f.*, r.mpa_name, COUNT(l.user_id) AS likes_count + FROM films f + LEFT JOIN likes l ON l.film_id = f.film_id + JOIN mpa r ON r.mpa_id = f.mpa_id + LEFT JOIN FILM_DIRECTORS fd ON fd.FILM_ID = f.FILM_ID + LEFT JOIN DIRECTORS d ON d.DIRECTOR_ID = fd.DIRECTOR_ID + WHERE f.NAME LIKE :film_name + OR d.DIRECTOR_NAME LIKE :director_name + GROUP BY f.film_id, r.mpa_name + ORDER BY likes_count DESC + """; @Override public Film create(Film film) { @@ -338,4 +351,32 @@ public List getCommonFilms(long userId, long friendId) { connectDirectors(commonFilms); return commonFilms; } + + @Override + public List getSearch(String query, String searchBy) { + MapSqlParameterSource params = new MapSqlParameterSource(); + switch (searchBy) { + case "director" -> { + params.addValue("film_name", ""); + params.addValue("director_name", "%" + query + "%"); + } + case "title" -> { + params.addValue("film_name", "%" + query + "%"); + params.addValue("director_name", ""); + } + case "director,title", "title,director" -> { + params.addValue("film_name", "%" + query + "%"); + params.addValue("director_name", "%" + query + "%"); + } + case "defaultSearch" -> { + params.addValue("film_name", "%%"); + params.addValue("director_name", "%%"); + } + default -> throw new ValidationException("некорректный запрос"); + } + List searchedFilms = jdbc.query(GET_SEARCH, params, mapper); + connectGenres(searchedFilms); + connectDirectors(searchedFilms); + return searchedFilms; + } } \ No newline at end of file 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 4518f27..27343ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -24,4 +24,6 @@ public interface FilmService { List getDirectorFilms(long id, String sortBy); List getCommonFilms(long userId, long friendId); + + List getSearch(String query, String searchBy); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index cb877cc..3474130 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -149,4 +149,9 @@ public List getCommonFilms(long userId, long friendId) { List commonFilms = jdbcFilmRepository.getCommonFilms(userId, friendId); return commonFilms; } + + @Override + public List getSearch(String query, String searchBy) { + return jdbcFilmRepository.getSearch(query, searchBy); + } } From f2caf55db41273923ca4d98812df8ca76632a46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BB=D0=B0=D0=B2=D0=B0?= Date: Tue, 13 May 2025 14:18:15 +0400 Subject: [PATCH 32/54] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BD=D0=B5=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index d2ae10a..f94ee1a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -101,8 +101,8 @@ WHERE fd.film_id IN (:film_ids) JOIN mpa r ON r.mpa_id = f.mpa_id LEFT JOIN FILM_DIRECTORS fd ON fd.FILM_ID = f.FILM_ID LEFT JOIN DIRECTORS d ON d.DIRECTOR_ID = fd.DIRECTOR_ID - WHERE f.NAME LIKE :film_name - OR d.DIRECTOR_NAME LIKE :director_name + WHERE LOWER(f.NAME) LIKE LOWER(:film_name) + OR LOWER(d.DIRECTOR_NAME) LIKE LOWER(:director_name) GROUP BY f.film_id, r.mpa_name ORDER BY likes_count DESC """; From 06769f79a77a12833ca0c442b7c12d9a5ced7e3e Mon Sep 17 00:00:00 2001 From: Just Roma Date: Tue, 13 May 2025 15:32:13 +0500 Subject: [PATCH 33/54] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dal/JdbcFilmRepository.java | 16 +++---- .../filmorate/dal/JdbcReviewRepository.java | 48 +++++++++---------- .../filmorate/dal/JdbcUserRepository.java | 26 +++++----- ...rRowMapper.java => ActivityRowMapper.java} | 2 +- 4 files changed, 46 insertions(+), 46 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/dal/mappers/{ActivityrRowMapper.java => ActivityRowMapper.java} (92%) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index bc1e2c9..e0f29fb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -276,11 +276,11 @@ public void addLike(long filmId, long userId) { params.addValue("film_id", filmId); jdbc.update(ADD_LIKE_QUERY, params, keyHolder); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", filmId); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", filmId); - jdbc.update(ACTIVITY_FILM_LIKE, params2); + jdbc.update(ACTIVITY_FILM_LIKE, paramsActivity); } @Override @@ -291,11 +291,11 @@ public void deleteLike(long filmId, long userId) { params.addValue("film_id", filmId); jdbc.update(DELETE_LIKE_QUERY, params, keyHolder); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", filmId); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", filmId); - jdbc.update(ACTIVITY_FILM_LIKE_DELETE, params2); + jdbc.update(ACTIVITY_FILM_LIKE_DELETE, paramsActivity); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 32d2808..9f14d94 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -138,11 +138,11 @@ public Review create(Review review) { jdbc.update(CREATE_REVIEW, params, keyHolder); review.setReviewId(keyHolder.getKeyAs(Long.class)); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", review.getUserId()); - params2.addValue("entityId", review.getReviewId()); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", review.getUserId()); + paramsActivity.addValue("entityId", review.getReviewId()); - jdbc.update(ACTIVITY_REVIEW_CREATE, params2); + jdbc.update(ACTIVITY_REVIEW_CREATE, paramsActivity); return review; } @@ -161,11 +161,11 @@ public Review update(Review review) { jdbc.update(UPDATE_REVIEW, params, keyHolder); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", review.getUserId()); - params2.addValue("entityId", review.getReviewId()); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", review.getUserId()); + paramsActivity.addValue("entityId", review.getReviewId()); - jdbc.update(ACTIVITY_REVIEW_UPDATE, params2); + jdbc.update(ACTIVITY_REVIEW_UPDATE, paramsActivity); return review; } @@ -176,11 +176,11 @@ public void deleteReview(long reviewId) { params.addValue("reviewId", reviewId); Optional review = getReviewById(reviewId); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", review.get().getUserId()); - params2.addValue("entityId", review.get().getReviewId()); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", review.get().getUserId()); + paramsActivity.addValue("entityId", review.get().getReviewId()); - jdbc.update(ACTIVITY_REVIEW_DELETE, params2); + jdbc.update(ACTIVITY_REVIEW_DELETE, paramsActivity); jdbc.update(DELETE_REVIEW, params); } @@ -192,11 +192,11 @@ public void addLike(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(ADD_LIKE_REVIEW, params); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", reviewId); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", reviewId); - jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, params2); + jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, paramsActivity); } @Override @@ -207,11 +207,11 @@ public void addDislike(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(ADD_DISLIKE_REVIEW, params); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", reviewId); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", reviewId); - jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, params2); + jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, paramsActivity); } @Override @@ -221,11 +221,11 @@ public void deleteReaction(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(DELETE_LIKE_REVIEW, params); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", reviewId); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", reviewId); - jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, params2); + jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, paramsActivity); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index eb037ba..fd01570 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -6,7 +6,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.dal.mappers.ActivityrRowMapper; +import ru.yandex.practicum.filmorate.dal.mappers.ActivityRowMapper; import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; @@ -20,7 +20,7 @@ public class JdbcUserRepository implements UserRepository { private final NamedParameterJdbcOperations jdbc; private final RowMapper mapper; - private final ActivityrRowMapper activityrRowMapper; + private final ActivityRowMapper activityRowMapper; private static final String CREATE_USER_QUERY = "INSERT INTO users (login, email, name, birthday) VALUES(:login,:email,:name,:birthday)"; private static final String UPDATE_USER_QUERY = "UPDATE users SET login=:login, email=:email, name=:name, birthday=:birthday WHERE user_id=:user_id"; @@ -52,9 +52,9 @@ private static long instantOfSecond() { @Override public List getActivityById(long userId) { - MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("userId", userId); - return jdbc.query(GET_ACTIVITY_BY_USER_ID, params, activityrRowMapper); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + return jdbc.query(GET_ACTIVITY_BY_USER_ID, paramsActivity, activityRowMapper); } @Override @@ -112,10 +112,10 @@ public void addFriend(long userId, long friendId) { params.addValue("friend_id", friendId); jdbc.update(ADD_FRIEND_QUERY, params, keyHolder); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", friendId); - jdbc.update(ACTIVITY_FRIEND_ADD, params2); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", friendId); + jdbc.update(ACTIVITY_FRIEND_ADD, paramsActivity); } @Override @@ -126,10 +126,10 @@ public void deleteFriend(long userId, long friendId) { params.addValue("friend_id", friendId); jdbc.update(DELETE_FRIEND_QUERY, params, keyHolder); - MapSqlParameterSource params2 = new MapSqlParameterSource(); - params2.addValue("userId", userId); - params2.addValue("entityId", friendId); - jdbc.update(ACTIVITY_FRIEND_DELETE, params2); + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", friendId); + jdbc.update(ACTIVITY_FRIEND_DELETE, paramsActivity); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityRowMapper.java similarity index 92% rename from src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java rename to src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityRowMapper.java index 4a9f8d2..d32ad12 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityrRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/mappers/ActivityRowMapper.java @@ -8,7 +8,7 @@ import java.sql.SQLException; @Component -public class ActivityrRowMapper implements RowMapper { +public class ActivityRowMapper implements RowMapper { @Override public Activity mapRow(ResultSet rs, int rowNum) throws SQLException { Activity activity = new Activity(); From 3088636eabe63954c2c892b515ff3fb80b625442 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Wed, 14 May 2025 13:37:14 +0300 Subject: [PATCH 34/54] =?UTF-8?q?feature:=20add=20recommendations=20-=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=A0=D0=B5=D0=BA=D0=BE=D0=BC=D0=B5=D0=BD=D0=B4=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/UserController.java | 10 +++ .../filmorate/dal/JdbcUserRepository.java | 32 ++++++++- .../filmorate/dal/UserRepository.java | 6 ++ .../filmorate/service/FilmServiceImpl.java | 8 +-- .../service/RecommendationService.java | 8 +++ .../service/RecommendationServiceImpl.java | 67 +++++++++++++++++ .../practicum/filmorate/service/SlopeOne.java | 72 +++++++++++++++++++ .../filmorate/service/UserServiceImpl.java | 6 +- src/main/resources/schema.sql | 8 +-- 9 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/RecommendationService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/RecommendationServiceImpl.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/SlopeOne.java 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 b17a7e8..72da76e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -6,10 +6,13 @@ import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.RecommendationService; import ru.yandex.practicum.filmorate.service.UserServiceImpl; import java.util.Collection; +import java.util.List; @RestController @RequiredArgsConstructor @@ -18,6 +21,7 @@ @Validated public class UserController { private final UserServiceImpl userService; + private final RecommendationService recommendationService; @GetMapping @ResponseStatus(HttpStatus.OK) @@ -72,4 +76,10 @@ public Collection getAllFriends(@PathVariable("userId") long userId) { public Collection getCommonFriends(@PathVariable("userId") long userId, @PathVariable("otherId") long otherId) { return userService.getCommonFriends(userId, otherId); } + + @GetMapping("/{userId}/recommendations") + @ResponseStatus(HttpStatus.OK) + public List getUserRecommendations(@PathVariable("userId") long userId) { + return recommendationService.getRecommendations(userId); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index b559549..140f57b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -19,15 +19,21 @@ public class JdbcUserRepository implements UserRepository { private static final String CREATE_USER_QUERY = "INSERT INTO users (login, email, name, birthday) VALUES(:login,:email,:name,:birthday)"; private static final String UPDATE_USER_QUERY = "UPDATE users SET login=:login, email=:email, name=:name, birthday=:birthday WHERE user_id=:user_id"; - private static final String DELETE_USER_QUERY = "DELETE FROM users WHERE user_id = :user_id"; - private static final String GET_USER_BY_ID_QUERY = "SELECT * FROM users WHERE user_id = :user_id"; + private static final String DELETE_USER_QUERY = "DELETE FROM users WHERE user_id=:user_id"; + private static final String GET_USER_BY_ID_QUERY = "SELECT * FROM users WHERE user_id=:user_id"; private static final String GET_ALL_USERS_QUERY = "SELECT * FROM users"; private static final String ADD_FRIEND_QUERY = "INSERT INTO friends(user_id, friend_id) VALUES(:user_id,:friend_id)"; private static final String DELETE_FRIEND_QUERY = "DELETE FROM friends WHERE user_id=:user_id AND friend_id=:friend_id"; - private static final String GET_USER_FRIENDS_QUERY = "SELECT * FROM users WHERE user_id IN (SELECT friend_id FROM friends WHERE user_id = :user_id)"; + private static final String GET_USER_FRIENDS_QUERY = "SELECT * FROM users WHERE user_id IN (SELECT friend_id FROM friends WHERE user_id=:user_id)"; private static final String FIND_COMMON_FRIENDS = "SELECT u.* FROM users u JOIN friends f1 ON u.user_id = f1.friend_id " + "JOIN friends f2 ON u.user_id = f2.friend_id WHERE f1.user_id = :user_id AND f2.user_id = :other_id"; private static final String FIND_USERS_BY_IDS_QUERY = "SELECT * FROM users WHERE user_id IN (:ids)"; + private static final String GET_USER_LIKED_FILMS_QUERY = """ + SELECT f.film_id + FROM likes l + WHERE l.user_id =:user_id + """; + private static final String GET_ALL_USERS_LIKES = "SELECT user_id, film_id FROM likes"; @Override public User create(User user) { @@ -115,4 +121,24 @@ public List getUsersByIds(List ids) { params.addValue("ids", ids); return jdbc.query(FIND_USERS_BY_IDS_QUERY, params, mapper); } + + @Override + public Set getUserLikedFilms(long userId) { + MapSqlParameterSource params = new MapSqlParameterSource("user_id", userId); + List result = jdbc.queryForList(GET_USER_LIKED_FILMS_QUERY, params, Long.class); + return new HashSet<>(result); + } + + @Override + public Map> getAllUserLikes() { + List> rows = jdbc.queryForList(GET_ALL_USERS_LIKES, new MapSqlParameterSource()); + + Map> userLikes = new HashMap<>(); + for (Map row : rows) { + Long userId = ((Number) row.get("user_id")).longValue(); + Long filmId = ((Number) row.get("film_id")).longValue(); + userLikes.computeIfAbsent(userId, k -> new HashSet<>()).add(filmId); + } + return userLikes; + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java index 531de81..6f9bbf6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/UserRepository.java @@ -3,7 +3,9 @@ import ru.yandex.practicum.filmorate.model.User; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; public interface UserRepository { Optional getUserById(long userId); @@ -25,4 +27,8 @@ public interface UserRepository { List getUserFriends(long userId); List getCommonFriends(long userId, long otherId); + + Set getUserLikedFilms(long userId); + + Map> getAllUserLikes(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java index 5132c95..cb877cc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceImpl.java @@ -4,10 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import ru.yandex.practicum.filmorate.dal.JdbcFilmRepository; -import ru.yandex.practicum.filmorate.dal.JdbcGenreRepository; -import ru.yandex.practicum.filmorate.dal.JdbcMpaRepository; -import ru.yandex.practicum.filmorate.dal.JdbcUserRepository; +import ru.yandex.practicum.filmorate.dal.*; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; @@ -26,6 +23,7 @@ public class FilmServiceImpl implements FilmService { private final JdbcUserRepository jdbcUserRepository; private final JdbcGenreRepository jdbcGenreRepository; private final JdbcMpaRepository jdbcMpaRepository; + private final JdbcDirectorRepository jdbcDirectorRepository; @Override public Film getFilmById(long filmId) { @@ -137,6 +135,8 @@ public List getPopularFilms(int count, Long genreId, Integer year) { @Override public List getDirectorFilms(long id, String sortBy) { + jdbcDirectorRepository.getById(id) + .orElseThrow(() -> new NotFoundException("Режиссёр с id = " + id + " не найден")); if (sortBy.equals("year")) { return jdbcFilmRepository.getDirectorFilmsByYear(id); } else if (sortBy.equals("likes")) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationService.java b/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationService.java new file mode 100644 index 0000000..b3f6f3d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationService.java @@ -0,0 +1,8 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Film; +import java.util.List; + +public interface RecommendationService { + List getRecommendations(long userId); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationServiceImpl.java new file mode 100644 index 0000000..95ee2ec --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/RecommendationServiceImpl.java @@ -0,0 +1,67 @@ +package ru.yandex.practicum.filmorate.service; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dal.JdbcUserRepository; +import ru.yandex.practicum.filmorate.dal.JdbcFilmRepository; +import ru.yandex.practicum.filmorate.model.Film; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +public class RecommendationServiceImpl implements RecommendationService { + private final JdbcUserRepository userRepository; + private final JdbcFilmRepository filmRepository; + private final SlopeOne slopeOne; + + @PostConstruct + public void init() { + slopeOne.buildDifferences(Collections.emptyMap()); + } + + private void rebuildModel() { + var raw = userRepository.getAllUserLikes(); + var data = raw.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> e.getValue().stream().collect(Collectors.toMap(f -> f, f -> 1.0)) + )); + slopeOne.buildDifferences(data); + } + + @Override + public List getRecommendations(long userId) { + var myLikes = userRepository.getAllUserLikes() + .getOrDefault(userId, Collections.emptySet()); + if (myLikes.isEmpty()) { + return Collections.emptyList(); + } + + rebuildModel(); + + var predictions = slopeOne.predictRatings( + myLikes.stream().collect(Collectors.toMap(f -> f, f -> 1.0)) + ); + predictions.keySet().removeAll(myLikes); + + if (predictions.isEmpty()) { + return Collections.emptyList(); + } + + var recommendations = predictions.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .map(e -> filmRepository.getFilmById(e.getKey())) + .flatMap(Optional::stream) + .collect(Collectors.toList()); + + filmRepository.connectGenres(recommendations); + filmRepository.connectDirectors(recommendations); + + return recommendations; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/SlopeOne.java b/src/main/java/ru/yandex/practicum/filmorate/service/SlopeOne.java new file mode 100644 index 0000000..be76669 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/SlopeOne.java @@ -0,0 +1,72 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class SlopeOne { + private final Map> diffMatrix = new HashMap<>(); + + private final Map> freqMatrix = new HashMap<>(); + + public void buildDifferences(Map> data) { + for (Map userRatings : data.values()) { + for (Map.Entry e1 : userRatings.entrySet()) { + long i = e1.getKey(); + double r1 = e1.getValue(); + + diffMatrix.computeIfAbsent(i, k -> new HashMap<>()); + freqMatrix.computeIfAbsent(i, k -> new HashMap<>()); + + for (Map.Entry e2 : userRatings.entrySet()) { + long j = e2.getKey(); + double r2 = e2.getValue(); + + + diffMatrix.get(i).merge(j, r1 - r2, Double::sum); + + freqMatrix.get(i).merge(j, 1, Integer::sum); + } + } + } + + for (Long i : diffMatrix.keySet()) { + for (Long j : diffMatrix.get(i).keySet()) { + double totalDiff = diffMatrix.get(i).get(j); + int count = freqMatrix.get(i).get(j); + diffMatrix.get(i).put(j, totalDiff / count); + } + } + } + + public Map predictRatings(Map userRatings) { + Map predictions = new HashMap<>(); + Map counts = new HashMap<>(); + + for (Map.Entry entry : userRatings.entrySet()) { + long j = entry.getKey(); + double rj = entry.getValue(); + + for (Map.Entry> row : diffMatrix.entrySet()) { + long i = row.getKey(); + Map diffs = row.getValue(); + + if (diffs.containsKey(j)) { + double diff = diffs.get(j); + int freq = freqMatrix.get(i).get(j); + + predictions.merge(i, (diff + rj) * freq, Double::sum); + counts.merge(i, freq, Integer::sum); + } + } + } + + for (Long i : predictions.keySet()) { + predictions.put(i, predictions.get(i) / counts.get(i)); + } + + return predictions; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index 19c8a55..ac5d0e2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -83,9 +83,9 @@ public void deleteFriend(long userId, long friendId) { @Override public List getAllFriends(long userId) { User user = getUserById(userId); - if (user == null) { - throw new NotFoundException("Пользователь с id = " + userId + " не найден"); - } +// if (user == null) { +// throw new NotFoundException("Пользователь с id = " + userId + " не найден"); +// } return jdbcUserRepository.getUserFriends(userId); } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 696ddca..092fdce 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -17,10 +17,10 @@ CREATE TABLE IF NOT EXISTS directors ( CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, - description VARCHAR(200), - release_date DATE, - duration INT CHECK (duration > 0), - mpa_id BIGINT REFERENCES mpa(mpa_id) + description VARCHAR(200) NOT NULL, + release_date DATE NOT NULL, + duration INT NOT NULL CHECK (duration > 0), + mpa_id BIGINT NOT NULL REFERENCES mpa(mpa_id) ); CREATE TABLE IF NOT EXISTS film_genres ( From a75234a6e8d7fd2e4c53d0aa3dfa5d4456e27eca Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Wed, 14 May 2025 13:56:34 +0300 Subject: [PATCH 35/54] clean ups --- .../practicum/filmorate/service/UserServiceImpl.java | 5 +---- src/main/resources/schema.sql | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index ac5d0e2..69c9b1c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -82,10 +82,7 @@ public void deleteFriend(long userId, long friendId) { @Override public List getAllFriends(long userId) { - User user = getUserById(userId); -// if (user == null) { -// throw new NotFoundException("Пользователь с id = " + userId + " не найден"); -// } + getUserById(userId); return jdbcUserRepository.getUserFriends(userId); } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 092fdce..696ddca 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -17,10 +17,10 @@ CREATE TABLE IF NOT EXISTS directors ( CREATE TABLE IF NOT EXISTS films ( film_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(255) NOT NULL, - description VARCHAR(200) NOT NULL, - release_date DATE NOT NULL, - duration INT NOT NULL CHECK (duration > 0), - mpa_id BIGINT NOT NULL REFERENCES mpa(mpa_id) + description VARCHAR(200), + release_date DATE, + duration INT CHECK (duration > 0), + mpa_id BIGINT REFERENCES mpa(mpa_id) ); CREATE TABLE IF NOT EXISTS film_genres ( From 472830e232be5dd5abb1586408ddba50c7b1af67 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Wed, 14 May 2025 17:10:16 +0500 Subject: [PATCH 36/54] edit constant search for Activity --- .../practicum/filmorate/Enum/EventType.java | 8 +++++ .../filmorate/Enum/OperationType.java | 7 +++++ .../filmorate/dal/JdbcFilmRepository.java | 14 ++++----- .../filmorate/dal/JdbcReviewRepository.java | 31 ++++++------------- .../filmorate/dal/JdbcUserRepository.java | 17 +++++----- 5 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/Enum/OperationType.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java b/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java new file mode 100644 index 0000000..86b32c0 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java @@ -0,0 +1,8 @@ +package ru.yandex.practicum.filmorate.Enum; + +public enum EventType { + LIKE, + DISLIKE, + FRIEND, + REVIEW +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/Enum/OperationType.java b/src/main/java/ru/yandex/practicum/filmorate/Enum/OperationType.java new file mode 100644 index 0000000..3163dbc --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/Enum/OperationType.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.Enum; + +public enum OperationType { + ADD, + UPDATE, + REMOVE +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index e0f29fb..add1ea3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -6,6 +6,8 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.Enum.EventType; +import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.FilmRowMapper; import ru.yandex.practicum.filmorate.dal.mappers.GenreRowMapper; @@ -96,19 +98,15 @@ WHERE fd.film_id IN (:film_ids) """; private static final String ACTIVITY_GENERAL = - "INSERT INTO activity (userId, entityId, eventType, operation, timestamp)"; + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp) VALUES(:userId, :entityId, '"; private static final String ACTIVITY_FILM_LIKE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'LIKE', 'ADD', - """ + instantOfSecond() + ")"; + EventType.LIKE + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_FILM_LIKE_DELETE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'LIKE', 'REMOVE', - """ + instantOfSecond() + ")"; + EventType.LIKE + "','" + OperationType.REMOVE + "'," + instantOfMilliSecond() + ")"; - private static long instantOfSecond() { + private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 9f14d94..707cfe4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -5,6 +5,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.Enum.EventType; +import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ReviewRowMapper; import ru.yandex.practicum.filmorate.model.Review; @@ -73,40 +75,27 @@ INSERT INTO reviews_likes (reviewId, userId, reaction_type) """; private static final String ACTIVITY_GENERAL = - "INSERT INTO activity (userId, entityId, eventType, operation, timestamp)"; + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp) VALUES(:userId, :entityId, '"; private static final String ACTIVITY_REVIEW_CREATE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'REVIEW', 'ADD', - """ + instantOfSecond() + ")"; + EventType.REVIEW + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_REVIEW_UPDATE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'REVIEW', 'UPDATE', - """ + instantOfSecond() + ")"; + EventType.REVIEW + "','" + OperationType.UPDATE + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_REVIEW_DELETE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'REVIEW', 'REMOVE', - """ + instantOfSecond() + ")"; - + EventType.REVIEW + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_REVIEW_ADD_LIKE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'LIKE', 'ADD', - """ + instantOfSecond() + ")"; + EventType.LIKE + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_REVIEW_ADD_DISLIKE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'DISLIKE', 'ADD', - """ + instantOfSecond() + ")"; + EventType.DISLIKE + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; private static final String ACTIVITY_REVIEW_DELETE_REACTION = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'LIKE', 'REMOVE', - """ + instantOfSecond() + ")"; + EventType.LIKE + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; - private static long instantOfSecond() { + private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index fd01570..4b14936 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -6,6 +6,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.Enum.EventType; +import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ActivityRowMapper; import ru.yandex.practicum.filmorate.model.Activity; import ru.yandex.practicum.filmorate.model.User; @@ -35,18 +37,17 @@ public class JdbcUserRepository implements UserRepository { private static final String FIND_USERS_BY_IDS_QUERY = "SELECT * FROM users WHERE user_id IN (:ids)"; private static final String ACTIVITY_GENERAL = - "INSERT INTO activity (userId, entityId, eventType, operation, timestamp) "; + "INSERT INTO activity (userId, entityId, eventType, operation, timestamp) VALUES(:userId, :entityId, '"; + private static final String ACTIVITY_FRIEND_ADD = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'FRIEND', 'ADD', - """ + instantOfSecond() + ")"; + EventType.FRIEND + "','" + OperationType.ADD + "'," + instantOfMilliSecond() + ")"; + private static final String ACTIVITY_FRIEND_DELETE = ACTIVITY_GENERAL + - """ - VALUES(:userId, :entityId, 'FRIEND', 'REMOVE', - """ + instantOfSecond() + ")"; + EventType.FRIEND + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; + private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId"; - private static long instantOfSecond() { + private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); } From e1c8ebb9292e066ab1353fe31829efae34a3787b Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Wed, 14 May 2025 15:58:13 +0300 Subject: [PATCH 37/54] merge commit --- .../ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index 805ad65..e1ad717 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -13,8 +13,7 @@ import ru.yandex.practicum.filmorate.model.User; import java.time.Instant; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Stream; @Repository From a536203321f068bf132d42f684d738cc1362ab81 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 15 May 2025 02:05:43 +0500 Subject: [PATCH 38/54] fix --- .../controller/ReviewController.java | 2 +- .../filmorate/dal/JdbcFilmRepository.java | 28 ++++++----- .../filmorate/dal/JdbcReviewRepository.java | 48 +++++++++++++++---- .../filmorate/dal/JdbcUserRepository.java | 9 +++- .../filmorate/service/ReviewServiceImpl.java | 2 +- .../filmorate/service/UserServiceImpl.java | 6 ++- 6 files changed, 70 insertions(+), 25 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 8b53672..af952ac 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -26,7 +26,7 @@ public Optional getReviewById(@PathVariable long id) { @GetMapping @ResponseStatus(HttpStatus.OK) - public List getAllReviewsByFilmId(@RequestParam(value = "filmId") long filmId, + public List getAllReviewsByFilmId(@RequestParam(value = "filmId", defaultValue = "-1") long filmId, @RequestParam(value = "count", defaultValue = "10") long count) { return reviewService.getAllReviewsByFilmId(filmId, count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index fe7e86f..32b3e83 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -1,6 +1,8 @@ package ru.yandex.practicum.filmorate.dal; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -21,6 +23,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +@Slf4j @Repository @RequiredArgsConstructor public class JdbcFilmRepository implements FilmRepository { @@ -281,17 +284,20 @@ public void connectDirectors(Collection films) { @Override public void addLike(long filmId, long userId) { - GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); - MapSqlParameterSource params = new MapSqlParameterSource(); - params.addValue("user_id", userId); - params.addValue("film_id", filmId); - jdbc.update(ADD_LIKE_QUERY, params, keyHolder); - - MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", userId); - paramsActivity.addValue("entityId", filmId); - - jdbc.update(ACTIVITY_FILM_LIKE, paramsActivity); + try { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("user_id", userId); + params.addValue("film_id", filmId); + jdbc.update(ADD_LIKE_QUERY, params); + + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", filmId); + + jdbc.update(ACTIVITY_FILM_LIKE, paramsActivity); + } catch (DataIntegrityViolationException ex) { + log.debug("Лайк уже существует: userId={}, filmId={}", userId, filmId); + } } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 707cfe4..e0c7086 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -11,8 +11,11 @@ import ru.yandex.practicum.filmorate.model.Review; import java.time.Instant; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; @Repository @@ -45,7 +48,22 @@ public class JdbcReviewRepository implements ReviewRepository { COALESCE(SUM(rl.reaction_type), 0) AS useful FROM reviews r LEFT JOIN reviews_likes rl ON r.reviewId = rl.reviewId - GROUP BY r.reviewId, r.content, r.isPositive, r.userId, r.filmId; + GROUP BY r.reviewId, r.content, r.isPositive, r.userId, r.filmId + LIMIT :count; + """; + private static final String GET_ALL_REVIEW_BY_FILM = """ + SELECT + r.reviewId, + r.content, + r.isPositive, + r.userId, + r.filmId, + COALESCE(SUM(rl.reaction_type), 0) AS useful + FROM reviews r + LEFT JOIN reviews_likes rl ON r.reviewId = rl.reviewId + WHERE r.filmId = :filmId + GROUP BY r.reviewId, r.content, r.isPositive, r.userId, r.filmId + LIMIT :count; """; private static final String CREATE_REVIEW = """ @@ -54,7 +72,7 @@ INSERT INTO reviews (content, isPositive, userId, filmId, useful) """; private static final String UPDATE_REVIEW = """ UPDATE reviews - SET content=:content, isPositive=:isPositive, userId=:userId, filmId=:filmId, useful=:useful + SET content=:content, isPositive=:isPositive, useful=:useful WHERE reviewId=:reviewId """; private static final String DELETE_REVIEW = """ @@ -110,7 +128,17 @@ public Optional getReviewById(long reviewId) { @Override public List getAllReviewsByFilmId(long filmId, long count) { - return jdbc.query(GET_ALL_REVIEW, reviewMapper).reversed(); + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("count", count); + if (filmId == -1) { + return jdbc.query(GET_ALL_REVIEW, params, reviewMapper).stream() + .sorted(Comparator.comparingLong(Review::getUseful).reversed()) + .collect(Collectors.toList()); + } + params.addValue("filmId", filmId); + return jdbc.query(GET_ALL_REVIEW_BY_FILM, params, reviewMapper).stream() + .sorted(Comparator.comparingLong(Review::getUseful).reversed()) + .collect(Collectors.toList()); } @Override @@ -143,8 +171,8 @@ public Review update(Review review) { params.addValue("content", review.getContent()); params.addValue("isPositive", review.getIsPositive()); - params.addValue("userId", review.getUserId()); - params.addValue("filmId", review.getFilmId()); +// params.addValue("userId", review.getUserId()); +// params.addValue("filmId", review.getFilmId()); params.addValue("useful", review.getUseful()); params.addValue("reviewId", review.getReviewId()); @@ -196,11 +224,11 @@ public void addDislike(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(ADD_DISLIKE_REVIEW, params); - MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", userId); - paramsActivity.addValue("entityId", reviewId); - - jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, paramsActivity); +// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); +// paramsActivity.addValue("userId", userId); +// paramsActivity.addValue("entityId", reviewId); +// +// jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, paramsActivity); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index e1ad717..346cd72 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -51,6 +51,14 @@ public class JdbcUserRepository implements UserRepository { EventType.FRIEND + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId"; + private static final String GET_ACTIVITY_BY_USER_FRIEND = """ + SELECT a.* + FROM activity a + WHERE a.userId IN ( + SELECT friend_id FROM friends WHERE user_id = :userId + ) + ORDER BY a.timestamp DESC; + """; private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); @@ -107,7 +115,6 @@ public Optional getUserById(long userId) { @Override public List getAllUsers() { return jdbc.query(GET_ALL_USERS_QUERY, mapper); - } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java index ecf6c7e..2c7c53f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java @@ -30,7 +30,7 @@ public Optional getReviewById(long reviewId) { @Override public List getAllReviewsByFilmId(long filmId, long count) { - checkFilmId(filmId); +// checkFilmId(filmId); return jdbcReviewRepository.getAllReviewsByFilmId(filmId, count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java index 05d6655..3decc38 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceImpl.java @@ -22,7 +22,11 @@ public class UserServiceImpl implements UserService { @Override public List getActivityById(long userId) { - return jdbcUserRepository.getActivityById(userId); + List activities = jdbcUserRepository.getActivityById(userId); + if (activities.isEmpty()) { + throw new NotFoundException("Активность пользователя не найдена"); + } + return activities; } @Override From 899d6e199ed2db5bcbcc98caf1b8d80c92556889 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Thu, 15 May 2025 01:53:04 +0300 Subject: [PATCH 39/54] clean ups --- .../filmorate/dal/JdbcReviewRepository.java | 1 - .../filmorate/service/ReviewService.java | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index e0c7086..21e8424 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -11,7 +11,6 @@ import ru.yandex.practicum.filmorate.model.Review; import java.time.Instant; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; 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 55d8dab..f2a70b1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewService.java @@ -6,20 +6,20 @@ import java.util.Optional; public interface ReviewService { - public Optional getReviewById(long reviewId); + Optional getReviewById(long reviewId); - public List getAllReviewsByFilmId(long filmId, long count); + List getAllReviewsByFilmId(long filmId, long count); - public Review create(Review review); + Review create(Review review); - public Review update(Review review); + Review update(Review review); - public void deleteReview(long reviewId); + void deleteReview(long reviewId); - public void addLike(long reviewId, long userId); + void addLike(long reviewId, long userId); - public void addDislike(long reviewId, long userId); + void addDislike(long reviewId, long userId); - public void deleteReaction(long reviewId, long userId); + void deleteReaction(long reviewId, long userId); } From f777dc6609935d8271a96ca483da233ceb73adaa Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 15 May 2025 14:21:55 +0500 Subject: [PATCH 40/54] fix 2 --- .../filmorate/dal/JdbcReviewRepository.java | 24 +++++++++---------- .../filmorate/dal/JdbcUserRepository.java | 8 ------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index e0c7086..83fd592 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -171,8 +171,6 @@ public Review update(Review review) { params.addValue("content", review.getContent()); params.addValue("isPositive", review.getIsPositive()); -// params.addValue("userId", review.getUserId()); -// params.addValue("filmId", review.getFilmId()); params.addValue("useful", review.getUseful()); params.addValue("reviewId", review.getReviewId()); @@ -184,7 +182,7 @@ public Review update(Review review) { jdbc.update(ACTIVITY_REVIEW_UPDATE, paramsActivity); - return review; + return getReviewById(review.getReviewId()).get(); } @Override @@ -209,11 +207,11 @@ public void addLike(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(ADD_LIKE_REVIEW, params); - MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", userId); - paramsActivity.addValue("entityId", reviewId); - - jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, paramsActivity); +// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); +// paramsActivity.addValue("userId", userId); +// paramsActivity.addValue("entityId", reviewId); +// +// jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, paramsActivity); } @Override @@ -238,11 +236,11 @@ public void deleteReaction(long reviewId, long userId) { params.addValue("userId", userId); jdbc.update(DELETE_LIKE_REVIEW, params); - MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", userId); - paramsActivity.addValue("entityId", reviewId); - - jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, paramsActivity); +// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); +// paramsActivity.addValue("userId", userId); +// paramsActivity.addValue("entityId", reviewId); +// +// jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, paramsActivity); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index 346cd72..05c4d0e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -51,14 +51,6 @@ public class JdbcUserRepository implements UserRepository { EventType.FRIEND + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId"; - private static final String GET_ACTIVITY_BY_USER_FRIEND = """ - SELECT a.* - FROM activity a - WHERE a.userId IN ( - SELECT friend_id FROM friends WHERE user_id = :userId - ) - ORDER BY a.timestamp DESC; - """; private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); From 8f9f057255616bdbeab2f5a75eb80547ed51ba55 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 15 May 2025 15:53:17 +0500 Subject: [PATCH 41/54] fix 2 --- .../practicum/filmorate/Enum/EventType.java | 1 - .../filmorate/dal/JdbcReviewRepository.java | 31 ++----------------- .../filmorate/dal/JdbcUserRepository.java | 5 +++ 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java b/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java index 86b32c0..c31602b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java +++ b/src/main/java/ru/yandex/practicum/filmorate/Enum/EventType.java @@ -2,7 +2,6 @@ public enum EventType { LIKE, - DISLIKE, FRIEND, REVIEW } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 83fd592..f4e916b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -104,14 +104,6 @@ INSERT INTO reviews_likes (reviewId, userId, reaction_type) private static final String ACTIVITY_REVIEW_DELETE = ACTIVITY_GENERAL + EventType.REVIEW + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; - private static final String ACTIVITY_REVIEW_ADD_LIKE = ACTIVITY_GENERAL + - EventType.LIKE + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; - - private static final String ACTIVITY_REVIEW_ADD_DISLIKE = ACTIVITY_GENERAL + - EventType.DISLIKE + "','" + OperationType.ADD + "', " + instantOfMilliSecond() + ")"; - - private static final String ACTIVITY_REVIEW_DELETE_REACTION = ACTIVITY_GENERAL + - EventType.LIKE + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); @@ -190,10 +182,9 @@ public void deleteReview(long reviewId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); - Optional review = getReviewById(reviewId); MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", review.get().getUserId()); - paramsActivity.addValue("entityId", review.get().getReviewId()); + paramsActivity.addValue("userId", getReviewById(reviewId).get().getUserId()); + paramsActivity.addValue("entityId", reviewId); jdbc.update(ACTIVITY_REVIEW_DELETE, paramsActivity); jdbc.update(DELETE_REVIEW, params); @@ -206,12 +197,6 @@ public void addLike(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(ADD_LIKE_REVIEW, params); - -// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); -// paramsActivity.addValue("userId", userId); -// paramsActivity.addValue("entityId", reviewId); -// -// jdbc.update(ACTIVITY_REVIEW_ADD_LIKE, paramsActivity); } @Override @@ -221,12 +206,6 @@ public void addDislike(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(ADD_DISLIKE_REVIEW, params); - -// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); -// paramsActivity.addValue("userId", userId); -// paramsActivity.addValue("entityId", reviewId); -// -// jdbc.update(ACTIVITY_REVIEW_ADD_DISLIKE, paramsActivity); } @Override @@ -235,12 +214,6 @@ public void deleteReaction(long reviewId, long userId) { params.addValue("reviewId", reviewId); params.addValue("userId", userId); jdbc.update(DELETE_LIKE_REVIEW, params); - -// MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); -// paramsActivity.addValue("userId", userId); -// paramsActivity.addValue("entityId", reviewId); -// -// jdbc.update(ACTIVITY_REVIEW_DELETE_REACTION, paramsActivity); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index 05c4d0e..d69d230 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -10,10 +10,12 @@ import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ActivityRowMapper; import ru.yandex.practicum.filmorate.model.Activity; +import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.model.User; import java.time.Instant; import java.util.*; +import java.util.stream.Collectors; import java.util.stream.Stream; @Repository @@ -61,6 +63,9 @@ public List getActivityById(long userId) { MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); paramsActivity.addValue("userId", userId); return jdbc.query(GET_ACTIVITY_BY_USER_ID, paramsActivity, activityRowMapper); +// .stream() +// .sorted(Comparator.comparingLong(Activity::getTimestamp).reversed()) +// .collect(Collectors.toList()); } @Override From a40945266f19034443e3704b9d137763f0c97286 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 15 May 2025 16:45:33 +0500 Subject: [PATCH 42/54] fix 3 --- .../practicum/filmorate/dal/JdbcFilmRepository.java | 3 +++ .../practicum/filmorate/dal/JdbcReviewRepository.java | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 32b3e83..d0e0564 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -8,6 +8,7 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import ru.yandex.practicum.filmorate.Enum.EventType; import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; @@ -282,6 +283,7 @@ public void connectDirectors(Collection films) { } } + @Transactional @Override public void addLike(long filmId, long userId) { try { @@ -300,6 +302,7 @@ public void addLike(long filmId, long userId) { } } + @Transactional @Override public void deleteLike(long filmId, long userId) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index ba32006..cb7849c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -5,9 +5,11 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import ru.yandex.practicum.filmorate.Enum.EventType; import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ReviewRowMapper; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Review; import java.time.Instant; @@ -132,6 +134,7 @@ public List getAllReviewsByFilmId(long filmId, long count) { .collect(Collectors.toList()); } + @Transactional @Override public Review create(Review review) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -141,7 +144,7 @@ public Review create(Review review) { params.addValue("isPositive", review.getIsPositive()); params.addValue("userId", review.getUserId()); params.addValue("filmId", review.getFilmId()); - params.addValue("useful", review.getUseful()); + params.addValue("useful", 0); jdbc.update(CREATE_REVIEW, params, keyHolder); review.setReviewId(keyHolder.getKeyAs(Long.class)); @@ -155,6 +158,7 @@ public Review create(Review review) { return review; } + @Transactional @Override public Review update(Review review) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -176,13 +180,16 @@ public Review update(Review review) { return getReviewById(review.getReviewId()).get(); } + @Transactional @Override public void deleteReview(long reviewId) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("reviewId", reviewId); MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", getReviewById(reviewId).get().getUserId()); + Review review = getReviewById(reviewId) + .orElseThrow(() -> new NotFoundException("Review not found")); + paramsActivity.addValue("userId", review.getUserId()); paramsActivity.addValue("entityId", reviewId); jdbc.update(ACTIVITY_REVIEW_DELETE, paramsActivity); From 4855d3679cca6a945e7d01abbda909269bb06c98 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 15 May 2025 21:15:30 +0500 Subject: [PATCH 43/54] fix fatalities --- .../practicum/filmorate/dal/JdbcFilmRepository.java | 12 ++++++------ .../filmorate/dal/JdbcReviewRepository.java | 12 ++++++------ .../practicum/filmorate/dal/JdbcUserRepository.java | 7 +------ 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index d0e0564..60cd7fd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -286,17 +286,17 @@ public void connectDirectors(Collection films) { @Transactional @Override public void addLike(long filmId, long userId) { + + MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); + paramsActivity.addValue("userId", userId); + paramsActivity.addValue("entityId", filmId); + + jdbc.update(ACTIVITY_FILM_LIKE, paramsActivity); try { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("user_id", userId); params.addValue("film_id", filmId); jdbc.update(ADD_LIKE_QUERY, params); - - MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", userId); - paramsActivity.addValue("entityId", filmId); - - jdbc.update(ACTIVITY_FILM_LIKE, paramsActivity); } catch (DataIntegrityViolationException ex) { log.debug("Лайк уже существует: userId={}, filmId={}", userId, filmId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index cb7849c..6964c1f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -124,7 +124,7 @@ public List getAllReviewsByFilmId(long filmId, long count) { MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("count", count); if (filmId == -1) { - return jdbc.query(GET_ALL_REVIEW, params, reviewMapper).stream() + return jdbc.query(GET_ALL_REVIEW, params, reviewMapper).stream() .sorted(Comparator.comparingLong(Review::getUseful).reversed()) .collect(Collectors.toList()); } @@ -168,16 +168,16 @@ public Review update(Review review) { params.addValue("isPositive", review.getIsPositive()); params.addValue("useful", review.getUseful()); params.addValue("reviewId", review.getReviewId()); - jdbc.update(UPDATE_REVIEW, params, keyHolder); + Review reviewUpdated = getReviewById(review.getReviewId()) + .orElseThrow(() -> new NotFoundException("Review not found")); MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); - paramsActivity.addValue("userId", review.getUserId()); - paramsActivity.addValue("entityId", review.getReviewId()); - + paramsActivity.addValue("userId", reviewUpdated.getUserId()); + paramsActivity.addValue("entityId", reviewUpdated.getReviewId()); jdbc.update(ACTIVITY_REVIEW_UPDATE, paramsActivity); - return getReviewById(review.getReviewId()).get(); + return reviewUpdated; } @Transactional diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java index d69d230..881c63d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcUserRepository.java @@ -10,12 +10,10 @@ import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ActivityRowMapper; import ru.yandex.practicum.filmorate.model.Activity; -import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.model.User; import java.time.Instant; import java.util.*; -import java.util.stream.Collectors; import java.util.stream.Stream; @Repository @@ -52,7 +50,7 @@ public class JdbcUserRepository implements UserRepository { private static final String ACTIVITY_FRIEND_DELETE = ACTIVITY_GENERAL + EventType.FRIEND + "','" + OperationType.REMOVE + "', " + instantOfMilliSecond() + ")"; - private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId"; + private static final String GET_ACTIVITY_BY_USER_ID = "SELECT * FROM activity WHERE userId = :userId ORDER BY eventId ASC"; private static long instantOfMilliSecond() { return Instant.now().toEpochMilli(); @@ -63,9 +61,6 @@ public List getActivityById(long userId) { MapSqlParameterSource paramsActivity = new MapSqlParameterSource(); paramsActivity.addValue("userId", userId); return jdbc.query(GET_ACTIVITY_BY_USER_ID, paramsActivity, activityRowMapper); -// .stream() -// .sorted(Comparator.comparingLong(Activity::getTimestamp).reversed()) -// .collect(Collectors.toList()); } @Override From 4ac3bf025cd627526d42a42769dec0178927991e Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Thu, 15 May 2025 22:01:07 +0300 Subject: [PATCH 44/54] clean ups --- .../ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java index 2c7c53f..6b8f385 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ReviewServiceImpl.java @@ -30,7 +30,6 @@ public Optional getReviewById(long reviewId) { @Override public List getAllReviewsByFilmId(long filmId, long count) { -// checkFilmId(filmId); return jdbcReviewRepository.getAllReviewsByFilmId(filmId, count); } From 9f8c99c89ce18c02a455788251aefa317a05d712 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 16 May 2025 09:05:41 +0500 Subject: [PATCH 45/54] fix test gitHub --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d365592..c6b25f4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.url=jdbc:h2:mem:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password \ No newline at end of file From ccf9f135f289c8d1cf18a1830efa87925c8c25a2 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 07:46:32 +0300 Subject: [PATCH 46/54] fix tests --- src/test/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index c0bd8e3..d002829 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.url=jdbc:h2:file:./db/filmorate-test spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password From ffe59ba320b67090217e5e4202ddd22cbfa8a7d6 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 07:51:41 +0300 Subject: [PATCH 47/54] fix tests --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d365592..c6b25f4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.url=jdbc:h2:mem:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password \ No newline at end of file From 1278e7998095f5e4743c7194595e376afe186297 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 07:52:42 +0300 Subject: [PATCH 48/54] fix tests --- src/test/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index d002829..c0bd8e3 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate-test +spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password From 0c1ace6fc8afe437afaafa5bc7b15427379a4040 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 08:09:43 +0300 Subject: [PATCH 49/54] fix tests --- src/main/resources/application.properties | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c6b25f4..a71f7b3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,4 +3,6 @@ spring.sql.init.mode=always spring.datasource.url=jdbc:h2:mem:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa -spring.datasource.password=password \ No newline at end of file +spring.datasource.password=password +spring.datasource.schema=classpath:schema.sql +spring.datasource.data=classpath:data.sql \ No newline at end of file From 6afc5b7083acd58553a881f4a26ebcc93fd39289 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 08:11:12 +0300 Subject: [PATCH 50/54] fix tests --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a71f7b3..9e4d113 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:mem:./db/filmorate +spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password From 39294f706581b0e838942fd0eb2d7c9a9811ab14 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 08:16:11 +0300 Subject: [PATCH 51/54] fix tests --- src/main/resources/application.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 9e4d113..d365592 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,6 +3,4 @@ spring.sql.init.mode=always spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa -spring.datasource.password=password -spring.datasource.schema=classpath:schema.sql -spring.datasource.data=classpath:data.sql \ No newline at end of file +spring.datasource.password=password \ No newline at end of file From 1fd36b2876d6e8fadad5bfa52c78160fced428c4 Mon Sep 17 00:00:00 2001 From: Nadezhda Kotegova Date: Fri, 16 May 2025 11:33:11 +0300 Subject: [PATCH 52/54] fix tests --- src/main/resources/application.properties | 4 +++- src/test/resources/application.properties | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d365592..9e4d113 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,4 +3,6 @@ spring.sql.init.mode=always spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa -spring.datasource.password=password \ No newline at end of file +spring.datasource.password=password +spring.datasource.schema=classpath:schema.sql +spring.datasource.data=classpath:data.sql \ No newline at end of file diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index c0bd8e3..d002829 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.url=jdbc:h2:file:./db/filmorate-test spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password From a3e9d856cbb87bce69509afeeec993f5026a0c38 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Sat, 17 May 2025 14:54:43 +0500 Subject: [PATCH 53/54] fix review --- .../{model => annotation}/StartDate.java | 2 +- .../StartDateValidator.java | 2 +- .../filmorate/dal/JdbcFilmRepository.java | 3 -- .../filmorate/dal/JdbcReviewRepository.java | 4 --- .../filmorate/exception/ErrorHandler.java | 29 ++++++++++++++++++- .../practicum/filmorate/model/Film.java | 1 + src/main/resources/application.properties | 2 +- 7 files changed, 32 insertions(+), 11 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/{model => annotation}/StartDate.java (92%) rename src/main/java/ru/yandex/practicum/filmorate/{model => annotation}/StartDateValidator.java (90%) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/StartDate.java b/src/main/java/ru/yandex/practicum/filmorate/annotation/StartDate.java similarity index 92% rename from src/main/java/ru/yandex/practicum/filmorate/model/StartDate.java rename to src/main/java/ru/yandex/practicum/filmorate/annotation/StartDate.java index 28b94d7..c680e6e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/StartDate.java +++ b/src/main/java/ru/yandex/practicum/filmorate/annotation/StartDate.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.model; +package ru.yandex.practicum.filmorate.annotation; import jakarta.validation.Constraint; import jakarta.validation.Payload; diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/StartDateValidator.java b/src/main/java/ru/yandex/practicum/filmorate/annotation/StartDateValidator.java similarity index 90% rename from src/main/java/ru/yandex/practicum/filmorate/model/StartDateValidator.java rename to src/main/java/ru/yandex/practicum/filmorate/annotation/StartDateValidator.java index 2ed4a1c..61193d6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/StartDateValidator.java +++ b/src/main/java/ru/yandex/practicum/filmorate/annotation/StartDateValidator.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.model; +package ru.yandex.practicum.filmorate.annotation; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java index 60cd7fd..9dbfff9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcFilmRepository.java @@ -8,7 +8,6 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import ru.yandex.practicum.filmorate.Enum.EventType; import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.DirectorRowMapper; @@ -283,7 +282,6 @@ public void connectDirectors(Collection films) { } } - @Transactional @Override public void addLike(long filmId, long userId) { @@ -302,7 +300,6 @@ public void addLike(long filmId, long userId) { } } - @Transactional @Override public void deleteLike(long filmId, long userId) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java index 6964c1f..9a08399 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/JdbcReviewRepository.java @@ -5,7 +5,6 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import ru.yandex.practicum.filmorate.Enum.EventType; import ru.yandex.practicum.filmorate.Enum.OperationType; import ru.yandex.practicum.filmorate.dal.mappers.ReviewRowMapper; @@ -134,7 +133,6 @@ public List getAllReviewsByFilmId(long filmId, long count) { .collect(Collectors.toList()); } - @Transactional @Override public Review create(Review review) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -158,7 +156,6 @@ public Review create(Review review) { return review; } - @Transactional @Override public Review update(Review review) { GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); @@ -180,7 +177,6 @@ public Review update(Review review) { return reviewUpdated; } - @Transactional @Override public void deleteReview(long reviewId) { MapSqlParameterSource params = new MapSqlParameterSource(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java index da47eeb..8d3a617 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java @@ -1,10 +1,13 @@ package ru.yandex.practicum.filmorate.exception; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; @RestControllerAdvice @Slf4j @@ -38,4 +41,28 @@ public ErrorResponse handleServerError(final InternalServerException e) { e.getMessage() ); } + + @ResponseBody + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse onConstraintValidationException(ConstraintViolationException e) { + log.error("Параметры не прошли валидацию Spring {}", e.getMessage()); + return new ErrorResponse( + "Объект не прошёл валидацию Spring ", + e.getMessage() + ); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + public ErrorResponse onMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.error("Объект не прошёл валидацию Spring {}", e.getMessage()); + return new ErrorResponse( + "Объект не прошёл валидацию Spring ", + e.getMessage() + ); + } + + } 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 fd8c6fc..cbcffd8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -2,6 +2,7 @@ import jakarta.validation.constraints.*; import lombok.*; +import ru.yandex.practicum.filmorate.annotation.StartDate; import java.time.LocalDate; import java.util.LinkedHashSet; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a71f7b3..9e11135 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:mem:./db/filmorate +spring.datasource.url=jdbc:h2:file:./db/filmorate-test spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password From a5607c65d791429a9b854bd6c6846ce514cd7b28 Mon Sep 17 00:00:00 2001 From: Nadia Kotezh <64777004+Kotezh@users.noreply.github.com> Date: Sat, 17 May 2025 13:07:29 +0300 Subject: [PATCH 54/54] Update application.properties --- src/test/resources/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index d002829..aee5f55 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,7 +1,7 @@ logging.level.org.zalando.logbook=TRACE spring.sql.init.mode=always -spring.datasource.url=jdbc:h2:file:./db/filmorate-test +spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password -spring.sql.init.data-locations=classpath:test-data.sql \ No newline at end of file +spring.sql.init.data-locations=classpath:test-data.sql