DATACOUCH-265 - Support pageable and sort for String based SpEL queries

Original pull request: #128.
This commit is contained in:
Subhashni Balakrishnan
2017-01-03 15:07:25 -08:00
parent 162d8124ab
commit 5d36ecc12b
4 changed files with 61 additions and 2 deletions

View File

@@ -72,7 +72,7 @@ public class N1qlCouchbaseRepositoryTests {
repository = factory.getRepository(PartyPagingRepository.class);
partyRepository = factory.getRepository(PartyRepository.class);
itemRepository = factory.getRepository(ItemRepository.class);
partyRepository.save(new Party(KEY_PARTY, "partyName", "MatchingDescription", null, 0, null));
partyRepository.save(new Party(KEY_PARTY, "partyName", "MatchingDescription", null, 1, null));
itemRepository.save(new Item(KEY_ITEM, "MatchingDescription"));
}
@@ -151,4 +151,30 @@ public class N1qlCouchbaseRepositoryTests {
List<Party> partyList = partyRepository.findByDescriptionOrName("MatchingDescription", "partyName");
assertTrue(partyList.size() == 1);
}
@Test
public void shouldPageWithStringBasedQuery() {
Pageable pageable = new PageRequest(0, 8, Sort.Direction.DESC, "attendees");
Page<Party> page1 = partyRepository.findPartiesWithAttendee(1, pageable);
assertEquals(16, page1.getTotalElements()); //12 generated parties + 4 specifically crafted party
assertEquals(8, page1.getNumberOfElements());
List<Party> parties = page1.getContent();
Long previousAttendees = null;
for (Party party : parties) {
if (previousAttendees != null) {
assertTrue(party.getAttendees() <= previousAttendees);
}
previousAttendees = party.getAttendees();
}
Page<Party> page2 = partyRepository.findPartiesWithAttendee(1, page1.nextPageable());
assertEquals(8, page2.getNumberOfElements());
parties = page2.getContent();
for (Party party : parties) {
if (previousAttendees != null) {
assertTrue(party.getAttendees() <= previousAttendees);
}
previousAttendees = party.getAttendees();
}
}
}

View File

@@ -7,6 +7,8 @@ import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.View;
import org.springframework.data.couchbase.core.query.ViewIndexed;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
/**
@@ -42,6 +44,9 @@ public interface PartyRepository extends CouchbaseRepository<Party, String> {
@Query("SELECT 1 = 1")
boolean justABoolean();
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `attendees` >= $1")
Page<Party> findPartiesWithAttendee(int count, Pageable pageable);
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $included || '%' AND attendees >= $min" +
" AND `desc` NOT LIKE '%' || $excluded || '%'")
List<Party> findAllWithNamedParams(@Param("excluded") String ex, @Param("included") String inc, @Param("min") long minimumAttendees);

View File

@@ -263,6 +263,8 @@ It adds two methods:
TIP: You can also use `Page` and `Slice` as method return types as well with a N1QL backed repository.
NOTE: If pageable and sort parameters are used with inline queries, there should not be any order by, limit or offset clause in the inline query itself otherwise the server would reject the query as malformed.
The second way of querying, supported also in older versions of Couchbase Server, is the View-backed one that we'll see in the next section.
[[couchbase.repository.views]]

View File

@@ -20,14 +20,23 @@ package org.springframework.data.couchbase.repository.query;
import com.couchbase.client.java.document.json.JsonValue;
import com.couchbase.client.java.query.N1qlQuery;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.dsl.path.DefaultLimitPath;
import com.couchbase.client.java.query.dsl.path.DefaultOrderByPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
/**
* A {@link RepositoryQuery} for Couchbase, based on N1QL and a String statement.
@@ -76,7 +85,24 @@ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery {
public Statement getStatement(ParameterAccessor accessor, Object[] runtimeParameters, ReturnedType returnedType) {
EvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(getQueryMethod().getParameters(), runtimeParameters);
String parsedStatement = this.queryParser.doParse(parser, evaluationContext, false);
return N1qlQuery.simple(parsedStatement).statement();
String orderByPart = "";
String limitByPart = "";
Sort sort = accessor.getSort();
if (sort != null) {
com.couchbase.client.java.query.dsl.Sort[] cbSorts = N1qlUtils.createSort(sort, getCouchbaseOperations().getConverter());
orderByPart = " " + new DefaultOrderByPath(null).orderBy(cbSorts).toString();
}
if (queryMethod.isPageQuery()) {
Pageable pageable = accessor.getPageable();
Assert.notNull(pageable);
limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize()).offset(pageable.getOffset()).toString();
} else if (queryMethod.isSliceQuery()) {
Pageable pageable = accessor.getPageable();
Assert.notNull(pageable);
limitByPart = " " + new DefaultLimitPath(null).limit(pageable.getPageSize() + 1).offset(pageable.getOffset()).toString();
}
return N1qlQuery.simple(parsedStatement + orderByPart + limitByPart).statement();
}
@Override