DATAGRAPH-433: Begin fixing of how uniquely indexed properties are handled

This commit is contained in:
Nicki Watt
2014-03-03 03:13:42 +00:00
committed by Michael Hunger
parent 48ab04c3da
commit 36c951e55d
32 changed files with 1063 additions and 213 deletions

View File

@@ -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 {

View File

@@ -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),

View File

@@ -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);
}
}
}

View File

@@ -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<S extends Proper
@Override
public void valueChanged(Object entity, Object oldVal, Object newVal) {
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);
}
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 ....
final PropertyContainer state = template.getPersistentState(entity);
if (state instanceof Node) {
Node node = (Node) state;
StoredEntityType set = template.getStoredEntityType(entity);
if (set != null) {
applyMissingSchemaIndexLabels(node, set);
}
StoredEntityType set = template.getStoredEntityType(entity);
if (set != null) {
applyMissingSchemaIndexLabels(state, set);
}
}

View File

@@ -18,20 +18,29 @@ package org.springframework.data.neo4j.repository;
import org.neo4j.cypherdsl.grammar.Execute;
import org.neo4j.cypherdsl.grammar.Skip;
import org.neo4j.cypherdsl.querydsl.CypherQueryDSL;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.ReadableIndex;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.helpers.collection.MapUtil;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.EndResult;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.repository.query.CypherQuery;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.support.index.IndexType;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
@@ -47,7 +56,8 @@ import static org.neo4j.helpers.collection.MapUtil.map;
* @param <S> Type of backing state, either Node or Relationship
*/
@Transactional(readOnly = true)
public abstract class AbstractGraphRepository<S extends PropertyContainer, T> implements GraphRepository<T>, NamedIndexRepository<T>, SpatialRepository<T>, CypherDslRepository<T> {
public abstract class AbstractGraphRepository<S extends PropertyContainer, T> implements
GraphRepository<T>, NamedIndexRepository<T>, SpatialRepository<T>, CypherDslRepository<T> {
private final LegacyIndexSearcher<S,T> legacyIndexSearcher;
/*
@@ -237,6 +247,43 @@ public abstract class AbstractGraphRepository<S extends PropertyContainer, T> 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<T> 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<String,Object> params = new HashMap<String,Object>();
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

View File

@@ -24,5 +24,5 @@ import org.springframework.data.repository.NoRepositoryBean;
* @since 12.01.11
*/
@NoRepositoryBean
public interface GraphRepository<T> extends CRUDRepository<T>, IndexRepository<T>, TraversalRepository<T> {
public interface GraphRepository<T> extends CRUDRepository<T>, IndexRepository<T>, SchemaIndexRepository<T>, TraversalRepository<T> {
}

View File

@@ -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<T> {
@Transactional
T findBySchemaPropertyValue(String property, Object value);
@Transactional
EndResult<T> findAllBySchemaPropertyValue(String property, Object value);
}

View File

@@ -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 <S extends PropertyContainer, T> Index<S> getIndex(Class<T> 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 <T> the entity
* @return the unique entity of type entityClass (if it exists) otherwise returns null.
*
*/
public <T> T findUniqueEntity(final Class<T> 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);
}

View File

@@ -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;

View File

@@ -282,7 +282,6 @@ public class GraphRepositoryTests {
}
@Test @Transactional
// @Ignore("cypher bug with escaped params")
public void testFindWithMultipleParameters() {
final int limit = 2;
Iterable<Person> teamMembers = personRepository.findSomeTeamMembers(testTeam.sdg.getName(), 0, limit);

View File

@@ -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());
}
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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.*;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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<Club>, NamedIndexRepository<Club> {

View File

@@ -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<UniqueClub>, NamedIndexRepository<Club> {

View File

@@ -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<UniqueNumericIdClub>, NamedIndexRepository<UniqueNumericIdClub> {

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<Club> {
}

View File

@@ -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<UniqueClub> {
}

View File

@@ -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<UniqueNumericIdClub> {
}

View File

@@ -13,12 +13,12 @@
<context:annotation-config/>
<bean class="org.springframework.data.neo4j.config.Neo4jConfiguration">
<property name="basePackage" value="org.springframework.data.neo4j.unique"/>
<property name="basePackage" value="org.springframework.data.neo4j.unique.legacy.domain"/>
</bean>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown"/>
<neo4j:repositories base-package="org.springframework.data.neo4j.unique.repository"/>
<neo4j:repositories base-package="org.springframework.data.neo4j.unique.legacy.repository"/>
</beans>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:spring-configured/>
<context:annotation-config/>
<bean class="org.springframework.data.neo4j.config.Neo4jConfiguration">
<property name="basePackage" value="org.springframework.data.neo4j.unique.schemabased.domain"/>
</bean>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown"/>
<neo4j:repositories base-package="org.springframework.data.neo4j.unique.schemabased.repository"/>
</beans>