# http://docs.neo4j.org/chunked/snapshot/rest-api-traverse.html#rest-api-traversal-returning-nodes-below-a-certain-depth try: import simplejson as json except ImportError: import json from neo4jrestclient import client from neo4jrestclient.request import Request from neo4jrestclient.request import NotFoundError from neo4jrestclient.request import StatusException class Order(object): BREADTH_FIRST = "breadth_first" DEPTH_FIRST = "depth_first" class Uniqueness(object): NODE_GLOBAL = "node_global" NONE = "none" RELATIONSHIP_GLOBAL = "relationship_global" NODE_PATH = "node_path" RELATIONSHIP_PATH = "relationship_path" class RelationshipDirection(object): ALL = "all" INCOMING = "in" OUTGOING = "out" class Filters(object): """Filters answer the question (return true/false) Evaluation.INCLUDE_AND_CONTINUE Evaluation.EXCLUDE_AND_CONTINUE """ ALL = {"language":"builtin", "name":"all"} ALL_BUT_START_NODE = {"language":"builtin", "name":"all_but_start_node"} class PruneEvaluators(object): """PruneEvaluators answer the question (return true/false) Evaluation.INCLUDE_AND_PRUNE Evaluation.EXCLUDE_AND_PRUNE """ pass class Traverser(object): NODE = "node" RELATIONSHIP = "relationship" PATH = "path" FULLPATH = "fullpath" def __init__(self, start_node, data): self._data = data self._endpoint = "http://localhost:7474/db/data/node/" + str(start_node.id) + "/traverse" self._cache = {} def request(self, return_type): try: return self._cache[return_type] except KeyError: response, content = Request().post(self._endpoint + '/' + return_type, data=self._data) if response.status == 200: results_list = json.loads(content) self._cache[return_type] = results_list return results_list elif response.status == 404: raise NotFoundError(response.status, "Node or relationship " \ "not found") raise StatusException(response.status, "Invalid data sent") @property def nodes(self): results = self.request(Traverser.NODE) return client.Iterable(client.Node, results, "self") @property def relationships(self): results = self.request(Traverser.RELATIONSHIP) return client.Iterable(client.Relationship, results, "self") @property def fullpaths(self): raise NotImplementedError() def __iter__(self): results = self.request(Traverser.PATH) return client.Iterable(client.Path, results, "self") class TraversalDescription(object): """https://github.com/neo4j/community/blob/master/kernel/src/main/java/org/neo4j/graphdb/traversal/TraversalDescription.java""" def __init__(self): self._data = {} self.uniqueness(Uniqueness.NODE_GLOBAL) self.max_depth(1) def uniqueness(self, value): self._data["uniqueness"] = value return self def filter(self, value): try: value["language"] self._data["return_filter"] = value except KeyError: self._data["return_filter"] = {"language":"javascript", "body":value} return self def prune(self, value, language="javascript"): try: value["language"] self._data["prune_evaluator"] = value except KeyError: self._data["prune_evaluator"] = {"language":language, "body":value} def order(self, value): self._data["order"] = value return self def depthFirst(self, value): self.order(Order.DEPTH_FIRST) return self def breadthFirst(self, value): self.order(Order.BREADTH_FIRST) return self def relationships(self, name, direction=RelationshipDirection.ALL): self._data["relationships"] = [] self.relationships_append(name, direction) self.relationships = self.relationships_append return self def relationships_append(self, name, direction=RelationshipDirection.ALL): self._data["relationships"].append({"direction":direction, "type":name}) return self def max_depth(self, value): self._data["max_depth"] = value def traverse(self, start_node): try: self._data['prune_evaluator'] del self._data["max_depth"] except KeyError: pass return Traverser(start_node, self._data) class Traversal(object): def __init__(self, start_node): self._description = Traversal.description() self._start_node = start_node @property def description(self): return self._description def __iter__(self): return self._description.traverse(self._start_node)