Add a component to display a publication list and fix publication search rest service to handle ids.
This commit is contained in:
@@ -4,6 +4,7 @@ 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.model.PublicationSearchJpaCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchResult;
|
||||
import org.codiki.infrastructure.publication.repository.PublicationRepository;
|
||||
import org.springframework.data.domain.Limit;
|
||||
@@ -48,7 +49,7 @@ public class PublicationJpaAdapter implements PublicationPort {
|
||||
|
||||
@Override
|
||||
public List<Publication> search(List<PublicationSearchCriterion> criteria) {
|
||||
List<PublicationSearchCriterion> adaptedCriteria = publicationSearchCriteriaJpaAdapter.adaptCriteriaForJpa(criteria);
|
||||
List<PublicationSearchJpaCriterion> adaptedCriteria = publicationSearchCriteriaJpaAdapter.adaptCriteriaForJpa(criteria);
|
||||
return repository.search(adaptedCriteria)
|
||||
.stream()
|
||||
.map(PublicationEntity::toDomain)
|
||||
|
||||
@@ -3,12 +3,15 @@ package org.codiki.infrastructure.publication;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codiki.domain.publication.exception.BadPublicationSearchCriterionException;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaField;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PublicationSearchCriteriaJpaAdapter {
|
||||
public List<PublicationSearchCriterion> adaptCriteriaForJpa(List<PublicationSearchCriterion> initialCriteria) {
|
||||
public List<PublicationSearchJpaCriterion> adaptCriteriaForJpa(List<PublicationSearchCriterion> initialCriteria) {
|
||||
List<PublicationSearchCriterion> result = new LinkedList<>();
|
||||
|
||||
for (PublicationSearchCriterion criterion : initialCriteria) {
|
||||
@@ -29,6 +32,19 @@ public class PublicationSearchCriteriaJpaAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.stream()
|
||||
.map(this::mapToJpaCriterion)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private PublicationSearchJpaCriterion mapToJpaCriterion(PublicationSearchCriterion criterion) {
|
||||
return new PublicationSearchJpaCriterion(
|
||||
PublicationSearchJpaField.fromDomain(criterion.searchField())
|
||||
.orElseThrow(() -> new BadPublicationSearchCriterionException(
|
||||
String.format("Unknown field research criterion: %s", criterion.searchField()))
|
||||
),
|
||||
criterion.searchType(),
|
||||
criterion.value()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.codiki.infrastructure.publication.model;
|
||||
|
||||
import org.codiki.domain.publication.model.search.ComparisonType;
|
||||
|
||||
public record PublicationSearchJpaCriterion(
|
||||
PublicationSearchJpaField searchField,
|
||||
ComparisonType searchType,
|
||||
Object value
|
||||
) { }
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.codiki.infrastructure.publication.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchField;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
public enum PublicationSearchJpaField {
|
||||
ID,
|
||||
KEY,
|
||||
TITLE,
|
||||
TEXT,
|
||||
DESCRIPTION,
|
||||
CREATION_DATE("creationDate"),
|
||||
CATEGORY_ID("categoryId"),
|
||||
AUTHOR_ID("author.id"),
|
||||
AUTHOR_PSEUDO("author.pseudo");
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
PublicationSearchJpaField() {
|
||||
this.fieldName = name().toLowerCase();
|
||||
}
|
||||
|
||||
PublicationSearchJpaField(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public static Optional<PublicationSearchJpaField> fromDomain(PublicationSearchField publicationSearchField) {
|
||||
return Arrays.stream(values())
|
||||
.filter(field -> field.name().equals(publicationSearchField.name()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.codiki.infrastructure.publication.repository;
|
||||
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaCriterion;
|
||||
|
||||
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);
|
||||
List<PublicationEntity> search(List<PublicationSearchJpaCriterion> criteria);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
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;
|
||||
import org.codiki.infrastructure.publication.model.PublicationEntity;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaCriterion;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class CustomPublicationRepositoryImpl implements CustomPublicationRepository {
|
||||
@@ -23,7 +22,7 @@ public class CustomPublicationRepositoryImpl implements CustomPublicationReposit
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublicationEntity> search(final List<PublicationSearchCriterion> criteria) {
|
||||
public List<PublicationEntity> search(final List<PublicationSearchJpaCriterion> criteria) {
|
||||
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
|
||||
CriteriaQuery<PublicationEntity> query = criteriaBuilder.createQuery(PublicationEntity.class);
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package org.codiki.infrastructure.publication.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
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.codiki.infrastructure.publication.model.PublicationSearchJpaCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaField;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static jakarta.persistence.criteria.JoinType.LEFT;
|
||||
import static org.codiki.infrastructure.publication.model.PublicationSearchJpaField.AUTHOR_PSEUDO;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.From;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
@@ -17,54 +19,63 @@ import jakarta.persistence.criteria.Root;
|
||||
@Component
|
||||
public class PublicationPredicateMapper {
|
||||
public Predicate map(
|
||||
List<PublicationSearchCriterion> criteria,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication
|
||||
List<PublicationSearchJpaCriterion> criteria,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication
|
||||
) {
|
||||
List<Predicate> criteriaPredicates = criteria.stream()
|
||||
.map(criterion -> map(criterion, criteriaBuilder, fromPublication))
|
||||
.toList();
|
||||
.map(criterion -> map(criterion, criteriaBuilder, fromPublication))
|
||||
.toList();
|
||||
return criteriaBuilder.or(criteriaPredicates.toArray(new Predicate[]{}));
|
||||
}
|
||||
|
||||
private Predicate map(
|
||||
PublicationSearchCriterion criterion,
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication
|
||||
PublicationSearchJpaCriterion 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());
|
||||
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
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication,
|
||||
PublicationSearchJpaField searchField,
|
||||
Object value
|
||||
) {
|
||||
Predicate result;
|
||||
|
||||
From<?, ?> from = fromPublication;
|
||||
String attributeName = searchField.name().toLowerCase();
|
||||
String attributeName = searchField.getFieldName();
|
||||
if (searchField == AUTHOR_PSEUDO) {
|
||||
from = fromPublication.join("author", LEFT);
|
||||
attributeName = "pseudo";
|
||||
}
|
||||
|
||||
return criteriaBuilder.equal(
|
||||
criteriaBuilder.lower(
|
||||
from.get(attributeName)
|
||||
),
|
||||
value
|
||||
);
|
||||
if (value instanceof UUID) {
|
||||
result = criteriaBuilder.equal(from.get(attributeName), value);
|
||||
} else {
|
||||
result = criteriaBuilder.equal(
|
||||
criteriaBuilder.lower(
|
||||
from.get(attributeName)
|
||||
),
|
||||
value
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Predicate mapContainsPredicate(
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication,
|
||||
PublicationSearchField searchField,
|
||||
Object value
|
||||
CriteriaBuilder criteriaBuilder,
|
||||
Root<PublicationEntity> fromPublication,
|
||||
PublicationSearchJpaField searchField,
|
||||
Object value
|
||||
) {
|
||||
From<?, ?> from = fromPublication;
|
||||
String attributeName = searchField.name().toLowerCase();
|
||||
@@ -74,10 +85,10 @@ public class PublicationPredicateMapper {
|
||||
}
|
||||
|
||||
return criteriaBuilder.like(
|
||||
criteriaBuilder.lower(
|
||||
from.get(attributeName)
|
||||
),
|
||||
String.format("%%%s%%", value)
|
||||
criteriaBuilder.lower(
|
||||
from.get(attributeName)
|
||||
),
|
||||
String.format("%%%s%%", value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package org.codiki.infrastructure.publication;
|
||||
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
|
||||
import org.codiki.domain.publication.model.search.PublicationSearchField;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaCriterion;
|
||||
import org.codiki.infrastructure.publication.model.PublicationSearchJpaField;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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;
|
||||
@@ -24,15 +27,15 @@ class PublicationSearchCriteriaJpaAdapterTest {
|
||||
void should_adapt_criteria_for_jpa() {
|
||||
// given
|
||||
List<PublicationSearchCriterion> initialCriteria = List.of(
|
||||
new PublicationSearchCriterion(KEY, CONTAINS, "critère")
|
||||
new PublicationSearchCriterion(PublicationSearchField.KEY, CONTAINS, "critère")
|
||||
);
|
||||
|
||||
// when
|
||||
List<PublicationSearchCriterion> result = adapter.adaptCriteriaForJpa(initialCriteria);
|
||||
List<PublicationSearchJpaCriterion> result = adapter.adaptCriteriaForJpa(initialCriteria);
|
||||
|
||||
// then
|
||||
List<PublicationSearchCriterion> expectedResult = List.of(
|
||||
new PublicationSearchCriterion(KEY, CONTAINS, "crit_re")
|
||||
List<PublicationSearchJpaCriterion> expectedResult = List.of(
|
||||
new PublicationSearchJpaCriterion(PublicationSearchJpaField.KEY, CONTAINS, "crit_re")
|
||||
);
|
||||
assertThat(result).isEqualTo(expectedResult);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user