Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import ru.yandex.practicum.filmorate.dto.FilmDto;
import ru.yandex.practicum.filmorate.dto.request.create.FilmCreateRequest;
import ru.yandex.practicum.filmorate.dto.request.update.FilmUpdateRequest;
import ru.yandex.practicum.filmorate.model.Assessment;
import ru.yandex.practicum.filmorate.service.FilmService;
import ru.yandex.practicum.filmorate.service.util.LikeAction;

Expand Down Expand Up @@ -66,6 +67,11 @@ public FilmDto update(@RequestBody FilmUpdateRequest request) {
return filmService.update(request);
}

@PutMapping("/{filmId}/assessment/{assessment}/user/{userId}")
public void setAssessment(@PathVariable long filmId,@PathVariable int assessment, @PathVariable long userId) {
filmService.changeAssessment(LikeAction.SET, filmId, assessment, userId);
}

@PutMapping("/{filmId}/like/{userId}")
public void setLike(@PathVariable long filmId, @PathVariable long userId) {
filmService.changeLike(LikeAction.SET, filmId, userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ru.yandex.practicum.filmorate.dal;

import ru.yandex.practicum.filmorate.model.Assessment;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.model.Like;

import java.util.Collection;
import java.util.Map;
Expand Down Expand Up @@ -52,4 +54,6 @@ public interface FilmStorage {
void removeFilm(long filmId);

Collection<Film> getFilmsByIds(Collection<Long> ids);

Like createLike(long filmId, int assessmentValue, long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import ru.yandex.practicum.filmorate.dal.FilmStorage;
import ru.yandex.practicum.filmorate.dal.rowmappers.LikeRowMapper;
import ru.yandex.practicum.filmorate.exception.InternalServerException;
import ru.yandex.practicum.filmorate.model.Assessment;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.model.Like;

import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

import static ru.yandex.practicum.filmorate.dal.database.sql.FilmQueryes.*;

Expand All @@ -34,7 +39,8 @@ public Film createFilm(Film film) {
film.getDescription(),
film.getReleaseDate(),
film.getDuration().toMinutes(),
film.getMpaId()
film.getMpaId(),
film.getAverageAssessment()
);
film.setId(id);
insertGenreIds(film);
Expand All @@ -52,6 +58,7 @@ public Film updateFilm(Film film) {
film.getReleaseDate(),
film.getDuration().toMinutes(),
film.getMpaId(),
film.getAverageAssessment(),
film.getId()
);
insertGenreIds(film);
Expand All @@ -65,9 +72,15 @@ public Optional<Film> findById(long filmId) {
Optional<Film> filmOptional = findOneByIdInTable(filmId, "films");
filmOptional.ifPresent(film -> film.setGenreIds(getGenreIdsByFilmId(filmId)));
filmOptional.ifPresent(film -> film.setDirectorIds(getDirectorIdsByFilmId(filmId)));
filmOptional.ifPresent(film -> film.setAssessments(getLikesByFilmId(filmId)));
return filmOptional;
}

private Set<Like> getLikesByFilmId(long filmId) {
return jdbc.query(SQL_FILMS_FIND_LIKES_BY_FILM_ID, new LikeRowMapper(), filmId).stream()
.collect(Collectors.toUnmodifiableSet());
}

@Override
public Collection<Film> findAll() {
return findManyFilms(SQL_FILMS_FIND_ALL);
Expand Down Expand Up @@ -193,6 +206,8 @@ private Collection<Film> findManyFilms(String query, Object... params) {
if (!rs.wasNull() && film != null) film.addGenreId(genreId);
int directorId = rs.getInt("director_id");
if (!rs.wasNull() && film != null) film.addDirectorId(directorId);
float assessment = rs.getFloat("assessment");
if (!rs.wasNull() && film != null) film.setAverageAssessment(assessment);
}
return new ArrayList<>(films.values());
}, params);
Expand Down Expand Up @@ -226,4 +241,31 @@ WHERE f.id IN (%s)

return findManyFilms(sql, ids.toArray());
}

@Transactional
@Override
public Like createLike(long filmId, int assessmentValue, long userId) {
long likeId = insertWithKeyHolder(
"INSERT INTO assessments (film_id, user_id, assessment) VALUES (?, ?, ?)",
filmId,
userId,
assessmentValue
);
updateAverageAssessment(filmId);
return Like.builder()
.id(likeId)
.assessment(Assessment.of(assessmentValue))
.userId(userId)
.build();
}

private void updateAverageAssessment(long filmId) {
Optional<Film> optionalFilm = findOneByIdInTable(filmId, "films");
optionalFilm.ifPresent(film -> {
film.setAssessments(getLikesByFilmId(filmId));
film.getAverageAssessment();
updateFilm(film);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class FilmQueryes {
mrg.RELEASE_DATE,
mrg.DURATION,
mrg.MPA_ID,
mrg.ASSESSMENT,
gof.GENRE_ID,
dof.DIRECTOR_ID,
user_id
Expand All @@ -19,6 +20,7 @@ public class FilmQueryes {
RELEASE_DATE,
DURATION,
MPA_ID,
f.ASSESSMENT,
l.USER_ID
FROM FILMS f
LEFT JOIN LIKES l ON f.ID = l.FILM_ID
Expand All @@ -35,6 +37,7 @@ public class FilmQueryes {
mrg.RELEASE_DATE,
mrg.DURATION,
mrg.MPA_ID,
mrg.ASSESSMENT,
gof.GENRE_ID,
dof.DIRECTOR_ID,
user_id
Expand All @@ -45,6 +48,7 @@ public class FilmQueryes {
RELEASE_DATE,
DURATION,
MPA_ID,
f.ASSESSMENT,
l.USER_ID
FROM FILMS f
LEFT JOIN LIKES l ON f.ID = l.FILM_ID
Expand Down Expand Up @@ -129,6 +133,12 @@ MERGE INTO GENRES_OF_FILMS (FILM_ID, GENRE_ID) KEY (FILM_ID, GENRE_ID) VALUES
WHERE dof.FILM_ID = ?
""";

public static final String SQL_FILMS_FIND_LIKES_BY_FILM_ID = """
SELECT *
FROM ASSESSMENTS
WHERE FILM_ID = ?
""";

public static final String SQL_FILMS_INSERT_DIRECTORIDS = """
MERGE INTO DIRECTORS_OF_FILMS (FILM_ID, DIRECTOR_ID) KEY (FILM_ID, DIRECTOR_ID) VALUES
""";
Expand All @@ -139,9 +149,10 @@ INSERT INTO films (
description,
release_date,
duration,
mpa_id
mpa_id,
assessment
)
VALUES (?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?)
""";

public static final String SQL_FILMS_UPDATE = """
Expand All @@ -150,7 +161,8 @@ INSERT INTO films (
description = ?,
release_date = ?,
duration = ?,
mpa_id = ?
mpa_id = ?,
assessment = ?
WHERE id = ?
""";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import org.springframework.stereotype.Component;
import ru.yandex.practicum.filmorate.dal.FilmStorage;
import ru.yandex.practicum.filmorate.exception.MethodNotImplementedException;
import ru.yandex.practicum.filmorate.model.Assessment;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.model.Like;

import java.util.Collection;
import java.util.Map;
Expand Down Expand Up @@ -87,4 +89,9 @@ public void removeFilm(long filmId) {
public Collection<Film> getFilmsByIds(Collection<Long> ids) {
throw new MethodNotImplementedException();
}

@Override
public Like createLike(long filmId, int assessmentValue, long userId) {
throw new MethodNotImplementedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public Film mapRow(ResultSet resultSet, int rowNum) throws SQLException {
.releaseDate(resultSet.getDate("release_date").toLocalDate())
.duration(Duration.ofMinutes(resultSet.getInt("duration")))
.mpaId(resultSet.getInt("mpa_id"))
.averageAssessment(resultSet.getFloat("assessment"))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ru.yandex.practicum.filmorate.dal.rowmappers;

import org.springframework.jdbc.core.RowMapper;
import ru.yandex.practicum.filmorate.model.Assessment;
import ru.yandex.practicum.filmorate.model.Like;

import java.sql.ResultSet;
import java.sql.SQLException;

public class LikeRowMapper implements RowMapper<Like> {
@Override
public Like mapRow(ResultSet resultSet, int rowNum) throws SQLException {
return Like.builder()
.id(resultSet.getLong("id"))
.filmId(resultSet.getLong("film_id"))
.userId(resultSet.getLong("user_id"))
.assessment(Assessment.of(resultSet.getInt("assessment")))
.build();
}
}
3 changes: 3 additions & 0 deletions src/main/java/ru/yandex/practicum/filmorate/dto/FilmDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class FilmDto {
@JsonProperty("rate")
int likesCount;

@JsonProperty("assessment")
float averageAssessment;

@Builder.Default
private MpaDto mpa = new MpaDto();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static FilmDto mapToFilmDto(Film film, Mpa mpa, Set<Genre> genres, Set<Di
.map(director -> new DirectorDto(director.getId(), director.getName()))
.toList()
)
.averageAssessment(film.getAverageAssessment())
.build();
}

Expand Down Expand Up @@ -87,6 +88,8 @@ public static Film updateFilmFields(Film film, FilmUpdateRequest request) {
.map(Director::getId)
.collect(Collectors.toSet()));

film.getAverageAssessment();

return film;
}

Expand Down
26 changes: 26 additions & 0 deletions src/main/java/ru/yandex/practicum/filmorate/model/Assessment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ru.yandex.practicum.filmorate.model;

import lombok.Getter;

@Getter
public enum Assessment {
UNDEFINED, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN;

private int value;

public static Assessment of(int value) {
Assessment result = Assessment.UNDEFINED;
if (value < 1 || value > 10) {
result.setValue(value);
return result;
}
result = values()[value];
result.setValue(result.ordinal());
return result;
}

private void setValue(int value) {
this.value = value;
}
}

29 changes: 28 additions & 1 deletion src/main/java/ru/yandex/practicum/filmorate/model/Film.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

@Data
@Builder(toBuilder = true)
Expand Down Expand Up @@ -37,8 +38,34 @@ public class Film {
private Set<Long> likes = new HashSet<>();

@JsonProperty(value = "rate")
private int likesCount;

@Builder.Default
private int likesCount = 0;
private Set<Like> assessments = new HashSet<>();

@JsonProperty(value = "assessment")
private float averageAssessment;

public float getAverageAssessment() {
if (assessments.isEmpty()) {
return 0f;
} else if (assessments.size() == 1) {
return assessments.iterator().next().getAssessment().getValue();
}
AtomicLong count = new AtomicLong();
AtomicLong sum = new AtomicLong();
assessments.stream()
.map(Like::getAssessment)
.filter(assessment -> !assessment.equals(Assessment.UNDEFINED))
.map(Assessment::getValue).forEach(value -> {
sum.addAndGet(value);
count.getAndIncrement();
});

float average = (float) sum.get() / count.get();
averageAssessment = Math.round(average * 100) / 100.0f;
return averageAssessment;
}

public int getLikesCount() {
likesCount = likes.size();
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/ru/yandex/practicum/filmorate/model/Like.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.yandex.practicum.filmorate.model;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Like {
long id;
long filmId;
long userId;
Assessment assessment;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import ru.yandex.practicum.filmorate.dto.FilmDto;
import ru.yandex.practicum.filmorate.dto.request.create.FilmCreateRequest;
import ru.yandex.practicum.filmorate.dto.request.update.FilmUpdateRequest;
import ru.yandex.practicum.filmorate.exception.MethodNotImplementedException;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ParameterNotValidException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
Expand Down Expand Up @@ -368,4 +369,31 @@ public Collection<FilmDto> getFilmsByIds(Collection<Long> ids) {
))
.toList();
}

public void changeAssessment(LikeAction likeAction, long filmId, int assessmentValue, long userId) {

if (Assessment.of(assessmentValue).equals(Assessment.UNDEFINED)) {
throw new ParameterNotValidException("assessment = " + assessmentValue +
".", "Значение должно быть от 1 до 10");
}
easyCheckFilm(filmId);
easyCheckUser(userId);

switch (likeAction) {
case SET -> filmStorage.createLike(filmId, assessmentValue, userId);
case REMOVE -> throw new MethodNotImplementedException();
}
}

private void easyCheckFilm(long filmId) {
if (filmStorage.checkFilmIsNotPresent(filmId)) {
throw new NotFoundException("Фильм с id=" + filmId + " не найден.");
}
}

private void easyCheckUser(long userId) {
if (userStorage.checkUserIsNotPresent(userId)) {
throw new NotFoundException("Пользователь с id=" + userId + " не найден.");
}
}
}
Loading
Loading