Skip to content
Draft
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
14 changes: 13 additions & 1 deletion src/main/java/org/websoso/WSSServer/domain/UserNovel.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;
import org.websoso.WSSServer.domain.common.BaseEntity;
import org.websoso.WSSServer.domain.common.ReadStatus;

Expand All @@ -30,8 +32,10 @@
@DynamicInsert
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "user_novel", uniqueConstraints = {
@UniqueConstraint(columnNames = {"user_id", "novel_id"})
@UniqueConstraint(columnNames = {"user_id", "novel_id", "is_deleted"})
})
@SQLDelete(sql = "UPDATE user_novel SET is_deleted = true WHERE user_novel_id = ?")
@SQLRestriction("is_deleted = false")
public class UserNovel extends BaseEntity {

@Id
Expand All @@ -55,6 +59,9 @@ public class UserNovel extends BaseEntity {
@Column
private LocalDate endDate;

@Column(columnDefinition = "Boolean default false", nullable = false)
private boolean isDeleted = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
Expand All @@ -78,6 +85,7 @@ private UserNovel(ReadStatus status, Float userNovelRating, LocalDate startDate,
this.user = user;
this.novel = novel;
this.isInterest = false;
this.isDeleted = false;
}

public static UserNovel create(ReadStatus status, Float userNovelRating, LocalDate startDate, LocalDate endDate,
Expand All @@ -103,4 +111,8 @@ public void deleteEvaluation() {
this.endDate = null;
}

public void restore() {
this.isDeleted = false;
deleteEvaluation();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public Page<Novel> findFilteredNovels(Pageable pageable, List<Genre> genres, Boo
List<Keyword> keywords) {

NumberTemplate<Long> popularity = Expressions.numberTemplate(Long.class,
"(SELECT COUNT(un) FROM UserNovel un WHERE un.novel = {0} AND (un.isInterest = true OR un.status <> 'QUIT'))",
"(SELECT COUNT(un) FROM UserNovel un WHERE un.novel = {0} AND un.isDeleted = false AND (un.isInterest = true OR un.status <> 'QUIT'))",
novel);

JPAQuery<Novel> query = jpaQueryFactory
Expand Down Expand Up @@ -106,20 +106,25 @@ public Page<Novel> findFilteredNovels(Pageable pageable, List<Genre> genres, Boo

private NumberExpression<Double> getAverageRating(QNovel novel) {
return Expressions.numberTemplate(Double.class,
"(SELECT AVG(un.userNovelRating) FROM UserNovel un WHERE un.novel = {0} AND un.userNovelRating <> 0)",
"(SELECT AVG(un.userNovelRating) FROM UserNovel un WHERE un.novel = {0} AND un.isDeleted = false AND un.userNovelRating <> 0)",
novel);
}

private NumberExpression<Integer> getKeywordCount(QNovel novel, List<Keyword> keywords) {
return Expressions.numberTemplate(Integer.class,
"(SELECT COUNT(unk.keyword) FROM UserNovelKeyword unk WHERE unk.userNovel.novel = {0} AND unk.keyword IN ({1}) GROUP BY unk.userNovel.novel.id)",
"(SELECT COUNT(unk.keyword) FROM UserNovelKeyword unk JOIN unk.userNovel un WHERE un.novel = {0} AND un.isDeleted = false AND unk.keyword IN ({1}) GROUP BY un.novel.id)",
novel, keywords);
}

private NumberExpression<Long> getPopularity(QNovel novel) {
return new CaseBuilder()
.when(userNovel.isInterest.isTrue()
.or(userNovel.status.in(WATCHING, WATCHED)))
.when(
userNovel.isDeleted.isFalse()
.and(
userNovel.isInterest.isTrue()
.or(userNovel.status.in(WATCHING, WATCHED))
)
)
.then(1L)
.otherwise(0L)
.sum();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
public interface NovelRepository extends JpaRepository<Novel, Long>, NovelCustomRepository {

@Query("SELECT n FROM Novel n JOIN UserNovel un ON n.novelId = un.novel.novelId " +
"WHERE un.isDeleted = false " +
"GROUP BY n.novelId " +
"ORDER BY MAX(un.createdDate) DESC")
Page<Novel> findSosoPick(Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface UserNovelRepository extends JpaRepository<UserNovel, Long>, Use

Integer countByNovelAndIsInterestTrue(Novel novel);

@Query("SELECT SUM(un.userNovelRating) FROM UserNovel un WHERE un.novel = :novel")
@Query("SELECT SUM(un.userNovelRating) FROM UserNovel un WHERE un.novel = :novel AND un.isDeleted = false")
Float sumUserNovelRatingByNovel(Novel novel);

Integer countByNovelAndUserNovelRatingNot(Novel novel, float ratingToExclude);
Expand All @@ -29,4 +29,7 @@ public interface UserNovelRepository extends JpaRepository<UserNovel, Long>, Use
List<UserNovel> findUserNovelByUser(User user);

Optional<UserNovel> findByNovel_NovelIdAndUser(Long novelId, User user);

@Query(value = "SELECT * FROM user_novel WHERE user_id = :userId AND novel_id = :novelId", nativeQuery = true)
Optional<UserNovel> findByUserAndNovelIncludeDeleted(Long userId, Long novelId);
}
21 changes: 14 additions & 7 deletions src/main/java/org/websoso/WSSServer/service/NovelService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -131,13 +132,19 @@ private String getRandomNovelGenreImage(List<NovelGenre> novelGenres) {

public void registerAsInterest(User user, Long novelId) {
Novel novel = getNovelOrException(novelId);
UserNovel userNovel = userNovelService.getUserNovelOrNull(user, novel);

if (userNovel != null && userNovel.getIsInterest()) {
throw new CustomUserNovelException(ALREADY_INTERESTED, "already registered as interested");
}

if (userNovel == null) {
Optional<UserNovel> existingUserNovel = userNovelRepository.findByUserAndNovelIncludeDeleted(user.getUserId(),
novelId);
UserNovel userNovel;

if (existingUserNovel.isPresent()) {
userNovel = existingUserNovel.get();
if ((!userNovel.isDeleted()) && userNovel.getIsInterest()) {
throw new CustomUserNovelException(ALREADY_INTERESTED, "already registered as interested");
}
if (userNovel.isDeleted()) {
userNovel.restore();
}
} else {
try {
userNovel = userNovelService.createUserNovelByInterest(user, novel);
} catch (DataIntegrityViolationException e) {
Expand Down
28 changes: 26 additions & 2 deletions src/main/java/org/websoso/WSSServer/service/UserNovelService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -98,6 +99,22 @@ public void createEvaluation(User user, UserNovelCreateRequest request) {
Novel novel = novelRepository.findById(request.novelId())
.orElseThrow(() -> new CustomNovelException(NOVEL_NOT_FOUND, "novel with the given id is not found"));

Optional<UserNovel> conflictingUserNovel = userNovelRepository.findByUserAndNovelIncludeDeleted(
user.getUserId(), novel.getNovelId());

if (conflictingUserNovel.isPresent()) {
UserNovel userNovel = conflictingUserNovel.get();
if (!userNovel.isDeleted()) {
throw new CustomUserNovelException(USER_NOVEL_ALREADY_EXISTS, "this novel is already registered");
}
userNovel.restore();
userNovel.updateUserNovel(request.userNovelRating(), request.status(), request.startDate(),
request.endDate());
createUserNovelAttractivePoints(userNovel, request.attractivePoints());
createNovelKeywords(userNovel, request.keywordIds());
return;
}

try {
UserNovel userNovel = userNovelRepository.save(UserNovel.create(
request.status(),
Expand Down Expand Up @@ -236,8 +253,15 @@ public void deleteEvaluation(User user, Long novelId) {
}

public UserNovel createUserNovelByInterest(User user, Novel novel) {
if (getUserNovelOrNull(user, novel) != null) {
throw new CustomUserNovelException(USER_NOVEL_ALREADY_EXISTS, "this novel is already registered");
Optional<UserNovel> conflictingUserNovel = userNovelRepository.findByUserAndNovelIncludeDeleted(
user.getUserId(), novel.getNovelId());
if (conflictingUserNovel.isPresent()) {
UserNovel userNovel = conflictingUserNovel.get();
if (!userNovel.isDeleted()) {
throw new CustomUserNovelException(USER_NOVEL_ALREADY_EXISTS, "this novel is already registered");
}
userNovel.restore();
return userNovel;
}
return userNovelRepository.save(UserNovel.create(null, 0.0f, null, null, user, novel));
}
Expand Down
Loading