use of com.peterphi.std.guice.hibernate.webquery.ConstrainedResultSet in project stdlib by petergeneric.
the class JPASearchExecutor method find.
/**
* Execute a search, returning a ConstrainedResultSet populated with the desired data (ID or Entity) with each piece of data
* optionally serialised using the supplied serialiser
*
* @param query
* the query to execute (including options like offset/limit, )
* @param strategy
* @param serialiser
* @param <T>
*
* @return
*/
public <T> ConstrainedResultSet<T> find(final QEntity entity, final WebQuery query, JPASearchStrategy strategy, Function<?, ?> serialiser) {
final String traceOperationId = Tracing.log("WebQuery:exec", () -> query.toString());
final HibernateSQLLogger statementLog;
if (query.isLogSQL())
statementLog = hibernateObserver.startSQLLogger(traceOperationId);
else
statementLog = null;
try {
// Build a view of the query based on
JPAQueryBuilder builder = new JPAQueryBuilder(sessionFactory.getCurrentSession(), entity);
builder.forWebQuery(query);
// First, compute the total size if requested
final Long total;
if (ALWAYS_COMPUTE_SIZE || query.isComputeSize()) {
JPAQueryBuilder countBuilder = new JPAQueryBuilder(sessionFactory.getCurrentSession(), entity);
countBuilder.forWebQuery(query);
total = countBuilder.selectCount();
} else {
total = null;
}
// If the auto strategy is in play, take into account what's being fetched back as well as whether there are any explicit collection joins or fetches
if (strategy == null || strategy == JPASearchStrategy.AUTO) {
if (StringUtils.equals(query.getFetch(), "id")) {
strategy = JPASearchStrategy.ENTITY_WRAPPED_ID;
} else {
// This is necessary for correct pagination because the SQL resultset will have more than one row per entity, and our offset/limit is based on entity
if ((query.getLimit() > 0 || query.getOffset() > 0) && (builder.hasCollectionJoin() || builder.hasCollectionFetch())) {
strategy = JPASearchStrategy.ID_THEN_QUERY_ENTITY;
} else {
strategy = JPASearchStrategy.ENTITY;
}
}
}
List list;
switch(strategy) {
case ID:
{
list = builder.selectIDs();
break;
}
case ENTITY_WRAPPED_ID:
{
list = builder.selectIDs();
// Transform the IDs into entity objects with the ID field populated
list = (List) list.stream().map(entity::newInstanceWithId).collect(Collectors.toList());
break;
}
case ENTITY:
{
// TODO could we use ScrollableResults if there are collection joins? pagination would be tricky
list = builder.selectEntity();
break;
}
case ID_THEN_QUERY_ENTITY:
{
// First, query for the IDs (and the total results if desired)
list = builder.selectIDs();
// Now re-query to retrieve the entities
builder = new JPAQueryBuilder(sessionFactory.getCurrentSession(), entity);
builder.forIDs(query, list);
if (!list.isEmpty())
list = builder.selectEntity();
break;
}
default:
throw new NotImplementedException("Search Strategy " + strategy + " not yet implemented");
}
// If a serialiser has been supplied,
if (serialiser != null)
list = (List) list.stream().map(serialiser).collect(Collectors.toList());
ConstrainedResultSet resultset = new ConstrainedResultSet<>(query, list);
if (statementLog != null && query.isLogSQL())
resultset.setSql(statementLog.getAllStatements());
if (total != null)
resultset.setTotal(total);
Tracing.logOngoing(traceOperationId, "WebQuery:exec:result", () -> "size=" + resultset.getList().size() + ", total=" + total);
return (ConstrainedResultSet<T>) resultset;
} finally {
if (statementLog != null)
statementLog.close();
}
}
Aggregations