Package org.neo4j.cypherdsl

Source Code of org.neo4j.cypherdsl.CypherQuery

/**
* 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 );
                }
            }
        }
    }
}
TOP

Related Classes of org.neo4j.cypherdsl.CypherQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.