diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java index 823db98a8..39f419fe7 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.HashSet; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.graphdb.DynamicRelationshipType; @@ -154,12 +153,6 @@ public class IndexTest extends EntityTestBase { @Indexed(indexType=IndexType.FULLTEXT, indexName = "InvalidIndexed") String fullTextDefaultIndexName; - @Indexed(indexType=IndexType.POINT, indexName = "InvalidIndexed") - double[] latlon; - - @Indexed(indexType=IndexType.POINT) - double[] latlonNoIndexName; - public void setFulltextNoIndexName(String fulltextNoIndexName) { this.fulltextNoIndexName = fulltextNoIndexName; } @@ -173,22 +166,22 @@ public class IndexTest extends EntityTestBase { static class InvalidSpatialIndexed { @Indexed(indexType=IndexType.POINT, indexName = "InvalidSpatialIndexed") - double[] latlon; + String latlon; @Indexed(indexType=IndexType.POINT) - double[] latlonNoIndexName; + String latlonNoIndexName; @Indexed(indexType=IndexType.POINT, indexName = "pointLayer") - double[] latlonValid; + String latlonValid; - public void setLatlonNoIndexName(double[] latlonNoIndexName) { + public void setLatlonNoIndexName(String latlonNoIndexName) { this.latlonNoIndexName = latlonNoIndexName; } - public void setLatlon(double[] latlon) { + public void setLatlon(String latlon) { this.latlon = latlon; } - public void setLatlonValid(double[] latlonValid) { + public void setLatlonValid(String latlonValid) { this.latlonValid = latlonValid; } } @@ -197,7 +190,7 @@ public class IndexTest extends EntityTestBase { @Transactional public void indexAccessWithFullAndNoSpatialIndexNameShouldFail() { InvalidSpatialIndexed invalidIndexed = persist(new InvalidSpatialIndexed()); - double[] latlon = {15.0,65}; + String latlon = "POINT (55 15)"; invalidIndexed.setLatlonNoIndexName(latlon); } @@ -205,16 +198,15 @@ public class IndexTest extends EntityTestBase { @Transactional public void indexAccessWithDefaultSpatialIndexNameShouldFail() { InvalidSpatialIndexed invalidIndexed = persist(new InvalidSpatialIndexed()); - double[] latlon = {15.0,65}; + String latlon = "POINT (55 15)"; invalidIndexed.setLatlon( latlon); } @Test - @Ignore @Transactional public void indexAccessWithValidSpatialIndexName() { InvalidSpatialIndexed invalidIndexed = persist(new InvalidSpatialIndexed()); - double[] latlon = {15.0,65}; + String latlon = "POINT (55 15)"; invalidIndexed.setLatlonValid( latlon); } diff --git a/spring-data-neo4j-parent/pom.xml b/spring-data-neo4j-parent/pom.xml index b98118bbf..bde68ae7d 100644 --- a/spring-data-neo4j-parent/pom.xml +++ b/spring-data-neo4j-parent/pom.xml @@ -413,6 +413,18 @@ ${neo4j.spatial.version} true + + org.neo4j + neo4j-shell + ${neo4j.version} + true + + + org.neo4j + neo4j-udc + ${neo4j.version} + true + org.neo4j neo4j-spatial diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 7226cae0b..79ab83b04 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -128,6 +128,11 @@ neo4j-cypher true + + org.neo4j + neo4j-shell + true + org.neo4j diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java index 1e558c2fb..a4f756656 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/AbstractGraphRepository.java @@ -16,6 +16,11 @@ package org.springframework.data.neo4j.repository; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + import org.apache.lucene.search.NumericRangeQuery; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.NotFoundException; @@ -34,11 +39,6 @@ import org.springframework.data.neo4j.support.Neo4jTemplate; import org.springframework.data.neo4j.support.index.NoSuchIndexException; import org.springframework.data.neo4j.support.index.NullReadableIndex; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - /** * Repository like finder for Node and Relationship-Entities. Provides finder methods for direct access, access via {@link org.springframework.data.neo4j.core.TypeRepresentationStrategy} * and indexing. @@ -47,7 +47,14 @@ import java.util.List; * @param Type of backing state, either Node or Relationship */ @org.springframework.stereotype.Repository -public abstract class AbstractGraphRepository implements GraphRepository, NamedIndexRepository { +public abstract class AbstractGraphRepository implements GraphRepository, NamedIndexRepository, SpatialRepository { + @Override + public ClosableIterable findByBoundingBox( String indexName, double lowerLeftLat, + double lowerLeftLon, double upperRightLat, double upperRightLon ) + { + return findAllByQuery( indexName, "bbox", String.format("[%f, %f, %f, %f]", lowerLeftLon, upperRightLon, lowerLeftLat, upperRightLat) ); + } + public static final ClosableIterable EMPTY_CLOSABLE_ITERABLE = new ClosableIterable() { @Override public void close() { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SpatialRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SpatialRepository.java new file mode 100644 index 000000000..66fd9fde9 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SpatialRepository.java @@ -0,0 +1,33 @@ +/** + * Copyright 2011 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 + * + * http://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.neo4j.repository; + +import org.neo4j.helpers.collection.ClosableIterable; + + + +/** + * @author mh + * @since 29.03.11 + */ +public interface SpatialRepository { + ClosableIterable findByBoundingBox(String indexName, double lowerLeftLat, + double lowerLeftLon, + double upperRightLat, + double upperRightLon); + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java index 4ee0f4746..0b576e52f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java @@ -136,7 +136,8 @@ public class DelegatingGraphDatabase implements GraphDatabase { if (isNode(type)) { if (indexManager.existsForNodes(indexName)) return (Index) checkAndGetExistingIndex(indexName, indexType, indexManager.forNodes(indexName)); - return (Index) indexManager.forNodes(indexName, indexConfigFor(indexType)); + Index index = indexManager.forNodes(indexName, indexConfigFor(indexType)); + return (Index) index; } else { if (indexManager.existsForRelationships(indexName)) return (Index) checkAndGetExistingIndex(indexName, indexType, indexManager.forRelationships(indexName)); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/index/IndexType.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/index/IndexType.java index 1d3b3ae3d..8615c9fe9 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/index/IndexType.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/index/IndexType.java @@ -35,7 +35,6 @@ public enum IndexType SIMPLE{ public Map getConfig() { return LuceneIndexImplementation.EXACT_CONFIG; } }, FULLTEXT { public Map getConfig() { return LuceneIndexImplementation.FULLTEXT_CONFIG; } }, POINT { public Map getConfig() { return MapUtil.stringMap( - IndexManager.PROVIDER, "spatial", "geometry_type" , "point") ; } }; - + IndexManager.PROVIDER, "spatial", "geometry_type" , "point","wkt","wkt") ; } }; public abstract MapgetConfig(); } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/model/Person.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/model/Person.java index 956f5e496..1b55942ce 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/model/Person.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/model/Person.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.springframework.data.neo4j.annotation.*; import org.springframework.data.neo4j.fieldaccess.DynamicProperties; +import org.springframework.data.neo4j.support.index.IndexType; import javax.validation.constraints.Max; import javax.validation.constraints.Min; @@ -42,6 +43,9 @@ public class Person { @Indexed private String nickname; + @Indexed(indexType = IndexType.POINT, indexName="personLayer") + private String wkt; + @Max(100) @Min(0) @Indexed @@ -159,6 +163,10 @@ public class Person { public void setBoss(Person boss) { this.boss = boss; } + + public void setLocation(String locationInWkt) { + this.wkt = locationInWkt; + } @Override public String toString() { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTest.java index 60580fb43..94b207608 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTest.java @@ -16,6 +16,18 @@ package org.springframework.data.neo4j.repository; +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; +import static org.junit.internal.matchers.IsCollectionContaining.hasItems; +import static org.neo4j.helpers.collection.IteratorUtil.addToCollection; +import static org.neo4j.helpers.collection.IteratorUtil.asCollection; + +import java.util.HashSet; +import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; @@ -38,18 +50,6 @@ import org.springframework.test.context.transaction.BeforeTransaction; import org.springframework.test.context.transaction.TransactionalTestExecutionListener; import org.springframework.transaction.annotation.Transactional; -import java.util.HashSet; -import java.util.Map; - -import static java.util.Arrays.asList; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.internal.matchers.IsCollectionContaining.hasItem; -import static org.junit.internal.matchers.IsCollectionContaining.hasItems; -import static org.neo4j.helpers.collection.IteratorUtil.addToCollection; -import static org.neo4j.helpers.collection.IteratorUtil.asCollection; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) @@ -88,6 +88,12 @@ public class GraphRepositoryTest { assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david, testTeam.emil)); } + @Test + public void testFindIterableOfPersonWithQueryAnnotationSpatial() { + Iterable teamMembers = personRepository.findByBoundingBox( "personLayer", 55, 15, 57, 17 ); + assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david, testTeam.emil)); + } + @Test public void testFindIterableOfPersonWithQueryAnnotationAndGremlin() { Iterable teamMembers = personRepository.findAllTeamMembersGremlin(testTeam.sdg); diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/PersonRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/PersonRepository.java index 1261df953..f2f612dc8 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/PersonRepository.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/PersonRepository.java @@ -34,7 +34,7 @@ import java.util.Map; * @author Oliver Gierke * @since 29.03.11 */ -public interface PersonRepository extends GraphRepository, NamedIndexRepository { +public interface PersonRepository extends GraphRepository, NamedIndexRepository, SpatialRepository { @Query("start team=node({p_team}) match (team)-[:persons]->(member) return member") Iterable findAllTeamMembers(@Param("p_team") Group team); @@ -62,6 +62,7 @@ public interface PersonRepository extends GraphRepository, NamedIndexRep @Query("start team=node({p_team}) match (team)-[:persons]->(member) return member") Iterable findAllTeamMembersSorted(@Param("p_team") Group team, Sort sort); + // Derived queries Iterable findByName(String name); } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/SpatialGraphRepositoryTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/SpatialGraphRepositoryTest.java new file mode 100644 index 000000000..250a846b6 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/SpatialGraphRepositoryTest.java @@ -0,0 +1,88 @@ +/** + * Copyright 2011 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 + * + * http://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.neo4j.repository; + +import static org.junit.Assert.assertThat; +import static org.junit.internal.matchers.IsCollectionContaining.hasItems; +import static org.neo4j.helpers.collection.IteratorUtil.asCollection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.neo4j.model.Person; +import org.springframework.data.neo4j.support.Neo4jTemplate; +import org.springframework.data.neo4j.support.node.Neo4jHelper; +import org.springframework.test.context.CleanContextCacheTestExecutionListener; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +@RunWith(SpringJUnit4ClassRunner.class) +@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) +@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/repository/GraphRepositoryTest-context.xml"}) +@Transactional +public class SpatialGraphRepositoryTest { + + protected final Log log = LogFactory.getLog(getClass()); + + @Autowired + private Neo4jTemplate neo4jTemplate; + + @Autowired + private PersonRepository personRepository; + @Autowired + GroupRepository groupRepository; + + @Autowired FriendshipRepository friendshipRepository; + + + @Autowired + PlatformTransactionManager transactionManager; + + private TestTeam testTeam; + + @BeforeTransaction + public void cleanDb() { + Neo4jHelper.cleanDb(neo4jTemplate); + } + @Before + public void setUp() throws Exception { + new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() { + protected void doInTransactionWithoutResult(TransactionStatus status) { + testTeam = new TestTeam(); + testTeam.createSDGTeam(personRepository, groupRepository,friendshipRepository); + } + }); + } + + @Test + public void testFindIterableOfPersonWithQueryAnnotationSpatial() { + Iterable teamMembers = personRepository.findByBoundingBox( "personLayer", 55, 15, 57, 17 ); + assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david, testTeam.emil)); + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/TestTeam.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/TestTeam.java index 9f5d868db..946fd941d 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/TestTeam.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/TestTeam.java @@ -42,9 +42,11 @@ public class TestTeam { michael = new Person("Michael", 36); michael.setBoss(emil); michael.setPersonality(Personality.EXTROVERT); + michael.setLocation( "POINT(16 56)" ); david = new Person("David", 25); david.setBoss(emil); + david.setLocation( "POINT (16 56)" ); friendShip = michael.knows(david); friendShip.setYears(2); sdg = new Group(); diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/neo4j/repository/GraphRepositoryTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/neo4j/repository/GraphRepositoryTest-context.xml index 966a09d21..f5987b6ae 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/neo4j/repository/GraphRepositoryTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/neo4j/repository/GraphRepositoryTest-context.xml @@ -7,16 +7,8 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> - - - - - true - - - - + \ No newline at end of file