DATAGRAPH-388 : First stab at getting Schema Indexes (Label based) in
This commit is contained in:
committed by
Michael Hunger
parent
02e4257c68
commit
8ebcabdfb2
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* 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.aspects.support;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.DynamicLabel;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.graphdb.schema.IndexDefinition;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
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.core.NodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.index.IndexType;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.mapping.StoredEntityType;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngine;
|
||||
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Nicki Watt
|
||||
* @since 09-02-2014
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelBasedIndexedPropertyEntityTests-context.xml",
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelingTypeRepresentationStrategyOverride-context.xml"})
|
||||
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class})
|
||||
public class LabelBasedIndexedPropertyEntityTests {
|
||||
|
||||
@Autowired
|
||||
protected NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy;
|
||||
|
||||
@Autowired
|
||||
protected GraphDatabaseService graphDatabaseService;
|
||||
@Autowired
|
||||
protected Neo4jTemplate neo4jTemplate;
|
||||
@Autowired
|
||||
protected Neo4jMappingContext ctx;
|
||||
|
||||
protected QueryEngine queryEngine;
|
||||
|
||||
protected Thing thing;
|
||||
protected SubThing subThing;
|
||||
protected SubSubThing subSubThing;
|
||||
protected StoredEntityType thingType;
|
||||
protected StoredEntityType subThingType;
|
||||
protected StoredEntityType subSubThingType;
|
||||
|
||||
@Before
|
||||
public void cleanDb() {
|
||||
assertTrue("This test expects a Label Based TRS to be in place and it is not!",neo4jTemplate.isLabelBased());
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Neo4jHelper.cleanDb(neo4jTemplate);
|
||||
tx.success();
|
||||
}
|
||||
queryEngine = neo4jTemplate.queryEngineFor(QueryType.Cypher);
|
||||
|
||||
// Hangs if these are done in the same TX see
|
||||
// LabelBasedIndexedPropertyHangingEntityTests
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
createThing();
|
||||
tx.success();
|
||||
}
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
createSubThing();
|
||||
tx.success();
|
||||
}
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
createSubSubThing();
|
||||
tx.success();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaBasedPropertyIndexesExistPostCreationForBaseEntity() {
|
||||
assertOnlyValidPropertyIndexedLabelsExist(
|
||||
(String) thingType.getAlias(),
|
||||
"schemaIndexedCommonName",
|
||||
"schemaIndexedThingName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaBasedPropertyIndexesExistPostCreationForHierarchicalEntities() {
|
||||
assertOnlyValidPropertyIndexedLabelsExist(
|
||||
(String) thingType.getAlias(),
|
||||
"schemaIndexedCommonName",
|
||||
"schemaIndexedThingName");
|
||||
|
||||
assertOnlyValidPropertyIndexedLabelsExist(
|
||||
(String) subThingType.getAlias(),
|
||||
"schemaIndexedCommonName",
|
||||
"schemaIndexedThingName",
|
||||
"schemaIndexedSubThingName");
|
||||
|
||||
assertOnlyValidPropertyIndexedLabelsExist(
|
||||
(String) subSubThingType.getAlias(),
|
||||
"schemaIndexedCommonName",
|
||||
"schemaIndexedThingName",
|
||||
"schemaIndexedSubThingName",
|
||||
"schemaIndexedSubSubThingName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbleToQueryUsingSchemaIndex() {
|
||||
Collection<String> names = executeQuery("Thing","schemaIndexedThingName","thing-theSchemaIndexedThingName");
|
||||
assertThat( names , containsInAnyOrder( "thing" ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbleToQueryUsingSchemaIndexAgainstHierarchy() {
|
||||
Collection<String> names1 = executeQuery( "Thing", "schemaIndexedThingName","thing-theSchemaIndexedThingName");
|
||||
assertThat( names1 , containsInAnyOrder( "thing" ));
|
||||
|
||||
Collection<String> names2 = executeQuery( "Thing", "schemaIndexedThingName","subThing-theSchemaIndexedThingName");
|
||||
assertThat( names2 , containsInAnyOrder( "subThing" ));
|
||||
|
||||
Collection<String> names3 = executeQuery( "Thing", "schemaIndexedThingName","subSubThing-theSchemaIndexedThingName");
|
||||
assertThat( names3 , containsInAnyOrder( "subSubThing" ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbleToQueryAndFindCommonValuesUsingSchemaIndexAcrossHierarchy() {
|
||||
Collection<String> names1 = executeQuery( "Thing", "schemaIndexedCommonName","common");
|
||||
assertThat( names1 , containsInAnyOrder( "thing" ,"subThing" ,"subSubThing" ));
|
||||
|
||||
}
|
||||
|
||||
private Collection<String> executeQuery(String label, String indexedPropName, String indexedPropValue) {
|
||||
Map<String,Object> params = new HashMap<String,Object>();
|
||||
params.put("indexedPropValue",indexedPropValue);
|
||||
Result result = queryEngine.query(
|
||||
"MATCH (n:"+label+") " +
|
||||
"USING INDEX n:Thing(" + indexedPropName + ") " +
|
||||
"where n." +indexedPropName + " = {indexedPropValue}" +
|
||||
"return n.name", params);
|
||||
assertNotNull(result);
|
||||
EndResult<String> results = result.to(String.class);
|
||||
return IteratorUtil.asCollection(results.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given Label, this method will ensure that the only label index
|
||||
* definitions associated with it, are those passed in to the method,
|
||||
* throwing an Assertion error if this is not the case
|
||||
*
|
||||
* @param label
|
||||
* @param propertyNames
|
||||
*/
|
||||
private void assertOnlyValidPropertyIndexedLabelsExist(String label, String... propertyNames) {
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Iterable<IndexDefinition> idefs = graphDatabaseService.schema().getIndexes(DynamicLabel.label(label));
|
||||
Set<String> propNames2Find = new HashSet<String>();
|
||||
Set<String> extraPropNames = new HashSet<String>();
|
||||
propNames2Find.addAll( Arrays.asList(propertyNames));
|
||||
|
||||
for (IndexDefinition idef: idefs) {
|
||||
assertEquals( idef.getLabel().name() , label );
|
||||
for (String key : idef.getPropertyKeys()) {
|
||||
if (propNames2Find.contains(key))
|
||||
propNames2Find.remove(key);
|
||||
else
|
||||
extraPropNames.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// We remove all the property names we find so by this point,
|
||||
// all we are looking for should be removed
|
||||
assertThat( format("Not all properties expected to be created as schema labels found missing (%s)",propNames2Find), propNames2Find, hasSize(0));
|
||||
assertThat( format("Additional properties created as schema labels (%s) not expected",extraPropNames) , extraPropNames, hasSize(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void createThing() {
|
||||
thing = new Thing();
|
||||
thing.setName("thing");
|
||||
thing.setLegacyIndexedThingName("thing-theLegacyIndexedThingName");
|
||||
thing.setSchemaIndexedThingName("thing-theSchemaIndexedThingName");
|
||||
thing.setSchemaIndexedCommonName("common");
|
||||
neo4jTemplate.save(thing);
|
||||
|
||||
thingType = neo4jTemplate.getStoredEntityType(thing);
|
||||
}
|
||||
|
||||
protected void createSubThing() {
|
||||
subThing = new SubThing();
|
||||
subThing.setName("subThing");
|
||||
subThing.setLegacyIndexedThingName("subThing-theLegacyIndexedThingName");
|
||||
subThing.setSchemaIndexedThingName("subThing-theSchemaIndexedThingName");
|
||||
subThing.setLegacyIndexedSubThingName("subThing-theLegacyIndexedSubThingName");
|
||||
subThing.setSchemaIndexedSubThingName("subThing-theSchemaIndexedSubThingName");
|
||||
subThing.setSchemaIndexedCommonName("common");
|
||||
neo4jTemplate.save(subThing);
|
||||
|
||||
subThingType = neo4jTemplate.getStoredEntityType(subThing);
|
||||
}
|
||||
|
||||
protected void createSubSubThing() {
|
||||
subSubThing = new SubSubThing();
|
||||
subSubThing.setName("subSubThing");
|
||||
subSubThing.setLegacyIndexedThingName("subSubThing-theLegacyIndexedThingName");
|
||||
subSubThing.setSchemaIndexedThingName("subSubThing-theSchemaIndexedThingName");
|
||||
subSubThing.setLegacyIndexedSubThingName("subSubThing-theLegacyIndexedSubThingName");
|
||||
subSubThing.setSchemaIndexedSubThingName("subSubThing-theSchemaIndexedSubThingName");
|
||||
subSubThing.setLegacyIndexedSubSubThingName("subSubThing-theLegacyIndexedSubSubThingName");
|
||||
subSubThing.setSchemaIndexedSubSubThingName("subSubThing-theSchemaIndexedSubSubThingName");
|
||||
subSubThing.setSchemaIndexedCommonName("common");
|
||||
neo4jTemplate.save(subSubThing);
|
||||
|
||||
subSubThingType = neo4jTemplate.getStoredEntityType(subSubThing);
|
||||
}
|
||||
|
||||
|
||||
@NodeEntity
|
||||
public static class Thing {
|
||||
|
||||
String name;
|
||||
|
||||
@Indexed(indexType = IndexType.SIMPLE)
|
||||
String legacyIndexedThingName;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
String schemaIndexedCommonName;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
String schemaIndexedThingName;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLegacyIndexedThingName() {
|
||||
return legacyIndexedThingName;
|
||||
}
|
||||
|
||||
public void setLegacyIndexedThingName(String legacyIndexedThingName) {
|
||||
this.legacyIndexedThingName = legacyIndexedThingName;
|
||||
}
|
||||
|
||||
public String getSchemaIndexedThingName() {
|
||||
return schemaIndexedThingName;
|
||||
}
|
||||
|
||||
public void setSchemaIndexedThingName(String schemaIndexedThingName) {
|
||||
this.schemaIndexedThingName = schemaIndexedThingName;
|
||||
}
|
||||
|
||||
public String getSchemaIndexedCommonName() {
|
||||
return schemaIndexedCommonName;
|
||||
}
|
||||
|
||||
public void setSchemaIndexedCommonName(String schemaIndexedCommonName) {
|
||||
this.schemaIndexedCommonName = schemaIndexedCommonName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubThing extends Thing {
|
||||
@Indexed(indexType = IndexType.SIMPLE)
|
||||
String legacyIndexedSubThingName;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
String schemaIndexedSubThingName;
|
||||
|
||||
public String getLegacyIndexedSubThingName() {
|
||||
return legacyIndexedSubThingName;
|
||||
}
|
||||
|
||||
public void setLegacyIndexedSubThingName(String legacyIndexedSubThingName) {
|
||||
this.legacyIndexedSubThingName = legacyIndexedSubThingName;
|
||||
}
|
||||
|
||||
public String getSchemaIndexedSubThingName() {
|
||||
return schemaIndexedSubThingName;
|
||||
}
|
||||
|
||||
public void setSchemaIndexedSubThingName(String schemaIndexedSubThingName) {
|
||||
this.schemaIndexedSubThingName = schemaIndexedSubThingName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubSubThing extends SubThing {
|
||||
@Indexed(indexType = IndexType.SIMPLE)
|
||||
String legacyIndexedSubSubThingName;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
String schemaIndexedSubSubThingName;
|
||||
|
||||
public String getLegacyIndexedSubSubThingName() {
|
||||
return legacyIndexedSubSubThingName;
|
||||
}
|
||||
|
||||
public void setLegacyIndexedSubSubThingName(String legacyIndexedSubSubThingName) {
|
||||
this.legacyIndexedSubSubThingName = legacyIndexedSubSubThingName;
|
||||
}
|
||||
|
||||
public String getSchemaIndexedSubSubThingName() {
|
||||
return schemaIndexedSubSubThingName;
|
||||
}
|
||||
|
||||
public void setSchemaIndexedSubSubThingName(String schemaIndexedSubSubThingName) {
|
||||
this.schemaIndexedSubSubThingName = schemaIndexedSubSubThingName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.aspects.support;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.data.neo4j.annotation.QueryType;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* This version DOES work, only because the entities have been setup as part of the
|
||||
* initialSet for the mappingContext. Compare with the other LabelBasedIndex...Tests
|
||||
*
|
||||
* @author Nicki Watt
|
||||
* @since 09-02-2014
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelBasedIndexedPropertyEntityTests-context-with-initialset.xml",
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelingTypeRepresentationStrategyOverride-context.xml"})
|
||||
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class})
|
||||
public class LabelBasedIndexedPropertyHangingAvertedViaInitialEntitySetTests extends LabelBasedIndexedPropertyEntityTests{
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void cleanDb() {
|
||||
assertTrue("This test expects a Label Based TRS to be in place and it is not!",neo4jTemplate.isLabelBased());
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Neo4jHelper.cleanDb(neo4jTemplate);
|
||||
tx.success();
|
||||
}
|
||||
queryEngine = neo4jTemplate.queryEngineFor(QueryType.Cypher);
|
||||
|
||||
// NW-ISSUE01
|
||||
// This now works because of the initialEntitySet in mappingContext
|
||||
// see LabelBasedIndexedPropertyEntityTests-context-with-initialset.xml
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
createThing();
|
||||
createSubThing();
|
||||
createSubSubThing();
|
||||
tx.success();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.aspects.support;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.data.neo4j.annotation.QueryType;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* This test actually does not work, it hangs, however is here to demonstrate
|
||||
* some of the issues involved. Compare with the other LabelBasedIndex...Tests
|
||||
*
|
||||
* @author Nicki Watt
|
||||
* @since 09-02-2014
|
||||
*/
|
||||
@Ignore("NW-ISSUE01 - This version of the test causes deadlock situation when trying to create indexes")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelBasedIndexedPropertyEntityTests-context.xml",
|
||||
"classpath:org/springframework/data/neo4j/aspects/support/LabelingTypeRepresentationStrategyOverride-context.xml"})
|
||||
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class})
|
||||
public class LabelBasedIndexedPropertyHangingEntityTests extends LabelBasedIndexedPropertyEntityTests{
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void cleanDb() {
|
||||
assertTrue("This test expects a Label Based TRS to be in place and it is not!",neo4jTemplate.isLabelBased());
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Neo4jHelper.cleanDb(neo4jTemplate);
|
||||
tx.success();
|
||||
}
|
||||
queryEngine = neo4jTemplate.queryEngineFor(QueryType.Cypher);
|
||||
|
||||
// NW-ISSUE01
|
||||
// By doing this all in one tx, we get a Timeout exception from
|
||||
// SchemaIndexProvider.createIndexInSeparateTx ....
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
createThing();
|
||||
createSubThing();
|
||||
createSubSubThing();
|
||||
tx.success();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -25,10 +25,12 @@ import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.helpers.collection.ClosableIterable;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.aspects.support.EntityTestBase;
|
||||
import org.springframework.data.neo4j.core.NodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.index.IndexType;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.mapping.StoredEntityType;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy;
|
||||
@@ -59,7 +61,7 @@ public abstract class AbstractNodeTypeRepresentationStrategyTestBase extends Ent
|
||||
|
||||
protected Thing thing;
|
||||
protected SubThing subThing;
|
||||
protected SubThing subSubThing;
|
||||
protected SubSubThing subSubThing;
|
||||
protected StoredEntityType thingType;
|
||||
protected StoredEntityType subThingType;
|
||||
protected StoredEntityType subSubThingType;
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
<?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:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
|
||||
|
||||
<context:component-scan base-package="org.springframework.data.neo4j.aspects">
|
||||
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
|
||||
<context:exclude-filter expression="org.springframework.context.annotation.Configuration" type="annotation"/>
|
||||
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
|
||||
</context:component-scan>
|
||||
|
||||
|
||||
<bean id="neo4jNodeBacking" class="org.springframework.data.neo4j.aspects.support.node.Neo4jNodeBacking" factory-method="aspectOf">
|
||||
<property name="template" ref="template"/>
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.data.neo4j.aspects.support.relationship.Neo4jRelationshipBacking" factory-method="aspectOf">
|
||||
<property name="template" ref="template"/>
|
||||
<property name="relationshipEntityStateFactory" ref="relationshipEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown" scope="singleton"/>
|
||||
|
||||
<bean id="conversionService" class="org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
|
||||
<bean id="indexCreationMappingEventListener" class="org.springframework.data.neo4j.support.mapping.IndexCreationMappingEventListener">
|
||||
<constructor-arg ref="indexProvider" />
|
||||
<constructor-arg ref="schemaIndexProvider" />
|
||||
<constructor-arg ref="nodeTypeRepresentationStrategy" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="mappingInfrastructure" class="org.springframework.data.neo4j.support.MappingInfrastructureFactoryBean">
|
||||
<property name="graphDatabaseService" ref="graphDatabaseService"/>
|
||||
<property name="conversionService" ref="conversionService"/>
|
||||
<property name="mappingContext" ref="mappingContext"/>
|
||||
<property name="entityStateHandler" ref="entityStateHandler"/>
|
||||
|
||||
<property name="nodeTypeRepresentationStrategy" ref="nodeTypeRepresentationStrategy"/>
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
<property name="nodeEntityInstantiator" ref="graphEntityInstantiator"/>
|
||||
|
||||
<property name="relationshipTypeRepresentationStrategy" ref="relationshipTypeRepresentationStrategy"/>
|
||||
<property name="relationshipEntityStateFactory" ref="relationshipEntityStateFactory"/>
|
||||
<property name="relationshipEntityInstantiator" ref="relationshipEntityInstantiator"/>
|
||||
<property name="validator">
|
||||
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="template" class="org.springframework.data.neo4j.support.Neo4jTemplate">
|
||||
<constructor-arg name="infrastructure" ref="mappingInfrastructure"/>
|
||||
</bean>
|
||||
|
||||
<bean id="indexProvider" class="org.springframework.data.neo4j.support.index.IndexProviderImpl">
|
||||
<constructor-arg ref="graphDatabase" />
|
||||
</bean>
|
||||
<bean id="schemaIndexProvider" class="org.springframework.data.neo4j.support.schema.SchemaIndexProvider">
|
||||
<constructor-arg ref="graphDatabase" />
|
||||
</bean>
|
||||
|
||||
<bean id="entityStateHandler" class="org.springframework.data.neo4j.support.mapping.EntityStateHandler">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
</bean>
|
||||
<bean id="graphDatabase" class="org.springframework.data.neo4j.support.DelegatingGraphDatabase">
|
||||
<constructor-arg ref="graphDatabaseService"/>
|
||||
</bean>
|
||||
<bean id="relationshipEntityInstantiator" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator">
|
||||
<constructor-arg ref="entityStateHandler"/>
|
||||
</bean>
|
||||
|
||||
<bean id="graphEntityInstantiator" class="org.springframework.data.neo4j.support.node.NodeEntityInstantiator">
|
||||
<constructor-arg ref="entityStateHandler"/>
|
||||
</bean>
|
||||
|
||||
<bean id="typeRepresentationStrategyFactory" class="org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory">
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getNodeTypeRepresentationStrategy" />
|
||||
<bean id="relationshipTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getRelationshipTypeRepresentationStrategy"/>
|
||||
|
||||
<bean id="nodeEntityStateFactory" class="org.springframework.data.neo4j.support.node.NodeEntityStateFactory">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory$Factory"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="mappingContext" class="org.springframework.data.neo4j.support.mapping.Neo4jMappingContext" >
|
||||
|
||||
<!-- NW-ISSUE01 Possibility for getting around some of the schema vs data tx issues
|
||||
is to set the initialEntitySet upfront, however its a pain to do this
|
||||
manually would probably be better if we could detect all the entities
|
||||
at startup rather than requiring them to be explicitly set here ... -->
|
||||
<property name="initialEntitySet" >
|
||||
<set>
|
||||
<value>org.springframework.data.neo4j.aspects.support.LabelBasedIndexedPropertyEntityTests.Thing</value>
|
||||
<value>org.springframework.data.neo4j.aspects.support.LabelBasedIndexedPropertyEntityTests.SubThing</value>
|
||||
<value>org.springframework.data.neo4j.aspects.support.LabelBasedIndexedPropertyEntityTests.SubSubThing</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="relationshipEntityStateFactory" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory$Factory"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.data.neo4j.config.JtaTransactionManagerFactoryBean">
|
||||
<constructor-arg ref="graphDatabaseService"/>
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
|
||||
|
||||
|
||||
|
||||
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
|
||||
|
||||
<!-- Adds dependency checks for setters annotated with @Required -->
|
||||
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
|
||||
|
||||
<bean class="org.springframework.data.neo4j.support.Neo4jExceptionTranslator"/>
|
||||
</beans>
|
||||
@@ -0,0 +1,134 @@
|
||||
<?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:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
|
||||
|
||||
<context:component-scan base-package="org.springframework.data.neo4j.aspects">
|
||||
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
|
||||
<context:exclude-filter expression="org.springframework.context.annotation.Configuration" type="annotation"/>
|
||||
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
|
||||
</context:component-scan>
|
||||
|
||||
|
||||
<bean id="neo4jNodeBacking" class="org.springframework.data.neo4j.aspects.support.node.Neo4jNodeBacking" factory-method="aspectOf">
|
||||
<property name="template" ref="template"/>
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.data.neo4j.aspects.support.relationship.Neo4jRelationshipBacking" factory-method="aspectOf">
|
||||
<property name="template" ref="template"/>
|
||||
<property name="relationshipEntityStateFactory" ref="relationshipEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown" scope="singleton"/>
|
||||
|
||||
<bean id="conversionService" class="org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
|
||||
<bean id="indexCreationMappingEventListener" class="org.springframework.data.neo4j.support.mapping.IndexCreationMappingEventListener">
|
||||
<constructor-arg ref="indexProvider" />
|
||||
<constructor-arg ref="schemaIndexProvider" />
|
||||
<constructor-arg ref="nodeTypeRepresentationStrategy" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="mappingInfrastructure" class="org.springframework.data.neo4j.support.MappingInfrastructureFactoryBean">
|
||||
<property name="graphDatabaseService" ref="graphDatabaseService"/>
|
||||
<property name="conversionService" ref="conversionService"/>
|
||||
<property name="mappingContext" ref="mappingContext"/>
|
||||
<property name="entityStateHandler" ref="entityStateHandler"/>
|
||||
|
||||
<property name="nodeTypeRepresentationStrategy" ref="nodeTypeRepresentationStrategy"/>
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
<property name="nodeEntityInstantiator" ref="graphEntityInstantiator"/>
|
||||
|
||||
<property name="relationshipTypeRepresentationStrategy" ref="relationshipTypeRepresentationStrategy"/>
|
||||
<property name="relationshipEntityStateFactory" ref="relationshipEntityStateFactory"/>
|
||||
<property name="relationshipEntityInstantiator" ref="relationshipEntityInstantiator"/>
|
||||
<property name="validator">
|
||||
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="template" class="org.springframework.data.neo4j.support.Neo4jTemplate">
|
||||
<constructor-arg name="infrastructure" ref="mappingInfrastructure"/>
|
||||
</bean>
|
||||
|
||||
<bean id="indexProvider" class="org.springframework.data.neo4j.support.index.IndexProviderImpl">
|
||||
<constructor-arg ref="graphDatabase" />
|
||||
</bean>
|
||||
<bean id="schemaIndexProvider" class="org.springframework.data.neo4j.support.schema.SchemaIndexProvider">
|
||||
<constructor-arg ref="graphDatabase" />
|
||||
</bean>
|
||||
|
||||
<bean id="entityStateHandler" class="org.springframework.data.neo4j.support.mapping.EntityStateHandler">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
</bean>
|
||||
<bean id="graphDatabase" class="org.springframework.data.neo4j.support.DelegatingGraphDatabase">
|
||||
<constructor-arg ref="graphDatabaseService"/>
|
||||
</bean>
|
||||
<bean id="relationshipEntityInstantiator" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator">
|
||||
<constructor-arg ref="entityStateHandler"/>
|
||||
</bean>
|
||||
|
||||
<bean id="graphEntityInstantiator" class="org.springframework.data.neo4j.support.node.NodeEntityInstantiator">
|
||||
<constructor-arg ref="entityStateHandler"/>
|
||||
</bean>
|
||||
|
||||
<bean id="typeRepresentationStrategyFactory" class="org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory">
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getNodeTypeRepresentationStrategy" />
|
||||
<bean id="relationshipTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getRelationshipTypeRepresentationStrategy"/>
|
||||
|
||||
<bean id="nodeEntityStateFactory" class="org.springframework.data.neo4j.support.node.NodeEntityStateFactory">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory$Factory"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="mappingContext" class="org.springframework.data.neo4j.support.mapping.Neo4jMappingContext" >
|
||||
|
||||
<!-- NW-ISSUE01 Possibility for getting around some of the schema vs data tx issues
|
||||
is to set the initialEntitySet upfront, however its a pain to do this
|
||||
manually would probably be better if we could detect all the entities
|
||||
at startup rather than requiring them to be explicitly set here ... -->
|
||||
<!--property name="initialEntitySet" >
|
||||
<set>
|
||||
<value>org.springframework.data.neo4j.aspects.support.typerepresentation.AbstractNodeTypeRepresentationStrategyTestBase.Thing</value>
|
||||
<value>org.springframework.data.neo4j.aspects.support.typerepresentation.AbstractNodeTypeRepresentationStrategyTestBase.SubThing</value>
|
||||
<value>org.springframework.data.neo4j.aspects.support.typerepresentation.AbstractNodeTypeRepresentationStrategyTestBase.SubSubThing</value>
|
||||
</set>
|
||||
</property-->
|
||||
</bean>
|
||||
|
||||
<bean id="relationshipEntityStateFactory" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory">
|
||||
<constructor-arg ref="mappingContext"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory$Factory"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.data.neo4j.config.JtaTransactionManagerFactoryBean">
|
||||
<constructor-arg ref="graphDatabaseService"/>
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
|
||||
|
||||
|
||||
|
||||
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
|
||||
|
||||
<!-- Adds dependency checks for setters annotated with @Required -->
|
||||
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
|
||||
|
||||
<bean class="org.springframework.data.neo4j.support.Neo4jExceptionTranslator"/>
|
||||
</beans>
|
||||
@@ -33,6 +33,7 @@
|
||||
<bean id="indexCreationMappingEventListener" class="org.springframework.data.neo4j.support.mapping.IndexCreationMappingEventListener">
|
||||
<constructor-arg ref="indexProvider" />
|
||||
<constructor-arg ref="schemaIndexProvider" />
|
||||
<constructor-arg ref="nodeTypeRepresentationStrategy" />
|
||||
</bean>
|
||||
|
||||
|
||||
|
||||
@@ -203,6 +203,8 @@ public abstract class Neo4jConfiguration {
|
||||
mappingContext.setInitialEntitySet(initialEntitySet);
|
||||
}
|
||||
mappingContext.setEntityAlias(entityAlias());
|
||||
mappingContext.setIsLabelBased(nodeTypeRepresentationStrategy().isLabelBased());
|
||||
mappingContext.setFailWhenIncompatibleLabelIndexUsage(false);
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@@ -239,7 +241,10 @@ public abstract class Neo4jConfiguration {
|
||||
|
||||
@Bean
|
||||
public IndexCreationMappingEventListener indexCreationMappingEventListener() throws Exception {
|
||||
return new IndexCreationMappingEventListener(indexProvider(),schemaIndexProvider());
|
||||
return new IndexCreationMappingEventListener(
|
||||
indexProvider(),
|
||||
schemaIndexProvider(),
|
||||
nodeTypeRepresentationStrategy());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
|
||||
|
||||
@Override
|
||||
public boolean accept(final Neo4jPersistentProperty property) {
|
||||
return isPropertyField(property) && property.isIndexed();
|
||||
return isPropertyField(property) && property.isIndexed() && !property.getIndexInfo().isLabelBased();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ public class NodeDelegatingFieldAccessorFactory extends DelegatingFieldAccessorF
|
||||
template,
|
||||
new PropertyFieldAccessorFactory(template),
|
||||
new ConvertingNodePropertyFieldAccessorFactory(template)),
|
||||
new SchemaIndexingPropertyFieldAccessorListenerFactory(
|
||||
template,
|
||||
new PropertyFieldAccessorFactory(template),
|
||||
new ConvertingNodePropertyFieldAccessorFactory(template)),
|
||||
new ValidatingNodePropertyFieldAccessorListenerFactory(template)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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.fieldaccess;
|
||||
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
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;
|
||||
|
||||
|
||||
public class SchemaIndexingPropertyFieldAccessorListenerFactory<S extends PropertyContainer, T> implements FieldAccessorListenerFactory {
|
||||
|
||||
private final PropertyFieldAccessorFactory propertyFieldAccessorFactory;
|
||||
private final ConvertingNodePropertyFieldAccessorFactory convertingNodePropertyFieldAccessorFactory;
|
||||
private final Neo4jTemplate template;
|
||||
|
||||
public SchemaIndexingPropertyFieldAccessorListenerFactory(final Neo4jTemplate template, final PropertyFieldAccessorFactory propertyFieldAccessorFactory, final ConvertingNodePropertyFieldAccessorFactory convertingNodePropertyFieldAccessorFactory) {
|
||||
this.template = template;
|
||||
this.propertyFieldAccessorFactory = propertyFieldAccessorFactory;
|
||||
this.convertingNodePropertyFieldAccessorFactory = convertingNodePropertyFieldAccessorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Neo4jPersistentProperty property) {
|
||||
return isPropertyField(property) && property.isIndexed() && property.getIndexInfo().isLabelBased();
|
||||
}
|
||||
|
||||
|
||||
private boolean isPropertyField(final Neo4jPersistentProperty property) {
|
||||
return propertyFieldAccessorFactory.accept(property) || convertingNodePropertyFieldAccessorFactory.accept(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessListener forField(Neo4jPersistentProperty property) {
|
||||
return new SchemaIndexingPropertyFieldAccessorListener(property, template);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author Nicki Watt
|
||||
* @since 09.02.2014
|
||||
*/
|
||||
public static class SchemaIndexingPropertyFieldAccessorListener<T extends PropertyContainer> implements FieldAccessListener {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(SchemaIndexingPropertyFieldAccessorListener.class);
|
||||
|
||||
private final Neo4jPersistentProperty property;
|
||||
private final Neo4jTemplate template;
|
||||
|
||||
public SchemaIndexingPropertyFieldAccessorListener(final Neo4jPersistentProperty property, Neo4jTemplate template) {
|
||||
this.property = property;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(Object entity, Object oldVal, Object newVal) {
|
||||
// Nothing to do as schema indexes are dealt with internally by Neo?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -53,14 +53,21 @@ public class IndexInfo {
|
||||
private String determineLabelIndexName(Indexed annotation, Neo4jPersistentProperty property) {
|
||||
if (!annotation.indexName().isEmpty()) throw new MappingException("No index name allowed on label based indexes");
|
||||
Neo4jPersistentEntity<?> entity = property.getOwner();
|
||||
// NW StoredEntityType not available at this stage yet ....
|
||||
// only set when entity.updateStoredType(..) called
|
||||
StoredEntityType entityType = entity.getEntityType();
|
||||
switch (annotation.level()) {
|
||||
case CLASS:
|
||||
Class<?> declaringClass = property.getField().getDeclaringClass();
|
||||
StoredEntityType classType = entityType.findByTypeClass(declaringClass);
|
||||
return classType.getAlias().toString();
|
||||
return
|
||||
(entityType != null)
|
||||
? entityType.findByTypeClass(declaringClass).getAlias().toString()
|
||||
: entity.getType().getSimpleName(); // Not right but not sure what to do here
|
||||
case INSTANCE:
|
||||
return entityType.getAlias().toString();
|
||||
return
|
||||
(entityType != null)
|
||||
? entityType.getAlias().toString()
|
||||
: entity.getType().getSimpleName(); // Not right but not sure what to do here
|
||||
case GLOBAL: throw new MappingException("No global index for label based indexes");
|
||||
}
|
||||
return entityType.getAlias().toString();
|
||||
|
||||
@@ -119,7 +119,10 @@ public class CypherQuery implements CypherQueryDefinition {
|
||||
}
|
||||
|
||||
private boolean addedStartClause(PartInfo partInfo) {
|
||||
if (!partInfo.isIndexed()) return false;
|
||||
boolean invalidStartClauseScenario1 = !partInfo.isIndexed();
|
||||
boolean invalidStartClauseScenario2 = partInfo.isIndexed() && partInfo.isLabelIndexed();
|
||||
|
||||
if (invalidStartClauseScenario1 || invalidStartClauseScenario2 ) return false;
|
||||
|
||||
ListIterator<StartClause> it = startClauses.listIterator();
|
||||
while (it.hasNext()) {
|
||||
|
||||
@@ -59,6 +59,9 @@ public class PartInfo {
|
||||
return getLeafProperty().isRelationship();
|
||||
}
|
||||
|
||||
public boolean isLabelIndexed() {
|
||||
return isIndexed() && getLeafProperty().getIndexInfo().isLabelBased();
|
||||
}
|
||||
|
||||
public boolean isIndexed() {
|
||||
return getLeafProperty().isIndexed();
|
||||
|
||||
@@ -22,17 +22,14 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.neo4j.conversion.ResultConverter;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.mapping.EntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.index.IndexProvider;
|
||||
import org.springframework.data.neo4j.support.mapping.EntityRemover;
|
||||
import org.springframework.data.neo4j.support.mapping.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
|
||||
import org.springframework.data.neo4j.support.schema.SchemaIndexProvider;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategies;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
|
||||
import org.springframework.data.neo4j.support.typesafety.TypeSafetyPolicy;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
|
||||
@@ -22,17 +22,14 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.neo4j.conversion.ResultConverter;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.mapping.EntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.index.IndexProvider;
|
||||
import org.springframework.data.neo4j.support.mapping.EntityRemover;
|
||||
import org.springframework.data.neo4j.support.mapping.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
|
||||
import org.springframework.data.neo4j.support.schema.SchemaIndexProvider;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategies;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
|
||||
import org.springframework.data.neo4j.support.typesafety.TypeSafetyPolicy;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
|
||||
@@ -102,7 +102,10 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
try {
|
||||
if (this.mappingContext == null) this.mappingContext = new Neo4jMappingContext();
|
||||
if (this.mappingContext == null) {
|
||||
this.mappingContext = new Neo4jMappingContext();
|
||||
this.mappingContext.setIsLabelBased(false);
|
||||
}
|
||||
if (this.isNewStrategyFactory == null) {
|
||||
this.isNewStrategyFactory = new MappingContextIsNewStrategyFactory(mappingContext);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.schema.SchemaIndexProvider;
|
||||
|
||||
import static org.springframework.data.neo4j.support.ParameterCheck.notNull;
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.support.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContextEvent;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.index.IndexProvider;
|
||||
@@ -31,10 +33,12 @@ import org.springframework.data.neo4j.support.schema.SchemaIndexProvider;
|
||||
public class IndexCreationMappingEventListener implements ApplicationListener<MappingContextEvent<Neo4jPersistentEntity<?>, Neo4jPersistentProperty>> {
|
||||
private IndexProvider indexProvider;
|
||||
private SchemaIndexProvider schemaIndexProvider;
|
||||
private TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy;
|
||||
|
||||
public IndexCreationMappingEventListener(IndexProvider indexProvider, SchemaIndexProvider schemaIndexProvider) {
|
||||
public IndexCreationMappingEventListener(IndexProvider indexProvider, SchemaIndexProvider schemaIndexProvider, TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy) {
|
||||
this.indexProvider = indexProvider;
|
||||
this.schemaIndexProvider = schemaIndexProvider;
|
||||
this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,14 +50,26 @@ public class IndexCreationMappingEventListener implements ApplicationListener<Ma
|
||||
|
||||
private void ensureEntityIndexes(Neo4jPersistentEntity<?> entity) {
|
||||
final Class entityType = entity.getType();
|
||||
indexProvider.getIndex(entity, null, IndexType.SIMPLE); // TODO only when TRS is non-label?
|
||||
|
||||
// TODO only when TRS is non-label? I think we prob need to do it
|
||||
// anyway as you can still mix legacy indexes with label based
|
||||
// ones???
|
||||
// Pass 1 - do schema based updates first to prevent locking
|
||||
entity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
if (!property.isIndexed()) return;
|
||||
if (property.getIndexInfo().isLabelBased()) {
|
||||
if (nodeTypeRepresentationStrategy.isLabelBased() && property.isIndexed() && property.getIndexInfo().isLabelBased()) {
|
||||
schemaIndexProvider.createIndex(property);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Pass 2 - do everything else
|
||||
indexProvider.getIndex(entity, null, IndexType.SIMPLE);
|
||||
entity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
if (property.isIndexed() && !property.getIndexInfo().isLabelBased()){
|
||||
indexProvider.getIndex(property, entityType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
package org.springframework.data.neo4j.support.mapping;
|
||||
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
@@ -34,6 +37,8 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* Neo4J specific {@link MappingContext} implementation. Simply creates {@link Neo4jPersistentEntityImpl} and
|
||||
* {@link org.springframework.data.neo4j.mapping.Neo4jPersistentProperty} instances.
|
||||
@@ -42,6 +47,31 @@ import java.util.*;
|
||||
*/
|
||||
public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentEntityImpl<?>, Neo4jPersistentProperty> {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(Neo4jMappingContext.class);
|
||||
|
||||
// By default we don't fail but rather just output a warning
|
||||
// (perhaps people have changed, or are busy changing TRS strategies
|
||||
// and are happy for properties annotated as label indexes to
|
||||
// resort to simple fields in this case ???)
|
||||
private boolean failWhenIncompatibleLabelIndexUsage = false;
|
||||
private Boolean isLabelBasedTRSInUse;
|
||||
|
||||
public Boolean getIsLabelBased() {
|
||||
return isLabelBasedTRSInUse;
|
||||
}
|
||||
|
||||
public void setIsLabelBased(Boolean labelBased) {
|
||||
isLabelBasedTRSInUse = labelBased;
|
||||
}
|
||||
|
||||
public boolean isFailWhenIncompatibleLabelIndexUsage() {
|
||||
return failWhenIncompatibleLabelIndexUsage;
|
||||
}
|
||||
|
||||
public void setFailWhenIncompatibleLabelIndexUsage(boolean failWhenIncompatibleLabelIndexUsage) {
|
||||
this.failWhenIncompatibleLabelIndexUsage = failWhenIncompatibleLabelIndexUsage;
|
||||
}
|
||||
|
||||
private final Map<Annotation, Boolean> referenceAnnotations = new IdentityHashMap<Annotation, java.lang.Boolean>();
|
||||
|
||||
protected <T> Neo4jPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
@@ -60,9 +90,29 @@ public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentE
|
||||
final Neo4jPersistentEntityImpl<?> entity = super.addPersistentEntity(typeInformation);
|
||||
Collection<Neo4jPersistentEntity<?>> superTypeEntities = addSuperTypes(entity);
|
||||
entity.updateStoredType(new StoredEntityType(entity,superTypeEntities,entityAlias));
|
||||
doAdditionalEntityVerification(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void doAdditionalEntityVerification(Neo4jPersistentEntityImpl<?> entity) {
|
||||
// NW-HACK checking if null for isLabelBasedTRSInUse, but should
|
||||
// prob just blow up??
|
||||
if (isLabelBasedTRSInUse!= null && !isLabelBasedTRSInUse) {
|
||||
entity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty persistentProperty) {
|
||||
if (persistentProperty.isIndexed() && persistentProperty.getIndexInfo().isLabelBased()) {
|
||||
if (failWhenIncompatibleLabelIndexUsage) {
|
||||
throw new RuntimeException(format("Incompatible entity definition: property %s has label based index annotation however label type representation strategy not in use",persistentProperty.getName()));
|
||||
} else {
|
||||
log.warn("Incompatible entity definition: property {} has label based index annotation however label type representation strategy not in use - will be treated as normal property", persistentProperty.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private List<Neo4jPersistentEntity<?>> addSuperTypes(Neo4jPersistentEntity<?> entity) {
|
||||
List<Neo4jPersistentEntity<?>> entities=new ArrayList<Neo4jPersistentEntity<?>>();
|
||||
final Class<?> type = entity.getType();
|
||||
|
||||
@@ -95,6 +95,9 @@ public abstract class Neo4jHelper {
|
||||
}
|
||||
|
||||
}
|
||||
for (Label label: node.getLabels()) {
|
||||
node.removeLabel(label);
|
||||
}
|
||||
}
|
||||
for (Node node : globalGraphOperations.getAllNodes()) {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.springframework.data.neo4j.support.schema;
|
||||
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.annotation.QueryType;
|
||||
import org.springframework.data.neo4j.conversion.EndResult;
|
||||
import org.springframework.data.neo4j.conversion.Result;
|
||||
@@ -9,6 +11,9 @@ import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngine;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.neo4j.helpers.collection.MapUtil.map;
|
||||
|
||||
/**
|
||||
@@ -31,7 +36,51 @@ public class SchemaIndexProvider {
|
||||
String label = indexInfo.getIndexName();
|
||||
String prop = property.getNeo4jPropertyName();
|
||||
String query = indexQuery(label, prop, indexInfo.isUnique());
|
||||
Result<Object> result = cypher.query(query, null);
|
||||
createIndexInSeparateTx(label,prop,query);
|
||||
}
|
||||
|
||||
public void createIndexInSeparateTx(final String label,final String prop, final String query) {
|
||||
/* 1) NW-ISSUE01
|
||||
If we don't do this in a separate tx we get the following
|
||||
error depending on certain circumstances .... :
|
||||
"org.neo4j.cypher.CypherExecutionException: Cannot perform
|
||||
schema updates in a transaction that has performed data updates."
|
||||
|
||||
HOWEVER, even doing this does not necessarily work in all cases as
|
||||
often it appears that there have been some previous updates in the
|
||||
original calling thread, which itself took out some locks and then
|
||||
essentially blocks this code from ever completing ... As a temp
|
||||
measure introducing a timeout to catch this case rather than letting
|
||||
it just hang forever (see LabelBasedIndexedPropertyHangingEntityTests)
|
||||
|
||||
TODO: Look at an alternative approach / way to ensure these schema
|
||||
updates are the first things done - this is not very efficient
|
||||
as it stands anyway
|
||||
*/
|
||||
ExecutorService pool = Executors.newFixedThreadPool(1);
|
||||
|
||||
try {
|
||||
pool.submit(new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
try (Transaction tx = gd.beginTx()) {
|
||||
cypher.query(query, null);
|
||||
tx.success();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}).get(2,TimeUnit.SECONDS);
|
||||
pool.shutdown();
|
||||
} catch (TimeoutException e) {
|
||||
throw new MappingException(format(
|
||||
"Timeour occured trying to create schema index %s on against label %s: " +
|
||||
"This may well be an indicator that another thread (the one which just " +
|
||||
"initiated this update), has probably got a lock of " +
|
||||
"this node and this timeout is because its in a deadlock situation and" +
|
||||
" cant acquire it - investigation required", prop, label),e);
|
||||
} catch (Exception e) {
|
||||
throw new MappingException(format("Unable to create schema index %s on against label %s", prop, label),e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> EndResult<T> findAll(Neo4jPersistentEntity entity) {
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.neo4j.support.typerepresentation;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.graphdb.index.IndexHits;
|
||||
import org.neo4j.helpers.collection.ClosableIterable;
|
||||
|
||||
@@ -17,14 +17,10 @@
|
||||
package org.springframework.data.neo4j.support.typerepresentation;
|
||||
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.NodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.core.RelationshipTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.repository.query.CypherQuery;
|
||||
import org.springframework.data.neo4j.support.index.IndexProvider;
|
||||
import org.springframework.data.neo4j.support.index.NoSuchIndexException;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngine;
|
||||
|
||||
public class TypeRepresentationStrategyFactory {
|
||||
private final GraphDatabase graphDatabaseService;
|
||||
|
||||
@@ -46,6 +46,9 @@ public class Person implements Being , Serializable {
|
||||
@Indexed
|
||||
private String nickname;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
private String alias;
|
||||
|
||||
@Indexed(indexType = IndexType.POINT, indexName="personLayer")
|
||||
private String wkt;
|
||||
|
||||
@@ -327,4 +330,12 @@ public class Person implements Being , Serializable {
|
||||
public void addSerialFriend(Person serialFriend) {
|
||||
getSerialFriends().add(serialFriend);
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,16 @@ public class TestTeam {
|
||||
|
||||
public TestTeam createSDGTeam(GraphRepository<Person> repo, GraphRepository<Group> groupRepo, GraphRepository<Friendship> friendshipRepository) {
|
||||
emil = new Person("Emil", 30);
|
||||
emil.setAlias("emilAlias");
|
||||
|
||||
michael = new Person("Michael", 36);
|
||||
michael.setBoss(emil);
|
||||
michael.setPersonality(Personality.EXTROVERT);
|
||||
michael.setLocation( "POINT(16 56)" );
|
||||
michael.setAlias("michaelAlias");
|
||||
|
||||
david = new Person("David", 25);
|
||||
david.setAlias("davidAlias");
|
||||
david.setBoss(emil);
|
||||
david.setLocation( 16.5, 56.5 );
|
||||
friendShip = michael.knows(david);
|
||||
|
||||
@@ -65,6 +65,9 @@ public abstract class AbstractDerivedFinderMethodTestBase {
|
||||
@Indexed
|
||||
String lastName;
|
||||
|
||||
@Indexed(indexType = IndexType.LABEL, numeric = false)
|
||||
String alias;
|
||||
|
||||
String name;
|
||||
boolean tagged;
|
||||
|
||||
@@ -152,6 +155,15 @@ public abstract class AbstractDerivedFinderMethodTestBase {
|
||||
getExpectedParams("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelBasedIndexQueryWithOneParam() throws Exception {
|
||||
assertRepositoryQueryMethod(ThingRepository.class,
|
||||
"findByAlias",
|
||||
new Object[]{"foo"},
|
||||
getExpectedQuery("subclass-to-supply-trs-specific-query"),
|
||||
getExpectedParams("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexQueryWithOneParamFullText() throws Exception {
|
||||
assertRepositoryQueryMethod(ThingRepository.class,
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -35,6 +36,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* Tests for the various finder method based scenarios
|
||||
@@ -91,6 +94,29 @@ public class DerivedFinderMethodForIndexedBasedTRSTests extends AbstractDerivedF
|
||||
super.testIndexQueryWithOneParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testLabelBasedIndexQueryWithOneParam() throws Exception {
|
||||
|
||||
// Ensure mappingContext set NOT to fail (but rather warn)
|
||||
// when incompatibility detected
|
||||
assertFalse(ctx.isFailWhenIncompatibleLabelIndexUsage());
|
||||
|
||||
/*
|
||||
Is this the correct logic??? - what should we do when a derived
|
||||
field has been marked as a label based indexed field and
|
||||
we have a legacy based indexing strategy in play. Have currently
|
||||
added in properties failWhenIncompatibleLabelIndexUsage and
|
||||
isLabelBasedTRSInUse to Neo4jMappingContext to help
|
||||
|
||||
*/
|
||||
// "findByAlias",
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`alias` = {0} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo" };
|
||||
super.testLabelBasedIndexQueryWithOneParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneParamFullText() throws Exception {
|
||||
@@ -362,4 +388,10 @@ public class DerivedFinderMethodForIndexedBasedTRSTests extends AbstractDerivedF
|
||||
super.testFindByNumericIndexedField();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testMultipleIndexedFields() throws Exception {
|
||||
super.testMultipleIndexedFields();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.Date;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Tests for the various finder method based scenarios
|
||||
@@ -366,4 +367,15 @@ public class DerivedFinderMethodForLabelBasedTRSTests extends AbstractDerivedFin
|
||||
this.trsSpecificExpectedQuery = "START `thing`=node:`Thing`(`number`={0}) RETURN `thing`";
|
||||
super.testFindByNumericIndexedField();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testLabelBasedIndexQueryWithOneParam() throws Exception {
|
||||
// findByAlias
|
||||
this.trsSpecificExpectedQuery = DEFAULT_MATCH_CLAUSE +
|
||||
" WHERE `thing`.`alias` = {0}" +
|
||||
" RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo" };
|
||||
super.testLabelBasedIndexQueryWithOneParam();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,4 +55,7 @@ public interface ThingRepository extends GraphRepository<AbstractDerivedFinderMe
|
||||
Thing findByBornAfter(Date date);
|
||||
Thing findById(long id);
|
||||
Thing findByOwnerId(long id);
|
||||
|
||||
// Label based indexes
|
||||
Thing findByAlias(String alias);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user