DomainEntityQueryExecutor.java
package org.codefilarete.stalactite.spring.repository.query.domain;
import java.util.List;
import java.util.function.Supplier;
import org.codefilarete.reflection.AccessorByMember;
import org.codefilarete.reflection.AccessorChain;
import org.codefilarete.reflection.Accessors;
import org.codefilarete.stalactite.engine.EntityCriteria.OrderByChain.Order;
import org.codefilarete.stalactite.engine.runtime.AdvancedEntityPersister;
import org.codefilarete.stalactite.engine.runtime.RelationalEntityPersister.ExecutableEntityQueryCriteria;
import org.codefilarete.stalactite.engine.runtime.query.EntityQueryCriteriaSupport;
import org.codefilarete.stalactite.engine.runtime.query.EntityQueryCriteriaSupport.EntityQueryPageSupport;
import org.codefilarete.stalactite.query.model.Limit;
import org.codefilarete.stalactite.spring.repository.query.execution.AbstractQueryExecutor;
import org.codefilarete.stalactite.spring.repository.query.StalactiteQueryMethod;
import org.codefilarete.stalactite.spring.repository.query.execution.StalactiteQueryMethodInvocationParameters;
import org.codefilarete.stalactite.spring.repository.query.derivation.ToCriteriaPartTreeTransformer;
import org.codefilarete.stalactite.spring.repository.query.derivation.ToCriteriaPartTreeTransformer.Condition;
import org.codefilarete.stalactite.sql.result.Accumulators;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.repository.query.parser.PartTree;
/**
* Implementation of {@link AbstractQueryExecutor} dedicated to domain entities.
* Implementation is based on {@link EntityQueryCriteriaSupport} provided by the {@link AdvancedEntityPersister}.
*
* @param <C> domain entity type
* @author Guillaume Mary
*/
public class DomainEntityQueryExecutor<C> extends AbstractQueryExecutor<List<C>, C> {
private final AdvancedEntityPersister<C, ?> entityPersister;
private final ToCriteriaPartTreeTransformer<C> criteriaAppender;
public DomainEntityQueryExecutor(StalactiteQueryMethod method,
AdvancedEntityPersister<C, ?> entityPersister,
PartTree partTree) {
super(method);
this.entityPersister = entityPersister;
this.criteriaAppender = new ToCriteriaPartTreeTransformer<>(
partTree,
entityPersister.getClassToPersist());
}
@Override
public Supplier<List<C>> buildQueryExecutor(StalactiteQueryMethodInvocationParameters invocationParameters) {
return () -> {
EntityQueryCriteriaSupport<C, ?> executableEntityQuery = entityPersister.newCriteriaSupport();
Condition condition = criteriaAppender.applyTo(
executableEntityQuery.getEntityCriteriaSupport(),
executableEntityQuery.getQueryPageSupport(),
executableEntityQuery.getQueryPageSupport());
condition.consume(invocationParameters.getValues());
ExecutableEntityQueryCriteria<C, ?> executableEntityQueryCriteria = handleDynamicParameters(invocationParameters, executableEntityQuery);
List<C> adaptation = executableEntityQueryCriteria.execute(Accumulators.toList());
return method.getResultProcessor().processResult(adaptation);
};
}
private ExecutableEntityQueryCriteria<C, ?> handleDynamicParameters(StalactiteQueryMethodInvocationParameters invocationParameters,
EntityQueryCriteriaSupport<C, ?> defaultExecutableEntityQuery) {
EntityQueryCriteriaSupport<C, ?> derivedQueryToUse;
// following code will manage both Sort as an argument, and Sort in a Pageable because getSort() handle both
if (invocationParameters.getSort().isSorted()) {
Class<?> declaringClass = method.getEntityInformation().getJavaType();
// Spring Sort class supports only first-level properties, in-depth ones seems not to be definable,
// therefore we create AccessorChain of only one property
EntityQueryPageSupport<C> dynamicSortSupport = new EntityQueryPageSupport<>();
invocationParameters.getSort().stream().forEachOrdered(order -> {
AccessorByMember<?, ?, ?> accessor = Accessors.accessor(declaringClass, order.getProperty());
dynamicSortSupport.orderBy(new AccessorChain<>(accessor),
order.getDirection() == Direction.ASC ? Order.ASC : Order.DESC,
order.isIgnoreCase());
});
derivedQueryToUse = defaultExecutableEntityQuery.copyFor(dynamicSortSupport);
} else {
derivedQueryToUse = defaultExecutableEntityQuery;
}
ExecutableEntityQueryCriteria<C, ?> result = derivedQueryToUse.wrapIntoExecutable();
Limit limit = invocationParameters.getLimit();
if (limit != null) {
result.limit(limit.getCount(), limit.getOffset());
}
return result;
}
}