AbstractRepositoryQuery.java
package org.codefilarete.stalactite.spring.repository.query.execution;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import org.codefilarete.reflection.AccessorChain;
import org.codefilarete.reflection.AccessorDefinition;
import org.codefilarete.stalactite.query.model.JoinLink;
import org.codefilarete.stalactite.spring.repository.query.StalactiteQueryMethod;
import org.codefilarete.stalactite.spring.repository.query.StalactiteRepositoryQuery;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultCollectioner;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultPager;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultReducer;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultSingler;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultSlicer;
import org.codefilarete.stalactite.spring.repository.query.execution.reduce.QueryResultStreamer;
import org.codefilarete.tool.Reflections;
import org.codefilarete.tool.collection.Iterables;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
/**
* Parent class of some {@link RepositoryQuery} to share some code
* @author Guillaume Mary
*/
public abstract class AbstractRepositoryQuery<C, R> implements StalactiteRepositoryQuery<C, R> {
public static IdentityHashMap<JoinLink<?, ?>, String> buildAliases(IdentityHashMap<? extends JoinLink<?, ?>, ? extends AccessorChain<?, ?>> columnToProperties) {
return Iterables.map(
columnToProperties.entrySet(),
Map.Entry::getKey,
entry -> AccessorDefinition.giveDefinition(entry.getValue()).getName().replace('.', '_'),
IdentityHashMap::new);
}
protected final StalactiteQueryMethod method;
public AbstractRepositoryQuery(StalactiteQueryMethod method) {
this.method = method;
}
@Override
public StalactiteQueryMethod getQueryMethod() {
return method;
}
@Override
public R execute(Object[] parameters) {
StalactiteQueryMethodInvocationParameters invocationParameters = new StalactiteQueryMethodInvocationParameters(method, parameters);
AbstractQueryExecutor<List<Object>, Object> queryExecutor = buildQueryExecutor(invocationParameters);
Supplier<List<Object>> resultSupplier = queryExecutor.buildQueryExecutor(invocationParameters);
R adaptation = buildResultReducer(invocationParameters)
.adapt(resultSupplier)
.apply(parameters);
ResultProcessor resultProcessor = buildResultProcessor(parameters);
return resultProcessor.processResult(adaptation);
}
protected abstract AbstractQueryExecutor<List<Object>, Object> buildQueryExecutor(StalactiteQueryMethodInvocationParameters invocationParameters);
protected <ROW> QueryResultReducer<R, ROW> buildResultReducer(StalactiteQueryMethodInvocationParameters invocationParameters) {
QueryResultReducer<?, C> result;
switch (method.getQueryMethodReturnType()) {
case COLLECTION:
result = new QueryResultCollectioner<>();
break;
case PAGE:
result = new QueryResultPager<>(this, invocationParameters, buildCountSupplier(invocationParameters));
break;
case SLICE:
result = new QueryResultSlicer<>(this, invocationParameters);
break;
case STREAM:
result = new QueryResultStreamer<>(this, invocationParameters);
break;
case SINGLE_ENTITY:
result = new QueryResultSingler<>();
break;
case SINGLE_PROJECTION:
result = new QueryResultSingler<>();
break;
default:
throw new IllegalArgumentException("Unsupported return type for method " + Reflections.toString(method.getMethod()));
}
return (QueryResultReducer<R, ROW>) result;
}
protected abstract LongSupplier buildCountSupplier(StalactiteQueryMethodInvocationParameters accessor);
protected ResultProcessor buildResultProcessor(Object[] parameters) {
// - hasDynamicProjection() is for case of method that gives the expected returned type as a last argument (or a compound one by Collection or other)
ResultProcessor resultProcessor = method.getResultProcessor();
if (method.getParameters().hasDynamicProjection()) {
resultProcessor = resultProcessor.withDynamicProjection(new ParametersParameterAccessor(method.getParameters(), parameters));
}
return resultProcessor;
}
}