diff --git a/.gitignore b/.gitignore
index d7268a3..97fa19e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,9 @@ target/
!**/src/main/**/target/
!**/src/test/**/target/
+### macOS ###
+.DS_Store
+
### STS ###
.apt_generated
.classpath
diff --git a/pom.xml b/pom.xml
index 0c428fa..14702dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,6 +43,7 @@
org.projectlombok
lombok
+ 1.18.30
true
@@ -81,6 +82,7 @@
org.projectlombok
lombok
+ 1.18.30
@@ -97,6 +99,25 @@
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.3.1
+
+
+
+ check
+
+ compile
+
+
+
+ checkstyle.xml
+ true
+
+
+
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..4e9b914
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/DirectorController.java
@@ -0,0 +1,55 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.dto.DirectorDto;
+import ru.yandex.practicum.filmorate.model.Director;
+import ru.yandex.practicum.filmorate.service.director.DirectorService;
+
+import java.util.Collection;
+
+@Slf4j
+@RestController
+@RequestMapping("/directors")
+@RequiredArgsConstructor
+@Validated
+public class DirectorController {
+
+ private final DirectorService directorService;
+
+ @GetMapping
+ public Collection getDirectors() {
+ log.info("Received GET /directors request");
+ return directorService.getDirectors();
+ }
+
+ @GetMapping("/{directorId}")
+ public DirectorDto getDirectorById(@PathVariable long directorId) {
+ log.info("Received GET /directors/{} request", directorId);
+ return directorService.getDirectorById(directorId);
+ }
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public DirectorDto addDirector(@RequestBody Director director) {
+ log.info("Received POST /directors request with body: {}", director);
+ return directorService.addDirector(director);
+ }
+
+ @PutMapping
+ public DirectorDto updateDirector(@RequestBody Director director) {
+ log.info("Received PUT /directors request with body: {}", director);
+ return directorService.updateDirector(director);
+ }
+
+ @DeleteMapping("/{directorId}")
+ public void deleteDirector(@PathVariable long directorId) {
+ log.info("Received DELETE /directors/{} request", directorId);
+ directorService.deleteDirector(directorId);
+
+ }
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java
index 86a12a3..95cfe67 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java
@@ -38,4 +38,11 @@ public ErrorResponse handleConstraintViolation(final ConstraintViolationExceptio
log.warn("constraint violation");
return new ErrorResponse(e.getMessage());
}
+
+ @ExceptionHandler(InternalServerException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public ErrorResponse handleException(Exception e) {
+ log.error("Ошибка сервера: {}", e.getMessage());
+ return new ErrorResponse("Внутренняя ошибка сервера: " + e.getMessage());
+ }
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FeedController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FeedController.java
new file mode 100644
index 0000000..1c06dd6
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FeedController.java
@@ -0,0 +1,26 @@
+package ru.yandex.practicum.filmorate.controller;
+
+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.Event;
+import ru.yandex.practicum.filmorate.service.feed.FeedService;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/users")
+public class FeedController {
+
+ private final FeedService feedService;
+
+ public FeedController(FeedService feedService) {
+ this.feedService = feedService;
+ }
+
+ @GetMapping("/{id}/feed")
+ public List getUserFeed(@PathVariable("id") long userId) {
+ return feedService.getUsersEventFeed(userId);
+ }
+}
\ No newline at end of file
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 79be9ce..14084c9 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -63,8 +63,39 @@ public void deleteLikeToFilm(@PathVariable long filmId, @PathVariable long userI
}
@GetMapping("/popular")
- public List getTopFilms(@RequestParam(defaultValue = "10") @Positive(message = "Count must be positive") int count) {
- log.info("Received GET /films/popular?count={} request", count);
- return filmService.getTopFilms(count);
+ public List getTopFilms(@RequestParam(defaultValue = "10") @Positive(message = "Count must be positive") int count,
+ @RequestParam(defaultValue = "-1") int genreId,
+ @RequestParam(defaultValue = "-1") int year) {
+ log.info("Received GET /films/popular?count={}&genreId={}&year={} request", count, genreId, year);
+ return filmService.getTopFilms(count, genreId, year);
+ }
+
+ @DeleteMapping("/{filmId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteFilm(@PathVariable long filmId) {
+ log.info("Received DELETE /films/{} request", filmId);
+ filmService.deleteFilm(filmId);
+ }
+
+ @GetMapping("/common")
+ public List getCommonFilms(
+ @RequestParam long userId,
+ @RequestParam long friendId) {
+ log.info("GET common films for userId={} and friendId={}", userId, friendId);
+ return filmService.getCommonFilms(userId, friendId);
+ }
+
+ @GetMapping("/director/{directorId}")
+ public List findByDirector(@PathVariable long directorId,
+ @RequestParam(name = "sortBy") String sortMode) {
+ log.info("Received GET /films/director/{}?sortBy={} request", directorId, sortMode);
+ return filmService.findByDirector(directorId, sortMode);
+ }
+
+ @GetMapping("/search")
+ public List searchFilms(@RequestParam String query,
+ @RequestParam String by) {
+ log.info("GET /films/search?query={}&by={}", query, by);
+ return filmService.searchFilms(query, by);
}
}
\ 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
new file mode 100644
index 0000000..f4fa2dd
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ReviewController.java
@@ -0,0 +1,92 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Positive;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.dto.NewReviewRequest;
+import ru.yandex.practicum.filmorate.dto.ReviewDto;
+import ru.yandex.practicum.filmorate.dto.UpdateReviewRequest;
+import ru.yandex.practicum.filmorate.service.review.ReviewService;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/reviews")
+public class ReviewController {
+ private final ReviewService reviewService;
+
+ public ReviewController(ReviewService reviewService) {
+ this.reviewService = reviewService;
+ }
+
+ @GetMapping
+ public List getFilmReviews(@RequestParam(defaultValue = "0") long filmId,
+ @RequestParam(defaultValue = "10")
+ @Positive(message = "Count must be positive") long count) {
+ log.info("Received GET {} reviews for film with ID = {}", count, filmId);
+ return reviewService.getFilmReviews(filmId, count);
+ }
+
+ @GetMapping("{reviewId}")
+ @ResponseStatus(HttpStatus.OK)
+ public ReviewDto getReviewById(@PathVariable int reviewId) {
+ log.info("Received GET review with ID = {}", reviewId);
+ return reviewService.getReviewById(reviewId);
+ }
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public ReviewDto addReview(@RequestBody @Valid NewReviewRequest request) {
+ log.info("Received POST new review: {}", request);
+ return reviewService.addReview(request);
+ }
+
+ @PutMapping
+ @ResponseStatus(HttpStatus.OK)
+ public ReviewDto updateReview(@RequestBody @Valid UpdateReviewRequest request) {
+ log.info("Received UPDATE review: {}", request);
+ return reviewService.updateReview(request);
+ }
+
+ @DeleteMapping("/{reviewId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteReview(@PathVariable long reviewId) {
+ log.info("Received DELETE review with ID = {}", reviewId);
+ reviewService.deleteReview(reviewId);
+ }
+
+ @PutMapping("/{reviewId}/like/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public void likeReview(@PathVariable long reviewId,
+ @PathVariable long userId) {
+ log.info("Received LIKE review with reviewId = {} by user with userId = {}", reviewId, userId);
+ reviewService.likeReview(reviewId, userId);
+ }
+
+ @PutMapping("/{reviewId}/dislike/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public void dislikeReview(@PathVariable long reviewId,
+ @PathVariable long userId) {
+ log.info("Received DISLIKE review with reviewId = {} by user with userId = {}", reviewId, userId);
+ reviewService.dislikeReview(reviewId, userId);
+ }
+
+ @DeleteMapping("/{reviewId}/like/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public void removeLike(@PathVariable long reviewId,
+ @PathVariable long userId) {
+ log.info("Received REMOVE LIKE from review with reviewId = {} by user with userId = {}", reviewId, userId);
+ reviewService.removeLike(reviewId, userId);
+ }
+
+ @DeleteMapping("/{reviewId}/dislike/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public void removeDislike(@PathVariable long reviewId,
+ @PathVariable long userId) {
+ log.info("Received REMOVE DISLIKE from review with reviewId = {} by user with userId = {}", reviewId, userId);
+ reviewService.removeDislike(reviewId, userId);
+ }
+}
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 1c16497..3da7c93 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -5,8 +5,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.dto.FilmDto;
import ru.yandex.practicum.filmorate.dto.UserDto;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.service.feed.FeedService;
+import ru.yandex.practicum.filmorate.service.film.FilmService;
import ru.yandex.practicum.filmorate.service.user.UserService;
import ru.yandex.practicum.filmorate.storage.user.UserDbStorage;
@@ -17,10 +20,12 @@
@RequestMapping("/users")
public class UserController {
private final UserService userService;
+ private final FilmService filmService;
@Autowired
- public UserController(UserDbStorage userDbStorage) {
- userService = new UserService(userDbStorage);
+ public UserController(UserDbStorage userDbStorage, FilmService filmService, FeedService feedService) {
+ userService = new UserService(userDbStorage, feedService);
+ this.filmService = filmService;
}
@GetMapping
@@ -72,5 +77,18 @@ public Collection getFriends(@PathVariable int id) {
log.info("getFriends");
return userService.getFriends(id);
}
+
+ @DeleteMapping("/{userId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteUser(@PathVariable int userId) {
+ log.info("Recieved DELETE /users/{} request", userId);
+ userService.deleteUser(userId);
+ }
+
+ @GetMapping("/{id}/recommendations")
+ public Collection getRecommendations(@PathVariable long id) {
+ log.info("get recommendations");
+ return filmService.getRecommendations(id);
+ }
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java
new file mode 100644
index 0000000..f18d332
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dal/DirectorRepository.java
@@ -0,0 +1,48 @@
+package ru.yandex.practicum.filmorate.dal;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.model.Director;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public class DirectorRepository extends BaseRepository {
+
+ private static final String FIND_ALL_QUERY = "SELECT * FROM DIRECTORS d";
+ private static final String FIND_BY_ID_QUERY = "SELECT * FROM DIRECTORS d WHERE d.director_id = ?";
+ private static final String INSERT_QUERY = "INSERT INTO DIRECTORS (NAME) VALUES(?)";
+ private static final String UPDATE_QUERY = "UPDATE DIRECTORS SET NAME = ? WHERE DIRECTOR_ID = ?";
+ private static final String DELETE_QUERY = "DELETE FROM DIRECTORS WHERE DIRECTOR_ID = ?";
+
+ public DirectorRepository(JdbcTemplate jdbc,
+ RowMapper mapper) {
+ super(jdbc, mapper);
+ }
+
+ public List findAll() {
+ return findMany(FIND_ALL_QUERY);
+ }
+
+ public Optional findById(long id) {
+ return findOne(FIND_BY_ID_QUERY, id);
+ }
+
+ public Director save(Director director) {
+ Long id = (Long) insert(INSERT_QUERY, director.getName());
+ director.setId(id);
+ return director;
+ }
+
+ public Director update(Director director) {
+ update(UPDATE_QUERY, director.getName(), director.getId());
+ return director;
+ }
+
+ public void delete(long id) {
+ update(DELETE_QUERY, id);
+ }
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FeedRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FeedRepository.java
new file mode 100644
index 0000000..96e866d
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FeedRepository.java
@@ -0,0 +1,31 @@
+package ru.yandex.practicum.filmorate.dal;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.dal.mapper.EventRowMapper;
+import ru.yandex.practicum.filmorate.model.Event;
+
+import java.util.List;
+
+@Repository
+public class FeedRepository {
+
+ private final JdbcTemplate jdbc;
+ private final EventRowMapper eventRowMapper;
+
+ public FeedRepository(JdbcTemplate jdbc, EventRowMapper eventRowMapper) {
+ this.jdbc = jdbc;
+ this.eventRowMapper = eventRowMapper;
+ }
+
+ public List getUsersEventFeed(long userId) {
+ String sqlQuery = "SELECT * FROM event_feed WHERE user_id = ?;";
+ return jdbc.query(sqlQuery, eventRowMapper, userId);
+ }
+
+ public void saveEvent(Event event) {
+ String sqlQuery = "INSERT INTO event_feed (timestamp, user_id, event_type, operation, entity_id) VALUES (?, ?, ?, ?, ?);";
+ jdbc.update(sqlQuery, event.getTimestamp(), event.getUserId(), event.getEventType().name(),
+ event.getOperation().name(), event.getEntityId());
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java
index 4adda28..a62d9ee 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmRepository.java
@@ -1,6 +1,8 @@
package ru.yandex.practicum.filmorate.dal;
+import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -8,12 +10,16 @@
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import ru.yandex.practicum.filmorate.dal.mapper.FilmRowMapper;
+import ru.yandex.practicum.filmorate.exception.ParameterNotValidException;
+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.Rating;
import java.sql.Date;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
@@ -30,12 +36,66 @@ public class FilmRepository extends BaseRepository {
private static final String GET_LIKES_QUERY = "SELECT user_id FROM Likes WHERE film_id = ?";
private static final String ADD_LIKE_QUERY = "INSERT INTO Likes (user_id, film_id) VALUES (?, ?)";
private static final String REMOVE_LIKE_QUERY = "DELETE FROM Likes WHERE film_id = ? AND user_id = ?";
+ private static final String GET_COMMON_FILMS = "SELECT f.*, r.rating_id as mpa_id, r.rating_name as mpa_name " +
+ "FROM Films f " +
+ "JOIN rating AS r ON f.rating_id = r.rating_id " +
+ "JOIN Likes l ON f.id = l.film_id " +
+ "WHERE l.film_id IN ( " +
+ " SELECT film_id FROM Likes WHERE user_id = ? " +
+ " INTERSECT " +
+ " SELECT film_id FROM Likes WHERE user_id = ? " +
+ ") " +
+ "GROUP BY f.id " +
+ "ORDER BY COUNT(l.user_id) DESC";
private static final String FIND_GENRES_FOR_FILMS_QUERY =
"SELECT fg.film_id, g.id as genre_id, g.name as genre_name " +
"FROM genre g " +
"JOIN film_genre fg ON g.id = fg.genre_id " +
"WHERE fg.film_id IN (:filmIds)";
+ private static final String DELETE_FILM_QUERY = "DELETE FROM Films WHERE id = ?";
+
+ private static final String FIND_DIRECTOR_FOR_FILMS_QUERY = """
+ SELECT fd.FILM_ID,
+ d.DIRECTOR_ID,
+ d.NAME as DIRECTOR_NAME
+ FROM FILM_DIRECTORS fd
+ JOIN DIRECTORS d ON (fd.DIRECTOR_ID = d.DIRECTOR_ID)
+ WHERE fd.film_id in (:filmIds)
+ """;
+
+ private static final String FIND_BY_DIRECTOR_SORT_BY_LIKES = """
+ SELECT f.*,
+ r.rating_id as mpa_id,
+ r.rating_name as mpa_name
+ FROM films AS f
+ JOIN rating AS r ON f.rating_id = r.rating_id
+ JOIN FILM_DIRECTORS fd ON f.ID = fd.FILM_ID
+ WHERE fd.DIRECTOR_ID = ?
+ ORDER BY (SELECT COUNT(1) FROM LIKES l WHERE l.FILM_ID = f.ID) DESC
+ """;
+
+ private static final String FIND_BY_DIRECTOR_SORT_BY_YEAR = """
+ SELECT f.*,
+ r.rating_id as mpa_id,
+ r.rating_name as mpa_name
+ FROM films AS f
+ JOIN rating AS r ON f.rating_id = r.rating_id
+ JOIN FILM_DIRECTORS fd ON f.ID = fd.FILM_ID
+ WHERE fd.DIRECTOR_ID = ?
+ ORDER BY f.RELEASE_DATE
+ """;
+
+ private static final String FIND_BY_TITLE_OR_DIRECTOR = """
+ SELECT f.*,
+ r.rating_id as mpa_id,
+ r.rating_name as mpa_name
+ FROM films AS f
+ JOIN rating AS r ON f.rating_id = r.rating_id
+ LEFT JOIN FILM_DIRECTORS fd ON f.ID = fd.FILM_ID
+ LEFT JOIN DIRECTORS d ON fd.DIRECTOR_ID = d.DIRECTOR_ID
+ WHERE
+ """;
private final JdbcTemplate jdbc;
private final NamedParameterJdbcTemplate namedJdbcTemplate;
@@ -51,6 +111,16 @@ private static class FilmGenreRelation {
}
}
+ private static class FilmDirectorRelation {
+ final long filmId;
+ final Director director;
+
+ FilmDirectorRelation(long filmId, Director director) {
+ this.filmId = filmId;
+ this.director = director;
+ }
+ }
+
private final RowMapper filmGenreRelationRowMapper = (rs, rowNum) -> {
Genre genre = new Genre();
genre.setId(rs.getInt("genre_id"));
@@ -58,6 +128,13 @@ private static class FilmGenreRelation {
return new FilmGenreRelation(rs.getLong("film_id"), genre);
};
+ private final RowMapper filmDirectorRelationRowMapper = (rs, rowNum) -> {
+ Director director = new Director();
+ director.setId(rs.getLong("director_id"));
+ director.setName(rs.getString("director_name"));
+ return new FilmDirectorRelation(rs.getLong("film_id"), director);
+ };
+
public FilmRepository(JdbcTemplate jdbc,
NamedParameterJdbcTemplate namedJdbcTemplate,
FilmRowMapper filmMapper) {
@@ -83,18 +160,29 @@ public List findAll() {
if (!films.isEmpty()) {
setGenresForFilms(films);
+ setDirectorForFilm(films);
}
return films;
}
+ public List findCommon(long userId, long filmId) {
+ List films = jdbc.query(GET_COMMON_FILMS, filmWithRatingMapper, userId, filmId);
+ if (!films.isEmpty()) {
+ setGenresForFilms(films);
+ }
+ return films;
+ }
+
+
public Optional findById(long id) {
List films = jdbc.query(FIND_BY_ID_QUERY, filmWithRatingMapper, id);
if (films.isEmpty()) {
return Optional.empty();
} else {
- Film film = films.get(0);
+ Film film = films.getFirst();
setGenresForFilms(List.of(film));
+ setDirectorForFilm(List.of(film));
return Optional.of(film);
}
}
@@ -148,7 +236,7 @@ public Film save(Film film) {
film.setId(id);
saveGenres(film);
-
+ saveDirector(film);
return findById(id).orElseThrow(() -> new IllegalStateException("Saved film not found, id: " + id));
}
@@ -169,9 +257,35 @@ public Film update(Film film) {
deleteGenres(film.getId());
saveGenres(film);
+ deleteFilms(film.getId());
+ saveDirector(film);
+
return findById(film.getId()).orElseThrow(() -> new IllegalStateException("Updated film not found, id: " + film.getId()));
}
+ public boolean deleteFilm(long id) {
+ return delete(DELETE_FILM_QUERY, id);
+ }
+
+ public Map> getAllLikesGroupedByUser() {
+ String sql = "SELECT * FROM Likes";
+
+ return jdbc.query(sql, new ResultSetExtractor