/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypherdsl;
import static org.neo4j.cypherdsl.query.Query.checkEmpty;
import static org.neo4j.cypherdsl.query.Query.checkNull;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.neo4j.cypherdsl.expression.All;
import org.neo4j.cypherdsl.expression.BooleanExpression;
import org.neo4j.cypherdsl.expression.CollectionExpression;
import org.neo4j.cypherdsl.expression.Expression;
import org.neo4j.cypherdsl.expression.NumericExpression;
import org.neo4j.cypherdsl.expression.PathExpression;
import org.neo4j.cypherdsl.expression.PropertyContainerExpression;
import org.neo4j.cypherdsl.expression.ReferenceExpression;
import org.neo4j.cypherdsl.expression.RelationshipExpression;
import org.neo4j.cypherdsl.expression.ScalarExpression;
import org.neo4j.cypherdsl.expression.StartExpression;
import org.neo4j.cypherdsl.expression.StringExpression;
import org.neo4j.cypherdsl.expression.NodeExpression;
import org.neo4j.cypherdsl.grammar.*;
import org.neo4j.cypherdsl.query.AbstractExpression;
import org.neo4j.cypherdsl.query.ExpressionCollection;
import org.neo4j.cypherdsl.query.Expressions;
import org.neo4j.cypherdsl.query.Extract;
import org.neo4j.cypherdsl.query.Filter;
import org.neo4j.cypherdsl.query.FunctionExpression;
import org.neo4j.cypherdsl.query.IterablePredicateExpression;
import org.neo4j.cypherdsl.query.LabelValue;
import org.neo4j.cypherdsl.query.NamedPath;
import org.neo4j.cypherdsl.query.Operator;
import org.neo4j.cypherdsl.query.OrderByExpression;
import org.neo4j.cypherdsl.query.PropertyValue;
import org.neo4j.cypherdsl.query.Query;
import org.neo4j.cypherdsl.query.SuffixFunctionExpression;
import org.neo4j.cypherdsl.query.Value;
import org.neo4j.cypherdsl.query.clause.*;
/**
* DSL for creating Cypher queries. Once created you can serialize to a string,
* or retrieve the internal Query model for further processing.
* <p/>
* It is possible to iteratively construct Cypher queries by calling toQuery()
* and then use the Query as continuation point. When a new CypherQuery is created
* by using the newQuery() method the Query is cloned, so that the original Query
* is not modified. This can be used effectively to create a base query which can then
* be used many times. Typical examples would be to create a query which is reused many times
* for paging purposes, and also to provide a base query using START and MATCH which is then
* expanded using WHERE and RETURN clauses.
*/
public class CypherQuery
{
/**
* Start building a new Cypher query, starting with a START clause
*
* @param startExpressions list of start expressions
* @return Grammar for Match clause
*/
public static StartNext start( StartExpression... startExpressions )
{
CypherQuery query = new CypherQuery();
return query.starts( startExpressions );
}
/**
* Start building a new Cypher query, starting with a MATCH clause
*
* @param paths
* @return
*/
public static StartNext match( PathExpression... paths )
{
CypherQuery query = new CypherQuery();
return query.matches(paths);
}
/**
* Start building a new Cypher query, starting with a CREATE clause
*
* @param paths
* @return
*/
public static UpdateNext create( PathExpression... paths )
{
CypherQuery query = new CypherQuery();
return query.creates( paths );
}
/**
* Start building a new Cypher query, starting with a MERGE clause
*
* @param paths
* @return
*/
public static UpdateNext merge( PathExpression... paths )
{
CypherQuery query = new CypherQuery();
return query.merges(paths);
}
/**
* Continue building on existing Query object
*
* @param query a previously created query object
* @return CypherQuery DSL that can be used to continue building the query
*/
public static <T> T continueQuery( Query query, Class<T> asClause )
throws ClassCastException
{
try
{
return new CypherQuery( (Query) query.clone() ).continueQuery( asClause );
}
catch ( CloneNotSupportedException e )
{
throw new RuntimeException( e );
}
}
// The internal query object. Methods in the DSL work on this
protected final Query query;
/**
* Use this constructor if you want to use the instantiation block style
* of using the DSL.
* <p/>
* Example:
* <pre>
* new CypherQuery()
* {{
* starts(node("n",1)).returns(identifier("n"));
* }}.toString()
* </pre>
*/
public CypherQuery()
{
query = new Query();
}
private CypherQuery( Query query )
{
try
{
this.query = (Query) query.clone();
}
catch ( CloneNotSupportedException e )
{
throw new IllegalStateException( "Query was not cloneable" );
}
}
// Common -------------------------------------------------------
/**
* Declare a Cypher query parameter.
* This will be replaced with {name}.
*
* @param name of the parameter
* @return Parameter instance
*/
public static Parameter param( String name )
{
checkEmpty( name, "Name" );
return new Parameter( name );
}
/**
* Declare a label.
*
* @param label literal value
* @return Label instance
*/
public static LabelValue label( String label )
{
return new LabelValue( identifier( label ) );
}
/**
* Declare a label.
*
* @param label literal value
* @return Label instance
*/
public static LabelValue label( Identifier label )
{
return new LabelValue( label );
}
/**
* Declare a literal string value, such as "Foo".
*
* @param value literal value
* @return Literal instance
*/
public static StringExpression literal( String value )
{
checkNull( value, "Value" );
return new Literal( value );
}
/**
* Declare a literal numeric value, such 3 or 4.5.
*
* @param value literal value
* @return Literal instance
*/
public static NumericExpression literal( Number value )
{
checkNull( value, "Value" );
return new Literal( value );
}
/**
* Declare a literal boolean value, such as true or false.
*
* @param value literal value
* @return Literal instance
*/
public static BooleanExpression literal( boolean value )
{
return new Literal( value );
}
/**
* Declare a literal value using an untyped object.
* <p/>
* If a string is passed in, then output will
* be quoted appropriately.
*
* @param value literal value
* @return Literal instance
*/
public static ScalarExpression literal( Object value )
{
checkNull( value, "Value" );
return new Literal( value );
}
/**
* Declare an identifier. This is used to
* refer to names declared elsewhere in the query.
* <p/>
* If you want to refer to properties, then create
* this first, and then call e.g. id.property("propname")
*
* @param name
* @return
*/
public static Identifier identifier( String name )
{
checkEmpty( name, "Identifier" );
return new Identifier( name );
}
/**
* Declare a collection of expressions. Values may be Expressions or literal values
* that are converted to Literal expressions by this method.
* <p/>
* Corresponds to:
* <pre>
* [value1,value2,value3]
* </pre>
*
* @param values
* @return
*/
public static CollectionExpression collection( Object... values )
{
Expression[] expressions = new Expression[values.length];
for ( int i = 0; i < values.length; i++ )
{
Object value = values[i];
expressions[i] = value instanceof Expression ? (Expression) value : literal( value );
}
return new Value( new ExpressionCollection( new Expressions( expressions ) ) );
}
/**
* Declare a list of identifiers.
*
* @param values
* @return
*/
public static Identifier[] identifiers( String... values )
{
Identifier[] identifiers = new Identifier[values.length];
for ( int i = 0; i < values.length; i++ )
{
String value = values[i];
identifiers[i] = identifier( value );
}
return identifiers;
}
/**
* Declare a list of parameters.
*
* @param names
* @return
*/
public static Parameter[] parameters( String... names )
{
Parameter[] parameters = new Parameter[names.length];
for ( int i = 0; i < names.length; i++ )
{
String value = names[i];
parameters[i] = param( value );
}
return parameters;
}
/**
* Declare a list of literals using longs. This can be handy
* for the nodesById method.
*
* @param values
* @return
*/
public static NumericExpression[] literals( long... values )
{
NumericExpression[] literals = new NumericExpression[values.length];
for ( int i = 0; i < values.length; i++ )
{
long value = values[i];
literals[i] = literal( value );
}
return literals;
}
/**
* Declare a value, which can be used for setting or matching
* properties in the CREATE or CREATE UNIQUE clauses.
*
* @param id
* @param value
* @return
*/
public static PropertyValue value( String id, Object value )
{
return new PropertyValue( identifier( id ), literal( value ) );
}
/**
* Declare a value, which can be used for setting or matching
* properties in the CREATE or CREATE UNIQUE clauses.
*
* @param id
* @param value
* @return
*/
public static PropertyValue value( String id, Expression value )
{
return new PropertyValue( identifier( id ), value );
}
/**
* Declare a value, which can be used for setting or matching
* properties in the CREATE or CREATE UNIQUE clauses.
*
* @param id
* @param value
* @return
*/
public static PropertyValue value( Identifier id, Expression value )
{
return new PropertyValue( id, value );
}
/**
* "and" a series of expressions together.
*
* @param expressions
* @return
*/
public static BooleanExpression and( BooleanExpression... expressions )
{
Query.checkNull( expressions, "Expressions" );
return new And( expressions );
}
/**
* "or" a series of expressions together.
*
* @param expressions
* @return
*/
public static BooleanExpression or( BooleanExpression... expressions )
{
Query.checkNull( expressions, "Expressions" );
return new Or( expressions );
}
/**
* Invert the boolean value of a predicate.
* <p/>
* Corresponds to:
* <pre>
* not(expression)
* </pre>
*
* @param expression
* @return
*/
public static BooleanExpression not( BooleanExpression expression )
{
Query.checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "not", expression ) );
}
/**
* Corresponds to:
* <pre>
* has(property)
* </pre>
*
* @param property
* @return
*/
public static BooleanExpression has( Property property )
{
return new Value( new FunctionExpression( "has", property ) );
}
/**
* Corresponds to:
* <pre>
* has(expression)
* </pre>
*
* @param expression
* @return
*/
public static BooleanExpression has( Expression expression )
{
return new Value( new FunctionExpression( "has", expression ) );
}
/**
* Corresponds to:
* <pre>
* expression is null
* </pre>
*
* @param expression
* @return
*/
public static BooleanExpression isNull( Expression expression )
{
return new Value( new SuffixFunctionExpression( " is null", expression ) );
}
/**
* Corresponds to:
* <pre>
* expression is not null
* </pre>
*
* @param expression
* @return
*/
public static BooleanExpression isNotNull( Expression expression )
{
return new Value( new SuffixFunctionExpression( " is not null", expression ) );
}
// Start --------------------------------------------------------
/**
* START clause. Use this with Java initialization block style.
*
* @param startExpressions
* @return
*/
protected StartNext starts( StartExpression... startExpressions )
{
query.add( new StartClause( Arrays.asList( startExpressions ) ) );
return new Grammar();
}
/**
* START clause. Use this with Java initialization block style.
*
* @param startExpressions
* @return
*/
protected StartNext starts( Iterable<StartExpression> startExpressions )
{
query.add( new StartClause( startExpressions ) );
return new Grammar();
}
/**
* CREATE clause. Use this with Java initialization block style.
*
* @param paths
* @return
*/
protected UpdateNext creates( PathExpression... paths )
{
query.add( new CreateClause( Arrays.asList( paths ) ) );
return new Grammar();
}
/**
* MERGE clause. Use this with Java initialization block style.
*
* @param paths
* @return
*/
protected UpdateNext merges( PathExpression... paths )
{
query.add( new MergeClause( Arrays.asList( paths ) ) );
return new Grammar();
}
/**
* MATCH clause. Use this with Java initialization block style.
*
* @param paths
* @return
*/
protected StartNext matches( PathExpression... paths )
{
query.add( new MatchClause( Arrays.asList( paths ) ) );
return new Grammar();
}
protected <T> T continueQuery( Class<T> asClause )
throws ClassCastException
{
return asClause.cast( new Grammar() );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node(id1,id2,id3)
* </pre>
*
* @param name
* @param id
* @return
*/
public static StartExpression.StartNodes nodesById( String name, long... id )
{
return nodesById( identifier( name ), id );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node(id1,id2,id3)
* </pre>
*
* @param name
* @param id
* @return
*/
public static StartExpression.StartNodes nodesById( Identifier name, long... id )
{
checkNull( name, "Name" );
for ( long i : id )
{
if ( i < 0 )
{
throw new IllegalArgumentException( "Id may not be below zero" );
}
}
return new StartExpression.StartNodes( name, literals( id ) );
}
@Deprecated
public static StartExpression.StartNodes nodeByParameter( String name, String parameter )
{
return nodesByParameter( name, parameter );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node({parameter})
* </pre>
*
* @param name
* @param parameter
* @return
*/
public static StartExpression.StartNodes nodesByParameter( String name, String parameter )
{
return nodesByParameter( identifier( name ), parameter );
}
@Deprecated
public static StartExpression.StartNodes nodeByparameter( Identifier name, String parameter )
{
return nodesByParameter( name, parameter );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node({parameter})
* </pre>
*
* @param name
* @param parameter
* @return
*/
public static StartExpression.StartNodes nodesByParameter( Identifier name, String parameter )
{
checkEmpty( name, "Name" );
checkEmpty( parameter, "Parameters" );
return new StartExpression.StartNodes( name, parameters( parameter ) );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node(*)
* </pre>
*
* @param name
* @return
*/
public static StartExpression.StartNodes allNodes( String name )
{
return allNodes( identifier( name ) );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node(*)
* </pre>
*
* @param name
* @return
*/
public static StartExpression.StartNodes allNodes( Identifier name )
{
checkNull( name, "Name" );
return new StartExpression.StartNodes( name, new Expression[]{new StartExpression.AllNodes()} );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName(key="value")
* </pre>
*
* @param name
* @param indexName
* @param key
* @param value
* @return
*/
public static StartExpression.StartNodesLookup lookup( String name, String indexName, String key, String value )
{
return lookup( identifier( name ), identifier( indexName ), identifier( key ), literal( value ) );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName(key="value")
* </pre>
*
* @param name
* @param indexName
* @param key
* @param value
* @return
*/
public static StartExpression.StartNodesLookup lookup( Identifier name, Identifier indexName,
ReferenceExpression key, StringExpression value )
{
checkEmpty( name, "Name" );
checkEmpty( indexName, "Index" );
return new StartExpression.StartNodesLookup( name, indexName, key, value );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName("query")
* </pre>
*
* @param name
* @param indexName
* @param query
* @return
*/
public static StartExpression.StartNodesQuery query( String name, String indexName, String query )
{
return query( identifier( name ), identifier( indexName ), query );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName("query")
* </pre>
*
* @param name
* @param indexName
* @param query
* @return
*/
public static StartExpression.StartNodesQuery query( Identifier name, Identifier indexName, String query )
{
checkNull( name, "Name" );
checkNull( indexName, "Index" );
checkEmpty( query, "Query" );
return new StartExpression.StartNodesQuery( name, indexName, query );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName({param}")
* </pre>
*
* @param name
* @param indexName
* @param param
* @return
*/
public static StartExpression.StartNodesQueryParam queryByParameter( String name, String indexName, String param )
{
return queryByParameter( identifier( name ), identifier( indexName ), param );
}
/**
* Declare start nodes. Corresponds to:
* <pre>
* name=node:indexName({param})
* </pre>
*
* @param name
* @param indexName
* @param param
* @return
*/
public static StartExpression.StartNodesQueryParam queryByParameter( Identifier name, Identifier indexName,
String param )
{
checkNull( name, "Name" );
checkNull( indexName, "Index" );
checkEmpty( param, "Param" );
return new StartExpression.StartNodesQueryParam( name, indexName, param );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship(id1,id2,id3)
* </pre>
*
* @param name
* @param id
* @return
*/
public static StartExpression.StartRelationships relationshipsById( String name, long... id )
{
return relationshipsById( identifier( name ), id );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship(id1,id2,id3)
* </pre>
*
* @param name
* @param id
* @return
*/
public static StartExpression.StartRelationships relationshipsById( Identifier name, long... id )
{
checkNull( name, "Name" );
for ( long i : id )
{
if ( i < 0 )
{
throw new IllegalArgumentException( "Id may not be below zero" );
}
}
return new StartExpression.StartRelationships( name, literals( id ) );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship({parameter})
* </pre>
*
* @param name
* @param parameter
* @return
*/
public static StartExpression.StartRelationshipsParameters relationshipsByParameter( String name, String parameter )
{
return relationshipsByParameter( identifier( name ), parameter );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship({parameter})
* </pre>
*
* @param name
* @param parameter
* @return
*/
public static StartExpression.StartRelationshipsParameters relationshipsByParameter( Identifier name,
String parameter
)
{
checkNull( name, "Name" );
checkEmpty( parameter, "Parameter" );
return new StartExpression.StartRelationshipsParameters( name, parameter );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship:indexName(key="value")
* </pre>
*
* @param name
* @param indexName
* @param key
* @param value
* @return
*/
public static StartExpression.StartRelationshipsIndex relationshipLookup( String name, String indexName,
String key, String value )
{
return relationshipLookup( identifier( name ), identifier( indexName ), identifier( key ), literal( value ) );
}
/**
* Declare start relationships. Corresponds to:
* <pre>
* name=relationship:indexName(key="value")
* </pre>
*
* @param name
* @param indexName
* @param key
* @param value
* @return
*/
public static StartExpression.StartRelationshipsIndex relationshipLookup( Identifier name, Identifier indexName,
Identifier key, StringExpression value )
{
checkNull( name, "Name" );
checkNull( indexName, "Index" );
checkNull( key, "Key" );
checkNull( value, "Value" );
return new StartExpression.StartRelationshipsIndex( name, indexName, key, value );
}
// Match --------------------------------------------------------
/**
* Start declaring a path for CREATE, CREATE UNIQUE, MATCH or WHERE clauses.
* <p/>
* Corresponds to:
* <pre>
* ()
* </pre>
*
* @return
*/
public static Path node()
{
return new Path( null, null, null, null );
}
/**
* Start declaring a path for CREATE, CREATE UNIQUE, MATCH or WHERE clauses.
* <p/>
* Corresponds to:
* <pre>
* (id)
* </pre>
*
* @param id
* @return
*/
public static Path node( String id )
{
return node( identifier( id ) );
}
/**
* Start declaring a path for CREATE, CREATE UNIQUE, MATCH or WHERE clauses.
* <p/>
* Corresponds to:
* <pre>
* (expression)
* </pre>
*
* @param expression
* @return
*/
public static Path node( Expression expression )
{
return new Path( expression, null, null, null );
}
/**
* Declare a named path for MATCH clauses
* <p/>
* Corresponds to:
* <pre>
* name=path
* </pre>
*
* @param name
* @return
*/
public static PathExpression path( String name, PathExpression path )
{
return path( identifier( name ), path );
}
/**
* Declare a named path for MATCH clauses
* <p/>
* Corresponds to:
* <pre>
* name=path
* </pre>
*
* @param name
* @return
*/
public static PathExpression path( Identifier name, PathExpression path )
{
checkNull( name, "Name" );
return new NamedPath( name, path );
}
/**
* Use this to declare a shortestPath.
* <p/>
* Corresponds to:
* <pre>
* shortestPath(path)
* </pre>
*
* @param path
* @return
*/
public static PathExpression shortestPath( PathExpression path )
{
Query.checkNull( path, "Path" );
return new Value( new FunctionExpression( "shortestPath", path ) );
}
/**
* Use this to declare a allShortestPaths
* <p/>
* Corresponds to:
* <pre>
* allShortestPaths(path)
* </pre>
*
* @param path
* @return
*/
public static PathExpression allShortestPaths( PathExpression path )
{
Query.checkNull( path, "Path" );
return new Value( new FunctionExpression( "allShortestPaths", path ) );
}
// Return -------------------------------------------------------
/**
* Use this to rename identifiers for RETURN or WITH
* <p/>
* Corresponds to:
* <pre>
* expression AS name
* </pre>
*
* @param expression
* @param name
* @return
*/
public static Expression as( Expression expression, String name )
{
return new Value( new Operator( expression, " AS " ), identifier( name ) );
}
/**
* Use this to rename identifiers for RETURN or WITH
* <p/>
* Corresponds to:
* <pre>
* expression AS name
* </pre>
*
* @param expression
* @param name
* @return
*/
public static Expression as( Expression expression, Identifier name )
{
return new Value( new Operator( expression, " AS " ), name );
}
/**
* Use this to declare DISTINCT
* <p/>
* Corresponds to:
* <pre>
* DISTINCT expression
* </pre>
*
* @param expression
* @return
*/
public static Expression distinct( Expression expression )
{
return new Value( new Operator( "DISTINCT " ), expression );
}
/**
* Declare a count(*) RETURN expression
*
* @return
*/
public static NumericExpression count()
{
return new Value( new FunctionExpression( "count", new AbstractExpression()
{
@Override
public void asString( StringBuilder builder )
{
builder.append( '*' );
}
} ) );
}
/**
* Declare a count(expression) RETURN expression
*
* @return
*/
public static NumericExpression count( Expression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "count", expression ) );
}
/**
* Declare a * RETURN expression
*/
public static All all()
{
return new All();
}
/**
* Declare a sum(expression) RETURN expression
*
* @return
*/
public static NumericExpression sum( NumericExpression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "sum", expression ) );
}
/**
* Declare a avg(expression) RETURN expression
*
* @return
*/
public static NumericExpression avg( Expression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "avg", expression ) );
}
/**
* Declare a max(expression) RETURN expression
*
* @return
*/
public static NumericExpression max( NumericExpression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "max", expression ) );
}
/**
* Declare a min(expression) RETURN expression
*
* @return
*/
public static NumericExpression min( NumericExpression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "min", expression ) );
}
/**
* Declare a collect(expression) RETURN expression
*
* @return
*/
public static CollectionExpression collect( ScalarExpression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "collect", expression ) );
}
// Order by -----------------------------------------------------
/**
* Declare an ORDER clause expression. Typically used with identifier("n").property("property") as
* parameter.
*
* @param expression
* @return
*/
public static OrderByExpression order( Expression expression )
{
Query.checkNull( expression, "Expression" );
return new OrderByExpression( expression, null );
}
/**
* Declare an ORDER clause expression, with either ASCENDING or DESCENDING order
* explicitly set. Typically used with identifier("n").property("property") as
* parameter.
*
* @param expression
* @param order
* @return
*/
public static OrderByExpression order( Expression expression, Order order )
{
Query.checkNull( expression, "Name" );
Query.checkNull( order, "Order" );
return new OrderByExpression( expression, order );
}
// For each -----------------------------------------------------
/**
* Use this to create expressions for use with the FOR EACH clause. Use
* the fluent API of ForEachStatements to create the statements to be evaluated
* in the FOR EACH clause.
*
* @param id
* @param in
* @return
*/
public static ForEachStatements in( String id, Expression in )
{
return new ForEachClause( identifier( id ), in );
}
/**
* Use this to create expressions for use with the FOR EACH clause. Use
* the fluent API of ForEachStatements to create the statements to be evaluated
* in the FOR EACH clause.
*
* @param id
* @param in
* @return
*/
public static ForEachStatements in( Identifier id, Expression in )
{
return new ForEachClause( id, in );
}
// Set ----------------------------------------------------------
/**
* Use this to set properties in the SET clause.
* <p/>
* Corresponds to:
* <pre>
* property=value
* </pre>
*
* @param property
* @param value
* @return
*/
public static SetProperty property( Property property, Expression value )
{
return new SetProperty( property, value );
}
// Functions ----------------------------------------------------
/**
* Declare an ALL expression. Corresponds to:
* <pre>
* ALL(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression all( String name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
return all( identifier( name ), iterable, predicateExpression );
}
/**
* Declare an ALL expression. Corresponds to:
* <pre>
* ALL(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression all( Identifier name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( predicateExpression, "Predicate" );
return new Value( new IterablePredicateExpression( "all", name, iterable, predicateExpression ) );
}
/**
* Declare an ANY expression. Corresponds to:
* <pre>
* ANY(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression any( String name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
return any( identifier( name ), iterable, predicateExpression );
}
/**
* Declare an ANY expression. Corresponds to:
* <pre>
* ANY(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression any( Identifier name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( predicateExpression, "Predicate" );
return new Value( new IterablePredicateExpression( "any", name, iterable, predicateExpression ) );
}
/**
* Declare a NONE expression. Corresponds to:
* <pre>
* NONE(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression none( String name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
return none( identifier( name ), iterable, predicateExpression );
}
/**
* Declare a NONE expression. Corresponds to:
* <pre>
* NONE(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression none( Identifier name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( predicateExpression, "Predicate" );
return new Value( new IterablePredicateExpression( "none", name, iterable, predicateExpression ) );
}
/**
* Declare a SINGLE expression. Corresponds to:
* <pre>
* SINGLE(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression single( String name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
return single( identifier( name ), iterable, predicateExpression );
}
/**
* Declare a SINGLE expression. Corresponds to:
* <pre>
* SINGLE(name IN iterable WHERE expression)
* </pre>
*
* @param name
* @param iterable
* @param predicateExpression
* @return
*/
public static BooleanExpression single( Identifier name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( predicateExpression, "Predicate" );
return new Value( new IterablePredicateExpression( "single", name, iterable, predicateExpression ) );
}
// Scalar expressions
/**
* Declare a length expression. Corresponds to:
* <pre>
* length(iterable)
* </pre>
*
* @param expression
* @return
*/
public static NumericExpression length( CollectionExpression expression )
{
checkNull( expression, "Expression" );
return new Value( new FunctionExpression( "length", expression ) );
}
/**
* Declare a type expression. Corresponds to:
* <pre>
* type(relationship)
* </pre>
*
* @param relationshipExpression
* @return
*/
public static StringExpression type( RelationshipExpression relationshipExpression )
{
checkNull( relationshipExpression, "Expression" );
return new Value( new FunctionExpression( "type", relationshipExpression ) );
}
/**
* Declare an id expression. Corresponds to:
* <pre>
* id(name)
* </pre>
*
* @param name
* @return
*/
public static NumericExpression id( String name )
{
checkNull( name, "Name" );
return new Value( new FunctionExpression( "id", identifier( name ) ) );
}
/**
* Declare an id expression. Corresponds to:
* <pre>
* id(propertyContainer)
* </pre>
*
* @param propertyContainerExpression
* @return
*/
public static NumericExpression id( PropertyContainerExpression propertyContainerExpression )
{
checkNull( propertyContainerExpression, "Expression" );
return new Value( new FunctionExpression( "id", propertyContainerExpression ) );
}
/**
* Declare a coalesce expression. Corresponds to:
* <pre>
* coalesce(expression1,expression2,expression3)
* </pre>
*
* @param expressions
* @return
*/
public static Value coalesce( Expression... expressions )
{
if ( expressions.length < 1 )
{
throw new IllegalArgumentException( "At least one expression must be provided to coalesce function" );
}
return new Value( new FunctionExpression( "coalesce", new Expressions( expressions ) ) );
}
/**
* Declare a head expression. Corresponds to:
* <pre>
* head(collection)
* </pre>
*
* @param collectionExpression
* @return
*/
public static Expression head( CollectionExpression collectionExpression )
{
checkNull( collectionExpression, "Expression" );
return new Value( new FunctionExpression( "head", collectionExpression ) );
}
/**
* Declare a last expression. Corresponds to:
* <pre>
* last(collection)
* </pre>
*
* @param collectionExpression
* @return
*/
public static Expression last( CollectionExpression collectionExpression )
{
checkNull( collectionExpression, "Expression" );
return new Value( new FunctionExpression( "last", collectionExpression ) );
}
// Iterable expressions
/**
* Declare a nodes expression. Corresponds to:
* <pre>
* nodes(path)
* </pre>
*
* @param pathExpression
* @return
*/
public static CollectionExpression nodes( PathExpression pathExpression )
{
checkNull( pathExpression, "Expression" );
return new Value( new FunctionExpression( "nodes", pathExpression ) );
}
/**
* Declare a relationships expression. Corresponds to:
* <pre>
* relationships(path)
* </pre>
*
* @param pathExpression
* @return
*/
public static CollectionExpression relationships( PathExpression pathExpression )
{
checkNull( pathExpression, "Expression" );
return new Value( new FunctionExpression( "relationships", pathExpression ) );
}
/**
* Declare a labels expression. Corresponds to:
* <pre>
* labels(node)
* </pre>
*
* @param nodeExpression
* @return
*/
public static CollectionExpression labels( NodeExpression nodeExpression )
{
checkNull( nodeExpression, "Expression" );
return new Value( new FunctionExpression( "labels", nodeExpression ) );
}
/**
* Declare an extract expression. Corresponds to:
* <pre>
* extract(name IN iterable : expression)
* </pre>
*
* @param iterable
* @param expression
* @return
*/
public static CollectionExpression extract( String name, CollectionExpression iterable,
ScalarExpression expression )
{
return extract( identifier( name ), iterable, expression );
}
/**
* Declare an extract expression. Corresponds to:
* <pre>
* extract(name IN iterable : expression)
* </pre>
*
* @param iterable
* @param expression
* @return
*/
public static CollectionExpression extract( Identifier name, CollectionExpression iterable,
ScalarExpression expression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( expression, "Expression" );
return new Value( new Extract( name, iterable, expression ) );
}
/**
* Declare a filter expression. Corresponds to:
* <pre>
* filter(name IN iterable : predicate)
* </pre>
*
* @param iterable
* @param predicateExpression
* @return
*/
public static CollectionExpression filter( String name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
return filter( identifier( name ), iterable, predicateExpression );
}
/**
* Declare a filter expression. Corresponds to:
* <pre>
* filter(name IN iterable : predicate)
* </pre>
*
* @param iterable
* @param predicateExpression
* @return
*/
public static CollectionExpression filter( Identifier name, CollectionExpression iterable,
BooleanExpression predicateExpression )
{
Query.checkNull( name, "Name" );
Query.checkNull( iterable, "Iterable" );
Query.checkNull( predicateExpression, "Predicate" );
return new Value( new Filter( name, iterable, predicateExpression ) );
}
/**
* Declare a tail expression. Corresponds to:
* <pre>
* tail(collectionExpression)
* </pre>
*
* @param collectionExpression
* @return
*/
public static CollectionExpression tail( CollectionExpression collectionExpression )
{
checkNull( collectionExpression, "Expression" );
return new Value( new FunctionExpression( "tail", collectionExpression ) );
}
/**
* Declare a range expression. Corresponds to:
* <pre>
* range(start,end)
* </pre>
*
* @param start
* @param end
* @return
*/
public static CollectionExpression range( Number start, Number end )
{
return range( literal( start ), literal( end ), null );
}
/**
* Declare a range expression. Corresponds to:
* <pre>
* range(start,end,step)
* </pre>
*
* @param start
* @param end
* @param step
* @return
*/
public static CollectionExpression range( Number start, Number end, Number step )
{
return range( literal( start ), literal( end ), literal( step ) );
}
/**
* Declare a range expression. Corresponds to:
* <pre>
* range(start,end)
* </pre>
*
* @param start
* @param end
* @return
*/
public static CollectionExpression range( NumericExpression start, NumericExpression end )
{
return range( start, end, null );
}
/**
* Declare a range expression. Corresponds to:
* <pre>
* range(start,end,step)
* </pre>
*
* @param start
* @param end
* @param step
* @return
*/
public static CollectionExpression range( NumericExpression start, NumericExpression end, NumericExpression step )
{
if ( step == null )
{
return new Value( new FunctionExpression( "range", new Expressions( new Expression[]{start, end} ) ) );
}
else
{
return new Value( new FunctionExpression( "range", new Expressions( new Expression[]{start, end,
step} ) ) );
}
}
// Mathematical expressions
/**
* Declare extra parentheses. This can be useful to ensure that operators are performed in the order you desire.
* <p/>
* Corresponds to:
* <pre>
* (numericExpression)
* </pre>
*/
public static NumericExpression p( NumericExpression numericExpression )
{
return new Value( new FunctionExpression( "", numericExpression ) );
}
/**
* Declare an abs expression. Corresponds to:
* <pre>
* abs(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression abs( Number numericalExpression )
{
return abs( literal( numericalExpression ) );
}
/**
* Declare an abs expression. Corresponds to:
* <pre>
* abs(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression abs( NumericExpression numericalExpression )
{
return new Value( new FunctionExpression( "abs", numericalExpression ) );
}
/**
* Declare a round function. Corresponds to:
* <pre>
* round(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression round( Number numericalExpression )
{
return round( literal( numericalExpression ) );
}
/**
* Declare a round function. Corresponds to:
* <pre>
* round(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression round( NumericExpression numericalExpression )
{
return new Value( new FunctionExpression( "round", numericalExpression ) );
}
/**
* Declare a sqrt expression. Corresponds to:
* <pre>
* sqrt(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression sqrt( Number numericalExpression )
{
return sqrt( literal( numericalExpression ) );
}
/**
* Declare a sqrt expression. Corresponds to:
* <pre>
* sqrt(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression sqrt( NumericExpression numericalExpression )
{
return new Value( new FunctionExpression( "sqrt", numericalExpression ) );
}
/**
* Declare a sign expression. Corresponds to:
* <pre>
* sign(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression sign( Number numericalExpression )
{
return sign( literal( numericalExpression ) );
}
/**
* Declare a sign expression. Corresponds to:
* <pre>
* sign(expression)
* </pre>
*
* @param numericalExpression
* @return
*/
public static NumericExpression sign( NumericExpression numericalExpression )
{
return new Value( new FunctionExpression( "sign", numericalExpression ) );
}
@Override
public String toString()
{
return query.toString();
}
// Grammar
protected class Grammar
implements StartNext, With, WithNext, Create, Set, Delete, Remove, CreateUnique, Merge, UpdateNext, Match, ReturnNext,
OrderBy,
Skip, Limit, Execute, Union, UnionNext
{
// With ---------------------------------------------------------
public WithNext with( Expression... withExpressions )
{
query.add( new WithClause( Arrays.asList( withExpressions ) ) );
return this;
}
@Override
public WithNext with( Iterable<Expression> withExpressions )
{
query.add( new WithClause( withExpressions ) );
return this;
}
// Union ---------------------------------------------------------
@Override
public UnionNext union()
{
query.add( new UnionClause() );
return this;
}
@Override
public UnionNext all()
{
UnionClause unionClause = query.lastClause(UnionClause.class);
if (unionClause != null) {
unionClause.all();
}
return this;
}
// Create -------------------------------------------------------
@Override
public UpdateNext create( PathExpression... paths )
{
query.add( new CreateClause( Arrays.asList( paths ) ) );
return this;
}
@Override
public UpdateNext create( Iterable<PathExpression> paths )
{
query.add( new CreateClause( paths ) );
return this;
}
// Set ----------------------------------------------------------
@Override
public UpdateNext set( SetProperty... setProperties )
{
query.add( new SetClause( Arrays.asList( setProperties ) ) );
return this;
}
@Override
public UpdateNext set( Iterable<SetProperty> setProperties )
{
query.add( new SetClause( setProperties ) );
return this;
}
// Delete -------------------------------------------------------
@Override
public UpdateNext delete( ReferenceExpression... expressions )
{
query.add( new DeleteClause( Arrays.asList( expressions ) ) );
return this;
}
@Override
public UpdateNext delete( Iterable<ReferenceExpression> expressions )
{
query.add( new DeleteClause( expressions ) );
return this;
}
// Remove -------------------------------------------------------
@Override
public UpdateNext remove( ReferenceExpression... expressions )
{
query.add( new RemoveClause( Arrays.asList( expressions ) ) );
return this;
}
@Override
public UpdateNext remove( Iterable<ReferenceExpression> expressions )
{
query.add( new RemoveClause( expressions ) );
return this;
}
// createUnique -------------------------------------------------------
@Override
public UpdateNext createUnique( PathExpression... expressions )
{
query.add( new CreateUniqueClause( Arrays.asList( expressions ) ) );
return this;
}
@Override
public UpdateNext createUnique( Iterable<PathExpression> expressions )
{
query.add( new CreateUniqueClause( expressions ) );
return this;
}
// merge -------------------------------------------------------
@Override
public UpdateNext merge( PathExpression... expressions )
{
query.add( new MergeClause( Arrays.asList( expressions ) ) );
return this;
}
@Override
public UpdateNext merge( Iterable<PathExpression> expressions )
{
query.add( new MergeClause( expressions ) );
return this;
}
// For each -----------------------------------------------------
@Override
public UpdateNext forEach( ForEachStatement statement )
{
query.add( statement.getClause() );
return this;
}
// Start --------------------------------------------------------
@Override
public StartNext starts( StartExpression... startExpression )
{
query.add( new StartClause( Arrays.asList( startExpression ) ) );
return this;
}
@Override
public StartNext starts( Iterable<StartExpression> startExpression )
{
query.add( new StartClause( startExpression ) );
return this;
}
// Match --------------------------------------------------------
@Override
public Match match( PathExpression... expressions )
{
query.add( new MatchClause( Arrays.asList( expressions ) ) );
return this;
}
@Override
public Match match( Iterable<PathExpression> expressions )
{
query.add( new MatchClause( expressions ) );
return this;
}
@Override
public Match optional() {
MatchClause matchClause = query.lastClause(MatchClause.class);
if (matchClause != null) {
matchClause.optional();
}
return this;
}
// Where --------------------------------------------------------
@Override
public Where where( BooleanExpression expression )
{
Query.checkNull( expression, "Expression" );
query.add( new WhereClause( expression ) );
return this;
}
// Return -------------------------------------------------------
@Override
public ReturnNext returns( Expression... returnExpressions )
{
query.add( new ReturnClause( Arrays.asList( returnExpressions ) ) );
return this;
}
@Override
public ReturnNext returns( Iterable<Expression> returnExpressions )
{
query.add( new ReturnClause( returnExpressions ) );
return this;
}
// OrderBy ------------------------------------------------------
@Override
public OrderBy orderBy( Expression... orderByExpressions )
{
query.add( new OrderByClause( Arrays.asList( orderByExpressions ) ) );
return this;
}
@Override
public OrderBy orderBy( Iterable<Expression> orderByExpressions )
{
query.add( new OrderByClause( orderByExpressions ) );
return this;
}
// Skip ---------------------------------------------------------
@Override
public Limit skip( int skip )
{
if ( skip < 0 )
{
throw new IllegalArgumentException( "Skip may not be below zero" );
}
query.add( new SkipClause( skip ) );
return this;
}
// Skip ---------------------------------------------------------
@Override
public Limit skip( String skip )
{
query.add( new SkipParameterClause( skip ) );
return this;
}
// Limit --------------------------------------------------------
@Override
public Execute limit( int limit )
{
if ( limit < 0 )
{
throw new IllegalArgumentException( "Limit may not be below zero" );
}
query.add( new LimitClause( limit ) );
return this;
}
// Limit --------------------------------------------------------
@Override
public Execute limit( String limit )
{
query.add( new LimitParameterClause( limit ) );
return this;
}
// Execute ------------------------------------------------------
@Override
public void asString( StringBuilder builder )
{
query.asString( builder );
}
@Override
public Query toQuery()
{
return query;
}
@Override
public ExecuteWithParameters parameter( String name, Object value )
{
return new ExecuteWithParams( query ).parameter( name, value );
}
@Override
public ExecuteWithParameters parameters( Map<String, Object> parameters )
{
return new ExecuteWithParams( query ).parameters( parameters );
}
@Override
public String toString()
{
return CypherQuery.this.toString();
}
}
protected class ExecuteWithParams
implements ExecuteWithParameters
{
private final Query query;
private final Map<String, Object> parameters = new HashMap<String, Object>();
public ExecuteWithParams( Query query )
{
this.query = query;
}
@Override
public Query toQuery()
{
return query;
}
public Map<String, Object> getParameters()
{
return parameters;
}
@Override
public ExecuteWithParameters parameter( String name, Object value )
{
this.parameters.put( name, value );
return this;
}
@Override
public ExecuteWithParameters parameters( Map<String, Object> parameters )
{
this.parameters.putAll( parameters );
return this;
}
@Override
public void asString( StringBuilder builder )
{
query.asString( builder );
}
@Override
public String toString()
{
return query.toString();
}
}
public static class And
extends Value
{
public And( BooleanExpression[] value )
{
super( new Expressions( value ) );
}
@Override
public void asString( StringBuilder builder )
{
Expressions expressions = (Expressions) value;
for ( int i = 0; i < expressions.expressions.length; i++ )
{
Expression expression = expressions.expressions[i];
if ( i > 0 )
{
builder.append( " and " );
}
if ( expression instanceof And || expression instanceof Or )
{
builder.append( '(' );
expression.asString( builder );
builder.append( ')' );
}
else
{
expression.asString( builder );
}
}
}
}
public static class Or
extends Value
{
public Or( BooleanExpression[] value )
{
super( new Expressions( value ) );
}
@Override
public void asString( StringBuilder builder )
{
Expressions expressions = (Expressions) value;
for ( int i = 0; i < expressions.expressions.length; i++ )
{
Expression expression = expressions.expressions[i];
if ( i > 0 )
{
builder.append( " or " );
}
if ( expression instanceof And )
{
builder.append( '(' );
expression.asString( builder );
builder.append( ')' );
}
else
{
expression.asString( builder );
}
}
}
}
}