DATAGRAPH-169 Backquoting all variable parts of derived finder queries to accommodate for non-identifier names.
This commit is contained in:
@@ -32,7 +32,7 @@ import java.util.Set;
|
||||
@NodeEntity
|
||||
public class Person {
|
||||
|
||||
public static final String NAME_INDEX = "name_index";
|
||||
public static final String NAME_INDEX = "name-index";
|
||||
@GraphId
|
||||
private Long graphId;
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ public class QueryEngineTest extends EntityTestBase {
|
||||
|
||||
@Test
|
||||
public void testQueryListOfTypeNode() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final Result<Map<String,Object>> queryResult = queryEngine.query(queryString, michaelsName());
|
||||
final Collection<Node> result = IteratorUtil.asCollection(queryResult.to(Node.class));
|
||||
|
||||
@@ -100,7 +100,7 @@ public class QueryEngineTest extends EntityTestBase {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testQueryListOfTypePerson() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final Collection<Person> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter(conversionService, template)));
|
||||
|
||||
assertEquals(asList(testTeam.emil),result);
|
||||
@@ -112,7 +112,7 @@ public class QueryEngineTest extends EntityTestBase {
|
||||
|
||||
@Test
|
||||
public void testQuerySingleOfTypePerson() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final Person result = queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter<Map<String,Object>,Person>(conversionService, template)).single();
|
||||
|
||||
assertEquals(testTeam.emil,result);
|
||||
@@ -195,7 +195,7 @@ public class QueryEngineTest extends EntityTestBase {
|
||||
}
|
||||
@Test
|
||||
public void testQueryListWithCustomConverter() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) match (person) <-[:boss]- (boss) return boss";
|
||||
final Collection<String> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter.ResultConverterAdapter<Map<String, Object>, String>() {
|
||||
@Override
|
||||
public String convert(Map<String, Object> row, Class<String> target) {
|
||||
@@ -208,14 +208,14 @@ public class QueryEngineTest extends EntityTestBase {
|
||||
|
||||
@Test
|
||||
public void testQueryForObjectAsString() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:persons]- (team) return team.name";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) match (person) <-[:persons]- (team) return team.name";
|
||||
final String result = queryEngine.query(queryString, michaelsName()).to(String.class).single();
|
||||
|
||||
assertEquals(testTeam.sdg.getName(),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsEnum() throws Exception {
|
||||
final String queryString = "start person=node:name_index(name={name}) return person.personality";
|
||||
final String queryString = "start person=node:`name-index`(name={name}) return person.personality";
|
||||
final Personality result = queryEngine.query(queryString, michaelsName()).to(Personality.class).single();
|
||||
|
||||
assertEquals(michael.getPersonality(),result);
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.repository.query;
|
||||
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -29,6 +24,11 @@ import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
/**
|
||||
* Value object to create Cypher queries.
|
||||
*
|
||||
@@ -133,7 +133,7 @@ class CypherQueryBuilder implements CypherQueryDefinition {
|
||||
builder.append(" where ").append(whereClauses);
|
||||
}
|
||||
|
||||
builder.append(" return ").append(variableContext.getVariableFor(entity));
|
||||
builder.append(" return ").append(String.format(QueryTemplates.VARIABLE, variableContext.getVariableFor(entity)));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,11 +65,20 @@ class MatchClause {
|
||||
private String matchPattern(VariableContext variableContext, PersistentPropertyPath<Neo4jPersistentProperty> relPath) {
|
||||
if (relPath.getLength() == 1) {
|
||||
final Neo4jPersistentProperty property = relPath.getBaseProperty();
|
||||
return variableContext.getVariableFor(property.getOwner()) + QueryTemplates.getArrow(property.getRelationshipInfo())
|
||||
+ variableContext.getVariableFor(relPath);
|
||||
return formatMatch(variableContext.getVariableFor(property.getOwner()),
|
||||
QueryTemplates.getArrow(property.getRelationshipInfo()),
|
||||
variableContext.getVariableFor(relPath));
|
||||
}
|
||||
final RelationshipInfo info = relPath.getLeafProperty().getRelationshipInfo();
|
||||
return matchPattern(variableContext, relPath.getParentPath()) + QueryTemplates.getArrow(info)
|
||||
+ variableContext.getVariableFor(relPath);
|
||||
return formatMatch2(matchPattern(variableContext, relPath.getParentPath()),
|
||||
QueryTemplates.getArrow(info),
|
||||
variableContext.getVariableFor(relPath));
|
||||
}
|
||||
|
||||
private String formatMatch(String first, String arrow, String second) {
|
||||
return String.format(QueryTemplates.MATCH_CLAUSE, first, arrow, second);
|
||||
}
|
||||
private String formatMatch2(String first, String arrow, String second) {
|
||||
return String.format(QueryTemplates.MATCH_CLAUSE2, first, arrow, second);
|
||||
}
|
||||
}
|
||||
@@ -27,18 +27,21 @@ public abstract class QueryTemplates {
|
||||
|
||||
public static final String PARAMETER = "%d";
|
||||
public static final String PARAMETER_INDEX_QUERY = "%s:%s";
|
||||
public static final String VARIABLE = "`%s`";
|
||||
|
||||
public static final String PLACEHOLDER = String.format("{%s}", PARAMETER);
|
||||
private static final String DIRECTION_INCOMING = "<-[:%s]-";
|
||||
private static final String DIRECTION_OUTGOING = "-[:%s]->";
|
||||
private static final String DIRECTION_BOTH = "-[:%s]-";
|
||||
private static final String DIRECTION_INCOMING = "<-[:`%s`]-";
|
||||
private static final String DIRECTION_OUTGOING = "-[:`%s`]->";
|
||||
private static final String DIRECTION_BOTH = "-[:`%s`]-";
|
||||
static final String MATCH_CLAUSE = "`%s`%s`%s`";
|
||||
static final String MATCH_CLAUSE2 = "%s%s`%s`";
|
||||
|
||||
static final String DEFAULT_START_CLAUSE = "%s=node:__types__(className=\"%s\")";
|
||||
static final String DEFAULT_START_CLAUSE = "`%s`=node:__types__(className=\"%s\")";
|
||||
static final String SKIP_LIMIT = " skip %d limit %d";
|
||||
static final String START_CLAUSE = "%s=node:%s(%s=" + PLACEHOLDER + ")";
|
||||
static final String START_CLAUSE_FULLTEXT = "%s=node:%s(" + PLACEHOLDER + ")";
|
||||
static final String WHERE_CLAUSE_1 = "%s.%s %s " + PLACEHOLDER;
|
||||
static final String WHERE_CLAUSE_0 = "%s.%s %s ";
|
||||
static final String START_CLAUSE = "`%s`=node:`%s`(`%s`=" + PLACEHOLDER + ")";
|
||||
static final String START_CLAUSE_FULLTEXT = "`%s`=node:`%s`(" + PLACEHOLDER + ")";
|
||||
static final String WHERE_CLAUSE_1 = "`%s`.`%s` %s " + PLACEHOLDER;
|
||||
static final String WHERE_CLAUSE_0 = "`%s`.`%s` %s ";
|
||||
static final String SORT_CLAUSE = "%s %s";
|
||||
static final String ORDER_BY_CLAUSE = " order by %s";
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.Set;
|
||||
@NodeEntity
|
||||
public class Person {
|
||||
|
||||
public static final String NAME_INDEX = "name_index";
|
||||
public static final String NAME_INDEX = "name-index";
|
||||
public static final org.neo4j.graphdb.RelationshipType KNOWS = DynamicRelationshipType.withName("knows");
|
||||
@GraphId
|
||||
private Long graphId;
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.repository.query;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -26,6 +23,9 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CypherQueryBuilder}.
|
||||
*
|
||||
@@ -35,7 +35,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
|
||||
CypherQueryBuilder query;
|
||||
private final String CLASS_NAME = Person.class.getName();
|
||||
private String DEFAULT_START_CLAUSE = "start person=node:__types__(className=\"" + CLASS_NAME + "\")";
|
||||
private String DEFAULT_START_CLAUSE = "start `person`=node:__types__(className=\"" + CLASS_NAME + "\")";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -49,7 +49,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("name", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is("start person=node:Person(name={0}) return person"));
|
||||
assertThat(query.toString(), is("start `person`=node:`Person`(`name`={0}) return `person`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -58,7 +58,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("titleLike", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is("start person=node:title({0}) return person"));
|
||||
assertThat(query.toString(), is("start `person`=node:`title`({0}) return `person`"));
|
||||
}
|
||||
@Test
|
||||
public void createsQueryForLikeProperty() {
|
||||
@@ -66,7 +66,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("infoLike", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where person.info =~ {0} return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where `person`.`info` =~ {0} return `person`"));
|
||||
}
|
||||
@Test
|
||||
public void createsQueryForGreaterThanPropertyReference() {
|
||||
@@ -74,7 +74,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("ageGreaterThan", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where person.age > {0} return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where `person`.`age` > {0} return `person`"));
|
||||
}
|
||||
@Test
|
||||
public void createsQueryForTwoPropertyExpressions() {
|
||||
@@ -82,7 +82,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
query.addRestriction(new Part("ageGreaterThan", Person.class));
|
||||
query.addRestriction(new Part("info", Person.class));
|
||||
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where person.age > {0} and person.info = {1} return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where `person`.`age` > {0} and `person`.`info` = {1} return `person`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -91,7 +91,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("ageIsNull", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where person.age is null return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE+" where `person`.`age` is null return `person`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,7 +100,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
Part part = new Part("group.name", Person.class);
|
||||
query.addRestriction(part);
|
||||
|
||||
assertThat(query.toString(), is("start person_group=node:Group(name={0}) match person<-[:members]-person_group return person"));
|
||||
assertThat(query.toString(), is("start `person_group`=node:`Group`(`name`={0}) match `person`<-[:`members`]-`person_group` return `person`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,7 +110,7 @@ public class CypherQueryBuilderUnitTests {
|
||||
query.addRestriction(new Part("group.name", Person.class));
|
||||
|
||||
assertThat(query.toString(),
|
||||
is("start person=node:Person(name={0}), person_group=node:Group(name={1}) match person<-[:members]-person_group return person"));
|
||||
is("start `person`=node:`Person`(`name`={0}), `person_group`=node:`Group`(`name`={1}) match `person`<-[:`members`]-`person_group` return `person`"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,12 +119,12 @@ public class CypherQueryBuilderUnitTests {
|
||||
query.addRestriction(new Part("age", Person.class));
|
||||
|
||||
final String className = Person.class.getName();
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE +" where person.age = {0} return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE +" where `person`.`age` = {0} return `person`"));
|
||||
}
|
||||
@Test
|
||||
public void createsSimpleTraversalClauseCorrectly() {
|
||||
query.addRestriction(new Part("group", Person.class));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE + " match person<-[:members]-person_group return person"));
|
||||
assertThat(query.toString(), is(DEFAULT_START_CLAUSE + " match `person`<-[:`members`]-`person_group` return `person`"));
|
||||
}
|
||||
|
||||
|
||||
@@ -138,29 +138,29 @@ public class CypherQueryBuilderUnitTests {
|
||||
|
||||
System.out.println(query.toString());
|
||||
assertThat(query.toString(), is(
|
||||
"start person=node:Person(name={0}), person_group=node:Group(name={1}) " +
|
||||
"match person<-[:members]-person_group, person<-[:members]-person_group-[:members]->person_group_members " +
|
||||
"where person.age > {2} and person_group_members.age = {3} " +
|
||||
"return person"
|
||||
"start `person`=node:`Person`(`name`={0}), `person_group`=node:`Group`(`name`={1}) " +
|
||||
"match `person`<-[:`members`]-`person_group`, `person`<-[:`members`]-`person_group`-[:`members`]->`person_group_members` " +
|
||||
"where `person`.`age` > {2} and `person_group_members`.`age` = {3} " +
|
||||
"return `person`"
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildsQueryWithSort() {
|
||||
query.addRestriction(new Part("name",Person.class));
|
||||
assertThat(query.toString(new Sort("person.name")), is("start person=node:Person(name={0}) return person order by person.name ASC"));
|
||||
assertThat(query.toString(new Sort("person.name")), is("start `person`=node:`Person`(`name`={0}) return `person` order by person.name ASC"));
|
||||
}
|
||||
@Test
|
||||
public void buildsQueryWithTwoSorts() {
|
||||
query.addRestriction(new Part("name",Person.class));
|
||||
Sort sort = new Sort(new Sort.Order("person.name"),new Sort.Order(Sort.Direction.DESC, "person.age"));
|
||||
assertThat(query.toString(sort), is("start person=node:Person(name={0}) return person order by person.name ASC,person.age DESC"));
|
||||
assertThat(query.toString(sort), is("start `person`=node:`Person`(`name`={0}) return `person` order by person.name ASC,person.age DESC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildsQueryWithPage() {
|
||||
query.addRestriction(new Part("name",Person.class));
|
||||
Pageable pageable = new PageRequest(3,10,new Sort("person.name"));
|
||||
assertThat(query.toString(pageable), is("start person=node:Person(name={0}) return person order by person.name ASC skip 30 limit 10"));
|
||||
assertThat(query.toString(pageable), is("start `person`=node:`Person`(`name`={0}) return `person` order by person.name ASC skip 30 limit 10"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user