diff --git a/src/test/java/org/springframework/data/couchbase/ContainerResourceRunner.java b/src/test/java/org/springframework/data/couchbase/ContainerResourceRunner.java new file mode 100644 index 00000000..4e58f23d --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/ContainerResourceRunner.java @@ -0,0 +1,20 @@ +package org.springframework.data.couchbase; + +import org.junit.ClassRule; +import org.junit.runners.model.InitializationError; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * This runner initializes container for the container based testing. + * + * @author Subhashni Balakrishnan + */ +public class ContainerResourceRunner extends SpringJUnit4ClassRunner { + + @ClassRule + public static final TestContainerResource resource = TestContainerResource.getResource(); + + public ContainerResourceRunner(Class clazz) throws InitializationError { + super(clazz); + } +} diff --git a/src/test/java/org/springframework/data/couchbase/CouchbaseHttpPortListeningCheck.java b/src/test/java/org/springframework/data/couchbase/CouchbaseHttpPortListeningCheck.java new file mode 100644 index 00000000..dd82b6a2 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/CouchbaseHttpPortListeningCheck.java @@ -0,0 +1,46 @@ +package org.springframework.data.couchbase; + +import java.util.concurrent.Callable; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; + +/** + * Helper to check if the Couchbase http endpoints are up. + */ +public class CouchbaseHttpPortListeningCheck implements Callable { + + private final int port; + private final String path; + + public CouchbaseHttpPortListeningCheck(int port, String path) { + this.port = port; + this.path = path; + } + + private Boolean executeRequest(URIBuilder builder) throws Exception { + try { + HttpGet request = new HttpGet(builder.build()); + HttpClient client = HttpClientBuilder.create().build(); + HttpResponse response = client.execute(request); + int status = response.getStatusLine().getStatusCode(); + if (status < 200 || status >= 300) { + return false; + } + return true; + } catch (Exception ex) { + Thread.sleep(1000); + throw ex; + } + } + + @Override + public Boolean call() throws Exception { + URIBuilder builder = new URIBuilder(); + builder.setScheme("http").setHost("localhost").setPort(this.port).setPath(this.path); + return executeRequest(builder); + } +} diff --git a/src/test/java/org/springframework/data/couchbase/CouchbaseWaitStrategy.java b/src/test/java/org/springframework/data/couchbase/CouchbaseWaitStrategy.java new file mode 100644 index 00000000..ad98f3a8 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/CouchbaseWaitStrategy.java @@ -0,0 +1,85 @@ +package org.springframework.data.couchbase; + +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.time.Duration; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import com.couchbase.client.java.util.features.Version; +import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.Container; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.WaitStrategy; + +/** + * WaitStrategy for Couchbase containers which makes the Server node is initialized, RBAC user and default bucket is + * created. + */ +public class CouchbaseWaitStrategy implements WaitStrategy { + + private Duration startupTimeout = Duration.of(60, SECONDS); + private final Boolean rbacEnabled; + + public CouchbaseWaitStrategy(String serverVersion) { + Version version = Version.parseVersion(serverVersion); + rbacEnabled = version.major() >= 5; + } + + private void checkResult(Container.ExecResult result, String command) throws Exception { + if (!result.getStdout().contains("SUCCESS")) { + throw new Exception(command + " command failed"); + } + } + + private void checkService(int port, String path) { + Callable externalCheck = new CouchbaseHttpPortListeningCheck(port, path); + Unreliables.retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> externalCheck.call()); + } + + @Override + public void waitUntilReady(GenericContainer container) { + try { + checkService(8091, "/pools"); + Container.ExecResult result; + + if (rbacEnabled) { + result = container.execInContainer("/opt/couchbase/bin/couchbase-cli", "cluster-init", + "--cluster=127.0.0.1:8091", "--services=data,index,query", "--cluster-name=localcontainer", + "--cluster-username=Administrator", "--cluster-password=password", "--cluster-ramsize=512", + "--cluster-index-ramsize=512", "--index-storage-setting=default"); + checkResult(result, "Cluster init"); + result = container.execInContainer("/opt/couchbase/bin/couchbase-cli", "user-manage", + "--cluster=127.0.0.1:8091", "--username=Administrator", "--password=password", "--set", + "--rbac-username=protected", "--rbac-password=password", "--rbac-name=default", "--roles=admin", + "--auth-domain=local"); + checkResult(result, "User manage"); + result = container.execInContainer("/opt/couchbase/bin/couchbase-cli", "bucket-create", + "--cluster=127.0.0.1:8091", "--username=Administrator", "--password=password", "--bucket=protected", + "--bucket-type=couchbase", "--bucket-ramsize=200", "--enable-flush=1", "--wait"); + } else { + result = container.execInContainer("/opt/couchbase/bin/couchbase-cli", "cluster-init", + "--cluster=127.0.0.1:8091", "--services=data,index,query", "-u", "Administrator", "-p", "password", + "--cluster-ramsize=512", "--cluster-index-ramsize=512", "--index-storage-setting=default"); + checkResult(result, "Cluster init"); + result = container.execInContainer("/opt/couchbase/bin/couchbase-cli", "bucket-create", + "--cluster=127.0.0.1:8091", "-u", "Administrator", "-p", "password", "--bucket=protected", + "--bucket-password=password", "--bucket-type=couchbase", "--bucket-ramsize=200", "--enable-flush=1", + "--wait"); + } + + checkResult(result, "Bucket create"); + checkService(8093, "/query/ping"); + } catch (Exception ex) { + ex.printStackTrace(); + System.exit(1); + } + } + + @Override + public WaitStrategy withStartupTimeout(Duration startupTimeout) { + this.startupTimeout = startupTimeout; + return this; + } +} diff --git a/src/test/java/org/springframework/data/couchbase/TestContainerResource.java b/src/test/java/org/springframework/data/couchbase/TestContainerResource.java new file mode 100644 index 00000000..9e703f21 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/TestContainerResource.java @@ -0,0 +1,67 @@ +package org.springframework.data.couchbase; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.rules.ExternalResource; +import org.testcontainers.containers.FixedHostPortGenericContainer; + +/** + * Testcontainers as external resource. It is recommended to use it as ClassRule. + * It also does the internal reference counting, in case if the getResource is called again. + * + */ +public class TestContainerResource extends ExternalResource { + + private static FixedHostPortGenericContainer couchbaseContainer = null; + private static final AtomicInteger referenceCount = new AtomicInteger(); + private static TestContainerResource currentInstance; + private static String serverVersion; + + + public static TestContainerResource getResource() { + if (currentInstance == null) { + currentInstance = new TestContainerResource(); + try { + Properties properties = new Properties(); + properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("server.properties")); + serverVersion = properties.getProperty("server.version"); + if(!properties.getProperty("server.resource").contentEquals("container")) { + return null; + } + } catch (Exception ex) { + serverVersion = "5.0.1"; + } + couchbaseContainer = new FixedHostPortGenericContainer("couchbase:" + serverVersion) + .withFixedExposedPort(8091, 8091) + .withFixedExposedPort(18091, 18091) + .withFixedExposedPort(8092, 8092) + .withFixedExposedPort(18092, 18092) + .withFixedExposedPort(8093, 8093) + .withFixedExposedPort(18093, 18093) + .withFixedExposedPort(8094, 8094) + .withFixedExposedPort(18094, 18094) + .withFixedExposedPort(11210, 11210) + .withFixedExposedPort(11211, 11211) + .withFixedExposedPort(11207, 11207); + couchbaseContainer.waitingFor(new CouchbaseWaitStrategy(serverVersion)); + couchbaseContainer.start(); + } + + return currentInstance; + } + + @Override + protected void before() { + referenceCount.incrementAndGet(); + } + + @Override + protected void after() { + if (referenceCount.decrementAndGet() == 0 && couchbaseContainer != null) { + if(couchbaseContainer.isRunning()) { + couchbaseContainer.close(); + } + currentInstance = null; + } + } +} diff --git a/src/test/java/org/springframework/data/couchbase/repo/PartyPagingRepository.java b/src/test/java/org/springframework/data/couchbase/repo/PartyPagingRepository.java deleted file mode 100644 index 307931cc..00000000 --- a/src/test/java/org/springframework/data/couchbase/repo/PartyPagingRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.springframework.data.couchbase.repo; - -import org.springframework.data.couchbase.repository.CouchbasePagingAndSortingRepository; -import org.springframework.data.couchbase.repository.Party; -import org.springframework.stereotype.Repository; - -@Repository -public interface PartyPagingRepository extends CouchbasePagingAndSortingRepository { -} diff --git a/src/test/java/org/springframework/data/couchbase/repo/PartyRepository.java b/src/test/java/org/springframework/data/couchbase/repo/PartyRepository.java deleted file mode 100644 index 8439b492..00000000 --- a/src/test/java/org/springframework/data/couchbase/repo/PartyRepository.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2017-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.couchbase.repo; - -import java.util.Date; -import java.util.List; - -import org.springframework.data.couchbase.core.query.*; -import org.springframework.data.couchbase.repository.CouchbaseRepository; -import org.springframework.data.couchbase.repository.Party; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -/** - * @author Simon Baslé - * @author Subhashni Balakrishnan - */ -@Repository -@ViewIndexed(designDoc = "party", viewName = "all") -@N1qlPrimaryIndexed -@N1qlSecondaryIndexed(indexName = "party") -public interface PartyRepository extends CouchbaseRepository { - - List findByAttendeesGreaterThanEqual(int minAttendees); - - List findByName(String name); - - List findByEventDateIs(Date targetDate); - - @View(designDocument = "party", viewName = "byDate") - List findFirst3ByEventDateGreaterThanEqual(Date targetDate); - - List 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(); - - @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `attendees` >= $1") - Page findPartiesWithAttendee(int count, Pageable pageable); - - @Query("#{#n1ql.selectEntity}") - List findParties(Sort sort); - - @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $included || '%' AND attendees >= $min" + - " AND `desc` NOT LIKE '%' || $excluded || '%'") - List findAllWithNamedParams(@Param("excluded") String ex, @Param("included") String inc, - @Param("min") long minimumAttendees); - - @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" + - " AND `desc` NOT LIKE '%' || $1 || '%'") - List findAllWithPositionalParams(String ex, String inc, long minimumAttendees); - - @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees < $3" + - " AND `desc` NOT LIKE '%' || $1 || '%' #{#n1ql.returning}") - List removeWithPositionalParams(String ex, String inc, long minimumAttendees); - - @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" + - " AND `desc` NOT LIKE '%' || $1 || '%' AND `desc` != \"this is \\\"$excluded\\\"\"") - List findAllWithPositionalParamsAndQuotedNamedParams(@Param("excluded") String ex, - @Param("included") String inc, @Param("min") long min); - - List findByDescriptionOrName(String description, String name); - - List removeByDescriptionOrName(String description, String name); - - @Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and eventDate = $1") - List getByEventDate(Date eventDate); - - List findByDescriptionStartingWith(String description); -} diff --git a/src/test/java/org/springframework/data/couchbase/repo/ItemRepository.java b/src/test/java/org/springframework/data/couchbase/repository/ItemRepository.java similarity index 63% rename from src/test/java/org/springframework/data/couchbase/repo/ItemRepository.java rename to src/test/java/org/springframework/data/couchbase/repository/ItemRepository.java index 235d4153..b56caa06 100644 --- a/src/test/java/org/springframework/data/couchbase/repo/ItemRepository.java +++ b/src/test/java/org/springframework/data/couchbase/repository/ItemRepository.java @@ -1,13 +1,10 @@ -package org.springframework.data.couchbase.repo; +package org.springframework.data.couchbase.repository; import java.util.List; import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed; -import org.springframework.data.couchbase.repository.Item; import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; -@Repository @N1qlPrimaryIndexed public interface ItemRepository extends CrudRepository { diff --git a/src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryTests.java similarity index 78% rename from src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryIntegrationTests.java rename to src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryTests.java index f360053a..01f68110 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/N1qlCouchbaseRepositoryTests.java @@ -25,67 +25,57 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataRetrievalFailureException; -//import org.springframework.data.couchbase.ContainerResourceRunner; + +import org.springframework.data.couchbase.ContainerResourceRunner; import org.springframework.data.couchbase.IntegrationTestApplicationConfig; -import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; -// must not be in same package as CouchbaseRepository, otherwise AutoWired will fail on couchbaseRepository -import org.springframework.data.couchbase.repo.ItemRepository; -import org.springframework.data.couchbase.repo.PartyRepository; -import org.springframework.data.couchbase.repo.PartyPagingRepository; +import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping; +import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory; +import org.springframework.data.couchbase.repository.support.IndexManager; 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.mapping.model.MappingInstantiationException; +import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; /** - * This has been copied from 3.2.x for testing backport of fix in DATACOUCH-484 - * This and dependent class have been copied from src/integration to src/test - * and the repository classes have been moved from org.springframework.data.couchbase.repository - * to org.springframework.data.couchbase.repo so that - * org.springframework.data.couchbase.repository.CouchbaseRepository is not instantiated by - * @Autowired - * * This tests PaginAndSortingRepository features in the Couchbase connector. * * @author Simon Baslé * @author Subhashni Balakrishnan - * @author Michael Reiche */ -// @RunWith(ContainerResourceRunner.class) -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(ContainerResourceRunner.class) @ContextConfiguration(classes = IntegrationTestApplicationConfig.class) -@SpringJUnitConfig(IntegrationTestApplicationConfig.class) @TestExecutionListeners(PartyPopulatorListener.class) -@EnableCouchbaseRepositories -public class N1qlCouchbaseRepositoryIntegrationTests { +public class N1qlCouchbaseRepositoryTests { - @Autowired private PartyPagingRepository repository; + @Autowired private RepositoryOperationsMapping operationsMapping; - @Autowired private PartyRepository partyRepository; + @Autowired private IndexManager indexManager; - @Autowired private ItemRepository itemRepository; + private PartyPagingRepository repository; + + private PartyRepository partyRepository; + + private ItemRepository itemRepository; private final String KEY_PARTY = "Party1"; private final String KEY_ITEM = "Item1"; @Before public void setup() throws Exception { + RepositoryFactorySupport factory = new CouchbaseRepositoryFactory(operationsMapping, indexManager); + repository = factory.getRepository(PartyPagingRepository.class); + partyRepository = factory.getRepository(PartyRepository.class); + itemRepository = factory.getRepository(ItemRepository.class); partyRepository.save(new Party(KEY_PARTY, "partyName", "MatchingDescription", null, 1, null)); itemRepository.save(new Item(KEY_ITEM, "MatchingDescription")); } @@ -144,7 +134,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldFindAllWithSort() { - Iterable allByAttendanceDesc = repository.findAll(Sort.by(Sort.Direction.DESC, "attendees")); + Iterable allByAttendanceDesc = repository.findAll(new Sort(Sort.Direction.DESC, "attendees")); long previousAttendance = Long.MAX_VALUE; for (Party party : allByAttendanceDesc) { assertTrue(party.getAttendees() <= previousAttendance); @@ -155,7 +145,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldSortOnRenamedFieldIfJsonNameIsProvidedInSort() { - Iterable parties = repository.findAll(Sort.by(Sort.Direction.DESC, "desc")); + Iterable parties = repository.findAll(new Sort(Sort.Direction.DESC, "desc")); String previousDesc = null; for (Party party : parties) { if (previousDesc != null) { @@ -168,7 +158,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldSortWithoutCaseSensitivity() { - Iterable parties = repository.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC, "desc").ignoreCase())); + Iterable parties = repository.findAll(new Sort(new Sort.Order(Sort.Direction.DESC, "desc").ignoreCase())); String previousDesc = null; for (Party party : parties) { if (previousDesc != null) { @@ -181,7 +171,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldPageThroughEntities() { - Pageable pageable = PageRequest.of(0, 8); + Pageable pageable = new PageRequest(0, 8); Page page1 = repository.findAll(pageable); assertTrue("Query for parties should be atleast 12", page1.getTotalElements() >= 12); @@ -190,7 +180,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldPageThroughSortedEntities() { - Pageable pageable = PageRequest.of(0, 8, Sort.Direction.DESC, "attendees"); + Pageable pageable = new PageRequest(0, 8, Sort.Direction.DESC, "attendees"); Page page1 = repository.findAll(pageable); assertTrue("Query for parties should be atleast 12", page1.getTotalElements() >= 12); @@ -214,7 +204,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { @Test public void shouldPageWithStringBasedQuery() { - Pageable pageable = PageRequest.of(0, 8, Sort.Direction.DESC, "attendees"); + Pageable pageable = new PageRequest(0, 8, Sort.Direction.DESC, "attendees"); Page page1 = partyRepository.findPartiesWithAttendee(1, pageable); assertTrue("Query for parties with attendees should be atleast 12", page1.getTotalElements() >= 12); assertEquals(8, page1.getNumberOfElements()); @@ -241,7 +231,7 @@ public class N1qlCouchbaseRepositoryIntegrationTests { // Fails on deserialization as a different entity item is also present @Test(expected = MappingInstantiationException.class) public void shouldFailWithMissingFilterStringBasedQuery() { - Sort sort = Sort.by(Sort.Direction.DESC, "attendees"); + Sort sort = new Sort(Sort.Direction.DESC, "attendees"); partyRepository.findParties(sort); } @@ -273,5 +263,4 @@ public class N1qlCouchbaseRepositoryIntegrationTests { List partyList = partyRepository.findByDescriptionStartingWith(description); assertTrue(partyList.size() == 0); } - } diff --git a/src/test/java/org/springframework/data/couchbase/repository/PartyPagingRepository.java b/src/test/java/org/springframework/data/couchbase/repository/PartyPagingRepository.java new file mode 100644 index 00000000..26c6458b --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/repository/PartyPagingRepository.java @@ -0,0 +1,4 @@ +package org.springframework.data.couchbase.repository; + +public interface PartyPagingRepository extends CouchbasePagingAndSortingRepository { +} diff --git a/src/test/java/org/springframework/data/couchbase/repository/PartyRepository.java b/src/test/java/org/springframework/data/couchbase/repository/PartyRepository.java new file mode 100644 index 00000000..143b1625 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/repository/PartyRepository.java @@ -0,0 +1,101 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.repository; + +import java.util.Date; +import java.util.List; + +import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed; +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.domain.Sort; +import org.springframework.data.repository.query.Param; + +/** + * @author Simon Baslé + * @author Subhashni Balakrishnan + */ +@ViewIndexed(designDoc = "party", viewName = "all") +@N1qlPrimaryIndexed +@N1qlSecondaryIndexed(indexName = "party") +public interface PartyRepository extends CouchbaseRepository { + + List findByAttendeesGreaterThanEqual(int minAttendees); + + List findByEventDateIs(Date targetDate); + + List findByName(String name); + + @View(designDocument = "party", viewName = "byDate") + List findFirst3ByEventDateGreaterThanEqual(Date targetDate); + + List 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(); + + @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `attendees` >= $1") + Page findPartiesWithAttendee(int count, Pageable pageable); + + @Query("#{#n1ql.selectEntity}") + List findParties(Sort sort); + + @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $included || '%' AND attendees >= $min" + + " AND `desc` NOT LIKE '%' || $excluded || '%'") + List findAllWithNamedParams(@Param("excluded") String ex, @Param("included") String inc, + @Param("min") long minimumAttendees); + + @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" + + " AND `desc` NOT LIKE '%' || $1 || '%'") + List findAllWithPositionalParams(String ex, String inc, long minimumAttendees); + + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees < $3" + + " AND `desc` NOT LIKE '%' || $1 || '%' #{#n1ql.returning}") + List removeWithPositionalParams(String ex, String inc, long minimumAttendees); + + @Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND `desc` LIKE '%' || $2 || '%' AND attendees >= $3" + + " AND `desc` NOT LIKE '%' || $1 || '%' AND `desc` != \"this is \\\"$excluded\\\"\"") + List findAllWithPositionalParamsAndQuotedNamedParams(@Param("excluded") String ex, + @Param("included") String inc, @Param("min") long min); + + List findByDescriptionOrName(String description, String name); + + List removeByDescriptionOrName(String description, String name); + + @Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and eventDate = $1") + List getByEventDate(Date eventDate); + + List findByDescriptionStartingWith(String description); +}