package pl.com.bottega.documentmanagement.infrastructure; import org.springframework.stereotype.Component; import pl.com.bottega.documentmanagement.api.*; import pl.com.bottega.documentmanagement.domain.*; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import java.util.Collection; import java.util.HashSet; import static com.google.common.base.Preconditions.checkNotNull; /** * Created by maciuch on 12.06.16. */ @Component public class JPADocumentsCatalog implements DocumentsCatalog { @PersistenceContext private EntityManager entityManager; @Override @RequiresAuth(roles = "STAFF") public DocumentDto get(DocumentNumber documentNumber) { checkNotNull(documentNumber); CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<DocumentDto> query = builder.createQuery(DocumentDto.class); Root<Document> root = query.from(Document.class); query.where(builder.and( builder.equal(root.get(Document_.documentNumber), documentNumber)), builder.not(root.get(Document_.deleted)) ); selectDocumentDto(builder, query, root); return entityManager.createQuery(query).getSingleResult(); } private void selectDocumentDto(CriteriaBuilder builder, CriteriaQuery<DocumentDto> query, Root<Document> root) { query.select(builder.construct(DocumentDto.class, root.get(Document_.documentNumber).get(DocumentNumber_.number), root.get(Document_.title), root.get(Document_.content), root.get(Document_.status), root.get(Document_.createdAt), root.get(Document_.verifiedAt), root.get(Document_.updatedAt), root.get(Document_.creator).get(Employee_.employeeId).get(EmployeeId_.id), root.get(Document_.verificator).get(Employee_.employeeId).get(EmployeeId_.id) )); } @Override @RequiresAuth(roles = "STAFF") public DocumentSearchResults find(DocumentCriteria documentCriteria) { checkNotNull(documentCriteria); CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<DocumentDto> query = builder.createQuery(DocumentDto.class); Root<Document> root = query.from(Document.class); selectDocumentDto(builder, query, root); applyCriteria(documentCriteria, builder, query, root); CriteriaQuery<Long> countQuery = builder.createQuery(Long.class); Root<Document> countRoot = countQuery.from(Document.class); countQuery.select(builder.count(countRoot)); applyCriteria(documentCriteria, builder, countQuery, countRoot); Query jpaQuery = entityManager.createQuery(query); Query jpaCountQuery = entityManager.createQuery(countQuery); long first = (documentCriteria.getPageNumber() - 1) * documentCriteria.getPerPage(); jpaQuery.setFirstResult((int)first); jpaQuery.setMaxResults(documentCriteria.getPerPage().intValue()); return new DocumentSearchResults(jpaQuery.getResultList(), documentCriteria.getPerPage(), documentCriteria.getPageNumber(), (Long) jpaCountQuery.getSingleResult() ); } private void applyCriteria(DocumentCriteria documentCriteria, CriteriaBuilder builder, CriteriaQuery query, Root<Document> root) { Collection<Predicate> predicates = new HashSet<>(); applyStatus(documentCriteria, builder, root, predicates); applyCreatedBy(documentCriteria, builder, root, predicates); applyVerifiedBy(documentCriteria, builder, root, predicates); applyCreatedFrom(documentCriteria, builder, root, predicates); applyCreatedUntil(documentCriteria, builder, root, predicates); applyVerifiedFrom(documentCriteria, builder, root, predicates); applyVerifiedUntil(documentCriteria, builder, root, predicates); applyQuery(documentCriteria, builder, root, predicates); applyNotDeleted(documentCriteria, builder, root, predicates); query.where(predicates.toArray(new Predicate[]{})); } private void applyNotDeleted(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { predicates.add(builder.not(root.get(Document_.deleted))); } private void applyQuery(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isQueryDefined()) { //(content like "%query%" OR title like "%query%") AND () AND () AND () predicates.add(builder.or( builder.like(root.get(Document_.content), "%" + documentCriteria.getQuery() + "%"), builder.like(root.get(Document_.title), "%" + documentCriteria.getQuery() + "%") )); } } private void applyCreatedUntil(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isCreatedUntilDefined()) { predicates.add(builder.lessThanOrEqualTo( root.get(Document_.createdAt), documentCriteria.getCreatedUntil() )); } } private void applyCreatedFrom(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isCreatedFromDefined()) { predicates.add(builder.greaterThanOrEqualTo( root.get(Document_.createdAt), documentCriteria.getCreatedFrom() )); } } private void applyVerifiedUntil(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isVerifiedUntilDefined()) { predicates.add(builder.lessThanOrEqualTo( root.get(Document_.verifiedAt), documentCriteria.getVerifiedUntil() )); } } private void applyVerifiedFrom(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isVerifiedFromDefined()) { predicates.add(builder.greaterThanOrEqualTo( root.get(Document_.verifiedAt), documentCriteria.getVerifiedFrom() )); } } private void applyCreatedBy(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isCreatedByDefined()) { predicates.add(builder.equal( root.get(Document_.creator).get(Employee_.employeeId).get(EmployeeId_.id), documentCriteria.getCreatedBy()) ); } } private void applyVerifiedBy(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isVerifiedByDefined()) { predicates.add(builder.equal( root.get(Document_.verificator).get(Employee_.employeeId).get(EmployeeId_.id), documentCriteria.getVerifiedBy()) ); } } private void applyStatus(DocumentCriteria documentCriteria, CriteriaBuilder builder, Root<Document> root, Collection<Predicate> predicates) { if (documentCriteria.isStatusDefined()) { predicates.add(builder.equal(root.get(Document_.status), documentCriteria.getStatus())); } } }