From 36c951e55d1161204358a0a5eaad29310f50e82c Mon Sep 17 00:00:00 2001 From: Nicki Watt Date: Mon, 3 Mar 2014 03:13:42 +0000 Subject: [PATCH] DATAGRAPH-433: Begin fixing of how uniquely indexed properties are handled --- .../integration/RestUniqueEntityTests.java | 6 +- .../NodeDelegatingFieldAccessorFactory.java | 5 +- .../SchemaIndexingFieldAccessorFactory.java | 111 +++++++++++ ...gPropertyFieldAccessorListenerFactory.java | 34 +++- .../repository/AbstractGraphRepository.java | 49 ++++- .../neo4j/repository/GraphRepository.java | 2 +- .../repository/SchemaIndexRepository.java | 35 ++++ .../data/neo4j/support/Neo4jTemplate.java | 32 ++++ .../unique/InvalidUniqueEntityTests.java | 15 -- .../repository/GraphRepositoryTests.java | 1 - .../data/neo4j/unique/UniqueEntityTests.java | 153 --------------- .../data/neo4j/unique/common/CommonClub.java | 25 +++ .../neo4j/unique/common/CommonUniqueClub.java | 28 +++ .../common/CommonUniqueEntityTestBase.java | 181 ++++++++++++++++++ .../common/CommonUniqueNumericIdClub.java | 24 +++ .../UniqueLegacyIndexBasedEntityTests.java | 126 ++++++++++++ .../{ => legacy}/UniqueRelationshipTests.java | 2 +- .../unique/{ => legacy}/domain/Club.java | 9 +- .../unique/legacy/domain/UniqueClub.java | 66 +++++++ .../domain/UniqueNumericIdClub.java | 8 +- .../repository/ClubRepository.java | 4 +- .../repository/UniqueClubRepository.java | 6 +- .../UniqueNumericIdClubRepository.java | 6 +- .../UniqueSchemaBasedEntityTests.java | 122 ++++++++++++ .../domain/Club.java} | 17 +- .../unique/schemabased/domain/UniqueClub.java | 61 ++++++ .../domain/UniqueNumericIdClub.java | 51 +++++ .../repository/ClubRepository.java | 23 +++ .../repository/UniqueClubRepository.java | 23 +++ .../UniqueNumericIdClubRepository.java | 23 +++ ...ext.xml => unique-legacy-test-context.xml} | 4 +- .../resources/unique-schema-test-context.xml | 24 +++ 32 files changed, 1063 insertions(+), 213 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingFieldAccessorFactory.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SchemaIndexRepository.java delete mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueEntityTests.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonClub.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueClub.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueEntityTestBase.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueNumericIdClub.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueLegacyIndexBasedEntityTests.java rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/UniqueRelationshipTests.java (98%) rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/domain/Club.java (81%) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueClub.java rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/domain/UniqueNumericIdClub.java (77%) rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/repository/ClubRepository.java (86%) rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/repository/UniqueClubRepository.java (81%) rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{ => legacy}/repository/UniqueNumericIdClubRepository.java (77%) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/UniqueSchemaBasedEntityTests.java rename spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/{domain/UniqueClub.java => schemabased/domain/Club.java} (73%) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueClub.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueNumericIdClub.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/ClubRepository.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueClubRepository.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueNumericIdClubRepository.java rename spring-data-neo4j/src/test/resources/{unique-test-context.xml => unique-legacy-test-context.xml} (94%) create mode 100644 spring-data-neo4j/src/test/resources/unique-schema-test-context.xml diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/integration/RestUniqueEntityTests.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/integration/RestUniqueEntityTests.java index 60efbda5f..f22708b70 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/integration/RestUniqueEntityTests.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/integration/RestUniqueEntityTests.java @@ -19,7 +19,7 @@ package org.springframework.data.neo4j.rest.integration; import org.junit.*; import org.junit.runner.RunWith; import org.springframework.data.neo4j.rest.support.RestTestBase; -import org.springframework.data.neo4j.unique.UniqueEntityTests; +import org.springframework.data.neo4j.unique.legacy.UniqueLegacyIndexBasedEntityTests; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -33,10 +33,10 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { - "classpath:unique-test-context.xml", + "classpath:unique-legacy-test-context.xml", "classpath:RestTests-context.xml"}) @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) -public class RestUniqueEntityTests extends UniqueEntityTests { +public class RestUniqueEntityTests extends UniqueLegacyIndexBasedEntityTests { @BeforeClass public static void startDb() throws Exception { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeDelegatingFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeDelegatingFieldAccessorFactory.java index 3f042bf7b..4af61460a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeDelegatingFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeDelegatingFieldAccessorFactory.java @@ -39,10 +39,10 @@ public class NodeDelegatingFieldAccessorFactory extends DelegatingFieldAccessorF template, new PropertyFieldAccessorFactory(template), new ConvertingNodePropertyFieldAccessorFactory(template)), - new SchemaIndexingPropertyFieldAccessorListenerFactory( + /*new SchemaIndexingPropertyFieldAccessorListenerFactory( template, new PropertyFieldAccessorFactory(template), - new ConvertingNodePropertyFieldAccessorFactory(template)), + new ConvertingNodePropertyFieldAccessorFactory(template)), */ new ValidatingNodePropertyFieldAccessorListenerFactory(template) ); } @@ -53,6 +53,7 @@ public class NodeDelegatingFieldAccessorFactory extends DelegatingFieldAccessorF new IdFieldAccessorFactory(template), new TransientFieldAccessorFactory(), //TODO Labels new LabelFieldAccessorFactory(template), + new SchemaIndexingFieldAccessorFactory(template), new TraversalFieldAccessorFactory(template), new QueryFieldAccessorFactory(template), new PropertyFieldAccessorFactory(template), diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingFieldAccessorFactory.java new file mode 100644 index 000000000..56f9e7f93 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingFieldAccessorFactory.java @@ -0,0 +1,111 @@ +/** + * 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.fieldaccess; + + +import org.neo4j.graphdb.DynamicLabel; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.PropertyContainer; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.neo4j.mapping.MappingPolicy; +import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; +import org.springframework.data.neo4j.support.Neo4jTemplate; +import org.springframework.data.neo4j.support.mapping.StoredEntityType; + +import java.util.Set; +import java.util.TreeSet; + +import static org.springframework.data.neo4j.support.DoReturn.doReturn; + +/** + * @author Nicki Watt + * @since 01.03.2014 + */ +public class SchemaIndexingFieldAccessorFactory implements FieldAccessorFactory { + private final Neo4jTemplate template; + + public SchemaIndexingFieldAccessorFactory(Neo4jTemplate template) { + this.template = template; + } + + @Override + public boolean accept(final Neo4jPersistentProperty property) { + return property.isIndexed() && property.getIndexInfo().isLabelBased(); + } + + @Override + public FieldAccessor forField(final Neo4jPersistentProperty property) { + return new SchemaIndexedFieldAccessor(template,property); + } + + public static class SchemaIndexedFieldAccessor extends PropertyFieldAccessorFactory.PropertyFieldAccessor { + + public SchemaIndexedFieldAccessor(Neo4jTemplate template,Neo4jPersistentProperty property) { + super(template,property); + } + + @Override + public boolean isWriteable(Object entity) { + return super.isWriteable(entity); + } + + @Override + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { + final PropertyContainer state = template.getPersistentState(entity); + if (!(state instanceof Node)) { + throw new IllegalArgumentException("not expecting to deal with non node property"); + } + + applyMissingSchemaIndexLabels(entity,(Node)state); + checkForUniqueViolation(entity, newVal, (Node)state); + return super.setValue(entity,newVal,mappingPolicy); + } + + private void checkForUniqueViolation(Object entity,Object newVal, Node stateToBeSaved) { + StoredEntityType set = template.getStoredEntityType(entity); + if (newVal != null && property.isUnique()) { + Object existingUniqueEntity = template.findUniqueEntity(set.getEntity().getType(),property.getNeo4jPropertyName(),newVal); + if (existingUniqueEntity == null) return; + final Node existingUniqueState = (Node)template.getPersistentState(existingUniqueEntity); + if (existingUniqueState.equals(stateToBeSaved)) return; + throw new DataIntegrityViolationException("Unique property "+property+" was to be set to duplicate value "+newVal); + } + } + + private void applyMissingSchemaIndexLabels(Object entity,Node state) { + // TODO - This logic should rather be done once when the + // entity is persisted for the first time rather than + // on each update .... + StoredEntityType set = template.getStoredEntityType(entity); + if (set != null) { + applyMissingSchemaIndexLabels(state, set); + } + } + + private void applyMissingSchemaIndexLabels(Node node, StoredEntityType set) { + for (StoredEntityType ancestorSet : set.getSuperTypes()) { + applyMissingSchemaIndexLabels(node, ancestorSet); + } + Label label = DynamicLabel.label( (String)set.getAlias()); + if (!node.hasLabel(label)) + node.addLabel(label); + } + + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingPropertyFieldAccessorListenerFactory.java index 3ebfa9650..cfeacbbb2 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SchemaIndexingPropertyFieldAccessorListenerFactory.java @@ -20,9 +20,12 @@ import org.neo4j.graphdb.DynamicLabel; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.PropertyContainer; +import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.schema.IndexDefinition; +import org.neo4j.index.lucene.ValueContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; import org.springframework.data.neo4j.support.mapping.StoredEntityType; @@ -76,16 +79,33 @@ public class SchemaIndexingPropertyFieldAccessorListenerFactory Type of backing state, either Node or Relationship */ @Transactional(readOnly = true) -public abstract class AbstractGraphRepository implements GraphRepository, NamedIndexRepository, SpatialRepository, CypherDslRepository { +public abstract class AbstractGraphRepository implements + GraphRepository, NamedIndexRepository, SpatialRepository, CypherDslRepository { private final LegacyIndexSearcher legacyIndexSearcher; /* @@ -237,6 +247,43 @@ public abstract class AbstractGraphRepository im } + /** + * Schema (aka Label based) Index based single finder which uses the default label + * name for this type to find the entity. + * + * @param property + * @param value + * @return Single Entity with this property and value or null if it does not exist + */ + @Override + public T findBySchemaPropertyValue(String property, Object value) { + return findAllBySchemaPropertyValue(property,value).singleOrNull(); + } + + /** + * Schema (aka Label based) finder, uses the default label name for this type + * to lookup entities. + * @param property + * @param value + * @return Iterable over Entities with this property and value + */ + @Override + public EndResult findAllBySchemaPropertyValue(String property, Object value) { + final String SCHEMA_PROP_MATCH_CLAUSE = "MATCH (entity:`%s`) where entity.`%s` = {propValue} return entity"; + + Neo4jPersistentEntity persistentEntity = template.getEntityType(clazz).getEntity(); + Neo4jPersistentProperty persistentProperty = (Neo4jPersistentProperty)persistentEntity.getPersistentProperty(property); + if (persistentProperty.getIndexInfo() == null || !persistentProperty.getIndexInfo().isLabelBased() ) { + throw new IllegalArgumentException(format("property {} is not schema indexed",property)); + } + + Map params = new HashMap(); + params.put("propValue", value); + String cypherQuery = format(SCHEMA_PROP_MATCH_CLAUSE, + persistentProperty.getIndexInfo().getIndexName(), property ); + return template.query(cypherQuery,params).to(clazz); + } + protected abstract S getById(long id); @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepository.java index 260ef7d6a..7c0f44eea 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepository.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepository.java @@ -24,5 +24,5 @@ import org.springframework.data.repository.NoRepositoryBean; * @since 12.01.11 */ @NoRepositoryBean -public interface GraphRepository extends CRUDRepository, IndexRepository, TraversalRepository { +public interface GraphRepository extends CRUDRepository, IndexRepository, SchemaIndexRepository, TraversalRepository { } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SchemaIndexRepository.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SchemaIndexRepository.java new file mode 100644 index 000000000..6f72ee829 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/SchemaIndexRepository.java @@ -0,0 +1,35 @@ +/** + * 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.springframework.data.neo4j.conversion.EndResult; +import org.springframework.transaction.annotation.Transactional; + + +/** + * @author Nicki Watt + * @since 01.03.2014 + */ +public interface SchemaIndexRepository { + + @Transactional + T findBySchemaPropertyValue(String property, Object value); + + @Transactional + EndResult findAllBySchemaPropertyValue(String property, Object value); + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java index 588c38230..f414ec6b5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java @@ -54,6 +54,7 @@ import org.springframework.data.neo4j.support.index.IndexProvider; import org.springframework.data.neo4j.support.index.IndexType; import org.springframework.data.neo4j.support.mapping.*; import org.springframework.data.neo4j.support.query.QueryEngine; +import org.springframework.data.neo4j.support.schema.SchemaIndexProvider; import org.springframework.data.neo4j.template.GraphCallback; import org.springframework.data.neo4j.template.Neo4jOperations; import org.springframework.data.util.ClassTypeInformation; @@ -67,6 +68,7 @@ import javax.validation.Validator; import java.util.Collections; import java.util.Map; +import static java.lang.String.format; import static org.springframework.data.neo4j.support.ParameterCheck.notNull; /** @@ -132,6 +134,7 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware { throw new IllegalArgumentException("Can't create graph repository for non-graph entity of type " + clazz); } + // Legacy Indexes Below @Deprecated public Index getIndex(Class type) { notNull(type, "entity type"); @@ -147,6 +150,31 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware { return getIndexProvider().getIndex(getPersistentEntity(type), indexName, indexType); } + // Schema Indexes Below + + /** + * Returns the unique entity of type entityClass (if it exists) otherwise returns null. + * Note: this method will only work with the newer schema based indexes (not legacy) + * + * @param entityClass Entity class + * @param propertyName Name of uniquely indexed property + * @param value value of property to find + * @param the entity + * @return the unique entity of type entityClass (if it exists) otherwise returns null. + * + */ + public T findUniqueEntity(final Class entityClass,String propertyName, Object value) { + final Neo4jPersistentEntityImpl persistentEntity = getPersistentEntity(entityClass); + Neo4jPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(propertyName); + + boolean labelIndexed = persistentProperty.isIndexed() && persistentProperty.getIndexInfo().isLabelBased(); + boolean indexedButNotUnique = persistentProperty.isIndexed() && !persistentProperty.isUnique(); + if (!labelIndexed || indexedButNotUnique) { + throw new IllegalArgumentException(format("propertyName '%s' must be uniquely (schema) indexed however it is not", propertyName)); + } + return (T)getSchemaIndexProvider().findAll(persistentProperty,value).singleOrNull(); + } + /** * @return true if a transaction manager is available and a transaction is currently running */ @@ -600,6 +628,10 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware { return infrastructure.getIndexProvider(); } + private SchemaIndexProvider getSchemaIndexProvider() { + return infrastructure.getSchemaIndexProvider(); + } + private Neo4jPersistentEntityImpl getPersistentEntity(Class type) { return getMappingContext().getPersistentEntity(type); } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/invalid/unique/InvalidUniqueEntityTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/invalid/unique/InvalidUniqueEntityTests.java index 6b005a6d9..f0ad8cb77 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/invalid/unique/InvalidUniqueEntityTests.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/invalid/unique/InvalidUniqueEntityTests.java @@ -15,24 +15,9 @@ */ package org.springframework.data.neo4j.invalid.unique; -import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.neo4j.graphdb.GraphDatabaseService; import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.mapping.model.MappingException; -import org.springframework.data.neo4j.unique.domain.Club; -import org.springframework.data.neo4j.unique.domain.UniqueClub; -import org.springframework.data.neo4j.unique.domain.UniqueNumericIdClub; -import org.springframework.data.neo4j.unique.repository.ClubRepository; -import org.springframework.data.neo4j.unique.repository.UniqueClubRepository; -import org.springframework.data.neo4j.unique.repository.UniqueNumericIdClubRepository; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; import static org.junit.Assert.assertEquals; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTests.java index 7b2874cd7..ea6ef32bd 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTests.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/repository/GraphRepositoryTests.java @@ -282,7 +282,6 @@ public class GraphRepositoryTests { } @Test @Transactional -// @Ignore("cypher bug with escaped params") public void testFindWithMultipleParameters() { final int limit = 2; Iterable teamMembers = personRepository.findSomeTeamMembers(testTeam.sdg.getName(), 0, limit); diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueEntityTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueEntityTests.java deleted file mode 100644 index d5b5740a1..000000000 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueEntityTests.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * 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.unique; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.neo4j.graphdb.GraphDatabaseService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.mapping.model.MappingException; -import org.springframework.data.neo4j.unique.domain.Club; -import org.springframework.data.neo4j.invalid.unique.InvalidClub; -import org.springframework.data.neo4j.unique.domain.UniqueClub; -import org.springframework.data.neo4j.unique.domain.UniqueNumericIdClub; -import org.springframework.data.neo4j.unique.repository.ClubRepository; -import org.springframework.data.neo4j.invalid.unique.InvalidClubRepository; -import org.springframework.data.neo4j.unique.repository.UniqueClubRepository; -import org.springframework.data.neo4j.unique.repository.UniqueNumericIdClubRepository; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; - -import static org.junit.Assert.assertEquals; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = {"classpath:unique-test-context.xml"}) -@Transactional -public class UniqueEntityTests { - - @Autowired - private ClubRepository clubRepository; - - @Autowired - private UniqueClubRepository uniqueClubRepository; - - @Autowired - protected GraphDatabaseService graphDatabaseService; - - @Autowired - private UniqueNumericIdClubRepository uniqueNumericIdClubRepository; - - @Before - public void setup() { - clubRepository.deleteAll(); - uniqueClubRepository.deleteAll(); - } - - @Test - public void shouldOnlyCreateSingleInstanceForUniqueNodeEntity() { - UniqueClub club = new UniqueClub(); - club.setName("foo"); - uniqueClubRepository.save(club); - - club = new UniqueClub(); - club.setName("foo"); - uniqueClubRepository.save(club); - - assertEquals(1, uniqueClubRepository.count()); - } - - @Test(expected = MappingException.class) - public void shouldFailOnNullPropertyValue() { - UniqueClub club = new UniqueClub(); - club.setName(null); - uniqueClubRepository.save(club); - } - - @Test - public void shouldOnlyCreateSingleInstanceForUniqueNumericNodeEntity() { - UniqueNumericIdClub club = new UniqueNumericIdClub(); - club.setClubId(100L); - uniqueNumericIdClubRepository.save(club); - - club = new UniqueNumericIdClub(100L); - uniqueNumericIdClubRepository.save(club); - - assertEquals(1, uniqueNumericIdClubRepository.count()); - } - - @Test(expected = MappingException.class) - public void shouldFailOnNullNumericPropertyValue() { - UniqueNumericIdClub club = new UniqueNumericIdClub(); - club.setClubId(null); - uniqueNumericIdClubRepository.save(club); - } - - @Test - public void shouldCreateMultipleInstancesForNonUniqueNodeEntity() { - Club club = new Club(); - club.setName("foo"); - clubRepository.save(club); - - club = new Club(); - club.setName("foo"); - clubRepository.save(club); - - assertEquals(2, clubRepository.count()); - } - - @Test - public void deletingUniqueNodeShouldRemoveItFromTheUniqueIndex() { - UniqueClub club = new UniqueClub(); - club.setName("foo"); - uniqueClubRepository.save(club); - assertEquals(1, uniqueClubRepository.count()); - - uniqueClubRepository.delete(club); - assertEquals(0, uniqueClubRepository.count()); - } - - @Test(expected = DataIntegrityViolationException.class) - public void updatingToADuplicateValueShouldCauseAnException() { - uniqueClubRepository.save(new UniqueClub("foo")); - UniqueClub club2 = uniqueClubRepository.save(new UniqueClub("bar")); - assertEquals(2, uniqueClubRepository.count()); - club2.setName("foo"); - uniqueClubRepository.save(club2); - } - - @Test - public void updatingToANewValueShouldKeepTheEntityUnique() { - UniqueClub club = uniqueClubRepository.save(new UniqueClub("foo")); - assertEquals(1, uniqueClubRepository.count()); - club.setName("bar"); - uniqueClubRepository.save(club); - assertEquals(1, uniqueClubRepository.count()); - final UniqueClub club2 = uniqueClubRepository.save(new UniqueClub("bar")); - assertEquals(club.getId(),club2.getId()); - } - @Test - public void updatingToANewValueShouldAlsoUpdateTheIndex() { - UniqueClub club = uniqueClubRepository.save(new UniqueClub("foo")); - assertEquals(1, uniqueClubRepository.count()); - assertEquals(club.getId(),uniqueClubRepository.findByPropertyValue("name","foo").getId()); - club.setName("bar"); - uniqueClubRepository.save(club); - assertEquals(club.getId(),uniqueClubRepository.findByPropertyValue("name","bar").getId()); - } -} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonClub.java new file mode 100644 index 000000000..388ea9ef0 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonClub.java @@ -0,0 +1,25 @@ +/** + * Copyright 2014 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.unique.common; + +public interface CommonClub { + + public Long getId(); + + public String getName(); + + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueClub.java new file mode 100644 index 000000000..2c4c8e7e0 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueClub.java @@ -0,0 +1,28 @@ +/** + * Copyright 2014 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.unique.common; + +public interface CommonUniqueClub { + + public Long getId(); + + public String getName(); + + public void setName(String name); + + public String getDescription(); + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueEntityTestBase.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueEntityTestBase.java new file mode 100644 index 000000000..7611c64a3 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueEntityTestBase.java @@ -0,0 +1,181 @@ +/** + * Copyright 2014 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.unique.common; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.neo4j.graphdb.Transaction; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.schemabased.domain.Club; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueClub; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueNumericIdClub; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +public abstract class CommonUniqueEntityTestBase { + + @Before + public void setup() { + clearDownAllRepositories(); + } + + @Test + public void shouldOnlyCreateSingleInstanceForUniqueNodeEntity() { + CommonUniqueClub club1 = createUniqueClub("foo", null); + CommonUniqueClub club2 = createUniqueClub("foo", null); + CommonUniqueClub club3 = createUniqueClub("foo", null); + + assertEquals(1, getUniqueClubRepository().count()); + assertEquals("Expected same node Ids", club1.getId(),club2.getId()); + } + + @Test + public void shouldMergeNewUniqueNodeEntityDataWithExistingDataWhenSaving() { + CommonUniqueClub club1 = createUniqueClub("bar", "description-1"); + CommonUniqueClub club2 = createUniqueClub("bar", "description-2"); + assertEquals(1, getUniqueClubRepository().count()); + assertEquals("Expected same node Ids", club1.getId(),club2.getId()); + CommonUniqueClub retrievedClub = (CommonUniqueClub)getUniqueClubRepository().findOne(club1.getId()); + assertEquals("Description not merged as expected", + "description-2", retrievedClub.getDescription()); + } + + @Test(expected = MappingException.class) + public void shouldFailOnNullPropertyValue() { + createUniqueClub(null, null); + } + + @Test(expected = MappingException.class) + public void shouldFailOnNullNumericPropertyValue() { + createUniqueNumericClub(null); + } + + @Test + public void shouldOnlyCreateSingleInstanceForUniqueNumericNodeEntity() { + CommonUniqueNumericIdClub club1 = createUniqueNumericClub(100L); + CommonUniqueNumericIdClub club2 = createUniqueNumericClub(100L); + assertEquals(1, getUniqueNumericIdClubRepository().count()); + assertEquals("Expected same node Ids", club1.getId(),club2.getId()); + } + + @Test + public void shouldCreateMultipleInstancesForNonUniqueNodeEntity() { + CommonClub club1 = createNonUniqueClub("foo"); + CommonClub club2 = createNonUniqueClub("foo"); + assertEquals(2, getClubRepository().count()); + assertNotEquals("Expected different node Ids", club1.getId(), club2.getId()); + } + + @Test + public void deletingUniqueNodeShouldRemoveItFromTheUniqueIndex() { + CommonUniqueClub club1 = createUniqueClub("foo", null); + assertEquals("Expected one unique entity",1, getUniqueClubRepository().count()); + getUniqueClubRepository().delete(club1); + assertEquals("Expected zero unique entities",0, getUniqueClubRepository().count()); + } + + @Test(expected = DataIntegrityViolationException.class) + public void updatingToADuplicateValueShouldCauseAnException() { + CommonUniqueClub club1 = createUniqueClub("foo", "foo description"); + CommonUniqueClub club2 = createUniqueClub("bar", "bar description"); + assertEquals(2, getUniqueClubRepository().count()); + assertNotEquals("Expected different node Ids", club1.getId(), club2.getId()); + club2.setName("foo"); + getUniqueClubRepository().save(club2); + } + + @Test + public void updatingToANewValueShouldAlsoUpdateTheIndex() { + CommonUniqueClub club1 = createUniqueClub("foo", "foo description"); + assertEquals(1, getUniqueClubRepository().count()); + CommonUniqueClub fooClub = lookupEntityByUniquePropertyValue("name", "foo"); + assertNotNull(fooClub); + assertEquals(club1.getId(),fooClub.getId()); + + club1.setName("bar"); + getUniqueClubRepository().save(club1); + assertEquals(1, getUniqueClubRepository().count()); + CommonUniqueClub currentClub = lookupEntityByUniquePropertyValue("name", "bar"); + assertNotNull(currentClub); + assertEquals(club1.getId(),currentClub.getId()); + + // We should not find "foo" now + CommonUniqueClub redundantClub = lookupEntityByUniquePropertyValue("name", "foo"); + assertNull(redundantClub); + + } + + @Test + public void updatingToANewValueShouldKeepTheEntityUnique() { + + CommonUniqueClub club1 = createUniqueClub("foo", "foo description"); + assertEquals(1, getUniqueClubRepository().count()); + CommonUniqueClub fooClub = lookupEntityByUniquePropertyValue("name", "foo"); + assertNotNull(fooClub); + assertEquals(club1.getId(),fooClub.getId()); + + club1.setName("bar"); + getUniqueClubRepository().save(club1); + assertEquals(1, getUniqueClubRepository().count()); + CommonUniqueClub currentClub = lookupEntityByUniquePropertyValue("name", "bar"); + assertNotNull(currentClub); + assertEquals(club1.getId(),currentClub.getId()); + + // We should not find "foo" now + CommonUniqueClub redundantClub = lookupEntityByUniquePropertyValue("name", "foo"); + assertNull(redundantClub); + } + + @Ignore("This scenario does not work, could be transactional issues") + @Test + public void updatingToANewValueShouldKeepTheEntityUniqueAndOldValueShouldBeReusableThereafter() { + + updatingToANewValueShouldAlsoUpdateTheIndex(); + + // At this stage we should find "bar" but not "foo" + CommonUniqueClub currentClub = (CommonUniqueClub)getUniqueClubRepository().findBySchemaPropertyValue("name", "bar"); + assertNotNull(currentClub); + CommonUniqueClub redundantClub = (CommonUniqueClub)getUniqueClubRepository().findBySchemaPropertyValue("name", "foo"); + assertNull(redundantClub); + + CommonUniqueClub fooReusingClub = createUniqueClub("foo", "foo description"); + assertNotEquals("A new id should have been created for re-use of foo but it was not!",currentClub.getId(),fooReusingClub.getId()); + assertEquals(2, getUniqueClubRepository().count()); + + } + + protected abstract CommonUniqueClub lookupEntityByUniquePropertyValue(String propertyName, Object value); + + protected abstract void clearDownAllRepositories(); + + protected abstract CommonUniqueClub createUniqueClub(String name, String description); + + protected abstract CommonUniqueNumericIdClub createUniqueNumericClub(Long clubId); + + protected abstract CommonClub createNonUniqueClub(String name); + + protected abstract GraphRepository getUniqueNumericIdClubRepository(); + + protected abstract GraphRepository getUniqueClubRepository(); + + protected abstract GraphRepository getClubRepository(); + + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueNumericIdClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueNumericIdClub.java new file mode 100644 index 000000000..53b0564c1 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/common/CommonUniqueNumericIdClub.java @@ -0,0 +1,24 @@ +/** + * Copyright 2014 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.unique.common; + +public interface CommonUniqueNumericIdClub { + + public Long getId(); + + public Long getClubId(); + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueLegacyIndexBasedEntityTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueLegacyIndexBasedEntityTests.java new file mode 100644 index 000000000..1004c1748 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueLegacyIndexBasedEntityTests.java @@ -0,0 +1,126 @@ +/** + * 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.unique.legacy; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.neo4j.graphdb.GraphDatabaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.common.CommonClub; +import org.springframework.data.neo4j.unique.common.CommonUniqueClub; +import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase; +import org.springframework.data.neo4j.unique.common.CommonUniqueNumericIdClub; +import org.springframework.data.neo4j.unique.legacy.domain.Club; +import org.springframework.data.neo4j.unique.legacy.domain.UniqueClub; +import org.springframework.data.neo4j.unique.legacy.domain.UniqueNumericIdClub; +import org.springframework.data.neo4j.unique.legacy.repository.ClubRepository; +import org.springframework.data.neo4j.unique.legacy.repository.UniqueClubRepository; +import org.springframework.data.neo4j.unique.legacy.repository.UniqueNumericIdClubRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"classpath:unique-legacy-test-context.xml"}) +@Transactional +public class UniqueLegacyIndexBasedEntityTests extends CommonUniqueEntityTestBase { + + @Autowired + private ClubRepository clubRepository; + + @Autowired + private UniqueClubRepository uniqueClubRepository; + + @Autowired + protected GraphDatabaseService graphDatabaseService; + + @Autowired + private UniqueNumericIdClubRepository uniqueNumericIdClubRepository; + + @Before + public void setup() { + super.setup(); + } + + @Override + protected void clearDownAllRepositories() { + uniqueClubRepository.deleteAll(); + clubRepository.deleteAll(); + uniqueClubRepository.deleteAll(); + } + + @Override + @Test(expected = DataIntegrityViolationException.class) + @Ignore("This method now throws a DataIntegrityViolationException for legacy indexes" + + " - verify if this is correct") + public void shouldOnlyCreateSingleInstanceForUniqueNumericNodeEntity() { + CommonUniqueNumericIdClub club1 = createUniqueNumericClub(100L); + CommonUniqueNumericIdClub club2 = createUniqueNumericClub(100L); + assertEquals(1, getUniqueNumericIdClubRepository().count()); + assertEquals("Expected same node Ids", club1.getId(),club2.getId()); + } + + @Override + protected CommonClub createNonUniqueClub(String name) { + Club club = new Club(); + club.setName(name); + clubRepository.save(club); + return club; + } + + @Override + protected CommonUniqueClub createUniqueClub(String name, String description) { + UniqueClub club = new UniqueClub(); + club.setName(name); + club.setDescription(description); + uniqueClubRepository.save(club); + return club; } + + @Override + protected CommonUniqueNumericIdClub createUniqueNumericClub(Long clubId) { + UniqueNumericIdClub club = new UniqueNumericIdClub(); + club.setClubId(clubId); + uniqueNumericIdClubRepository.save(club); + return club; + } + + @Override + protected CommonUniqueClub lookupEntityByUniquePropertyValue(String propertyName, Object value) { + return (CommonUniqueClub)getUniqueClubRepository().findByPropertyValue(propertyName, value); + } + + @Override + protected GraphRepository getUniqueNumericIdClubRepository() { + return uniqueNumericIdClubRepository; + } + + @Override + protected GraphRepository getUniqueClubRepository() { + return uniqueClubRepository; + } + + @Override + protected GraphRepository getClubRepository() { + return clubRepository; + } + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueRelationshipTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueRelationshipTests.java similarity index 98% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueRelationshipTests.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueRelationshipTests.java index 3ae48315d..438dbab19 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/UniqueRelationshipTests.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/UniqueRelationshipTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique; +package org.springframework.data.neo4j.unique.legacy; import org.junit.Test; import org.neo4j.graphdb.*; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/Club.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/Club.java similarity index 81% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/Club.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/Club.java index 246ff8902..33a12d2e5 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/Club.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/Club.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.domain; +package org.springframework.data.neo4j.unique.legacy.domain; import org.springframework.data.neo4j.annotation.GraphId; import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.unique.common.CommonClub; @NodeEntity -public class Club { +public class Club implements CommonClub { private String name; @@ -33,4 +34,8 @@ public class Club { public void setName(String name) { this.name = name; } + + public Long getId() { + return id; + } } \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueClub.java new file mode 100644 index 000000000..4a1c6604f --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueClub.java @@ -0,0 +1,66 @@ +/** + * 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.unique.legacy.domain; + +import org.springframework.data.neo4j.annotation.GraphId; +import org.springframework.data.neo4j.annotation.Indexed; +import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.support.index.IndexType; +import org.springframework.data.neo4j.unique.common.CommonUniqueClub; + +@NodeEntity +public class UniqueClub implements CommonUniqueClub { + + @Indexed(unique = true,indexType = IndexType.SIMPLE) + private String name; + + private String description; + + @GraphId + Long id; + + public UniqueClub() { + } + + public UniqueClub(String name) { + this.name = name; + } + + public UniqueClub(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueNumericIdClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueNumericIdClub.java similarity index 77% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueNumericIdClub.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueNumericIdClub.java index 55f27d6e8..7def2e951 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueNumericIdClub.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/domain/UniqueNumericIdClub.java @@ -13,16 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.domain; +package org.springframework.data.neo4j.unique.legacy.domain; import org.springframework.data.neo4j.annotation.GraphId; import org.springframework.data.neo4j.annotation.Indexed; import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.support.index.IndexType; +import org.springframework.data.neo4j.unique.common.CommonUniqueNumericIdClub; @NodeEntity -public class UniqueNumericIdClub { +public class UniqueNumericIdClub implements CommonUniqueNumericIdClub { - @Indexed(unique = true) + @Indexed(unique = true, indexType = IndexType.SIMPLE) private Long clubId; @GraphId diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/ClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/ClubRepository.java similarity index 86% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/ClubRepository.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/ClubRepository.java index b817b6c9d..5d4e14298 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/ClubRepository.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/ClubRepository.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.repository; +package org.springframework.data.neo4j.unique.legacy.repository; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.neo4j.repository.NamedIndexRepository; -import org.springframework.data.neo4j.unique.domain.Club; +import org.springframework.data.neo4j.unique.legacy.domain.Club; public interface ClubRepository extends GraphRepository, NamedIndexRepository { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueClubRepository.java similarity index 81% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueClubRepository.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueClubRepository.java index e605e2650..99e65af96 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueClubRepository.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueClubRepository.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.repository; +package org.springframework.data.neo4j.unique.legacy.repository; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.neo4j.repository.NamedIndexRepository; -import org.springframework.data.neo4j.unique.domain.Club; -import org.springframework.data.neo4j.unique.domain.UniqueClub; +import org.springframework.data.neo4j.unique.legacy.domain.Club; +import org.springframework.data.neo4j.unique.legacy.domain.UniqueClub; public interface UniqueClubRepository extends GraphRepository, NamedIndexRepository { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueNumericIdClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueNumericIdClubRepository.java similarity index 77% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueNumericIdClubRepository.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueNumericIdClubRepository.java index bedf0b698..c7fad1e0f 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/repository/UniqueNumericIdClubRepository.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/legacy/repository/UniqueNumericIdClubRepository.java @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.repository; +package org.springframework.data.neo4j.unique.legacy.repository; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.neo4j.repository.NamedIndexRepository; -import org.springframework.data.neo4j.unique.domain.Club; -import org.springframework.data.neo4j.unique.domain.UniqueClub; -import org.springframework.data.neo4j.unique.domain.UniqueNumericIdClub; +import org.springframework.data.neo4j.unique.legacy.domain.UniqueNumericIdClub; public interface UniqueNumericIdClubRepository extends GraphRepository, NamedIndexRepository { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/UniqueSchemaBasedEntityTests.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/UniqueSchemaBasedEntityTests.java new file mode 100644 index 000000000..9f4c6c908 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/UniqueSchemaBasedEntityTests.java @@ -0,0 +1,122 @@ +/** + * 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.unique.schemabased; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.neo4j.graphdb.GraphDatabaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.common.CommonClub; +import org.springframework.data.neo4j.unique.common.CommonUniqueClub; +import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase; +import org.springframework.data.neo4j.unique.common.CommonUniqueNumericIdClub; +import org.springframework.data.neo4j.unique.schemabased.domain.Club; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueClub; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueNumericIdClub; +import org.springframework.data.neo4j.unique.schemabased.repository.ClubRepository; +import org.springframework.data.neo4j.unique.schemabased.repository.UniqueClubRepository; +import org.springframework.data.neo4j.unique.schemabased.repository.UniqueNumericIdClubRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"classpath:unique-schema-test-context.xml"}) +@Transactional +public class UniqueSchemaBasedEntityTests extends CommonUniqueEntityTestBase { + + @Autowired + private ClubRepository clubRepository; + + @Autowired + private UniqueClubRepository uniqueClubRepository; + + @Autowired + private UniqueNumericIdClubRepository uniqueNumericIdClubRepository; + + @Autowired + protected GraphDatabaseService graphDatabaseService; + + @Before + public void setup() { + super.setup(); + } + + @Override + protected void clearDownAllRepositories() { + uniqueClubRepository.deleteAll(); + clubRepository.deleteAll(); + uniqueNumericIdClubRepository.deleteAll(); + } + + @Override + @Ignore("This scenario does not currently work") + @Test + public void updatingToANewValueShouldKeepTheEntityUniqueAndOldValueShouldBeReusableThereafter() { + super.updatingToANewValueShouldKeepTheEntityUniqueAndOldValueShouldBeReusableThereafter(); + } + + @Override + protected CommonUniqueClub lookupEntityByUniquePropertyValue(String propertyName, Object value) { + return (CommonUniqueClub)getUniqueClubRepository().findBySchemaPropertyValue(propertyName, value); + } + + @Override + protected CommonClub createNonUniqueClub(String name) { + Club club = new Club(); + club.setName(name); + clubRepository.save(club); + return club; + } + + @Override + protected CommonUniqueClub createUniqueClub(String name, String description) { + UniqueClub club = new UniqueClub(); + club.setName(name); + club.setDescription(description); + uniqueClubRepository.save(club); + return club; } + + @Override + protected CommonUniqueNumericIdClub createUniqueNumericClub(Long clubId) { + UniqueNumericIdClub club = new UniqueNumericIdClub(); + club.setClubId(clubId); + uniqueNumericIdClubRepository.save(club); + return club; + } + + @Override + protected GraphRepository getUniqueNumericIdClubRepository() { + return uniqueNumericIdClubRepository; + } + + @Override + protected GraphRepository getUniqueClubRepository() { + return uniqueClubRepository; + } + + @Override + protected GraphRepository getClubRepository() { + return clubRepository; + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/Club.java similarity index 73% rename from spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueClub.java rename to spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/Club.java index e08f9f46f..04f8b8539 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/domain/UniqueClub.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/Club.java @@ -13,29 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.neo4j.unique.domain; +package org.springframework.data.neo4j.unique.schemabased.domain; import org.springframework.data.neo4j.annotation.GraphId; -import org.springframework.data.neo4j.annotation.Indexed; import org.springframework.data.neo4j.annotation.NodeEntity; -import org.springframework.data.neo4j.support.index.IndexType; +import org.springframework.data.neo4j.unique.common.CommonClub; @NodeEntity -public class UniqueClub { +public class Club implements CommonClub { - @Indexed(unique = true,indexType = IndexType.SIMPLE) private String name; @GraphId Long id; - public UniqueClub() { - } - - public UniqueClub(String name) { - this.name = name; - } - public String getName() { return name; } @@ -47,4 +38,4 @@ public class UniqueClub { public Long getId() { return id; } -} +} \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueClub.java new file mode 100644 index 000000000..49657a2a8 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueClub.java @@ -0,0 +1,61 @@ +/** + * 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.unique.schemabased.domain; + +import org.springframework.data.neo4j.annotation.GraphId; +import org.springframework.data.neo4j.annotation.Indexed; +import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.support.index.IndexType; +import org.springframework.data.neo4j.unique.common.CommonUniqueClub; + +@NodeEntity +public class UniqueClub implements CommonUniqueClub { + + @Indexed(unique = true,indexType = IndexType.LABEL) + private String name; + + private String description; + + @GraphId + Long id; + + public UniqueClub() { + } + + public UniqueClub(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueNumericIdClub.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueNumericIdClub.java new file mode 100644 index 000000000..43e71f176 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/domain/UniqueNumericIdClub.java @@ -0,0 +1,51 @@ +/** + * 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.unique.schemabased.domain; + +import org.springframework.data.neo4j.annotation.GraphId; +import org.springframework.data.neo4j.annotation.Indexed; +import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.support.index.IndexType; +import org.springframework.data.neo4j.unique.common.CommonUniqueNumericIdClub; + +@NodeEntity +public class UniqueNumericIdClub implements CommonUniqueNumericIdClub { + + @Indexed(unique = true, indexType = IndexType.LABEL) + private Long clubId; + + @GraphId + Long id; + + public UniqueNumericIdClub() { + } + + public UniqueNumericIdClub(Long clubId) { + this.clubId = clubId; + } + + public Long getClubId() { + return clubId; + } + + public void setClubId(Long clubId) { + this.clubId = clubId; + } + + public Long getId() { + return id; + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/ClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/ClubRepository.java new file mode 100644 index 000000000..bcf981063 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/ClubRepository.java @@ -0,0 +1,23 @@ +/** + * 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.unique.schemabased.repository; + +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.schemabased.domain.Club; + +public interface ClubRepository extends GraphRepository { + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueClubRepository.java new file mode 100644 index 000000000..cbcfc16c7 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueClubRepository.java @@ -0,0 +1,23 @@ +/** + * 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.unique.schemabased.repository; + +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueClub; + +public interface UniqueClubRepository extends GraphRepository { + +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueNumericIdClubRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueNumericIdClubRepository.java new file mode 100644 index 000000000..27ca92f21 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/unique/schemabased/repository/UniqueNumericIdClubRepository.java @@ -0,0 +1,23 @@ +/** + * 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.unique.schemabased.repository; + +import org.springframework.data.neo4j.repository.GraphRepository; +import org.springframework.data.neo4j.unique.schemabased.domain.UniqueNumericIdClub; + +public interface UniqueNumericIdClubRepository extends GraphRepository { + +} diff --git a/spring-data-neo4j/src/test/resources/unique-test-context.xml b/spring-data-neo4j/src/test/resources/unique-legacy-test-context.xml similarity index 94% rename from spring-data-neo4j/src/test/resources/unique-test-context.xml rename to spring-data-neo4j/src/test/resources/unique-legacy-test-context.xml index 64b40556f..9ec4af92d 100644 --- a/spring-data-neo4j/src/test/resources/unique-test-context.xml +++ b/spring-data-neo4j/src/test/resources/unique-legacy-test-context.xml @@ -13,12 +13,12 @@ - + - + diff --git a/spring-data-neo4j/src/test/resources/unique-schema-test-context.xml b/spring-data-neo4j/src/test/resources/unique-schema-test-context.xml new file mode 100644 index 000000000..562ecc5a4 --- /dev/null +++ b/spring-data-neo4j/src/test/resources/unique-schema-test-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + +