/** * 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 java.util.Arrays.asList; import static org.neo4j.cypherdsl.CypherQuery.identifier; import java.io.Serializable; import org.neo4j.cypherdsl.expression.Expression; import org.neo4j.cypherdsl.query.Direction; import org.neo4j.cypherdsl.query.PropertyValue; import org.neo4j.cypherdsl.query.PropertyValues; import org.neo4j.cypherdsl.query.Query; /** * Represents a relationship in a path. */ public class PathRelationship implements AsString, Serializable, Cloneable { public final Path leftNode; public final Direction direction; // null indicates that the path is only a start-node public final Identifier as; public final Iterable<Identifier> relationships; public final PropertyValues relationshipPropertyValues; public final Integer minHops; public final Integer maxHops; PathRelationship(Path leftNode, Direction direction, Identifier as, Iterable<Identifier> relationships, PropertyValues relationshipPropertyValues, Integer minHops, Integer maxHops) { this.leftNode = leftNode; this.direction = direction; this.as = as; this.relationships = relationships; this.relationshipPropertyValues = relationshipPropertyValues; this.minHops = minHops; this.maxHops = maxHops; } /** * If this relationship is used in a CREATE or CREATE UNIQUE clause, * then you can use this method to specify property values. * Use e.g. {@link CypherQuery.value( String,Object )} to create * the individual values to be passed in here. * <p/> * Corresponds to: * <pre> * (n)-[:relationship {prop1:value1,prop2:value2}) * </pre> * * @param propertyValues * @return */ public PathRelationship values( PropertyValue... propertyValues ) { return new PathRelationship( leftNode, direction, as, relationships, new PropertyValues( asList( propertyValues ) ), minHops, maxHops ); } /** * If this relationship is used in a CREATE or CREATE UNIQUE clause, * then you can use this method to specify property values. * Use e.g. {@link CypherQuery.value( String,Object )} to create * the individual values to be passed in here. * <p/> * Corresponds to: * <pre> * (n)-[:relationship {prop1:value1,prop2:value2}) * </pre> * * @param propertyValues * @return */ public PathRelationship values( Iterable<PropertyValue> propertyValues ) { return new PathRelationship( leftNode, direction, as, relationships, new PropertyValues( propertyValues ), minHops, maxHops ); } /** * Use this method to name a relationship * <p/> * Corresponds to: * <pre> * (n)-[name]-(m) * </pre> * * @param name * @return */ public PathRelationship as( String name ) { return as( CypherQuery.identifier( name ) ); } /** * Use this method to name a relationship * <p/> * Corresponds to: * <pre> * (n)-[name]-(m) * </pre> * * @param name * @return */ public PathRelationship as( Identifier name ) { Query.checkNull( name, "Name" ); return new PathRelationship( leftNode, direction, name, relationships, relationshipPropertyValues, minHops, maxHops ); } /** * Use this method to declare how many hops are allowed. You can either specify * min, max or both. * <p/> * Corresponds to: * <pre> * (n)-[:*minHops,maxHops]-(m) * </pre> * * @param minHops * @param maxHops * @return */ public PathRelationship hops( Integer minHops, Integer maxHops ) { if ( minHops != null && minHops < 0 ) { throw new IllegalArgumentException( "Minimum number of hops must be over zero" ); } if ( maxHops != null && maxHops < 0 ) { throw new IllegalArgumentException( "Maximum number of hops must be over zero" ); } return new PathRelationship( leftNode, direction, as, relationships, relationshipPropertyValues, minHops, maxHops ); } /** * Declare the end node of this path. This must be called before using * this expression in any clause, as otherwise you would not have a complete * path. * <p/> * Corresponds to: * <pre> * (n)--() * </pre> * * @return */ public Path node() { return new Path( null, this, null, null ); } /** * Declare the end node of this path. This must be called before using * this expression in any clause, as otherwise you would not have a complete * path. * <p/> * Corresponds to: * <pre> * (n)--(id) * </pre> * * @return */ public Path node( String id ) { return node( identifier( id ) ); } /** * Declare the end node of this path. This must be called before using * this expression in any clause, as otherwise you would not have a complete * path. * <p/> * Corresponds to: * <pre> * (n)--(id) * </pre> * * @return */ public Path node( Expression id ) { return new Path( id, this, null, null ); } @Override public void asString( StringBuilder builder ) { leftNode.asString( builder ); builder.append( direction.equals( Direction.IN ) ? "<-" : "-" ); boolean hasRelationships = relationships.iterator().hasNext(); if ( as != null || hasRelationships || minHops != null || maxHops != null || relationshipPropertyValues!= null ) { builder.append( '[' ); if ( as != null ) { as.asString(builder); } if ( hasRelationships ) { builder.append( ':' ); String or = ""; for ( Identifier relationship : relationships ) { builder.append( or ); relationship.asString( builder ); or = "|"; } } if ( minHops != null || maxHops != null ) { builder.append( '*' ); if ( minHops != null ) { builder.append( minHops ); } builder.append( ".." ); if ( maxHops != null ) { builder.append( maxHops ); } } if ( relationshipPropertyValues != null ) { builder.append( ' ' ); relationshipPropertyValues.asString( builder ); } builder.append( ']' ); } builder.append( direction.equals( Direction.OUT ) ? "->" : "-" ); } }