Remove the sort from query before executing count. (#1194)

Also creates the query with skip and limit from any Pageable parameter instead of applying it later.
Closes #1191.
This commit is contained in:
Michael Reiche
2021-08-18 09:07:15 -07:00
committed by GitHub
parent 7e2963a365
commit dffd203a57
4 changed files with 37 additions and 14 deletions

View File

@@ -136,7 +136,9 @@ public class Query {
}
this.limit = pageable.getPageSize();
this.skip = pageable.getOffset();
return with(pageable.getSort());
if(!this.sort.equals(pageable.getSort()))
this.sort.and(pageable.getSort());
return this;
}
/**
@@ -174,6 +176,11 @@ public class Query {
return this;
}
public Query withoutSort(){
this.sort = Sort.unsorted();
return this;
}
public void appendSkipAndLimit(final StringBuilder sb) {
if (limit > 0) {
sb.append(" LIMIT ").append(limit);
@@ -287,8 +294,10 @@ public class Query {
appendString(statement, n1ql.selectEntity); // select ...
appendWhereString(statement, n1ql.filter); // typeKey = typeValue
appendWhere(statement, new int[] { 0 }, template.getConverter()); // criteria on this Query
appendSort(statement);
appendSkipAndLimit(statement);
if(!isCount){
appendSort(statement);
appendSkipAndLimit(statement);
}
return statement.toString();
}

View File

@@ -19,8 +19,8 @@ import java.util.List;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery;
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery;
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@@ -112,7 +112,7 @@ interface CouchbaseQueryExecution {
public Object execute(Query query, Class<?> type, String collection) {
int pageSize = pageable.getPageSize();
// Apply Pageable but tweak limit to peek into next page
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
Query modifiedQuery = query.skip(pageable.getOffset()).limit(pageSize + 1);
List result = find.matching(modifiedQuery).all();
boolean hasNext = result.size() > pageSize;
return new SliceImpl<Object>(hasNext ? result.subList(0, pageSize) : result, pageable, hasNext);
@@ -142,14 +142,12 @@ interface CouchbaseQueryExecution {
public Object execute(Query query, Class<?> type, String collection) {
int overallLimit = 0; // query.getLimit();
TerminatingFindByQuery<?> matching = operation.matching(query);
// Apply raw pagination
query.with(pageable);
// Adjust limit if page would exceed the overall limit
if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) {
query.limit((int) (overallLimit - pageable.getOffset()));
}
return PageableExecutionUtils.getPage(matching.all(), pageable, () -> {
long count = operation.matching(query.skip(-1).limit(-1)).count();
long count = operation.matching(query.skip(-1).limit(-1).withoutSort()).count();
return overallLimit != 0 ? Math.min(count, overallLimit) : count;
});
}

View File

@@ -22,6 +22,7 @@ import static org.springframework.data.couchbase.core.query.N1QLExpression.x;
import static org.springframework.data.couchbase.core.query.QueryCriteria.where;
import java.util.Iterator;
import java.util.Optional;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
@@ -29,6 +30,7 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProper
import org.springframework.data.couchbase.core.query.N1QLExpression;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.QueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext;
@@ -37,6 +39,7 @@ import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.util.Assert;
/**
* @author Michael Nitschinger
@@ -72,12 +75,24 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
return from(part, property, where(addMetaIfRequired(bucketName, path, property)), iterator);
}
@Override
public Query createQuery() {
Query q = this.createQuery((Optional.of(this.accessor).map(ParameterAccessor::getSort).orElse(Sort.unsorted())));
Pageable pageable = accessor.getPageable();
if(pageable.isPaged()) {
q.skip(pageable.getOffset());
q.limit(pageable.getPageSize());
}
return q;
}
static Converter<? super CouchbasePersistentProperty, String> cvtr = new MyConverter();
static class MyConverter implements Converter<CouchbasePersistentProperty, String> {
@Override
public String convert(CouchbasePersistentProperty source) {
return new StringBuilder(source.getFieldName().length()+2).append("`").append(source.getFieldName()).append("`").toString();
return new StringBuilder(source.getFieldName().length() + 2).append("`").append(source.getFieldName()).append("`")
.toString();
}
}
@@ -90,7 +105,7 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
CouchbasePersistentProperty property = path.getLeafProperty();
return from(part, property, base.and(addMetaIfRequired(bucketName,path, property)), iterator);
return from(part, property, base.and(addMetaIfRequired(bucketName, path, property)), iterator);
}
@Override
@@ -100,7 +115,8 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
@Override
protected Query complete(QueryCriteria criteria, Sort sort) {
return (criteria == null ? new Query() : new Query().addCriteria(criteria)).with(sort);
Query q = (criteria == null ? new Query() : new Query().addCriteria(criteria)).with(sort);
return q;
}
private QueryCriteria from(final Part part, final CouchbasePersistentProperty property, final QueryCriteria criteria,
@@ -166,8 +182,7 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
}
}
public static N1QLExpression addMetaIfRequired(
String bucketName,
public static N1QLExpression addMetaIfRequired(String bucketName,
final PersistentPropertyPath<CouchbasePersistentProperty> persistentPropertyPath,
final CouchbasePersistentProperty property) {
if (property.isIdProperty()) {

View File

@@ -76,6 +76,7 @@ import org.springframework.data.couchbase.util.IgnoreWhen;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -449,7 +450,7 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
Long count = airportRepository.countFancyExpression(asList("JFK"), asList("jfk"), false);
assertEquals(1, count);
Pageable pageable = PageRequest.of(0, 2);
Pageable pageable = PageRequest.of(0, 2).withSort(Sort.by("iata"));
Page<Airport> aPage = airportRepository.findAllByIataNot("JFK", pageable);
assertEquals(iatas.length - 1, aPage.getTotalElements());
assertEquals(pageable.getPageSize(), aPage.getContent().size());