AuditedModelFilter.java

package org.gringlobal.service.filter;

import java.time.Instant;
import java.util.List;
import java.util.Set;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.collections4.CollectionUtils;
import org.genesys.blocks.model.filters.EmptyModelFilter;
import org.genesys.blocks.model.filters.TemporalFilter;
import org.gringlobal.model.AuditedModel;
import org.gringlobal.model.QAuditedModel;

import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.ListPath;
import com.querydsl.jpa.JPAExpressions;

@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true)
public abstract class AuditedModelFilter<T extends AuditedModelFilter<T, R>, R extends AuditedModel> extends EmptyModelFilter<T, R> {

	private static final long serialVersionUID = 3000864197634727372L;
	/** The created by. */
	public Set<Long> createdBy;
	/** The created date. */
	public TemporalFilter<Instant> createdDate;
	/** The last modified by. */
	public Set<Long> modifiedBy;
	/** The last modified date. */
	public TemporalFilter<Instant> modifiedDate;
	
	/**
	 * @deprecated Must use {@link #collectPredicates(EntityPathBase, QAuditedModel)}!
	 */
	@Override
	@Deprecated
	protected List<Predicate> collectPredicates(EntityPathBase<R> instance) {
		return super.collectPredicates(instance);
	}

	protected List<Predicate> collectPredicates(final EntityPathBase<R> instance, final QAuditedModel auditedModel) {
		List<Predicate> predicates = super.collectPredicates(instance);
		if (CollectionUtils.isNotEmpty(createdBy)) {
			predicates.add(auditedModel.createdBy.in(createdBy));
		}
		if (CollectionUtils.isNotEmpty(modifiedBy)) {
			predicates.add(auditedModel.modifiedBy.in(modifiedBy));
		}
		if (createdDate != null) {
			predicates.add(createdDate.buildQuery(auditedModel.createdDate));
		}
		if (modifiedDate != null) {
			predicates.add(modifiedDate.buildQuery(auditedModel.modifiedDate));
		}
		return predicates;
	}

	/**
	 * Created date.
	 *
	 * @return the date filter
	 */
	public synchronized TemporalFilter<Instant> createdDate() {
		if (createdDate == null) {
			createdDate = new TemporalFilter<Instant>();
		}
		return createdDate;
	}

	/**
	 * Last modified date.
	 *
	 * @return the date filter
	 */
	public synchronized TemporalFilter<Instant> modifiedDate() {
		if (modifiedDate == null) {
			modifiedDate = new TemporalFilter<Instant>();
		}
		return modifiedDate;
	}

	/**
	 * Generate a single predicate that assures a nested collection is not empty,
	 * and uses a JPA sub-query to test for neste objects that match filter predicates
	 * in nestedPredicates.
	 *
	 * @param nestedCollection the ListPath to a nested collection of objects
	 * @param entityPath the alias that is used in joinExpression and to collect nested predicates
	 * @param joinExpression the join expression to the parent entity
	 * @param nestedPredicates predicates generated by the filter for the nested entity
	 *
	 * @return a single Predicate with: .isNotEmpty().and(subquery).
	 */
	protected Predicate nestedFilter(ListPath<?, ?> nestedCollection, EntityPathBase<?> entityPath, BooleanExpression joinExpression, List<Predicate> nestedPredicates) {
		nestedPredicates.add(0, joinExpression);
		var sourceExpression = JPAExpressions.selectFrom(entityPath).where(nestedPredicates.toArray(Predicate[]::new)).exists();
		return nestedCollection.isNotEmpty().and(sourceExpression);
	}

}