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 d5badc8..848cd15 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -38,7 +38,7 @@ public Collection getTop(@RequestParam(defaultValue = "10", required = @GetMapping("/common") public Collection getCommonLikedFilms(@RequestParam(required = true) Long userId, - @RequestParam(required = true) Long friendId) { + @RequestParam(required = true) Long friendId) { return filmService.getCommonLikedFilms(userId, friendId); } @@ -71,8 +71,13 @@ public void deleteLike(@PathVariable long filmId, @PathVariable long userId) { filmService.changeLike(LikeAction.REMOVE, filmId, userId); } + @GetMapping("/search") + public Collection search(@RequestParam String query, @RequestParam String by) { + return filmService.search(query, by); + } + @DeleteMapping("/{filmId}") public void deleteFilm(@PathVariable long filmId) { filmService.remove(filmId); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java index b5ee1b1..dab18e0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/FilmStorage.java @@ -44,6 +44,10 @@ public interface FilmStorage { Collection getCommonLikedFilms(long userId, long friendId); + + Collection search(String query, String by); + /// Удаление фильма по id void removeFilm(long filmId); + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java index 30ba174..602782b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/database/FilmDbStorage.java @@ -13,8 +13,6 @@ import java.sql.SQLException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.HashMap; -import java.util.HashSet; import static ru.yandex.practicum.filmorate.dal.database.sql.FilmQueryes.*; @@ -23,10 +21,7 @@ public class FilmDbStorage extends BaseDbStorage implements FilmStorage { @Autowired - public FilmDbStorage( - JdbcTemplate jdbc, - @Qualifier("filmRowMapper") RowMapper mapper - ) { + public FilmDbStorage(JdbcTemplate jdbc, @Qualifier("filmRowMapper") RowMapper mapper) { super(jdbc, mapper); } @@ -41,7 +36,6 @@ public Film createFilm(Film film) { film.getDuration().toMinutes(), film.getMpaId() ); - film.setId(id); insertGenreIds(film); insertDirectorIds(film); @@ -60,7 +54,6 @@ public Film updateFilm(Film film) { film.getMpaId(), film.getId() ); - insertGenreIds(film); insertDirectorIds(film); return film; @@ -72,7 +65,6 @@ public Optional findById(long filmId) { Optional filmOptional = findOneByIdInTable(filmId, "films"); filmOptional.ifPresent(film -> film.setGenreIds(getGenreIdsByFilmId(filmId))); filmOptional.ifPresent(film -> film.setDirectorIds(getDirectorIdsByFilmId(filmId))); - return filmOptional; } @@ -105,7 +97,7 @@ public Collection getTop(int top) { public Collection getTopByFilters(Integer top, Integer genreId, String year) { Collection films; if (genreId != null && year != null && !year.isEmpty()) { - films = findManyByQuery(SQL_FILMS_FIND_TOP_BY_GENRE_AND_YEAR, Integer.parseInt(year), genreId, top); + films = findManyByQuery(SQL_FILMS_FIND_TOP_BY_GENRE_AND_YEAR, Integer.parseInt(year), genreId, top); } else if (year != null && !year.isEmpty()) { films = findManyByQuery(SQL_FILMS_FIND_TOP_BY_YEAR, Integer.parseInt(year), top); } else if (genreId != null) { @@ -113,11 +105,10 @@ public Collection getTopByFilters(Integer top, Integer genreId, String yea } else { films = findManyByQuery(SQL_FILMS_FIND_TOP, top); } - return films.stream().peek(film -> { Set genres = getGenreIdsByFilmId(film.getId()); film.setGenreIds(new HashSet<>(genres)); - }).toList(); + }).toList(); } @Override @@ -125,14 +116,50 @@ public boolean checkFilmIsNotPresent(Long filmId) { return checkIdIsNotPresentInTable(filmId, "films"); } + @Override + public Map> getAllLikes() { + String sql = "SELECT user_id, film_id FROM likes"; + Map> allLikes = new HashMap<>(); + jdbc.query(sql, (rs) -> { + long userId = rs.getLong("user_id"); + long filmId = rs.getLong("film_id"); + allLikes.computeIfAbsent(userId, k -> new HashSet<>()).add(filmId); + }); + return allLikes; + } + + @Override + public Collection getCommonLikedFilms(long userId, long friendId) { + return findManyFilms(SQL_FILMS_FIND_COMMON_LIKED, userId, friendId); + } + + @Override + public Collection search(String query, String by) { + String searchPattern = "%" + query.toLowerCase() + "%"; + String condition; + if (by.contains("director") && by.contains("title")) { + condition = "(LOWER(f.film_name) LIKE ? OR LOWER(d.director_name) LIKE ?)"; + return findManyFilms(String.format(SQL_FILMS_SEARCH, condition), searchPattern, searchPattern); + } else if (by.contains("director")) { + condition = "LOWER(d.director_name) LIKE ?"; + return findManyFilms(String.format(SQL_FILMS_SEARCH, condition), searchPattern); + } else { + condition = "LOWER(f.film_name) LIKE ?"; + return findManyFilms(String.format(SQL_FILMS_SEARCH, condition), searchPattern); + } + } + + @Override + public void removeFilm(long filmId) { + updateWithControl("DELETE FROM films WHERE id = ?", filmId); + } + private void insertGenreIds(Film film) { Set genreIds = film.getGenreIds(); if (genreIds.isEmpty()) { return; } - String placeholders = String.join(",", - Collections.nCopies(genreIds.size(), " (" + film.getId() + ", ?)") - ); + String placeholders = String.join(",", Collections.nCopies(genreIds.size(), " (" + film.getId() + ", ?)")); String sql = SQL_FILMS_INSERT_GENREIDS + placeholders; updateWithControl(sql, genreIds.toArray()); } @@ -142,9 +169,7 @@ private void insertDirectorIds(Film film) { if (directorIds.isEmpty()) { return; } - String placeholders = String.join(",", - Collections.nCopies(directorIds.size(), " (" + film.getId() + ", ?)") - ); + String placeholders = String.join(",", Collections.nCopies(directorIds.size(), " (" + film.getId() + ", ?)")); String sql = SQL_FILMS_INSERT_DIRECTORIDS + placeholders; updateWithControl(sql, directorIds.toArray()); } @@ -156,32 +181,25 @@ private Collection findManyFilms(String query, Object... params) { while (rs.next()) { long filmId = rs.getLong("id"); Film film = films.computeIfAbsent(filmId, id -> { - try { return rowMapper.mapRow(rs, rowNum.getAndIncrement()); } catch (SQLException e) { - throw new InternalServerException( - "Не удалось получить все фильмы из базы.\n" + e.getMessage() - ); + throw new InternalServerException("Не удалось получить все фильмы из базы.\n" + e.getMessage()); } }); - long userId = rs.getLong("user_id"); if (!rs.wasNull() && film != null) { film.addLike(userId); } - int genreId = rs.getInt("genre_id"); if (!rs.wasNull() && film != null) { film.addGenreId(genreId); } - int directorId = rs.getInt("director_id"); if (!rs.wasNull() && film != null) { film.addDirectorId(directorId); } } - return new ArrayList<>(films.values()); }, params); } @@ -193,29 +211,4 @@ private Set getGenreIdsByFilmId(long filmId) { private Set getDirectorIdsByFilmId(long filmId) { return findColumnByQuery(SQL_FILMS_FIND_DIRECTORIDS_BY_FILM_ID, Integer.class, filmId); } - - @Override - public Map> getAllLikes() { - - String sql = "SELECT user_id, film_id FROM likes"; - Map> allLikes = new HashMap<>(); - - jdbc.query(sql, (rs) -> { - long userId = rs.getLong("user_id"); - long filmId = rs.getLong("film_id"); - allLikes.computeIfAbsent(userId, k -> new HashSet<>()).add(filmId); - }); - - return allLikes; - } - - @Override - public Collection getCommonLikedFilms(long userId, long friendId) { - return findManyFilms(SQL_FILMS_FIND_COMMON_LIKED, userId, friendId); - } - - @Override - public void removeFilm(long filmId) { - updateWithControl("DELETE FROM films WHERE id = ?", filmId); - } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/database/sql/FilmQueryes.java b/src/main/java/ru/yandex/practicum/filmorate/dal/database/sql/FilmQueryes.java index b2405d6..e1bbc27 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/database/sql/FilmQueryes.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/database/sql/FilmQueryes.java @@ -208,4 +208,25 @@ WHERE f.id IN ( ) ORDER BY likes_count DESC; """; + + public static final String SQL_FILMS_SEARCH = """ + SELECT f.id, + f.film_name, + f.description, + f.release_date, + f.duration, + f.mpa_id, + m.mpa_name, + gof.genre_id, + dof.director_id, + l.user_id + FROM films f + LEFT JOIN mpa m ON f.mpa_id = m.id + LEFT JOIN genres_of_films gof ON f.id = gof.film_id + LEFT JOIN directors_of_films dof ON f.id = dof.film_id + LEFT JOIN directors d ON dof.director_id = d.id + LEFT JOIN likes l ON f.id = l.film_id + WHERE %s + ORDER BY (SELECT COUNT(*) FROM likes WHERE film_id = f.id) DESC, f.id ASC; + """; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java index a20c49e..c72242b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/dal/inmemory/InMemoryFilmStorage.java @@ -1,55 +1,38 @@ package ru.yandex.practicum.filmorate.dal.inmemory; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import ru.yandex.practicum.filmorate.dal.FilmStorage; import ru.yandex.practicum.filmorate.exception.MethodNotImplementedException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.servise.util.IdentifyService; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.HashMap; - -import java.util.Set; +import java.util.*; @Component -@Qualifier("inMemoryFilmStorage") -@RequiredArgsConstructor public class InMemoryFilmStorage implements FilmStorage { - private final Map films; - private final IdentifyService identifyService; - @Override public Optional findById(long id) { - return films.values().stream() - .filter(f -> f.getId().equals(id)).findFirst(); + throw new MethodNotImplementedException(); } @Override public Collection findAll() { - return films.values(); + throw new MethodNotImplementedException(); } @Override public Film createFilm(Film film) { - film.setId(identifyService.getNextId(films)); - films.put(film.getId(), film); - return film; + throw new MethodNotImplementedException(); } @Override public Film updateFilm(Film film) { - films.put(film.getId(), film); - return film; + throw new MethodNotImplementedException(); } @Override public boolean checkFilmIsNotPresent(Long filmId) { - return films.containsKey(filmId); + throw new MethodNotImplementedException(); } @Override @@ -63,23 +46,23 @@ public Collection getTopByFilters(Integer count, Integer genreId, String y } @Override - public void removeLike(long filmId, long userId) { + public void setLike(long filmId, long userId) { throw new MethodNotImplementedException(); } @Override - public Collection getALLFilmsOfDirector(Integer directorId) { + public void removeLike(long filmId, long userId) { throw new MethodNotImplementedException(); } @Override - public void setLike(long filmId, long userId) { + public Collection getALLFilmsOfDirector(Integer directorId) { throw new MethodNotImplementedException(); } @Override public Map> getAllLikes() { - return new HashMap<>(); + throw new MethodNotImplementedException(); } @Override @@ -87,8 +70,13 @@ public Collection getCommonLikedFilms(long userId, long friendId) { throw new MethodNotImplementedException(); } + @Override + public Collection search(String query, String by) { + throw new MethodNotImplementedException(); + } + @Override public void removeFilm(long filmId) { throw new MethodNotImplementedException(); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/servise/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/servise/FilmService.java index fdaf33e..7f3c486 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/servise/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/servise/FilmService.java @@ -313,4 +313,16 @@ private void logFilmUpdate(FilmUpdateRequest request, Film film) { String updatedData = String.join(", ", updatedFields); log.info("Данные для обновления: [{}]", updatedData); } + + public Collection search(String query, String by) { + log.info("Запрос на поиск фильмов: query='{}', by='{}'", query, by); + return filmStorage.search(query, by).stream() + .map(film -> FilmMapper.mapToFilmDto( + film, + mpas.get(film.getMpaId()), + getGenresByIds(film.getGenreIds()), + getDirectorsByIds(film.getDirectorIds()) + )) + .toList(); + } }