DATACOUCH-187 - Allow counting queries and single projections.

This change allows simple projections to types long, boolean, String when an inline N1QL query uses an aggregation function like AVG, COUNT.

The projection's result must be a single row with a single key/value pair in the N1QL response. Only the value gets returned.
This commit is contained in:
Simon Baslé
2016-01-18 18:06:15 +01:00
parent 721bdede2a
commit 8f5e9e3df8
8 changed files with 198 additions and 10 deletions

View File

@@ -16,22 +16,21 @@
package org.springframework.data.couchbase.repository;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
import java.util.Date;
import java.util.List;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.error.DocumentDoesNotExistException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.couchbase.repository.support.IndexManager;
@@ -76,9 +75,9 @@ public class N1qlCrudRepositoryTests {
@After
public void cleanUp() {
try { itemRepository.delete(KEY_ITEM); } catch (DocumentDoesNotExistException e) {}
try { partyRepository.delete(KEY_PARTY); } catch (DocumentDoesNotExistException e) {}
try { partyRepository.delete(KEY_PARTY_KEYWORD); } catch (DocumentDoesNotExistException e) {}
try { itemRepository.delete(KEY_ITEM); } catch (DataRetrievalFailureException e) {}
try { partyRepository.delete(KEY_PARTY); } catch (DataRetrievalFailureException e) {}
try { partyRepository.delete(KEY_PARTY_KEYWORD); } catch (DataRetrievalFailureException e) {}
}
@Test
@@ -107,4 +106,56 @@ public class N1qlCrudRepositoryTests {
}
}
}
@Test
public void shouldGenerateCountProjection() {
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", null, new Date(), 40, new Point(500, 500));
partyRepository.save(partyHasKeyword);
long countTotal = partyRepository.count();
long countCustom = partyRepository.countAllByDescriptionNotNull();
assertEquals(countTotal - 1, countCustom);
}
@Test
public void shouldCountWhenReturningLongAndUsingStringSelectFromSpEL() {
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "second party", new Date(), 40, new Point(500, 500));
partyRepository.save(partyHasKeyword);
long countTotal = partyRepository.count();
long countCustom = partyRepository.countCustom();
assertEquals(countTotal, countCustom);
}
@Test
public void shouldCustomCountWhenReturningLongAndUsingStringWithoutSpEL() {
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "second party", new Date(), 40, new Point(500, 500));
partyRepository.save(partyHasKeyword);
long countTotal = partyRepository.count();
long countCustom = partyRepository.countCustomPlusFive();
assertEquals(countTotal + 5, countCustom);
}
@Test(expected = CouchbaseQueryExecutionException.class)
public void shouldFailConversionWithStringReturnType() {
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "desc is a N1QL keyword", new Date(), 40, new Point(500, 500));
partyRepository.save(partyHasKeyword);
String someString = partyRepository.findSomeString();
}
@Test
public void shouldDoNumericProjectionWithStringBasedQuery() {
Party partyHasKeyword = new Party(KEY_PARTY_KEYWORD, "party", "desc is a N1QL keyword", new Date(), 4000000, new Point(500, 500));
partyRepository.save(partyHasKeyword);
long max = partyRepository.findMaxAttendees();
assertEquals(4000000, max);
}
@Test
public void shouldDoBooleanProjectionWithStringBasedQuery() {
boolean someBoolean = partyRepository.justABoolean();
assertEquals(true, someBoolean);
}
}

View File

@@ -3,11 +3,14 @@ package org.springframework.data.couchbase.repository;
import java.util.Date;
import java.util.List;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.View;
import org.springframework.data.couchbase.core.query.ViewIndexed;
/**
* @author Simon Baslé
*/
@ViewIndexed(designDoc = "party", viewName = "all")
public interface PartyRepository extends CouchbaseRepository<Party, String> {
List<Party> findByAttendeesGreaterThanEqual(int minAttendees);
@@ -19,4 +22,20 @@ public interface PartyRepository extends CouchbaseRepository<Party, String> {
List<Object> findAllByDescriptionNotNull();
long countAllByDescriptionNotNull();
@Query("SELECT MAX(attendees) FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
long findMaxAttendees();
@Query("SELECT `desc` FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
String findSomeString();
@Query("SELECT count(*) + 5 FROM #{#n1ql.bucket} WHERE #{#n1ql.filter}")
long countCustomPlusFive();
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter}")
long countCustom();
@Query("SELECT 1 = 1")
boolean justABoolean();
}