DATAGRAPH-449 Updated setup and type representation strategy reference docs
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package org.springframework.data.neo4j.aspects.support.typerepresentation;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.neo4j.aspects.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.aspects.support.domain.*;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Nicki Watt
|
||||
* @since 15.04.2014
|
||||
*/
|
||||
public class AliasOverrideTypeRepresentationStrategyTest {
|
||||
|
||||
protected GraphDatabaseService graphDatabaseService;
|
||||
protected Neo4jTemplate neo4jTemplate;
|
||||
protected ClassPathXmlApplicationContext applicationContext;
|
||||
|
||||
private void setupDefaultAppCtx() {
|
||||
applicationContext = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/data/neo4j/aspects/support/LabelBasedIndexedPropertyEntityTests-context-basic.xml");
|
||||
applicationContext.registerShutdownHook();
|
||||
applicationContext.refresh();
|
||||
graphDatabaseService = applicationContext.getBean(GraphDatabaseService.class);
|
||||
neo4jTemplate = applicationContext.getBean(Neo4jTemplate.class);
|
||||
}
|
||||
|
||||
private void setupOverrideAppCtx() {
|
||||
applicationContext = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/data/neo4j/aspects/support/classNameAliasOverride-context.xml");
|
||||
applicationContext.registerShutdownHook();
|
||||
applicationContext.refresh();
|
||||
graphDatabaseService = applicationContext.getBean(GraphDatabaseService.class);
|
||||
neo4jTemplate = applicationContext.getBean(Neo4jTemplate.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (applicationContext != null) applicationContext.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNameUsedForDefaultTRS() {
|
||||
setupDefaultAppCtx();
|
||||
String simpleLabelName = Thing.class.getSimpleName();
|
||||
testExpectedNameAppliedForLabelTRS(simpleLabelName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFQDNNameUsedForOverridenTRS() {
|
||||
setupOverrideAppCtx();
|
||||
String fqdnLabelName = Thing.class.getName();
|
||||
testExpectedNameAppliedForLabelTRS(fqdnLabelName);
|
||||
}
|
||||
|
||||
public void testExpectedNameAppliedForLabelTRS(String expectedLabelName) {
|
||||
// Given I create a Node Entity and it is saved into the graph
|
||||
// And I verify this by ensuring the nodeId is present
|
||||
Thing thing = createThing(graphDatabaseService);
|
||||
Long savedNodeId = ((NodeBacked) thing).getNodeId();
|
||||
assertNotNull("Node Id Should have been assigned as part of persist call ",savedNodeId);
|
||||
|
||||
// When I get all the labels from this Node
|
||||
// Then I expect to find the two appropriate TRS based labels
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Node retrievedNode = neo4jTemplate.getNode(savedNodeId);
|
||||
Collection<Label> labels = IteratorUtil.asCollection(retrievedNode.getLabels());
|
||||
assertThat( labels, hasItems(
|
||||
DynamicLabel.label(expectedLabelName),
|
||||
DynamicLabel.label("_" + expectedLabelName)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Thing createThing(GraphDatabaseService graphDB) {
|
||||
Thing thing = null;
|
||||
try (Transaction tx = graphDB.beginTx()) {
|
||||
thing = new Thing();
|
||||
thing.setName("theThing");
|
||||
((NodeBacked)thing).persist();
|
||||
tx.success();
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<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.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.springframework.data.neo4j.aspects.support.domain"/>
|
||||
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown"/>
|
||||
|
||||
<!-- Use fully qualified name as type alias instead -->
|
||||
<bean id="entityAlias" class="org.springframework.data.neo4j.support.mapping.ClassNameAlias" />
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.springframework.data.neo4j.config;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.data.neo4j.config.spring.BasicJavaConfig;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.repositories.PersonRepository;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Create SDN using (non test based) Java Config - No XML in site!
|
||||
*/
|
||||
public class BasicJavaConfigTest {
|
||||
|
||||
AnnotationConfigApplicationContext appCtx;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (appCtx != null) appCtx.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyAppCtxStartsCorrectlyWithJavaConfig() {
|
||||
startJavaBasedAppCtx();
|
||||
}
|
||||
|
||||
private void startJavaBasedAppCtx() {
|
||||
appCtx = new AnnotationConfigApplicationContext();
|
||||
appCtx.register(BasicJavaConfig.class);
|
||||
appCtx.registerShutdownHook();
|
||||
appCtx.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicRepositoryFunctionality() {
|
||||
startJavaBasedAppCtx();
|
||||
GraphDatabaseService graphDatabaseService = appCtx.getBean(GraphDatabaseService.class);
|
||||
PersonRepository personRepository = appCtx.getBean(PersonRepository.class);
|
||||
try (Transaction tx = graphDatabaseService.beginTx()) {
|
||||
Person person = new Person("Howdy",50);
|
||||
personRepository.save(person);
|
||||
assertNotNull(person.getId());
|
||||
tx.success();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.springframework.data.neo4j.config.spring;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.TestGraphDatabaseFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackages = "org.springframework.data.neo4j.repositories")
|
||||
public class BasicJavaConfig extends Neo4jConfiguration {
|
||||
|
||||
public BasicJavaConfig() {
|
||||
setBasePackage("org.springframework.data.neo4j.model");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GraphDatabaseService graphDatabaseService() {
|
||||
return new TestGraphDatabaseFactory().newImpermanentDatabase();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
/**
|
||||
* 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.query;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.metatest.TestImpermanentGraphDatabase;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.neo4j.test.TestGraphDatabaseFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.NodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.IndexBasedNodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
|
||||
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 org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* Tests for the various finder method based scenarios
|
||||
* , specifically where the Index Type Representation Strategy is being used.
|
||||
*
|
||||
* @author Oliver Gierke & Nicki Watt
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
|
||||
public class DerivedFinderMethodForIndexedBasedTRSViaJavaConfigTests extends AbstractDerivedFinderMethodTestBase {
|
||||
|
||||
private static final String DEFAULT_START_CLAUSE = "START `thing`=node:__types__(className=\"Thing\")";
|
||||
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackages = "org.springframework.data.neo4j.repository.query")
|
||||
static class Config extends Neo4jConfiguration {
|
||||
|
||||
Config() {
|
||||
// Equivalent of setting basePackage for XML based <neo4j:config base-package=".."/>
|
||||
// (This will probably move into an/the @EnableNeo4jRepositories in the future)
|
||||
setBasePackage("org.springframework.data.neo4j.model,org.springframework.data.neo4j.repository.query");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeRepresentationStrategyFactory typeRepresentationStrategyFactory() {
|
||||
return new TypeRepresentationStrategyFactory(
|
||||
graphDatabase(),
|
||||
TypeRepresentationStrategyFactory.Strategy.Indexed);
|
||||
}
|
||||
|
||||
@Bean(name="graphDatabaseService", destroyMethod = "shutdown")
|
||||
public GraphDatabaseService graphDatabaseService() {
|
||||
return new TestGraphDatabaseFactory().newImpermanentDatabase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Autowired
|
||||
NodeTypeRepresentationStrategy strategy;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
super.setup();
|
||||
assertThat("The tests in this class should be configured to use the Label " +
|
||||
"based Type Representation Strategy, however it is not ... ",
|
||||
strategy, instanceOf(IndexBasedNodeTypeRepresentationStrategy.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testQueryWithEntityGraphId() throws Exception {
|
||||
// findByOwnerId
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing_owner`=node({0}) " +
|
||||
"MATCH (`thing`)-[:`owner`]->(`thing_owner`) " +
|
||||
"WHERE `thing`.__type__ IN ['Thing'] ";
|
||||
super.testQueryWithEntityGraphId();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithTwoParams() throws Exception {
|
||||
// "findByFirstNameAndLastName",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:foo AND lastName:bar" };
|
||||
super.testIndexQueryWithTwoParams();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneParam() throws Exception {
|
||||
// "findByFirstName",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`(`firstName`={0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo" };
|
||||
super.testIndexQueryWithOneParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testSchemaIndexQueryWithOneParam() throws Exception {
|
||||
|
||||
/*
|
||||
TODO - Determine exactly what correct query should be when
|
||||
using a schema based index and a Legacy based TRS
|
||||
*/
|
||||
// "findByAlias",
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`alias` = {0} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo" };
|
||||
super.testSchemaIndexQueryWithOneParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneParamFullText() throws Exception {
|
||||
// "findByDescription",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`search`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "description:foo" };
|
||||
super.testIndexQueryWithOneParamFullText();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneParamFullTextAndOneParam() throws Exception {
|
||||
// "findByDescriptionAndFirstName",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`search`({0}) WHERE `thing`.`firstName` = {1} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "description:foo","bar" };
|
||||
super.testIndexQueryWithOneParamFullTextAndOneParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneParamAndOneParamFullText() throws Exception {
|
||||
// "findByFirstNameAndDescription",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`(`firstName`={0}) WHERE `thing`.`description` = {1} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo","bar" };
|
||||
super.testIndexQueryWithOneParamAndOneParamFullText();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneNonIndexedParam() throws Exception {
|
||||
// "findByAge",
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`age` = {0} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { 100 };
|
||||
super.testIndexQueryWithOneNonIndexedParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithOneNonIndexedParamAndOneIndexedParam() throws Exception {
|
||||
// "findByAgeAndFirstName",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`(`firstName`={1}) WHERE `thing`.`age` = {0} RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { 100, "foo" };
|
||||
super.testIndexQueryWithOneNonIndexedParamAndOneIndexedParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithLikeIndexedParam() throws Exception {
|
||||
// "findByFirstNameLike",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:foo" };
|
||||
super.testIndexQueryWithLikeIndexedParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithLikeIndexedParamWithSpaces() throws Exception {
|
||||
// "findByFirstNameLike",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:\"foo bar\"" };
|
||||
super.testIndexQueryWithLikeIndexedParamWithSpaces();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithContainsIndexedParam() throws Exception {
|
||||
// "findByFirstNameContains",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:*foo*" };
|
||||
super.testIndexQueryWithContainsIndexedParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithStartsWithIndexedParam() throws Exception {
|
||||
// "findByFirstNameStartsWith",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:foo*" };
|
||||
super.testIndexQueryWithStartsWithIndexedParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testIndexQueryWithEndsWithIndexedParam() throws Exception {
|
||||
// "findByFirstNameEndsWith",
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0}) RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "firstName:*foo" };
|
||||
super.testIndexQueryWithEndsWithIndexedParam();
|
||||
}
|
||||
|
||||
@Test(expected = RepositoryQueryException.class)
|
||||
@Override
|
||||
public void testFailIndexQueryWithStartsWithIndexedParamWithSpaces() throws Exception {
|
||||
// findByFirstNameStartsWith
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`({0})" +
|
||||
" RETURN `thing`";
|
||||
super.testFailIndexQueryWithStartsWithIndexedParamWithSpaces();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParam() throws Exception {
|
||||
// findByName
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` = {0}" +
|
||||
" RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "foo" };
|
||||
super.testFindBySimpleStringParam();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamStartsWith() throws Exception {
|
||||
// findByNameStartsWith
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` =~ {0}" +
|
||||
" RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { "^foo.*" };
|
||||
super.testFindBySimpleStringParamStartsWith();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamEndsWith() throws Exception {
|
||||
// findByNameEndsWith
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` =~ {0}" +
|
||||
" RETURN `thing`";
|
||||
this.trsSpecificExpectedParams = new Object[] { ".*foo$" };
|
||||
super.testFindBySimpleStringParamEndsWith();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamContains() throws Exception {
|
||||
// findByNameContains
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` =~ {0}" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringParamContains();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamLike() throws Exception {
|
||||
// findByNameLike
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` =~ {0}" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringParamLike();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamNotLike() throws Exception {
|
||||
// findByNameNotLike
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE not( `thing`.`name` =~ {0} )" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringParamNotLike();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringParamRegexp() throws Exception {
|
||||
// findByNameMatches
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` =~ {0}" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringParamRegexp();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleBooleanIsTrue() throws Exception {
|
||||
// findByTaggedIsTrue
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`tagged` = true" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleBooleanIsTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleBooleanIsFalse() throws Exception {
|
||||
// findByTaggedIsFalse
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`tagged` = false" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleBooleanIsFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringExists() throws Exception {
|
||||
// findByNameExists
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE has(`thing`.`name` )" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringExists();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringInCollection() throws Exception {
|
||||
// findByNameIn
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` in {0}" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringInCollection();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringInCollectionOfEnums() throws Exception {
|
||||
// findByNameIn
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`name` in {0}" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringInCollectionOfEnums();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleStringNotInCollection() throws Exception {
|
||||
// findByNameNotIn
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE not( `thing`.`name` in {0} )" +
|
||||
" RETURN `thing`";
|
||||
super.testFindBySimpleStringNotInCollection();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleDateBefore() throws Exception {
|
||||
// findByBornBefore
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`born` < {0} RETURN `thing`";
|
||||
super.testFindBySimpleDateBefore();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindBySimpleDateAfter() throws Exception {
|
||||
// findByBornAfter
|
||||
this.trsSpecificExpectedQuery = DEFAULT_START_CLAUSE +
|
||||
" WHERE `thing`.`born` > {0} RETURN `thing`";
|
||||
super.testFindBySimpleDateAfter();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testFindByNumericIndexedField() throws Exception {
|
||||
// findByNumber
|
||||
this.trsSpecificExpectedQuery =
|
||||
"START `thing`=node:`Thing`(`number`={0}) RETURN `thing`";
|
||||
super.testFindByNumericIndexedField();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testMultipleIndexedFields() throws Exception {
|
||||
super.testMultipleIndexedFields();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,11 @@
|
||||
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:annotation-config/>
|
||||
<neo4j:config storeDirectory="target/config-test"/>
|
||||
<bean id="graphDbFactory" class="org.neo4j.graphdb.factory.GraphDatabaseFactory"/>
|
||||
<bean id="graphDatabaseService" scope="singleton" destroy-method="shutdown" factory-bean="graphDbFactory" factory-method="newEmbeddedDatabase">
|
||||
<constructor-arg value="target/config-test"/>
|
||||
</bean>
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService"/>
|
||||
<bean id="config" class="org.springframework.data.neo4j.config.DataGraphNamespaceHandlerTests$Config"/>
|
||||
|
||||
<neo4j:repositories base-package="org.springframework.data.neo4j.model"/>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean id="typeRepresentationStrategyFactory" class="org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory">
|
||||
<constructor-arg index="0" ref="graphDatabase"/>
|
||||
<constructor-arg index="1" value="Indexed"/>
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
<constructor-arg value="Indexed"/>
|
||||
</bean>
|
||||
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.springframework.data.neo4j.model,org.springframework.data.neo4j.repository.query"/>
|
||||
|
||||
@@ -4,21 +4,13 @@
|
||||
<title>Entity type representation</title>
|
||||
<para>
|
||||
There are several ways to represent the Java type hierarchy of the data model in the graph. In general, for all
|
||||
node and relationship entities, type information is needed to perform certain repository operations. Some of
|
||||
this type information hierarchy is saved in the graph database.
|
||||
</para>
|
||||
<para>
|
||||
As the type information is also stored in labels, node/relationship-properties and/or indexes it might amount to a substantial
|
||||
amount of data in the graph. It is possible to use an <code>@TypeAlias("name")</code> annotation on nodes and relationships to have a
|
||||
short constant name for each type which is (unlike the default approach) renaming-refactoring-safe.
|
||||
Other than in previous versions, Spring Data Neo4j uses the simple class name as default.
|
||||
For using the fully qualified class name by default, register a <code>Neo4jMappingContext</code> bean configured with an
|
||||
instance of <code>org.springframework.data.neo4j.support.mapping.ClassNameAlias</code>.
|
||||
It is also possible to opt out of storing type information using the <code>NoopTypeRepresentationStrategies</code>.
|
||||
node and relationship entities, type information is needed to perform certain repository operations (such as findAll()).
|
||||
This means that some of the type information hierarchy needs to be saved in the graph database, and SDN
|
||||
makes use of "Type Representation Strategies" in order to achieve this.
|
||||
</para>
|
||||
<para>
|
||||
Implementations of <code>TypeRepresentationStrategy</code> take care of persisting this information during entity instance
|
||||
creation. They also provide the repository methods that use this type information to perform their operations,
|
||||
creation. They are also used by certain repository methods to perform their operations,
|
||||
like <code>findAll</code> and <code>count</code>. The derived finderMethods also use the type information for graph global queries.
|
||||
</para>
|
||||
<para>
|
||||
@@ -88,9 +80,71 @@
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
In order to use a different Type Representation Strategy, simply register an alternative "typeRepresentationStrategyFactory"
|
||||
spring bean specifying the strategy required. For example to use the legacy indexing strategy for nodes you could define
|
||||
the following override bean.
|
||||
<example>
|
||||
<title>XML-based configuration</title>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<bean id="typeRepresentationStrategyFactory" class="org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory">
|
||||
<constructor-arg ref="graphDatabase"/>
|
||||
<constructor-arg value="Indexed"/>
|
||||
</bean>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
Whilst in Java Config this may look as follows:
|
||||
<example>
|
||||
<title>Java-based configuration</title>
|
||||
<programlisting language="java"><![CDATA[
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackages = "org.springframework.data.neo4j.ref.whatever.repositories")
|
||||
static class Config extends Neo4jConfiguration {
|
||||
|
||||
Config() {
|
||||
// Equivalent of setting basePackage for XML based <neo4j:config base-package=".."/>
|
||||
// (This will probably move into an/the @EnableNeo4jRepositories in the future)
|
||||
setBasePackage("org.springframework.data.neo4j.model,org.springframework.data.neo4j.repository.query");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeRepresentationStrategyFactory typeRepresentationStrategyFactory() {
|
||||
return new TypeRepresentationStrategyFactory(
|
||||
graphDatabase(),
|
||||
TypeRepresentationStrategyFactory.Strategy.Indexed);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
]]></programlisting>
|
||||
</example>
|
||||
</para>
|
||||
<para>
|
||||
As some type information is also stored in labels, node/relationship-properties and/or indexes it might amount to a substantial
|
||||
amount of data in the graph. It is possible to use an <code>@TypeAlias("name")</code> annotation on nodes and relationships to have a
|
||||
short constant name for each type which is (unlike the default approach) renaming-refactoring-safe.
|
||||
From 3.0 onwards, Spring Data Neo4j uses the simple class name as the default whilst previous versions used to default to the fully qualified name.
|
||||
If you would like to use the fully qualified class name by default, you can
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Register a <code>Neo4jMappingContext</code> bean configured with an instance of <code>org.springframework.data.neo4j.support.mapping.ClassNameAlias</code>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Override the spring "entityAlias" bean with an instance of <code>org.springframework.data.neo4j.support.mapping.ClassNameAlias</code>. For example, using XML config this would look as follows:
|
||||
<programlisting language="xml"><![CDATA[<bean id="entityAlias" class="org.springframework.data.neo4j.support.mapping.ClassNameAlias" />]]></programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
It is also possible to opt out of storing type information completely by using the <code>NoopTypeRepresentationStrategies</code>.
|
||||
</para>
|
||||
<para>
|
||||
Spring Data Neo4j will by default autodetect which are the most suitable strategies for node and relationship
|
||||
entities. For new data stores, it will always opt for the indexing strategies. If a data store was created
|
||||
entities. For new data stores, it will always opt for the indexing strategies (Label based for nodes, and legacy
|
||||
index based for relationships). If a data store was created
|
||||
with the older<code>SubReferenceNodeTypeRepresentationStrategy</code>, then it will continue to use that
|
||||
strategy for node entities. It will however in that case use the no-op strategy for relationship entities,
|
||||
which means that the old data stores have no support for searching for relationship entities. The indexing
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<section>
|
||||
<title>Dependencies for Spring Data Neo4j Simple Mapping</title>
|
||||
<para>
|
||||
For the simple POJO mapping it is enough to add the <code>org.springframework.data:spring-data-neo4j:2.1.0.RELEASE</code> dependency
|
||||
For the simple POJO mapping it is enough to add the <code>org.springframework.data:spring-data-neo4j:3.0.0.RELEASE</code> dependency
|
||||
to your project.
|
||||
</para>
|
||||
<example>
|
||||
@@ -25,7 +25,7 @@
|
||||
<programlisting language="xml"><![CDATA[<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j</artifactId>
|
||||
<version>2.1.0.RELEASE</version>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
</dependency>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
@@ -43,9 +43,9 @@
|
||||
<programlisting language="java"><![CDATA[sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
springVersion = "3.1.0.RELEASE"
|
||||
springDataNeo4jVersion = "2.1.0.RELEASE"
|
||||
aspectjVersion = "1.6.12"
|
||||
springVersion = "3.2.8.RELEASE"
|
||||
springDataNeo4jVersion = "3.0.0.RELEASE"
|
||||
aspectjVersion = "1.7.4"
|
||||
|
||||
apply from:'https://github.com/SpringSource/spring-data-neo4j/raw/master/build/
|
||||
gradle/springdataneo4j.gradle'
|
||||
@@ -126,13 +126,13 @@ repositories {
|
||||
<programlisting language="xml"><![CDATA[<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j-aspects</artifactId>
|
||||
<version>2.1.0.RELEASE</version>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.12</version>
|
||||
<version>1.7.4</version>
|
||||
</dependency>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
@@ -150,18 +150,18 @@ repositories {
|
||||
<programlisting language="xml"><![CDATA[<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.4</version>
|
||||
<dependencies>
|
||||
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.12</version>
|
||||
<version>1.7.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>1.6.12</version>
|
||||
<version>1.7.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -203,12 +203,42 @@ repositories {
|
||||
<title>XML namespace</title>
|
||||
<para>
|
||||
The XML namespace can be used to configure Spring Data Neo4j. The <code>config</code> element
|
||||
provides an XML-based configuration of Spring Data Neo4j in one line. It has three attributes.
|
||||
<code>graphDatabaseService</code> points out the Neo4j instance to use. For convenience,
|
||||
<code>storeDirectory</code> can be set instead of <code>graphDatabaseService</code> to
|
||||
point to a directory where a new <code>EmbeddedGraphDatabase</code> will be created. For
|
||||
cross-store configuration, the <code>entityManagerFactory</code> attribute needs to be
|
||||
configured.
|
||||
provides an XML-based configuration of Spring Data Neo4j in one line. It has four attributes.
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<code>base-package</code> points to a set of packages (provided as a comma separated String of names)
|
||||
which SDN will scan for locate all of your domain entity classes (<code>@NodeEntity</code> and <code>@RelationshipEntity</code>).
|
||||
<note>
|
||||
<para>
|
||||
Neo4j 2.0 introduced the requirement to separately manage schema and data transactions which altered some
|
||||
options for SDN with regards be being able to automatically detect and register <code>@NodeEntity</code> and <code>@RelationshipEntity</code>s on the fly.
|
||||
Several approaches were attempted to try and handle this automatically with SDN 3.0.X, none of which worked in a satisfactory manner.
|
||||
This has resulted in the base-package becoming a mandatory field now with entity metadata handling becoming an
|
||||
explicit step in the lifecycle.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<code>graphDatabaseService</code> points out the Neo4j instance to use.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<code>storeDirectory</code> is a convenient alternative (instead of <code>graphDatabaseService</code>)
|
||||
to point to a directory where a new <code>EmbeddedGraphDatabase</code> will be created.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<code>entityManagerFactory</code> is only required for cross-store configuration.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
</para>
|
||||
<example>
|
||||
<title>XML configuration with store directory</title>
|
||||
@@ -226,28 +256,24 @@ repositories {
|
||||
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
<neo4j:config storeDirectory="target/config-test"/>
|
||||
<neo4j:config
|
||||
storeDirectory="target/config-test"
|
||||
base-package="org.example.domain"/>
|
||||
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>XML configuration with GraphDatabaseService bean</title>
|
||||
<title>XML configuration with basic GraphDatabaseService bean</title>
|
||||
<programlisting language="xml"><![CDATA[<context:annotation-config/>
|
||||
|
||||
<bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
|
||||
destroy-method="shutdown">
|
||||
<constructor-arg index="0" value="target/config-test"/>
|
||||
<!-- optionally pass in neo4j-config parameters to the graph database
|
||||
<constructor-arg index="1">
|
||||
<map>
|
||||
<entry key="allow_store_upgrade" value="true"/>
|
||||
</map>
|
||||
</constructor-arg>
|
||||
-->
|
||||
<bean id="graphDbFactory" class="org.neo4j.graphdb.factory.GraphDatabaseFactory"/>
|
||||
<bean id="graphDatabaseService" scope="singleton" destroy-method="shutdown"
|
||||
factory-bean="graphDbFactory" factory-method="newEmbeddedDatabase">
|
||||
<constructor-arg value="target/config-test"/>
|
||||
</bean>
|
||||
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService"/>
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.example.domain"/>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
<example>
|
||||
@@ -289,7 +315,8 @@ repositories {
|
||||
</bean>
|
||||
|
||||
<neo4j:config storeDirectory="target/config-test"
|
||||
entityManagerFactory="entityManagerFactory"/>
|
||||
entityManagerFactory="entityManagerFactory"
|
||||
base-package="org.example.domain"/>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
</section>
|
||||
@@ -336,22 +363,54 @@ repositories {
|
||||
<code>Neo4jConfiguration</code> is registered with the context. This is either done
|
||||
explicitly in the context configuration, or via classpath scanning for classes that
|
||||
have the @Configuration annotation. The only thing that must be provided is the
|
||||
<code>GraphDatabaseService</code>. The example below shows how to register the
|
||||
<code>@Configuration Neo4jConfiguration</code> class, as well as Spring's
|
||||
<code>ConfigurationClassPostProcessor</code> that transforms the
|
||||
<code>@Configuration</code> class to bean definitions.
|
||||
<code>GraphDatabaseService</code> and the <code>basePackage</code> must also be set.
|
||||
The examples below show how this can be done.
|
||||
|
||||
<example>
|
||||
<title>Java-based bean configuration</title>
|
||||
<programlisting language="xml"><![CDATA[<![CDATA[<beans ...>
|
||||
<title>Pure Java based bean configuration</title>
|
||||
<programlisting language="java">
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackages = "org.example.repositories")
|
||||
public class BasicJavaConfig extends Neo4jConfiguration {
|
||||
|
||||
public BasicJavaConfig() {
|
||||
setBasePackage("org.example.domain");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GraphDatabaseService graphDatabaseService() {
|
||||
return new GraphDatabaseFactory().newEmbeddedDatabase("path/to/mydb");
|
||||
}
|
||||
|
||||
// You can add your own beans here, and/or override some of the
|
||||
// default config (such as Type Representation Strategies etc)
|
||||
|
||||
}
|
||||
|
||||
</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Java-based bean config initialiation via XML </title>
|
||||
<para>
|
||||
To register the default
|
||||
<code>@Configuration Neo4jConfiguration</code> class, as well as Spring's
|
||||
<code>ConfigurationClassPostProcessor</code> that transforms the
|
||||
<code>@Configuration</code> class to bean definitions via XML.
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans ...>
|
||||
...
|
||||
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
|
||||
<bean class="org.springframework.data.neo4j.config.Neo4jConfiguration"/>
|
||||
<bean class="org.springframework.data.neo4j.config.Neo4jConfiguration">
|
||||
<property name="basePackage" value="org.example.domain" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.context.annotation.ConfigurationClassPostProcessor"/>
|
||||
|
||||
<bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
|
||||
destroy-method="shutdown" scope="singleton">
|
||||
<constructor-arg index="0" value="target/config-test"/>
|
||||
<bean id="graphDbFactory" class="org.neo4j.graphdb.factory.GraphDatabaseFactory"/>
|
||||
<bean id="graphDatabaseService" scope="singleton" destroy-method="shutdown"
|
||||
factory-bean="graphDbFactory" factory-method="newEmbeddedDatabase">
|
||||
<constructor-arg value="target/config-test"/>
|
||||
</bean>
|
||||
...
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user