/** * 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.graphdb.traversal; import java.util.HashSet; import java.util.Set; import org.neo4j.graphdb.Path; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; /** * Common {@link Evaluator}s useful during common traversals. * * @author Mattias Persson * @see Evaluator * @see TraversalDescription */ public abstract class Evaluators { private static final Evaluator ALL = new Evaluator() { public Evaluation evaluate( Path path ) { return Evaluation.INCLUDE_AND_CONTINUE; } }; private static final Evaluator ALL_BUT_START_POSITION = new Evaluator() { public Evaluation evaluate( Path path ) { return path.length() == 0 ? Evaluation.EXCLUDE_AND_CONTINUE : Evaluation.INCLUDE_AND_CONTINUE; } }; /** * @return an evaluator which includes everything it encounters and doesn't prune * anything. */ public static Evaluator all() { return ALL; } /** * @return an evaluator which never prunes and includes everything except * the first position, i.e. the the start node. */ public static Evaluator excludeStartPosition() { return ALL_BUT_START_POSITION; } /** * Returns an {@link Evaluator} which includes positions down to {@code depth} * and prunes everything deeper than that. * * @param depth the max depth to traverse to. * @return Returns an {@link Evaluator} which includes positions down to * {@code depth} and prunes everything deeper than that. */ public static Evaluator toDepth( final int depth ) { return new Evaluator() { public Evaluation evaluate( Path path ) { return path.length() < depth ? Evaluation.INCLUDE_AND_CONTINUE : Evaluation.INCLUDE_AND_PRUNE; } }; } /** * Returns an {@link Evaluator} which only includes positions from {@code depth} * and deeper and never prunes anything. * * @param depth the depth to start include positions from. * @return Returns an {@link Evaluator} which only includes positions from * {@code depth} and deeper and never prunes anything. */ public static Evaluator fromDepth( final int depth ) { return new Evaluator() { public Evaluation evaluate( Path path ) { return path.length() < depth ? Evaluation.EXCLUDE_AND_CONTINUE : Evaluation.INCLUDE_AND_CONTINUE; } }; } /** * Returns an {@link Evaluator} which only includes positions at {@code depth} * and prunes everything deeper than that. * * @param depth the depth to start include positions from. * @return Returns an {@link Evaluator} which only includes positions at * {@code depth} and prunes everything deeper than that. */ public static Evaluator atDepth( final int depth ) { return new Evaluator() { public Evaluation evaluate( Path path ) { return path.length() < depth ? Evaluation.EXCLUDE_AND_CONTINUE : Evaluation.INCLUDE_AND_PRUNE; } }; } /** * Returns an {@link Evaluator} which only includes positions between * depths {@code minDepth} and {@code maxDepth}. It prunes everything deeper * than {@code maxDepth}. * * @param minDepth minimum depth a position must have to be included. * @param maxDepth maximum depth a position must have to be included. * @return Returns an {@link Evaluator} which only includes positions between * depths {@code minDepth} and {@code maxDepth}. It prunes everything deeper * than {@code maxDepth}. */ public static Evaluator includingDepths( final int minDepth, final int maxDepth ) { return new Evaluator() { public Evaluation evaluate( Path path ) { int length = path.length(); return Evaluation.of( length >= minDepth && length <= maxDepth, length < maxDepth ); } }; } /** * Returns an {@link Evaluator} which compares the type of the last relationship * in a {@link Path} to a given set of relationship types (one or more).If the type of * the last relationship in a path is of one of the given types then * {@code evaluationIfMatch} will be returned, otherwise * {@code evaluationIfNoMatch} will be returned. * * @param evaluationIfMatch the {@link Evaluation} to return if the type of the * last relationship in the path matches any of the given types. * @param evaluationIfNoMatch the {@link Evaluation} to return if the type of the * last relationship in the path doesn't match any of the given types. * @param type the (first) type (of possibly many) to match the last relationship * in paths with. * @param orAnyOfTheseTypes additional types to match the last relationship in * paths with. * @return an {@link Evaluator} which compares the type of the last relationship * in a {@link Path} to a given set of relationship types. */ public static Evaluator lastRelationshipTypeIs( final Evaluation evaluationIfMatch, final Evaluation evaluationIfNoMatch, RelationshipType type, RelationshipType... orAnyOfTheseTypes ) { final Set<String> expectedTypes = new HashSet<String>(); expectedTypes.add( type.name() ); for ( RelationshipType otherType : orAnyOfTheseTypes ) { expectedTypes.add( otherType.name() ); } return new Evaluator() { @Override public Evaluation evaluate( Path path ) { Relationship lastRelationship = path.lastRelationship(); if ( lastRelationship == null ) { return evaluationIfNoMatch; } return expectedTypes.contains( lastRelationship.getType().name() ) ? evaluationIfMatch : evaluationIfNoMatch; } }; } /** * @see #lastRelationshipTypeIs(Evaluation, Evaluation, RelationshipType, RelationshipType...). * Uses {@link Evaluation#INCLUDE_AND_CONTINUE} for {@code evaluationIfMatch} * and {@link Evaluation#EXCLUDE_AND_CONTINUE} for {@code evaluationIfNoMatch}. * * @param type the (first) type (of possibly many) to match the last relationship * in paths with. * @param orAnyOfTheseTypes additional types to match the last relationship in * paths with. * @return an {@link Evaluator} which compares the type of the last relationship * in a {@link Path} to a given set of relationship types. */ public static Evaluator returnWhereLastRelationshipTypeIs( RelationshipType type, RelationshipType... orAnyOfTheseTypes ) { return lastRelationshipTypeIs( Evaluation.INCLUDE_AND_CONTINUE, Evaluation.EXCLUDE_AND_CONTINUE, type, orAnyOfTheseTypes ); } /** * @see #lastRelationshipTypeIs(Evaluation, Evaluation, RelationshipType, RelationshipType...). * Uses {@link Evaluation#INCLUDE_AND_PRUNE} for {@code evaluationIfMatch} * and {@link Evaluation#INCLUDE_AND_CONTINUE} for {@code evaluationIfNoMatch}. * * @param type the (first) type (of possibly many) to match the last relationship * in paths with. * @param orAnyOfTheseTypes additional types to match the last relationship in * paths with. * @return an {@link Evaluator} which compares the type of the last relationship * in a {@link Path} to a given set of relationship types. */ public static Evaluator pruneWhereLastRelationshipTypeIs( RelationshipType type, RelationshipType... orAnyOfTheseTypes ) { return lastRelationshipTypeIs( Evaluation.INCLUDE_AND_PRUNE, Evaluation.EXCLUDE_AND_CONTINUE, type, orAnyOfTheseTypes ); } }