feat: implement search by manga's alternative titles
This commit is contained in:
parent
1526dc4bc9
commit
69ee91b9c6
@ -3,6 +3,7 @@ package com.magamochi.mangamochi.model.dto;
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
import com.magamochi.mangamochi.model.entity.Manga;
|
||||
import com.magamochi.mangamochi.model.entity.MangaAlternativeTitle;
|
||||
import com.magamochi.mangamochi.model.entity.MangaChapter;
|
||||
import com.magamochi.mangamochi.model.entity.MangaProvider;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@ -35,7 +36,7 @@ public record MangaDTO(
|
||||
manga.getPublishedTo(),
|
||||
manga.getSynopsis(),
|
||||
manga.getMangaProviders().size(),
|
||||
manga.getAlternativeTitles(),
|
||||
manga.getAlternativeTitles().stream().map(MangaAlternativeTitle::getTitle).toList(),
|
||||
manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(),
|
||||
manga.getMangaAuthors().stream()
|
||||
.map(mangaAuthor -> mangaAuthor.getAuthor().getName())
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
package com.magamochi.mangamochi.model.entity;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.array.ListArrayType;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import lombok.*;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
|
||||
@Entity
|
||||
@ -26,10 +24,6 @@ public class Manga {
|
||||
|
||||
private String title;
|
||||
|
||||
@Type(ListArrayType.class)
|
||||
@Column(name = "alternative_titles", columnDefinition = "text[]")
|
||||
private List<String> alternativeTitles;
|
||||
|
||||
// @Enumerated(EnumType.STRING)
|
||||
private String status;
|
||||
|
||||
@ -61,5 +55,8 @@ public class Manga {
|
||||
@OneToMany(mappedBy = "manga")
|
||||
private List<UserFavoriteManga> userFavoriteMangas;
|
||||
|
||||
@OneToMany(mappedBy = "manga")
|
||||
private List<MangaAlternativeTitle> alternativeTitles;
|
||||
|
||||
private Integer chapterCount;
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package com.magamochi.mangamochi.model.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "manga_alternative_titles")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class MangaAlternativeTitle {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "manga_id")
|
||||
private Manga manga;
|
||||
|
||||
private String title;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.magamochi.mangamochi.model.repository;
|
||||
|
||||
import com.magamochi.mangamochi.model.entity.MangaAlternativeTitle;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MangaAlternativeTitlesRepository
|
||||
extends JpaRepository<MangaAlternativeTitle, Long> {}
|
||||
@ -27,9 +27,14 @@ public class MangaSpecification {
|
||||
var titlePredicate =
|
||||
criteriaBuilder.like(criteriaBuilder.lower(root.get("title")), searchPattern);
|
||||
|
||||
var authorsPredicate = searchInAuthors(root, query, criteriaBuilder, searchPattern);
|
||||
var alternativeTitlesPredicate =
|
||||
searchInAlternativeTitles(root, criteriaBuilder, searchPattern);
|
||||
|
||||
var searchPredicate = criteriaBuilder.or(titlePredicate, authorsPredicate);
|
||||
var authorsPredicate = searchInAuthors(root, criteriaBuilder, searchPattern);
|
||||
|
||||
var searchPredicate =
|
||||
criteriaBuilder.or(
|
||||
criteriaBuilder.or(titlePredicate, alternativeTitlesPredicate), authorsPredicate);
|
||||
|
||||
predicates.add(searchPredicate);
|
||||
}
|
||||
@ -64,11 +69,16 @@ public class MangaSpecification {
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate searchInAlternativeTitles(
|
||||
Root<Manga> root, CriteriaBuilder criteriaBuilder, String searchPattern) {
|
||||
Join<Manga, ?> alternativeTitlesJoin = root.join("alternativeTitles", JoinType.LEFT);
|
||||
|
||||
return criteriaBuilder.like(
|
||||
criteriaBuilder.lower(alternativeTitlesJoin.get("title")), searchPattern);
|
||||
}
|
||||
|
||||
private static Predicate searchInAuthors(
|
||||
Root<Manga> root,
|
||||
CriteriaQuery<?> query,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
String searchPattern) {
|
||||
Root<Manga> root, CriteriaBuilder criteriaBuilder, String searchPattern) {
|
||||
Join<Manga, ?> mangaAuthorsJoin = root.join("mangaAuthors", JoinType.LEFT);
|
||||
Join<Object, Author> authorJoin = mangaAuthorsJoin.join("author", JoinType.LEFT);
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ public class MangaImportService {
|
||||
|
||||
private final JikanClient jikanClient;
|
||||
private final MangaChapterImageRepository mangaChapterImageRepository;
|
||||
private final MangaAlternativeTitlesRepository mangaAlternativeTitlesRepository;
|
||||
|
||||
RateLimiter rateLimiter = RateLimiter.create(1);
|
||||
|
||||
@ -125,7 +126,6 @@ public class MangaImportService {
|
||||
rateLimiter.acquire();
|
||||
var mangaData = jikanClient.getMangaById(manga.getMalId());
|
||||
|
||||
manga.setAlternativeTitles(mangaData.data().title_synonyms());
|
||||
manga.setSynopsis(mangaData.data().synopsis());
|
||||
manga.setStatus(mangaData.data().status());
|
||||
manga.setScore(DoubleUtil.round((double) mangaData.data().score(), 2));
|
||||
@ -205,7 +205,12 @@ public class MangaImportService {
|
||||
manga.setCoverImage(image);
|
||||
}
|
||||
|
||||
mangaRepository.save(manga);
|
||||
var mangaEntity = mangaRepository.save(manga);
|
||||
var alternativeTitles =
|
||||
mangaData.data().title_synonyms().stream()
|
||||
.map(at -> MangaAlternativeTitle.builder().manga(mangaEntity).title(at).build())
|
||||
.toList();
|
||||
mangaAlternativeTitlesRepository.saveAll(alternativeTitles);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("Error updating manga data for manga {}. {}", manga.getTitle(), e);
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
CREATE TABLE manga_alternative_titles
|
||||
(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
manga_id BIGINT REFERENCES mangas (id),
|
||||
title VARCHAR NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO manga_alternative_titles (manga_id, title)
|
||||
SELECT id as manga_id,
|
||||
unnest(alternative_titles) as title
|
||||
FROM mangas
|
||||
WHERE alternative_titles IS NOT NULL;
|
||||
|
||||
CREATE INDEX idx_manga_alternative_titles_manga_id ON manga_alternative_titles (manga_id);
|
||||
|
||||
CREATE INDEX idx_manga_alternative_titles_title ON manga_alternative_titles (title);
|
||||
|
||||
ALTER TABLE mangas DROP COLUMN alternative_titles;
|
||||
Loading…
x
Reference in New Issue
Block a user