From 46339e7f50400a2c73adae76939895943b7e6b45 Mon Sep 17 00:00:00 2001 From: Alexander Krutov Date: Mon, 13 Jan 2025 00:31:41 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D0=A1=D0=BF=D1=80=D0=B8=D0=BD=D1=82=2012?= =?UTF-8?q?=20|=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F=D0=B5=D1=82?= =?UTF-8?q?=20=D0=91=D0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 9 + .../exception/InternalErrorException.java | 7 + .../practicum/filmorate/model/Genre.java | 2 + .../yandex/practicum/filmorate/model/Mpa.java | 2 + .../repository/FilmDbRepository.java | 320 ++++++++++++++++++ .../repository/FriendshipDbRepository.java | 106 ++++++ .../repository/GenreDbRepository.java | 93 +++++ .../repository/InMemoryFilmRepository.java | 3 +- .../repository/InMemoryUserRepository.java | 3 +- .../repository/LikeDbRepository.java | 65 ++++ .../filmorate/repository/MpaDbRepository.java | 45 +++ .../repository/UserDbRepository.java | 131 +++++++ .../repository/contracts/FilmRepository.java | 6 +- .../contracts/FriendshipRepository.java | 15 + .../repository/contracts/GenreRepository.java | 16 + .../repository/contracts/LikeRepository.java | 8 + .../repository/contracts/MpaRepository.java | 11 + .../repository/contracts/UserRepository.java | 8 - .../repository/mappers/FilmRowMapper.java | 28 ++ .../repository/mappers/GenreRowMapper.java | 18 + .../repository/mappers/MpaRowMapper.java | 18 + .../repository/mappers/UserRowMapper.java | 22 ++ src/main/resources/application.properties | 6 + src/main/resources/application.yaml | 1 - src/main/resources/data.sql | 14 + src/main/resources/schema.sql | 52 +++ 26 files changed, 994 insertions(+), 15 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/InternalErrorException.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FriendshipRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/contracts/GenreRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/contracts/LikeRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/contracts/MpaRepository.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java create mode 100644 src/main/resources/application.properties delete mode 100644 src/main/resources/application.yaml create mode 100644 src/main/resources/data.sql create mode 100644 src/main/resources/schema.sql diff --git a/pom.xml b/pom.xml index 4e78c94..5beaf1d 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,15 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + org.projectlombok diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/InternalErrorException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/InternalErrorException.java new file mode 100644 index 0000000..cf2d3a6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/InternalErrorException.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.exception; + +public class InternalErrorException extends RuntimeException { + public InternalErrorException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java index 679fd03..4e0db6a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java @@ -1,8 +1,10 @@ package ru.yandex.practicum.filmorate.model; +import lombok.Builder; import lombok.Data; @Data +@Builder public class Genre { private Long id; private String title; 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 1297784..4197347 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -1,8 +1,10 @@ package ru.yandex.practicum.filmorate.model; +import lombok.Builder; import lombok.Data; @Data +@Builder public class Mpa { private Long id; private String title; diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java new file mode 100644 index 0000000..895b492 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java @@ -0,0 +1,320 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +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.Repository; +import ru.yandex.practicum.filmorate.exception.InternalErrorException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; +import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; +import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; +import ru.yandex.practicum.filmorate.repository.mappers.FilmRowMapper; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.*; +import java.util.stream.Collectors; + +@Repository +@RequiredArgsConstructor +@Primary +public class FilmDbRepository implements FilmRepository { + public static final String TABLE_NAME = "films"; + private static final String FILM_GENRE_TABLE_NAME = "film_genre"; + + private final JdbcTemplate jdbc; + private final GenreRepository genreRepository; + private final MpaRepository mpaRepository; + private final FilmRowMapper mapper = new FilmRowMapper(); + + @Override + public List getAll() { + List films = jdbc.query( + "SELECT * FROM ? ORDER BY name", + mapper, + TABLE_NAME + ); + + if (!films.isEmpty()) { + fillGenreForFilmList(films); + } + + return films; + } + + @Override + public Film findById(final Long id) { + try { + Film film = jdbc.queryForObject( + "SELECT * FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ); + + fillGenreForFilm(film); + + return film; + } catch (RuntimeException e) { + throw new NotFoundException("Film not found"); + } + } + + @Override + public Film create(final Film film) { + KeyHolder keyHolder = new GeneratedKeyHolder(); + Mpa mpa = getMpaByObject(film.getMpa()); + + try { + jdbc.update( + conn -> { + PreparedStatement stmt = conn.prepareStatement( + "INSERT INTO ? (mpa_id, name, description, release_date, duration) " + + "VALUES (?, ?, ?, ?, ?)", + Statement.RETURN_GENERATED_KEYS + ); + + stmt.setString(1, TABLE_NAME); + stmt.setLong(2, mpa == null ? 0L : mpa.getId()); + stmt.setString(3, film.getName()); + stmt.setString(4, film.getDescription()); + stmt.setDate(5, Date.valueOf(film.getReleaseDate())); + stmt.setInt(6, film.getDuration()); + + return stmt; + }, + keyHolder + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on saving data"); + } + + Long id = keyHolder.getKeyAs(Long.class); + + if (id == null) { + throw new InternalErrorException("Error on saving data"); + } + + film.setId(id); + addRelations(film); + + return film; + } + + @Override + public Film update(final Film film) { + Mpa mpa = getMpaByObject(film.getMpa()); + int updated = 0; + + try { + updated = jdbc.update( + "UPDATE ? " + + "SET mpa_id = ?, name = ?, description = ?, release_date = ?, duration = ? " + + "WHERE id = ?", + TABLE_NAME, + mpa == null ? 0L : mpa.getId(), + film.getName(), + film.getDescription(), + Date.valueOf(film.getReleaseDate()), + film.getDuration(), + film.getId() + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on updating data"); + } + + if (updated < 1) { + throw new InternalErrorException("Error on updating data"); + } + + syncFilmGenres(film); + + return findById(film.getId()); + } + + @Override + public List getPopular(int count) { + return jdbc.query( + "SELECT f.*, COUNT(l.id) like_cnt " + + "FROM ? AS f " + + "LEFT JOIN ? as l ON (l.film_id = f.id) " + + "GROUP BY f.id " + + "ORDER BY likes DESC " + + "LIMIT ?", + mapper, + TABLE_NAME, + LikeDbRepository.TABLE_NAME, + count + ); + } + + @Override + public boolean isExists(Long id) { + try { + return jdbc.queryForObject( + "SELECT id FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ) != null; + } catch (RuntimeException e) { + return false; + } + } + + private Mpa getMpaByObject(Mpa mpa) { + if (mpa == null || mpa.getId() == null) { + return null; + } + + try { + return mpaRepository.findById(mpa.getId()); + } catch (RuntimeException ignored) { + return null; + } + } + + private void addRelations(Film film) { + Set genres = film.getGenres().stream().filter(Objects::nonNull).collect(Collectors.toSet()); + + if (genres.isEmpty()) { + return; + } + + try { + jdbc.batchUpdate( + "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)", + new BatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) throws SQLException { + Genre genre = genres.iterator().next(); + ps.setLong(1, film.getId()); + ps.setLong(2, genre.getId()); + } + + public int getBatchSize() { + return genres.size(); + } + } + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on saving film genre"); + } + } + + private void syncFilmGenres(Film film) { + if (film == null) { + return; + } + + List availableIds = genreRepository.getAll().stream().map(Genre::getId).toList(); + List deleteRows = new ArrayList<>(); + List newGenres = film.getGenres() + .stream() + .filter( + el -> Objects.nonNull(el) + && Objects.nonNull(el.getId()) + && availableIds.contains(el.getId()) + ) + .map(Genre::getId) + .toList(); + + SqlRowSet curGenres = jdbc.queryForRowSet( + "SELECT id, genre_id FROM ? WHERE film_id = ?", + FILM_GENRE_TABLE_NAME, + film.getId() + ); + + while (curGenres.next()) { + Long id = curGenres.getLong("id"); + Long genreId = curGenres.getLong("genre_id"); + + if (newGenres.contains(genreId)) { + newGenres.remove(genreId); + continue; + } + + deleteRows.add(id); + } + + if (!deleteRows.isEmpty()) { + try { + jdbc.update( + "DELETE FROM ? WHERE id IN (?)", + FILM_GENRE_TABLE_NAME, + String.join(", ", deleteRows.stream().map(String::valueOf).toList()) + ); + } catch (RuntimeException ignored) { + } + } + + if (newGenres.isEmpty()) { + return; + } + + try { + jdbc.batchUpdate( + "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)", + new BatchPreparedStatementSetter() { + public void setValues(PreparedStatement ps, int i) throws SQLException { + Long genreId = newGenres.iterator().next(); + ps.setLong(1, film.getId()); + ps.setLong(2, genreId); + } + + public int getBatchSize() { + return newGenres.size(); + } + } + ); + } catch (RuntimeException ignored) { + } + } + +// private void deleteFilmGenres(Long filmId) { +// if (filmId == null) { +// return; +// } +// +// try { +// jdbc.update("DELETE FROM film_genre WHERE film_id = ?", filmId); +// } catch (DataAccessException e) { +// throw new InternalErrorException(e.getMessage()); +// } +// } + + private void fillGenreForFilm(Film film) { + if (film == null) { + return; + } + + film.getGenres().addAll(genreRepository.findByFilmId(film.getId())); + } + + private void fillGenreForFilmList(List films) { + if (films.isEmpty()) { + return; + } + + Map> genres = genreRepository.findByFilmId( + films.stream().map(Film::getId).toList() + ); + + if (genres.isEmpty()) { + return; + } + + films.forEach((Film film) -> film.getGenres().addAll( + genres.getOrDefault(film.getId(), new ArrayList<>()) + )); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java new file mode 100644 index 0000000..ec1160d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java @@ -0,0 +1,106 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.InternalErrorException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.repository.contracts.FriendshipRepository; +import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; +import ru.yandex.practicum.filmorate.repository.mappers.UserRowMapper; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class FriendshipDbRepository implements FriendshipRepository { + + public static final String TABLE_NAME = "friendship"; + + private final JdbcTemplate jdbc; + private final UserRepository userRepository; + private final UserRowMapper userRowMapper = new UserRowMapper(); + + @Override + public void addFriend(final Long userId, final Long friendId) { + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!userRepository.isExists(friendId)) { + throw new NotFoundException("Friend not found"); + } + + try { + jdbc.update( + "INSERT INTO ? (user_id, friend_id, active) VALUES (?, ?, ?)", + TABLE_NAME, + userId, + friendId, + false + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on adding friend"); + } + } + + @Override + public void deleteFriend(final Long userId, final Long friendId) { + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!userRepository.isExists(friendId)) { + throw new NotFoundException("Friend not found"); + } + + try { + jdbc.update( + "DELETE FROM ? WHERE user_id = ? AND friend_id = ?", + TABLE_NAME, + userId, + friendId + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on deleting friend"); + } + } + + @Override + public List findFriendsByUserId(final Long userId) { + try { + return jdbc.query( + "SELECT f.* " + + "FROM ? AS f " + + "WHERE f.id IN (SELECT fs.friend_id FROM ? AS fs WHERE fs.user_id = ?)", + userRowMapper, + UserDbRepository.TABLE_NAME, + TABLE_NAME, + userId + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on getting user friends"); + } + } + + @Override + public List findCommonFriends(Long userId, Long friendId) { + try { + return jdbc.query( + "SELECT f.* " + + "FROM ? AS f " + + "WHERE f.id IN (SELECT fs1.friend_id FROM ? AS fs1 WHERE fs1.user_id = ?) " + + "AND f.id IN (SELECT fs2.friend_id FROM ? AS fs2 WHERE fs2.user_id = ?)", + userRowMapper, + UserDbRepository.TABLE_NAME, + TABLE_NAME, + userId, + TABLE_NAME, + friendId + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on getting user friends"); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java new file mode 100644 index 0000000..1f43991 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java @@ -0,0 +1,93 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; +import ru.yandex.practicum.filmorate.repository.mappers.GenreRowMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +@RequiredArgsConstructor +@Primary +public class GenreDbRepository implements GenreRepository { + public static final String TABLE_NAME = "genres"; + private static final String FILM_GENRE_TABLE_NAME = "film_genre"; + + private final JdbcTemplate jdbc; + private final GenreRowMapper mapper = new GenreRowMapper(); + + @Override + public List getAll() { + return jdbc.query( + "SELECT * FROM ? ORDER BY title", + mapper, + TABLE_NAME + ); + } + + @Override + public List findByFilmId(final Long filmId) { + return jdbc.query( + "SELECT g.*" + + "FROM ? AS g " + + "INNER JOIN ? AS fg ON fg.genre_id = g.id " + + "WHERE fg.film_id = ?", + mapper, + TABLE_NAME, + FILM_GENRE_TABLE_NAME, + filmId + ); + } + + @Override + public Map> findByFilmId(final List filmIds) { + Map> genresMap = new HashMap<>(); + jdbc.queryForList( + "SELECT g.*, fg.film_id " + + "FROM ? AS g " + + "INNER JOIN ? AS fg ON fg.genre_id = g.id " + + "WHERE fg.film_id IN (?)", + TABLE_NAME, + FILM_GENRE_TABLE_NAME, + String.join( + ",", + filmIds.stream().map(String::valueOf).toList() + ) + ).forEach(v -> { + Genre genre = Genre.builder() + .id((Long)v.get("id")) + .title((String)v.get("title")) + .build(); + + Long filmId = (Long)v.get("film_id"); + List genres = genresMap.getOrDefault(filmId, new ArrayList<>()); + genres.add(genre); + + genresMap.put(filmId, genres); + }); + + return genresMap; + } + + @Override + public Genre findById(final Long id) { + try { + return jdbc.queryForObject( + "SELECT * FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ); + } catch (RuntimeException e) { + throw new NotFoundException("Genre not found"); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java index 6a72eec..41e5848 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; @@ -13,7 +14,7 @@ import java.util.Optional; import java.util.stream.Collectors; -@Component +@Repository @RequiredArgsConstructor public class InMemoryFilmRepository implements FilmRepository { private static Long id = 1L; diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java index 332b7a4..9f496f9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java @@ -1,13 +1,14 @@ package ru.yandex.practicum.filmorate.repository; import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import java.util.*; -@Component +@Repository public class InMemoryUserRepository implements UserRepository { private static Long id = 1L; private final Map users = new HashMap<>(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java new file mode 100644 index 0000000..4aec3ae --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java @@ -0,0 +1,65 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.InternalErrorException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; +import ru.yandex.practicum.filmorate.repository.contracts.LikeRepository; +import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; + +@Repository +@RequiredArgsConstructor +@Primary +public class LikeDbRepository implements LikeRepository { + public static final String TABLE_NAME = "film_like"; + + private final JdbcTemplate jdbc; + private final UserRepository userRepository; + private final FilmRepository filmRepository; + + @Override + public void addLike(final Long filmId, final Long userId) { + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!filmRepository.isExists(filmId)) { + throw new NotFoundException("Film not found"); + } + + try { + jdbc.update( + "INSERT INTO ? (film_id, user_id) VALUES (?, ?)", + TABLE_NAME, + filmId, + userId + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on adding like"); + } + } + + @Override + public void deleteLike(final Long filmId, final Long userId) { + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!filmRepository.isExists(filmId)) { + throw new NotFoundException("Film not found"); + } + + try { + jdbc.update( + "DELETE FROM ? WHERE film_id = ? AND user_id = ?", + TABLE_NAME, + filmId, + userId + ); + } catch (RuntimeException ignored) { + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java new file mode 100644 index 0000000..7539843 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java @@ -0,0 +1,45 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; +import ru.yandex.practicum.filmorate.repository.mappers.MpaRowMapper; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +@Primary +public class MpaDbRepository implements MpaRepository { + public static final String TABLE_NAME = "mpas"; + + private final JdbcTemplate jdbc; + private final MpaRowMapper mapper = new MpaRowMapper(); + + @Override + public List getAll() { + return jdbc.query( + "SELECT * FROM ? ORDER BY title", + mapper, + TABLE_NAME + ); + } + + @Override + public Mpa findById(final Long id) { + try { + return jdbc.queryForObject( + "SELECT * FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ); + } catch (RuntimeException e) { + throw new NotFoundException("Mpa not found"); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java new file mode 100644 index 0000000..a7d7cf3 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java @@ -0,0 +1,131 @@ +package ru.yandex.practicum.filmorate.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.InternalErrorException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; +import ru.yandex.practicum.filmorate.repository.mappers.UserRowMapper; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.*; + +@Repository +@RequiredArgsConstructor +@Primary +public class UserDbRepository implements UserRepository { + public static final String TABLE_NAME = "users"; + private final JdbcTemplate jdbc; + + private final UserRowMapper mapper = new UserRowMapper(); + + @Override + public List getAll() { + return jdbc.query( + "SELECT * FROM ? ORDER BY name", + mapper, + TABLE_NAME + ); + } + + public User findById(final Long id) { + try { + return jdbc.queryForObject( + "SELECT * FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ); + } catch (RuntimeException e) { + throw new NotFoundException("User not found"); + } + } + + @Override + public User create(final User user) { + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + jdbc.update( + conn -> { + PreparedStatement stmt = conn.prepareStatement( + "INSERT INTO ? (email, login, name, birthday, password) " + + "VALUES (?, ?, ?, ?, ?)", + Statement.RETURN_GENERATED_KEYS + ); + + stmt.setString(1, TABLE_NAME); + stmt.setString(2, user.getEmail()); + stmt.setString(3, user.getLogin()); + stmt.setString(4, user.getName()); + stmt.setDate(5, Date.valueOf(user.getBirthday())); + stmt.setString(6, user.getPassword()); + + return stmt; + }, + keyHolder + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on saving data"); + } + + Long id = keyHolder.getKeyAs(Long.class); + + if (id == null) { + throw new InternalErrorException("Error on saving data"); + } + + user.setId(id); + + return user; + } + + @Override + public User update(final User user) { + int updated = 0; + + try { + updated = jdbc.update( + "UPDATE ? " + + "SET email = ?, login = ?, name = ?, birthdat = ?, password = ? " + + "WHERE id = ?", + TABLE_NAME, + user.getEmail(), + user.getLogin(), + user.getName(), + Date.valueOf(user.getBirthday()), + user.getPassword(), + user.getId() + ); + } catch (RuntimeException e) { + throw new InternalErrorException("Error on updating data"); + } + + if (updated < 1) { + throw new InternalErrorException("Error on updating data"); + } + + return user; + } + + @Override + public boolean isExists(Long id) { + try { + return jdbc.queryForObject( + "SELECT id FROM ? WHERE id = ?", + mapper, + TABLE_NAME, + id + ) != null; + } catch (RuntimeException e) { + return false; + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FilmRepository.java index 8b49390..0cac72a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FilmRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FilmRepository.java @@ -13,9 +13,7 @@ public interface FilmRepository { Film update(Film film); - void addLike(Long id, Long userId); - - void deleteLike(Long id, Long userId); - List getPopular(int count); + + boolean isExists(Long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FriendshipRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FriendshipRepository.java new file mode 100644 index 0000000..acaaa71 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/FriendshipRepository.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.repository.contracts; + +import ru.yandex.practicum.filmorate.model.User; + +import java.util.List; + +public interface FriendshipRepository { + void addFriend(final Long userId, final Long friendId); + + void deleteFriend(final Long userId, final Long friendId); + + List findFriendsByUserId(final Long userId); + + List findCommonFriends(Long userId, Long friendId); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/GenreRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/GenreRepository.java new file mode 100644 index 0000000..063ab30 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/GenreRepository.java @@ -0,0 +1,16 @@ +package ru.yandex.practicum.filmorate.repository.contracts; + +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; +import java.util.Map; + +public interface GenreRepository { + List getAll(); + + List findByFilmId(Long filmId); + + Map> findByFilmId(List filmIds); + + Genre findById(Long id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/LikeRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/LikeRepository.java new file mode 100644 index 0000000..0f9c644 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/LikeRepository.java @@ -0,0 +1,8 @@ +package ru.yandex.practicum.filmorate.repository.contracts; + +public interface LikeRepository { + + void addLike(final Long id, final Long userId); + + void deleteLike(final Long id, final Long userId); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/MpaRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/MpaRepository.java new file mode 100644 index 0000000..bb2a292 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/MpaRepository.java @@ -0,0 +1,11 @@ +package ru.yandex.practicum.filmorate.repository.contracts; + +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.util.List; + +public interface MpaRepository { + List getAll(); + + Mpa findById(Long id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/UserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/UserRepository.java index 706a3b8..ac35e01 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/UserRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/contracts/UserRepository.java @@ -13,13 +13,5 @@ public interface UserRepository { User update(User user); - void addFriend(Long userId, Long friendId); - - void deleteFriend(Long userId, Long friendId); - - List findFriendsByUserId(Long userId); - - List findCommonFriends(Long userId, Long otherUserId); - boolean isExists(Long id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java new file mode 100644 index 0000000..76cc15e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java @@ -0,0 +1,28 @@ +package ru.yandex.practicum.filmorate.repository.mappers; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class FilmRowMapper implements RowMapper { + + @Override + public Film mapRow(ResultSet rs, int rowNum) throws SQLException { + return Film.builder() + .id(rs.getLong("id")) + .name(rs.getString("name")) + .description(rs.getString("description")) + .duration(rs.getInt("duration")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .mpa( + Mpa.builder() + .id(rs.getLong("mpa_id")) +// .title(rs.getString("mpa_title")) + .build() + ) + .build(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java new file mode 100644 index 0000000..f5af801 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java @@ -0,0 +1,18 @@ +package ru.yandex.practicum.filmorate.repository.mappers; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.Genre; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class GenreRowMapper implements RowMapper { + + @Override + public Genre mapRow(ResultSet rs, int rowNum) throws SQLException { + return Genre.builder() + .id(rs.getLong("id")) + .title(rs.getString("title")) + .build(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java new file mode 100644 index 0000000..06e6c24 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java @@ -0,0 +1,18 @@ +package ru.yandex.practicum.filmorate.repository.mappers; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MpaRowMapper implements RowMapper { + + @Override + public Mpa mapRow(ResultSet rs, int rowNum) throws SQLException { + return Mpa.builder() + .id(rs.getLong("id")) + .title(rs.getString("title")) + .build(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java new file mode 100644 index 0000000..10e8cbd --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java @@ -0,0 +1,22 @@ +package ru.yandex.practicum.filmorate.repository.mappers; + +import org.springframework.jdbc.core.RowMapper; +import ru.yandex.practicum.filmorate.model.User; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class UserRowMapper implements RowMapper { + + @Override + public User mapRow(ResultSet rs, int rowNum) throws SQLException { + return User.builder() + .id(rs.getLong("id")) + .name(rs.getString("name")) + .login(rs.getString("login")) + .email(rs.getString("email")) + .password(rs.getString("password")) + .birthday(rs.getDate("birthday").toLocalDate()) + .build(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..cef16d7 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,6 @@ +spring.sql.init.mode=always +# ? jdbc-url ???????, ??? ?????? ????? ????????? ? ???? +spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml deleted file mode 100644 index 1d1b4bf..0000000 --- a/src/main/resources/application.yaml +++ /dev/null @@ -1 +0,0 @@ -logging.level.org.zalando.logbook: TRACE diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..9352059 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,14 @@ +INSERT INTO mpas (title) +VALUES ('G'), + ('PG'), + ('PG-13'), + ('R'), + ('NC-17'); + +INSERT INTO genres (title) +VALUES ('Комедия'), + ('Драма'), + ('Мультфильм'), + ('Триллер'), + ('Документальный'), + ('Боевик'); \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..d0d2844 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,52 @@ +CREATE TABLE IF NOT EXISTS films ( + id long generated by default as identity primary key, + mpa_id long not null, + name varchar not null, + description text, + release_date date, + duration int not null default 0 +); + +CREATE TABLE IF NOT EXISTS mpas ( + id long generated by default as identity primary key, + title varchar not null +); + +CREATE TABLE IF NOT EXISTS genres ( + id long generated by default as identity primary key, + title varchar not null +); + +CREATE TABLE IF NOT EXISTS users ( + id long generated by default as identity primary key, + email varchar not null unique, + login varchar not null unique, + name varchar not null, + birthday date, + password varchar not null +); + +CREATE TABLE IF NOT EXISTS film_genre ( + film_id long, + genre_id long, + foreign key (film_id) references films (id) on DELETE cascade, + foreign key (genre_id) references genres (id) on DELETE cascade, + primary key (film_id, genre_id) +); + +CREATE TABLE IF NOT EXISTS film_like ( + film_id long, + user_id long, + foreign key (film_id) references films (id) on DELETE cascade, + foreign key (user_id) references users (id) on DELETE cascade, + primary key (film_id, user_id) +); + +CREATE TABLE IF NOT EXISTS friendship ( + user_id long, + friend_id long, + active boolean not null default false, + foreign key (user_id) references users (id) on DELETE cascade, + foreign key (friend_id) references users (id) on DELETE cascade, + primary key (user_id, friend_id) +); \ No newline at end of file From 0033a9aeba515789527ad3f466746ec125d3a52e Mon Sep 17 00:00:00 2001 From: Alexander Krutov Date: Tue, 14 Jan 2025 01:24:49 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=B2=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=81=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/GenreController.java | 29 ++++ .../filmorate/controller/MpaController.java | 32 +++++ .../practicum/filmorate/model/Genre.java | 4 +- .../yandex/practicum/filmorate/model/Mpa.java | 4 +- .../practicum/filmorate/model/User.java | 2 +- .../repository/FilmDbRepository.java | 133 +++++------------- .../repository/FriendshipDbRepository.java | 23 ++- .../repository/GenreDbRepository.java | 22 ++- .../repository/InMemoryFilmRepository.java | 99 ------------- .../repository/InMemoryUserRepository.java | 129 ----------------- .../repository/LikeDbRepository.java | 6 +- .../filmorate/repository/MpaDbRepository.java | 8 +- .../repository/UserDbRepository.java | 37 +++-- .../repository/mappers/FilmRowMapper.java | 2 +- .../repository/mappers/GenreRowMapper.java | 2 +- .../repository/mappers/MpaRowMapper.java | 2 +- .../repository/mappers/UserRowMapper.java | 1 - .../filmorate/service/FilmService.java | 33 ++++- .../filmorate/service/GenreService.java | 22 +++ .../filmorate/service/MpaService.java | 22 +++ .../filmorate/service/UserService.java | 10 +- src/main/resources/application.properties | 2 +- src/main/resources/data.sql | 4 +- src/main/resources/schema.sql | 10 +- .../filmorate/FilmControllerTests.java | 13 +- .../filmorate/UserControllerTests.java | 5 +- 26 files changed, 244 insertions(+), 412 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.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/MpaService.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java new file mode 100644 index 0000000..96defa2 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -0,0 +1,29 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.service.GenreService; + +import java.util.Collection; + +@RestController +@RequestMapping("/genres") +public class GenreController { + private final GenreService genreService; + + @Autowired + public GenreController(final GenreService genreService) { + this.genreService = genreService; + } + + @GetMapping + public Collection list() { + return genreService.getList(); + } + + @GetMapping("/{id}") + public Genre getById(@PathVariable final Long id) { + return genreService.getById(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 new file mode 100644 index 0000000..f4bfb36 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -0,0 +1,32 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Autowired; +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.MpaService; + +import java.util.Collection; + +@RestController +@RequestMapping("/mpa") +public class MpaController { + private final MpaService mpaService; + + @Autowired + public MpaController(final MpaService mpaService) { + this.mpaService = mpaService; + } + + @GetMapping + public Collection list() { + return mpaService.getList(); + } + + @GetMapping("/{id}") + public Mpa getById(@PathVariable final Long id) { + return mpaService.getById(id); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java index 4e0db6a..4f5fe0a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.model; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Builder; import lombok.Data; @@ -7,5 +8,6 @@ @Builder public class Genre { private Long id; - private String title; + @JsonInclude(value = JsonInclude.Include.NON_NULL) + private String name; } 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 4197347..3bb4e2d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.model; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Builder; import lombok.Data; @@ -7,5 +8,6 @@ @Builder public class Mpa { private Long id; - private String title; + @JsonInclude(value = JsonInclude.Include.NON_NULL) + private String name; } 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 e91ddd3..fbe2a49 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -15,6 +15,6 @@ public class User { private String login; private String name; private LocalDate birthday; - private String password; +// private String password; private final Set friends = new HashSet<>(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java index 895b492..6e8b571 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java @@ -1,12 +1,12 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.BatchPreparedStatementSetter; 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.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -25,6 +25,7 @@ import java.util.*; import java.util.stream.Collectors; +@Slf4j @Repository @RequiredArgsConstructor @Primary @@ -40,9 +41,8 @@ public class FilmDbRepository implements FilmRepository { @Override public List getAll() { List films = jdbc.query( - "SELECT * FROM ? ORDER BY name", - mapper, - TABLE_NAME + "SELECT * FROM " + TABLE_NAME, + mapper ); if (!films.isEmpty()) { @@ -56,9 +56,8 @@ public List getAll() { public Film findById(final Long id) { try { Film film = jdbc.queryForObject( - "SELECT * FROM ? WHERE id = ?", + "SELECT * FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ); @@ -79,23 +78,23 @@ public Film create(final Film film) { jdbc.update( conn -> { PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO ? (mpa_id, name, description, release_date, duration) " + + "INSERT INTO " + TABLE_NAME + " (mpa_id, name, description, release_date, duration) " + "VALUES (?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS ); - stmt.setString(1, TABLE_NAME); - stmt.setLong(2, mpa == null ? 0L : mpa.getId()); - stmt.setString(3, film.getName()); - stmt.setString(4, film.getDescription()); - stmt.setDate(5, Date.valueOf(film.getReleaseDate())); - stmt.setInt(6, film.getDuration()); + stmt.setLong(1, mpa == null ? 0L : mpa.getId()); + stmt.setString(2, film.getName()); + stmt.setString(3, film.getDescription()); + stmt.setDate(4, Date.valueOf(film.getReleaseDate())); + stmt.setInt(5, film.getDuration()); return stmt; }, keyHolder ); } catch (RuntimeException e) { + log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving data"); } @@ -118,10 +117,9 @@ public Film update(final Film film) { try { updated = jdbc.update( - "UPDATE ? " + + "UPDATE " + TABLE_NAME + " " + "SET mpa_id = ?, name = ?, description = ?, release_date = ?, duration = ? " + "WHERE id = ?", - TABLE_NAME, mpa == null ? 0L : mpa.getId(), film.getName(), film.getDescription(), @@ -130,14 +128,16 @@ public Film update(final Film film) { film.getId() ); } catch (RuntimeException e) { + log.error(e.getMessage(), e); throw new InternalErrorException("Error on updating data"); } if (updated < 1) { - throw new InternalErrorException("Error on updating data"); + throw new NotFoundException("Film not found"); } - syncFilmGenres(film); + deleteFilmGenres(film.getId()); + addRelations(film); return findById(film.getId()); } @@ -145,15 +145,13 @@ public Film update(final Film film) { @Override public List getPopular(int count) { return jdbc.query( - "SELECT f.*, COUNT(l.id) like_cnt " + - "FROM ? AS f " + - "LEFT JOIN ? as l ON (l.film_id = f.id) " + + "SELECT f.*, COUNT(l.film_id) like_cnt " + + "FROM " + TABLE_NAME + " AS f " + + "LEFT JOIN " + LikeDbRepository.TABLE_NAME + " as l ON (l.film_id = f.id) " + "GROUP BY f.id " + - "ORDER BY likes DESC " + + "ORDER BY like_cnt DESC " + "LIMIT ?", mapper, - TABLE_NAME, - LikeDbRepository.TABLE_NAME, count ); } @@ -162,9 +160,8 @@ public List getPopular(int count) { public boolean isExists(Long id) { try { return jdbc.queryForObject( - "SELECT id FROM ? WHERE id = ?", + "SELECT id FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ) != null; } catch (RuntimeException e) { @@ -191,12 +188,14 @@ private void addRelations(Film film) { return; } + Iterator genreIterator = genres.iterator(); + try { jdbc.batchUpdate( - "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)", + "INSERT INTO " + FILM_GENRE_TABLE_NAME + " (film_id, genre_id) VALUES (?, ?)", new BatchPreparedStatementSetter() { public void setValues(PreparedStatement ps, int i) throws SQLException { - Genre genre = genres.iterator().next(); + Genre genre = genreIterator.next(); ps.setLong(1, film.getId()); ps.setLong(2, genre.getId()); } @@ -207,91 +206,23 @@ public int getBatchSize() { } ); } catch (RuntimeException e) { + log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving film genre"); } } - private void syncFilmGenres(Film film) { - if (film == null) { - return; - } - - List availableIds = genreRepository.getAll().stream().map(Genre::getId).toList(); - List deleteRows = new ArrayList<>(); - List newGenres = film.getGenres() - .stream() - .filter( - el -> Objects.nonNull(el) - && Objects.nonNull(el.getId()) - && availableIds.contains(el.getId()) - ) - .map(Genre::getId) - .toList(); - - SqlRowSet curGenres = jdbc.queryForRowSet( - "SELECT id, genre_id FROM ? WHERE film_id = ?", - FILM_GENRE_TABLE_NAME, - film.getId() - ); - - while (curGenres.next()) { - Long id = curGenres.getLong("id"); - Long genreId = curGenres.getLong("genre_id"); - - if (newGenres.contains(genreId)) { - newGenres.remove(genreId); - continue; - } - - deleteRows.add(id); - } - - if (!deleteRows.isEmpty()) { - try { - jdbc.update( - "DELETE FROM ? WHERE id IN (?)", - FILM_GENRE_TABLE_NAME, - String.join(", ", deleteRows.stream().map(String::valueOf).toList()) - ); - } catch (RuntimeException ignored) { - } - } - - if (newGenres.isEmpty()) { + private void deleteFilmGenres(Long filmId) { + if (filmId == null) { return; } try { - jdbc.batchUpdate( - "INSERT INTO film_genre (film_id, genre_id) VALUES (?, ?)", - new BatchPreparedStatementSetter() { - public void setValues(PreparedStatement ps, int i) throws SQLException { - Long genreId = newGenres.iterator().next(); - ps.setLong(1, film.getId()); - ps.setLong(2, genreId); - } - - public int getBatchSize() { - return newGenres.size(); - } - } - ); - } catch (RuntimeException ignored) { + jdbc.update("DELETE FROM " + FILM_GENRE_TABLE_NAME + " WHERE film_id = ?", filmId); + } catch (RuntimeException e) { + throw new InternalErrorException(e.getMessage()); } } -// private void deleteFilmGenres(Long filmId) { -// if (filmId == null) { -// return; -// } -// -// try { -// jdbc.update("DELETE FROM film_genre WHERE film_id = ?", filmId); -// } catch (DataAccessException e) { -// throw new InternalErrorException(e.getMessage()); -// } -// } - private void fillGenreForFilm(Film film) { if (film == null) { return; diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java index ec1160d..9a8e8f0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java @@ -34,8 +34,7 @@ public void addFriend(final Long userId, final Long friendId) { try { jdbc.update( - "INSERT INTO ? (user_id, friend_id, active) VALUES (?, ?, ?)", - TABLE_NAME, + "INSERT INTO " + TABLE_NAME + " (user_id, friend_id, active) VALUES (?, ?, ?)", userId, friendId, false @@ -57,8 +56,7 @@ public void deleteFriend(final Long userId, final Long friendId) { try { jdbc.update( - "DELETE FROM ? WHERE user_id = ? AND friend_id = ?", - TABLE_NAME, + "DELETE FROM " + TABLE_NAME + " WHERE user_id = ? AND friend_id = ?", userId, friendId ); @@ -72,11 +70,11 @@ public List findFriendsByUserId(final Long userId) { try { return jdbc.query( "SELECT f.* " + - "FROM ? AS f " + - "WHERE f.id IN (SELECT fs.friend_id FROM ? AS fs WHERE fs.user_id = ?)", + "FROM " + UserDbRepository.TABLE_NAME + " AS f " + + "WHERE f.id IN (" + + "SELECT fs.friend_id FROM " + TABLE_NAME + " AS fs WHERE fs.user_id = ?" + + ")", userRowMapper, - UserDbRepository.TABLE_NAME, - TABLE_NAME, userId ); } catch (RuntimeException e) { @@ -89,14 +87,11 @@ public List findCommonFriends(Long userId, Long friendId) { try { return jdbc.query( "SELECT f.* " + - "FROM ? AS f " + - "WHERE f.id IN (SELECT fs1.friend_id FROM ? AS fs1 WHERE fs1.user_id = ?) " + - "AND f.id IN (SELECT fs2.friend_id FROM ? AS fs2 WHERE fs2.user_id = ?)", + "FROM " + UserDbRepository.TABLE_NAME + " AS f " + + "WHERE f.id IN (SELECT fs1.friend_id FROM " + TABLE_NAME + " AS fs1 WHERE fs1.user_id = ?) " + + "AND f.id IN (SELECT fs2.friend_id FROM " + TABLE_NAME + " AS fs2 WHERE fs2.user_id = ?)", userRowMapper, - UserDbRepository.TABLE_NAME, - TABLE_NAME, userId, - TABLE_NAME, friendId ); } catch (RuntimeException e) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java index 1f43991..8314527 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java @@ -27,9 +27,8 @@ public class GenreDbRepository implements GenreRepository { @Override public List getAll() { return jdbc.query( - "SELECT * FROM ? ORDER BY title", - mapper, - TABLE_NAME + "SELECT * FROM " + TABLE_NAME, + mapper ); } @@ -37,12 +36,10 @@ public List getAll() { public List findByFilmId(final Long filmId) { return jdbc.query( "SELECT g.*" + - "FROM ? AS g " + - "INNER JOIN ? AS fg ON fg.genre_id = g.id " + + "FROM " + TABLE_NAME + " AS g " + + "INNER JOIN " + FILM_GENRE_TABLE_NAME + " AS fg ON fg.genre_id = g.id " + "WHERE fg.film_id = ?", mapper, - TABLE_NAME, - FILM_GENRE_TABLE_NAME, filmId ); } @@ -52,11 +49,9 @@ public Map> findByFilmId(final List filmIds) { Map> genresMap = new HashMap<>(); jdbc.queryForList( "SELECT g.*, fg.film_id " + - "FROM ? AS g " + - "INNER JOIN ? AS fg ON fg.genre_id = g.id " + + "FROM " + TABLE_NAME + " AS g " + + "INNER JOIN " + FILM_GENRE_TABLE_NAME + " AS fg ON fg.genre_id = g.id " + "WHERE fg.film_id IN (?)", - TABLE_NAME, - FILM_GENRE_TABLE_NAME, String.join( ",", filmIds.stream().map(String::valueOf).toList() @@ -64,7 +59,7 @@ public Map> findByFilmId(final List filmIds) { ).forEach(v -> { Genre genre = Genre.builder() .id((Long)v.get("id")) - .title((String)v.get("title")) + .name((String)v.get("name")) .build(); Long filmId = (Long)v.get("film_id"); @@ -81,9 +76,8 @@ public Map> findByFilmId(final List filmIds) { public Genre findById(final Long id) { try { return jdbc.queryForObject( - "SELECT * FROM ? WHERE id = ?", + "SELECT * FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ); } catch (RuntimeException e) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java deleted file mode 100644 index 41e5848..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryFilmRepository.java +++ /dev/null @@ -1,99 +0,0 @@ -package ru.yandex.practicum.filmorate.repository; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; -import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -@Repository -@RequiredArgsConstructor -public class InMemoryFilmRepository implements FilmRepository { - private static Long id = 1L; - private final Map films = new HashMap<>(); - private final UserRepository userRepository; - - public List getAll() { - return films.values().stream().toList(); - } - - public Film findById(final Long id) { - return Optional - .ofNullable(films.get(id)) - .orElseThrow(() -> new NotFoundException("Film not found")); - } - - @Override - public Film create(final Film film) { - Film newFilm = Film.builder() - .id(getNextId()) - .name(film.getName()) - .description(film.getDescription()) - .releaseDate(film.getReleaseDate()) - .duration(film.getDuration()) - .build(); - - films.put(newFilm.getId(), newFilm); - - return newFilm; - } - - @Override - public Film update(final Film film) { - Film updatedFilm = findById(film.getId()); - - updatedFilm.setName(film.getName()); - updatedFilm.setDescription(film.getDescription()); - updatedFilm.setReleaseDate(film.getReleaseDate()); - updatedFilm.setDuration(film.getDuration()); - - films.put(updatedFilm.getId(), updatedFilm); - - return updatedFilm; - } - - @Override - public void addLike(final Long id, final Long userId) { - Film film = findById(id); - - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - film.getLikes().add(userId); - films.put(id, film); - } - - @Override - public void deleteLike(final Long id, final Long userId) { - Film film = findById(id); - - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - film.getLikes().remove(userId); - films.put(id, film); - } - - @Override - public List getPopular(int count) { - return films.values() - .stream() - .sorted((Film a, Film b) -> b.getLikes().size() - a.getLikes().size()) - .limit(count) - .collect(Collectors.toList()); - } - - private Long getNextId() { - return id++; - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java deleted file mode 100644 index 9f496f9..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/InMemoryUserRepository.java +++ /dev/null @@ -1,129 +0,0 @@ -package ru.yandex.practicum.filmorate.repository; - -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; - -import java.util.*; - -@Repository -public class InMemoryUserRepository implements UserRepository { - private static Long id = 1L; - private final Map users = new HashMap<>(); - - @Override - public List getAll() { - return users.values().stream().toList(); - } - - public User findById(final Long id) { - return Optional - .ofNullable(users.get(id)) - .orElseThrow(() -> new NotFoundException("User not found")); - } - - @Override - public User create(final User user) { - User newUser = User.builder() - .id(getNextId()) - .email(user.getEmail()) - .login(user.getLogin()) - .name(user.getName()) - .birthday(user.getBirthday()) - .build(); - - users.put(newUser.getId(), newUser); - - return newUser; - } - - @Override - public User update(final User user) { - User updatedUser = findById(user.getId()); - - updatedUser.setEmail(user.getEmail()); - updatedUser.setLogin(user.getLogin()); - updatedUser.setName(user.getName()); - updatedUser.setBirthday(user.getBirthday()); - - users.put(updatedUser.getId(), updatedUser); - - return updatedUser; - } - - @Override - public void addFriend(final Long userId, final Long friendId) { - User user = findById(userId); - User friend = findById(friendId); - - user.getFriends().add(friendId); - friend.getFriends().add(userId); - - users.put(user.getId(), user); - users.put(friend.getId(), friend); - } - - @Override - public void deleteFriend(final Long userId, final Long friendId) { - User user = findById(userId); - User friend = findById(friendId); - - user.getFriends().remove(friendId); - friend.getFriends().remove(userId); - - users.put(user.getId(), user); - users.put(friend.getId(), friend); - } - - @Override - public List findFriendsByUserId(final Long userId) { - Set friends = findById(userId).getFriends(); - List friendsList = new ArrayList<>(); - - if (friends.isEmpty()) { - return friendsList; - } - - friends.forEach((Long id) -> { - User friend = findById(id); - friendsList.add(friend); - }); - - return friendsList; - } - - @Override - public List findCommonFriends(Long userId, Long otherUserId) { - Set userFriends = findById(userId).getFriends(); - Set otherUserFriends = findById(otherUserId).getFriends(); - - List friendsList = new ArrayList<>(); - - if (userFriends.isEmpty() || otherUserFriends.isEmpty()) { - return friendsList; - } - - userFriends.stream() - .filter(otherUserFriends::contains) - .forEach((Long id) -> friendsList.add(findById(id))); - - return friendsList; - } - - @Override - public boolean isExists(final Long id) { - return users.containsKey(id); - } - - private void validateUser(final Long id) { - if (!isExists(id)) { - throw new NotFoundException("User not found"); - } - } - - private Long getNextId() { - return id++; - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java index 4aec3ae..2d9f380 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java @@ -32,8 +32,7 @@ public void addLike(final Long filmId, final Long userId) { try { jdbc.update( - "INSERT INTO ? (film_id, user_id) VALUES (?, ?)", - TABLE_NAME, + "INSERT INTO " + TABLE_NAME + " (film_id, user_id) VALUES (?, ?)", filmId, userId ); @@ -54,8 +53,7 @@ public void deleteLike(final Long filmId, final Long userId) { try { jdbc.update( - "DELETE FROM ? WHERE film_id = ? AND user_id = ?", - TABLE_NAME, + "DELETE FROM " + TABLE_NAME + " WHERE film_id = ? AND user_id = ?", filmId, userId ); diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java index 7539843..62edc0b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java @@ -23,9 +23,8 @@ public class MpaDbRepository implements MpaRepository { @Override public List getAll() { return jdbc.query( - "SELECT * FROM ? ORDER BY title", - mapper, - TABLE_NAME + "SELECT * FROM " + TABLE_NAME, + mapper ); } @@ -33,9 +32,8 @@ public List getAll() { public Mpa findById(final Long id) { try { return jdbc.queryForObject( - "SELECT * FROM ? WHERE id = ?", + "SELECT * FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ); } catch (RuntimeException e) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java index a7d7cf3..788a101 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -17,6 +18,7 @@ import java.sql.Statement; import java.util.*; +@Slf4j @Repository @RequiredArgsConstructor @Primary @@ -29,18 +31,16 @@ public class UserDbRepository implements UserRepository { @Override public List getAll() { return jdbc.query( - "SELECT * FROM ? ORDER BY name", - mapper, - TABLE_NAME + "SELECT * FROM " + TABLE_NAME, + mapper ); } public User findById(final Long id) { try { return jdbc.queryForObject( - "SELECT * FROM ? WHERE id = ?", + "SELECT * FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ); } catch (RuntimeException e) { @@ -56,23 +56,22 @@ public User create(final User user) { jdbc.update( conn -> { PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO ? (email, login, name, birthday, password) " + - "VALUES (?, ?, ?, ?, ?)", + "INSERT INTO " + TABLE_NAME + " (email, login, name, birthday) " + + "VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS ); - stmt.setString(1, TABLE_NAME); - stmt.setString(2, user.getEmail()); - stmt.setString(3, user.getLogin()); - stmt.setString(4, user.getName()); - stmt.setDate(5, Date.valueOf(user.getBirthday())); - stmt.setString(6, user.getPassword()); + stmt.setString(1, user.getEmail()); + stmt.setString(2, user.getLogin()); + stmt.setString(3, user.getName()); + stmt.setDate(4, Date.valueOf(user.getBirthday())); return stmt; }, keyHolder ); } catch (RuntimeException e) { + log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving data"); } @@ -93,23 +92,22 @@ public User update(final User user) { try { updated = jdbc.update( - "UPDATE ? " + - "SET email = ?, login = ?, name = ?, birthdat = ?, password = ? " + + "UPDATE " + TABLE_NAME + " " + + "SET email = ?, login = ?, name = ?, birthday = ? " + "WHERE id = ?", - TABLE_NAME, user.getEmail(), user.getLogin(), user.getName(), Date.valueOf(user.getBirthday()), - user.getPassword(), user.getId() ); } catch (RuntimeException e) { + log.error(e.getMessage(), e); throw new InternalErrorException("Error on updating data"); } if (updated < 1) { - throw new InternalErrorException("Error on updating data"); + throw new NotFoundException("User not found"); } return user; @@ -119,9 +117,8 @@ public User update(final User user) { public boolean isExists(Long id) { try { return jdbc.queryForObject( - "SELECT id FROM ? WHERE id = ?", + "SELECT id FROM " + TABLE_NAME + " WHERE id = ?", mapper, - TABLE_NAME, id ) != null; } catch (RuntimeException e) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java index 76cc15e..7dba787 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java @@ -20,7 +20,7 @@ public Film mapRow(ResultSet rs, int rowNum) throws SQLException { .mpa( Mpa.builder() .id(rs.getLong("mpa_id")) -// .title(rs.getString("mpa_title")) +// .name(rs.getString("mpa_name")) .build() ) .build(); diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java index f5af801..64717f7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/GenreRowMapper.java @@ -12,7 +12,7 @@ public class GenreRowMapper implements RowMapper { public Genre mapRow(ResultSet rs, int rowNum) throws SQLException { return Genre.builder() .id(rs.getLong("id")) - .title(rs.getString("title")) + .name(rs.getString("name")) .build(); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java index 06e6c24..5d1f815 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/MpaRowMapper.java @@ -12,7 +12,7 @@ public class MpaRowMapper implements RowMapper { public Mpa mapRow(ResultSet rs, int rowNum) throws SQLException { return Mpa.builder() .id(rs.getLong("id")) - .title(rs.getString("title")) + .name(rs.getString("name")) .build(); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java index 10e8cbd..4daffe2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/UserRowMapper.java @@ -15,7 +15,6 @@ public User mapRow(ResultSet rs, int rowNum) throws SQLException { .name(rs.getString("name")) .login(rs.getString("login")) .email(rs.getString("email")) - .password(rs.getString("password")) .birthday(rs.getDate("birthday").toLocalDate()) .build(); } 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 931d258..57d7657 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -2,9 +2,15 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.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.repository.contracts.FilmRepository; +import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; +import ru.yandex.practicum.filmorate.repository.contracts.LikeRepository; +import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; import java.time.LocalDate; import java.util.List; @@ -16,6 +22,9 @@ public class FilmService { private static final LocalDate RELEASE_MIN_DATE = LocalDate.of(1895, 12, 28); private final FilmRepository filmRepository; + private final LikeRepository likeRepository; + private final MpaRepository mpaRepository; + private final GenreRepository genreRepository; public List getList() { return filmRepository.getAll(); @@ -35,14 +44,14 @@ public void addLike(final Long id, final Long userId) { validateFilmId(id); validateUserId(userId); - filmRepository.addLike(id, userId); + likeRepository.addLike(id, userId); } public void deleteLike(final Long id, final Long userId) { validateFilmId(id); validateUserId(userId); - filmRepository.deleteLike(id, userId); + likeRepository.deleteLike(id, userId); } public List getPopular(final int count) { @@ -73,6 +82,26 @@ private void validate(final Film film) { if (film.getDuration() < 0) { throw new ValidationException("Film duration is negative"); } + + if ( + film.getMpa() != null + && film.getMpa().getId() != null + ) { + try { + Mpa mpa = mpaRepository.findById(film.getMpa().getId()); + } catch (NotFoundException e) { + throw new ValidationException("Mpa not found"); + } + } + + if (film.getGenres() != null && !film.getGenres().isEmpty()) { + List availableIds = genreRepository.getAll().stream().map(Genre::getId).toList(); + film.getGenres().forEach(genre -> { + if (genre.getId() == null || !availableIds.contains(genre.getId())) { + throw new ValidationException("Invalid Genre id"); + } + }); + } } private void validateFilmId(final Long id) { 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..547aeb7 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -0,0 +1,22 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class GenreService { + private final GenreRepository genreRepository; + + public List getList() { + return genreRepository.getAll(); + } + + public Genre getById(Long id) { + return genreRepository.findById(id); + } +} 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..0fb43ce --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -0,0 +1,22 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class MpaService { + private final MpaRepository mpaRepository; + + public List getList() { + return mpaRepository.getAll(); + } + + public Mpa getById(Long id) { + return mpaRepository.findById(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 b98aed2..2791df4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.repository.contracts.FriendshipRepository; import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import java.time.LocalDate; @@ -13,6 +14,7 @@ @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; + private final FriendshipRepository friendshipRepository; public List getList() { return userRepository.getAll(); @@ -33,23 +35,23 @@ public User update(final User user) { } public List getUserFriends(final Long userId) { - return userRepository.findFriendsByUserId(userId); + return friendshipRepository.findFriendsByUserId(userId); } public List getCommonFriends(final Long id, final Long otherId) { - return userRepository.findCommonFriends(id, otherId); + return friendshipRepository.findCommonFriends(id, otherId); } public void addFriend(final Long userId, final Long friendId) { validateUserFriend(userId, friendId); - userRepository.addFriend(userId, friendId); + friendshipRepository.addFriend(userId, friendId); } public void deleteFriend(final Long userId, final Long friendId) { validateUserFriend(userId, friendId); - userRepository.deleteFriend(userId, friendId); + friendshipRepository.deleteFriend(userId, friendId); } private void validateUserData(final User user) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cef16d7..e95b527 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,4 +3,4 @@ spring.sql.init.mode=always spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa -spring.datasource.password=password \ No newline at end of file +spring.datasource.password=password diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 9352059..bae952e 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,11 +1,11 @@ -INSERT INTO mpas (title) +INSERT INTO mpas (name) VALUES ('G'), ('PG'), ('PG-13'), ('R'), ('NC-17'); -INSERT INTO genres (title) +INSERT INTO genres (name) VALUES ('Комедия'), ('Драма'), ('Мультфильм'), diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index d0d2844..7be1c47 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,3 +1,5 @@ +DROP ALL OBJECTS; + CREATE TABLE IF NOT EXISTS films ( id long generated by default as identity primary key, mpa_id long not null, @@ -9,12 +11,12 @@ CREATE TABLE IF NOT EXISTS films ( CREATE TABLE IF NOT EXISTS mpas ( id long generated by default as identity primary key, - title varchar not null + name varchar not null ); CREATE TABLE IF NOT EXISTS genres ( id long generated by default as identity primary key, - title varchar not null + name varchar not null ); CREATE TABLE IF NOT EXISTS users ( @@ -22,8 +24,8 @@ CREATE TABLE IF NOT EXISTS users ( email varchar not null unique, login varchar not null unique, name varchar not null, - birthday date, - password varchar not null + birthday date +-- password varchar not null ); CREATE TABLE IF NOT EXISTS film_genre ( diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java index 2e27b65..b876e5f 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java @@ -3,10 +3,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.repository.InMemoryFilmRepository; -import ru.yandex.practicum.filmorate.repository.InMemoryUserRepository; +import ru.yandex.practicum.filmorate.repository.FilmDbRepository; +import ru.yandex.practicum.filmorate.repository.UserDbRepository; import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import ru.yandex.practicum.filmorate.service.FilmService; @@ -25,10 +26,14 @@ public class FilmControllerTests { @BeforeEach public void setUp() { - UserRepository userRepository = new InMemoryUserRepository(); + JdbcTemplate + UserRepository userRepository = new UserDbRepository(); controller = new ru.yandex.practicum.filmorate.controller.FilmController( - new FilmService(new InMemoryFilmRepository(userRepository)) + new FilmService(new FilmDbRepository( + , + userRepository, + )) ); diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java index 6612a5f..be2ccf8 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java @@ -3,9 +3,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.repository.InMemoryUserRepository; +import ru.yandex.practicum.filmorate.repository.UserDbRepository; import ru.yandex.practicum.filmorate.service.UserService; import java.time.LocalDate; @@ -19,7 +20,7 @@ public class UserControllerTests { @BeforeEach public void setUp() { controller = new ru.yandex.practicum.filmorate.controller.UserController( - new UserService(new InMemoryUserRepository()) + new UserService(new UserDbRepository(new JdbcTemplate())) ); } From d73cd0a68550bbf99149f642bebc8078bc002f47 Mon Sep 17 00:00:00 2001 From: Alexander Krutov Date: Wed, 15 Jan 2025 01:30:26 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 5 +++ .../repository/FilmDbRepository.java | 33 ++++++++------- .../repository/FriendshipDbRepository.java | 19 --------- .../repository/GenreDbRepository.java | 31 +++++++------- .../repository/LikeDbRepository.java | 23 ----------- .../filmorate/repository/MpaDbRepository.java | 5 +-- .../repository/UserDbRepository.java | 21 ++++------ .../repository/mappers/FilmRowMapper.java | 2 +- .../filmorate/service/FilmService.java | 41 ++++++++++++++----- .../filmorate/service/GenreService.java | 9 +++- .../filmorate/service/MpaService.java | 10 ++++- .../filmorate/service/UserService.java | 33 +++++++++++++++ .../filmorate/FilmControllerTests.java | 36 ++++------------ .../filmorate/UserControllerTests.java | 20 ++++----- 14 files changed, 144 insertions(+), 144 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 d7278a3..c43af92 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -22,6 +22,11 @@ public Collection list() { return filmService.getList(); } + @GetMapping("/{id}") + public Film getFilm(@PathVariable final Long id) { + return filmService.getFilm(id); + } + @PostMapping public Film create(@RequestBody final Film film) { return filmService.create(film); diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java index 6e8b571..9adadd0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java @@ -2,14 +2,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Mpa; @@ -22,13 +20,17 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; @Slf4j @Repository @RequiredArgsConstructor -@Primary public class FilmDbRepository implements FilmRepository { public static final String TABLE_NAME = "films"; private static final String FILM_GENRE_TABLE_NAME = "film_genre"; @@ -41,7 +43,9 @@ public class FilmDbRepository implements FilmRepository { @Override public List getAll() { List films = jdbc.query( - "SELECT * FROM " + TABLE_NAME, + "SELECT f.*, m.name mpa_name " + + "FROM " + TABLE_NAME + " AS f " + + "LEFT JOIN " + MpaDbRepository.TABLE_NAME + " AS m ON m.id = f.mpa_id", mapper ); @@ -56,7 +60,10 @@ public List getAll() { public Film findById(final Long id) { try { Film film = jdbc.queryForObject( - "SELECT * FROM " + TABLE_NAME + " WHERE id = ?", + "SELECT f.*, m.name mpa_name " + + "FROM " + TABLE_NAME + " AS f " + + "LEFT JOIN " + MpaDbRepository.TABLE_NAME + " AS m ON m.id = f.mpa_id " + + "WHERE f.id = ?", mapper, id ); @@ -65,7 +72,7 @@ public Film findById(final Long id) { return film; } catch (RuntimeException e) { - throw new NotFoundException("Film not found"); + return null; } } @@ -113,10 +120,9 @@ public Film create(final Film film) { @Override public Film update(final Film film) { Mpa mpa = getMpaByObject(film.getMpa()); - int updated = 0; try { - updated = jdbc.update( + jdbc.update( "UPDATE " + TABLE_NAME + " " + "SET mpa_id = ?, name = ?, description = ?, release_date = ?, duration = ? " + "WHERE id = ?", @@ -132,10 +138,6 @@ public Film update(final Film film) { throw new InternalErrorException("Error on updating data"); } - if (updated < 1) { - throw new NotFoundException("Film not found"); - } - deleteFilmGenres(film.getId()); addRelations(film); @@ -145,9 +147,10 @@ public Film update(final Film film) { @Override public List getPopular(int count) { return jdbc.query( - "SELECT f.*, COUNT(l.film_id) like_cnt " + + "SELECT f.*, m.name mpa_name, COUNT(l.film_id) like_cnt " + "FROM " + TABLE_NAME + " AS f " + "LEFT JOIN " + LikeDbRepository.TABLE_NAME + " as l ON (l.film_id = f.id) " + + "LEFT JOIN " + MpaDbRepository.TABLE_NAME + " as m ON (m.id = f.mpa_id) " + "GROUP BY f.id " + "ORDER BY like_cnt DESC " + "LIMIT ?", @@ -161,7 +164,7 @@ public boolean isExists(Long id) { try { return jdbc.queryForObject( "SELECT id FROM " + TABLE_NAME + " WHERE id = ?", - mapper, + Long.class, id ) != null; } catch (RuntimeException e) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java index 9a8e8f0..56fc361 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java @@ -4,10 +4,8 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.repository.contracts.FriendshipRepository; -import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import ru.yandex.practicum.filmorate.repository.mappers.UserRowMapper; import java.util.List; @@ -19,19 +17,10 @@ public class FriendshipDbRepository implements FriendshipRepository { public static final String TABLE_NAME = "friendship"; private final JdbcTemplate jdbc; - private final UserRepository userRepository; private final UserRowMapper userRowMapper = new UserRowMapper(); @Override public void addFriend(final Long userId, final Long friendId) { - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - if (!userRepository.isExists(friendId)) { - throw new NotFoundException("Friend not found"); - } - try { jdbc.update( "INSERT INTO " + TABLE_NAME + " (user_id, friend_id, active) VALUES (?, ?, ?)", @@ -46,14 +35,6 @@ public void addFriend(final Long userId, final Long friendId) { @Override public void deleteFriend(final Long userId, final Long friendId) { - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - if (!userRepository.isExists(friendId)) { - throw new NotFoundException("Friend not found"); - } - try { jdbc.update( "DELETE FROM " + TABLE_NAME + " WHERE user_id = ? AND friend_id = ?", diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java index 8314527..644550f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java @@ -1,10 +1,9 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; import ru.yandex.practicum.filmorate.repository.mappers.GenreRowMapper; @@ -13,10 +12,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Repository @RequiredArgsConstructor -@Primary public class GenreDbRepository implements GenreRepository { public static final String TABLE_NAME = "genres"; private static final String FILM_GENRE_TABLE_NAME = "film_genre"; @@ -35,7 +34,7 @@ public List getAll() { @Override public List findByFilmId(final Long filmId) { return jdbc.query( - "SELECT g.*" + + "SELECT g.* " + "FROM " + TABLE_NAME + " AS g " + "INNER JOIN " + FILM_GENRE_TABLE_NAME + " AS fg ON fg.genre_id = g.id " + "WHERE fg.film_id = ?", @@ -47,27 +46,27 @@ public List findByFilmId(final Long filmId) { @Override public Map> findByFilmId(final List filmIds) { Map> genresMap = new HashMap<>(); - jdbc.queryForList( - "SELECT g.*, fg.film_id " + + SqlRowSet rowSet = jdbc.queryForRowSet( + String.format( + "SELECT g.*, fg.film_id " + "FROM " + TABLE_NAME + " AS g " + "INNER JOIN " + FILM_GENRE_TABLE_NAME + " AS fg ON fg.genre_id = g.id " + - "WHERE fg.film_id IN (?)", - String.join( - ",", - filmIds.stream().map(String::valueOf).toList() + "WHERE fg.film_id IN (%s)", + filmIds.stream().map(el -> Long.toString(el)).collect(Collectors.joining(",")) ) - ).forEach(v -> { + ); + while (rowSet.next()) { Genre genre = Genre.builder() - .id((Long)v.get("id")) - .name((String)v.get("name")) + .id(rowSet.getLong("id")) + .name(rowSet.getString("name")) .build(); - Long filmId = (Long)v.get("film_id"); + Long filmId = rowSet.getLong("film_id"); List genres = genresMap.getOrDefault(filmId, new ArrayList<>()); genres.add(genre); genresMap.put(filmId, genres); - }); + } return genresMap; } @@ -81,7 +80,7 @@ public Genre findById(final Long id) { id ); } catch (RuntimeException e) { - throw new NotFoundException("Genre not found"); + return null; } } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java index 2d9f380..fbadc05 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java @@ -1,35 +1,20 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; import ru.yandex.practicum.filmorate.repository.contracts.LikeRepository; -import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; @Repository @RequiredArgsConstructor -@Primary public class LikeDbRepository implements LikeRepository { public static final String TABLE_NAME = "film_like"; private final JdbcTemplate jdbc; - private final UserRepository userRepository; - private final FilmRepository filmRepository; @Override public void addLike(final Long filmId, final Long userId) { - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - if (!filmRepository.isExists(filmId)) { - throw new NotFoundException("Film not found"); - } - try { jdbc.update( "INSERT INTO " + TABLE_NAME + " (film_id, user_id) VALUES (?, ?)", @@ -43,14 +28,6 @@ public void addLike(final Long filmId, final Long userId) { @Override public void deleteLike(final Long filmId, final Long userId) { - if (!userRepository.isExists(userId)) { - throw new NotFoundException("User not found"); - } - - if (!filmRepository.isExists(filmId)) { - throw new NotFoundException("Film not found"); - } - try { jdbc.update( "DELETE FROM " + TABLE_NAME + " WHERE film_id = ? AND user_id = ?", diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java index 62edc0b..e4bd10e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java @@ -1,10 +1,8 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; import ru.yandex.practicum.filmorate.repository.mappers.MpaRowMapper; @@ -13,7 +11,6 @@ @Repository @RequiredArgsConstructor -@Primary public class MpaDbRepository implements MpaRepository { public static final String TABLE_NAME = "mpas"; @@ -37,7 +34,7 @@ public Mpa findById(final Long id) { id ); } catch (RuntimeException e) { - throw new NotFoundException("Mpa not found"); + return null; } } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java index 788a101..73c1c35 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java @@ -2,13 +2,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import ru.yandex.practicum.filmorate.repository.mappers.UserRowMapper; @@ -21,11 +19,11 @@ @Slf4j @Repository @RequiredArgsConstructor -@Primary public class UserDbRepository implements UserRepository { + public static final String TABLE_NAME = "users"; - private final JdbcTemplate jdbc; + private final JdbcTemplate jdbc; private final UserRowMapper mapper = new UserRowMapper(); @Override @@ -44,7 +42,7 @@ public User findById(final Long id) { id ); } catch (RuntimeException e) { - throw new NotFoundException("User not found"); + return null; } } @@ -88,10 +86,8 @@ public User create(final User user) { @Override public User update(final User user) { - int updated = 0; - try { - updated = jdbc.update( + jdbc.update( "UPDATE " + TABLE_NAME + " " + "SET email = ?, login = ?, name = ?, birthday = ? " + "WHERE id = ?", @@ -106,22 +102,19 @@ public User update(final User user) { throw new InternalErrorException("Error on updating data"); } - if (updated < 1) { - throw new NotFoundException("User not found"); - } - return user; } @Override - public boolean isExists(Long id) { + public boolean isExists(final Long id) { try { return jdbc.queryForObject( "SELECT id FROM " + TABLE_NAME + " WHERE id = ?", - mapper, + Long.class, id ) != null; } catch (RuntimeException e) { + System.out.println("Error: " + e.getMessage()); return false; } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java index 7dba787..045b868 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/mappers/FilmRowMapper.java @@ -20,7 +20,7 @@ public Film mapRow(ResultSet rs, int rowNum) throws SQLException { .mpa( Mpa.builder() .id(rs.getLong("mpa_id")) -// .name(rs.getString("mpa_name")) + .name(rs.getString("mpa_name")) .build() ) .build(); 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 57d7657..4372801 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -6,11 +6,7 @@ import ru.yandex.practicum.filmorate.exception.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.repository.contracts.FilmRepository; -import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; -import ru.yandex.practicum.filmorate.repository.contracts.LikeRepository; -import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; +import ru.yandex.practicum.filmorate.repository.contracts.*; import java.time.LocalDate; import java.util.List; @@ -25,11 +21,22 @@ public class FilmService { private final LikeRepository likeRepository; private final MpaRepository mpaRepository; private final GenreRepository genreRepository; + private final UserRepository userRepository; public List getList() { return filmRepository.getAll(); } + public Film getFilm(final Long id) { + Film film = filmRepository.findById(id); + + if (film == null) { + throw new NotFoundException("Film not found"); + } + + return film; + } + public Film create(final Film film) { validate(film); return filmRepository.create(film); @@ -37,12 +44,18 @@ public Film create(final Film film) { public Film update(final Film film) { validate(film); + + if (!filmRepository.isExists(film.getId())) { + throw new NotFoundException("Film not found"); + } + return filmRepository.update(film); } public void addLike(final Long id, final Long userId) { validateFilmId(id); validateUserId(userId); + filmAndUserExists(id, userId); likeRepository.addLike(id, userId); } @@ -50,6 +63,7 @@ public void addLike(final Long id, final Long userId) { public void deleteLike(final Long id, final Long userId) { validateFilmId(id); validateUserId(userId); + filmAndUserExists(id, userId); likeRepository.deleteLike(id, userId); } @@ -62,6 +76,16 @@ public List getPopular(final int count) { return filmRepository.getPopular(count); } + private void filmAndUserExists(final Long filmId, final Long userId) { + if (!filmRepository.isExists(filmId)) { + throw new NotFoundException("Film not found"); + } + + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + } + private void validate(final Film film) { if (film == null) { throw new ValidationException("Film is null"); @@ -86,12 +110,9 @@ private void validate(final Film film) { if ( film.getMpa() != null && film.getMpa().getId() != null + && mpaRepository.findById(film.getMpa().getId()) == null ) { - try { - Mpa mpa = mpaRepository.findById(film.getMpa().getId()); - } catch (NotFoundException e) { - throw new ValidationException("Mpa not found"); - } + throw new ValidationException("Mpa not found"); } if (film.getGenres() != null && !film.getGenres().isEmpty()) { 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 547aeb7..5d1d893 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; @@ -17,6 +18,12 @@ public List getList() { } public Genre getById(Long id) { - return genreRepository.findById(id); + Genre genre = genreRepository.findById(id); + + if (genre == null) { + throw new NotFoundException("Genre not found"); + } + + return genre; } } 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 0fb43ce..4863984 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; @@ -17,6 +18,13 @@ public List getList() { } public Mpa getById(Long id) { - return mpaRepository.findById(id); + + Mpa mpa = mpaRepository.findById(id); + + if (mpa == null) { + throw new NotFoundException("Mpa not found"); + } + + return mpa; } } 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 2791df4..d2e06a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.repository.contracts.FriendshipRepository; @@ -31,26 +32,58 @@ public User update(final User user) { validateUserData(user); setNameIfEmpty(user); + if (!userRepository.isExists(user.getId())) { + throw new NotFoundException("User not found"); + } + return userRepository.update(user); } public List getUserFriends(final Long userId) { + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + return friendshipRepository.findFriendsByUserId(userId); } public List getCommonFriends(final Long id, final Long otherId) { + if (!userRepository.isExists(id)) { + throw new NotFoundException("User not found"); + } + + if (!userRepository.isExists(otherId)) { + throw new NotFoundException("Friend not found"); + } + return friendshipRepository.findCommonFriends(id, otherId); } public void addFriend(final Long userId, final Long friendId) { validateUserFriend(userId, friendId); + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!userRepository.isExists(friendId)) { + throw new NotFoundException("Friend not found"); + } + friendshipRepository.addFriend(userId, friendId); } public void deleteFriend(final Long userId, final Long friendId) { validateUserFriend(userId, friendId); + if (!userRepository.isExists(userId)) { + throw new NotFoundException("User not found"); + } + + if (!userRepository.isExists(friendId)) { + throw new NotFoundException("Friend not found"); + } + friendshipRepository.deleteFriend(userId, friendId); } diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java index b876e5f..f0eb334 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java @@ -1,15 +1,10 @@ package ru.yandex.practicum.filmorate; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.repository.FilmDbRepository; -import ru.yandex.practicum.filmorate.repository.UserDbRepository; -import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; -import ru.yandex.practicum.filmorate.service.FilmService; import java.time.LocalDate; import java.util.Random; @@ -21,23 +16,8 @@ public class FilmControllerTests { private static final int DESCRIPTION_LIMIT = 200; private static final LocalDate RELEASE_MIN_DATE = LocalDate.of(1895, 12, 28); + @Autowired private ru.yandex.practicum.filmorate.controller.FilmController controller; - private ru.yandex.practicum.filmorate.controller.UserController userController; - - @BeforeEach - public void setUp() { - JdbcTemplate - UserRepository userRepository = new UserDbRepository(); - - controller = new ru.yandex.practicum.filmorate.controller.FilmController( - new FilmService(new FilmDbRepository( - , - userRepository, - )) - ); - - - } private static Film makeFilm() { return Film.builder() @@ -65,23 +45,25 @@ private static String generateString(int length) { @Test public void filmAddedWithValidFieldValues() { - final Film[] films = {null}; + int filmsCountBefore = controller.list().size(); - assertDoesNotThrow(() -> films[0] = controller.create(makeFilm()), "Film not created"); - assertTrue(controller.list().contains(films[0]), "Film not added"); + assertDoesNotThrow(() -> controller.create(makeFilm()), "Film not created"); + assertNotEquals(filmsCountBefore, controller.list(), "Film not added"); } @Test public void filmUpdatedWithValidFieldValues() { Film film = controller.create(makeFilm()); + final Film[] films = {null}; film.setName("Film 2"); film.setDescription("Film description 2"); film.setDuration(200); film.setReleaseDate(LocalDate.of(2021, 11, 28)); - assertDoesNotThrow(() -> controller.update(film), "Film not updated"); - assertTrue(controller.list().contains(film), "Film not found"); + assertDoesNotThrow(() -> films[0] = controller.update(film), "Film not updated"); + + assertEquals(films[0], controller.getFilm(film.getId()), "Film not found"); } @Test diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java index be2ccf8..8734819 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java @@ -1,13 +1,10 @@ package ru.yandex.practicum.filmorate; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.repository.UserDbRepository; -import ru.yandex.practicum.filmorate.service.UserService; import java.time.LocalDate; @@ -15,20 +12,17 @@ @SpringBootTest public class UserControllerTests { - private ru.yandex.practicum.filmorate.controller.UserController controller; - @BeforeEach - public void setUp() { - controller = new ru.yandex.practicum.filmorate.controller.UserController( - new UserService(new UserDbRepository(new JdbcTemplate())) - ); - } + @Autowired + private ru.yandex.practicum.filmorate.controller.UserController controller; + private static int userIndex = 0; private static User makeUser() { + userIndex++; return User.builder() .name("Vasiliy Pupkin") - .login("login") - .email("v.p.test@sample.host") + .login("login" + userIndex) + .email("v.p.test" + userIndex + "@sample.host") .birthday(LocalDate.of(1990, 8, 1)) .build(); } From a8a74c8e4d3163554ff7546f29513842401833d7 Mon Sep 17 00:00:00 2001 From: Alexander Krutov Date: Thu, 16 Jan 2025 22:35:48 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 10 +++++++++- .../filmorate/controller/GenreController.java | 13 ++++++------- .../filmorate/controller/UserController.java | 10 +++++++++- .../ru/yandex/practicum/filmorate/model/User.java | 1 - .../filmorate/repository/FilmDbRepository.java | 15 ++++++++------- .../repository/FriendshipDbRepository.java | 9 +++++---- .../filmorate/repository/GenreDbRepository.java | 3 ++- .../filmorate/repository/LikeDbRepository.java | 5 +++-- .../filmorate/repository/MpaDbRepository.java | 3 ++- .../filmorate/repository/UserDbRepository.java | 12 ++++++------ .../practicum/filmorate/service/FilmService.java | 6 +++++- src/main/resources/application.properties | 1 - src/main/resources/schema.sql | 13 ++++++------- 13 files changed, 61 insertions(+), 40 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 c43af92..9c9a3c4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,7 +1,15 @@ package ru.yandex.practicum.filmorate.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.service.FilmService; 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 96defa2..4131ac6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -1,7 +1,10 @@ package ru.yandex.practicum.filmorate.controller; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import lombok.RequiredArgsConstructor; +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.GenreService; @@ -9,14 +12,10 @@ @RestController @RequestMapping("/genres") +@RequiredArgsConstructor public class GenreController { private final GenreService genreService; - @Autowired - public GenreController(final GenreService genreService) { - this.genreService = genreService; - } - @GetMapping public Collection list() { return genreService.getList(); 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 bdbc0c6..7fbe1c1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -1,7 +1,15 @@ package ru.yandex.practicum.filmorate.controller; import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserService; 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 fbe2a49..e10fe50 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -15,6 +15,5 @@ public class User { private String login; private String name; private LocalDate birthday; -// private String password; private final Set friends = new HashSet<>(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java index 9adadd0..24e7609 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FilmDbRepository.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -71,7 +72,7 @@ public Film findById(final Long id) { fillGenreForFilm(film); return film; - } catch (RuntimeException e) { + } catch (DataAccessException e) { return null; } } @@ -100,7 +101,7 @@ public Film create(final Film film) { }, keyHolder ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving data"); } @@ -133,7 +134,7 @@ public Film update(final Film film) { film.getDuration(), film.getId() ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { log.error(e.getMessage(), e); throw new InternalErrorException("Error on updating data"); } @@ -167,7 +168,7 @@ public boolean isExists(Long id) { Long.class, id ) != null; - } catch (RuntimeException e) { + } catch (DataAccessException e) { return false; } } @@ -179,7 +180,7 @@ private Mpa getMpaByObject(Mpa mpa) { try { return mpaRepository.findById(mpa.getId()); - } catch (RuntimeException ignored) { + } catch (DataAccessException ignored) { return null; } } @@ -208,7 +209,7 @@ public int getBatchSize() { } } ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving film genre"); } @@ -221,7 +222,7 @@ private void deleteFilmGenres(Long filmId) { try { jdbc.update("DELETE FROM " + FILM_GENRE_TABLE_NAME + " WHERE film_id = ?", filmId); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException(e.getMessage()); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java index 56fc361..d2be29d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/FriendshipDbRepository.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; @@ -28,7 +29,7 @@ public void addFriend(final Long userId, final Long friendId) { friendId, false ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException("Error on adding friend"); } } @@ -41,7 +42,7 @@ public void deleteFriend(final Long userId, final Long friendId) { userId, friendId ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException("Error on deleting friend"); } } @@ -58,7 +59,7 @@ public List findFriendsByUserId(final Long userId) { userRowMapper, userId ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException("Error on getting user friends"); } } @@ -75,7 +76,7 @@ public List findCommonFriends(Long userId, Long friendId) { userId, friendId ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException("Error on getting user friends"); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java index 644550f..5101edc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/GenreDbRepository.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Repository; @@ -79,7 +80,7 @@ public Genre findById(final Long id) { mapper, id ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { return null; } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java index fbadc05..aeda961 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/LikeDbRepository.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.InternalErrorException; @@ -21,7 +22,7 @@ public void addLike(final Long filmId, final Long userId) { filmId, userId ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { throw new InternalErrorException("Error on adding like"); } } @@ -34,7 +35,7 @@ public void deleteLike(final Long filmId, final Long userId) { filmId, userId ); - } catch (RuntimeException ignored) { + } catch (DataAccessException ignored) { } } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java index e4bd10e..f7d11bf 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/MpaDbRepository.java @@ -1,6 +1,7 @@ package ru.yandex.practicum.filmorate.repository; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.model.Mpa; @@ -33,7 +34,7 @@ public Mpa findById(final Long id) { mapper, id ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { return null; } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java index 73c1c35..79bbdf6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java +++ b/src/main/java/ru/yandex/practicum/filmorate/repository/UserDbRepository.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; @@ -14,7 +15,7 @@ import java.sql.Date; import java.sql.PreparedStatement; import java.sql.Statement; -import java.util.*; +import java.util.List; @Slf4j @Repository @@ -41,7 +42,7 @@ public User findById(final Long id) { mapper, id ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { return null; } } @@ -68,7 +69,7 @@ public User create(final User user) { }, keyHolder ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { log.error(e.getMessage(), e); throw new InternalErrorException("Error on saving data"); } @@ -97,7 +98,7 @@ public User update(final User user) { Date.valueOf(user.getBirthday()), user.getId() ); - } catch (RuntimeException e) { + } catch (DataAccessException e) { log.error(e.getMessage(), e); throw new InternalErrorException("Error on updating data"); } @@ -113,8 +114,7 @@ public boolean isExists(final Long id) { Long.class, id ) != null; - } catch (RuntimeException e) { - System.out.println("Error: " + e.getMessage()); + } catch (DataAccessException e) { return false; } } 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 4372801..d837716 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -6,7 +6,11 @@ import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.repository.contracts.*; +import ru.yandex.practicum.filmorate.repository.contracts.FilmRepository; +import ru.yandex.practicum.filmorate.repository.contracts.GenreRepository; +import ru.yandex.practicum.filmorate.repository.contracts.LikeRepository; +import ru.yandex.practicum.filmorate.repository.contracts.MpaRepository; +import ru.yandex.practicum.filmorate.repository.contracts.UserRepository; import java.time.LocalDate; import java.util.List; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e95b527..f0e14c4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,4 @@ spring.sql.init.mode=always -# ? jdbc-url ???????, ??? ?????? ????? ????????? ? ???? spring.datasource.url=jdbc:h2:file:./db/filmorate spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 7be1c47..4e78a2c 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -3,7 +3,7 @@ DROP ALL OBJECTS; CREATE TABLE IF NOT EXISTS films ( id long generated by default as identity primary key, mpa_id long not null, - name varchar not null, + name varchar(255) not null, description text, release_date date, duration int not null default 0 @@ -11,21 +11,20 @@ CREATE TABLE IF NOT EXISTS films ( CREATE TABLE IF NOT EXISTS mpas ( id long generated by default as identity primary key, - name varchar not null + name varchar(255) not null ); CREATE TABLE IF NOT EXISTS genres ( id long generated by default as identity primary key, - name varchar not null + name varchar(255) not null ); CREATE TABLE IF NOT EXISTS users ( id long generated by default as identity primary key, - email varchar not null unique, - login varchar not null unique, - name varchar not null, + email varchar(255) not null unique, + login varchar(255) not null unique, + name varchar(255) not null, birthday date --- password varchar not null ); CREATE TABLE IF NOT EXISTS film_genre (