DATAGRAPH-389 : Derived Queries for Labels - part 1
This commit is contained in:
committed by
Michael Hunger
parent
7ca8959caf
commit
4c1be9925a
@@ -23,15 +23,13 @@ import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.LabelBasedNodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
public class CypherQuery implements CypherQueryDefinition {
|
||||
private final VariableContext variableContext = new VariableContext();
|
||||
@@ -79,15 +77,8 @@ public class CypherQuery implements CypherQueryDefinition {
|
||||
if (!addedStartClause(partInfo)) {
|
||||
whereClauses.add(new WhereClause(partInfo,template));
|
||||
}
|
||||
} else if (leafProperty.isRelationship()) {
|
||||
startClauses.add(new NodeEntityMatchingStartClause(partInfo));
|
||||
if (useLabels) {
|
||||
whereClauses.add(new LabelBasedTypeRestrictingWhereClause(new PartInfo(path, variableContext.getVariableFor(entity), part, -1), entity, template));
|
||||
} else {
|
||||
whereClauses.add(new IndexBasedTypeRestrictingWhereClause(new PartInfo(path, variableContext.getVariableFor(entity), part, -1), entity, template));
|
||||
}
|
||||
} else if (leafProperty.isIdProperty()) {
|
||||
startClauses.add(new NodeEntityMatchingStartClause(partInfo));
|
||||
} else if (leafProperty.isRelationship() || leafProperty.isIdProperty()) {
|
||||
startClauses.add(new GraphIdStartClause(partInfo));
|
||||
if (useLabels) {
|
||||
whereClauses.add(new LabelBasedTypeRestrictingWhereClause(new PartInfo(path, variableContext.getVariableFor(entity), part, -1), entity, template));
|
||||
} else {
|
||||
@@ -128,11 +119,19 @@ public class CypherQuery implements CypherQueryDefinition {
|
||||
|
||||
private boolean addedStartClause(PartInfo partInfo) {
|
||||
if (!partInfo.isIndexed()) return false;
|
||||
for (StartClause startClause : startClauses) {
|
||||
// only merge when same index and same variable
|
||||
|
||||
ListIterator<StartClause> it = startClauses.listIterator();
|
||||
while (it.hasNext()) {
|
||||
StartClause startClause = it.next();
|
||||
if (startClause.sameIdentifier(partInfo)) {
|
||||
if (startClause.sameIndex(partInfo)) {
|
||||
startClause.merge(partInfo);
|
||||
if (startClause.hasMultipleParts()) {
|
||||
// Replace it as we could not detect this initially ...
|
||||
List<PartInfo> newList = new ArrayList<PartInfo>();
|
||||
newList.addAll(startClause.getPartInfos());
|
||||
it.set(StartClauseFactory.create(newList));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// must stop b/c of invalid combination (same identifier but different index)
|
||||
@@ -140,7 +139,7 @@ public class CypherQuery implements CypherQueryDefinition {
|
||||
}
|
||||
}
|
||||
}
|
||||
startClauses.add(new StartClause(partInfo));
|
||||
startClauses.add(StartClauseFactory.create(partInfo));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,52 +173,82 @@ public class CypherQuery implements CypherQueryDefinition {
|
||||
}
|
||||
|
||||
private String render() {
|
||||
|
||||
String startClauses = collectionToDelimitedString(this.startClauses, ", ");
|
||||
String matchClauses = toQueryString(this.matchClauses);
|
||||
String whereClauses = collectionToDelimitedString(this.whereClauses, " AND ");
|
||||
|
||||
StringBuilder builder = new StringBuilder("");
|
||||
boolean startClauseInUse = renderStartClauses(builder, startClauses);
|
||||
renderMatchClauses(builder, matchClauses, startClauseInUse);
|
||||
renderWhereClauses(builder, whereClauses);
|
||||
renderReturnClauses(builder);
|
||||
|
||||
boolean matchKeyWordUsed = false;
|
||||
boolean startClauseUsed = buildStartClauseIfRequired(builder, startClauses);
|
||||
if (!startClauseUsed && useLabels) {
|
||||
matchKeyWordUsed = true;
|
||||
builder.append(" MATCH ").append(defaultMatchBasedStartClause(entity));
|
||||
}
|
||||
if (hasText(matchClauses)) {
|
||||
builder.append(matchKeyWordUsed ? " , " : " MATCH ");
|
||||
builder.append(matchClauses);
|
||||
}
|
||||
|
||||
if (hasText(whereClauses)) {
|
||||
builder.append(" WHERE ").append(whereClauses);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void renderReturnClauses(StringBuilder builder) {
|
||||
String returnEntity = String.format(QueryTemplates.VARIABLE,getEntityName(entity));
|
||||
if (isCountQuery) {
|
||||
builder.append(" RETURN ").append("count(").append(returnEntity).append(")");
|
||||
} else {
|
||||
builder.append(" RETURN ").append(returnEntity);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void renderWhereClauses(StringBuilder builder, String whereClauses) {
|
||||
if (hasText(whereClauses)) {
|
||||
builder.append(" WHERE ").append(whereClauses);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderMatchClauses(StringBuilder builder, String matchClauses, boolean startClauseInUse) {
|
||||
if (hasText(matchClauses)) {
|
||||
builder.append(" MATCH ").append(matchClauses);
|
||||
return;
|
||||
}
|
||||
if (useLabelBasedTRS() && !startClauseInUse) {
|
||||
builder.append(" MATCH ").append(defaultMatchBasedStartClause(entity));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This will change to get rid of the start clauses completely but
|
||||
* for now we just get it to work!
|
||||
* From Neo4j 2.0 onwards the start clause is optional (although still needs to be
|
||||
* used for certain cases where index lookups are required etc. This method takes
|
||||
* the currently built up query in builder (which should be empty at this point)
|
||||
* and begins to add in any currently defined start clauses. In the absence of
|
||||
* any start clauses, it will add in the default start clause if using an indexing
|
||||
* strtegy.
|
||||
*
|
||||
* @param builder current query which has been built up
|
||||
* @param startClauses List of current start clauses
|
||||
* @return true if this method resulted in the query having a START clause
|
||||
* applied to it otherwise false
|
||||
*/
|
||||
private boolean buildStartClauseIfRequired(StringBuilder builder, String startClauses) {
|
||||
private boolean renderStartClauses(StringBuilder builder, String startClauses) {
|
||||
if (hasText(startClauses)) {
|
||||
builder.append("START ").append(startClauses);
|
||||
return true;
|
||||
} else if (!useLabels) {
|
||||
// TODO: Need to change index based stuff to also not use START
|
||||
}
|
||||
if (useIndexBasedTRS()) {
|
||||
builder.append("START ").append(defaultIndexBasedStartClause(entity));
|
||||
return true;
|
||||
}
|
||||
|
||||
// For a label based strategy, we do not use a start clause
|
||||
// but rather begin with a MATCH clause
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean useIndexBasedTRS() {
|
||||
return !useLabels;
|
||||
}
|
||||
|
||||
private boolean useLabelBasedTRS() {
|
||||
return useLabels;
|
||||
}
|
||||
|
||||
|
||||
private String addSorts(Sort sort) {
|
||||
final List<String> sorts = formatSorts(sort);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright 2013 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.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a start clause which makes use of an exact index
|
||||
* match.
|
||||
*
|
||||
* @author Nicki Watt
|
||||
*/
|
||||
public class ExactIndexBasedStartClause extends IndexBasedStartClause {
|
||||
|
||||
public ExactIndexBasedStartClause(PartInfo partInfo) {
|
||||
super(partInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final PartInfo partInfo = getPartInfo();
|
||||
final String identifier = partInfo.getIdentifier();
|
||||
final String indexName = partInfo.getIndexName();
|
||||
final int parameterIndex = partInfo.getParameterIndex();
|
||||
return String.format(QueryTemplates.START_CLAUSE_INDEX_LOOKUP, identifier, indexName, partInfo.getNeo4jPropertyName(), parameterIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Parameter, Object> resolveParameters(Map<Parameter, Object> parameters, Neo4jTemplate template) {
|
||||
Map<Parameter, PartInfo> myParameters = findMyParameters(parameters.keySet());
|
||||
|
||||
Map<Parameter, Object> result = new LinkedHashMap<Parameter, Object>(parameters);
|
||||
result.keySet().removeAll(myParameters.keySet());
|
||||
|
||||
final Map<PartInfo, Object> values = matchToPartsAndConvert(myParameters, parameters,template);
|
||||
|
||||
Parameter firstParam = IteratorUtil.first(myParameters.keySet());
|
||||
Object value=IteratorUtil.first(values.values());
|
||||
result.put(firstParam, value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright 2013 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.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a start clause which makes use of a full text index
|
||||
* based match against one or more parts.
|
||||
*
|
||||
* @author Nicki Watt
|
||||
*/
|
||||
public class FullTextIndexBasedStartClause extends IndexBasedStartClause {
|
||||
|
||||
public FullTextIndexBasedStartClause(PartInfo partInfo) {
|
||||
super(partInfo);
|
||||
}
|
||||
|
||||
public FullTextIndexBasedStartClause(List<PartInfo> partInfos) {
|
||||
super(partInfos.get(0));
|
||||
int i = 0;
|
||||
for (PartInfo partInfo: partInfos) {
|
||||
if (i != 0) {
|
||||
this.merge(partInfo);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final PartInfo partInfo = getPartInfo();
|
||||
final String identifier = partInfo.getIdentifier();
|
||||
final String indexName = partInfo.getIndexName();
|
||||
final int parameterIndex = partInfo.getParameterIndex();
|
||||
return String.format(QueryTemplates.START_CLAUSE_INDEX_QUERY, identifier, indexName, parameterIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Parameter, Object> resolveParameters(Map<Parameter, Object> parameters, Neo4jTemplate template) {
|
||||
Map<Parameter, PartInfo> myParameters = findMyParameters(parameters.keySet());
|
||||
|
||||
Map<Parameter, Object> result = new LinkedHashMap<Parameter, Object>(parameters);
|
||||
result.keySet().removeAll(myParameters.keySet());
|
||||
|
||||
final Map<PartInfo, Object> values = matchToPartsAndConvert(myParameters, parameters,template);
|
||||
|
||||
Parameter firstParam = IteratorUtil.first(myParameters.keySet());
|
||||
result.put(firstParam, renderQuery(values));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2013 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.
|
||||
@@ -20,8 +20,15 @@ import org.springframework.data.repository.query.Parameter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NodeEntityMatchingStartClause extends StartClause {
|
||||
public NodeEntityMatchingStartClause(PartInfo partInfo) {
|
||||
/**
|
||||
* Represents a start clause where the actual graph id
|
||||
* of the entity is used.
|
||||
*
|
||||
* @author Nicki Watt
|
||||
*/
|
||||
public class GraphIdStartClause extends StartClause {
|
||||
|
||||
public GraphIdStartClause(PartInfo partInfo) {
|
||||
super(partInfo);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2013 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.
|
||||
@@ -15,16 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.repository.query;
|
||||
|
||||
public class IndexRestrictingStartClause extends StartClause {
|
||||
private final String className;
|
||||
/**
|
||||
* Abstract class which represents a start clause which makes
|
||||
* use of an indexof some sort.
|
||||
*
|
||||
* @author Nicki Watt
|
||||
*/
|
||||
abstract class IndexBasedStartClause extends StartClause {
|
||||
|
||||
public IndexRestrictingStartClause(PartInfo partInfo, String className) {
|
||||
public IndexBasedStartClause(PartInfo partInfo) {
|
||||
super(partInfo);
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(QueryTemplates.DEFAULT_INDEXBASED_START_CLAUSE, getPartInfo().getIdentifier(), className);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* This class represents ....
|
||||
* All the information about a particular part of a Neo4jPersistentProperty?
|
||||
* @author mh
|
||||
* @since 31.10.11
|
||||
*/
|
||||
|
||||
@@ -27,60 +27,33 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* Representation of a Cypher {@literal start} clause.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
// TODO id-startclause, index-startclause (exact,point,fulltext)
|
||||
class StartClause {
|
||||
abstract class StartClause {
|
||||
|
||||
private final SortedMap<Integer,PartInfo> partInfos=new TreeMap<Integer, PartInfo> ();
|
||||
|
||||
/**
|
||||
* Creates a new {@link StartClause} from the given {@link Neo4jPersistentProperty}, variable and the given
|
||||
* parameter index.
|
||||
* Creates a new {@link StartClause} from the given {@link Neo4jPersistentProperty},
|
||||
* variable and the given parameter index.
|
||||
*/
|
||||
public StartClause(PartInfo partInfo) {
|
||||
this.partInfos.put(partInfo.getParameterIndex(), partInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final PartInfo partInfo = getPartInfo();
|
||||
final String identifier = partInfo.getIdentifier();
|
||||
final String indexName = partInfo.getIndexName();
|
||||
final int parameterIndex = partInfo.getParameterIndex();
|
||||
// fulltext or multiple
|
||||
if (shouldRenderQuery()) {
|
||||
return String.format(QueryTemplates.START_CLAUSE_INDEX_QUERY, identifier, indexName, parameterIndex);
|
||||
}
|
||||
// exact and single
|
||||
return String.format(QueryTemplates.START_CLAUSE_INDEX_LOOKUP, identifier, indexName, partInfo.getNeo4jPropertyName(), parameterIndex);
|
||||
/**
|
||||
* Returns true if this start clause comprises of multiple parts
|
||||
* @return
|
||||
*/
|
||||
protected boolean hasMultipleParts() {
|
||||
return partInfos.size() > 1;
|
||||
}
|
||||
|
||||
private boolean shouldRenderQuery() {
|
||||
PartInfo partInfo = getPartInfo();
|
||||
return partInfo.isFullText() || EnumSet.of(Part.Type.LIKE,Part.Type.STARTING_WITH,Part.Type.CONTAINING,Part.Type.ENDING_WITH).contains(partInfo.getType())|| partInfos.size() > 1;
|
||||
}
|
||||
|
||||
public Map<Parameter, Object> resolveParameters(Map<Parameter, Object> parameters, Neo4jTemplate template) {
|
||||
Map<Parameter, PartInfo> myParameters = findMyParameters(parameters.keySet());
|
||||
public abstract Map<Parameter, Object> resolveParameters(Map<Parameter, Object> parameters, Neo4jTemplate template);
|
||||
|
||||
Map<Parameter, Object> result = new LinkedHashMap<Parameter, Object>(parameters);
|
||||
result.keySet().removeAll(myParameters.keySet());
|
||||
|
||||
final Map<PartInfo, Object> values = matchToPartsAndConvert(myParameters, parameters,template);
|
||||
|
||||
Parameter firstParam = IteratorUtil.first(myParameters.keySet());
|
||||
if (shouldRenderQuery()) {
|
||||
result.put(firstParam, renderQuery(values));
|
||||
} else {
|
||||
Object value=IteratorUtil.first(values.values());
|
||||
result.put(firstParam, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String renderQuery(Map<PartInfo, Object> values) {
|
||||
protected String renderQuery(Map<PartInfo, Object> values) {
|
||||
StringBuilder sb=new StringBuilder();
|
||||
for (Map.Entry<PartInfo, Object> entry : values.entrySet()) {
|
||||
if (sb.length()>0) sb.append(" AND ");
|
||||
@@ -91,7 +64,7 @@ class StartClause {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Map<PartInfo, Object> matchToPartsAndConvert(Map<Parameter, PartInfo> myParameters, Map<Parameter, Object> parameters, Neo4jTemplate template) {
|
||||
protected Map<PartInfo, Object> matchToPartsAndConvert(Map<Parameter, PartInfo> myParameters, Map<Parameter, Object> parameters, Neo4jTemplate template) {
|
||||
Map<PartInfo, Object> result = new LinkedHashMap<PartInfo, Object>();
|
||||
for (Map.Entry<Parameter, PartInfo> entry : myParameters.entrySet()) {
|
||||
Object value = parameters.get(entry.getKey());
|
||||
@@ -103,15 +76,15 @@ class StartClause {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object convertIfNecessary(Neo4jTemplate template, Object value, Neo4jPersistentProperty property) {
|
||||
if (property.isIndexedNumerically()) return new ValueContext(value).indexNumeric();
|
||||
protected Object convertIfNecessary(Neo4jTemplate template, Object value, Neo4jPersistentProperty property) {
|
||||
if (property.isIndexedNumerically()) return new ValueContext(value).indexNumeric();
|
||||
if (property.isNeo4jPropertyType() && property.isNeo4jPropertyValue(value)) return value;
|
||||
|
||||
PropertyConverter converter = new PropertyConverter(template.getConversionService(), property);
|
||||
return converter.serializePropertyValue(value);
|
||||
}
|
||||
|
||||
private Map<Parameter,PartInfo> findMyParameters(Set<Parameter> parameters) {
|
||||
protected Map<Parameter,PartInfo> findMyParameters(Set<Parameter> parameters) {
|
||||
Map<Parameter,PartInfo> result=new LinkedHashMap<Parameter, PartInfo>();
|
||||
for (Parameter parameter : parameters) {
|
||||
PartInfo partInfo = partInfos.get(parameter.getIndex());
|
||||
@@ -149,4 +122,10 @@ class StartClause {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Collection<PartInfo> getPartInfos() {
|
||||
return partInfos.values();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2013 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.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is responsible for creating appropriate StartClause
|
||||
* instances depending on the part(s) it is being created from.
|
||||
*
|
||||
* @author Nicki Watt
|
||||
*/
|
||||
public class StartClauseFactory {
|
||||
|
||||
/**
|
||||
* At present, Multiple parts are always assumed to result in a
|
||||
* a FullTextIndexBasedStartClause
|
||||
* @param partInfos The various parts which the start clause
|
||||
* needs to be created around/for.
|
||||
* @return A appropriate StartClause
|
||||
*/
|
||||
public static StartClause create(List<PartInfo> partInfos) {
|
||||
return (partInfos.size() == 1)
|
||||
? create(partInfos.get(0))
|
||||
: new FullTextIndexBasedStartClause(partInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a particular partInfo, create an appropriate StartClause
|
||||
* instance
|
||||
*
|
||||
* @param partInfo The part which the start clause needs to be
|
||||
* created around/for.
|
||||
* @return A appropriate StartClause
|
||||
*/
|
||||
public static StartClause create(PartInfo partInfo) {
|
||||
if (partInfo.isIndexed()) {
|
||||
return (partInfo.isFullText() || isTextualSearchLikePart(partInfo))
|
||||
? new FullTextIndexBasedStartClause(partInfo)
|
||||
: new ExactIndexBasedStartClause(partInfo);
|
||||
}
|
||||
|
||||
Neo4jPersistentProperty leafProperty = partInfo.getLeafProperty();
|
||||
if (leafProperty.isRelationship() || leafProperty.isIdProperty()) {
|
||||
return new GraphIdStartClause(partInfo);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot determine an appropriate Start Clause for partInfo=" + partInfo );
|
||||
}
|
||||
|
||||
private static boolean isTextualSearchLikePart(PartInfo partInfo) {
|
||||
return EnumSet.of(Part.Type.LIKE,Part.Type.STARTING_WITH,Part.Type.CONTAINING,Part.Type.ENDING_WITH).contains(partInfo.getType());
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractDerivedFinderMethodTestBase {
|
||||
protected Object[] trsSpecificExpectedParams;
|
||||
|
||||
@Test
|
||||
public void testCreateIndexQuery() throws Exception {
|
||||
public void testCypherQueryBuilderWithTwoIndexedParams() throws Exception {
|
||||
CypherQueryBuilder builder = new CypherQueryBuilder(ctx, Thing.class, template);
|
||||
builder.addRestriction(new Part("firstName",Thing.class));
|
||||
builder.addRestriction(new Part("lastName",Thing.class));
|
||||
@@ -111,6 +111,7 @@ public abstract class AbstractDerivedFinderMethodTestBase {
|
||||
assertEquals(
|
||||
getExpectedQuery("START `thing`=node:`Thing`({0}) RETURN `thing`"),
|
||||
query.toQueryString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user