/* * Copyright (c) [2011-2016] "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.Collections; 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.neo4j.examples.movies.domain.Rating; import org.springframework.data.neo4j.examples.movies.domain.TempMovie; import org.springframework.data.neo4j.examples.movies.domain.User; import org.springframework.data.neo4j.examples.movies.repo.CinemaRepository; import org.springframework.data.neo4j.examples.movies.repo.RatingRepository; import org.springframework.data.neo4j.examples.movies.repo.UserRepository; 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 Mark Angrish * @author Vince Bickers */ @ContextConfiguration(classes = {DerivedRelationshipEntityQueryTests.MoviesContext.class}) @RunWith(SpringJUnit4ClassRunner.class) public class DerivedRelationshipEntityQueryTests extends MultiDriverTestClass { @Autowired PlatformTransactionManager platformTransactionManager; @Autowired private UserRepository userRepository; @Autowired private CinemaRepository cinemaRepository; @Autowired private RatingRepository ratingRepository; private TransactionTemplate transactionTemplate; @Before public void clearDatabase() { transactionTemplate = new TransactionTemplate(platformTransactionManager); getGraphDatabaseService().execute("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE r, n"); } private void executeUpdate(String cypher) { getGraphDatabaseService().execute(cypher); } @Test @Transactional public void shouldFindREFromCustomQuery() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); userRepository.save(critic); Rating rating = ratingRepository.findRatingByUserAndTempMovie(critic.getId(), film.getId()); assertNotNull(rating); assertNotNull("The loaded rating shouldn't be null", rating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), rating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), rating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), rating.getUser().getId()); } /** * @see DATAGRAPH-629 */ @Test @Transactional public void shouldFindREWithSingleProperty() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); userRepository.save(critic); List<Rating> ratings = ratingRepository.findByStars(2); assertNotNull(ratings); Rating loadedRating = ratings.get(0); assertNotNull("The loaded rating shouldn't be null", loadedRating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), loadedRating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), loadedRating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), loadedRating.getUser().getId()); } /** * @see DATAGRAPH-629 */ @Test @Transactional public void shouldFindREWithMultiplePropertiesAnded() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Rating> ratings = ratingRepository.findByStarsAndRatingTimestamp(2, 1000); assertNotNull(ratings); Rating loadedRating = ratings.get(0); assertNotNull("The loaded rating shouldn't be null", loadedRating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), loadedRating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), loadedRating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), loadedRating.getUser().getId()); ratings = ratingRepository.findByStarsAndRatingTimestamp(2, 2000); assertEquals(0, ratings.size()); } /** * @see DATAGRAPH-629 */ @Test @Transactional public void shouldFindREWithMultiplePropertiesOred() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Rating> ratings = ratingRepository.findByStarsOrRatingTimestamp(5, 1000); assertNotNull(ratings); Rating loadedRating = ratings.get(0); assertNotNull("The loaded rating shouldn't be null", loadedRating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), loadedRating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), loadedRating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), loadedRating.getUser().getId()); ratings = ratingRepository.findByStarsAndRatingTimestamp(5, 2000); assertEquals(0, ratings.size()); } /** * @see DATAGRAPH-629 */ @Test @Transactional public void shouldFindREWithMultiplePropertiesDifferentComparisonOperatorsAnded() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Rating> ratings = ratingRepository.findByStarsAndRatingTimestampLessThan(2, 2000); assertNotNull(ratings); Rating loadedRating = ratings.get(0); assertNotNull("The loaded rating shouldn't be null", loadedRating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), loadedRating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), loadedRating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), loadedRating.getUser().getId()); ratings = ratingRepository.findByStarsAndRatingTimestamp(2, 3000); assertEquals(0, ratings.size()); } /** * @see DATAGRAPH-629 */ @Test @Transactional public void shouldFindREWithMultiplePropertiesDifferentComparisonOperatorsOred() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Rating> ratings = ratingRepository.findByStarsOrRatingTimestampGreaterThan(5, 500); assertNotNull(ratings); Rating loadedRating = ratings.get(0); assertNotNull("The loaded rating shouldn't be null", loadedRating); assertEquals("The relationship properties weren't saved correctly", filmRating.getStars(), loadedRating.getStars()); assertEquals("The rated film wasn't saved correctly", film.getName(), loadedRating.getMovie().getName()); assertEquals("The critic wasn't saved correctly", critic.getId(), loadedRating.getUser().getId()); ratings = ratingRepository.findByStarsAndRatingTimestamp(5, 2000); assertEquals(0, ratings.size()); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithNestedStartNodeProperty() { executeUpdate("CREATE (m1:Movie {name:'Speed'}) CREATE (m2:Movie {name:'The Matrix'}) CREATE (m:Movie {name:'Chocolat'})" + " CREATE (u:User {name:'Michal'}) CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByUserName("Michal"); assertEquals(2, ratings.size()); Collections.sort(ratings); assertEquals("Speed", ratings.get(0).getMovie().getName()); assertEquals("The Matrix", ratings.get(1).getMovie().getName()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithNestedEndNodeProperty() { executeUpdate("CREATE (m1:Movie {name:'Finding Dory'}) CREATE (m2:Movie {name:'Captain America'}) CREATE (m:Movie {name:'X-Men'})" + " CREATE (u:User {name:'Vince'}) CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByMovieName("Captain America"); assertEquals(1, ratings.size()); assertEquals("Vince", ratings.get(0).getUser().getName()); assertEquals("Captain America", ratings.get(0).getMovie().getName()); assertEquals(4, ratings.get(0).getStars()); ratings = ratingRepository.findByMovieName("X-Men"); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithBothStartEndNestedProperty() { executeUpdate("CREATE (m1:Movie {name:'Independence Day: Resurgence'}) CREATE (m2:Movie {name:'The Conjuring 2'}) CREATE (m:Movie {name:'The BFG'})" + " CREATE (u:User {name:'Daniela'}) CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByUserNameAndMovieName("Daniela", "Independence Day: Resurgence"); assertEquals(1, ratings.size()); assertEquals("Daniela", ratings.get(0).getUser().getName()); assertEquals("Independence Day: Resurgence", ratings.get(0).getMovie().getName()); assertEquals(3, ratings.get(0).getStars()); ratings = ratingRepository.findByUserNameAndMovieName("Daniela", "The BFG"); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithBaseAndNestedStartNodePropertyAnded() { executeUpdate("CREATE (m1:Movie {name:'The Shallows'}) CREATE (m2:Movie {name:'Central Intelligence'}) CREATE (m:Movie {name:'Now you see me'})" + " CREATE (u:User {name:'Luanne'}) CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByUserNameAndStars("Luanne", 3); assertEquals(1, ratings.size()); assertEquals("Luanne", ratings.get(0).getUser().getName()); assertEquals("The Shallows", ratings.get(0).getMovie().getName()); assertEquals(3, ratings.get(0).getStars()); ratings = ratingRepository.findByUserNameAndStars("Luanne", 1); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-662 * //TODO FIXME */ @Test(expected = UnsupportedOperationException.class) public void shouldFindRelEntitiesWithBaseAndNestedStartNodePropertyOred() { executeUpdate("CREATE (m1:Movie {name:'Swiss Army Man'}) CREATE (m2:Movie {name:'Me Before You'}) CREATE (m:Movie {name:'X-Men Apocalypse'})" + " CREATE (u:User {name:'Mark'}) CREATE (u2:User {name:'Adam'}) " + " CREATE (u)-[:RATED {stars:2}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)" + " CREATE (u2)-[:RATED {stars:3}]->(m)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByStarsOrUserName(3, "Mark"); assertEquals(3, ratings.size()); Collections.sort(ratings); assertEquals("Swiss Army Man", ratings.get(0).getMovie().getName()); assertEquals("X-Men Apocalypse", ratings.get(1).getMovie().getName()); assertEquals("Me Before You", ratings.get(2).getMovie().getName()); ratings = ratingRepository.findByStarsOrUserName(0, "Vince"); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithBaseAndNestedEndNodeProperty() { executeUpdate("CREATE (m1:Movie {name:'Our Kind of Traitor'}) CREATE (m2:Movie {name:'Teenage Mutant Ninja Turtles'}) CREATE (m:Movie {name:'Zootopia'})" + " CREATE (u:User {name:'Chris'}) CREATE (u2:User {name:'Katerina'}) " + " CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)" + " CREATE (u2)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByStarsAndMovieName(4, "Teenage Mutant Ninja Turtles"); assertEquals(2, ratings.size()); Collections.sort(ratings); assertEquals("Chris", ratings.get(0).getUser().getName()); assertEquals("Katerina", ratings.get(1).getUser().getName()); ratings = ratingRepository.findByStarsAndMovieName(5, "Teenage Mutant Ninja Turtles"); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithBaseAndBothStartEndNestedProperty() { executeUpdate("CREATE (m1:Movie {name:'The Jungle Book'}) CREATE (m2:Movie {name:'The Angry Birds Movie'}) CREATE (m:Movie {name:'Alice Through The Looking Glass'})" + " CREATE (u:User {name:'Alessandro'}) CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByUserNameAndMovieNameAndStars("Alessandro", "The Jungle Book", 3); assertEquals(1, ratings.size()); assertEquals("Alessandro", ratings.get(0).getUser().getName()); assertEquals("The Jungle Book", ratings.get(0).getMovie().getName()); assertEquals(3, ratings.get(0).getStars()); ratings = ratingRepository.findByUserNameAndMovieNameAndStars("Colin", "Speed", 0); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-632 */ @Test public void shouldFindRelEntitiesWithTwoStartNodeNestedProperties() { executeUpdate("CREATE (m1:Movie {name:'Batman v Superman'}) CREATE (m2:Movie {name:'Genius'}) CREATE (m:Movie {name:'Home'})" + " CREATE (u:User {name:'David', middleName:'M'}) CREATE (u2:User {name:'Martin', middleName:'M'}) " + " CREATE (u)-[:RATED {stars:3}]->(m1) CREATE (u)-[:RATED {stars:4}]->(m2)" + " CREATE (u2)-[:RATED {stars:4}]->(m2)"); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { List<Rating> ratings = ratingRepository.findByUserNameAndUserMiddleName("David", "M"); assertEquals(2, ratings.size()); Collections.sort(ratings); assertEquals("David", ratings.get(0).getUser().getName()); assertEquals("Batman v Superman", ratings.get(0).getMovie().getName()); assertEquals("David", ratings.get(1).getUser().getName()); assertEquals("Genius", ratings.get(1).getMovie().getName()); ratings = ratingRepository.findByUserNameAndUserMiddleName("David", "V"); assertEquals(0, ratings.size()); } }); } /** * @see DATAGRAPH-813 */ @Test @Transactional public void shouldDeleteAndReturnDeletedIds() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Long> ratingIds = ratingRepository.deleteByStarsOrRatingTimestampGreaterThan(2, 500); assertEquals(filmRating.getId(), ratingIds.get(0)); assertEquals(1, ratingIds.size()); List<Rating> ratings = ratingRepository.findByStarsAndRatingTimestamp(2, 2000); assertEquals(0, ratings.size()); } /** * @see DATAGRAPH-813 */ @Test @Transactional public void shouldCountByStars() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); long starredRatings = ratingRepository.countByStars(2); assertEquals(1L, starredRatings); } /** * @see DATAGRAPH-813 */ @Test @Transactional public void shouldRemoveByUserNameAndReturnCountOfDeletedObjects() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); long countRemovedObjects = ratingRepository.removeByUserName("Gary"); assertEquals(1L, countRemovedObjects); } /** * @see DATAGRAPH-813 */ @Test @Transactional public void shouldCountNothingWithNonMatchingFilter() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); long countRemovedObjects = ratingRepository.removeByUserName("Bill"); assertEquals(0L, countRemovedObjects); } /** * @see DATAGRAPH-813 */ @Test @Transactional public void shouldDeleteNothingWithNonMatchingFilter() { User critic = new User("Gary"); TempMovie film = new TempMovie("Fast and Furious XVII"); Rating filmRating = critic.rate(film, 2, "They've made far too many of these films now!"); filmRating.setRatingTimestamp(1000); userRepository.save(critic); List<Long> deletedIds = ratingRepository.deleteByStarsOrRatingTimestampGreaterThan(3, 2000); assertEquals(0L, deletedIds.size()); } @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"); } } }