From cc340b4e664e0d925273a1826d1110e3090968d3 Mon Sep 17 00:00:00 2001 From: Alexandr Nazyan Date: Wed, 15 Feb 2023 21:47:52 +0300 Subject: [PATCH 01/26] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/FilmDbStorage.java | 13 +++++++++++-- .../practicum/filmorate/dao/UserDbStorage.java | 14 +++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index e61dcb2..8e8719c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -19,6 +19,7 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Slf4j @Component("filmDBStorage") @@ -105,8 +106,16 @@ public Film updateFilm(Film film) { @Override public void deleteFilmById(int filmId) { - checkFilmInDb(filmId); - + Optional userOptional = Optional.of(getFilmById(filmId)); + if(userOptional.isPresent()) { + jdbcTemplate.update("DELETE FROM film_genre where filmId = ?", filmId); + jdbcTemplate.update("DELETE FROM likesList where filmId = ?", filmId); + jdbcTemplate.update("DELETE FROM films where filmId = ?", filmId); + log.info("Фильм с filmId " + filmId + " был удален."); + } else { + log.info("Фильм с filmId " + filmId + " не был удален."); + throw new NotFoundObjectException("Фильм с filmId " + filmId + " не был удален."); + } } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index faa63ee..ab78f73 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -14,6 +14,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Slf4j @Component("userDBStorage") @@ -77,7 +78,18 @@ public User updateUser(User user) { @Override public User deleteUserById(int userId) { - return null; + Optional userOptional = Optional.of(getUserById(userId)); + if(userOptional.isPresent()) { + jdbcTemplate.update("DELETE FROM friendship where userId = ?", userId); + jdbcTemplate.update("DELETE FROM friendship where friendId = ?", userId); + jdbcTemplate.update("DELETE FROM likesList where userId = ?", userId); + jdbcTemplate.update("DELETE FROM users where userId = ?", userId); + log.info("Пользователь с userId " + userId + " был удален."); + return userOptional.get(); + } else { + log.info("Пользователь с userId " + userId + " не был удален."); + throw new NotFoundObjectException("Пользователь с userId " + userId + " не был удален."); + } } @Override From 18a27c40504567ca2b60475f5628f2dbff703e85 Mon Sep 17 00:00:00 2001 From: mutaev Date: Wed, 15 Feb 2023 02:33:29 +0300 Subject: [PATCH 02/26] add-recommendations add base methods - no implement --- .../practicum/filmorate/controller/UserController.java | 9 ++++++++- .../yandex/practicum/filmorate/dao/UserDbStorage.java | 10 ++++++++-- .../practicum/filmorate/service/UserService.java | 3 +++ .../filmorate/service/UserServiceManager.java | 6 +++++- .../practicum/filmorate/storage/UserStorage.java | 3 +++ 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 895a51c..5111303 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -3,11 +3,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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.UserService; import javax.validation.Valid; -import java.util.*; +import java.util.Collection; +import java.util.List; @Slf4j @RestController @@ -69,6 +71,11 @@ public List getFriends(@PathVariable int id) { public List getCommonFriends(@PathVariable int id, @PathVariable int otherId) { return userService.getCommonFriends(id, otherId); } + + @GetMapping("/{id}/recommendations") + public List recommendFilms(@PathVariable int id) { + return userService.recommendFilms(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index faa63ee..bddc9b4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -1,13 +1,12 @@ package ru.yandex.practicum.filmorate.dao; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.service.UserService; import ru.yandex.practicum.filmorate.storage.UserStorage; import java.sql.ResultSet; @@ -152,6 +151,13 @@ public List getCommonFriends(int userId, int otherId) { } } + @Override + public List getRecommendedFilms(int id) { + String sql = "SELECT * FROM films WHERE userId="+id; + S + return null; + } + private boolean checkUserInDb(Integer id){ String sql = "SELECT userId FROM users"; SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql); 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 0eab755..093e085 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.service; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import java.util.Collection; @@ -16,4 +17,6 @@ public interface UserService { User deleteFriend(int userId, int friendId); List getFriends(int id); List getCommonFriends(int userId, int otherId); + + List recommendFilms(int id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index dfe6948..84c161e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exceptions.ValidationException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.UserStorage; @@ -71,7 +72,10 @@ public List getCommonFriends(int userId, int otherId) { } } return commonFriends; + } - + @Override + public List recommendFilms(int id) { + return userStorage.getRecommendedFilms(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index 8f19b0a..64b9d26 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.storage; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import java.util.List; @@ -15,4 +16,6 @@ public interface UserStorage { User deleteFriend(int userId, int friendId); List getFriends(int id); List getCommonFriends(int userId, int otherId); + + List getRecommendedFilms(int id); } From 84a304be1826fc892742776c8665d9effed1ea0e Mon Sep 17 00:00:00 2001 From: mutaev Date: Wed, 15 Feb 2023 03:35:43 +0300 Subject: [PATCH 03/26] add-recommendations implemented getRecommendedFilms method - pass 364 postman tests --- .../filmorate/controller/UserController.java | 4 ++-- .../practicum/filmorate/dao/UserDbStorage.java | 16 +++++++++++++--- .../practicum/filmorate/service/UserService.java | 2 +- .../filmorate/service/UserServiceManager.java | 2 +- .../filmorate/storage/InMemoryUserStorage.java | 7 ++++++- src/main/resources/application.properties | 4 ++-- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 5111303..740c9a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -73,8 +73,8 @@ public List getCommonFriends(@PathVariable int id, @PathVariable int other } @GetMapping("/{id}/recommendations") - public List recommendFilms(@PathVariable int id) { - return userService.recommendFilms(id); + public List getRecommendedFilms(@PathVariable int id) { + return userService.getRecommendedFilms(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index bddc9b4..5e8abf2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -153,9 +153,19 @@ public List getCommonFriends(int userId, int otherId) { @Override public List getRecommendedFilms(int id) { - String sql = "SELECT * FROM films WHERE userId="+id; - S - return null; + String sql = "SELECT FILMID, NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID FROM FILMS as f JOIN " + + "(SELECT FILMID as recommended FROM LIKESLIST " + + "WHERE USERID = (SELECT USERID FROM LIKESLIST " + + " WHERE FILMID IN (SELECT FILMID as userfilmlist from LIKESLIST where USERID = " + id +") " + + " AND USERID <> " + id + + " GROUP BY USERID " + + " ORDER BY count(USERID) DESC " + + " LIMIT 1) " + + "AND FILMID NOT IN " + + " (SELECT FILMID as userfilmlist from LIKESLIST where USERID = " + id +")) as Lr " + + "ON f.FILMID = recommended"; + + return jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, new FilmDbStorage(jdbcTemplate))); } private boolean checkUserInDb(Integer id){ 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 093e085..ffb5236 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -18,5 +18,5 @@ public interface UserService { List getFriends(int id); List getCommonFriends(int userId, int otherId); - List recommendFilms(int id); + List getRecommendedFilms(int id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index 84c161e..f73a200 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -75,7 +75,7 @@ public List getCommonFriends(int userId, int otherId) { } @Override - public List recommendFilms(int id) { + public List getRecommendedFilms(int id) { return userStorage.getRecommendedFilms(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java index 56eec0d..afb11d9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -1,8 +1,8 @@ package ru.yandex.practicum.filmorate.storage; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.validators.UserValidator; @@ -76,4 +76,9 @@ public List getCommonFriends(int userId, int otherId) { return null; } + @Override + public List getRecommendedFilms(int id) { + return null; + } + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 25509ee..71703d7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,8 +1,8 @@ logging.level.ru.yandex.practicum=debug -logging.level.org.zalando.logbook=TRACE +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;AUTO_SERVER=TRUE spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password \ No newline at end of file From ba12d8180be32dd172d62107f52c696e484b44a6 Mon Sep 17 00:00:00 2001 From: mutaev Date: Tue, 14 Feb 2023 04:47:37 +0300 Subject: [PATCH 04/26] get-add-common-films without validation for existence of users and friendship --- .../filmorate/controller/FilmController.java | 8 ++++++- .../filmorate/dao/FilmDbStorage.java | 23 ++++++++++++++++++- .../filmorate/service/FilmService.java | 2 +- .../filmorate/service/FilmServiceManager.java | 14 ++++++----- .../filmorate/storage/FilmStorage.java | 2 +- .../storage/InMemoryFilmStorage.java | 12 +++++++--- 6 files changed, 48 insertions(+), 13 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 765d7fa..558efa5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -8,7 +8,8 @@ import ru.yandex.practicum.filmorate.service.FilmService; import javax.validation.Valid; -import java.util.*; +import java.util.Collection; +import java.util.List; @Slf4j @RestController @@ -18,6 +19,11 @@ public class FilmController { private final FilmService filmService; + @GetMapping("/common") + public List getCommonFilms(@RequestParam("userId") int userId, @RequestParam("friendId") int friendId) { + return filmService.getCommonFilms(userId, friendId); + } + @GetMapping public Collection getAllFilms() { return filmService.getAllFilms(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index e61dcb2..1664ec2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -12,7 +12,6 @@ import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.storage.FilmStorage; -import ru.yandex.practicum.filmorate.validators.FilmValidator; import java.sql.ResultSet; import java.sql.SQLException; @@ -42,6 +41,26 @@ public List getAllFilms() { return jdbcTemplate.query("SELECT * FROM films", new FilmMapper(jdbcTemplate, this)); } + @Override + public List getCommonFilms(int userId, int friendId) { +// String sql = "SELECT * FROM FILMS as f " + +// "JOIN " + +// "(SELECT FILMID as LikedFilm " + +// "FROM (SELECT ufl as FILMID " + +// "FROM (SELECT FILMID ufl FROM LIKESLIST as ul where USERID = "+ userId + ") " + +// "JOIN (SELECT FILMID ffl FROM LIKESLIST as fl where USERID = "+ friendId + ") " + +// "ON ufl = ffl)) ON f.FILMID = LikedFilm"; + + String sql2 = "SELECT FILMID, NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + + "FROM (SELECT * FROM FILMS as f JOIN " + + "(SELECT A.FILMID as common, A.USERID as AU, B.USERID as BU " + + "FROM LIKESLIST A, LIKESLIST B " + + "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) " + + "ON f.FILMID = common) as c " + + "WHERE (AU = %d AND BU = %d)"; + return jdbcTemplate.query(String.format(sql2, userId, friendId), new FilmMapper(jdbcTemplate, this)); + } + @Override public Film getFilmById(int id) { String sql = "SELECT * FROM films WHERE filmId="+id; @@ -182,6 +201,8 @@ public Mpa getMpaById(int id){ } } + + private boolean checkMpaInDb(int id){ String sql = "SELECT mpaId FROM mpa"; SqlRowSet getMpaFromDb = jdbcTemplate.queryForRowSet(sql); 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 b7494c7..c3ad366 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -4,7 +4,6 @@ import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; -import java.util.Collection; import java.util.List; public interface FilmService { @@ -22,4 +21,5 @@ public interface FilmService { List getAllMpa(); Mpa getMpaById(int id); + List getCommonFilms(int userId, int friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index 9b62265..dd050dd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -1,20 +1,15 @@ package ru.yandex.practicum.filmorate.service; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; -import java.util.*; -import java.util.stream.Collectors; +import java.util.List; @Service public class FilmServiceManager implements FilmService { @@ -28,6 +23,11 @@ public FilmServiceManager(@Qualifier("filmDBStorage") FilmStorage filmStorage, U this.userStorage = userStorage; } + @Override + public List getCommonFilms(int userId, int friendId) { + return filmStorage.getCommonFilms(userId, friendId); + } + @Override public List getAllFilms() { return filmStorage.getAllFilms(); @@ -88,4 +88,6 @@ public Mpa getMpaById(int id) { return filmStorage.getMpaById(id); } + + } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index fbd1da0..2bc6fe5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -4,7 +4,6 @@ import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; -import java.util.Collection; import java.util.List; public interface FilmStorage { @@ -22,4 +21,5 @@ public interface FilmStorage { List getAllMpa(); Mpa getMpaById(int id); + List getCommonFilms(int userId, int friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java index 262695d..eb031f1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -1,7 +1,6 @@ package ru.yandex.practicum.filmorate.storage; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.exceptions.ValidationException; import ru.yandex.practicum.filmorate.model.Film; @@ -9,8 +8,10 @@ import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.validators.FilmValidator; -import java.time.LocalDate; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Slf4j @@ -100,4 +101,9 @@ public Mpa getMpaById(int id) { return null; } + @Override + public List getCommonFilms(int userId, int friendId) { + return null; + } + } From 4ffb8a3a6071d3ff595b7045b0a067d68cf52786 Mon Sep 17 00:00:00 2001 From: mutaev Date: Tue, 14 Feb 2023 04:51:05 +0300 Subject: [PATCH 05/26] get-add-common-films without validation for existence of users and friendship --- .../java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 1664ec2..d8f3e95 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -51,6 +51,7 @@ public List getCommonFilms(int userId, int friendId) { // "JOIN (SELECT FILMID ffl FROM LIKESLIST as fl where USERID = "+ friendId + ") " + // "ON ufl = ffl)) ON f.FILMID = LikedFilm"; + String sql2 = "SELECT FILMID, NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + "FROM (SELECT * FROM FILMS as f JOIN " + "(SELECT A.FILMID as common, A.USERID as AU, B.USERID as BU " + From a3dbd23b82362de7eaa4c03b746491212959376d Mon Sep 17 00:00:00 2001 From: mutaev Date: Tue, 14 Feb 2023 04:58:07 +0300 Subject: [PATCH 06/26] get-add-common-films without validation for existence of users and friendship --- .../yandex/practicum/filmorate/dao/FilmDbStorage.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index d8f3e95..5639c3c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -43,15 +43,6 @@ public List getAllFilms() { @Override public List getCommonFilms(int userId, int friendId) { -// String sql = "SELECT * FROM FILMS as f " + -// "JOIN " + -// "(SELECT FILMID as LikedFilm " + -// "FROM (SELECT ufl as FILMID " + -// "FROM (SELECT FILMID ufl FROM LIKESLIST as ul where USERID = "+ userId + ") " + -// "JOIN (SELECT FILMID ffl FROM LIKESLIST as fl where USERID = "+ friendId + ") " + -// "ON ufl = ffl)) ON f.FILMID = LikedFilm"; - - String sql2 = "SELECT FILMID, NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + "FROM (SELECT * FROM FILMS as f JOIN " + "(SELECT A.FILMID as common, A.USERID as AU, B.USERID as BU " + @@ -59,6 +50,7 @@ public List getCommonFilms(int userId, int friendId) { "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) " + "ON f.FILMID = common) as c " + "WHERE (AU = %d AND BU = %d)"; + return jdbcTemplate.query(String.format(sql2, userId, friendId), new FilmMapper(jdbcTemplate, this)); } From f8f02db9315f4a1138c1efbea3cd12dc23286e4c Mon Sep 17 00:00:00 2001 From: mutaev Date: Tue, 14 Feb 2023 23:51:15 +0300 Subject: [PATCH 07/26] get-add-common-films simplified bd request sorting List by likesCount --- .../practicum/filmorate/dao/FilmDbStorage.java | 14 +++++++------- .../ru/yandex/practicum/filmorate/model/Film.java | 9 +++++++-- .../filmorate/service/FilmServiceManager.java | 5 ++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 5639c3c..0fcd1cf 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -43,15 +43,15 @@ public List getAllFilms() { @Override public List getCommonFilms(int userId, int friendId) { - String sql2 = "SELECT FILMID, NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + - "FROM (SELECT * FROM FILMS as f JOIN " + - "(SELECT A.FILMID as common, A.USERID as AU, B.USERID as BU " + + String sql2 = "SELECT DISTINCT(FILMID), NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + + "FROM FILMS as f JOIN " + + "(SELECT A.FILMID as FI, A.USERID as AU, B.USERID as BU " + "FROM LIKESLIST A, LIKESLIST B " + - "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) " + - "ON f.FILMID = common) as c " + - "WHERE (AU = %d AND BU = %d)"; + "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) as common " + + "ON f.FILMID = common.FI " + + "WHERE (AU = " + userId + " AND BU = " + friendId + ")"; - return jdbcTemplate.query(String.format(sql2, userId, friendId), new FilmMapper(jdbcTemplate, this)); + return jdbcTemplate.query(sql2, new FilmMapper(jdbcTemplate, this)); } @Override 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 e2fa9ea..feee0dc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -3,9 +3,11 @@ import lombok.Data; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; -import javax.validation.constraints.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.Size; import java.time.LocalDate; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; @@ -50,4 +52,7 @@ public void addGenre(Genre genre){ genres.add(genre); } + public Integer getLikesCount(){ + return likes.size(); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index dd050dd..e9b9062 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -9,6 +9,7 @@ import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; +import java.util.Comparator; import java.util.List; @Service @@ -25,7 +26,9 @@ public FilmServiceManager(@Qualifier("filmDBStorage") FilmStorage filmStorage, U @Override public List getCommonFilms(int userId, int friendId) { - return filmStorage.getCommonFilms(userId, friendId); + List resultList = filmStorage.getCommonFilms(userId, friendId); + resultList.sort(Comparator.comparingInt(Film::getLikesCount).reversed()); + return resultList; } @Override From d559d60efedf5195a5d9fbdf923ca08ca9ec3c91 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Fri, 17 Feb 2023 18:44:46 +0300 Subject: [PATCH 08/26] =?UTF-8?q?feat:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=A2=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 14 +- .../controller/ReviewController.java | 170 ++++++++++++++++++ .../filmorate/dao/FilmDbStorage.java | 84 +++++---- .../practicum/filmorate/dao/FilmMapper.java | 2 +- .../filmorate/dao/review/ReviewDbStorage.java | 125 +++++++++++++ .../dao/review/ReviewLikesDbStorage.java | 94 ++++++++++ .../filmorate/exceptions/ErrorHandler.java | 5 +- .../practicum/filmorate/model/Film.java | 12 +- .../practicum/filmorate/model/Review.java | 25 +++ .../practicum/filmorate/model/User.java | 3 +- .../filmorate/service/FilmServiceManager.java | 7 +- .../filmorate/service/UserService.java | 3 +- .../service/review/ReviewService.java | 10 ++ .../service/review/ReviewServiceImpl.java | 89 +++++++++ .../filmorate/storage/FilmStorage.java | 2 - .../storage/InMemoryFilmStorage.java | 2 +- .../storage/review/ReviewLikesStorage.java | 13 ++ .../storage/review/ReviewStorage.java | 15 ++ src/main/resources/schema.sql | 16 ++ 19 files changed, 622 insertions(+), 69 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.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/review/ReviewService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java 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 765d7fa..97e3615 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -31,19 +31,19 @@ public Film getFilm(@PathVariable int id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) public Film createFilm(@Valid @RequestBody Film film) { - log.info("Creating Film " + film); + log.info("Creating Film {}", film.getName()); return filmService.createFilm(film); } @PutMapping public Film updateFilm(@Valid @RequestBody Film film) { - log.info("Updating Film " + film); + log.info("Updating Film {}", film.getName()); return filmService.updateFilm(film); } @DeleteMapping("/{id}") public void deleteFilm(@PathVariable int id) { - log.info("Deleting Film " + id); + log.info("Deleting Film {}", id); filmService.deleteFilmById(id); } @@ -53,12 +53,16 @@ public List getPopularFilms(@RequestParam(defaultValue = "10") int count) } @PutMapping("/{id}/like/{userId}") - public Film likeFilm(@PathVariable int id, @PathVariable int userId) { + public Film likeFilm( + @PathVariable int id, + @PathVariable int userId) { return filmService.likeFilm(id, userId); } @DeleteMapping("/{id}/like/{userId}") - public Film deleteLikeFromFilm(@PathVariable int id, @PathVariable int userId) { + public Film deleteLikeFromFilm( + @PathVariable int id, + @PathVariable int userId) { return filmService.deleteLikeFromFilm(id, userId); } } 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..35c22e7 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -0,0 +1,170 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.service.review.ReviewService; +import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; + +import javax.validation.Valid; +import javax.validation.ValidationException; +import java.util.List; + +@RestController +@Slf4j +@AllArgsConstructor +@RequestMapping("/reviews") +public class ReviewController { + private final ReviewService service; + private final ReviewStorage storage; + + // Одинаковый путь для эндпоинтов getAllReviews & getReviews + + @GetMapping(params = {""}) + public List getAllReviews() { + try { + List reviews = storage.getAllReviews(); + log.info("Список всех ревью в размере {} переданы.", reviews.size()); + return reviews; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @GetMapping("/{id}") + public Review getReviewById(@PathVariable("id") Long reviewId) { + try { + Review review = storage.getById(reviewId); + log.info("Обзор с ID #{} пользователя с ID #{} передан", review.getId(), review.getUserId()); + return review; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @PostMapping + public Review postReview(@RequestBody @Valid Review review) { + try { + review = storage.add(review); + log.info("Отзыв с ID #{} добавлен.", review.getId()); + return review; + } catch (ValidationException e) { + log.error(e.getMessage()); + throw e; + } + } + + @PutMapping + public Review putReview(@RequestBody @Valid Review review) { + try { + review = storage.update(review); + log.info("Отзыв с ID #{} обновлен.", review.getId()); + return review; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @DeleteMapping + public Review deleteReview(@RequestBody @Valid Review review) { + try { + storage.delete(review); + log.info("Отзыв с ID #{} удален.", review.getId()); + return review; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @GetMapping(params = {"count"}) + public List getReviews(@RequestParam(defaultValue = "10") Integer count) { + try { + List reviews = storage.getReviewsWithLimit(count); + log.info("Ревью в размере {} переданы", count); + return reviews; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @GetMapping(params = {"filmId", "count"}) + public List getReviewsWithFilmId( + @RequestParam Long filmId, + @RequestParam(defaultValue = "10") Integer count) { + try { + List reviews = storage.getAllReviewsByFilmId(filmId, count); + log.info("Ревью в размере {} фильма с ID {}", count, filmId); + return reviews; + } catch (DataAccessException e) { + log.error(e.getMessage()); + throw e; + } + } + + @PutMapping("/{id}/like/{userId}") + public Review addLike( + @PathVariable("id") Long reviewId, + @PathVariable Long userId) { + try { + Review review = service.addLike(reviewId, userId); + log.info("Лайк отзыв с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; + } catch (DataAccessException | ValidationException e) { + log.error(e.getMessage()); + throw e; + } + } + + @PutMapping("/{id}/dislike/{userId}") + public Review addDislike( + @PathVariable("id") Long reviewId, + @PathVariable Long userId) { + try { + Review review = service.addDislike(reviewId, userId); + log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; + } catch (DataAccessException | ValidationException e) { + log.error(e.getMessage()); + throw e; + } + } + + @DeleteMapping("/{id}/like/{userId}") + public Review deleteLike( + @PathVariable("id") Long reviewId, + @PathVariable Long userId) { + try { + Review review = service.deleteLike(reviewId, userId); + log.info("Лайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; + } catch (DataAccessException | ValidationException e) { + log.error(e.getMessage()); + throw e; + } + } + + @DeleteMapping("/{id}/dislike/{userId}") + public Review deleteDislike( + @PathVariable("id") Long reviewId, + @PathVariable Long userId) { + try { + Review review = service.deleteDislike(reviewId, userId); + log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; + } catch (DataAccessException | ValidationException e) { + log.error(e.getMessage()); + throw e; + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index e61dcb2..8baaa98 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -12,7 +12,6 @@ import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.storage.FilmStorage; -import ru.yandex.practicum.filmorate.validators.FilmValidator; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,7 +25,7 @@ public class FilmDbStorage implements FilmStorage { private static int filmId = 0; private final JdbcTemplate jdbcTemplate; - private static final LocalDate FILMSTARTDATE = LocalDate.of(1895, 12, 28); + private static final LocalDate FILM_START_DATE = LocalDate.of(1895, 12, 28); public FilmDbStorage(JdbcTemplate jdbcTemplate) { @@ -45,19 +44,19 @@ public List getAllFilms() { @Override public Film getFilmById(int id) { String sql = "SELECT * FROM films WHERE filmId="+id; - if (checkFilmInDb(id)){ + if (checkFilmInDb(id)) { return jdbcTemplate.query(sql, this::makeFilm); - }else{ + } else { return null; } } @Override public Film createFilm(Film film) { - if (film.getReleaseDate().isBefore(FILMSTARTDATE)) { + if (film.getReleaseDate().isBefore(FILM_START_DATE)) { log.info("Не пройдена валидация даты выпуска фильма. Так рано фильмы не снимали!"); throw new ValidationException("Так рано фильмы не снимали!"); - }else{ + } else { film.setId(generateFilmId()); jdbcTemplate.update("INSERT INTO films(filmId, name, description, release_date, duration, mpaId) " + "VALUES(?,?,?,?,?,?)", @@ -67,8 +66,8 @@ public Film createFilm(Film film) { film.getReleaseDate(), film.getDuration(), film.getMpa().getId()); - if(film.getGenres().size()>0){ - for (Genre genre : film.getGenres()){ + if (film.getGenres().size() > 0) { + for (Genre genre : film.getGenres()) { jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) VALUES(?,?)", film.getId(), genre.getId()); @@ -81,7 +80,7 @@ public Film createFilm(Film film) { @Override public Film updateFilm(Film film) { - if(checkFilmInDb(film.getId())){ + if (checkFilmInDb(film.getId())) { jdbcTemplate.update("UPDATE films SET name=?, description=?, release_date=?, duration=?, " + "mpaId=? WHERE filmId=?", film.getName(), @@ -90,14 +89,14 @@ public Film updateFilm(Film film) { film.getDuration(), film.getMpa().getId(), film.getId()); - jdbcTemplate.update("DELETE FROM likesList WHERE filmId=?", film.getId()); - jdbcTemplate.update("DELETE FROM film_genre WHERE filmId=?", film.getId()); - for(Integer userId : film.getLikes()){ - jdbcTemplate.update("INSERT INTO likesList VALUES(?,?)", film.getId(), userId); + jdbcTemplate.update("DELETE FROM likesList WHERE filmId = ?", film.getId()); + jdbcTemplate.update("DELETE FROM film_genre WHERE filmId = ?", film.getId()); + for (Integer userId : film.getLikes()) { + jdbcTemplate.update("INSERT INTO likesList VALUES(?, ?)", film.getId(), userId); } - for (Genre genre : film.getGenres()){ + for (Genre genre : film.getGenres()) { jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) " + - "VALUES(?,?)", film.getId(), genre.getId()); + "VALUES(?, ?)", film.getId(), genre.getId()); } } return film; @@ -106,7 +105,6 @@ public Film updateFilm(Film film) { @Override public void deleteFilmById(int filmId) { checkFilmInDb(filmId); - } @Override @@ -128,7 +126,7 @@ public Film deleteLikeFromFilm(int filmId, int userId) { @Override public List getPopularFilms(int count) { String sql = "SELECT f.*, count(fl.userId) AS likes FROM films AS f LEFT JOIN likesList AS fl " + - "ON f.filmId=fl.filmId GROUP BY f.filmId ORDER BY likes DESC LIMIT "+count; + "ON f.filmId=fl.filmId GROUP BY f.filmId ORDER BY likes DESC LIMIT " + count; return jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, this)); } @@ -136,7 +134,7 @@ public List getPopularFilms(int count) { public List getAllGenres() { List genres = new ArrayList<>(); SqlRowSet allGenres = jdbcTemplate.queryForRowSet("SELECT * FROM genre"); - while(allGenres.next()){ + while (allGenres.next()) { Genre genre = new Genre(allGenres.getInt("genreId"), allGenres.getString("name")); genres.add(genre); } @@ -147,12 +145,12 @@ public List getAllGenres() { public Genre getGenreById(int id) { checkGenreInDb(id); SqlRowSet genreRows = jdbcTemplate.queryForRowSet("SELECT * FROM genre WHERE genreId = ?", id); - if(genreRows.next()){ + if (genreRows.next()) { Genre genre = new Genre(genreRows.getInt("genreId"), genreRows.getString("name")); log.info("Жанр с id={}, это {}.", genre.getId(), genre.getName()); return genre; - }else{ + } else { log.info("Жанра с таким id нет!"); return null; } @@ -162,56 +160,56 @@ public Genre getGenreById(int id) { public List getAllMpa() { List mpas = new ArrayList<>(); SqlRowSet allMpas = jdbcTemplate.queryForRowSet("SELECT * FROM mpa"); - while(allMpas.next()){ + while (allMpas.next()) { Mpa mpa = new Mpa(allMpas.getInt("mpaId"), allMpas.getString("name")); mpas.add(mpa); } return mpas; } - public Mpa getMpaById(int id){ + public Mpa getMpaById(int id) { checkMpaInDb(id); SqlRowSet mpaRows = jdbcTemplate.queryForRowSet("SELECT * FROM mpa WHERE mpaId = ?", id); - if(mpaRows.next()){ + if (mpaRows.next()) { Mpa mpa = new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); log.info("Рейтинг с id={}, это {}.", mpa.getId(), mpa.getName()); return mpa; - }else{ + } else { log.info("Рейтинга с таким id нет!"); return null; } } - private boolean checkMpaInDb(int id){ + private boolean checkMpaInDb(int id) { String sql = "SELECT mpaId FROM mpa"; SqlRowSet getMpaFromDb = jdbcTemplate.queryForRowSet(sql); List ids = new ArrayList<>(); while (getMpaFromDb.next()){ ids.add(getMpaFromDb.getInt("mpaId")); } - if(ids.contains(id)){ + if (ids.contains(id)) { return true; - }else{ + } else { throw new MpaNotFoundException("Рейтинга с таким id нет в базе!"); } } - private boolean checkFilmInDb(Integer id){ + private boolean checkFilmInDb(Integer id) { String sql = "SELECT filmId FROM films"; SqlRowSet getFilmFromDb = jdbcTemplate.queryForRowSet(sql); List ids = new ArrayList<>(); - while (getFilmFromDb.next()){ + while (getFilmFromDb.next()) { ids.add(getFilmFromDb.getInt("filmId")); } - if(ids.contains(id)){ + if (ids.contains(id)) { return true; - }else{ + } else { throw new NotFoundObjectException("Фильма с таким id нет в базе!"); } } private Film makeFilm(ResultSet rs) throws SQLException { - if (rs.next()){ + if (rs.next()) { Film film = new Film(rs.getString("name"), rs.getString("description"), rs.getDate("release_date").toLocalDate(), @@ -219,46 +217,46 @@ private Film makeFilm(ResultSet rs) throws SQLException { film.setId(rs.getInt("filmId")); film.setMpa(getMpaById(rs.getInt("mpaId"))); SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId=?", film.getId()); - while(getFilmGenres.next()){ + while (getFilmGenres.next()) { Genre genre = getGenreById(getFilmGenres.getInt("genreId")); film.addGenre(genre); } SqlRowSet getFilmLikes = jdbcTemplate.queryForRowSet("SELECT userId FROM likesList WHERE filmId = ?", film.getId()); - while(getFilmLikes.next()){ + while (getFilmLikes.next()) { film.addLIke(getFilmLikes.getInt("userId")); } return film; - }else{ + } else { return null; } } - private boolean checkGenreInDb(Integer id){ + private boolean checkGenreInDb(Integer id) { String sql = "SELECT genreId FROM genre"; SqlRowSet getGenreFromDb = jdbcTemplate.queryForRowSet(sql); List ids = new ArrayList<>(); - while (getGenreFromDb.next()){ + while (getGenreFromDb.next()) { ids.add(getGenreFromDb.getInt("genreId")); } - if(ids.contains(id)){ + if (ids.contains(id)) { return true; - }else{ + } else { throw new GenreNotFoundException("Жанра с таким id нет в базе!"); } } - private boolean checkUserInDb(Integer id){ + private boolean checkUserInDb(Integer id) { String sql = "SELECT userId FROM users"; SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql); List ids = new ArrayList<>(); - while (getUsersFromDb.next()){ + while (getUsersFromDb.next()) { ids.add(getUsersFromDb.getInt("userId")); } - if(ids.contains(id)){ + if (ids.contains(id)) { return true; - }else{ + } else { throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java index dea5041..d0b0d04 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java @@ -33,7 +33,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep rs.getInt("duration")); film.setId(rs.getInt("filmId")); film.setMpa(filmStorage.getMpaById(rs.getInt("mpaId"))); - SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId=?", film.getId()); + SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId = ?", film.getId()); while(getFilmGenres.next()){ Genre genre = filmStorage.getGenreById(getFilmGenres.getInt("genreId")); film.addGenre(genre); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java new file mode 100644 index 0000000..3382945 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -0,0 +1,125 @@ +package ru.yandex.practicum.filmorate.dao.review; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; +import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Repository("reviewDbStorage") +@RequiredArgsConstructor +@Slf4j +public class ReviewDbStorage implements ReviewStorage { + private static long REVIEW_ID; + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + private final ReviewLikesStorage reviewLikesStorage; + + @Override + public Review add(Review review) { + createId(review); + String sql = "INSERT INTO review (review_id, content, isPositive, user_id, film_id, useful) " + + "VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; + SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + namedParameterJdbcTemplate.update(sql, parameterSource); + reviewLikesStorage.add(review); + return review; + } + + @Override + public Review update(Review review) { + checkReviewById(review); + String sql = "MERGE INTO review KEY(review_id) VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; + SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + namedParameterJdbcTemplate.update(sql, parameterSource); + reviewLikesStorage.update(review); + return review; + } + + @Override + public Review delete(Review review) { + checkReviewById(review); + String sql = "DELETE FROM review WHERE review_id = :id"; + SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + namedParameterJdbcTemplate.update(sql, parameterSource); + reviewLikesStorage.delete(review); + return review; + } + + @Override + public Review getById(long reviewId) { + String sql = "SELECT * FROM review WHERE review_id = :id"; + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("review_id", reviewId); + Review review = namedParameterJdbcTemplate.queryForObject(sql, parameterSource, this::getRowMapper); + + review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getId())); + return review; + } + + @Override + public List getAllReviewsByFilmId(long filmId, int limit) { + String sql = "SELECT * FROM review WHERE film_id = :filmId ORDER BY useful DESC LIMIT :limit"; + SqlParameterSource parameterSource = new MapSqlParameterSource() + .addValue("filmId", filmId) + .addValue("limit", limit); + return readReviews(sql, parameterSource); + } + + @Override + public List getReviewsWithLimit(int limit) { + String sql = "SELECT * FROM review ORDER BY useful DESC LIMIT :limit"; + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("limit", limit); + return readReviews(sql, parameterSource); + } + + @Override + public List getAllReviews() { + String sql = "SELECT * FROM review ORDER BY useful DESC"; + SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(Review.class); + return readReviews(sql, parameterSource); + } + + private List readReviews(String sql, SqlParameterSource parameterSource) { + Stream reviews = namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper); + Map reviewsLikes = reviewLikesStorage.getAllReviewLikes(); + if (reviewsLikes.size() > 0) { + reviews.forEach(review -> reviewsLikes.forEach((userId, like) -> { + if (review.getUserId() == userId) review.getLikes().put(userId, like); + })); + } + return reviews.collect(Collectors.toList()); + } + + private Review getRowMapper(ResultSet rs, int rowNum) throws SQLException { + return Review.builder() + .id(rs.getLong("review_id")) + .content(rs.getString("content")) + .filmId(rs.getLong("film_id")) + .userId(rs.getLong("user_id")) + .isPositive(rs.getBoolean("isPositive")) + .useful(rs.getInt("useful")) + .build(); + } + + private void checkReviewById(Review review) { + String sql = "SELECT review_id FROM review WHERE review_id = :id"; + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", review.getId()); + namedParameterJdbcTemplate.queryForObject(sql, parameterSource, (rs, rowNum) -> rs.getLong("review_id")); + } + + private void createId(Review review) { + if (review.getId() < REVIEW_ID || review.getId() == 0) review.setId(++REVIEW_ID); + REVIEW_ID = review.getId(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java new file mode 100644 index 0000000..eb12fd7 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java @@ -0,0 +1,94 @@ +package ru.yandex.practicum.filmorate.dao.review; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +@Repository("reviewLikesDbStorage") +@RequiredArgsConstructor +public class ReviewLikesDbStorage implements ReviewLikesStorage { + + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + private final JdbcTemplate jdbcTemplate; + + @Override + public void add(Review review) { + Map likes = review.getLikes(); + + if (likes.size() > 0) { + String sql = getInsertSql(likes, review); + jdbcTemplate.update(sql); + } + } + + @Override + public void update(Review review) { + Map reviewLikes = review.getLikes(); + + if (reviewLikes.size() > 0) { + String sql = getInsertSql(reviewLikes, review); + delete(review); + jdbcTemplate.update(sql); + } + } + + @Override + public void delete(Review review) { + String sql = "DELETE FROM review_likes WHERE review_id = :id"; + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", review.getId()); + namedParameterJdbcTemplate.update(sql, parameterSource); + } + + @Override + public Map getReviewLikesById(long reviewId) { + String sql = "SELECT user_id, isLike FROM review_likes WHERE review_id = ?"; + Stream likesRowStream = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> + new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike")), reviewId); + Map reviewLikes = new HashMap<>(); + if (likesRowStream.findAny().isPresent()) { + likesRowStream.forEach(reviewLikesRow -> + reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); + } + return reviewLikes; + } + + @Override + public Map getAllReviewLikes() { + String sql = "SELECT user_id, isLike FROM review_likes"; + Stream likesRowStream = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> + new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike"))); + Map reviewLikes = new HashMap<>(); + if (likesRowStream.findAny().isPresent()) { + likesRowStream.forEach(reviewLikesRow -> + reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); + } + return reviewLikes; + } + + private String getInsertSql(Map reviewLikes, Review review) { + int commaAndSpace = 2; + long reviewId = review.getId(); + StringBuilder sql = new StringBuilder("INSERT INTO review_likes (user_id, review_id, isLike) VALUES "); + reviewLikes.forEach((userId, isLike) -> sql.append(String.format("(%d, %d, %b), ", userId, reviewId, isLike))); + sql.setLength(sql.length() - commaAndSpace); + return sql.toString(); + } + + @Data + @AllArgsConstructor + private class ReviewLikesRow { + private long userId; + private boolean isLike; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java index 5efc77c..8f314ad 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.exceptions; +import org.springframework.dao.DataAccessException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -15,9 +16,9 @@ public ErrorResponse handleValidationException(final ValidationException e) { return new ErrorResponse(e.getMessage()); } - @ExceptionHandler + @ExceptionHandler({NotFoundObjectException.class, DataAccessException.class}) @ResponseStatus(HttpStatus.NOT_FOUND) - public ErrorResponse handleNotFoundUserException(final NotFoundObjectException e) { + public ErrorResponse handleNotFoundUserException(final RuntimeException e) { return new ErrorResponse(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 e2fa9ea..13ea94e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -3,7 +3,10 @@ import lombok.Data; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; -import javax.validation.constraints.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import javax.validation.constraints.Size; import java.time.LocalDate; import java.util.HashSet; import java.util.LinkedHashSet; @@ -37,10 +40,10 @@ public void addLIke(Integer userId){ likes.add(userId); } - public void removeLike(Integer userId){ + public void removeLike(Integer userId) { if (likes.contains(userId)){ likes.remove(userId); - }else{ + } else { throw new NotFoundObjectException("Лайк от пользователя "+userId+" этому фильму и так не был поставлен, " + "удалять нечего"); } @@ -49,5 +52,4 @@ public void removeLike(Integer userId){ public void addGenre(Genre genre){ genres.add(genre); } - -} +} \ No newline at end of file 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..91e4e4a --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -0,0 +1,25 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.Builder; +import lombok.Data; +import org.springframework.stereotype.Component; + +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; + +@Data +@Builder(toBuilder = true) +public class Review { + private long id; + @NotNull(message = "Пустое описание рецензии") + private String content; + @NotNull + private boolean isPositive; + @NotNull + private long userId; + @NotNull + private long filmId; + private int useful; + private final Map likes = new HashMap<>(); // User ID - true/false for like/dislike +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java index 16a3457..c3f19dc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -1,10 +1,10 @@ package ru.yandex.practicum.filmorate.model; import lombok.Data; -import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import javax.validation.constraints.*; import java.time.LocalDate; +import java.util.HashSet; import java.util.Set; import java.util.TreeSet; @@ -34,5 +34,4 @@ public User(String email, String login, String name, LocalDate birthday) { public void addFriendId(int userId){ friendIds.add(userId); } - } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index 9b62265..8d16c1c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -1,20 +1,15 @@ package ru.yandex.practicum.filmorate.service; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; -import java.util.*; -import java.util.stream.Collectors; +import java.util.List; @Service public class FilmServiceManager implements FilmService { 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 0eab755..c2db3c1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -6,7 +6,6 @@ import java.util.List; public interface UserService { - Collection getAll(); User getById(int id); User createUser(User user); @@ -16,4 +15,4 @@ public interface UserService { User deleteFriend(int userId, int friendId); List getFriends(int id); List getCommonFriends(int userId, int otherId); -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java new file mode 100644 index 0000000..009cb74 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java @@ -0,0 +1,10 @@ +package ru.yandex.practicum.filmorate.service.review; + +import ru.yandex.practicum.filmorate.model.Review; + +public interface ReviewService { + Review addLike(long reviewId, long userId); + Review deleteLike(long reviewId, long userId); + Review addDislike(long reviewId, long userId); + Review deleteDislike(long reviewId, long userId); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java new file mode 100644 index 0000000..b48713b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java @@ -0,0 +1,89 @@ +package ru.yandex.practicum.filmorate.service.review; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; + +import javax.validation.ValidationException; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +@Service +@RequiredArgsConstructor +public class ReviewServiceImpl implements ReviewService { + private final ReviewStorage reviewStorage; + + @Override + public Review addLike(long reviewId, long userId) { + Review review = reviewStorage.getById(reviewId); + Map reviewLikes = review.getLikes(); + + if (reviewLikes.containsKey(userId) && reviewLikes.get(userId).equals(true)) { + throw new ValidationException("Этот пользователь уже поставил лайк."); + } + reviewLikes.put(userId, true); + updateReviewLikes(review, reviewLikes); + return review; + } + + @Override + public Review deleteLike(long reviewId, long userId) { + Review review = reviewStorage.getById(reviewId); + Map reviewLikes = review.getLikes(); + + if (!reviewLikes.containsKey(userId) && reviewLikes.get(userId).equals(false)) { + throw new ValidationException("Этот пользователь не ставил лайк."); + } + reviewLikes.remove(userId); + updateReviewLikes(review, reviewLikes); + return review; + } + + @Override + public Review addDislike(long reviewId, long userId) { + Review review = reviewStorage.getById(reviewId); + Map reviewLikes = review.getLikes(); + + if (reviewLikes.containsKey(userId) && reviewLikes.get(userId).equals(false)) { + throw new ValidationException("Этот пользователь уже поставил дизлайк."); + } + reviewLikes.put(userId, false); + updateReviewLikes(review, reviewLikes); + return review; + } + + @Override + public Review deleteDislike(long reviewId, long userId) { + Review review = reviewStorage.getById(reviewId); + Map reviewLikes = review.getLikes(); + + if (!reviewLikes.containsKey(userId) && reviewLikes.get(userId).equals(true)) { + throw new ValidationException("Этот пользователь уже поставил дизлайк."); + } + reviewLikes.remove(userId); + updateReviewLikes(review, reviewLikes); + return review; + } + + private void setNewUseful(Review review) { + int newUseful; + Map reviewLikes = review.getLikes(); + AtomicInteger likes = new AtomicInteger(); + AtomicInteger dislikes = new AtomicInteger(); + reviewLikes.values().forEach(like -> { + if (like) { + likes.getAndIncrement(); + } + dislikes.getAndIncrement(); + }); + newUseful = likes.intValue() - dislikes.intValue(); + review.setUseful(newUseful); + } + + private void updateReviewLikes(Review review, Map reviewLikes) { + review.getLikes().putAll(reviewLikes); + setNewUseful(review); + reviewStorage.update(review); + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index fbd1da0..69b4e34 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -8,7 +8,6 @@ import java.util.List; public interface FilmStorage { - List getAllFilms(); Film getFilmById(int filmId); Film createFilm(Film film); @@ -21,5 +20,4 @@ public interface FilmStorage { Genre getGenreById(int id); List getAllMpa(); Mpa getMpaById(int id); - } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java index 262695d..3f48e9d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -100,4 +100,4 @@ public Mpa getMpaById(int id) { return null; } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java new file mode 100644 index 0000000..0acd6c5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.storage.review; + +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.Map; + +public interface ReviewLikesStorage { + void add(Review review); + void update(Review review); + void delete(Review review); + Map getReviewLikesById(long reviewId); + Map getAllReviewLikes(); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java new file mode 100644 index 0000000..6214c03 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.storage.review; + +import ru.yandex.practicum.filmorate.model.Review; + +import java.util.List; + +public interface ReviewStorage { + Review add(Review review); + Review update(Review review); + Review delete(Review review); + Review getById(long reviewId); + List getAllReviewsByFilmId(long filmId, int limit); + List getReviewsWithLimit(int limit); + List getAllReviews(); +} \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 40e5d50..3164640 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -44,4 +44,20 @@ CREATE TABLE IF NOT EXISTS mpa ( CREATE TABLE IF NOT EXISTS friendshipStatus ( friendshipStatusId int, description varchar +); + +CREATE TABLE IF NOT EXISTS review ( + review_id LONG PRIMARY KEY, + content varchar NOT NULL CHECK (content <> ' '), + isPositive boolean NOT NULL, + user_id LONG REFERENCES users (userId), + film_id LONG REFERENCES films (filmId), + useful int +); + +CREATE TABLE IF NOT EXISTS review_likes ( + id LONG GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + user_id LONG REFERENCES users (userId) ON DELETE CASCADE, + review_id LONG REFERENCES review (review_id) ON DELETE CASCADE, + isLike BOOLEAN NOT NULL ); \ No newline at end of file From aed5f21b32fb314671e0bb66e532486335c43022 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Sat, 18 Feb 2023 00:11:05 +0300 Subject: [PATCH 09/26] =?UTF-8?q?feat=20&=20fix:=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D1=81=D0=BE=D0=B3=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D0=BD=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 57 ++++------- .../filmorate/dao/review/ReviewDbStorage.java | 96 ++++++++++++------- .../dao/review/ReviewLikesDbStorage.java | 30 +++--- .../filmorate/exceptions/ErrorHandler.java | 2 + .../practicum/filmorate/model/Review.java | 9 +- .../service/review/ReviewServiceImpl.java | 11 +-- .../storage/review/ReviewLikesStorage.java | 2 +- .../storage/review/ReviewStorage.java | 4 +- src/main/resources/application.properties | 5 +- 9 files changed, 111 insertions(+), 105 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 35c22e7..70ead70 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -20,25 +20,11 @@ public class ReviewController { private final ReviewService service; private final ReviewStorage storage; - // Одинаковый путь для эндпоинтов getAllReviews & getReviews - - @GetMapping(params = {""}) - public List getAllReviews() { - try { - List reviews = storage.getAllReviews(); - log.info("Список всех ревью в размере {} переданы.", reviews.size()); - return reviews; - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; - } - } - @GetMapping("/{id}") public Review getReviewById(@PathVariable("id") Long reviewId) { try { Review review = storage.getById(reviewId); - log.info("Обзор с ID #{} пользователя с ID #{} передан", review.getId(), review.getUserId()); + log.info("Обзор с ID #{} пользователя с ID #{} передан", review.getReviewId(), review.getUserId()); return review; } catch (DataAccessException e) { log.error(e.getMessage()); @@ -50,7 +36,7 @@ public Review getReviewById(@PathVariable("id") Long reviewId) { public Review postReview(@RequestBody @Valid Review review) { try { review = storage.add(review); - log.info("Отзыв с ID #{} добавлен.", review.getId()); + log.info("Отзыв с ID #{} добавлен.", review.getReviewId()); return review; } catch (ValidationException e) { log.error(e.getMessage()); @@ -62,7 +48,7 @@ public Review postReview(@RequestBody @Valid Review review) { public Review putReview(@RequestBody @Valid Review review) { try { review = storage.update(review); - log.info("Отзыв с ID #{} обновлен.", review.getId()); + log.info("Отзыв с ID #{} обновлен.", review.getReviewId()); return review; } catch (DataAccessException e) { log.error(e.getMessage()); @@ -70,37 +56,30 @@ public Review putReview(@RequestBody @Valid Review review) { } } - @DeleteMapping - public Review deleteReview(@RequestBody @Valid Review review) { + @DeleteMapping("/{id}") + public void deleteReview(@PathVariable("id") long reviewId) { try { - storage.delete(review); - log.info("Отзыв с ID #{} удален.", review.getId()); - return review; - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; - } - } - - @GetMapping(params = {"count"}) - public List getReviews(@RequestParam(defaultValue = "10") Integer count) { - try { - List reviews = storage.getReviewsWithLimit(count); - log.info("Ревью в размере {} переданы", count); - return reviews; + storage.delete(reviewId); + log.info("Отзыв с ID #{} удален.", reviewId); } catch (DataAccessException e) { log.error(e.getMessage()); throw e; } } - @GetMapping(params = {"filmId", "count"}) - public List getReviewsWithFilmId( - @RequestParam Long filmId, + @GetMapping + public List getReviewsByFilmId( + @RequestParam(required = false) Long filmId, @RequestParam(defaultValue = "10") Integer count) { try { - List reviews = storage.getAllReviewsByFilmId(filmId, count); - log.info("Ревью в размере {} фильма с ID {}", count, filmId); + List reviews; + if (filmId == null) { + reviews = storage.getAllReviews(); + log.info("Передан список всех отзывов в размере {}", reviews.size()); + return reviews; + } + reviews = storage.getAllReviewsByFilmId(filmId, count); + log.info("Список отзывов в размере {} фильма с ID {}", count, filmId); return reviews; } catch (DataAccessException e) { log.error(e.getMessage()); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index 3382945..bec2caa 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -2,11 +2,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; @@ -16,7 +18,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import java.util.stream.Stream; @Repository("reviewDbStorage") @RequiredArgsConstructor @@ -24,14 +25,16 @@ public class ReviewDbStorage implements ReviewStorage { private static long REVIEW_ID; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + private final JdbcTemplate jdbcTemplate; private final ReviewLikesStorage reviewLikesStorage; @Override public Review add(Review review) { + negativeUserOrFilmCheck(review); createId(review); String sql = "INSERT INTO review (review_id, content, isPositive, user_id, film_id, useful) " + "VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; - SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + SqlParameterSource parameterSource = getParameterSource(review); namedParameterJdbcTemplate.update(sql, parameterSource); reviewLikesStorage.add(review); return review; @@ -39,50 +42,55 @@ public Review add(Review review) { @Override public Review update(Review review) { - checkReviewById(review); - String sql = "MERGE INTO review KEY(review_id) VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; - SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + checkReviewById(review.getReviewId()); + String sql = "UPDATE review SET content = :content, isPositive = :isPositive WHERE review_id = :id"; + SqlParameterSource parameterSource = new MapSqlParameterSource() + .addValue("id", review.getReviewId()) + .addValue("content", review.getContent()) + .addValue("isPositive", review.getIsPositive()); + namedParameterJdbcTemplate.update(sql, parameterSource); + return getById(review.getReviewId()); + } + + @Override + public Review updateUseful(Review review) { + String sql = "UPDATE review SET useful = :useful WHERE review_id = :id"; + SqlParameterSource parameterSource = new MapSqlParameterSource() + .addValue("useful", review.getUseful()) + .addValue("id", review.getReviewId()); namedParameterJdbcTemplate.update(sql, parameterSource); reviewLikesStorage.update(review); - return review; + return getById(review.getReviewId()); } @Override - public Review delete(Review review) { - checkReviewById(review); + public void delete(long reviewId) { + checkReviewById(reviewId); String sql = "DELETE FROM review WHERE review_id = :id"; - SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(review); + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); - reviewLikesStorage.delete(review); - return review; + reviewLikesStorage.delete(reviewId); } @Override public Review getById(long reviewId) { - String sql = "SELECT * FROM review WHERE review_id = :id"; - SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("review_id", reviewId); - Review review = namedParameterJdbcTemplate.queryForObject(sql, parameterSource, this::getRowMapper); + if (reviewId <= 0) throw new NotFoundObjectException("Такого отзыва не существует."); + String sql = "SELECT * FROM review WHERE review_id = ?"; + Review review = jdbcTemplate.queryForObject(sql, this::getRowMapper, reviewId); - review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getId())); + review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getReviewId())); return review; } @Override public List getAllReviewsByFilmId(long filmId, int limit) { + if (filmId <= 0) throw new NotFoundObjectException("Такого фильма не существует."); String sql = "SELECT * FROM review WHERE film_id = :filmId ORDER BY useful DESC LIMIT :limit"; SqlParameterSource parameterSource = new MapSqlParameterSource() .addValue("filmId", filmId) .addValue("limit", limit); return readReviews(sql, parameterSource); } - - @Override - public List getReviewsWithLimit(int limit) { - String sql = "SELECT * FROM review ORDER BY useful DESC LIMIT :limit"; - SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("limit", limit); - return readReviews(sql, parameterSource); - } - @Override public List getAllReviews() { String sql = "SELECT * FROM review ORDER BY useful DESC"; @@ -91,19 +99,22 @@ public List getAllReviews() { } private List readReviews(String sql, SqlParameterSource parameterSource) { - Stream reviews = namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper); - Map reviewsLikes = reviewLikesStorage.getAllReviewLikes(); - if (reviewsLikes.size() > 0) { - reviews.forEach(review -> reviewsLikes.forEach((userId, like) -> { - if (review.getUserId() == userId) review.getLikes().put(userId, like); - })); + List reviews = namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper) + .collect(Collectors.toList()); + if (reviews.size() > 0) { + Map reviewsLikes = reviewLikesStorage.getAllReviewLikes(); + if (reviewsLikes.size() > 0) { + reviews.forEach(review -> reviewsLikes.forEach((userId, like) -> { + if (review.getUserId().equals(userId)) review.getLikes().put(userId, like); + })); + } } - return reviews.collect(Collectors.toList()); + return reviews; } private Review getRowMapper(ResultSet rs, int rowNum) throws SQLException { return Review.builder() - .id(rs.getLong("review_id")) + .reviewId(rs.getLong("review_id")) .content(rs.getString("content")) .filmId(rs.getLong("film_id")) .userId(rs.getLong("user_id")) @@ -112,14 +123,29 @@ private Review getRowMapper(ResultSet rs, int rowNum) throws SQLException { .build(); } - private void checkReviewById(Review review) { + private MapSqlParameterSource getParameterSource(Review review) { + return new MapSqlParameterSource() + .addValue("id", review.getReviewId()) + .addValue("content", review.getContent()) + .addValue("isPositive", review.getIsPositive()) + .addValue("userId", review.getUserId()) + .addValue("filmId", review.getFilmId()) + .addValue("useful", review.getUseful()); + } + + private void checkReviewById(long reviewId) { String sql = "SELECT review_id FROM review WHERE review_id = :id"; - SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", review.getId()); + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.queryForObject(sql, parameterSource, (rs, rowNum) -> rs.getLong("review_id")); } private void createId(Review review) { - if (review.getId() < REVIEW_ID || review.getId() == 0) review.setId(++REVIEW_ID); - REVIEW_ID = review.getId(); + if (review.getReviewId() < REVIEW_ID || review.getReviewId() == 0) review.setReviewId(++REVIEW_ID); + REVIEW_ID = review.getReviewId(); + } + + private void negativeUserOrFilmCheck(Review review) throws NotFoundObjectException { + if (review.getFilmId() < 0 || review.getUserId() < 0) + throw new NotFoundObjectException("Такого пользовователя или фильма не существует."); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java index eb12fd7..5a57222 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java @@ -12,13 +12,13 @@ import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.stream.Stream; +import java.util.stream.Collectors; @Repository("reviewLikesDbStorage") @RequiredArgsConstructor public class ReviewLikesDbStorage implements ReviewLikesStorage { - private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final JdbcTemplate jdbcTemplate; @@ -38,26 +38,27 @@ public void update(Review review) { if (reviewLikes.size() > 0) { String sql = getInsertSql(reviewLikes, review); - delete(review); + delete(review.getReviewId()); jdbcTemplate.update(sql); } } @Override - public void delete(Review review) { + public void delete(long reviewId) { String sql = "DELETE FROM review_likes WHERE review_id = :id"; - SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", review.getId()); + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); } @Override public Map getReviewLikesById(long reviewId) { String sql = "SELECT user_id, isLike FROM review_likes WHERE review_id = ?"; - Stream likesRowStream = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> - new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike")), reviewId); + List likesRow = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> + new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike")), reviewId) + .collect(Collectors.toList()); Map reviewLikes = new HashMap<>(); - if (likesRowStream.findAny().isPresent()) { - likesRowStream.forEach(reviewLikesRow -> + if (likesRow.size() > 0) { + likesRow.forEach(reviewLikesRow -> reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); } return reviewLikes; @@ -66,11 +67,12 @@ public Map getReviewLikesById(long reviewId) { @Override public Map getAllReviewLikes() { String sql = "SELECT user_id, isLike FROM review_likes"; - Stream likesRowStream = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> - new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike"))); + List likesRow = jdbcTemplate.queryForStream(sql, (rs, rowNum) -> + new ReviewLikesRow(rs.getLong("user_id"), rs.getBoolean("isLike"))) + .collect(Collectors.toList()); Map reviewLikes = new HashMap<>(); - if (likesRowStream.findAny().isPresent()) { - likesRowStream.forEach(reviewLikesRow -> + if (likesRow.size() > 0) { + likesRow.forEach(reviewLikesRow -> reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); } return reviewLikes; @@ -78,7 +80,7 @@ public Map getAllReviewLikes() { private String getInsertSql(Map reviewLikes, Review review) { int commaAndSpace = 2; - long reviewId = review.getId(); + long reviewId = review.getReviewId(); StringBuilder sql = new StringBuilder("INSERT INTO review_likes (user_id, review_id, isLike) VALUES "); reviewLikes.forEach((userId, isLike) -> sql.append(String.format("(%d, %d, %b), ", userId, reviewId, isLike))); sql.setLength(sql.length() - commaAndSpace); diff --git a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java index 8f314ad..209edd1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java @@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import ru.yandex.practicum.filmorate.model.ErrorResponse; +import javax.validation.ValidationException; + @RestControllerAdvice public class ErrorHandler { diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Review.java b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java index 91e4e4a..8501d65 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Review.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Review.java @@ -2,7 +2,6 @@ import lombok.Builder; import lombok.Data; -import org.springframework.stereotype.Component; import javax.validation.constraints.NotNull; import java.util.HashMap; @@ -11,15 +10,15 @@ @Data @Builder(toBuilder = true) public class Review { - private long id; + private long reviewId; @NotNull(message = "Пустое описание рецензии") private String content; @NotNull - private boolean isPositive; + private Boolean isPositive; @NotNull - private long userId; + private Long userId; @NotNull - private long filmId; + private Long filmId; private int useful; private final Map likes = new HashMap<>(); // User ID - true/false for like/dislike } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java index b48713b..5ccb42c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java @@ -70,20 +70,17 @@ private void setNewUseful(Review review) { int newUseful; Map reviewLikes = review.getLikes(); AtomicInteger likes = new AtomicInteger(); - AtomicInteger dislikes = new AtomicInteger(); reviewLikes.values().forEach(like -> { - if (like) { - likes.getAndIncrement(); - } - dislikes.getAndIncrement(); + if (like) likes.getAndIncrement(); + if (!like) likes.decrementAndGet(); }); - newUseful = likes.intValue() - dislikes.intValue(); + newUseful = likes.intValue(); review.setUseful(newUseful); } private void updateReviewLikes(Review review, Map reviewLikes) { review.getLikes().putAll(reviewLikes); setNewUseful(review); - reviewStorage.update(review); + reviewStorage.updateUseful(review); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java index 0acd6c5..1e2781c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewLikesStorage.java @@ -7,7 +7,7 @@ public interface ReviewLikesStorage { void add(Review review); void update(Review review); - void delete(Review review); + void delete(long reviewId); Map getReviewLikesById(long reviewId); Map getAllReviewLikes(); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java index 6214c03..4f29dac 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/review/ReviewStorage.java @@ -7,9 +7,9 @@ public interface ReviewStorage { Review add(Review review); Review update(Review review); - Review delete(Review review); + Review updateUseful(Review review); + void delete(long reviewId); Review getById(long reviewId); List getAllReviewsByFilmId(long filmId, int limit); - List getReviewsWithLimit(int limit); List getAllReviews(); } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 25509ee..231479b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,8 @@ logging.level.ru.yandex.practicum=debug 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: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.hikari.maximum-pool-size=500 \ No newline at end of file From 760e98790481c89c00b67a49f28704999fe9c6fa Mon Sep 17 00:00:00 2001 From: AleksandraBoycova <111087964+AleksandraBoycova@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:39:59 +0300 Subject: [PATCH 10/26] Add director (#9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Добавлен класс director и DirectorDbStorage * Fixed not found status --------- Co-authored-by: Aleksandra Co-authored-by: kasisaki <32216047+kasisaki@users.noreply.github.com> --- .../controller/DirectorController.java | 55 +++++++ .../filmorate/controller/FilmController.java | 8 + .../filmorate/dao/DirectorDbStorage.java | 141 ++++++++++++++++++ .../filmorate/dao/DirectorMapper.java | 18 +++ .../filmorate/dao/FilmDbStorage.java | 66 +++++--- .../practicum/filmorate/model/Director.java | 15 ++ .../practicum/filmorate/model/Film.java | 1 + .../filmorate/service/DirectorService.java | 15 ++ .../service/DirectorServiceManager.java | 61 ++++++++ .../filmorate/storage/DirectorStorage.java | 16 ++ src/main/resources/data.sql | 2 + src/main/resources/schema.sql | 15 +- 12 files changed, 395 insertions(+), 18 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.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/DirectorServiceManager.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.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..bd294da --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -0,0 +1,55 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.service.DirectorService; + +import java.net.DatagramSocket; +import java.util.List; + +@RestController +@RequestMapping ("directors") +public class DirectorController { + private DirectorService directorService; + + @Autowired + public DirectorController(DirectorService directorService) { + this.directorService = directorService; + } + + @GetMapping + public ResponseEntity> getAll () { + List directorList = directorService.getAll(); + return new ResponseEntity<>(directorList, HttpStatus.OK); + } + + @GetMapping ("{id}") + public ResponseEntity getById (@PathVariable Integer id) { + Director director = directorService.getById(id); + return new ResponseEntity<>(director, HttpStatus.OK); + } + + + + @PostMapping + public ResponseEntity create (@RequestBody Director director) { + Director createdDirector = directorService.create(director); + return new ResponseEntity<>(createdDirector, HttpStatus.OK); + } + + + @PutMapping + public ResponseEntity update (@RequestBody Director director) { + Director updatedDirector = directorService.update(director); + return new ResponseEntity<>(updatedDirector, HttpStatus.OK); + } + + @DeleteMapping ("{id}") + public ResponseEntity delete (@PathVariable Integer id) { + Director director = directorService.delete(id); + return new ResponseEntity<>(director, HttpStatus.OK); + } +} 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 558efa5..4fdeab2 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.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.service.DirectorService; import ru.yandex.practicum.filmorate.service.FilmService; import javax.validation.Valid; @@ -18,6 +19,7 @@ public class FilmController { private final FilmService filmService; + private final DirectorService directorService; @GetMapping("/common") public List getCommonFilms(@RequestParam("userId") int userId, @RequestParam("friendId") int friendId) { @@ -67,5 +69,11 @@ public Film likeFilm(@PathVariable int id, @PathVariable int userId) { public Film deleteLikeFromFilm(@PathVariable int id, @PathVariable int userId) { return filmService.deleteLikeFromFilm(id, userId); } + + @GetMapping ("director/{directorId}") + public List getFilmsByDirectorId (@PathVariable Integer directorId, + @RequestParam (value = "sortBy")String param) { + return directorService.getFilmsSortedByLikesOrYear(directorId, param); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java new file mode 100644 index 0000000..30a4c29 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -0,0 +1,141 @@ +package ru.yandex.practicum.filmorate.dao; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; +import ru.yandex.practicum.filmorate.exceptions.ValidationException; +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.DirectorStorage; + +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component +public class DirectorDbStorage implements DirectorStorage { + private final JdbcTemplate jdbcTemplate; + private final FilmDbStorage filmDbStorage; + public DirectorDbStorage(JdbcTemplate jdbcTemplate, FilmDbStorage filmDbStorage) { + this.jdbcTemplate = jdbcTemplate; + this.filmDbStorage = filmDbStorage; + } + + @Override + public List findAll() { + String statement = "SELECT * FROM directors"; + List directors = jdbcTemplate.query(statement, new DirectorMapper()); + directors.forEach(director -> director.setFilms(new HashSet<>(findFilmsByDirectorId(director.getId())))); + return directors; + } + + @Override + public Director create(Director director) { + if(director.getName() == null || director.getName().isBlank()) { + throw new ValidationException("Name is required"); + } + String statement = "INSERT INTO directors (directorName) VALUES (?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection + .prepareStatement(statement, Statement.RETURN_GENERATED_KEYS); + ps.setString(1, director.getName()); + return ps; + }, keyHolder); + if (keyHolder.getKey() != null) { + if (director.getFilms() != null) { + updateFilmsForDirector(keyHolder.getKey().intValue(), director.getFilms()); + } + return findById(keyHolder.getKey().intValue()); + } + return null; + } + + @Override + public Director update(Director director) { + if (director.getId() == null) { + throw new NotFoundObjectException("Director id is null"); + } + if (! isExists(director.getId())) { + throw new NotFoundObjectException("Director with " + director.getId() + " not found"); + } + if(director.getName() == null || director.getName().isBlank()) { + throw new ValidationException("Name is required"); + } + String statement = "UPDATE directors SET directorName = ? WHERE directorId = ?"; + jdbcTemplate.update(statement, director.getName(), director.getId()); + if (director.getFilms() != null) { + updateFilmsForDirector(director.getId(), director.getFilms()); + } + return findById(director.getId()); + } + + @Override + public Director findById(Integer id) { + if (! isExists(id)) { + throw new NotFoundObjectException("Director with " + id + " not found"); + } + String statement = "SELECT * FROM directors WHERE directorID = ?"; + Director director = jdbcTemplate.queryForObject(statement, new DirectorMapper(), id); + if (director == null) { + throw new NotFoundObjectException("Director with " + id + " not found"); + } + director.setFilms(new HashSet<>(findFilmsByDirectorId(id))); + return director; + } + + @Override + public Director delete(Integer id) { + Director director = findById(id); + jdbcTemplate.update("DELETE FROM directorFilm WHERE directorID = ?", id); + String statement = "DELETE FROM directors WHERE directorID = ?"; + jdbcTemplate.update(statement, id); + deleteDirectorFromDirectorFilm(id); + return director; + } + + public List findFilmsByDirectorId (Integer directorId) { + if (! isExists(directorId)) { + throw new NotFoundObjectException("Director with " + directorId + " not found"); + } + String statement = "SELECT directorId,films.* FROM directorFilm LEFT JOIN films ON directorFilm.filmId = films.filmId WHERE directorId = ?"; + List films = jdbcTemplate.query(statement, new FilmMapper(jdbcTemplate, filmDbStorage), directorId); + if (films != null) { + films.forEach(film -> film.setDirectors(new HashSet<>(findDirectorsByFilmId(film.getId())))); + } + return films; + } + + public void deleteDirectorFromDirectorFilm (Integer id) { + String statement = "DELETE FROM directorFilm WHERE directorId = ?"; + jdbcTemplate.update(statement,id); + } + + private void updateFilmsForDirector (Integer directorId, Set films) { + String statement = "DELETE FROM directorFilm WHERE directorId = ?"; + jdbcTemplate.update(statement,directorId); + statement = "INSERT INTO directorFilm (directorId, filmId) VALUES (?, ?)"; + for (Film film : films) { + jdbcTemplate.update(statement, directorId, film.getId()); + } + } + + public boolean isExists(Integer id) { + String s = "SELECT COUNT(*) FROM directors WHERE directorId=?"; + Long obj = jdbcTemplate.queryForObject(s, Long.class, id); + if (obj != null) { + return obj != 0; + } else { + return false; + } + } + private List findDirectorsByFilmId (Integer filmId) { + String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName FROM directorFilm LEFT JOIN directors ON directorFilm.directorId = directors.directorId WHERE directorFilm.filmId = ?"; + return jdbcTemplate.query(statement, new DirectorMapper(), filmId); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java new file mode 100644 index 0000000..bba397e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java @@ -0,0 +1,18 @@ +package ru.yandex.practicum.filmorate.dao; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.Director; + +import java.sql.ResultSet; +import java.sql.SQLException; + + +public class DirectorMapper implements RowMapper { + @Override + public Director mapRow(ResultSet rs, int rowNum) throws SQLException { + Director director = new Director(); + director.setId(rs.getInt("directorId")); + director.setName(rs.getString("directorName")); + return director; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 8ba41ba..5afbf58 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -8,6 +8,7 @@ import ru.yandex.practicum.filmorate.exceptions.MpaNotFoundException; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.exceptions.ValidationException; +import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; @@ -17,9 +18,14 @@ import java.sql.SQLException; import java.time.LocalDate; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.Optional; + + + @Slf4j @Component("filmDBStorage") public class FilmDbStorage implements FilmStorage { @@ -39,7 +45,11 @@ private int generateFilmId() { @Override public List getAllFilms() { - return jdbcTemplate.query("SELECT * FROM films", new FilmMapper(jdbcTemplate, this)); + List films = jdbcTemplate.query("SELECT * FROM films", new FilmMapper(jdbcTemplate, this)); + if (films != null) { + films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); + } + return films; } @Override @@ -59,7 +69,11 @@ public List getCommonFilms(int userId, int friendId) { public Film getFilmById(int id) { String sql = "SELECT * FROM films WHERE filmId="+id; if (checkFilmInDb(id)){ - return jdbcTemplate.query(sql, this::makeFilm); + Film film = jdbcTemplate.query(sql, this::makeFilm); + if (film != null) { + film.setDirectors(new HashSet<>(getDirectorByFilmId(id))); + } + return film; }else{ return null; } @@ -70,7 +84,7 @@ public Film createFilm(Film film) { if (film.getReleaseDate().isBefore(FILMSTARTDATE)) { log.info("Не пройдена валидация даты выпуска фильма. Так рано фильмы не снимали!"); throw new ValidationException("Так рано фильмы не снимали!"); - }else{ + }else { film.setId(generateFilmId()); jdbcTemplate.update("INSERT INTO films(filmId, name, description, release_date, duration, mpaId) " + "VALUES(?,?,?,?,?,?)", @@ -80,21 +94,24 @@ public Film createFilm(Film film) { film.getReleaseDate(), film.getDuration(), film.getMpa().getId()); - if(film.getGenres().size()>0){ - for (Genre genre : film.getGenres()){ + if (film.getGenres().size() > 0) { + for (Genre genre : film.getGenres()) { jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) VALUES(?,?)", film.getId(), genre.getId()); } } - + jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); + if (film.getDirectors() != null) { + film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); + } } - return film; + return getFilmById(film.getId()); } @Override public Film updateFilm(Film film) { - if(checkFilmInDb(film.getId())){ + if(checkFilmInDb(film.getId())) { jdbcTemplate.update("UPDATE films SET name=?, description=?, release_date=?, duration=?, " + "mpaId=? WHERE filmId=?", film.getName(), @@ -105,25 +122,29 @@ public Film updateFilm(Film film) { film.getId()); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=?", film.getId()); jdbcTemplate.update("DELETE FROM film_genre WHERE filmId=?", film.getId()); - for(Integer userId : film.getLikes()){ + for (Integer userId : film.getLikes()) { jdbcTemplate.update("INSERT INTO likesList VALUES(?,?)", film.getId(), userId); } - for (Genre genre : film.getGenres()){ + for (Genre genre : film.getGenres()) { jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) " + "VALUES(?,?)", film.getId(), genre.getId()); } + jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); + if (film.getDirectors() != null) { + film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); + } } - return film; + return getFilmById(film.getId()); } @Override public void deleteFilmById(int filmId) { - Optional userOptional = Optional.of(getFilmById(filmId)); - if(userOptional.isPresent()) { + if(checkFilmInDb(filmId)) { jdbcTemplate.update("DELETE FROM film_genre where filmId = ?", filmId); jdbcTemplate.update("DELETE FROM likesList where filmId = ?", filmId); jdbcTemplate.update("DELETE FROM films where filmId = ?", filmId); log.info("Фильм с filmId " + filmId + " был удален."); + jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", filmId); } else { log.info("Фильм с filmId " + filmId + " не был удален."); throw new NotFoundObjectException("Фильм с filmId " + filmId + " не был удален."); @@ -150,7 +171,11 @@ public Film deleteLikeFromFilm(int filmId, int userId) { public List getPopularFilms(int count) { String sql = "SELECT f.*, count(fl.userId) AS likes FROM films AS f LEFT JOIN likesList AS fl " + "ON f.filmId=fl.filmId GROUP BY f.filmId ORDER BY likes DESC LIMIT "+count; - return jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, this)); + List films = jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, this)); + if (films != null) { + films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); + } + return films; } @Override @@ -219,16 +244,16 @@ private boolean checkMpaInDb(int id){ } } - private boolean checkFilmInDb(Integer id){ + private boolean checkFilmInDb(Integer id) { String sql = "SELECT filmId FROM films"; SqlRowSet getFilmFromDb = jdbcTemplate.queryForRowSet(sql); List ids = new ArrayList<>(); while (getFilmFromDb.next()){ ids.add(getFilmFromDb.getInt("filmId")); } - if(ids.contains(id)){ + if(ids.contains(id)) { return true; - }else{ + } else { throw new NotFoundObjectException("Фильма с таким id нет в базе!"); } } @@ -285,6 +310,13 @@ private boolean checkUserInDb(Integer id){ throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); } + + } + private List getDirectorByFilmId (Integer filmId) { + String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName " + + "FROM directorFilm LEFT JOIN directors " + + "ON directorFilm.directorId = directors.directorId WHERE directorFilm.filmId = ?"; + return jdbcTemplate.query(statement, new DirectorMapper(), filmId); } } 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..9fb3df8 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Data +public class Director { + private Integer id; + + private String name; + private Set films; +} 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 feee0dc..ca72bbe 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -27,6 +27,7 @@ public class Film { private Set likes = new LinkedHashSet<>(); private Set genres = new LinkedHashSet<>(); private Mpa mpa; + private Set directors; public Film(String name, String description, LocalDate releaseDate, int duration) { this.name = name; 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..837b144 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.model.Film; + +import java.util.List; + +public interface DirectorService { + Director create (Director director); + Director update (Director director); + Director getById (Integer id); + Director delete (Integer id); + List getAll (); + List getFilmsSortedByLikesOrYear (Integer id, String param); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java new file mode 100644 index 0000000..aa287f3 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java @@ -0,0 +1,61 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.DirectorStorage; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +public class DirectorServiceManager implements DirectorService { + private DirectorStorage storage; + + @Autowired + public DirectorServiceManager(DirectorStorage storage) { + this.storage = storage; + } + + @Override + public Director create(Director director) { + return storage.create(director); + } + + @Override + public Director update(Director director) { + return storage.update(director); + } + + @Override + public Director getById(Integer id) { + return storage.findById(id); + } + + @Override + public Director delete(Integer id) { + return storage.delete(id); + } + + @Override + public List getAll() { + return storage.findAll(); + } + + @Override + public List getFilmsSortedByLikesOrYear(Integer id, String param) { + List filmsByDirectorId = storage.findFilmsByDirectorId(id); + + if ("year".equalsIgnoreCase(param)) { + return filmsByDirectorId + .stream().sorted(Comparator.comparing(Film::getReleaseDate)).collect(Collectors.toList()); + } + else if ("likes".equalsIgnoreCase(param)) { + return filmsByDirectorId.stream().sorted(Comparator.comparing(film -> film.getLikes().size())).collect(Collectors.toList()); + } + return filmsByDirectorId; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java new file mode 100644 index 0000000..1e9234d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java @@ -0,0 +1,16 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Director; +import ru.yandex.practicum.filmorate.model.Film; + +import java.util.List; + +public interface DirectorStorage { + List findAll (); + Director create (Director director); + Director update (Director director); + Director findById (Integer id); + Director delete (Integer id); + List findFilmsByDirectorId (Integer directorId); + +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 1de346b..831d36a 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,3 +1,5 @@ +DELETE FROM directorFilm; +DELETE FROM directors; DELETE FROM films; DELETE FROM users; DELETE FROM film_genre; diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 40e5d50..12f1031 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -44,4 +44,17 @@ CREATE TABLE IF NOT EXISTS mpa ( CREATE TABLE IF NOT EXISTS friendshipStatus ( friendshipStatusId int, description varchar -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS directors ( + directorId int NOT NULL AUTO_INCREMENT PRIMARY KEY, + directorName varchar + ); + + CREATE TABLE IF NOT EXISTS directorFilm ( + directorFilmId int NOT NULL AUTO_INCREMENT PRIMARY KEY, + filmId int, + directorId int, + CONSTRAINT filmDirectorFilm FOREIGN KEY (filmId) REFERENCES films (filmId), + CONSTRAINT directorFilmDirector FOREIGN KEY (directorId) REFERENCES directors (directorId) + ); From ce692e9c9eab6d2055d78341e69438f41389c7a8 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Tue, 21 Feb 2023 09:36:57 +0300 Subject: [PATCH 11/26] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=20=D0=BA=D0=BE=D0=BD=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D1=83=20=D0=B8=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 118 ++++++------------ .../filmorate/exceptions/ErrorHandler.java | 7 ++ .../service/review/ReviewService.java | 8 ++ .../service/review/ReviewServiceImpl.java | 31 +++++ .../filmorate/storage/DirectorStorage.java | 1 - 5 files changed, 81 insertions(+), 84 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 70ead70..38ebb37 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -2,14 +2,11 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.dao.DataAccessException; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Review; import ru.yandex.practicum.filmorate.service.review.ReviewService; -import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; import javax.validation.Valid; -import javax.validation.ValidationException; import java.util.List; @RestController @@ -18,132 +15,87 @@ @RequestMapping("/reviews") public class ReviewController { private final ReviewService service; - private final ReviewStorage storage; @GetMapping("/{id}") public Review getReviewById(@PathVariable("id") Long reviewId) { - try { - Review review = storage.getById(reviewId); - log.info("Обзор с ID #{} пользователя с ID #{} передан", review.getReviewId(), review.getUserId()); - return review; - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; - } + Review review = service.getById(reviewId); + log.info("Обзор с ID #{} пользователя с ID #{} передан", review.getReviewId(), review.getUserId()); + return review; + } @PostMapping public Review postReview(@RequestBody @Valid Review review) { - try { - review = storage.add(review); - log.info("Отзыв с ID #{} добавлен.", review.getReviewId()); - return review; - } catch (ValidationException e) { - log.error(e.getMessage()); - throw e; - } + review = service.add(review); + log.info("Отзыв с ID #{} добавлен.", review.getReviewId()); + return review; } @PutMapping public Review putReview(@RequestBody @Valid Review review) { - try { - review = storage.update(review); - log.info("Отзыв с ID #{} обновлен.", review.getReviewId()); - return review; - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; - } + review = service.update(review); + log.info("Отзыв с ID #{} обновлен.", review.getReviewId()); + return review; } @DeleteMapping("/{id}") public void deleteReview(@PathVariable("id") long reviewId) { - try { - storage.delete(reviewId); - log.info("Отзыв с ID #{} удален.", reviewId); - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; - } + service.delete(reviewId); + log.info("Отзыв с ID #{} удален.", reviewId); } @GetMapping public List getReviewsByFilmId( @RequestParam(required = false) Long filmId, @RequestParam(defaultValue = "10") Integer count) { - try { - List reviews; - if (filmId == null) { - reviews = storage.getAllReviews(); - log.info("Передан список всех отзывов в размере {}", reviews.size()); - return reviews; - } - reviews = storage.getAllReviewsByFilmId(filmId, count); - log.info("Список отзывов в размере {} фильма с ID {}", count, filmId); + List reviews; + if (filmId == null) { + reviews = service.getAllReviews(); + log.info("Передан список всех отзывов в размере {}", reviews.size()); return reviews; - } catch (DataAccessException e) { - log.error(e.getMessage()); - throw e; } + reviews = service.getAllReviewsByFilmId(filmId, count); + log.info("Список отзывов в размере {} фильма с ID {}", count, filmId); + return reviews; } @PutMapping("/{id}/like/{userId}") public Review addLike( @PathVariable("id") Long reviewId, @PathVariable Long userId) { - try { - Review review = service.addLike(reviewId, userId); - log.info("Лайк отзыв с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", - reviewId, userId, review.getUseful()); - return review; - } catch (DataAccessException | ValidationException e) { - log.error(e.getMessage()); - throw e; - } + Review review = service.addLike(reviewId, userId); + log.info("Лайк отзыв с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; } @PutMapping("/{id}/dislike/{userId}") public Review addDislike( @PathVariable("id") Long reviewId, @PathVariable Long userId) { - try { - Review review = service.addDislike(reviewId, userId); - log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", - reviewId, userId, review.getUseful()); - return review; - } catch (DataAccessException | ValidationException e) { - log.error(e.getMessage()); - throw e; - } + Review review = service.addDislike(reviewId, userId); + log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; } @DeleteMapping("/{id}/like/{userId}") public Review deleteLike( @PathVariable("id") Long reviewId, @PathVariable Long userId) { - try { - Review review = service.deleteLike(reviewId, userId); - log.info("Лайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", - reviewId, userId, review.getUseful()); - return review; - } catch (DataAccessException | ValidationException e) { - log.error(e.getMessage()); - throw e; - } + Review review = service.deleteLike(reviewId, userId); + log.info("Лайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; } @DeleteMapping("/{id}/dislike/{userId}") public Review deleteDislike( @PathVariable("id") Long reviewId, @PathVariable Long userId) { - try { - Review review = service.deleteDislike(reviewId, userId); - log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", - reviewId, userId, review.getUseful()); - return review; - } catch (DataAccessException | ValidationException e) { - log.error(e.getMessage()); - throw e; - } + Review review = service.deleteDislike(reviewId, userId); + log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", + reviewId, userId, review.getUseful()); + return review; } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java index 209edd1..74a71f1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exceptions/ErrorHandler.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.exceptions; +import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DataAccessException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -10,35 +11,41 @@ import javax.validation.ValidationException; @RestControllerAdvice +@Slf4j public class ErrorHandler { @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleValidationException(final ValidationException e) { + log.error(e.getMessage()); return new ErrorResponse(e.getMessage()); } @ExceptionHandler({NotFoundObjectException.class, DataAccessException.class}) @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleNotFoundUserException(final RuntimeException e) { + log.error(e.getMessage()); return new ErrorResponse(e.getMessage()); } @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResponse handleThrowable(final Throwable e) { + log.error(e.getMessage()); return new ErrorResponse(e.getMessage()); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleMpaNotFoundException(final MpaNotFoundException e){ + log.error(e.getMessage()); return new ErrorResponse(String.format("Возникла ошибка поиска рейтинга: \"%s\".", e.getMessage())); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) public ErrorResponse handleGenreNotFoundException(final GenreNotFoundException e){ + log.error(e.getMessage()); return new ErrorResponse(String.format("Возникла ошибка поиска жанра: \"%s\".", e.getMessage())); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java index 009cb74..39e1b08 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewService.java @@ -2,7 +2,15 @@ import ru.yandex.practicum.filmorate.model.Review; +import java.util.List; + public interface ReviewService { + Review add(Review review); + Review update(Review review); + void delete(long reviewId); + Review getById(long reviewId); + List getAllReviewsByFilmId(long filmId, int limit); + List getAllReviews(); Review addLike(long reviewId, long userId); Review deleteLike(long reviewId, long userId); Review addDislike(long reviewId, long userId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java index 5ccb42c..4433a06 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java @@ -6,6 +6,7 @@ import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; import javax.validation.ValidationException; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -14,6 +15,36 @@ public class ReviewServiceImpl implements ReviewService { private final ReviewStorage reviewStorage; + @Override + public Review add(Review review) { + return reviewStorage.add(review); + } + + @Override + public Review update(Review review) { + return reviewStorage.update(review); + } + + @Override + public void delete(long reviewId) { + reviewStorage.delete(reviewId); + } + + @Override + public Review getById(long reviewId) { + return reviewStorage.getById(reviewId); + } + + @Override + public List getAllReviewsByFilmId(long filmId, int limit) { + return reviewStorage.getAllReviewsByFilmId(filmId, limit); + } + + @Override + public List getAllReviews() { + return reviewStorage.getAllReviews(); + } + @Override public Review addLike(long reviewId, long userId) { Review review = reviewStorage.getById(reviewId); diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java index 1e9234d..c067acf 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/DirectorStorage.java @@ -12,5 +12,4 @@ public interface DirectorStorage { Director findById (Integer id); Director delete (Integer id); List findFilmsByDirectorId (Integer directorId); - } From 83aefe0e0fb50bdb754f8ef9c7eef6d4a31f4d07 Mon Sep 17 00:00:00 2001 From: Alexandr Nazyan Date: Wed, 22 Feb 2023 01:15:32 +0300 Subject: [PATCH 12/26] =?UTF-8?q?fead:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20Events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/UserController.java | 6 ++ .../filmorate/dao/DirectorDbStorage.java | 3 +- .../filmorate/dao/EventDbStorage.java | 39 +++++++++++ .../filmorate/dao/FilmDbStorage.java | 18 ++--- .../filmorate/dao/UserDbStorage.java | 26 +++++-- .../dao/{ => mappers}/DirectorMapper.java | 2 +- .../filmorate/dao/mappers/EventMapper.java | 22 ++++++ .../dao/{ => mappers}/FilmMapper.java | 12 ++-- .../dao/{ => mappers}/UserMapper.java | 2 +- .../filmorate/dao/review/ReviewDbStorage.java | 13 ++++ .../practicum/filmorate/model/Event.java | 28 ++++++++ .../filmorate/model/enums/EventTypes.java | 7 ++ .../filmorate/model/enums/OperationTypes.java | 7 ++ .../filmorate/service/UserService.java | 2 + .../filmorate/service/UserServiceManager.java | 6 ++ .../storage/InMemoryUserStorage.java | 6 ++ .../filmorate/storage/UserStorage.java | 3 +- src/main/resources/data.sql | 17 ++--- src/main/resources/schema.sql | 70 ++++++++++++------- 19 files changed, 229 insertions(+), 60 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java rename src/main/java/ru/yandex/practicum/filmorate/dao/{ => mappers}/DirectorMapper.java (90%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/mappers/EventMapper.java rename src/main/java/ru/yandex/practicum/filmorate/dao/{ => mappers}/FilmMapper.java (88%) rename src/main/java/ru/yandex/practicum/filmorate/dao/{ => mappers}/UserMapper.java (96%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Event.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/enums/EventTypes.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/enums/OperationTypes.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 740c9a7..d4f249f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserService; @@ -76,6 +77,11 @@ public List getCommonFriends(@PathVariable int id, @PathVariable int other public List getRecommendedFilms(@PathVariable int id) { return userService.getRecommendedFilms(id); } + + @GetMapping("/{id}/feed") + public List getEvents(@PathVariable int id) { + return userService.getEvents(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index 30a4c29..a70145f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -4,6 +4,8 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.mappers.DirectorMapper; +import ru.yandex.practicum.filmorate.dao.mappers.FilmMapper; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.exceptions.ValidationException; import ru.yandex.practicum.filmorate.model.Director; @@ -12,7 +14,6 @@ import java.sql.PreparedStatement; import java.sql.Statement; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java new file mode 100644 index 0000000..73cbc3e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java @@ -0,0 +1,39 @@ +package ru.yandex.practicum.filmorate.dao; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.mappers.EventMapper; +import ru.yandex.practicum.filmorate.model.Event; +import ru.yandex.practicum.filmorate.model.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class EventDbStorage { + private final JdbcTemplate jdbcTemplate; +// @Autowired +// public EventDbStorage(JdbcTemplate jdbcTemplate) { +// this.jdbcTemplate = jdbcTemplate; +// } + + + public void saveEvent(long userId, EventTypes eventType, OperationTypes operation, long entityId) { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + jdbcTemplate.update("INSERT INTO events(TIMESTAMP, USERID, EVENTTYPE, OPERATION, ENTITYID) VALUES (?,?,?,?,?)", + timestamp.getTime() , userId, eventType.name(), operation.name(), entityId); + } + + public List getEvent(int id) { + return jdbcTemplate.queryForStream("SELECT * " + + "FROM EVENTS " + + "WHERE USERID = ?;", (rs, rowNum) -> + new EventMapper().mapRow(rs, rowNum), id).collect(Collectors.toList()); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 7d89391..09ecf78 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -1,9 +1,12 @@ package ru.yandex.practicum.filmorate.dao; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.mappers.DirectorMapper; +import ru.yandex.practicum.filmorate.dao.mappers.FilmMapper; import ru.yandex.practicum.filmorate.exceptions.GenreNotFoundException; import ru.yandex.practicum.filmorate.exceptions.MpaNotFoundException; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; @@ -12,6 +15,8 @@ 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.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.FilmStorage; import java.sql.ResultSet; @@ -20,24 +25,17 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.Optional; - - @Slf4j @Component("filmDBStorage") +@RequiredArgsConstructor public class FilmDbStorage implements FilmStorage { private static int filmId = 0; private final JdbcTemplate jdbcTemplate; private static final LocalDate FILM_START_DATE = LocalDate.of(1895, 12, 28); - - - public FilmDbStorage(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } + private final EventDbStorage eventDbStorage; private int generateFilmId() { return ++filmId; @@ -156,6 +154,7 @@ public Film likeFilm(int filmId, int userId) { checkFilmInDb(filmId); checkUserInDb(userId); jdbcTemplate.update("INSERT INTO likesList VALUES (?,?)", filmId, userId); + eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.ADD, filmId); return getFilmById(filmId); } @@ -164,6 +163,7 @@ public Film deleteLikeFromFilm(int filmId, int userId) { checkFilmInDb(filmId); checkUserInDb(userId); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=? AND userId=?", filmId, userId); + eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.REMOVE, filmId); return getFilmById(filmId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index 81852e2..fa7a585 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -1,12 +1,18 @@ package ru.yandex.practicum.filmorate.dao; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.mappers.FilmMapper; +import ru.yandex.practicum.filmorate.dao.mappers.UserMapper; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.model.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.UserStorage; import java.sql.ResultSet; @@ -17,14 +23,13 @@ @Slf4j @Component("userDBStorage") +@RequiredArgsConstructor public class UserDbStorage implements UserStorage { private static int userId = 0; private final JdbcTemplate jdbcTemplate; - - public UserDbStorage(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } + private final EventDbStorage eventDbStorage; + private final FilmMapper filmMapper; private int generateUserId() { return ++userId; @@ -94,6 +99,7 @@ public User deleteUserById(int userId) { @Override public void addFriend(int userId, int friendId) { if(checkUserInDb(userId)&&checkUserInDb(friendId)){ + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + "WHERE userId=?", friendId); @@ -107,16 +113,19 @@ public void addFriend(int userId, int friendId) { jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='apply'", Integer.class), friendId, userId); + //eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.UPDATE, friendId); }else{ jdbcTemplate.update("INSERT INTO friendship VALUES (?,?,?)", userId, friendId, jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class)); - } +// eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); + } } } @Override public User deleteFriend(int userId, int friendId) { + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.REMOVE, friendId); jdbcTemplate.update("DELETE FROM friendship WHERE userId=? AND friendId=?", userId, friendId); List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + @@ -128,6 +137,7 @@ public User deleteFriend(int userId, int friendId) { jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class), friendId, userId); + //eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.REMOVE, friendId); } return getUserById(friendId); } @@ -177,7 +187,7 @@ public List getRecommendedFilms(int id) { " (SELECT FILMID as userfilmlist from LIKESLIST where USERID = " + id +")) as Lr " + "ON f.FILMID = recommended"; - return jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, new FilmDbStorage(jdbcTemplate))); + return jdbcTemplate.query(sql, filmMapper); } private boolean checkUserInDb(Integer id){ @@ -211,4 +221,8 @@ private User makeUser(ResultSet rs) throws SQLException { return null; } } + @Override + public List getEvents(int id) { + return eventDbStorage.getEvent(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/DirectorMapper.java similarity index 90% rename from src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java rename to src/main/java/ru/yandex/practicum/filmorate/dao/mappers/DirectorMapper.java index bba397e..b163cdc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/DirectorMapper.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.dao; +package ru.yandex.practicum.filmorate.dao.mappers; import org.springframework.jdbc.core.RowMapper; import ru.yandex.practicum.filmorate.model.Director; diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/EventMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/EventMapper.java new file mode 100644 index 0000000..d71a770 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/EventMapper.java @@ -0,0 +1,22 @@ +package ru.yandex.practicum.filmorate.dao.mappers; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.Event; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class EventMapper implements RowMapper { + @Override + public Event mapRow(ResultSet rs, int rowNum) throws SQLException { + return Event.builder(). + timestamp(rs.getLong("timestamp")). + userId(rs.getInt("userId")). + eventType(rs.getString("eventType")). + operation(rs.getString("operation")). + eventId(rs.getInt("eventId")). + entityId(rs.getLong("entityId")). + build(); + } +} + diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java similarity index 88% rename from src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java rename to src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java index d0b0d04..3e54fd9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java @@ -1,10 +1,13 @@ -package ru.yandex.practicum.filmorate.dao; +package ru.yandex.practicum.filmorate.dao.mappers; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.storage.FilmStorage; @@ -14,16 +17,13 @@ import java.util.ArrayList; import java.util.List; +@Component +@RequiredArgsConstructor public class FilmMapper implements ResultSetExtractor> { private final JdbcTemplate jdbcTemplate; private final FilmStorage filmStorage; - public FilmMapper(JdbcTemplate jdbcTemplate, @Qualifier("filmDBStorage") FilmStorage filmStorage) { - this.jdbcTemplate = jdbcTemplate; - this.filmStorage = filmStorage; - } - public List extractData(ResultSet rs) throws SQLException, DataAccessException { List films = new ArrayList<>(); while (rs.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java similarity index 96% rename from src/main/java/ru/yandex/practicum/filmorate/dao/UserMapper.java rename to src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java index 0802f86..cedc8b6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.dao; +package ru.yandex.practicum.filmorate.dao.mappers; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index bec2caa..bb5ac2a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -8,8 +8,11 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.dao.EventDbStorage; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; @@ -27,6 +30,7 @@ public class ReviewDbStorage implements ReviewStorage { private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final JdbcTemplate jdbcTemplate; private final ReviewLikesStorage reviewLikesStorage; + private final EventDbStorage eventDbStorage; @Override public Review add(Review review) { @@ -37,18 +41,24 @@ public Review add(Review review) { SqlParameterSource parameterSource = getParameterSource(review); namedParameterJdbcTemplate.update(sql, parameterSource); reviewLikesStorage.add(review); + eventDbStorage.saveEvent(review.getUserId(), EventTypes.REVIEW, + OperationTypes.ADD, review.getReviewId()); return review; } @Override public Review update(Review review) { checkReviewById(review.getReviewId()); + Integer userId = jdbcTemplate.queryForObject("SELECT USERID FROM REVIEW WHERE REVIEW_ID = " + + review.getReviewId(), Integer.class); String sql = "UPDATE review SET content = :content, isPositive = :isPositive WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource() .addValue("id", review.getReviewId()) .addValue("content", review.getContent()) .addValue("isPositive", review.getIsPositive()); namedParameterJdbcTemplate.update(sql, parameterSource); + eventDbStorage.saveEvent(userId, EventTypes.REVIEW, + OperationTypes.UPDATE, review.getReviewId()); return getById(review.getReviewId()); } @@ -66,10 +76,13 @@ public Review updateUseful(Review review) { @Override public void delete(long reviewId) { checkReviewById(reviewId); + Review review = getById(reviewId); String sql = "DELETE FROM review WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); reviewLikesStorage.delete(reviewId); + eventDbStorage.saveEvent(Math.toIntExact(review.getUserId()), EventTypes.REVIEW, + OperationTypes.REMOVE, Math.toIntExact(review.getReviewId())); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Event.java b/src/main/java/ru/yandex/practicum/filmorate/model/Event.java new file mode 100644 index 0000000..d97a067 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Event.java @@ -0,0 +1,28 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.sql.Timestamp; + +@Getter +@Setter +@Builder +public class Event { + private long timestamp; + private int userId; + private String eventType; + private String operation; + private int eventId; + private long entityId; + + public Event(long timestamp, int userId, String eventType, String operation, int eventId, long entityId) { + this.timestamp = timestamp; + this.userId = userId; + this.eventType = eventType; + this.operation = operation; + this.eventId = eventId; + this.entityId = entityId; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/enums/EventTypes.java b/src/main/java/ru/yandex/practicum/filmorate/model/enums/EventTypes.java new file mode 100644 index 0000000..2a39dad --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/enums/EventTypes.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.model.enums; + +public enum EventTypes { + LIKE, + REVIEW, + FRIEND +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/enums/OperationTypes.java b/src/main/java/ru/yandex/practicum/filmorate/model/enums/OperationTypes.java new file mode 100644 index 0000000..44d5839 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/enums/OperationTypes.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.model.enums; + +public enum OperationTypes { + REMOVE, + ADD, + UPDATE +} 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 57a2c6e..ae48ed5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.service; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; @@ -17,4 +18,5 @@ public interface UserService { List getFriends(int id); List getCommonFriends(int userId, int otherId); List getRecommendedFilms(int id); + List getEvents(int id); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index f73a200..4e69c95 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exceptions.ValidationException; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.UserStorage; @@ -78,4 +79,9 @@ public List getCommonFriends(int userId, int otherId) { public List getRecommendedFilms(int id) { return userStorage.getRecommendedFilms(id); } + + @Override + public List getEvents(int id) { + return userStorage.getEvents(id); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java index afb11d9..da03ba9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.validators.UserValidator; @@ -81,4 +82,9 @@ public List getRecommendedFilms(int id) { return null; } + @Override + public List getEvents(int id) { + return null; + } + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index 64b9d26..cf6eaae 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.storage; +import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; @@ -16,6 +17,6 @@ public interface UserStorage { User deleteFriend(int userId, int friendId); List getFriends(int id); List getCommonFriends(int userId, int otherId); - List getRecommendedFilms(int id); + List getEvents(int id); } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 831d36a..4a0d3c0 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,13 +1,14 @@ -DELETE FROM directorFilm; -DELETE FROM directors; -DELETE FROM films; -DELETE FROM users; -DELETE FROM film_genre; +-- DELETE FROM directorFilm; +-- DELETE FROM directors; +-- DELETE FROM films; +-- DELETE FROM users; +-- DELETE FROM film_genre; DELETE FROM genre; -DELETE FROM likesList; -DELETE FROM friendship; +-- DELETE FROM likesList; +-- DELETE FROM friendship; DELETE FROM mpa; -DELETE FROM friendshipStatus; +-- DELETE FROM friendshipStatus; +-- DELETE FROM events; INSERT INTO genre (genreId, name) VALUES (1, 'Комедия'); INSERT INTO genre (genreId, name) VALUES (2, 'Драма'); INSERT INTO genre (genreId, name) VALUES (3, 'Мультфильм'); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index bd8d688..cff7f2b 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,3 +1,23 @@ +CREATE TABLE IF NOT EXISTS genre ( + genreId int PRIMARY KEY , + name varchar +); + +CREATE TABLE IF NOT EXISTS mpa ( + mpaId int, + name varchar +); + +CREATE TABLE IF NOT EXISTS friendshipStatus ( + friendshipStatusId int PRIMARY KEY , + description varchar +); + + +CREATE TABLE IF NOT EXISTS directors ( + directorId int NOT NULL AUTO_INCREMENT PRIMARY KEY, + directorName varchar +); CREATE TABLE IF NOT EXISTS films ( filmId INTEGER PRIMARY KEY, name varchar(200), @@ -16,34 +36,24 @@ CREATE TABLE IF NOT EXISTS users ( ); CREATE TABLE IF NOT EXISTS film_genre ( - filmId int, - genreId int + filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , + genreId int REFERENCES GENRE(genreId) ON DELETE CASCADE , + PRIMARY KEY (filmId, genreId) ); -CREATE TABLE IF NOT EXISTS genre ( - genreId int, - name varchar -); + CREATE TABLE IF NOT EXISTS likesList ( - filmId int, - userId int + filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , + userId int REFERENCES USERS(userId) ON DELETE CASCADE, + PRIMARY KEY (filmId, userId) ); CREATE TABLE IF NOT EXISTS friendship ( - userId int, - friendId int, - friendshipStatusId int -); - -CREATE TABLE IF NOT EXISTS mpa ( - mpaId int, - name varchar -); - -CREATE TABLE IF NOT EXISTS friendshipStatus ( - friendshipStatusId int, - description varchar + userId int REFERENCES USERS(userId) ON DELETE CASCADE , + friendId int REFERENCES USERS(userId) ON DELETE CASCADE , + friendshipStatusId int REFERENCES FRIENDSHIPSTATUS(friendshipStatusId), + PRIMARY KEY (userId, friendId) ); CREATE TABLE IF NOT EXISTS review ( @@ -62,15 +72,21 @@ CREATE TABLE IF NOT EXISTS review_likes ( isLike BOOLEAN NOT NULL ); -CREATE TABLE IF NOT EXISTS directors ( - directorId int NOT NULL AUTO_INCREMENT PRIMARY KEY, - directorName varchar - ); + CREATE TABLE IF NOT EXISTS directorFilm ( directorFilmId int NOT NULL AUTO_INCREMENT PRIMARY KEY, - filmId int, - directorId int, + filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , + directorId int REFERENCES DIRECTORS(DIRECTORID) ON DELETE CASCADE, CONSTRAINT filmDirectorFilm FOREIGN KEY (filmId) REFERENCES films (filmId), CONSTRAINT directorFilmDirector FOREIGN KEY (directorId) REFERENCES directors (directorId) ); + +CREATE TABLE IF NOT EXISTS events ( + timestamp long, + userId int REFERENCES USERS(userId) ON DELETE CASCADE , + eventType varchar(6), + operation varchar(6), + eventId int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + entityId long +); \ No newline at end of file From 25f8e0041a35f7f494f261b9c57330568673a371 Mon Sep 17 00:00:00 2001 From: mutaev Date: Wed, 22 Feb 2023 01:55:42 +0300 Subject: [PATCH 13/26] add-feed add user existence check add getting review user id before update --- .../yandex/practicum/filmorate/dao/EventDbStorage.java | 9 ++++----- .../practicum/filmorate/dao/review/ReviewDbStorage.java | 2 +- src/main/resources/data.sql | 4 ++-- src/main/resources/schema.sql | 2 ++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java index 73cbc3e..f2e5bf2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java @@ -1,10 +1,10 @@ package ru.yandex.practicum.filmorate.dao; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.dao.mappers.EventMapper; +import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.enums.EventTypes; import ru.yandex.practicum.filmorate.model.enums.OperationTypes; @@ -18,10 +18,6 @@ @RequiredArgsConstructor public class EventDbStorage { private final JdbcTemplate jdbcTemplate; -// @Autowired -// public EventDbStorage(JdbcTemplate jdbcTemplate) { -// this.jdbcTemplate = jdbcTemplate; -// } public void saveEvent(long userId, EventTypes eventType, OperationTypes operation, long entityId) { @@ -31,6 +27,9 @@ public void saveEvent(long userId, EventTypes eventType, OperationTypes operatio } public List getEvent(int id) { + if (!jdbcTemplate.queryForRowSet("SELECT USERID FROM USERS WHERE USERID =?", id).next()) { + throw new NotFoundObjectException("User with id " + id + " not found"); + } return jdbcTemplate.queryForStream("SELECT * " + "FROM EVENTS " + "WHERE USERID = ?;", (rs, rowNum) -> diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index bb5ac2a..2f960db 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -49,7 +49,7 @@ public Review add(Review review) { @Override public Review update(Review review) { checkReviewById(review.getReviewId()); - Integer userId = jdbcTemplate.queryForObject("SELECT USERID FROM REVIEW WHERE REVIEW_ID = " + Integer userId = jdbcTemplate.queryForObject("SELECT USER_ID FROM REVIEW WHERE REVIEW_ID = " + review.getReviewId(), Integer.class); String sql = "UPDATE review SET content = :content, isPositive = :isPositive WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource() diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 4a0d3c0..da588cb 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -3,10 +3,10 @@ -- DELETE FROM films; -- DELETE FROM users; -- DELETE FROM film_genre; -DELETE FROM genre; +-- DELETE FROM genre; -- DELETE FROM likesList; -- DELETE FROM friendship; -DELETE FROM mpa; +-- DELETE FROM mpa; -- DELETE FROM friendshipStatus; -- DELETE FROM events; INSERT INTO genre (genreId, name) VALUES (1, 'Комедия'); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index cff7f2b..e1adede 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,3 +1,5 @@ +DROP ALL OBJECTS DELETE FILES; + CREATE TABLE IF NOT EXISTS genre ( genreId int PRIMARY KEY , name varchar From 534f5a33b09aaa36907eca7a0b1e173400d7cf66 Mon Sep 17 00:00:00 2001 From: mutaev Date: Wed, 22 Feb 2023 02:23:39 +0300 Subject: [PATCH 14/26] add-feed replaced some constructors with lombok annotation simplified checkUserInDb method removed commented code some other small changes --- .../filmorate/dao/DirectorDbStorage.java | 6 ++-- .../filmorate/dao/UserDbStorage.java | 36 +++++++++---------- .../filmorate/dao/mappers/UserMapper.java | 12 +++---- .../practicum/filmorate/model/Director.java | 3 -- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index a70145f..94cff72 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.dao; +import lombok.RequiredArgsConstructor; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; @@ -19,13 +20,10 @@ import java.util.Set; @Component +@RequiredArgsConstructor public class DirectorDbStorage implements DirectorStorage { private final JdbcTemplate jdbcTemplate; private final FilmDbStorage filmDbStorage; - public DirectorDbStorage(JdbcTemplate jdbcTemplate, FilmDbStorage filmDbStorage) { - this.jdbcTemplate = jdbcTemplate; - this.filmDbStorage = filmDbStorage; - } @Override public List findAll() { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index fa7a585..0fb563c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -30,6 +30,7 @@ public class UserDbStorage implements UserStorage { private final JdbcTemplate jdbcTemplate; private final EventDbStorage eventDbStorage; private final FilmMapper filmMapper; + private final UserMapper userMapper; private int generateUserId() { return ++userId; @@ -38,7 +39,7 @@ private int generateUserId() { @Override public List getAllUsers() { String sql = "SELECT * FROM users"; - return jdbcTemplate.query(sql, new UserMapper(jdbcTemplate, this)); + return jdbcTemplate.query(sql, userMapper); } @Override @@ -99,7 +100,6 @@ public User deleteUserById(int userId) { @Override public void addFriend(int userId, int friendId) { if(checkUserInDb(userId)&&checkUserInDb(friendId)){ - eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + "WHERE userId=?", friendId); @@ -113,12 +113,12 @@ public void addFriend(int userId, int friendId) { jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='apply'", Integer.class), friendId, userId); - //eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.UPDATE, friendId); + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.UPDATE, friendId); }else{ jdbcTemplate.update("INSERT INTO friendship VALUES (?,?,?)", userId, friendId, jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class)); -// eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); } } } @@ -130,21 +130,22 @@ public User deleteFriend(int userId, int friendId) { List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + "WHERE userId=?", userId); + while(checkFriends.next()){ friends.add(checkFriends.getInt("friendId")); } + if(friends.contains(userId)){ jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class), friendId, userId); - //eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.REMOVE, friendId); } return getUserById(friendId); } @Override public List getFriends(int id) { - if(checkUserInDb(id)){ + if(checkUserInDb(id)) { List userFriends = new ArrayList<>(); SqlRowSet getFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship WHERE userId=?", id); @@ -152,7 +153,7 @@ public List getFriends(int id) { userFriends.add(getUserById(getFriends.getInt("friendId"))); } return userFriends; - }else{ + } else { return null; } } @@ -160,7 +161,7 @@ public List getFriends(int id) { @Override public List getCommonFriends(int userId, int otherId) { - if(checkUserInDb(userId)){ + if(checkUserInDb(userId)) { List userFriends = new ArrayList<>(); SqlRowSet getFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship WHERE userId=?", userId); @@ -168,7 +169,7 @@ public List getCommonFriends(int userId, int otherId) { userFriends.add(getUserById(getFriends.getInt("friendId"))); } return userFriends; - }else{ + } else { return null; } } @@ -190,18 +191,13 @@ public List getRecommendedFilms(int id) { return jdbcTemplate.query(sql, filmMapper); } - private boolean checkUserInDb(Integer id){ - String sql = "SELECT userId FROM users"; - SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql); - List ids = new ArrayList<>(); - while (getUsersFromDb.next()){ - ids.add(getUsersFromDb.getInt("userId")); - } - if(ids.contains(id)){ - return true; - }else{ - throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); + private boolean checkUserInDb(Integer id) { + String sql = "SELECT userId FROM users where USERID =?"; + SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql, id); + if (!getUsersFromDb.next()) { + throw new NotFoundObjectException("Пользователя с id" + id + " нет в базе!"); } + return true; } private User makeUser(ResultSet rs) throws SQLException { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java index cedc8b6..e44ede1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/UserMapper.java @@ -1,27 +1,23 @@ package ru.yandex.practicum.filmorate.dao.mappers; -import org.springframework.beans.factory.annotation.Qualifier; +import lombok.RequiredArgsConstructor; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.storage.UserStorage; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +@Component +@RequiredArgsConstructor public class UserMapper implements ResultSetExtractor> { private final JdbcTemplate jdbcTemplate; - private final UserStorage userStorage; - - public UserMapper(JdbcTemplate jdbcTemplate, @Qualifier("userDBStorage") UserStorage userStorage) { - this.jdbcTemplate = jdbcTemplate; - this.userStorage = userStorage; - } public List extractData(ResultSet rs) throws SQLException, DataAccessException { List users = new ArrayList<>(); 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 9fb3df8..23953ec 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Director.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Director.java @@ -2,14 +2,11 @@ import lombok.Data; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; import java.util.Set; @Data public class Director { private Integer id; - private String name; private Set films; } From 69fcb7b7ec1513e3720f015f514b1ff933a62f64 Mon Sep 17 00:00:00 2001 From: Ilusha92 Date: Wed, 22 Feb 2023 13:24:52 +0300 Subject: [PATCH 15/26] add search by title and director final ver --- .../filmorate/controller/FilmController.java | 6 +++ .../filmorate/dao/FilmDbStorage.java | 50 +++++++++++++++++++ .../practicum/filmorate/model/Film.java | 2 +- .../filmorate/service/FilmService.java | 2 +- .../filmorate/service/FilmServiceManager.java | 9 ++++ .../filmorate/storage/FilmStorage.java | 1 + .../storage/InMemoryFilmStorage.java | 5 ++ 7 files changed, 73 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 de855e8..5961d51 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -79,5 +79,11 @@ public List getFilmsByDirectorId (@PathVariable Integer directorId, @RequestParam (value = "sortBy")String param) { return directorService.getFilmsSortedByLikesOrYear(directorId, param); } + + @GetMapping("/search") + public List searchFilms(@RequestParam String query, + @RequestParam List by) { + return filmService.searchFilms(query, by); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 09ecf78..36cb4e8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -317,4 +317,54 @@ private List getDirectorByFilmId (Integer filmId) { return jdbcTemplate.query(statement, new DirectorMapper(), filmId); } + public List searchFilms(String query1, List by) { + List films1 = new ArrayList<>(); + if (by.size() == 1) { + if (by.get(0).toLowerCase().equals("title")) { + SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByTitle.next()) { + Film film = new Film(searchByTitle.getString("name"), + searchByTitle.getString("description"), + searchByTitle.getDate("release_date").toLocalDate(), + searchByTitle.getInt("duration")); + film.setId(searchByTitle.getInt("filmId")); + film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); + films1.add(film); + } + } + if (by.get(0).toLowerCase().equals("director")) { + SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( + "SELECT df.* FROM directorFilm as df " + + "INNER JOIN directors as d ON df.directorId = d.directorId " + + "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByDirector.next()) { + Integer filmId1 = searchByDirector.getInt("filmId"); + films1.add(getFilmById(filmId1)); + } + } + } + if (by.size() == 2) { + SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByTitle.next()) { + Film film = new Film(searchByTitle.getString("name"), + searchByTitle.getString("description"), + searchByTitle.getDate("release_date").toLocalDate(), + searchByTitle.getInt("duration")); + film.setId(searchByTitle.getInt("filmId")); + film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); + films1.add(film); + } + SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( + "SELECT df.* FROM directorFilm as df " + + "INNER JOIN directors as d ON df.directorId = d.directorId " + + "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByDirector.next()) { + Integer filmId1 = searchByDirector.getInt("filmId"); + films1.add(getFilmById(filmId1)); + } + + } + return films1; + } + } 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 2060588..f050006 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -27,7 +27,7 @@ public class Film { private Set likes = new LinkedHashSet<>(); private Set genres = new LinkedHashSet<>(); private Mpa mpa; - private Set directors; + private Set directors= new LinkedHashSet<>(); public Film(String name, String description, LocalDate releaseDate, int duration) { this.name = name; 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 c3ad366..a297069 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -20,6 +20,6 @@ public interface FilmService { Genre getGenreById(int id); List getAllMpa(); Mpa getMpaById(int id); - + List searchFilms(String query, List by); List getCommonFilms(int userId, int friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index a82334d..f3384a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -91,4 +91,13 @@ public Mpa getMpaById(int id) { return filmStorage.getMpaById(id); } + @Override + public List searchFilms(String query, List by) { + + List resultList = filmStorage.searchFilms(query, by); + resultList.sort(Comparator.comparingInt(Film::getLikesCount).reversed()); + return resultList; + + } + } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index c46b646..ced89e4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -20,4 +20,5 @@ public interface FilmStorage { List getAllMpa(); Mpa getMpaById(int id); List getCommonFilms(int userId, int friendId); + List searchFilms(String query, List by); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java index 679373a..628ec2c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -106,4 +106,9 @@ public List getCommonFilms(int userId, int friendId) { return null; } + @Override + public List searchFilms(String query, List by){ + return null; + } + } \ No newline at end of file From 0fa59a062a987b932b2f47c3604c75a8633ea2a0 Mon Sep 17 00:00:00 2001 From: Ilusha92 Date: Wed, 22 Feb 2023 15:46:08 +0300 Subject: [PATCH 16/26] =?UTF-8?q?=D0=B4=D0=B5=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit all tests ok --- .../filmorate/controller/FilmController.java | 6 +- .../filmorate/dao/FilmDbStorage.java | 65 ++++++++----------- 2 files changed, 32 insertions(+), 39 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 5961d51..a62b7dd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -9,6 +9,8 @@ import ru.yandex.practicum.filmorate.service.FilmService; import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.util.Collection; import java.util.List; @@ -81,8 +83,8 @@ public List getFilmsByDirectorId (@PathVariable Integer directorId, } @GetMapping("/search") - public List searchFilms(@RequestParam String query, - @RequestParam List by) { + public List searchFilms(@RequestParam @NotNull @NotBlank String query, + @RequestParam @NotNull @NotBlank List by) { return filmService.searchFilms(query, by); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 36cb4e8..1fd01ee 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -35,6 +35,7 @@ public class FilmDbStorage implements FilmStorage { private static int filmId = 0; private final JdbcTemplate jdbcTemplate; private static final LocalDate FILM_START_DATE = LocalDate.of(1895, 12, 28); + //private static final String SEARCH_BY_TITLE = "SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))"; private final EventDbStorage eventDbStorage; private int generateFilmId() { @@ -321,50 +322,40 @@ public List searchFilms(String query1, List by) { List films1 = new ArrayList<>(); if (by.size() == 1) { if (by.get(0).toLowerCase().equals("title")) { - SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); - while (searchByTitle.next()) { - Film film = new Film(searchByTitle.getString("name"), - searchByTitle.getString("description"), - searchByTitle.getDate("release_date").toLocalDate(), - searchByTitle.getInt("duration")); - film.setId(searchByTitle.getInt("filmId")); - film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); - films1.add(film); + searchByTitle(query1, films1); } - } if (by.get(0).toLowerCase().equals("director")) { - SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( - "SELECT df.* FROM directorFilm as df " + - "INNER JOIN directors as d ON df.directorId = d.directorId " + - "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); - while (searchByDirector.next()) { - Integer filmId1 = searchByDirector.getInt("filmId"); - films1.add(getFilmById(filmId1)); - } + searchByDirector(query1, films1); } } if (by.size() == 2) { - SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); - while (searchByTitle.next()) { - Film film = new Film(searchByTitle.getString("name"), - searchByTitle.getString("description"), - searchByTitle.getDate("release_date").toLocalDate(), - searchByTitle.getInt("duration")); - film.setId(searchByTitle.getInt("filmId")); - film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); - films1.add(film); - } - SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( - "SELECT df.* FROM directorFilm as df " + - "INNER JOIN directors as d ON df.directorId = d.directorId " + - "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); - while (searchByDirector.next()) { - Integer filmId1 = searchByDirector.getInt("filmId"); - films1.add(getFilmById(filmId1)); - } - + searchByTitle(query1, films1); + searchByDirector(query1, films1); } return films1; } + private void searchByTitle(String query1, List films1) { + SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByTitle.next()) { + Film film = new Film(searchByTitle.getString("name"), + searchByTitle.getString("description"), + searchByTitle.getDate("release_date").toLocalDate(), + searchByTitle.getInt("duration")); + film.setId(searchByTitle.getInt("filmId")); + film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); + films1.add(film); + } + } + + private void searchByDirector(String query1, List films1) { + SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( + "SELECT df.* FROM directorFilm as df " + + "INNER JOIN directors as d ON df.directorId = d.directorId " + + "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); + while (searchByDirector.next()) { + Integer filmId1 = searchByDirector.getInt("filmId"); + films1.add(getFilmById(filmId1)); + } + } } From d609e78d3e2c86c6e2985685539c756e32d7b22b Mon Sep 17 00:00:00 2001 From: Ilusha92 Date: Wed, 22 Feb 2023 16:06:27 +0300 Subject: [PATCH 17/26] restructed schema all develop tests ok --- src/main/resources/schema.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index e1adede..ce234ff 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -47,8 +47,7 @@ CREATE TABLE IF NOT EXISTS film_genre ( CREATE TABLE IF NOT EXISTS likesList ( filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , - userId int REFERENCES USERS(userId) ON DELETE CASCADE, - PRIMARY KEY (filmId, userId) + userId int REFERENCES USERS(userId) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS friendship ( From b41ed3432ac71d60d8aabde876ab87f8aa3a811e Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Fri, 24 Feb 2023 00:16:07 +0300 Subject: [PATCH 18/26] =?UTF-8?q?fix:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B8=20=D0=B2=D0=B7=D0=B0=D0=B8=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D1=8F=20review=20&?= =?UTF-8?q?=20event=20dao=20=D0=B2=20ReviewService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/review/ReviewDbStorage.java | 42 +++-------------- .../service/review/ReviewServiceImpl.java | 45 ++++++++++++++++--- src/main/resources/schema.sql | 5 +-- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index 2f960db..bc9792d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -8,18 +8,13 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.dao.EventDbStorage; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Review; -import ru.yandex.practicum.filmorate.model.enums.EventTypes; -import ru.yandex.practicum.filmorate.model.enums.OperationTypes; -import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; @Repository("reviewDbStorage") @@ -29,8 +24,6 @@ public class ReviewDbStorage implements ReviewStorage { private static long REVIEW_ID; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final JdbcTemplate jdbcTemplate; - private final ReviewLikesStorage reviewLikesStorage; - private final EventDbStorage eventDbStorage; @Override public Review add(Review review) { @@ -40,25 +33,18 @@ public Review add(Review review) { "VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; SqlParameterSource parameterSource = getParameterSource(review); namedParameterJdbcTemplate.update(sql, parameterSource); - reviewLikesStorage.add(review); - eventDbStorage.saveEvent(review.getUserId(), EventTypes.REVIEW, - OperationTypes.ADD, review.getReviewId()); return review; } @Override public Review update(Review review) { checkReviewById(review.getReviewId()); - Integer userId = jdbcTemplate.queryForObject("SELECT USER_ID FROM REVIEW WHERE REVIEW_ID = " - + review.getReviewId(), Integer.class); String sql = "UPDATE review SET content = :content, isPositive = :isPositive WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource() .addValue("id", review.getReviewId()) .addValue("content", review.getContent()) .addValue("isPositive", review.getIsPositive()); namedParameterJdbcTemplate.update(sql, parameterSource); - eventDbStorage.saveEvent(userId, EventTypes.REVIEW, - OperationTypes.UPDATE, review.getReviewId()); return getById(review.getReviewId()); } @@ -69,7 +55,6 @@ public Review updateUseful(Review review) { .addValue("useful", review.getUseful()) .addValue("id", review.getReviewId()); namedParameterJdbcTemplate.update(sql, parameterSource); - reviewLikesStorage.update(review); return getById(review.getReviewId()); } @@ -80,19 +65,13 @@ public void delete(long reviewId) { String sql = "DELETE FROM review WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); - reviewLikesStorage.delete(reviewId); - eventDbStorage.saveEvent(Math.toIntExact(review.getUserId()), EventTypes.REVIEW, - OperationTypes.REMOVE, Math.toIntExact(review.getReviewId())); } @Override public Review getById(long reviewId) { if (reviewId <= 0) throw new NotFoundObjectException("Такого отзыва не существует."); String sql = "SELECT * FROM review WHERE review_id = ?"; - Review review = jdbcTemplate.queryForObject(sql, this::getRowMapper, reviewId); - - review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getReviewId())); - return review; + return jdbcTemplate.queryForObject(sql, this::getRowMapper, reviewId); } @Override @@ -102,27 +81,16 @@ public List getAllReviewsByFilmId(long filmId, int limit) { SqlParameterSource parameterSource = new MapSqlParameterSource() .addValue("filmId", filmId) .addValue("limit", limit); - return readReviews(sql, parameterSource); + return namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper) + .collect(Collectors.toList()); } + @Override public List getAllReviews() { String sql = "SELECT * FROM review ORDER BY useful DESC"; SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(Review.class); - return readReviews(sql, parameterSource); - } - - private List readReviews(String sql, SqlParameterSource parameterSource) { - List reviews = namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper) + return namedParameterJdbcTemplate.queryForStream(sql, parameterSource, this::getRowMapper) .collect(Collectors.toList()); - if (reviews.size() > 0) { - Map reviewsLikes = reviewLikesStorage.getAllReviewLikes(); - if (reviewsLikes.size() > 0) { - reviews.forEach(review -> reviewsLikes.forEach((userId, like) -> { - if (review.getUserId().equals(userId)) review.getLikes().put(userId, like); - })); - } - } - return reviews; } private Review getRowMapper(ResultSet rs, int rowNum) throws SQLException { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java index 4433a06..c4982a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/review/ReviewServiceImpl.java @@ -2,7 +2,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.EventDbStorage; import ru.yandex.practicum.filmorate.model.Review; +import ru.yandex.practicum.filmorate.model.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; +import ru.yandex.practicum.filmorate.storage.review.ReviewLikesStorage; import ru.yandex.practicum.filmorate.storage.review.ReviewStorage; import javax.validation.ValidationException; @@ -14,35 +18,51 @@ @RequiredArgsConstructor public class ReviewServiceImpl implements ReviewService { private final ReviewStorage reviewStorage; + private final ReviewLikesStorage reviewLikesStorage; + private final EventDbStorage eventDbStorage; @Override public Review add(Review review) { - return reviewStorage.add(review); + review = reviewStorage.add(review); + reviewLikesStorage.add(review); + eventDbStorage.saveEvent(review.getUserId(), EventTypes.REVIEW, + OperationTypes.ADD, review.getReviewId()); + return review; } @Override public Review update(Review review) { - return reviewStorage.update(review); + review = reviewStorage.update(review); + eventDbStorage.saveEvent(review.getUserId(), EventTypes.REVIEW, + OperationTypes.UPDATE, review.getReviewId()); + return review; } @Override public void delete(long reviewId) { reviewStorage.delete(reviewId); + reviewLikesStorage.delete(reviewId); + eventDbStorage.saveEvent(Math.toIntExact(reviewId), EventTypes.REVIEW, + OperationTypes.REMOVE, Math.toIntExact(reviewId)); } @Override public Review getById(long reviewId) { - return reviewStorage.getById(reviewId); + Review review = reviewStorage.getById(reviewId); + review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getReviewId())); + return review; } @Override public List getAllReviewsByFilmId(long filmId, int limit) { - return reviewStorage.getAllReviewsByFilmId(filmId, limit); + List reviews = reviewStorage.getAllReviewsByFilmId(filmId, limit); + return getReviewWithLikes(reviews); } @Override public List getAllReviews() { - return reviewStorage.getAllReviews(); + List reviews = reviewStorage.getAllReviews(); + return getReviewWithLikes(reviews); } @Override @@ -112,6 +132,19 @@ private void setNewUseful(Review review) { private void updateReviewLikes(Review review, Map reviewLikes) { review.getLikes().putAll(reviewLikes); setNewUseful(review); - reviewStorage.updateUseful(review); + review = reviewStorage.updateUseful(review); + reviewLikesStorage.update(review); + } + + private List getReviewWithLikes(List reviews) { + if (reviews.size() > 0) { + Map reviewsLikes = reviewLikesStorage.getAllReviewLikes(); + if (reviewsLikes.size() > 0) { + reviews.forEach(review -> reviewsLikes.forEach((userId, like) -> { + if (review.getUserId().equals(userId)) review.getLikes().put(userId, like); + })); + } + } + return reviews; } } \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index e1adede..81707d3 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -46,9 +46,8 @@ CREATE TABLE IF NOT EXISTS film_genre ( CREATE TABLE IF NOT EXISTS likesList ( - filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , - userId int REFERENCES USERS(userId) ON DELETE CASCADE, - PRIMARY KEY (filmId, userId) + filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE, + userId int REFERENCES USERS(userId) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS friendship ( From 22af13663401d437eb0a32fa204abbf39ba08f6f Mon Sep 17 00:00:00 2001 From: Alexandr Nazyan Date: Fri, 24 Feb 2023 01:47:45 +0300 Subject: [PATCH 19/26] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DirectorController.java | 7 +++++ .../filmorate/controller/FilmController.java | 14 +++++---- .../filmorate/controller/GenreController.java | 2 ++ .../filmorate/controller/MpaController.java | 2 ++ .../controller/ReviewController.java | 21 ++++--------- .../filmorate/controller/UserController.java | 5 +++- .../filmorate/dao/DirectorDbStorage.java | 8 ++++- .../filmorate/dao/EventDbStorage.java | 5 ++++ .../filmorate/dao/FilmDbStorage.java | 30 +++++++++++-------- .../filmorate/dao/UserDbStorage.java | 17 +++++++---- .../filmorate/dao/review/ReviewDbStorage.java | 6 ++++ .../dao/review/ReviewLikesDbStorage.java | 22 +++++++++----- .../service/DirectorServiceManager.java | 1 - .../filmorate/service/FilmServiceManager.java | 3 -- 14 files changed, 91 insertions(+), 52 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 bd294da..cce7d82 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.controller; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -12,6 +13,7 @@ @RestController @RequestMapping ("directors") +@Slf4j public class DirectorController { private DirectorService directorService; @@ -22,12 +24,14 @@ public DirectorController(DirectorService directorService) { @GetMapping public ResponseEntity> getAll () { + log.info("Получен запрос на список директоров"); List directorList = directorService.getAll(); return new ResponseEntity<>(directorList, HttpStatus.OK); } @GetMapping ("{id}") public ResponseEntity getById (@PathVariable Integer id) { + log.info("Получен запрос на директора по id " + id); Director director = directorService.getById(id); return new ResponseEntity<>(director, HttpStatus.OK); } @@ -36,6 +40,7 @@ public ResponseEntity getById (@PathVariable Integer id) { @PostMapping public ResponseEntity create (@RequestBody Director director) { + log.info("Получен запрос на создание директора"); Director createdDirector = directorService.create(director); return new ResponseEntity<>(createdDirector, HttpStatus.OK); } @@ -43,12 +48,14 @@ public ResponseEntity create (@RequestBody Director director) { @PutMapping public ResponseEntity update (@RequestBody Director director) { + log.info("Получен запрос на обновление директора с id " + director.getId()); Director updatedDirector = directorService.update(director); return new ResponseEntity<>(updatedDirector, HttpStatus.OK); } @DeleteMapping ("{id}") public ResponseEntity delete (@PathVariable Integer id) { + log.info("Получен запрос на удаление директора с id " + id); Director director = directorService.delete(id); return new ResponseEntity<>(director, HttpStatus.OK); } 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 a62b7dd..f3f6ffd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -35,6 +35,7 @@ public Collection getAllFilms() { @GetMapping("/{id}") public Film getFilm(@PathVariable int id) { + log.info("Get Film {}", id); return filmService.getFilmById(id); } @@ -59,32 +60,33 @@ public void deleteFilm(@PathVariable int id) { @GetMapping("/popular") public List getPopularFilms(@RequestParam(defaultValue = "10") int count) { + log.info("Получен запрос на список популярных фильмов"); return filmService.getPopularFilms(count); } @PutMapping("/{id}/like/{userId}") - public Film likeFilm( - @PathVariable int id, - @PathVariable int userId) { + public Film likeFilm(@PathVariable int id, @PathVariable int userId) { + log.info("Получен запрос на добавление лайка фильму id " + id + " юзером " + userId); return filmService.likeFilm(id, userId); } @DeleteMapping("/{id}/like/{userId}") - public Film deleteLikeFromFilm( - @PathVariable int id, - @PathVariable int userId) { + public Film deleteLikeFromFilm(@PathVariable int id, @PathVariable int userId) { + log.info("Получен запрос на удаление лайка фильму id " + id + " юзером " + userId); return filmService.deleteLikeFromFilm(id, userId); } @GetMapping ("director/{directorId}") public List getFilmsByDirectorId (@PathVariable Integer directorId, @RequestParam (value = "sortBy")String param) { + log.info("Получен запрос на получение"); return directorService.getFilmsSortedByLikesOrYear(directorId, param); } @GetMapping("/search") public List searchFilms(@RequestParam @NotNull @NotBlank String query, @RequestParam @NotNull @NotBlank List by) { + log.info("Получен запрос на поиск фильмов"); return filmService.searchFilms(query, by); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java index a232dd9..ea15fec 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -22,11 +22,13 @@ public GenreController(FilmService filmService) { @GetMapping public List getAllGenres(){ + log.info("Получен запрос на получение списка жанров"); return filmService.getAllGenres(); } @GetMapping("/{id}") public Genre getGenreById(@PathVariable("id") int id){ + log.info("Получен запрос на получение жанра по id " + id); return filmService.getGenreById(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java index 42ce986..d8f4367 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -22,12 +22,14 @@ public MpaController(FilmService filmService) { @GetMapping public List getAllMpa(){ + log.info("Получен запрос на получение списка Mpa"); return filmService.getAllMpa(); } @GetMapping("/{id}") public Mpa getMpaById(@PathVariable("id") int id){ + log.info("Получен запрос на получение Mpa по id " + id); return filmService.getMpaById(id); } } \ No newline at end of file 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 38ebb37..fd8d3ab 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java @@ -45,9 +45,8 @@ public void deleteReview(@PathVariable("id") long reviewId) { } @GetMapping - public List getReviewsByFilmId( - @RequestParam(required = false) Long filmId, - @RequestParam(defaultValue = "10") Integer count) { + public List getReviewsByFilmId(@RequestParam(required = false) Long filmId, + @RequestParam(defaultValue = "10") Integer count) { List reviews; if (filmId == null) { reviews = service.getAllReviews(); @@ -60,9 +59,7 @@ public List getReviewsByFilmId( } @PutMapping("/{id}/like/{userId}") - public Review addLike( - @PathVariable("id") Long reviewId, - @PathVariable Long userId) { + public Review addLike(@PathVariable("id") Long reviewId, @PathVariable Long userId) { Review review = service.addLike(reviewId, userId); log.info("Лайк отзыв с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", reviewId, userId, review.getUseful()); @@ -70,9 +67,7 @@ public Review addLike( } @PutMapping("/{id}/dislike/{userId}") - public Review addDislike( - @PathVariable("id") Long reviewId, - @PathVariable Long userId) { + public Review addDislike(@PathVariable("id") Long reviewId, @PathVariable Long userId) { Review review = service.addDislike(reviewId, userId); log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} добавлен. Количество лайков отзыва {}", reviewId, userId, review.getUseful()); @@ -80,9 +75,7 @@ public Review addDislike( } @DeleteMapping("/{id}/like/{userId}") - public Review deleteLike( - @PathVariable("id") Long reviewId, - @PathVariable Long userId) { + public Review deleteLike(@PathVariable("id") Long reviewId, @PathVariable Long userId) { Review review = service.deleteLike(reviewId, userId); log.info("Лайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", reviewId, userId, review.getUseful()); @@ -90,9 +83,7 @@ public Review deleteLike( } @DeleteMapping("/{id}/dislike/{userId}") - public Review deleteDislike( - @PathVariable("id") Long reviewId, - @PathVariable Long userId) { + public Review deleteDislike(@PathVariable("id") Long reviewId, @PathVariable Long userId) { Review review = service.deleteDislike(reviewId, userId); log.info("Дизлайк отзыва с ID #{} пользователя c ID #{} удален. Количество лайков отзыва {}", reviewId, userId, review.getUseful()); 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 d4f249f..239fd5a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -52,7 +52,6 @@ public void deleteUserById(@PathVariable int id) { @PutMapping("/{id}/friends/{friendId}") public void addFriend(@PathVariable("id") Integer id, @PathVariable("friendId") Integer friendId) { - log.info("Friends list" + userService.getById(id) + " added " + userService.getById(friendId)); userService.addFriend(id, friendId); } @@ -65,21 +64,25 @@ public User deleteFriend(@PathVariable int id, @PathVariable int friendId) { @GetMapping("/{id}/friends") public List getFriends(@PathVariable int id) { + log.info("Получен запрос на получение список друзей юзера с id " + id); return userService.getFriends(id); } @GetMapping("/{id}/friends/common/{otherId}") public List getCommonFriends(@PathVariable int id, @PathVariable int otherId) { + log.info("Получен запрос на получение списка общих друзей пользователя id " + id); return userService.getCommonFriends(id, otherId); } @GetMapping("/{id}/recommendations") public List getRecommendedFilms(@PathVariable int id) { + log.info("Получен запрос на получение"); return userService.getRecommendedFilms(id); } @GetMapping("/{id}/feed") public List getEvents(@PathVariable int id) { + log.info("Получен запрос на получение списка событий пользователя с id " + id); return userService.getEvents(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index 94cff72..12afff6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; @@ -21,6 +22,7 @@ @Component @RequiredArgsConstructor +@Slf4j public class DirectorDbStorage implements DirectorStorage { private final JdbcTemplate jdbcTemplate; private final FilmDbStorage filmDbStorage; @@ -30,12 +32,14 @@ public List findAll() { String statement = "SELECT * FROM directors"; List directors = jdbcTemplate.query(statement, new DirectorMapper()); directors.forEach(director -> director.setFilms(new HashSet<>(findFilmsByDirectorId(director.getId())))); + log.info("Список директоров отправлен"); return directors; } @Override public Director create(Director director) { if(director.getName() == null || director.getName().isBlank()) { + log.warn("Имя директора отсутствует"); throw new ValidationException("Name is required"); } String statement = "INSERT INTO directors (directorName) VALUES (?)"; @@ -58,6 +62,7 @@ public Director create(Director director) { @Override public Director update(Director director) { if (director.getId() == null) { + log.warn("Обьект директора = null"); throw new NotFoundObjectException("Director id is null"); } if (! isExists(director.getId())) { @@ -71,6 +76,7 @@ public Director update(Director director) { if (director.getFilms() != null) { updateFilmsForDirector(director.getId(), director.getFilms()); } + return findById(director.getId()); } @@ -124,7 +130,7 @@ private void updateFilmsForDirector (Integer directorId, Set films) { } } - public boolean isExists(Integer id) { + private boolean isExists(Integer id) { String s = "SELECT COUNT(*) FROM directors WHERE directorId=?"; Long obj = jdbcTemplate.queryForObject(s, Long.class, id); if (obj != null) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java index f2e5bf2..ec70ce6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.dao; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.dao.mappers.EventMapper; @@ -16,6 +17,7 @@ @Component @RequiredArgsConstructor +@Slf4j public class EventDbStorage { private final JdbcTemplate jdbcTemplate; @@ -24,12 +26,15 @@ public void saveEvent(long userId, EventTypes eventType, OperationTypes operatio Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); jdbcTemplate.update("INSERT INTO events(TIMESTAMP, USERID, EVENTTYPE, OPERATION, ENTITYID) VALUES (?,?,?,?,?)", timestamp.getTime() , userId, eventType.name(), operation.name(), entityId); + log.info("Событие для пользователя " + userId + " сохранено"); } public List getEvent(int id) { if (!jdbcTemplate.queryForRowSet("SELECT USERID FROM USERS WHERE USERID =?", id).next()) { + log.warn("Пользователь " + id + " не найден"); throw new NotFoundObjectException("User with id " + id + " not found"); } + log.info("Список событий для пользователя " + id + " отправлен"); return jdbcTemplate.queryForStream("SELECT * " + "FROM EVENTS " + "WHERE USERID = ?;", (rs, rowNum) -> diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 1fd01ee..d045815 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -48,6 +48,7 @@ public List getAllFilms() { if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); } + log.info("Список всех фильмов отправлен"); return films; } @@ -60,7 +61,7 @@ public List getCommonFilms(int userId, int friendId) { "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) as common " + "ON f.FILMID = common.FI " + "WHERE (AU = " + userId + " AND BU = " + friendId + ")"; - + log.info("Список общих фильмов между пользователями " + userId + " и " + friendId + " отправлен"); return jdbcTemplate.query(sql2, new FilmMapper(jdbcTemplate, this)); } @@ -69,19 +70,19 @@ public Film getFilmById(int id) { String sql = "SELECT * FROM films WHERE filmId="+id; if (checkFilmInDb(id)){ Film film = jdbcTemplate.query(sql, this::makeFilm); - if (film != null) { film.setDirectors(new HashSet<>(getDirectorByFilmId(id))); - } + log.info("Фильм с id " + id + " отправлен"); return film; } else { - return null; + log.warn("Фильм с id " + id + " не ннайден"); + throw new NotFoundObjectException("Фильм с id " + id + " не ннайден"); } } @Override public Film createFilm(Film film) { if (film.getReleaseDate().isBefore(FILM_START_DATE)) { - log.info("Не пройдена валидация даты выпуска фильма. Так рано фильмы не снимали!"); + log.warn("Не пройдена валидация даты выпуска фильма. Так рано фильмы не снимали!"); throw new ValidationException("Так рано фильмы не снимали!"); } else { film.setId(generateFilmId()); @@ -105,6 +106,7 @@ public Film createFilm(Film film) { film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); } } + log.info("Фильм с id " + film.getId() + " сохранен"); return getFilmById(film.getId()); } @@ -133,6 +135,7 @@ public Film updateFilm(Film film) { film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); } } + log.info("Фильм с id " + film.getId() + " обновлен"); return getFilmById(film.getId()); } @@ -145,7 +148,7 @@ public void deleteFilmById(int filmId) { log.info("Фильм с filmId " + filmId + " был удален."); jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", filmId); } else { - log.info("Фильм с filmId " + filmId + " не был удален."); + log.warn("Фильм с filmId " + filmId + " не был удален."); throw new NotFoundObjectException("Фильм с filmId " + filmId + " не был удален."); } } @@ -156,6 +159,7 @@ public Film likeFilm(int filmId, int userId) { checkUserInDb(userId); jdbcTemplate.update("INSERT INTO likesList VALUES (?,?)", filmId, userId); eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.ADD, filmId); + log.info("Лайк для фильма " + filmId + " пользователем" + userId + " добавлен"); return getFilmById(filmId); } @@ -165,6 +169,7 @@ public Film deleteLikeFromFilm(int filmId, int userId) { checkUserInDb(userId); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=? AND userId=?", filmId, userId); eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.REMOVE, filmId); + log.info("Лайк для фильма " + filmId + " пользователем" + userId + " удален"); return getFilmById(filmId); } @@ -176,6 +181,7 @@ public List getPopularFilms(int count) { if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); } + log.info("Список популярных фильмов длинной " + count + " отправлен"); return films; } @@ -187,6 +193,7 @@ public List getAllGenres() { Genre genre = new Genre(allGenres.getInt("genreId"), allGenres.getString("name")); genres.add(genre); } + log.info("Список всех жанров отправлен"); return genres; } @@ -200,8 +207,8 @@ public Genre getGenreById(int id) { log.info("Жанр с id={}, это {}.", genre.getId(), genre.getName()); return genre; } else { - log.info("Жанра с таким id нет!"); - return null; + log.warn("Жанра с id " + id+ " нет!"); + throw new NotFoundObjectException("Жанра с id " + id+ " нет!"); } } @@ -213,6 +220,7 @@ public List getAllMpa() { Mpa mpa = new Mpa(allMpas.getInt("mpaId"), allMpas.getString("name")); mpas.add(mpa); } + log.info("Список всех рейтингов отправлен"); return mpas; } @@ -224,7 +232,6 @@ public Mpa getMpaById(int id) { log.info("Рейтинг с id={}, это {}.", mpa.getId(), mpa.getName()); return mpa; } else { - log.info("Рейтинга с таким id нет!"); return null; } } @@ -239,6 +246,7 @@ private boolean checkMpaInDb(int id) { if (ids.contains(id)) { return true; } else { + log.warn("Рейтинга с id " + id + "нет!"); throw new MpaNotFoundException("Рейтинга с таким id нет в базе!"); } } @@ -279,7 +287,6 @@ private Film makeFilm(ResultSet rs) throws SQLException { } else { return null; } - } private boolean checkGenreInDb(Integer id) { @@ -308,9 +315,8 @@ private boolean checkUserInDb(Integer id) { } else { throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); } - - } + private List getDirectorByFilmId (Integer filmId) { String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName " + "FROM directorFilm LEFT JOIN directors " + diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index 0fb563c..2396f2f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -39,6 +39,7 @@ private int generateUserId() { @Override public List getAllUsers() { String sql = "SELECT * FROM users"; + log.info("Список всех пользователей отправлен"); return jdbcTemplate.query(sql, userMapper); } @@ -46,6 +47,7 @@ public List getAllUsers() { public User getUserById(int id) { if(checkUserInDb(id)){ String sql = "SELECT * FROM users WHERE userId="+id; + log.info("Пользоветель с id " + id + " отправлен"); return jdbcTemplate.query(sql, this::makeUser); }else{ return null; @@ -65,6 +67,7 @@ public User createUser(User user) { user.getLogin(), user.getName(), user.getBirthday()); + log.info("Пользователь с id " + user.getId() + " сохранен"); return user; } @@ -78,6 +81,7 @@ public User updateUser(User user) { user.getBirthday(), user.getId()); } + log.info("Пользователь с id " + user.getId() + " изменен"); return user; } @@ -114,12 +118,14 @@ public void addFriend(int userId, int friendId) { jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='apply'", Integer.class), friendId, userId); eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.UPDATE, friendId); + log.info("Дружба медлу пользователями " + friendId + " и " + friendId + " сохранена"); }else{ jdbcTemplate.update("INSERT INTO friendship VALUES (?,?,?)", userId, friendId, jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class)); eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); - } + log.info("Дружба медлу пользователями " + friendId + " и " + friendId + " сохранена"); + } } } @@ -130,11 +136,10 @@ public User deleteFriend(int userId, int friendId) { List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + "WHERE userId=?", userId); - + log.info("Дружба медлу пользователями " + friendId + " и " + friendId + " удалена"); while(checkFriends.next()){ friends.add(checkFriends.getInt("friendId")); } - if(friends.contains(userId)){ jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", @@ -152,6 +157,7 @@ public List getFriends(int id) { while (getFriends.next()){ userFriends.add(getUserById(getFriends.getInt("friendId"))); } + log.info("Список друзей пользователя " + id + " отрпавлен"); return userFriends; } else { return null; @@ -168,6 +174,7 @@ public List getCommonFriends(int userId, int otherId) { while (getFriends.next()){ userFriends.add(getUserById(getFriends.getInt("friendId"))); } + log.info("Список общих друзей между пользователями " + userId + " и " + otherId + "отрпавлен"); return userFriends; } else { return null; @@ -187,14 +194,14 @@ public List getRecommendedFilms(int id) { "AND FILMID NOT IN " + " (SELECT FILMID as userfilmlist from LIKESLIST where USERID = " + id +")) as Lr " + "ON f.FILMID = recommended"; - + log.info("Список рекомендуемых фильмов для пользователя " + id + " отправлен"); return jdbcTemplate.query(sql, filmMapper); } - private boolean checkUserInDb(Integer id) { String sql = "SELECT userId FROM users where USERID =?"; SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql, id); if (!getUsersFromDb.next()) { + log.warn("Пользователя с id" + id + " нет в базе!"); throw new NotFoundObjectException("Пользователя с id" + id + " нет в базе!"); } return true; diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index 2f960db..4525ee9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -43,6 +43,7 @@ public Review add(Review review) { reviewLikesStorage.add(review); eventDbStorage.saveEvent(review.getUserId(), EventTypes.REVIEW, OperationTypes.ADD, review.getReviewId()); + log.info("Отзыв " + review.getReviewId() + " добавлен"); return review; } @@ -59,6 +60,7 @@ public Review update(Review review) { namedParameterJdbcTemplate.update(sql, parameterSource); eventDbStorage.saveEvent(userId, EventTypes.REVIEW, OperationTypes.UPDATE, review.getReviewId()); + log.info("Отзыв " + review.getReviewId() + " обновлен"); return getById(review.getReviewId()); } @@ -83,6 +85,7 @@ public void delete(long reviewId) { reviewLikesStorage.delete(reviewId); eventDbStorage.saveEvent(Math.toIntExact(review.getUserId()), EventTypes.REVIEW, OperationTypes.REMOVE, Math.toIntExact(review.getReviewId())); + log.info("Отзыв " + review.getReviewId() + " удален"); } @Override @@ -92,6 +95,7 @@ public Review getById(long reviewId) { Review review = jdbcTemplate.queryForObject(sql, this::getRowMapper, reviewId); review.getLikes().putAll(reviewLikesStorage.getReviewLikesById(review.getReviewId())); + log.info("Отзыв " + review.getReviewId() + " отправлен"); return review; } @@ -102,12 +106,14 @@ public List getAllReviewsByFilmId(long filmId, int limit) { SqlParameterSource parameterSource = new MapSqlParameterSource() .addValue("filmId", filmId) .addValue("limit", limit); + log.info("Список отзывов к фильму " + filmId + " отправлен"); return readReviews(sql, parameterSource); } @Override public List getAllReviews() { String sql = "SELECT * FROM review ORDER BY useful DESC"; SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(Review.class); + log.info("Список всех отзывов отпрален"); return readReviews(sql, parameterSource); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java index 5a57222..3d93fdb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewLikesDbStorage.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -18,17 +19,25 @@ @Repository("reviewLikesDbStorage") @RequiredArgsConstructor +@Slf4j public class ReviewLikesDbStorage implements ReviewLikesStorage { private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final JdbcTemplate jdbcTemplate; + @Data + @AllArgsConstructor + private class ReviewLikesRow { + private long userId; + private boolean isLike; + } + @Override public void add(Review review) { Map likes = review.getLikes(); - if (likes.size() > 0) { String sql = getInsertSql(likes, review); jdbcTemplate.update(sql); + log.info("Лайк для отзыва " + review.getReviewId() + " добавлен"); } } @@ -40,6 +49,7 @@ public void update(Review review) { String sql = getInsertSql(reviewLikes, review); delete(review.getReviewId()); jdbcTemplate.update(sql); + log.info("Лайк для отзыва " + review.getReviewId() + " обновлен"); } } @@ -48,6 +58,7 @@ public void delete(long reviewId) { String sql = "DELETE FROM review_likes WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); + log.info("Лайк для отзыва " + reviewId + " удален"); } @Override @@ -61,6 +72,7 @@ public Map getReviewLikesById(long reviewId) { likesRow.forEach(reviewLikesRow -> reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); } + log.info("Список лайков для отзыва " + reviewId + " отправлен"); return reviewLikes; } @@ -75,6 +87,7 @@ public Map getAllReviewLikes() { likesRow.forEach(reviewLikesRow -> reviewLikes.put(reviewLikesRow.getUserId(), reviewLikesRow.isLike())); } + log.info("Список всех лайков отправлен"); return reviewLikes; } @@ -86,11 +99,4 @@ private String getInsertSql(Map reviewLikes, Review review) { sql.setLength(sql.length() - commaAndSpace); return sql.toString(); } - - @Data - @AllArgsConstructor - private class ReviewLikesRow { - private long userId; - private boolean isLike; - } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java index aa287f3..446c48b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java @@ -9,7 +9,6 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; @Component public class DirectorServiceManager implements DirectorService { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index f3384a7..8ac6af8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -93,11 +93,8 @@ public Mpa getMpaById(int id) { @Override public List searchFilms(String query, List by) { - List resultList = filmStorage.searchFilms(query, by); resultList.sort(Comparator.comparingInt(Film::getLikesCount).reversed()); return resultList; - } - } \ No newline at end of file From 3cddda6ab40257fb6eba6d195418279b5f5e01a0 Mon Sep 17 00:00:00 2001 From: mutaev Date: Fri, 24 Feb 2023 06:01:13 +0300 Subject: [PATCH 20/26] refactor develop changelog in telegram for internal use only --- .../controller/DirectorController.java | 11 +- .../filmorate/controller/FilmController.java | 5 +- .../filmorate/controller/GenreController.java | 14 +- .../filmorate/controller/MpaController.java | 14 +- .../filmorate/dao/DirectorDbStorage.java | 4 +- .../filmorate/dao/EventDbStorage.java | 1 - .../filmorate/dao/FilmDbStorage.java | 192 ++++-------------- .../filmorate/dao/GenreDbStorage.java | 67 ++++++ .../practicum/filmorate/dao/MpaDbStorage.java | 73 +++++++ .../filmorate/dao/UserDbStorage.java | 46 ++--- .../filmorate/dao/mappers/FilmMapper.java | 23 ++- .../practicum/filmorate/model/Film.java | 6 +- .../yandex/practicum/filmorate/model/Mpa.java | 1 - .../filmorate/service/FilmService.java | 6 - .../filmorate/service/FilmServiceManager.java | 44 ++-- .../filmorate/service/GenreService.java | 14 ++ .../service/GenreServiceManager.java | 31 +++ .../filmorate/service/MpaService.java | 14 ++ .../filmorate/service/MpaServiceManager.java | 30 +++ .../filmorate/service/UserServiceManager.java | 26 ++- .../filmorate/storage/FilmStorage.java | 6 - .../filmorate/storage/GenreStorage.java | 17 ++ .../storage/InMemoryFilmStorage.java | 114 ----------- .../storage/InMemoryUserStorage.java | 90 -------- .../filmorate/storage/MpaStorage.java | 14 ++ .../filmorate/storage/UserStorage.java | 2 - src/main/resources/schema.sql | 4 +- 27 files changed, 389 insertions(+), 480 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.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 index bd294da..e0f2850 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java @@ -1,24 +1,19 @@ package ru.yandex.practicum.filmorate.controller; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.service.DirectorService; -import java.net.DatagramSocket; import java.util.List; @RestController +@RequiredArgsConstructor @RequestMapping ("directors") public class DirectorController { - private DirectorService directorService; - - @Autowired - public DirectorController(DirectorService directorService) { - this.directorService = directorService; - } + private final DirectorService directorService; @GetMapping public ResponseEntity> getAll () { 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 a62b7dd..171f12b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -10,7 +10,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; import java.util.Collection; import java.util.List; @@ -83,8 +82,8 @@ public List getFilmsByDirectorId (@PathVariable Integer directorId, } @GetMapping("/search") - public List searchFilms(@RequestParam @NotNull @NotBlank String query, - @RequestParam @NotNull @NotBlank List by) { + public List searchFilms(@RequestParam @NotBlank String query, + @RequestParam @NotBlank List by) { return filmService.searchFilms(query, by); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java index a232dd9..860980f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -1,32 +1,30 @@ package ru.yandex.practicum.filmorate.controller; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.service.GenreService; import java.util.List; @Slf4j @RestController +@RequiredArgsConstructor @RequestMapping("/genres") public class GenreController { - private final FilmService filmService; - - public GenreController(FilmService filmService) { - this.filmService = filmService; - } + private final GenreService genreService; @GetMapping public List getAllGenres(){ - return filmService.getAllGenres(); + return genreService.getAllGenres(); } @GetMapping("/{id}") public Genre getGenreById(@PathVariable("id") int id){ - return filmService.getGenreById(id); + return genreService.getGenreById(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java index 42ce986..b815bf3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -1,33 +1,31 @@ package ru.yandex.practicum.filmorate.controller; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.service.MpaService; import java.util.List; @Slf4j @RestController +@RequiredArgsConstructor @RequestMapping("/mpa") public class MpaController { - private final FilmService filmService; - - public MpaController(FilmService filmService) { - this.filmService = filmService; - } + private final MpaService mpaService; @GetMapping public List getAllMpa(){ - return filmService.getAllMpa(); + return mpaService.getAllMpa(); } @GetMapping("/{id}") public Mpa getMpaById(@PathVariable("id") int id){ - return filmService.getMpaById(id); + return mpaService.getMpaById(id); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index 94cff72..4f73016 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class DirectorDbStorage implements DirectorStorage { private final JdbcTemplate jdbcTemplate; - private final FilmDbStorage filmDbStorage; + private final FilmMapper filmMapper; @Override public List findAll() { @@ -103,7 +103,7 @@ public List findFilmsByDirectorId (Integer directorId) { throw new NotFoundObjectException("Director with " + directorId + " not found"); } String statement = "SELECT directorId,films.* FROM directorFilm LEFT JOIN films ON directorFilm.filmId = films.filmId WHERE directorId = ?"; - List films = jdbcTemplate.query(statement, new FilmMapper(jdbcTemplate, filmDbStorage), directorId); + List films = jdbcTemplate.query(statement, filmMapper, directorId); if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(findDirectorsByFilmId(film.getId())))); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java index f2e5bf2..f5a3ea4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/EventDbStorage.java @@ -19,7 +19,6 @@ public class EventDbStorage { private final JdbcTemplate jdbcTemplate; - public void saveEvent(long userId, EventTypes eventType, OperationTypes operation, long entityId) { Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); jdbcTemplate.update("INSERT INTO events(TIMESTAMP, USERID, EVENTTYPE, OPERATION, ENTITYID) VALUES (?,?,?,?,?)", diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 1fd01ee..1cf2409 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -3,28 +3,26 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.dao.mappers.DirectorMapper; import ru.yandex.practicum.filmorate.dao.mappers.FilmMapper; -import ru.yandex.practicum.filmorate.exceptions.GenreNotFoundException; -import ru.yandex.practicum.filmorate.exceptions.MpaNotFoundException; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.exceptions.ValidationException; import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.model.enums.EventTypes; -import ru.yandex.practicum.filmorate.model.enums.OperationTypes; +import ru.yandex.practicum.filmorate.service.MpaService; import ru.yandex.practicum.filmorate.storage.FilmStorage; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.PreparedStatement; import java.time.LocalDate; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; @Slf4j @@ -32,19 +30,14 @@ @RequiredArgsConstructor public class FilmDbStorage implements FilmStorage { - private static int filmId = 0; private final JdbcTemplate jdbcTemplate; private static final LocalDate FILM_START_DATE = LocalDate.of(1895, 12, 28); - //private static final String SEARCH_BY_TITLE = "SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))"; - private final EventDbStorage eventDbStorage; - - private int generateFilmId() { - return ++filmId; - } + private final FilmMapper filmMapper; + private final MpaService mpaService; @Override public List getAllFilms() { - List films = jdbcTemplate.query("SELECT * FROM films", new FilmMapper(jdbcTemplate, this)); + List films = jdbcTemplate.query("SELECT * FROM films", filmMapper); if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); } @@ -53,7 +46,7 @@ public List getAllFilms() { @Override public List getCommonFilms(int userId, int friendId) { - String sql2 = "SELECT DISTINCT(FILMID), NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + + String sql = "SELECT DISTINCT(FILMID), NAME, DESCRIPTION, RELEASE_DATE, DURATION, MPAID " + "FROM FILMS as f JOIN " + "(SELECT A.FILMID as FI, A.USERID as AU, B.USERID as BU " + "FROM LIKESLIST A, LIKESLIST B " + @@ -61,14 +54,14 @@ public List getCommonFilms(int userId, int friendId) { "ON f.FILMID = common.FI " + "WHERE (AU = " + userId + " AND BU = " + friendId + ")"; - return jdbcTemplate.query(sql2, new FilmMapper(jdbcTemplate, this)); + return jdbcTemplate.query(sql, filmMapper); } @Override public Film getFilmById(int id) { String sql = "SELECT * FROM films WHERE filmId="+id; if (checkFilmInDb(id)){ - Film film = jdbcTemplate.query(sql, this::makeFilm); + Film film = jdbcTemplate.query(sql, filmMapper).get(0); if (film != null) { film.setDirectors(new HashSet<>(getDirectorByFilmId(id))); } @@ -83,29 +76,36 @@ public Film createFilm(Film film) { if (film.getReleaseDate().isBefore(FILM_START_DATE)) { log.info("Не пройдена валидация даты выпуска фильма. Так рано фильмы не снимали!"); throw new ValidationException("Так рано фильмы не снимали!"); - } else { - film.setId(generateFilmId()); - jdbcTemplate.update("INSERT INTO films(filmId, name, description, release_date, duration, mpaId) " + - "VALUES(?,?,?,?,?,?)", - film.getId(), - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - film.getMpa().getId()); - if (film.getGenres().size() > 0) { - for (Genre genre : film.getGenres()) { - jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) VALUES(?,?)", - film.getId(), - genre.getId()); - } - } - jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); - if (film.getDirectors() != null) { - film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); + } + String sql = "INSERT INTO FILMS (MPAID, NAME, DESCRIPTION, RELEASE_DATE, DURATION) VALUES (?,?,?,?,?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql, new String[]{"filmId"}); + ps.setInt(1, film.getMpa().getId()); + ps.setString(2, film.getName()); + ps.setString(3, film.getDescription()); + ps.setDate(4, java.sql.Date.valueOf(film.getReleaseDate())); + ps.setInt(5, film.getDuration()); + return ps; + }, keyHolder); + int generatedId = Objects.requireNonNull(keyHolder.getKey()).intValue(); + film.setId(generatedId); + + if (film.getGenres().size() > 0) { + for (Genre genre : film.getGenres()) { + jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) VALUES(?,?)", + film.getId(), + genre.getId()); } } - return getFilmById(film.getId()); + + jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); + if (film.getDirectors() != null) { + film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); + } + + return getFilmById(generatedId); } @Override @@ -155,7 +155,6 @@ public Film likeFilm(int filmId, int userId) { checkFilmInDb(filmId); checkUserInDb(userId); jdbcTemplate.update("INSERT INTO likesList VALUES (?,?)", filmId, userId); - eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.ADD, filmId); return getFilmById(filmId); } @@ -164,7 +163,6 @@ public Film deleteLikeFromFilm(int filmId, int userId) { checkFilmInDb(filmId); checkUserInDb(userId); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=? AND userId=?", filmId, userId); - eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.REMOVE, filmId); return getFilmById(filmId); } @@ -172,77 +170,13 @@ public Film deleteLikeFromFilm(int filmId, int userId) { public List getPopularFilms(int count) { String sql = "SELECT f.*, count(fl.userId) AS likes FROM films AS f LEFT JOIN likesList AS fl " + "ON f.filmId=fl.filmId GROUP BY f.filmId ORDER BY likes DESC LIMIT "+count; - List films = jdbcTemplate.query(sql, new FilmMapper(jdbcTemplate, this)); + List films = jdbcTemplate.query(sql, filmMapper); if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(getDirectorByFilmId(film.getId())))); } return films; } - @Override - public List getAllGenres() { - List genres = new ArrayList<>(); - SqlRowSet allGenres = jdbcTemplate.queryForRowSet("SELECT * FROM genre"); - while (allGenres.next()) { - Genre genre = new Genre(allGenres.getInt("genreId"), allGenres.getString("name")); - genres.add(genre); - } - return genres; - } - - @Override - public Genre getGenreById(int id) { - checkGenreInDb(id); - SqlRowSet genreRows = jdbcTemplate.queryForRowSet("SELECT * FROM genre WHERE genreId = ?", id); - if (genreRows.next()) { - Genre genre = new Genre(genreRows.getInt("genreId"), - genreRows.getString("name")); - log.info("Жанр с id={}, это {}.", genre.getId(), genre.getName()); - return genre; - } else { - log.info("Жанра с таким id нет!"); - return null; - } - } - - @Override - public List getAllMpa() { - List mpas = new ArrayList<>(); - SqlRowSet allMpas = jdbcTemplate.queryForRowSet("SELECT * FROM mpa"); - while (allMpas.next()) { - Mpa mpa = new Mpa(allMpas.getInt("mpaId"), allMpas.getString("name")); - mpas.add(mpa); - } - return mpas; - } - - public Mpa getMpaById(int id) { - checkMpaInDb(id); - SqlRowSet mpaRows = jdbcTemplate.queryForRowSet("SELECT * FROM mpa WHERE mpaId = ?", id); - if (mpaRows.next()) { - Mpa mpa = new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); - log.info("Рейтинг с id={}, это {}.", mpa.getId(), mpa.getName()); - return mpa; - } else { - log.info("Рейтинга с таким id нет!"); - return null; - } - } - - private boolean checkMpaInDb(int id) { - String sql = "SELECT mpaId FROM mpa"; - SqlRowSet getMpaFromDb = jdbcTemplate.queryForRowSet(sql); - List ids = new ArrayList<>(); - while (getMpaFromDb.next()){ - ids.add(getMpaFromDb.getInt("mpaId")); - } - if (ids.contains(id)) { - return true; - } else { - throw new MpaNotFoundException("Рейтинга с таким id нет в базе!"); - } - } - private boolean checkFilmInDb(Integer id) { String sql = "SELECT filmId FROM films"; SqlRowSet getFilmFromDb = jdbcTemplate.queryForRowSet(sql); @@ -257,45 +191,6 @@ private boolean checkFilmInDb(Integer id) { } } - private Film makeFilm(ResultSet rs) throws SQLException { - if (rs.next()) { - Film film = new Film(rs.getString("name"), - rs.getString("description"), - rs.getDate("release_date").toLocalDate(), - rs.getInt("duration")); - film.setId(rs.getInt("filmId")); - film.setMpa(getMpaById(rs.getInt("mpaId"))); - SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId=?", film.getId()); - while (getFilmGenres.next()) { - Genre genre = getGenreById(getFilmGenres.getInt("genreId")); - film.addGenre(genre); - } - SqlRowSet getFilmLikes = jdbcTemplate.queryForRowSet("SELECT userId FROM likesList WHERE filmId = ?", - film.getId()); - while (getFilmLikes.next()) { - film.addLIke(getFilmLikes.getInt("userId")); - } - return film; - } else { - return null; - } - - } - - private boolean checkGenreInDb(Integer id) { - String sql = "SELECT genreId FROM genre"; - SqlRowSet getGenreFromDb = jdbcTemplate.queryForRowSet(sql); - List ids = new ArrayList<>(); - while (getGenreFromDb.next()) { - ids.add(getGenreFromDb.getInt("genreId")); - } - if (ids.contains(id)) { - return true; - } else { - throw new GenreNotFoundException("Жанра с таким id нет в базе!"); - } - } - private boolean checkUserInDb(Integer id) { String sql = "SELECT userId FROM users"; SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql); @@ -321,10 +216,10 @@ private List getDirectorByFilmId (Integer filmId) { public List searchFilms(String query1, List by) { List films1 = new ArrayList<>(); if (by.size() == 1) { - if (by.get(0).toLowerCase().equals("title")) { + if (by.get(0).equalsIgnoreCase("title")) { searchByTitle(query1, films1); } - if (by.get(0).toLowerCase().equals("director")) { + if (by.get(0).equalsIgnoreCase("director")) { searchByDirector(query1, films1); } } @@ -343,7 +238,8 @@ private void searchByTitle(String query1, List films1) { searchByTitle.getDate("release_date").toLocalDate(), searchByTitle.getInt("duration")); film.setId(searchByTitle.getInt("filmId")); - film.setMpa(getMpaById(searchByTitle.getInt("mpaId"))); + film.setMpa(mpaService.getMpaById(searchByTitle.getInt("mpaId"))); + //необходимо извабивиться от использования данного сервиса именно здесь films1.add(film); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java new file mode 100644 index 0000000..0f7a683 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java @@ -0,0 +1,67 @@ +package ru.yandex.practicum.filmorate.dao; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exceptions.GenreNotFoundException; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.storage.GenreStorage; + +import java.util.*; + +@Slf4j +@Component +@RequiredArgsConstructor +public class GenreDbStorage implements GenreStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public List getAllGenres() { + List genres = new ArrayList<>(); + SqlRowSet allGenres = jdbcTemplate.queryForRowSet("SELECT * FROM genre"); + while (allGenres.next()) { + Genre genre = new Genre(allGenres.getInt("genreId"), allGenres.getString("name")); + genres.add(genre); + } + return genres; + } + + @Override + public Genre getGenreById(int id) { + SqlRowSet genreRows = jdbcTemplate.queryForRowSet("SELECT * FROM genre WHERE genreId = ?", id); + if (genreRows.next()) { + Genre genre = new Genre(genreRows.getInt("genreId"), + genreRows.getString("name")); + log.info("Жанр с id={}, это {}.", genre.getId(), genre.getName()); + return genre; + } else { + throw new GenreNotFoundException("Жанра с таким id нет в базе!"); + } + } + + @Override + public Set getGenresByFilmId(int filmId) { + Set filmGenres = new HashSet<>(); + SqlRowSet rs = jdbcTemplate.queryForRowSet("SELECT * FROM FILM_GENRE as fg " + + "LEFT JOIN GENRE as g " + + "ON fg.GENREID = g.GENREID " + + "WHERE filmId = ?", filmId); + while (rs.next()) { + filmGenres.add(new Genre(rs.getInt("genreId"), rs.getString("name"))); + } + return filmGenres; + } + + @Override + public Map getGenreIdNamesMap() { + Map genreIdNamesMap = new HashMap<>(); + List genres = getAllGenres(); + for (Genre genre : genres) { + genreIdNamesMap.put(genre.getId(), genre.getName()); + } + return genreIdNamesMap; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java new file mode 100644 index 0000000..6adc197 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java @@ -0,0 +1,73 @@ +package ru.yandex.practicum.filmorate.dao; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exceptions.MpaNotFoundException; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.storage.MpaStorage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class MpaDbStorage implements MpaStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public List getAllMpa() { + List mpas = new ArrayList<>(); + SqlRowSet allMpas = jdbcTemplate.queryForRowSet("SELECT * FROM mpa"); + while (allMpas.next()) { + Mpa mpa = new Mpa(allMpas.getInt("mpaId"), allMpas.getString("name")); + mpas.add(mpa); + } + return mpas; + } + + @Override + public Mpa getMpaById(int id) { + checkMpaInDb(id); + SqlRowSet mpaRows = jdbcTemplate.queryForRowSet("SELECT * FROM mpa WHERE mpaId = ?", id); + if (mpaRows.next()) { + Mpa mpa = new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); + log.info("Рейтинг с id={}, это {}.", mpa.getId(), mpa.getName()); + return mpa; + } else { + log.info("Рейтинга с таким id нет!"); + return null; + } + } + + @Override + public Map getMpaIdNamesMap() { + Map mpaIdNamesMap = new HashMap<>(); + List mpas = getAllMpa(); + for (Mpa mpa : mpas) { + mpaIdNamesMap.put(mpa.getId(), mpa.getName()); + } + return mpaIdNamesMap; + } + + private boolean checkMpaInDb(int id) { + String sql = "SELECT mpaId FROM mpa"; + SqlRowSet getMpaFromDb = jdbcTemplate.queryForRowSet(sql); + List ids = new ArrayList<>(); + while (getMpaFromDb.next()){ + ids.add(getMpaFromDb.getInt("mpaId")); + } + if (ids.contains(id)) { + return true; + } else { + throw new MpaNotFoundException("Рейтинга с таким id нет в базе!"); + } + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index 0fb563c..b80c2bb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -3,22 +3,23 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.dao.mappers.FilmMapper; import ru.yandex.practicum.filmorate.dao.mappers.UserMapper; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; -import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.model.enums.EventTypes; -import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.UserStorage; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; @Slf4j @@ -26,15 +27,10 @@ @RequiredArgsConstructor public class UserDbStorage implements UserStorage { - private static int userId = 0; private final JdbcTemplate jdbcTemplate; - private final EventDbStorage eventDbStorage; private final FilmMapper filmMapper; private final UserMapper userMapper; - private int generateUserId() { - return ++userId; - } @Override public List getAllUsers() { @@ -54,17 +50,21 @@ public User getUserById(int id) { @Override public User createUser(User user) { - user.setId(generateUserId()); - if ((user.getName()==null)||(user.getName().isBlank())) { - log.info("Поле \"Имя\" пустое, ему будет присвоено значение поля \"Логин\""); - user.setName(user.getLogin()); - } - jdbcTemplate.update("INSERT INTO users(userId, email, login, name, birthdate) VALUES (?,?,?,?,?)", - user.getId(), - user.getEmail(), - user.getLogin(), - user.getName(), - user.getBirthday()); + String sql = "INSERT INTO users (NAME, EMAIL, LOGIN, BIRTHDATE) VALUES (?, ?, ?, ?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + + + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql, + new String[]{"userid"}); + ps.setString(1, user.getName()); + ps.setString(2, user.getEmail()); + ps.setString(3, user.getLogin()); + ps.setDate(4, java.sql.Date.valueOf(user.getBirthday())); + return ps; + }, keyHolder); + int generatedId = Objects.requireNonNull(keyHolder.getKey()).intValue(); + user.setId(generatedId); return user; } @@ -113,19 +113,17 @@ public void addFriend(int userId, int friendId) { jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='apply'", Integer.class), friendId, userId); - eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.UPDATE, friendId); + }else{ jdbcTemplate.update("INSERT INTO friendship VALUES (?,?,?)", userId, friendId, jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class)); - eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); } } } @Override public User deleteFriend(int userId, int friendId) { - eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.REMOVE, friendId); jdbcTemplate.update("DELETE FROM friendship WHERE userId=? AND friendId=?", userId, friendId); List friends = new ArrayList<>(); SqlRowSet checkFriends = jdbcTemplate.queryForRowSet("SELECT friendId FROM friendship " + @@ -217,8 +215,4 @@ private User makeUser(ResultSet rs) throws SQLException { return null; } } - @Override - public List getEvents(int id) { - return eventDbStorage.getEvent(id); - } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java index 3e54fd9..2d01a95 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java @@ -1,16 +1,14 @@ package ru.yandex.practicum.filmorate.dao.mappers; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.storage.FilmStorage; +import ru.yandex.practicum.filmorate.service.MpaService; +import ru.yandex.practicum.filmorate.storage.GenreStorage; import java.sql.ResultSet; import java.sql.SQLException; @@ -22,7 +20,8 @@ public class FilmMapper implements ResultSetExtractor> { private final JdbcTemplate jdbcTemplate; - private final FilmStorage filmStorage; + private final GenreStorage genreStorage; + private final MpaService mpaService; public List extractData(ResultSet rs) throws SQLException, DataAccessException { List films = new ArrayList<>(); @@ -32,16 +31,18 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep rs.getDate("release_date").toLocalDate(), rs.getInt("duration")); film.setId(rs.getInt("filmId")); - film.setMpa(filmStorage.getMpaById(rs.getInt("mpaId"))); + film.setMpa(mpaService.getMpaById(rs.getInt("mpaId"))); SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId = ?", film.getId()); - while(getFilmGenres.next()){ - Genre genre = filmStorage.getGenreById(getFilmGenres.getInt("genreId")); - film.addGenre(genre); - } +// while(getFilmGenres.next()){ +// Genre genre = genreStorage.getGenreById(getFilmGenres.getInt("genreId")); +// film.addGenre(genre); +// } + film.setGenres(genreStorage.getGenresByFilmId(film.getId())); + SqlRowSet getFilmLikes = jdbcTemplate.queryForRowSet("SELECT userId FROM likesList WHERE filmId = ?", film.getId()); while(getFilmLikes.next()){ - film.addLIke(getFilmLikes.getInt("userId")); + film.addLike(getFilmLikes.getInt("userId")); } films.add(film); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index f050006..958d5f7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -36,7 +36,7 @@ public Film(String name, String description, LocalDate releaseDate, int duration this.duration = duration; } - public void addLIke(Integer userId){ + public void addLike(Integer userId){ likes.add(userId); } @@ -44,8 +44,8 @@ public void removeLike(Integer userId) { if (likes.contains(userId)){ likes.remove(userId); } else { - throw new NotFoundObjectException("Лайк от пользователя "+userId+" этому фильму и так не был поставлен, " + - "удалять нечего"); + throw new NotFoundObjectException("Лайк от пользователя " + userId + + " этому фильму и так не был поставлен, удалять нечего"); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java index bdb7ddd..fc27cdd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -7,7 +7,6 @@ public class Mpa { private Integer id; private String name; - public Mpa(Integer id, String name) { this.id = id; this.name = name; 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 a297069..3877a52 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -1,8 +1,6 @@ package ru.yandex.practicum.filmorate.service; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; import java.util.List; @@ -16,10 +14,6 @@ public interface FilmService { Film likeFilm(int filmId, int userId); Film deleteLikeFromFilm(int filmId, int userId); List getPopularFilms(int count); - List getAllGenres(); - Genre getGenreById(int id); - List getAllMpa(); - Mpa getMpaById(int id); List searchFilms(String query, List by); List getCommonFilms(int userId, int friendId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index f3384a7..48c4da4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -1,11 +1,11 @@ package ru.yandex.practicum.filmorate.service; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.EventDbStorage; 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.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; @@ -13,16 +13,12 @@ import java.util.List; @Service +@RequiredArgsConstructor public class FilmServiceManager implements FilmService { private final FilmStorage filmStorage; private final UserStorage userStorage; - - @Autowired - public FilmServiceManager(@Qualifier("filmDBStorage") FilmStorage filmStorage, UserStorage userStorage) { - this.filmStorage = filmStorage; - this.userStorage = userStorage; - } + private final EventDbStorage eventDbStorage; @Override public List getCommonFilms(int userId, int friendId) { @@ -58,12 +54,16 @@ public void deleteFilmById(int id) { @Override public Film likeFilm(int filmId, int userId) { - return filmStorage.likeFilm(filmId, userId); + Film film = filmStorage.likeFilm(filmId, userId); + eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.ADD, filmId); + return film; } @Override public Film deleteLikeFromFilm(int filmId, int userId) { - return filmStorage.deleteLikeFromFilm(filmId, userId); + Film film = filmStorage.deleteLikeFromFilm(filmId, userId); + eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.REMOVE, filmId); + return film; } @Override @@ -71,26 +71,6 @@ public List getPopularFilms(int count) { return filmStorage.getPopularFilms(count); } - @Override - public List getAllGenres() { - return filmStorage.getAllGenres(); - } - - @Override - public Genre getGenreById(int id) { - return filmStorage.getGenreById(id); - } - - @Override - public List getAllMpa() { - return filmStorage.getAllMpa(); - } - - @Override - public Mpa getMpaById(int id) { - return filmStorage.getMpaById(id); - } - @Override public List searchFilms(String query, List by) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java new file mode 100644 index 0000000..3f77a78 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; +import java.util.Map; + +public interface GenreService { + List getAllGenres(); + + Genre getGenreById(int id); + + Map getGenreIdNamesMap(); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java new file mode 100644 index 0000000..15f9544 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java @@ -0,0 +1,31 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.GenreDbStorage; +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class GenreServiceManager implements GenreService { + + private final GenreDbStorage genreDbStorage; + + @Override + public List getAllGenres() { + return genreDbStorage.getAllGenres(); + } + + @Override + public Genre getGenreById(int id) { + return genreDbStorage.getGenreById(id); + } + + @Override + public Map getGenreIdNamesMap() { + return genreDbStorage.getGenreIdNamesMap(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java new file mode 100644 index 0000000..de478fc --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.util.List; +import java.util.Map; + +public interface MpaService { + List getAllMpa(); + + Mpa getMpaById(int id); + + Map getMpaIdNamesMap(); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java new file mode 100644 index 0000000..61c9d42 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java @@ -0,0 +1,30 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.storage.MpaStorage; + +import java.util.List; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class MpaServiceManager implements MpaService { + private final MpaStorage mpaStorage; + + @Override + public List getAllMpa() { + return mpaStorage.getAllMpa(); + } + + @Override + public Mpa getMpaById(int id) { + return mpaStorage.getMpaById(id); + } + + @Override + public Map getMpaIdNamesMap() { + return mpaStorage.getMpaIdNamesMap(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index 4e69c95..c616e67 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -1,26 +1,27 @@ package ru.yandex.practicum.filmorate.service; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.EventDbStorage; import ru.yandex.practicum.filmorate.exceptions.ValidationException; import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.model.enums.EventTypes; +import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.UserStorage; import java.util.ArrayList; import java.util.List; @Service +@Slf4j +@RequiredArgsConstructor public class UserServiceManager implements UserService{ private final UserStorage userStorage; - - @Autowired - public UserServiceManager(@Qualifier("userDBStorage") UserStorage userStorage) { - this.userStorage = userStorage; - } + private final EventDbStorage eventDbStorage; @Override public List getAll() { @@ -34,6 +35,10 @@ public User getById(int id) { @Override public User createUser(User user) { + if ((user.getName()==null)||(user.getName().isBlank())) { + log.info("Поле \"Имя\" пустое, ему будет присвоено значение поля \"Логин\""); + user.setName(user.getLogin()); + } return userStorage.createUser(user); } @@ -50,11 +55,14 @@ public User deleteUserById(int id) { @Override public void addFriend(int userId, int friendId) { userStorage.addFriend(userId, friendId); + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.ADD, friendId); } @Override public User deleteFriend(int userId, int friendId) throws ValidationException { - return userStorage.deleteFriend(userId, friendId); + User user = userStorage.deleteFriend(userId, friendId); + eventDbStorage.saveEvent(userId, EventTypes.FRIEND, OperationTypes.REMOVE, friendId); + return user; } @Override @@ -82,6 +90,6 @@ public List getRecommendedFilms(int id) { @Override public List getEvents(int id) { - return userStorage.getEvents(id); + return eventDbStorage.getEvent(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index ced89e4..f52f2a9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -1,8 +1,6 @@ package ru.yandex.practicum.filmorate.storage; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; import java.util.List; @@ -15,10 +13,6 @@ public interface FilmStorage { Film likeFilm(int filmId, int userId); Film deleteLikeFromFilm(int filmId, int userId); List getPopularFilms(int count); - List getAllGenres(); - Genre getGenreById(int id); - List getAllMpa(); - Mpa getMpaById(int id); List getCommonFilms(int userId, int friendId); List searchFilms(String query, List by); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java new file mode 100644 index 0000000..ec58021 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface GenreStorage { + List getAllGenres(); + + Genre getGenreById(int id); + + Set getGenresByFilmId(int filmId); + + Map getGenreIdNamesMap(); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java deleted file mode 100644 index 628ec2c..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ /dev/null @@ -1,114 +0,0 @@ -package ru.yandex.practicum.filmorate.storage; - -import lombok.extern.slf4j.Slf4j; -import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; -import ru.yandex.practicum.filmorate.exceptions.ValidationException; -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.validators.FilmValidator; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -@Slf4j -public class InMemoryFilmStorage implements FilmStorage { - - private final Map films = new HashMap<>(); - private int filmId = 0; - - private int generateFilmId() { - return ++filmId; - } - - @Override - public List getAllFilms() { - return new ArrayList<>(films.values()); - } - - @Override - public Film getFilmById(int filmId) { - if (films.containsKey(filmId)) { - return films.get(filmId); - } else { - throw new NotFoundObjectException("Film with this " + filmId + " ID not found."); - } - } - - @Override - public Film createFilm(Film film) { - if (FilmValidator.valid(film)) { - film.setId(generateFilmId()); - films.put(film.getId(), film); - log.info("Film" + film.getId() + " created"); - } else { - throw new ValidationException("Film with this " + film.getId() + " ID already created"); - } - return film; - } - - @Override - public Film updateFilm(Film film) { - if (!films.containsKey(film.getId())) { - throw new NotFoundObjectException("Not found this film"); - } else { - films.remove(film.getId()); - films.put(film.getId(), film); - } - return film; - } - - @Override - public void deleteFilmById(int filmId) { - films.remove(filmId); - } - - @Override - public Film likeFilm(int filmId, int userId) { - return null; - } - - @Override - public Film deleteLikeFromFilm(int filmId, int userId) { - return null; - } - - @Override - public List getPopularFilms(int count) { - return null; - } - - @Override - public List getAllGenres() { - return null; - } - - @Override - public Genre getGenreById(int id) { - return null; - } - - @Override - public List getAllMpa() { - return null; - } - - @Override - public Mpa getMpaById(int id) { - return null; - } - - @Override - public List getCommonFilms(int userId, int friendId) { - return null; - } - - @Override - public List searchFilms(String query, List by){ - return null; - } - -} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java deleted file mode 100644 index da03ba9..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ /dev/null @@ -1,90 +0,0 @@ -package ru.yandex.practicum.filmorate.storage; - -import lombok.extern.slf4j.Slf4j; -import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; -import ru.yandex.practicum.filmorate.model.Event; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.validators.UserValidator; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -@Slf4j -public class InMemoryUserStorage implements UserStorage{ - - private final HashMap users = new HashMap<>(); - private int userId = 0; - - private int generateUserId() { - return ++userId; - } - - @Override - public List getAllUsers() { - return new ArrayList<>(users.values()); - } - - @Override - public User getUserById(int userId) { - return users.get(userId); - } - - @Override - public User createUser(User user) { - UserValidator.checkName(user); - user.setId(generateUserId()); - users.put(user.getId(), user); - return user; - } - - @Override - public User updateUser(User user) { - if (users.containsKey(user.getId())) { - users.remove(user.getId()); - users.put(user.getId(), user); - } else { - throw new NotFoundObjectException("Невозможно обновить данные. Такого пользователя не существует."); - } - return user; - } - - @Override - public User deleteUserById(int userId) { - User user = users.get(userId); - users.remove(userId); - return user; - } - - @Override - public void addFriend(int userId, int friendId) { - - } - - @Override - public User deleteFriend(int userId, int friendId) { - return null; - } - - @Override - public List getFriends(int id) { - return null; - } - - @Override - public List getCommonFriends(int userId, int otherId) { - return null; - } - - @Override - public List getRecommendedFilms(int id) { - return null; - } - - @Override - public List getEvents(int id) { - return null; - } - -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java new file mode 100644 index 0000000..5852e89 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.util.List; +import java.util.Map; + +public interface MpaStorage { + List getAllMpa(); + + Mpa getMpaById(int id); + + Map getMpaIdNamesMap(); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index cf6eaae..d2eefd0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.storage; -import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; @@ -18,5 +17,4 @@ public interface UserStorage { List getFriends(int id); List getCommonFriends(int userId, int otherId); List getRecommendedFilms(int id); - List getEvents(int id); } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index ce234ff..4e14078 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS directors ( directorName varchar ); CREATE TABLE IF NOT EXISTS films ( - filmId INTEGER PRIMARY KEY, + filmId INTEGER PRIMARY KEY AUTO_INCREMENT , name varchar(200), description varchar, release_date date, @@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS films ( ); CREATE TABLE IF NOT EXISTS users ( - userId INTEGER PRIMARY KEY, + userId INTEGER PRIMARY KEY AUTO_INCREMENT , email varchar, login varchar, name varchar, From 7e20e6790e99e204ac821112d44c172ca2262f41 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Fri, 24 Feb 2023 11:30:19 +0300 Subject: [PATCH 21/26] =?UTF-8?q?fix:=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/review/ReviewDbStorage.java | 12 +++++++----- src/main/resources/schema.sql | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index bc9792d..09f4f1d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -7,6 +7,8 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exceptions.NotFoundObjectException; import ru.yandex.practicum.filmorate.model.Review; @@ -28,11 +30,12 @@ public class ReviewDbStorage implements ReviewStorage { @Override public Review add(Review review) { negativeUserOrFilmCheck(review); - createId(review); - String sql = "INSERT INTO review (review_id, content, isPositive, user_id, film_id, useful) " + - "VALUES (:id, :content, :isPositive, :userId, :filmId, :useful)"; + String sql = "INSERT INTO review (content, isPositive, user_id, film_id, useful) " + + "VALUES (:content, :isPositive, :userId, :filmId, :useful)"; SqlParameterSource parameterSource = getParameterSource(review); - namedParameterJdbcTemplate.update(sql, parameterSource); + KeyHolder keyHolder = new GeneratedKeyHolder(); + namedParameterJdbcTemplate.update(sql, parameterSource, keyHolder); + review.setReviewId((long) keyHolder.getKey()); return review; } @@ -61,7 +64,6 @@ public Review updateUseful(Review review) { @Override public void delete(long reviewId) { checkReviewById(reviewId); - Review review = getById(reviewId); String sql = "DELETE FROM review WHERE review_id = :id"; SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("id", reviewId); namedParameterJdbcTemplate.update(sql, parameterSource); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 81707d3..a3fc053 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -58,7 +58,7 @@ CREATE TABLE IF NOT EXISTS friendship ( ); CREATE TABLE IF NOT EXISTS review ( - review_id LONG PRIMARY KEY, + review_id LONG GENERATED ALWAYS AS IDENTITY PRIMARY KEY, content varchar NOT NULL CHECK (content <> ' '), isPositive boolean NOT NULL, user_id LONG REFERENCES users (userId), @@ -67,10 +67,10 @@ CREATE TABLE IF NOT EXISTS review ( ); CREATE TABLE IF NOT EXISTS review_likes ( - id LONG GENERATED ALWAYS AS IDENTITY PRIMARY KEY, user_id LONG REFERENCES users (userId) ON DELETE CASCADE, review_id LONG REFERENCES review (review_id) ON DELETE CASCADE, - isLike BOOLEAN NOT NULL + isLike BOOLEAN NOT NULL, + PRIMARY KEY (user_id, review_id) ); From b41ccdb1c0f8f10c9748735a10dc4c628c49f610 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Fri, 24 Feb 2023 11:35:00 +0300 Subject: [PATCH 22/26] =?UTF-8?q?refactor:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/dao/review/ReviewDbStorage.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java index 09f4f1d..73c69a5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/review/ReviewDbStorage.java @@ -21,9 +21,7 @@ @Repository("reviewDbStorage") @RequiredArgsConstructor -@Slf4j public class ReviewDbStorage implements ReviewStorage { - private static long REVIEW_ID; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final JdbcTemplate jdbcTemplate; @@ -122,11 +120,6 @@ private void checkReviewById(long reviewId) { namedParameterJdbcTemplate.queryForObject(sql, parameterSource, (rs, rowNum) -> rs.getLong("review_id")); } - private void createId(Review review) { - if (review.getReviewId() < REVIEW_ID || review.getReviewId() == 0) review.setReviewId(++REVIEW_ID); - REVIEW_ID = review.getReviewId(); - } - private void negativeUserOrFilmCheck(Review review) throws NotFoundObjectException { if (review.getFilmId() < 0 || review.getUserId() < 0) throw new NotFoundObjectException("Такого пользовователя или фильма не существует."); From f3473d270c61faa6f8afedcc04d004b23972b15c Mon Sep 17 00:00:00 2001 From: Ilusha92 Date: Fri, 24 Feb 2023 13:12:34 +0300 Subject: [PATCH 23/26] Update README.md --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2cf454a..d19e6a6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,25 @@ -# java-filmorate -Template repository for Filmorate project. +# Filmorate +![](https://img.shields.io/badge/Language-Java-orange) + +![](https://img.shields.io/badge/Framework-Spring_boot-green) + +![](https://img.shields.io/badge/Build_automation_tool-Maven-blue) + +![](https://img.shields.io/badge/Database-H2Database-blue) + +#### Приложение имеет: + +1. Full Rest API для работы с пользователями, фильмами, жанрами и режисёрами фильмов. +2. Для хранения данных задействована H2DB. +3. Входные данные проходят валидацию. +4. Реализовано логирование на Slf4j. +5. Приложение имеет стандартные функциональности соцсети: Лента событий, добавление отзывов о фильме, добавление друзей и т.д. +6. Дополнительные характеристики фильма: рейтинг на основе кол-ва лайков от пользователей, возрастные рекомендации для просмотра, жанр фильма. +7. У фильмов реализовано свойство - режиссёр фильма с функциональностью: + - вывод всех фильмов режиссёра, отсортированных по количеству лайков. + - вывод всех фильмов режиссёра, отсортированных по годам. +8. Основные свойства пользователя: e-mail, логин, имя, день рождения. +9. Дополнительные связи пользователя: друзья, отзывы и лайки фильмам. +10. Есть возможность получения списка фильмов по определнным фильтрам и заданной сортировке + + From 0ca95ffbe33cfd9d47916452f75dbef96e53dcd7 Mon Sep 17 00:00:00 2001 From: Igor Shmidt Date: Fri, 24 Feb 2023 13:22:49 +0300 Subject: [PATCH 24/26] =?UTF-8?q?refactor:=20=D1=83=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=8B=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B8=20=D1=86?= =?UTF-8?q?=D0=B8=D0=BA=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/DirectorDbStorage.java | 19 +++--- .../filmorate/dao/FilmDbStorage.java | 64 ++++++++++++------- .../filmorate/dao/UserDbStorage.java | 8 +-- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index 4f73016..9c00d00 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -102,7 +102,8 @@ public List findFilmsByDirectorId (Integer directorId) { if (! isExists(directorId)) { throw new NotFoundObjectException("Director with " + directorId + " not found"); } - String statement = "SELECT directorId,films.* FROM directorFilm LEFT JOIN films ON directorFilm.filmId = films.filmId WHERE directorId = ?"; + String statement = "SELECT directorId,films.* FROM directorFilm " + + "LEFT JOIN films ON directorFilm.filmId = films.filmId WHERE directorId = ?"; List films = jdbcTemplate.query(statement, filmMapper, directorId); if (films != null) { films.forEach(film -> film.setDirectors(new HashSet<>(findDirectorsByFilmId(film.getId())))); @@ -116,12 +117,13 @@ public void deleteDirectorFromDirectorFilm (Integer id) { } private void updateFilmsForDirector (Integer directorId, Set films) { - String statement = "DELETE FROM directorFilm WHERE directorId = ?"; - jdbcTemplate.update(statement,directorId); - statement = "INSERT INTO directorFilm (directorId, filmId) VALUES (?, ?)"; - for (Film film : films) { - jdbcTemplate.update(statement, directorId, film.getId()); - } + String deleteStatement = "DELETE FROM directorFilm WHERE directorId = ?"; + int commaAndSpace = 2; + jdbcTemplate.update(deleteStatement, directorId); + StringBuilder updateStatment = new StringBuilder("INSERT INTO directorFilm (directorId, filmId) VALUES "); + films.forEach(film -> updateStatment.append(String.format("(%d, %d), ", directorId, film.getId()))); + updateStatment.setLength(updateStatment.length() - commaAndSpace); + jdbcTemplate.update(updateStatment.toString()); } public boolean isExists(Integer id) { @@ -133,8 +135,9 @@ public boolean isExists(Integer id) { return false; } } + private List findDirectorsByFilmId (Integer filmId) { String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName FROM directorFilm LEFT JOIN directors ON directorFilm.directorId = directors.directorId WHERE directorFilm.filmId = ?"; return jdbcTemplate.query(statement, new DirectorMapper(), filmId); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 1cf2409..d86c83c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -23,7 +23,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; - +import java.util.Set; @Slf4j @Component("filmDBStorage") @@ -91,21 +91,46 @@ public Film createFilm(Film film) { }, keyHolder); int generatedId = Objects.requireNonNull(keyHolder.getKey()).intValue(); film.setId(generatedId); + setGenres(film); + setDirectors(film); + return getFilmById(generatedId); + } - if (film.getGenres().size() > 0) { - for (Genre genre : film.getGenres()) { - jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) VALUES(?,?)", - film.getId(), - genre.getId()); - } + private void setGenres(Film film) { + Set genres = film.getGenres(); + int filmId = film.getId(); + int commaAndSpace = 2; + if (genres.size() > 0) { + StringBuilder sqlGenre = new StringBuilder("INSERT INTO film_genre(filmId, genreId) VALUES "); + genres.forEach(genre -> sqlGenre.append(String.format("(%d, %d), ", filmId, genre.getId()))); + sqlGenre.setLength(sqlGenre.length() - commaAndSpace); + jdbcTemplate.update(sqlGenre.toString()); } + } + private void setDirectors(Film film) { + int commaAndSpace = 2; + int filmId = film.getId(); jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); - if (film.getDirectors() != null) { - film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); + Set directors = film.getDirectors(); + if (directors != null && directors.size() > 0) { + StringBuilder sqlDirectors = new StringBuilder("INSERT INTO directorFilm (filmId, directorId) VALUES "); + directors.forEach(director -> sqlDirectors.append(String.format("(%d, %d), ", filmId, director.getId()))); + sqlDirectors.setLength(sqlDirectors.length() - commaAndSpace); + jdbcTemplate.update(sqlDirectors.toString()); } + } - return getFilmById(generatedId); + private void setLikes(Film film) { + int commaAndSpace = 2; + int filmId = film.getId(); + Set likes = film.getLikes(); + if (likes.size() > 0) { + StringBuilder sql = new StringBuilder("INSERT INTO likesList VALUES "); + likes.forEach(userId -> sql.append(String.format("(%d, %d)", filmId, userId))); + sql.setLength(sql.length() - commaAndSpace); + jdbcTemplate.update(sql.toString()); + } } @Override @@ -121,17 +146,9 @@ public Film updateFilm(Film film) { film.getId()); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=?", film.getId()); jdbcTemplate.update("DELETE FROM film_genre WHERE filmId=?", film.getId()); - for (Integer userId : film.getLikes()) { - jdbcTemplate.update("INSERT INTO likesList VALUES(?,?)", film.getId(), userId); - } - for (Genre genre : film.getGenres()) { - jdbcTemplate.update("INSERT INTO film_genre(filmId, genreId) " + - "VALUES(?,?)", film.getId(), genre.getId()); - } - jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", film.getId()); - if (film.getDirectors() != null) { - film.getDirectors().forEach(d-> jdbcTemplate.update("INSERT INTO directorFilm (filmId, directorId) VALUES (?, ?)", film.getId(), d.getId())); - } + setLikes(film); + setGenres(film); + setDirectors(film); } return getFilmById(film.getId()); } @@ -203,9 +220,8 @@ private boolean checkUserInDb(Integer id) { } else { throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); } - - } + private List getDirectorByFilmId (Integer filmId) { String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName " + "FROM directorFilm LEFT JOIN directors " + @@ -254,4 +270,4 @@ private void searchByDirector(String query1, List films1) { films1.add(getFilmById(filmId1)); } } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index b80c2bb..d1bcd52 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -113,12 +113,11 @@ public void addFriend(int userId, int friendId) { jdbcTemplate.update("UPDATE friendship SET friendshipStatusId=? WHERE userId=? AND friendId=?", jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='apply'", Integer.class), friendId, userId); - - }else{ + } else { jdbcTemplate.update("INSERT INTO friendship VALUES (?,?,?)", userId, friendId, jdbcTemplate.queryForObject("SELECT friendshipStatusId FROM friendshipStatus WHERE description='not apply'", Integer.class)); - } + } } } @@ -156,7 +155,6 @@ public List getFriends(int id) { } } - @Override public List getCommonFriends(int userId, int otherId) { if(checkUserInDb(userId)) { @@ -215,4 +213,4 @@ private User makeUser(ResultSet rs) throws SQLException { return null; } } -} +} \ No newline at end of file From 60dbe894da365114061517bcde41069720b47d73 Mon Sep 17 00:00:00 2001 From: Ilusha92 Date: Fri, 24 Feb 2023 17:03:21 +0300 Subject: [PATCH 25/26] =?UTF-8?q?=D0=9E=D1=81=D1=82=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D1=81=D1=8C=20=D1=80=D0=B0=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=D1=81=D1=8F=20=D1=81=20FilmMapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/dao/DirectorDbStorage.java | 11 +---- .../filmorate/dao/FilmDbStorage.java | 47 ++++++------------- .../filmorate/dao/GenreDbStorage.java | 1 - .../practicum/filmorate/dao/MpaDbStorage.java | 2 - .../filmorate/dao/UserDbStorage.java | 11 +---- .../filmorate/dao/mappers/FilmMapper.java | 9 ++-- .../filmorate/service/UserService.java | 2 +- .../filmorate/service/UserServiceManager.java | 4 +- .../filmorate/storage/UserStorage.java | 2 +- .../filmorate/validators/FilmValidator.java | 26 ---------- .../filmorate/validators/UserValidator.java | 15 ------ src/main/resources/schema.sql | 9 +--- 12 files changed, 29 insertions(+), 110 deletions(-) delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/validators/FilmValidator.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/validators/UserValidator.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java index c728eab..468eb2f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/DirectorDbStorage.java @@ -32,7 +32,6 @@ public List findAll() { String statement = "SELECT * FROM directors"; List directors = jdbcTemplate.query(statement, new DirectorMapper()); directors.forEach(director -> director.setFilms(new HashSet<>(findFilmsByDirectorId(director.getId())))); - log.info("Список директоров отправлен"); return directors; } @@ -97,10 +96,8 @@ public Director findById(Integer id) { @Override public Director delete(Integer id) { Director director = findById(id); - jdbcTemplate.update("DELETE FROM directorFilm WHERE directorID = ?", id); String statement = "DELETE FROM directors WHERE directorID = ?"; jdbcTemplate.update(statement, id); - deleteDirectorFromDirectorFilm(id); return director; } @@ -117,11 +114,6 @@ public List findFilmsByDirectorId (Integer directorId) { return films; } - public void deleteDirectorFromDirectorFilm (Integer id) { - String statement = "DELETE FROM directorFilm WHERE directorId = ?"; - jdbcTemplate.update(statement,id); - } - private void updateFilmsForDirector (Integer directorId, Set films) { String deleteStatement = "DELETE FROM directorFilm WHERE directorId = ?"; int commaAndSpace = 2; @@ -143,7 +135,8 @@ private boolean isExists(Integer id) { } private List findDirectorsByFilmId (Integer filmId) { - String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName FROM directorFilm LEFT JOIN directors ON directorFilm.directorId = directors.directorId WHERE directorFilm.filmId = ?"; + String statement = "SELECT df.filmId, d.directorId, d.directorName FROM directorFilm AS dF " + + "LEFT JOIN directors AS d ON df.directorId = d.directorId WHERE df.filmId = ?"; return jdbcTemplate.query(statement, new DirectorMapper(), filmId); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index d86c83c..0e15d36 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -33,7 +33,6 @@ public class FilmDbStorage implements FilmStorage { private final JdbcTemplate jdbcTemplate; private static final LocalDate FILM_START_DATE = LocalDate.of(1895, 12, 28); private final FilmMapper filmMapper; - private final MpaService mpaService; @Override public List getAllFilms() { @@ -53,7 +52,6 @@ public List getCommonFilms(int userId, int friendId) { "WHERE A.FILMID = B.FILMID AND A.USERID <> B.USERID) as common " + "ON f.FILMID = common.FI " + "WHERE (AU = " + userId + " AND BU = " + friendId + ")"; - return jdbcTemplate.query(sql, filmMapper); } @@ -156,13 +154,8 @@ public Film updateFilm(Film film) { @Override public void deleteFilmById(int filmId) { if(checkFilmInDb(filmId)) { - jdbcTemplate.update("DELETE FROM film_genre where filmId = ?", filmId); - jdbcTemplate.update("DELETE FROM likesList where filmId = ?", filmId); jdbcTemplate.update("DELETE FROM films where filmId = ?", filmId); - log.info("Фильм с filmId " + filmId + " был удален."); - jdbcTemplate.update("DELETE FROM directorFilm WHERE filmId = ?", filmId); } else { - log.info("Фильм с filmId " + filmId + " не был удален."); throw new NotFoundObjectException("Фильм с filmId " + filmId + " не был удален."); } } @@ -223,51 +216,39 @@ private boolean checkUserInDb(Integer id) { } private List getDirectorByFilmId (Integer filmId) { - String statement = "SELECT directorFilm.filmId, directors.directorId, directors.directorName " + - "FROM directorFilm LEFT JOIN directors " + - "ON directorFilm.directorId = directors.directorId WHERE directorFilm.filmId = ?"; + String statement = "SELECT df.filmId, d.directorId, d.directorName " + + "FROM directorFilm AS df LEFT JOIN directors AS d " + + "ON df.directorId = d.directorId WHERE df.filmId = ?"; return jdbcTemplate.query(statement, new DirectorMapper(), filmId); } public List searchFilms(String query1, List by) { - List films1 = new ArrayList<>(); + List searchResultFilms = new ArrayList<>(); if (by.size() == 1) { if (by.get(0).equalsIgnoreCase("title")) { - searchByTitle(query1, films1); - } + searchResultFilms.addAll(Objects.requireNonNull(jdbcTemplate.query( + "SELECT * FROM films WHERE lower(name) LIKE ?", filmMapper, "%" + query1.toLowerCase() + "%"))); + } if (by.get(0).equalsIgnoreCase("director")) { - searchByDirector(query1, films1); + searchByDirector(query1,searchResultFilms); } } if (by.size() == 2) { - searchByTitle(query1, films1); - searchByDirector(query1, films1); - } - return films1; - } - - private void searchByTitle(String query1, List films1) { - SqlRowSet searchByTitle = jdbcTemplate.queryForRowSet("SELECT * FROM films WHERE lower(name) LIKE lower(CONCAT('%',?,'%'))", query1); - while (searchByTitle.next()) { - Film film = new Film(searchByTitle.getString("name"), - searchByTitle.getString("description"), - searchByTitle.getDate("release_date").toLocalDate(), - searchByTitle.getInt("duration")); - film.setId(searchByTitle.getInt("filmId")); - film.setMpa(mpaService.getMpaById(searchByTitle.getInt("mpaId"))); - //необходимо извабивиться от использования данного сервиса именно здесь - films1.add(film); + searchResultFilms.addAll(Objects.requireNonNull(jdbcTemplate.query( + "SELECT * FROM films WHERE lower(name) LIKE ?", filmMapper, "%" + query1.toLowerCase() + "%"))); + searchByDirector(query1,searchResultFilms); } + return searchResultFilms; } - private void searchByDirector(String query1, List films1) { + private void searchByDirector(String query1, List searchResultFilms) { SqlRowSet searchByDirector = jdbcTemplate.queryForRowSet( "SELECT df.* FROM directorFilm as df " + "INNER JOIN directors as d ON df.directorId = d.directorId " + "WHERE lower(d.directorName) LIKE lower(CONCAT('%',?,'%'))", query1); while (searchByDirector.next()) { Integer filmId1 = searchByDirector.getInt("filmId"); - films1.add(getFilmById(filmId1)); + searchResultFilms.add(getFilmById(filmId1)); } } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java index 0f7a683..3e7293b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java @@ -35,7 +35,6 @@ public Genre getGenreById(int id) { if (genreRows.next()) { Genre genre = new Genre(genreRows.getInt("genreId"), genreRows.getString("name")); - log.info("Жанр с id={}, это {}.", genre.getId(), genre.getName()); return genre; } else { throw new GenreNotFoundException("Жанра с таким id нет в базе!"); diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java index 6adc197..5feded1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java @@ -38,10 +38,8 @@ public Mpa getMpaById(int id) { SqlRowSet mpaRows = jdbcTemplate.queryForRowSet("SELECT * FROM mpa WHERE mpaId = ?", id); if (mpaRows.next()) { Mpa mpa = new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); - log.info("Рейтинг с id={}, это {}.", mpa.getId(), mpa.getName()); return mpa; } else { - log.info("Рейтинга с таким id нет!"); return null; } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index d1bcd52..40d59bf 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -82,17 +82,10 @@ public User updateUser(User user) { } @Override - public User deleteUserById(int userId) { - Optional userOptional = Optional.of(getUserById(userId)); - if(userOptional.isPresent()) { - jdbcTemplate.update("DELETE FROM friendship where userId = ?", userId); - jdbcTemplate.update("DELETE FROM friendship where friendId = ?", userId); - jdbcTemplate.update("DELETE FROM likesList where userId = ?", userId); + public void deleteUserById(int userId) { + if(checkUserInDb(userId)) { jdbcTemplate.update("DELETE FROM users where userId = ?", userId); - log.info("Пользователь с userId " + userId + " был удален."); - return userOptional.get(); } else { - log.info("Пользователь с userId " + userId + " не был удален."); throw new NotFoundObjectException("Пользователь с userId " + userId + " не был удален."); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java index 2d01a95..1b64cb1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java @@ -7,6 +7,7 @@ import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.service.MpaService; import ru.yandex.practicum.filmorate.storage.GenreStorage; @@ -33,10 +34,10 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep film.setId(rs.getInt("filmId")); film.setMpa(mpaService.getMpaById(rs.getInt("mpaId"))); SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId = ?", film.getId()); -// while(getFilmGenres.next()){ -// Genre genre = genreStorage.getGenreById(getFilmGenres.getInt("genreId")); -// film.addGenre(genre); -// } + while(getFilmGenres.next()){ + Genre genre = genreStorage.getGenreById(getFilmGenres.getInt("genreId")); + film.addGenre(genre); + } film.setGenres(genreStorage.getGenresByFilmId(film.getId())); SqlRowSet getFilmLikes = jdbcTemplate.queryForRowSet("SELECT userId FROM likesList WHERE filmId = ?", 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 ae48ed5..b2a85fc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -12,7 +12,7 @@ public interface UserService { User getById(int id); User createUser(User user); User updateUser(User user); - User deleteUserById(int id); + void deleteUserById(int id); void addFriend(int userId, int friendId); User deleteFriend(int userId, int friendId); List getFriends(int id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index c616e67..df8a69c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -48,8 +48,8 @@ public User updateUser(User user) { } @Override - public User deleteUserById(int id) { - return userStorage.deleteUserById(id); + public void deleteUserById(int id) { + userStorage.deleteUserById(id); } @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index d2eefd0..419532a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -11,7 +11,7 @@ public interface UserStorage { User getUserById(int userId); User createUser(User user); User updateUser(User user); - User deleteUserById(int userId); + void deleteUserById(int userId); void addFriend(int userId, int friendId); User deleteFriend(int userId, int friendId); List getFriends(int id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/validators/FilmValidator.java b/src/main/java/ru/yandex/practicum/filmorate/validators/FilmValidator.java deleted file mode 100644 index 0376cd1..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/validators/FilmValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -package ru.yandex.practicum.filmorate.validators; - -import ru.yandex.practicum.filmorate.exceptions.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; - -import java.time.LocalDate; - -public class FilmValidator { - - private static boolean checkYear(Film film) { - LocalDate checkDate = LocalDate.of(1895, 12, 28); - if (film.getReleaseDate() != null - && film.getReleaseDate().isBefore(checkDate)) - return true; - throw new ValidationException("Invalid film's release date"); - } - - private static boolean checkLike(Film film) { - - return true; - } - - public static boolean valid(Film film) { - return (checkYear(film)); - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/validators/UserValidator.java b/src/main/java/ru/yandex/practicum/filmorate/validators/UserValidator.java deleted file mode 100644 index f8cbe6d..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/validators/UserValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.yandex.practicum.filmorate.validators; - -import ru.yandex.practicum.filmorate.model.User; - -public class UserValidator { - - public static User checkName(User user) { - if (user.getName() == null) { - user.setName(user.getLogin()); - } else if (user.getName().isEmpty() || user.getName().isBlank()) { - user.setName(user.getLogin()); - } - return user; - } -} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 035e4e1..e90b90c 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -15,7 +15,6 @@ CREATE TABLE IF NOT EXISTS friendshipStatus ( description varchar ); - CREATE TABLE IF NOT EXISTS directors ( directorId int NOT NULL AUTO_INCREMENT PRIMARY KEY, directorName varchar @@ -43,8 +42,6 @@ CREATE TABLE IF NOT EXISTS film_genre ( PRIMARY KEY (filmId, genreId) ); - - CREATE TABLE IF NOT EXISTS likesList ( filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , userId int REFERENCES USERS(userId) ON DELETE CASCADE @@ -73,15 +70,13 @@ CREATE TABLE IF NOT EXISTS review_likes ( PRIMARY KEY (user_id, review_id) ); - - - CREATE TABLE IF NOT EXISTS directorFilm ( +CREATE TABLE IF NOT EXISTS directorFilm ( directorFilmId int NOT NULL AUTO_INCREMENT PRIMARY KEY, filmId int REFERENCES FILMS(filmId) ON DELETE CASCADE , directorId int REFERENCES DIRECTORS(DIRECTORID) ON DELETE CASCADE, CONSTRAINT filmDirectorFilm FOREIGN KEY (filmId) REFERENCES films (filmId), CONSTRAINT directorFilmDirector FOREIGN KEY (directorId) REFERENCES directors (directorId) - ); +); CREATE TABLE IF NOT EXISTS events ( timestamp long, From 46cdbc22a2df128bee978c9a4ccb3d1955ab60b9 Mon Sep 17 00:00:00 2001 From: mutaev Date: Fri, 24 Feb 2023 22:07:49 +0300 Subject: [PATCH 26/26] refactor develop changed dependencies removed loop access to DB --- .../filmorate/controller/FilmController.java | 4 +- .../filmorate/dao/FilmDbStorage.java | 33 ++-------- .../filmorate/dao/GenreDbStorage.java | 28 ++++++-- .../practicum/filmorate/dao/MpaDbStorage.java | 9 ++- .../filmorate/dao/UserDbStorage.java | 3 +- .../filmorate/dao/mappers/FilmMapper.java | 15 ++--- .../filmorate/service/DirectorService.java | 2 +- .../service/DirectorServiceManager.java | 25 ++------ .../filmorate/service/FilmService.java | 1 + .../filmorate/service/FilmServiceManager.java | 64 +++++++++++++++---- .../filmorate/service/GenreService.java | 7 +- .../service/GenreServiceManager.java | 23 +++++-- .../filmorate/service/MpaService.java | 2 +- .../filmorate/service/MpaServiceManager.java | 4 +- .../filmorate/service/UserService.java | 1 + .../filmorate/service/UserServiceManager.java | 20 +++++- .../filmorate/storage/GenreStorage.java | 3 +- .../filmorate/storage/MpaStorage.java | 2 +- .../filmorate/storage/UserStorage.java | 1 + 19 files changed, 145 insertions(+), 102 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 18da8dd..9fe6912 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.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.service.DirectorService; import ru.yandex.practicum.filmorate.service.FilmService; import javax.validation.Valid; @@ -20,7 +19,6 @@ public class FilmController { private final FilmService filmService; - private final DirectorService directorService; @GetMapping("/common") public List getCommonFilms(@RequestParam("userId") int userId, @RequestParam("friendId") int friendId) { @@ -79,7 +77,7 @@ public Film deleteLikeFromFilm(@PathVariable int id, @PathVariable int userId) { public List getFilmsByDirectorId (@PathVariable Integer directorId, @RequestParam (value = "sortBy")String param) { log.info("Получен запрос на получение"); - return directorService.getFilmsSortedByLikesOrYear(directorId, param); + return filmService.getFilmsSortedByLikesOrYear(directorId, param); } @GetMapping("/search") diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java index 0e15d36..1fba54e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FilmDbStorage.java @@ -14,16 +14,11 @@ import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.service.MpaService; import ru.yandex.practicum.filmorate.storage.FilmStorage; import java.sql.PreparedStatement; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; +import java.util.*; @Slf4j @Component("filmDBStorage") @@ -163,7 +158,6 @@ public void deleteFilmById(int filmId) { @Override public Film likeFilm(int filmId, int userId) { checkFilmInDb(filmId); - checkUserInDb(userId); jdbcTemplate.update("INSERT INTO likesList VALUES (?,?)", filmId, userId); return getFilmById(filmId); } @@ -171,7 +165,6 @@ public Film likeFilm(int filmId, int userId) { @Override public Film deleteLikeFromFilm(int filmId, int userId) { checkFilmInDb(filmId); - checkUserInDb(userId); jdbcTemplate.update("DELETE FROM likesList WHERE filmId=? AND userId=?", filmId, userId); return getFilmById(filmId); } @@ -188,33 +181,15 @@ public List getPopularFilms(int count) { } private boolean checkFilmInDb(Integer id) { - String sql = "SELECT filmId FROM films"; - SqlRowSet getFilmFromDb = jdbcTemplate.queryForRowSet(sql); - List ids = new ArrayList<>(); - while (getFilmFromDb.next()) { - ids.add(getFilmFromDb.getInt("filmId")); - } - if (ids.contains(id)) { + String sql = "SELECT filmId FROM films where filmId =?"; + SqlRowSet getFilmFromDb = jdbcTemplate.queryForRowSet(sql, id); + if (getFilmFromDb.next()) { return true; } else { throw new NotFoundObjectException("Фильма с таким id нет в базе!"); } } - private boolean checkUserInDb(Integer id) { - String sql = "SELECT userId FROM users"; - SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql); - List ids = new ArrayList<>(); - while (getUsersFromDb.next()) { - ids.add(getUsersFromDb.getInt("userId")); - } - if (ids.contains(id)) { - return true; - } else { - throw new NotFoundObjectException("Пользователя с таким id нет в базе!"); - } - } - private List getDirectorByFilmId (Integer filmId) { String statement = "SELECT df.filmId, d.directorId, d.directorName " + "FROM directorFilm AS df LEFT JOIN directors AS d " + diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java index 3e7293b..e332abc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/GenreDbStorage.java @@ -33,9 +33,8 @@ public List getAllGenres() { public Genre getGenreById(int id) { SqlRowSet genreRows = jdbcTemplate.queryForRowSet("SELECT * FROM genre WHERE genreId = ?", id); if (genreRows.next()) { - Genre genre = new Genre(genreRows.getInt("genreId"), + return new Genre(genreRows.getInt("genreId"), genreRows.getString("name")); - return genre; } else { throw new GenreNotFoundException("Жанра с таким id нет в базе!"); } @@ -55,12 +54,31 @@ public Set getGenresByFilmId(int filmId) { } @Override - public Map getGenreIdNamesMap() { - Map genreIdNamesMap = new HashMap<>(); + public Map getGenresMap() { + Map genreIdNamesMap = new HashMap<>(); List genres = getAllGenres(); for (Genre genre : genres) { - genreIdNamesMap.put(genre.getId(), genre.getName()); + genreIdNamesMap.put(genre.getId(), genre); } return genreIdNamesMap; } + + public Map> getAllGenresOfAllFilms() { + Map> genresOfAllFilms = new HashMap<>(); + String sql = "SELECT filmId, genreId FROM FILM_GENRE"; + SqlRowSet rs = jdbcTemplate.queryForRowSet(sql); + Map allGenres = getGenresMap(); + while (rs.next()) { + Integer filmId = rs.getInt("filmId"); + Integer genreId = rs.getInt("genreId"); + if (genresOfAllFilms.containsKey(filmId)) { + genresOfAllFilms.get(filmId).add(allGenres.get(genreId)); + continue; + } + genresOfAllFilms.put(filmId, new HashSet<>() {{ + add(allGenres.get(genreId)); + }}); + } + return genresOfAllFilms; + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java index 5feded1..927a79c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/MpaDbStorage.java @@ -37,19 +37,18 @@ public Mpa getMpaById(int id) { checkMpaInDb(id); SqlRowSet mpaRows = jdbcTemplate.queryForRowSet("SELECT * FROM mpa WHERE mpaId = ?", id); if (mpaRows.next()) { - Mpa mpa = new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); - return mpa; + return new Mpa(mpaRows.getInt("mpaId"), mpaRows.getString("name")); } else { return null; } } @Override - public Map getMpaIdNamesMap() { - Map mpaIdNamesMap = new HashMap<>(); + public Map getMpasMap() { + Map mpaIdNamesMap = new HashMap<>(); List mpas = getAllMpa(); for (Mpa mpa : mpas) { - mpaIdNamesMap.put(mpa.getId(), mpa.getName()); + mpaIdNamesMap.put(mpa.getId(), mpa); } return mpaIdNamesMap; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java index 40d59bf..1aa5202 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/UserDbStorage.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Optional; @Slf4j @Component("userDBStorage") @@ -180,7 +179,7 @@ public List getRecommendedFilms(int id) { return jdbcTemplate.query(sql, filmMapper); } - private boolean checkUserInDb(Integer id) { + public boolean checkUserInDb(Integer id) { String sql = "SELECT userId FROM users where USERID =?"; SqlRowSet getUsersFromDb = jdbcTemplate.queryForRowSet(sql, id); if (!getUsersFromDb.next()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java index 1b64cb1..09efe49 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/mappers/FilmMapper.java @@ -7,38 +7,33 @@ import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Component; 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.service.MpaService; -import ru.yandex.practicum.filmorate.storage.GenreStorage; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Component @RequiredArgsConstructor public class FilmMapper implements ResultSetExtractor> { private final JdbcTemplate jdbcTemplate; - private final GenreStorage genreStorage; private final MpaService mpaService; + public List extractData(ResultSet rs) throws SQLException, DataAccessException { List films = new ArrayList<>(); + Map mpas = mpaService.getMpasMap(); while (rs.next()) { Film film = new Film(rs.getString("name"), rs.getString("description"), rs.getDate("release_date").toLocalDate(), rs.getInt("duration")); film.setId(rs.getInt("filmId")); - film.setMpa(mpaService.getMpaById(rs.getInt("mpaId"))); - SqlRowSet getFilmGenres = jdbcTemplate.queryForRowSet("SELECT genreId FROM film_genre WHERE filmId = ?", film.getId()); - while(getFilmGenres.next()){ - Genre genre = genreStorage.getGenreById(getFilmGenres.getInt("genreId")); - film.addGenre(genre); - } - film.setGenres(genreStorage.getGenresByFilmId(film.getId())); + film.setMpa(mpas.get(rs.getInt("mpaId"))); SqlRowSet getFilmLikes = jdbcTemplate.queryForRowSet("SELECT userId FROM likesList WHERE filmId = ?", film.getId()); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java index 837b144..324abf4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorService.java @@ -11,5 +11,5 @@ public interface DirectorService { Director getById (Integer id); Director delete (Integer id); List getAll (); - List getFilmsSortedByLikesOrYear (Integer id, String param); + List findFilmsByDirectorId (Integer directorId); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java index 446c48b..6ab48a5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/DirectorServiceManager.java @@ -1,23 +1,17 @@ package ru.yandex.practicum.filmorate.service; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.model.Director; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.storage.DirectorStorage; -import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; @Component +@RequiredArgsConstructor public class DirectorServiceManager implements DirectorService { - private DirectorStorage storage; - - @Autowired - public DirectorServiceManager(DirectorStorage storage) { - this.storage = storage; - } + private final DirectorStorage storage; @Override public Director create(Director director) { @@ -45,16 +39,7 @@ public List getAll() { } @Override - public List getFilmsSortedByLikesOrYear(Integer id, String param) { - List filmsByDirectorId = storage.findFilmsByDirectorId(id); - - if ("year".equalsIgnoreCase(param)) { - return filmsByDirectorId - .stream().sorted(Comparator.comparing(Film::getReleaseDate)).collect(Collectors.toList()); - } - else if ("likes".equalsIgnoreCase(param)) { - return filmsByDirectorId.stream().sorted(Comparator.comparing(film -> film.getLikes().size())).collect(Collectors.toList()); - } - return filmsByDirectorId; + public List findFilmsByDirectorId(Integer directorId) { + return storage.findFilmsByDirectorId(directorId); } } 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 3877a52..cc361f3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -16,4 +16,5 @@ public interface FilmService { List getPopularFilms(int count); List searchFilms(String query, List by); List getCommonFilms(int userId, int friendId); + List getFilmsSortedByLikesOrYear(Integer directorId, String param); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java index 92f3a2c..47be078 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmServiceManager.java @@ -4,47 +4,68 @@ import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.dao.EventDbStorage; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.enums.EventTypes; import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.FilmStorage; -import ru.yandex.practicum.filmorate.storage.UserStorage; -import java.util.Comparator; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class FilmServiceManager implements FilmService { private final FilmStorage filmStorage; - private final UserStorage userStorage; + private final UserService userService; private final EventDbStorage eventDbStorage; + private final GenreService genreService; + private final DirectorService directorService; @Override public List getCommonFilms(int userId, int friendId) { List resultList = filmStorage.getCommonFilms(userId, friendId); resultList.sort(Comparator.comparingInt(Film::getLikesCount).reversed()); - return resultList; + return setGenresOfFilmList(resultList); } @Override public List getAllFilms() { - return filmStorage.getAllFilms(); + List films = filmStorage.getAllFilms(); + return setGenresOfFilmList(films); + } + + private List setGenresOfFilmList(List films) { + Map> allGenresOfAllFilms = genreService.getAllGenresOfAllFilms(); + for (Film film : films) { + film.setGenres(allGenresOfAllFilms.get(film.getId())); + if (film.getGenres() == null) { + film.setGenres(new HashSet<>()); + } + } + return films; } @Override - public Film getFilmById(int id) { - return filmStorage.getFilmById(id); + public Film getFilmById(int filmId) { + Film film = filmStorage.getFilmById(filmId); + film.setGenres(genreService.getGenresByFilmId(filmId)); + + return film; } @Override public Film createFilm(Film film) { - return filmStorage.createFilm(film); + filmStorage.createFilm(film); + film.setGenres(genreService.getGenresByFilmId(film.getId())); + return film; } @Override public Film updateFilm(Film film) { - return filmStorage.updateFilm(film); + filmStorage.updateFilm(film); + film.setGenres(genreService.getGenresByFilmId(film.getId())); + return film; } @Override @@ -54,6 +75,7 @@ public void deleteFilmById(int id) { @Override public Film likeFilm(int filmId, int userId) { + userService.checkUserInDb(userId); Film film = filmStorage.likeFilm(filmId, userId); eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.ADD, filmId); return film; @@ -61,20 +83,38 @@ public Film likeFilm(int filmId, int userId) { @Override public Film deleteLikeFromFilm(int filmId, int userId) { + userService.checkUserInDb(userId); Film film = filmStorage.deleteLikeFromFilm(filmId, userId); + film.setGenres(genreService.getGenresByFilmId(filmId)); eventDbStorage.saveEvent(userId, EventTypes.LIKE, OperationTypes.REMOVE, filmId); return film; } @Override public List getPopularFilms(int count) { - return filmStorage.getPopularFilms(count); + return setGenresOfFilmList(filmStorage.getPopularFilms(count)); } @Override public List searchFilms(String query, List by) { List resultList = filmStorage.searchFilms(query, by); resultList.sort(Comparator.comparingInt(Film::getLikesCount).reversed()); - return resultList; + return setGenresOfFilmList(resultList); + } + + @Override + public List getFilmsSortedByLikesOrYear(Integer directorId, String param) { + List filmsByDirectorId = directorService.findFilmsByDirectorId(directorId); + setGenresOfFilmList(filmsByDirectorId); + + if ("year".equalsIgnoreCase(param)) { + return filmsByDirectorId + .stream().sorted(Comparator.comparing(Film::getReleaseDate)).collect(Collectors.toList()); + } + else if ("likes".equalsIgnoreCase(param)) { + return filmsByDirectorId.stream().sorted(Comparator.comparing(film -> film.getLikes().size())).collect(Collectors.toList()); + } + + return filmsByDirectorId; } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java index 3f77a78..754a6b3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -4,11 +4,16 @@ import java.util.List; import java.util.Map; +import java.util.Set; public interface GenreService { List getAllGenres(); Genre getGenreById(int id); - Map getGenreIdNamesMap(); + Map getGenresMap(); + + Set getGenresByFilmId(int filmId); + Map> getAllGenresOfAllFilms(); + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java index 15f9544..e6e6db0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreServiceManager.java @@ -2,30 +2,41 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.dao.GenreDbStorage; import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.storage.GenreStorage; import java.util.List; import java.util.Map; +import java.util.Set; @Component @RequiredArgsConstructor public class GenreServiceManager implements GenreService { - private final GenreDbStorage genreDbStorage; + private final GenreStorage genreStorage; @Override public List getAllGenres() { - return genreDbStorage.getAllGenres(); + return genreStorage.getAllGenres(); } @Override public Genre getGenreById(int id) { - return genreDbStorage.getGenreById(id); + return genreStorage.getGenreById(id); } @Override - public Map getGenreIdNamesMap() { - return genreDbStorage.getGenreIdNamesMap(); + public Map getGenresMap() { + return genreStorage.getGenresMap(); + } + + @Override + public Set getGenresByFilmId(int filmId) { + return genreStorage.getGenresByFilmId(filmId); + } + + @Override + public Map> getAllGenresOfAllFilms() { + return genreStorage.getAllGenresOfAllFilms(); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java index de478fc..90a6b5a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -10,5 +10,5 @@ public interface MpaService { Mpa getMpaById(int id); - Map getMpaIdNamesMap(); + Map getMpasMap(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java index 61c9d42..ee33972 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaServiceManager.java @@ -24,7 +24,7 @@ public Mpa getMpaById(int id) { } @Override - public Map getMpaIdNamesMap() { - return mpaStorage.getMpaIdNamesMap(); + public Map getMpasMap() { + return mpaStorage.getMpasMap(); } } 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 b2a85fc..1619992 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -19,4 +19,5 @@ public interface UserService { List getCommonFriends(int userId, int otherId); List getRecommendedFilms(int id); List getEvents(int id); + boolean checkUserInDb(Integer userId); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java index df8a69c..dc112e4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserServiceManager.java @@ -7,13 +7,13 @@ import ru.yandex.practicum.filmorate.exceptions.ValidationException; import ru.yandex.practicum.filmorate.model.Event; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.model.enums.EventTypes; import ru.yandex.practicum.filmorate.model.enums.OperationTypes; import ru.yandex.practicum.filmorate.storage.UserStorage; -import java.util.ArrayList; -import java.util.List; +import java.util.*; @Service @Slf4j @@ -22,6 +22,7 @@ public class UserServiceManager implements UserService{ private final UserStorage userStorage; private final EventDbStorage eventDbStorage; + private final GenreService genreService; @Override public List getAll() { @@ -85,11 +86,24 @@ public List getCommonFriends(int userId, int otherId) { @Override public List getRecommendedFilms(int id) { - return userStorage.getRecommendedFilms(id); + List recommendedFilms = userStorage.getRecommendedFilms(id); + Map> allGenres = genreService.getAllGenresOfAllFilms(); + for (Film film : recommendedFilms) { + film.setGenres(allGenres.get(film.getId())); + if (film.getGenres() == null) { + film.setGenres(new HashSet<>()); + } + } + return recommendedFilms; } @Override public List getEvents(int id) { return eventDbStorage.getEvent(id); } + + @Override + public boolean checkUserInDb(Integer userId) { + return userStorage.checkUserInDb(userId); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java index ec58021..1c8bca8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java @@ -13,5 +13,6 @@ public interface GenreStorage { Set getGenresByFilmId(int filmId); - Map getGenreIdNamesMap(); + Map getGenresMap(); + Map> getAllGenresOfAllFilms(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java index 5852e89..a642d7e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java @@ -10,5 +10,5 @@ public interface MpaStorage { Mpa getMpaById(int id); - Map getMpaIdNamesMap(); + Map getMpasMap(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index 419532a..e61ea04 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -17,4 +17,5 @@ public interface UserStorage { List getFriends(int id); List getCommonFriends(int userId, int otherId); List getRecommendedFilms(int id); + boolean checkUserInDb(Integer userId); }