package com.magamochi.model.specification; import static java.util.Objects.nonNull; import com.magamochi.content.model.dto.MangaImportJobFilterDTO; import com.magamochi.content.model.entity.MangaImportJob; import jakarta.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.data.jpa.domain.Specification; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class MangaImportJobSpecification { public static Specification build(MangaImportJobFilterDTO filter) { return (root, query, cb) -> { List predicates = new ArrayList<>(); if (StringUtils.isNotBlank(filter.searchQuery())) { var searchTerm = filter.searchQuery().trim(); var searchPattern = "%" + searchTerm.toLowerCase() + "%"; var filenamePredicate = cb.like(cb.lower(root.get("originalFilename")), searchPattern); List orPredicates = new ArrayList<>(); orPredicates.add(filenamePredicate); try { var numericValue = Long.parseLong(searchTerm); orPredicates.add(cb.equal(root.get("id"), numericValue)); orPredicates.add(cb.equal(root.get("malId"), numericValue)); orPredicates.add(cb.equal(root.get("aniListId"), numericValue)); } catch (NumberFormatException ignored) { // not a numeric value, skip ID predicates } predicates.add(cb.or(orPredicates.toArray(Predicate[]::new))); } if (nonNull(filter.status())) { predicates.add(cb.equal(root.get("status"), filter.status())); } return cb.and(predicates.toArray(Predicate[]::new)); }; } }