DATAGRAPH-214 numeric fields can be indexed non-numerically

DATAGRAPH-181 fix for creating unique entities with numeric unique fields, still needs a fix in Neo4j
This commit is contained in:
Michael Hunger
2012-03-25 04:15:00 +02:00
parent b6cd024b19
commit 35b3d4da86
10 changed files with 146 additions and 8 deletions

View File

@@ -89,6 +89,9 @@ public class Group {
private String indexLevelName;
private String[] roleNames;
@Indexed(numeric = false)
private Byte secret;
public Date getCreationDate() {
return creationDate;
}
@@ -285,4 +288,12 @@ public class Group {
public void setMentorship(Mentorship mentorship) {
this.mentorship = mentorship;
}
public Byte getSecret() {
return secret;
}
public void setSecret(Byte secret) {
this.secret = secret;
}
}

View File

@@ -21,6 +21,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
@@ -265,6 +266,22 @@ public class IndexTest extends EntityTestBase {
assertEquals(new HashSet<Group>(Arrays.asList(group, group2)), result);
}
@Test
@Transactional
public void testFindAllGroupsByNonNumericIndexedNumber() {
final Group group = new Group();
final byte value = (byte) 100;
group.setSecret(value);
groupRepository.save(group);
final PropertyContainer node = neo4jTemplate.getPersistentState(group);
final Iterable<Group> found = this.groupRepository.findAllByPropertyValue("secret", value);
assertEquals(1, IteratorUtil.count(found));
final Node foundWithTemplate = neo4jTemplate.lookup("Group","secret", value).to(Node.class).singleOrNull();
assertEquals(node, foundWithTemplate);
final Node foundGroup = neo4jTemplate.getGraphDatabaseService().index().forNodes("Group").get("secret", value).getSingle();
assertEquals(node, foundGroup);
}
@Test
@Transactional
public void shouldFindGroupyByQueryString() {

View File

@@ -41,6 +41,8 @@ public @interface Indexed {
boolean unique() default false;
boolean numeric() default true;
// FQN is a fix for javac compiler bug http://bugs.sun.com/view_bug.do?bug_id=6512707
org.springframework.data.neo4j.annotation.Indexed.Level level() default org.springframework.data.neo4j.annotation.Indexed.Level.CLASS;

View File

@@ -75,7 +75,7 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
@Override
public void valueChanged(Object entity, Object oldVal, Object newVal) {
@SuppressWarnings("unchecked") Index<T> index = template.getIndex(property, entity.getClass());
if (newVal instanceof Number) newVal = ValueContext.numeric((Number) newVal);
if (newVal instanceof Number && property.getIndexInfo().isNumeric()) newVal = ValueContext.numeric((Number) newVal);
final T state = template.getPersistentState(entity);
index.remove(state, indexKey);

View File

@@ -29,6 +29,7 @@ public class IndexInfo {
private final Indexed.Level level;
private String indexKey;
private final boolean unique;
private boolean numeric;
public IndexInfo(Indexed annotation, Neo4jPersistentProperty property) {
this.indexName = determineIndexName(annotation, property);
@@ -37,6 +38,7 @@ public class IndexInfo {
this.indexKey = fieldName.isEmpty() ? property.getNeo4jPropertyName() : fieldName;
unique = annotation.unique();
level = annotation.level();
numeric = annotation.numeric();
}
@@ -66,4 +68,8 @@ public class IndexInfo {
public boolean isUnique() {
return unique;
}
public boolean isNumeric() {
return numeric;
}
}

View File

@@ -33,6 +33,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.EndResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.support.index.NoSuchIndexException;
import org.springframework.data.neo4j.support.index.NullReadableIndex;
@@ -177,12 +178,13 @@ public abstract class AbstractGraphRepository<S extends PropertyContainer, T> im
}
private IndexHits<S> getIndexHits(String indexName, String property, Object value) {
if (value instanceof Number) {
private IndexHits<S> getIndexHits(String indexName, String propertyName, Object value) {
final Neo4jPersistentProperty property = template.getPersistentProperty(clazz, propertyName);
if (value instanceof Number && (property==null || property.getIndexInfo().isNumeric())) {
Number number = (Number) value;
return getIndex(indexName, property).query(property, createInclusiveRangeQuery(property, number,number));
return getIndex(indexName, propertyName).query(propertyName, createInclusiveRangeQuery(propertyName, number,number));
}
return getIndex(indexName, property).get(property, value);
return getIndex(indexName, propertyName).get(propertyName, value);
}
protected ReadableIndex<S> getIndex(String indexName, String property) {

View File

@@ -20,6 +20,7 @@ import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.index.lucene.ValueContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
@@ -583,12 +584,19 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
@Override
public <T extends PropertyContainer> Index<T> getIndex(Class<?> indexedType, String propertyName) {
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(indexedType);
final Neo4jPersistentProperty property = persistentEntity.getPersistentProperty(propertyName);
final Neo4jPersistentProperty property = getPersistentProperty(indexedType, propertyName);
if (property==null) return getIndexProvider().getIndex(indexedType,null);
return getIndexProvider().getIndex(property, indexedType);
}
public Neo4jPersistentProperty getPersistentProperty(Class<?> type, String propertyName) {
if (type==null || propertyName==null) return null;
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(type);
final int dotIndex = propertyName.lastIndexOf(".");
if (dotIndex >-1) propertyName = propertyName.substring(dotIndex, propertyName.length());
return persistentEntity.getPersistentProperty(propertyName);
}
private IndexProvider getIndexProvider() {
return infrastructure.getIndexProvider();
}
@@ -677,9 +685,10 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
public Node createUniqueNode(Object entity) {
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entity.getClass());
final Neo4jPersistentProperty uniqueProperty = persistentEntity.getUniqueProperty();
final Object value = uniqueProperty.getValueFromEntity(entity, MappingPolicy.MAP_FIELD_DIRECT_POLICY);
Object value = uniqueProperty.getValueFromEntity(entity, MappingPolicy.MAP_FIELD_DIRECT_POLICY);
if (value==null) return createNode();
final IndexInfo indexInfo = uniqueProperty.getIndexInfo();
if (value instanceof Number && indexInfo.isNumeric()) value=ValueContext.numeric((Number)value);
return getGraphDatabase().getOrCreateNode(indexInfo.getIndexName(), indexInfo.getIndexKey(), value, Collections.<String, Object>emptyMap());
}
}

View File

@@ -25,9 +25,11 @@ import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.neo4j.unique.domain.Club;
import org.springframework.data.neo4j.unique.domain.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.unique.repository.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;
@@ -51,6 +53,9 @@ public class UniqueEntityTest {
@Autowired
protected GraphDatabaseService graphDatabaseService;
@Autowired
private UniqueNumericIdClubRepository uniqueNumericIdClubRepository;
@Before
public void setup() {
clubRepository.deleteAll();
@@ -69,6 +74,17 @@ public class UniqueEntityTest {
assertEquals(1, uniqueClubRepository.count());
}
@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
public void shouldCreateMultipleInstancesForNonUniqueNodeEntity() {

View File

@@ -0,0 +1,49 @@
/**
* 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.domain;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
@NodeEntity
public class UniqueNumericIdClub {
@Indexed(unique = true, numeric = false)
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,26 @@
/**
* 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.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;
public interface UniqueNumericIdClubRepository extends GraphRepository<UniqueNumericIdClub>, NamedIndexRepository<UniqueNumericIdClub> {
}