/* * Copyright (c) [2011-2017] "Pivotal Software, Inc." / "Neo Technology" / "Graph Aware Ltd." * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product may include a number of subcomponents with * separate copyright notices and license terms. Your use of the source * code for these subcomponents is subject to the terms and * conditions of the subcomponent's license, as noted in the LICENSE file. * */ package org.springframework.data.neo4j.queries; import static org.junit.Assert.*; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.ogm.session.SessionFactory; import org.neo4j.ogm.testutil.MultiDriverTestClass; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.*; import org.springframework.data.neo4j.examples.movies.domain.Cinema; import org.springframework.data.neo4j.examples.movies.domain.queryresult.CinemaQueryResult; import org.springframework.data.neo4j.examples.movies.domain.queryresult.CinemaQueryResultInterface; import org.springframework.data.neo4j.examples.movies.repo.CinemaRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; /** * @author Luanne Misquitta * @author Jasper Blues * @author Mark Angrish * @author Nicolas Mervaillie * @see DATAGRAPH-680 */ @ContextConfiguration(classes = {PagedQueryTests.MoviesContext.class}) @RunWith(SpringJUnit4ClassRunner.class) public class PagedQueryTests extends MultiDriverTestClass { @Autowired PlatformTransactionManager platformTransactionManager; @Autowired private CinemaRepository cinemaRepository; private TransactionTemplate transactionTemplate; @Before public void init() { transactionTemplate = new TransactionTemplate(platformTransactionManager); getGraphDatabaseService().execute("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE r, n"); } public void setup() { String[] names = new String[]{"Picturehouse", "Regal", "Ritzy", "Metro", "Inox", "PVR", "Cineplex", "Landmark", "Rainbow", "Movietime"}; for (String name : names) { Cinema cinema = new Cinema(name); cinema.setLocation("London"); cinema.setCapacity(500); cinemaRepository.save(cinema); } } private void executeUpdate(String cypher) { getGraphDatabaseService().execute(cypher); } @Test @Transactional public void shouldFindPagedCinemas() { setup(); Pageable pageable = new PageRequest(0, 3); Page<Cinema> page = cinemaRepository.getPagedCinemas(pageable); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); page = cinemaRepository.getPagedCinemas(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); page = cinemaRepository.getPagedCinemas(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); page = cinemaRepository.getPagedCinemas(page.nextPageable()); assertEquals(1, page.getNumberOfElements()); assertFalse(page.hasNext()); } @Test(expected = IllegalArgumentException.class) @Transactional public void shouldThrowExceptionIfCountQueryAbsent() { setup(); Pageable pageable = new PageRequest(0, 3); cinemaRepository.getPagedCinemasWithoutCountQuery(pageable); } /** * Repeats shouldFindPagedCinemas for query results - concrete classes. * * @see DATAGRAPH-893 */ @Test @Transactional public void shouldFindPagedQueryResults() { setup(); Pageable pageable = new PageRequest(0, 3); Page<CinemaQueryResult> page = cinemaRepository.getPagedCinemaQueryResults(pageable); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); // FIXME : bug here - content is always null // assertNotNull(page.getContent().get(0).getName()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResults(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResults(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResults(page.nextPageable()); assertEquals(1, page.getNumberOfElements()); assertFalse(page.hasNext()); } /** * @see DATAGRAPH-893 */ @Test @Transactional public void shouldFindSlicedQueryResults() { setup(); Pageable pageable = new PageRequest(0, 3); Slice<CinemaQueryResult> page = cinemaRepository.getSlicedCinemaQueryResults(pageable); assertEquals(3, page.getNumberOfElements()); // FIXME : bug here - content is always null // assertNotNull(page.getContent().get(0).getName()); assertTrue(page.hasNext()); page = cinemaRepository.getSlicedCinemaQueryResults(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); page = cinemaRepository.getSlicedCinemaQueryResults(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); page = cinemaRepository.getSlicedCinemaQueryResults(page.nextPageable()); assertEquals(1, page.getNumberOfElements()); assertFalse(page.hasNext()); } /** * Repeats shouldFindPagedCinemas for query results - interfaces * * @see DATAGRAPH-893 */ @Test @Transactional public void shouldFindPagedQueryInterfaceResults() { setup(); Pageable pageable = new PageRequest(0, 3); Page<CinemaQueryResultInterface> page = cinemaRepository.getPagedCinemaQueryResultInterfaces(pageable); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); // FIXME : bug here - content is always null // assertNotNull(page.getContent().get(0).getName()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResultInterfaces(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResultInterfaces(page.nextPageable()); assertEquals(3, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate page = cinemaRepository.getPagedCinemaQueryResultInterfaces(page.nextPageable()); assertEquals(1, page.getNumberOfElements()); assertFalse(page.hasNext()); } @Test @Transactional public void shouldUseQueryParametersInCountQuery() { setup(); Pageable pageable = new PageRequest(0, 5); Page<Cinema> page = cinemaRepository.getPagedCinemasByCityWithPageCount("London", pageable); assertEquals(5, page.getNumberOfElements()); assertEquals(10, page.getTotalElements()); //With a count query, the total elements should equal the number returned by the count query assertTrue(page.hasNext()); page = cinemaRepository.getPagedCinemasByCityWithPageCount("London", page.nextPageable()); assertEquals(5, page.getNumberOfElements()); assertEquals(10, page.getTotalElements()); //With a count query, the total elements should equal the number returned by the count query assertFalse(page.hasNext()); //with a count query, the next page calculation is correct } @Test @Transactional public void shouldFindSlicedCinemas() { setup(); Pageable pageable = new PageRequest(0, 3); Slice<Cinema> slice = cinemaRepository.getSlicedCinemasByName(pageable); assertNotNull(slice.getContent().get(0).getName()); assertEquals(3, slice.getNumberOfElements()); assertTrue(slice.hasNext()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(3, slice.getNumberOfElements()); assertTrue(slice.hasNext()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(3, slice.getNumberOfElements()); assertTrue(slice.hasNext()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(1, slice.getNumberOfElements()); assertFalse(slice.hasNext()); } @Test @Transactional public void shouldCorrectlyCalculateWhetherNextSliceExists() { setup(); Pageable pageable = new PageRequest(0, 5); Slice<Cinema> slice = cinemaRepository.getSlicedCinemasByName(pageable); assertEquals(5, slice.getNumberOfElements()); assertTrue(slice.hasNext()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(5, slice.getNumberOfElements()); assertFalse(slice.hasNext()); } /** * @see DATAGRAPH-887 */ @Test @Transactional public void shouldFindPagedAndSortedCinemas() { setup(); Pageable pageable = new PageRequest(0, 4, Sort.Direction.ASC, "name"); Page<Cinema> page = cinemaRepository.findByLocation("London", pageable); assertEquals(4, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); assertEquals("Cineplex", page.getContent().get(0).getName()); assertEquals("Inox", page.getContent().get(1).getName()); assertEquals("Landmark", page.getContent().get(2).getName()); assertEquals("Metro", page.getContent().get(3).getName()); page = cinemaRepository.findByLocation("London", page.nextPageable()); assertEquals(4, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); assertEquals("Movietime", page.getContent().get(0).getName()); assertEquals("PVR", page.getContent().get(1).getName()); assertEquals("Picturehouse", page.getContent().get(2).getName()); assertEquals("Rainbow", page.getContent().get(3).getName()); page = cinemaRepository.findByLocation("London", page.nextPageable()); assertEquals(2, page.getNumberOfElements()); assertFalse(page.hasNext()); assertEquals(10, page.getTotalElements()); assertEquals("Regal", page.getContent().get(0).getName()); assertEquals("Ritzy", page.getContent().get(1).getName()); } /** * @see DATAGRAPH-887 */ @Test public void shouldSortPageWhenNestedPropertyIsInvolved() { executeUpdate("CREATE (p:Theatre {name:'Picturehouse', city:'London', capacity:5000}) " + "CREATE (r:Theatre {name:'Ritzy', city:'London', capacity: 7500}) " + "CREATE (m:Theatre {name:'Picturehouse', city:'London', capacity: 5000}) " + "CREATE (u:User {name:'Michal'}) " + "CREATE (u)-[:VISITED]->(r) " + "CREATE (u)-[:VISITED]->(m)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { Page<Cinema> page = cinemaRepository.findByLocationAndVisitedName("London", "Michal", new PageRequest(0, 1, Sort.Direction.DESC, "name")); assertEquals(1, page.getNumberOfElements()); assertEquals("Ritzy", page.getContent().get(0).getName()); page = cinemaRepository.findByLocationAndVisitedName("London", "Michal", new PageRequest(1, 1, Sort.Direction.DESC, "name")); assertEquals(1, page.getNumberOfElements()); assertEquals("Picturehouse", page.getContent().get(0).getName()); } }); } /** * @see DATAGRAPH-887 */ @Test public void shouldSortPageByNestedPropertyIsInvolved() { executeUpdate("CREATE (p:Theatre {name:'Picturehouse', city:'London', capacity:5000}) " + "CREATE (r:Theatre {name:'Ritzy', city:'London', capacity: 7500}) " + "CREATE (m:Theatre {name:'Regal', city:'Bombay', capacity: 5000}) " + "CREATE (u:User {name:'Michal'}) " + "CREATE (u)-[:VISITED]->(r) " + "CREATE (u)-[:VISITED]->(m)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { Page<Cinema> page = cinemaRepository.findByVisitedName("Michal", new PageRequest(0, 1, Sort.Direction.ASC, "location")); assertEquals(1, page.getNumberOfElements()); assertEquals("Regal", page.getContent().get(0).getName()); page = cinemaRepository.findByVisitedName("Michal", new PageRequest(1, 1, Sort.Direction.DESC, "location")); assertEquals(1, page.getNumberOfElements()); assertEquals("Regal", page.getContent().get(0).getName()); } }); } /** * @see DATAGRAPH-887 */ @Test @Transactional public void shouldFindSortedCinemas() { setup(); Sort sort = new Sort(Sort.Direction.ASC, "name"); List<Cinema> cinemas = cinemaRepository.findByLocation("London", sort); assertEquals(10, cinemas.size()); assertEquals("Cineplex", cinemas.get(0).getName()); assertEquals("Inox", cinemas.get(1).getName()); assertEquals("Landmark", cinemas.get(2).getName()); assertEquals("Metro", cinemas.get(3).getName()); assertEquals("Movietime", cinemas.get(4).getName()); assertEquals("PVR", cinemas.get(5).getName()); assertEquals("Picturehouse", cinemas.get(6).getName()); assertEquals("Rainbow", cinemas.get(7).getName()); assertEquals("Regal", cinemas.get(8).getName()); assertEquals("Ritzy", cinemas.get(9).getName()); } /** * @see DATAGRAPH-887 */ @Test @Transactional public void shouldFindPagedAndSortedCinemasByCapacity() { setup(); Pageable pageable = new PageRequest(0, 4, Sort.Direction.ASC, "name"); Page<Cinema> page = cinemaRepository.findByCapacity(500, pageable); assertEquals(4, page.getNumberOfElements()); assertEquals("Cineplex", page.getContent().get(0).getName()); assertEquals("Inox", page.getContent().get(1).getName()); assertEquals("Landmark", page.getContent().get(2).getName()); assertEquals("Metro", page.getContent().get(3).getName()); pageable = new PageRequest(1, 4, Sort.Direction.ASC, "name"); page = cinemaRepository.findByCapacity(500, pageable); assertEquals(4, page.getContent().size()); assertEquals("Movietime", page.getContent().get(0).getName()); assertEquals("PVR", page.getContent().get(1).getName()); assertEquals("Picturehouse", page.getContent().get(2).getName()); assertEquals("Rainbow", page.getContent().get(3).getName()); pageable = new PageRequest(2, 4, Sort.Direction.ASC, "name"); page = cinemaRepository.findByCapacity(500, pageable); assertEquals(2, page.getContent().size()); assertEquals("Regal", page.getContent().get(0).getName()); assertEquals("Ritzy", page.getContent().get(1).getName()); } /** * @see DATAGRAPH-653 */ @Test @Transactional public void shouldFindPagedCinemasSortedWithCustomQuery() { setup(); Pageable pageable = new PageRequest(0, 4, Sort.Direction.ASC, "n.name"); Page<Cinema> page = cinemaRepository.getPagedCinemas(pageable); assertEquals(4, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate assertEquals("Cineplex", page.getContent().get(0).getName()); assertEquals("Inox", page.getContent().get(1).getName()); assertEquals("Landmark", page.getContent().get(2).getName()); assertEquals("Metro", page.getContent().get(3).getName()); page = cinemaRepository.getPagedCinemas(page.nextPageable()); assertEquals(4, page.getNumberOfElements()); assertTrue(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate assertEquals("Movietime", page.getContent().get(0).getName()); assertEquals("PVR", page.getContent().get(1).getName()); assertEquals("Picturehouse", page.getContent().get(2).getName()); assertEquals("Rainbow", page.getContent().get(3).getName()); page = cinemaRepository.getPagedCinemas(page.nextPageable()); assertEquals(2, page.getNumberOfElements()); assertFalse(page.hasNext()); assertEquals(10, page.getTotalElements()); //this should not be relied on as incorrect as the total elements is an estimate assertEquals("Regal", page.getContent().get(0).getName()); assertEquals("Ritzy", page.getContent().get(1).getName()); } /** * @see DATAGRAPH-653 */ @Test @Transactional public void shouldFindSlicedCinemasSortedWithCustomQuery() { setup(); Pageable pageable = new PageRequest(0, 4, Sort.Direction.ASC, "n.name"); Slice<Cinema> slice = cinemaRepository.getSlicedCinemasByName(pageable); assertEquals(4, slice.getNumberOfElements()); assertTrue(slice.hasNext()); assertEquals("Cineplex", slice.getContent().get(0).getName()); assertEquals("Inox", slice.getContent().get(1).getName()); assertEquals("Landmark", slice.getContent().get(2).getName()); assertEquals("Metro", slice.getContent().get(3).getName()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(4, slice.getNumberOfElements()); assertTrue(slice.hasNext()); assertEquals("Movietime", slice.getContent().get(0).getName()); assertEquals("PVR", slice.getContent().get(1).getName()); assertEquals("Picturehouse", slice.getContent().get(2).getName()); assertEquals("Rainbow", slice.getContent().get(3).getName()); slice = cinemaRepository.getSlicedCinemasByName(slice.nextPageable()); assertEquals(2, slice.getNumberOfElements()); assertFalse(slice.hasNext()); assertEquals("Regal", slice.getContent().get(0).getName()); assertEquals("Ritzy", slice.getContent().get(1).getName()); } /** * @see DATAGRAPH-653 */ @Test @Transactional public void shouldFindCinemasSortedByNameWithCustomQuery() { setup(); Sort sort = new Sort(Sort.Direction.ASC, "n.name"); List<Cinema> cinemas = cinemaRepository.getCinemasSortedByName(sort); assertEquals(10, cinemas.size()); assertEquals("Cineplex", cinemas.get(0).getName()); assertEquals("Inox", cinemas.get(1).getName()); assertEquals("Landmark", cinemas.get(2).getName()); assertEquals("Metro", cinemas.get(3).getName()); assertEquals("Movietime", cinemas.get(4).getName()); assertEquals("PVR", cinemas.get(5).getName()); assertEquals("Picturehouse", cinemas.get(6).getName()); assertEquals("Rainbow", cinemas.get(7).getName()); assertEquals("Regal", cinemas.get(8).getName()); assertEquals("Ritzy", cinemas.get(9).getName()); } @Configuration @ComponentScan({"org.springframework.data.neo4j.examples.movies.service"}) @EnableNeo4jRepositories("org.springframework.data.neo4j.examples.movies.repo") @EnableTransactionManagement static class MoviesContext { @Bean public PlatformTransactionManager transactionManager() { return new Neo4jTransactionManager(sessionFactory()); } @Bean public SessionFactory sessionFactory() { return new SessionFactory(getBaseConfiguration().build(), "org.springframework.data.neo4j.examples.movies.domain"); } } }