Add search publications use case but it's bugged.
This commit is contained in:
@@ -37,5 +37,24 @@
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.codiki.infrastructure.publication;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.publication.model.Publication;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.domain.publication.port.PublicationPort;
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
import org.codiki.infrastructure.publication.repository.PublicationRepository;
|
||||
@@ -12,9 +14,14 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class PublicationJpaAdapter implements PublicationPort {
|
||||
private final PublicationRepository repository;
|
||||
private final PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter;
|
||||
|
||||
public PublicationJpaAdapter(PublicationRepository repository) {
|
||||
public PublicationJpaAdapter(
|
||||
PublicationRepository repository,
|
||||
PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter
|
||||
) {
|
||||
this.repository = repository;
|
||||
this.publicationSearchCriteriaJpaAdapter = publicationSearchCriteriaJpaAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,4 +40,13 @@ public class PublicationJpaAdapter implements PublicationPort {
|
||||
public void delete(Publication publication) {
|
||||
repository.deleteById(publication.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Publication> search(List<PublicationSearchCriterion> criteria) {
|
||||
List<PublicationSearchCriterion> adaptedCriteria = publicationSearchCriteriaJpaAdapter.adaptCriteriaForJpa(criteria);
|
||||
return repository.search(adaptedCriteria)
|
||||
.stream()
|
||||
.map(PublicationEntity::toDomain)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.codiki.infrastructure.publication;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PublicationSearchCriteriaJpaAdapter {
|
||||
public List<PublicationSearchCriterion> adaptCriteriaForJpa(List<PublicationSearchCriterion> initialCriteria) {
|
||||
List<PublicationSearchCriterion> result = new LinkedList<>();
|
||||
|
||||
for (PublicationSearchCriterion criterion : initialCriteria) {
|
||||
boolean criterionAdaptationOccurred = false;
|
||||
|
||||
if (criterion.value() instanceof String criterionValue) {
|
||||
String unaccentedCriterionValue = StringUtils.stripAccents(criterionValue);
|
||||
result.add(new PublicationSearchCriterion(
|
||||
criterion.searchField(),
|
||||
criterion.searchType(),
|
||||
unaccentedCriterionValue
|
||||
));
|
||||
criterionAdaptationOccurred = true;
|
||||
}
|
||||
|
||||
if (!criterionAdaptationOccurred) {
|
||||
result.add(criterion);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class AuthorEntity {
|
||||
@Id
|
||||
private UUID id;
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
private String pseudo;
|
||||
// private String illustrationId;
|
||||
|
||||
public AuthorEntity(Author author) {
|
||||
@@ -35,6 +35,6 @@ public class AuthorEntity {
|
||||
}
|
||||
|
||||
public Author toDomain() {
|
||||
return new Author(id, name, "image");
|
||||
return new Author(id, pseudo, "image");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.codiki.infrastructure.publication.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
|
||||
public interface CustomPublicationRepository {
|
||||
List<PublicationEntity> search(List<PublicationSearchCriterion> criteria);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.codiki.infrastructure.publication.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
@Repository
|
||||
public class CustomPublicationRepositoryImpl implements CustomPublicationRepository {
|
||||
private final EntityManager entityManager;
|
||||
private final PublicationPredicateMapper publicationPredicateMapper;
|
||||
|
||||
public CustomPublicationRepositoryImpl(EntityManager entityManager, PublicationPredicateMapper publicationPredicateMapper) {
|
||||
this.entityManager = entityManager;
|
||||
this.publicationPredicateMapper = publicationPredicateMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublicationEntity> search(final List<PublicationSearchCriterion> criteria) {
|
||||
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
|
||||
CriteriaQuery<PublicationEntity> query = criteriaBuilder.createQuery(PublicationEntity.class);
|
||||
Root<PublicationEntity> fromPublication = query.from(PublicationEntity.class);
|
||||
|
||||
Predicate predicate = publicationPredicateMapper.map(criteria, criteriaBuilder, fromPublication);
|
||||
|
||||
CriteriaQuery<PublicationEntity> criteriaQuery = query.select(fromPublication)
|
||||
.distinct(true)
|
||||
.where(predicate);
|
||||
|
||||
return entityManager.createQuery(criteriaQuery)
|
||||
.getResultList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.codiki.infrastructure.publication.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.codiki.domain.publication.model.search.PublicationSearchField.AUTHOR_PSEUDO;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchField;
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static jakarta.persistence.criteria.JoinType.LEFT;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.From;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
@Component
|
||||
public class PublicationPredicateMapper {
|
||||
public Predicate map(
|
||||
List<PublicationSearchCriterion> criteria,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication
|
||||
) {
|
||||
List<Predicate> criteriaPredicates = criteria.stream()
|
||||
.map(criterion -> map(criterion, criteriaBuilder, fromPublication))
|
||||
.toList();
|
||||
return criteriaBuilder.or(criteriaPredicates.toArray(new Predicate[]{}));
|
||||
}
|
||||
|
||||
private Predicate map(
|
||||
PublicationSearchCriterion criterion,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication
|
||||
) {
|
||||
return switch (criterion.searchType()) {
|
||||
case EQUALS -> mapEqualsPredicate(criteriaBuilder, fromPublication, criterion.searchField(), criterion.value());
|
||||
case CONTAINS -> mapContainsPredicate(criteriaBuilder, fromPublication, criterion.searchField(), criterion.value());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private Predicate mapEqualsPredicate(
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication,
|
||||
PublicationSearchField searchField,
|
||||
Object value
|
||||
) {
|
||||
From<?, ?> from = fromPublication;
|
||||
String attributeName = searchField.name().toLowerCase();
|
||||
if (searchField == AUTHOR_PSEUDO) {
|
||||
from = fromPublication.join("author", LEFT);
|
||||
attributeName = "pseudo";
|
||||
}
|
||||
|
||||
return criteriaBuilder.equal(
|
||||
from.get(attributeName),
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
private Predicate mapContainsPredicate(
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication,
|
||||
PublicationSearchField searchField,
|
||||
Object value
|
||||
) {
|
||||
From<?, ?> from = fromPublication;
|
||||
String attributeName = searchField.name().toLowerCase();
|
||||
if (searchField == AUTHOR_PSEUDO) {
|
||||
from = fromPublication.join("author", LEFT);
|
||||
attributeName = "pseudo";
|
||||
}
|
||||
|
||||
return criteriaBuilder.like(
|
||||
from.get(attributeName),
|
||||
String.format("%%%s%%", value)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface PublicationRepository extends JpaRepository<PublicationEntity, UUID> {
|
||||
public interface PublicationRepository extends JpaRepository<PublicationEntity, UUID>, CustomPublicationRepository {
|
||||
@Query("""
|
||||
SELECT p
|
||||
FROM PublicationEntity p
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.codiki.infrastructure.publication;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.codiki.domain.publication.model.search.ComparisonType.CONTAINS;
|
||||
import static org.codiki.domain.publication.model.search.PublicationSearchField.KEY;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PublicationSearchCriteriaJpaAdapterTest {
|
||||
private PublicationSearchCriteriaJpaAdapter adapter;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
adapter = new PublicationSearchCriteriaJpaAdapter();
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class AdaptCriteriaForJpa {
|
||||
@Test
|
||||
void should_adapt_criteria_for_jpa() {
|
||||
// given
|
||||
List<PublicationSearchCriterion> initialCriteria = List.of(
|
||||
new PublicationSearchCriterion(KEY, CONTAINS, "critère")
|
||||
);
|
||||
|
||||
// when
|
||||
List<PublicationSearchCriterion> result = adapter.adaptCriteriaForJpa(initialCriteria);
|
||||
|
||||
// then
|
||||
List<PublicationSearchCriterion> expectedResult = List.of(
|
||||
new PublicationSearchCriterion(KEY, CONTAINS, "critere")
|
||||
);
|
||||
assertThat(result).isEqualTo(expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user