diff --git a/README.md b/README.md
index 2cf454a..ddca9f6 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,103 @@
-# java-filmorate
-Template repository for Filmorate project.
+# Filmorate
+Это проект кинотеки, в который можно добавлять комментарии, оценивать фильмы находить самые популярные а так добавлять
+в друзья пользователей кинотеки.
+
+# Схема БД
+
+
+# Примеры запросов
+
+### Для пользователей
+
+* Создание пользователя
+```SQL
+INSERT INTO users(email,
+ login,
+ name,
+ birthday)
+VALUES (?,?,?,?);
+```
+
+* Обновление пользователя
+```SQL
+UPDATE users
+ SET email=?,
+ login=?,
+ name=?,
+ birthday=?
+ WHERE id=?;
+```
+* Получение пользоывтеля по ID
+```SQL
+SELECT * FROM users WHERE id=?;
+```
+* Получение всех пользователей
+```SQL
+SELECT * FROM users;
+```
+* Удаление пользователя
+ ```SQL
+DELETE FROM users WHERE id=?;
+```
+* Добавление в список друзей
+ ```SQL
+INSERT INTO friends (user_id, to_user_id) VALUES (?,?);
+```
+* Получение списка друзей
+ ```SQL
+"SELECT to_user_id FROM friends WHERE user_id=?;
+```
+* Обновление списка друзей
+ ```SQL
+DELETE FROM users WHERE id=?;
+```
+### Для фильмов
+
+* Добавление фильма
+ ```SQL
+INSERT INTO films(name,
+ description,
+ release_date,
+ duration,
+ mpa_rating_id)
+ VALUES(?,?,?,?,?);
+```
+* Обновление фильма
+ ```SQL
+UPDATE films SET name=?,
+ description=?,
+ release_date=?,
+ duration=?,
+ mpa_rating_id=?
+WHERE id=?;
+```
+* Удаление фильма
+ ```SQL
+DELETE FROM films WHERE id=?;
+```
+* Получение фильма по ID
+ ```SQL
+SELECT * FROM films WHERE id=?;
+```
+* Получение всех фильмов
+ ```SQL
+SELECT * FROM films;
+```
+* Получение списка лайков фильма
+ ```SQL
+SELECT user_id FROM film_likes WHERE film_id=?;
+```
+* Добавление лайка фильма
+ ```SQL
+INSERT INTO film_likes(film_id, user_id) VALUES (?,?);
+```
+* Удвление лайка фильма
+ ```SQL
+DELETE FROM film_likes WHERE film_id=? AND user_id=?;
+```
+* Получение списка жанров фильма
+ ```SQL
+SELECT g.genre_id AS id, gs.name AS name
+ FROM genre AS g LEFT OUTER JOIN genres AS gs ON g.genre_id = gs.id
+ WHERE g.film_id =? ORDER BY id";
+```
diff --git a/filmorate.png b/filmorate.png
new file mode 100644
index 0000000..bca715a
Binary files /dev/null and b/filmorate.png differ
diff --git a/pom.xml b/pom.xml
index 2e002aa..baec517 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,24 @@
logbook-spring-boot-starter
3.7.2
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+ runtime
+
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..1950b3c
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java
@@ -0,0 +1,43 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import jakarta.validation.constraints.Positive;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.service.GenreService;
+
+import java.util.Collection;
+
+@Validated
+@RestController
+@RequestMapping("/genres")
+public class GenreController {
+
+ private final GenreService genreService;
+ private final Logger logger = LoggerFactory.getLogger(GenreService.class);
+
+ @Autowired
+ public GenreController(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @GetMapping({"/{id}"})
+ @ResponseStatus(HttpStatus.OK)
+ public Genre getGenreId(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("возращаем жанр по id: " + id);
+ return genreService.getGenreId(id);
+ }
+
+ @GetMapping
+ @ResponseStatus(HttpStatus.OK)
+ public Collection getGenreAll() {
+ logger.info("возращаем список жанров");
+ return genreService.getGenreAll();
+ }
+
+}
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..177b9d8
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java
@@ -0,0 +1,43 @@
+package ru.yandex.practicum.filmorate.controller;
+
+
+import jakarta.validation.constraints.Positive;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.service.MpaService;
+
+import java.util.Collection;
+
+@Validated
+@RestController
+@RequestMapping("/mpa")
+public class MpaController {
+ private final Logger logger = LoggerFactory.getLogger(MpaController.class);
+
+ private final MpaService mpaService;
+
+ @Autowired
+ public MpaController(MpaService mpaService) {
+ this.mpaService = mpaService;
+ }
+
+
+ @GetMapping({"/{id}"})
+ @ResponseStatus(HttpStatus.OK)
+ public Mpa getMpaId(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("возращаем жанр по id: " + id);
+ return mpaService.getMpaId(id);
+ }
+
+ @GetMapping
+ @ResponseStatus(HttpStatus.OK)
+ public Collection getMpaAll() {
+ logger.info("возращаем список жанров");
+ return mpaService.getMpaAll();
+ }
+}
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 938f2b8..03988a7 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -90,7 +90,7 @@ public Collection friendsGetList(@Positive(message = "неверное з
@ResponseStatus(HttpStatus.OK)
public Collection friendsGetCommonList(@Positive(message = "неверное значение") @PathVariable long id,
@Positive(message = "неверное значение") @PathVariable long otherId) {
- logger.info("показывает список друзей");
+ logger.info("показывает обший список друзей");
return userService.friendsGetCommonList(id, otherId);
}
}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java
new file mode 100644
index 0000000..dd8d262
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java
@@ -0,0 +1,7 @@
+package ru.yandex.practicum.filmorate.exception;
+
+public class NotFoundException extends RuntimeException {
+ public NotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
index 297ba77..03296f2 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -5,15 +5,11 @@
import lombok.*;
import java.time.LocalDate;
+import java.util.HashSet;
import java.util.Set;
-/**
- * Film.
- */
-@Getter
-@Setter
-@ToString
-@AllArgsConstructor
+@Data
+@NoArgsConstructor
public class Film extends DataModel implements Comparable {
private Long id;
@@ -34,7 +30,12 @@ public class Film extends DataModel implements Comparable {
@Min(1)
private int duration;
- private Set likesId;
+ private Set likesId = new HashSet<>();
+
+ private Set genres = new HashSet<>();
+
+ // @NotNull (message ="рейтинг не может быть пустым")
+ private Mpa mpa;
@Override
public int compareTo(Film o) {
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Friends.java b/src/main/java/ru/yandex/practicum/filmorate/model/Friends.java
new file mode 100644
index 0000000..50de1a3
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Friends.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.filmorate.model;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+@Data
+@NoArgsConstructor
+public class Friends {
+
+ @NonNull
+ private long userId;
+
+ @NonNull
+ private long toUserId;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java
new file mode 100644
index 0000000..3244cd4
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java
@@ -0,0 +1,18 @@
+package ru.yandex.practicum.filmorate.model;
+
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+@Data
+@NoArgsConstructor
+public class Genre extends DataModel {
+
+ @NonNull
+ private Long id;
+
+ @NonNull
+ private String name;
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Like.java b/src/main/java/ru/yandex/practicum/filmorate/model/Like.java
new file mode 100644
index 0000000..957dbb0
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Like.java
@@ -0,0 +1,17 @@
+package ru.yandex.practicum.filmorate.model;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+@Data
+@NoArgsConstructor
+public class Like {
+
+ @NonNull
+ private long userId;
+
+ @NonNull
+ private long filmId;
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java
new file mode 100644
index 0000000..963d28b
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java
@@ -0,0 +1,18 @@
+package ru.yandex.practicum.filmorate.model;
+
+import jakarta.validation.constraints.Positive;
+import lombok.*;
+
+@Data
+@NoArgsConstructor
+public class Mpa extends DataModel {
+
+ @NonNull
+ @Positive
+ private long id;
+
+
+ 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 c8dd66e..ecb60fa 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
@@ -5,12 +5,11 @@
import lombok.*;
import java.time.LocalDate;
-import java.util.Set;
@Setter
@Getter
@ToString
-@AllArgsConstructor
+@RequiredArgsConstructor
@EqualsAndHashCode(exclude = {"id", "name", "birthday"}, callSuper = false)
public class User extends DataModel {
@@ -30,7 +29,4 @@ public class User extends DataModel {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate birthday;
- private Set friendsId;
-
-
}
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 e9aea22..433fdb7 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
@@ -8,12 +8,12 @@
import ru.yandex.practicum.filmorate.controller.ValidateController;
import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
import ru.yandex.practicum.filmorate.exception.ValidationException;
-import ru.yandex.practicum.filmorate.model.Film;
-import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.model.*;
import ru.yandex.practicum.filmorate.storage.FilmStorage;
import ru.yandex.practicum.filmorate.storage.UserStorage;
import java.util.Collection;
+import java.util.HashSet;
import java.util.stream.Collectors;
@Service
@@ -23,6 +23,7 @@ public class FilmService {
private final UserStorage userStorage;
private final ValidateController validateController;
+
private final Logger logger = LoggerFactory.getLogger(FilmService.class);
@Autowired
@@ -36,6 +37,7 @@ public FilmService(FilmStorage filmStorage, UserStorage userStorage,
public Film create(Film film) {
validateController.validateFilm(film);
Film returnFilm = filmStorage.create(film);
+ filmStorage.addGenre(returnFilm.getId(), returnFilm.getGenres());
logger.info("Фильм добавлен id: " + returnFilm.getId());
return returnFilm;
}
@@ -46,19 +48,26 @@ public Film getFilmId(long id) {
throw new ErrorIsNull("нет такого id");
}
logger.info("поиск по id=" + id);
+
+ getFilm.setGenres(filmStorage.getGenre(id));
+ getFilm.setLikesId(new HashSet<>(filmStorage.getLikeId(id)));
return getFilm;
}
public Collection getAll() {
logger.info("Вернули список");
- Collection returnAll = filmStorage.getAll();
- if (returnAll.isEmpty()) {
+ Collection returnAllFilm = filmStorage.getAll();
+
+ if (returnAllFilm.isEmpty()) {
throw new ErrorIsNull("список пуст");
}
- return returnAll;
+ filmStorage.getAllFullGenreLike(returnAllFilm);
+ return returnAllFilm;
}
+
public void delete(long id) {
+
Film delFilm = filmStorage.delete(id);
if (delFilm == null) {
throw new ErrorIsNull("нет такого id");
@@ -80,6 +89,8 @@ public Film update(Film newFilm) {
}
validateController.validateFilm(newFilm);
logger.info("запись фильма обновлена");
+
+ filmStorage.updateGenre(newFilm.getId(), newFilm.getGenres());
return filmStorage.update(newFilm);
}
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..2a57a4f
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java
@@ -0,0 +1,43 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.storage.GenreStorage;
+
+import java.util.Collection;
+
+@Service
+public class GenreService {
+ private final GenreStorage genreStorage;
+ private final Logger logger = LoggerFactory.getLogger(GenreStorage.class);
+
+ @Autowired
+ public GenreService(GenreStorage genreStorage) {
+ this.genreStorage = genreStorage;
+ }
+
+ public Genre getGenreId(long id) {
+ Genre result = genreStorage.getId(id);
+ if (result == null) {
+ logger.warn("нет такого жанра");
+ throw new ErrorIsNull("нет такого жанра");
+ }
+ logger.info("возвращаем жанр по id: " + id);
+ return result;
+ }
+
+ public Collection getGenreAll() {
+ logger.info("возращаем все жанры");
+ Collection reselt = genreStorage.getAll();
+ if (reselt.isEmpty()) {
+ throw new ErrorIsNull("список жанров пуст");
+ }
+ return reselt;
+ }
+
+
+}
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..8553b60
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java
@@ -0,0 +1,43 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.storage.MpaStorage;
+
+import java.util.Collection;
+
+@Service
+public class MpaService {
+
+ private final Logger logger = LoggerFactory.getLogger(MpaStorage.class);
+ private final MpaStorage mpa;
+
+ @Autowired
+ public MpaService(MpaStorage mpa) {
+ this.mpa = mpa;
+ }
+
+ public Mpa getMpaId(long id) {
+ Mpa result = mpa.getId(id);
+ if (result == null) {
+ logger.warn("нет такого рейтиена");
+ throw new ErrorIsNull("нет такого рейтиена");
+ }
+ logger.info("возвращаем рейтинг по id: " + id);
+ return result;
+ }
+
+ public Collection getMpaAll() {
+ logger.info("возращаем все жанры");
+ Collection reselt = mpa.getAll();
+ if (reselt.isEmpty()) {
+ throw new ErrorIsNull("список жанров пуст");
+ }
+ return reselt;
+ }
+
+}
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 1ecaa82..72da770 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
@@ -22,7 +22,7 @@ public class UserService {
private final Logger logger = LoggerFactory.getLogger(FilmService.class);
@Autowired
- public UserService(UserStorage userStorage, ValidateController validateController) {
+ public UserService(UserStorage userStorage, ValidateController validateController) {
this.userStorage = userStorage;
this.validateController = validateController;
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
index 38ac22e..e8d4fc1 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
@@ -1,8 +1,11 @@
package ru.yandex.practicum.filmorate.storage;
import ru.yandex.practicum.filmorate.model.DataModel;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.Genre;
import java.util.Collection;
+import java.util.Set;
public interface FilmStorage {
@@ -21,4 +24,15 @@ public interface FilmStorage {
Collection setLikeId(long id, long userId);
Collection delLikesId(long id, long userId);
+
+ void addGenre(long filmId, Set genres);
+
+ void deleteGenre(long filmId);
+
+ void updateGenre(long filmId, Set genres);
+
+ Set getGenre(long filmId);
+
+ void getAllFullGenreLike(Collection films);
+
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java
new file mode 100644
index 0000000..99204ab
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java
@@ -0,0 +1,13 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.DataModel;
+
+import java.util.Collection;
+
+public interface GenreStorage {
+
+ T getId(long id);
+
+ Collection getAll();
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
deleted file mode 100644
index a625616..0000000
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package ru.yandex.practicum.filmorate.storage;
-
-import org.springframework.stereotype.Repository;
-import ru.yandex.practicum.filmorate.model.Film;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-@Repository
-public class InMemoryFilmStorage extends Storage implements FilmStorage {
-
- @Override
- public Film create(Film film) {
- film.setId(getNextId());
- if (film.getLikesId() == null) {
- film.setLikesId(new HashSet<>() {
- });
- }
- dataMap.put(film.getId(), film);
- logger.info("Фильм добавлен id: " + film.getId());
- return film;
- }
-
- @Override
- public Film update(Film newFilm) {
- Film oldFilm = dataMap.get(newFilm.getId());
- oldFilm.setName(newFilm.getName());
- oldFilm.setDescription(newFilm.getDescription());
- oldFilm.setReleaseDate(newFilm.getReleaseDate());
- oldFilm.setDuration(newFilm.getDuration());
-
- if (newFilm.getLikesId() == null) {
- newFilm.setLikesId(new HashSet<>() {
- });
- }
- oldFilm.setLikesId(newFilm.getLikesId());
- logger.info("Запись фильма обновлена");
- return oldFilm;
- }
-
- @Override
- public Collection getLikeId(long id) {
- Film getLikes = dataMap.get(id);
- return getLikes.getLikesId();
- }
-
- @Override
- public Collection setLikeId(long id, long userId) {
- Film getLikes = dataMap.get(id);
- getLikes.getLikesId().add(userId);
- return getLikes.getLikesId();
- }
-
- @Override
- public Collection delLikesId(long id, long userId) {
- Film getLikes = dataMap.get(id);
- Set newLikesList = getLikes.getLikesId();
- newLikesList.remove(id);
- getLikes.setLikesId(newLikesList);
- return newLikesList;
- }
-
- private long getNextId() {
- long currentMaxId = dataMap.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
-
- }
-}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
deleted file mode 100644
index 3fc2128..0000000
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package ru.yandex.practicum.filmorate.storage;
-
-import org.springframework.stereotype.Repository;
-import ru.yandex.practicum.filmorate.model.User;
-
-import java.util.*;
-
-@Repository
-public class InMemoryUserStorage extends Storage implements UserStorage {
-
- @Override
- public User create(User user) {
- user.setId(getNextId());
- if (user.getFriendsId() == null) {
- user.setFriendsId(new HashSet<>() {
- });
- }
- dataMap.put(user.getId(), user);
- logger.info("Пользователь добавлен id: " + user.getId());
- return user;
- }
-
- @Override
- public User update(User newUser) {
- User oldUser = dataMap.get(newUser.getId());
- oldUser.setName(newUser.getName());
- oldUser.setEmail(newUser.getEmail());
- oldUser.setLogin(newUser.getLogin());
- oldUser.setBirthday(newUser.getBirthday());
- oldUser.setFriendsId(newUser.getFriendsId());
- logger.info("Запись пользователя обновлена");
- return oldUser;
- }
-
- @Override
- public Collection getFriendId(long id) {
- User getFriends = dataMap.get(id);
- return getFriends.getFriendsId();
- }
-
- @Override
- public Collection setFriendId(long id, long friendsId) {
- User getFriends = dataMap.get(id); //добавление в друзья
- Set newFriendsList = getFriends.getFriendsId();
- newFriendsList.add(friendsId);
- getFriends.setFriendsId(newFriendsList);
-
- User getFriendsTo = dataMap.get(friendsId); //зеркальное добавление в друзья
- Set newFriendsListTo = getFriendsTo.getFriendsId();
- newFriendsListTo.add(id);
- getFriendsTo.setFriendsId(newFriendsListTo);
- return newFriendsList;
- }
-
- @Override
- public Collection delFriendId(long id, long friendsId) {
- User getFriends = dataMap.get(id); //удаление из друзей
- Set newFriendsList = getFriends.getFriendsId();
- newFriendsList.remove(friendsId);
- getFriends.setFriendsId(newFriendsList);
-
- User getFriendsTo = dataMap.get(friendsId); //удаление из друзей
- Set newFriendsListTo = getFriendsTo.getFriendsId();
- newFriendsListTo.remove(id);
- getFriendsTo.setFriendsId(newFriendsListTo);
-
- return newFriendsList;
- }
-
- private long getNextId() {
- long currentMaxId = dataMap.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java
new file mode 100644
index 0000000..bf53b0c
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java
@@ -0,0 +1,14 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.DataModel;
+
+import java.util.Collection;
+
+public interface MpaStorage {
+
+
+ T getId(long id);
+
+ Collection getAll();
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
index 3cb17a4..05d0bbb 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
@@ -4,6 +4,7 @@
import java.util.Collection;
+
public interface UserStorage {
T create(T data);
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseRepository.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseRepository.java
new file mode 100644
index 0000000..83de445
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseRepository.java
@@ -0,0 +1,71 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+import java.util.List;
+import java.util.Optional;
+
+// базовый блок обработки запросов с db
+@RequiredArgsConstructor
+public class BaseRepository {
+
+
+ protected final JdbcTemplate jdbc;
+ protected final RowMapper mapper;
+
+ protected Optional findOne(String query, Object... params) { //возращаем 1 объект и db
+ try {
+ T result = jdbc.queryForObject(query, mapper, params);
+ return Optional.ofNullable(result); // возращаем объект в обёртке optional
+ } catch (EmptyResultDataAccessException ignored) {
+ return Optional.empty(); // если ошибка возращаем пустую обертку optional
+ } catch (DataAccessException e) {
+ throw new ErrorIsNull(e.getMessage());
+ }
+ }
+
+ protected List findMany(String query, Object... params) { //возращаем список с объектами из db
+ return jdbc.query(query, mapper, params);
+ }
+
+ protected boolean delete(String query, long id) { // удаление элемента по id из db
+ int rowsDeleted = jdbc.update(query, id);
+ return rowsDeleted > 0;
+ }
+
+ protected void update(String query, Object... params) { //обновление данных в db
+ int rowUpdated = jdbc.update(query, params);
+ if (rowUpdated == 0) {
+ throw new NotFoundException("не удалось обновить данные");
+ }
+ }
+
+ protected long insert(String query, Object... params) { //добавление новой записи с возращением id записи
+ GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
+ jdbc.update(connection -> {
+ PreparedStatement ps = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
+ for (int idx = 0; idx < params.length; idx++) {
+ ps.setObject(idx + 1, params[idx]);
+ }
+ return ps;
+ }, keyHolder);
+ Integer id = keyHolder.getKeyAs(Integer.class);
+ // Возвращаем id нового пользователя
+ if (id != null) {
+ return id;
+ } else {
+ throw new ValidationException("не удалось сохраанить данные");
+ }
+ }
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStore.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStore.java
new file mode 100644
index 0000000..e010c19
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStore.java
@@ -0,0 +1,202 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.support.rowset.SqlRowSet;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+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.storage.FilmStorage;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.yandex.practicum.filmorate.storage.mappers.GenreRowMapper;
+
+@Repository
+
+public class FilmDbStore extends BaseRepository implements FilmStorage {
+
+ protected final Logger logger = LoggerFactory.getLogger(FilmDbStore.class); //логгер
+
+ public FilmDbStore(JdbcTemplate jdbc, RowMapper mapper) {
+ super(jdbc, mapper);
+ }
+
+ @Override
+ public Film create(Film film) { //добавление нового фильма
+
+ try {
+ String query = "INSERT INTO films(name, description, release_date, duration, mpa_rating_id) VALUES(?,?,?,?,?)";
+ long id = insert(
+ query,
+ film.getName(),
+ film.getDescription(),
+ film.getReleaseDate(),
+ film.getDuration(),
+ film.getMpa().getId()
+ );
+ film.setId(id);
+ logger.info("добавили фильм id: " + id);
+ } catch (DataAccessException e) {
+ throw new ErrorIsNull(e.getMessage());
+ }
+ return film;
+ }
+
+ @Override
+ public Film update(Film film) { //обновили запись фильма
+ String query = "UPDATE films SET name=?, description=?, release_date=?, duration=?, mpa_rating_id=? WHERE id=?";
+ update(
+ query,
+ film.getName(),
+ film.getDescription(),
+ film.getReleaseDate(),
+ film.getDuration(),
+ film.getMpa().getId(),
+ film.getId()
+ );
+
+ logger.info("запись фильма обновлена");
+ return film;
+ }
+
+ @Override
+ public Film delete(long id) { // удаление фильма по id
+ Film film = getId(id);
+ String query = "DELETE FROM films WHERE id=?";
+ boolean isDelete = delete(query, id);
+ if (isDelete) {
+ logger.info("удален фильм id: " + id);
+
+ return film;
+ } else {
+ throw new NotFoundException("ошибка удаления записи");
+ }
+ }
+
+ @Override
+ public Film getId(long id) { //получам фильм по id
+ String query = "SELECT f.*, mpa_r.name AS mpa_name FROM films AS f LEFT OUTER JOIN MPA_RATING AS mpa_r " +
+ "ON f.MPA_RATING_ID = mpa_r.id WHERE f.id=?";
+ Optional film = findOne(query, id);
+ if (film.isPresent()) {
+ logger.info("возращаем фильм id: " + id);
+ Film result = film.get();
+ result.setLikesId(new HashSet<>(getLikeId(result.getId())));
+ return result;
+ } else {
+ throw new ErrorIsNull("фильма с таким id нет");
+ }
+ }
+
+ @Override
+ public Collection getAll() { //получам весь список фильмов
+ String query = "SELECT f.id, f.name, f.description, f.release_date, f.duration, f.mpa_rating_id, mpa_r.name AS mpa_name " +
+ "FROM films AS f LEFT OUTER JOIN MPA_RATING AS mpa_r ON f.MPA_RATING_ID = mpa_r.id";
+ logger.info("возращаем список фильмов");
+ return findMany(query);
+ }
+
+ public void getAllFullGenreLike(Collection films) {
+ List filmsId = films.stream().map(film -> String.valueOf(film.getId())).collect(Collectors.toList()); //создам список id фильмов из переданной коллекции
+ Map filmMap = films.stream().collect(Collectors.toMap(Film::getId, film -> film)); //создаем мапу id фильмом и самим фильмом)
+
+ String queryGenre = "SELECT g.film_id, gs.id AS id, gs.name" +
+ " FROM GENRE AS g LEFT OUTER JOIN GENRES AS gs ON g.GENRE_ID = gs.ID WHERE film_id IN (%s)";
+ String queryLikes = "SELECT film_id, user_id FROM film_likes WHERE film_id IN (%s)";
+
+ SqlRowSet rsGenre = jdbc.queryForRowSet(String.format(queryGenre, String.join(",", filmsId)));
+ while (rsGenre.next()) {
+ Genre genre = new Genre();
+ genre.setId(rsGenre.getLong("id"));
+ genre.setName(rsGenre.getString("name"));
+ filmMap.get(rsGenre.getLong("film_id")).getGenres().add(genre);
+ }
+
+ SqlRowSet rsLike = jdbc.queryForRowSet(String.format(queryLikes, String.join(",", filmsId)));
+ while (rsLike.next()) {
+ filmMap.get(rsLike.getLong("film_id")).getLikesId().add(rsLike.getLong("user_id"));
+ }
+ }
+
+ @Override
+ public Collection getLikeId(long filmId) { // получение списка лайков
+ String query = "SELECT user_id FROM film_likes WHERE film_id=" + filmId;
+ logger.info("получили список лайков");
+ return jdbc.queryForList(query, Long.class);
+ }
+
+ @Override
+ public Collection setLikeId(long filmId, long userId) { //добавление лайка
+ Collection likeList = getLikeId(filmId);
+ if (likeList.contains(userId)) {
+ throw new ErrorIsNull("данный пользователе уже поставил лайк");
+ }
+ String query = "INSERT INTO film_likes(film_id, user_id) VALUES (?,?)";
+ int rowUpdated = jdbc.update(query, filmId, userId);
+ if (rowUpdated > 0) {
+ logger.info("лайк добавлен");
+ return getLikeId(filmId);
+ } else {
+ throw new ErrorIsNull("ошибка добавления лайка");
+ }
+ }
+
+ @Override
+ public Collection delLikesId(long filmId, long userId) { // удалили лайк из списка
+ String quary = "DELETE FROM film_likes WHERE film_id=? AND user_id=?";
+ int rowDeleted = jdbc.update(quary, filmId, userId);
+ if (rowDeleted > 0) {
+ logger.info("удалили лайк из списка");
+ return getLikeId(filmId);
+ }
+ throw new ErrorIsNull("ошибка при удалении лайка");
+ }
+
+ @Override
+ public void addGenre(long filmId, Set genreSet) {
+ try {
+ List