Пример #1
0
 def __init__(self, graph, path):
     self.graph = graph
     dbms_uri = remote(self.graph.graph_service).uri
     self.remote = Remote(dbms_uri.rstrip("/") + path)
     try:
         self.remote.get_json("")
     except GraphError:
         raise NotImplementedError("No extension found at path %r on "
                                   "graph <%s>" %
                                   (path, remote(self.graph).uri))
Пример #2
0
 def __eq__(self, other):
     if not isinstance(other, GraphObject):
         return False
     remote_self = remote(self.__ogm__.node)
     remote_other = remote(other.__ogm__.node)
     if remote_self and remote_other:
         return remote_self == remote_other
     else:
         return self.__primarylabel__ == other.__primarylabel__ and \
                self.__primarykey__ == other.__primarykey__ and \
                self.__primaryvalue__ == other.__primaryvalue__
Пример #3
0
    def match(self, start_node=None, rel_type=None, end_node=None, bidirectional=False, limit=None):
        """ Match and return all relationships with specific criteria.

        For example, to find all of Alice's friends::

            for rel in graph.match(start_node=alice, rel_type="FRIEND"):
                print(rel.end_node()["name"])

        :param start_node: start node of relationships to match (:const:`None` means any node)
        :param rel_type: type of relationships to match (:const:`None` means any type)
        :param end_node: end node of relationships to match (:const:`None` means any node)
        :param bidirectional: :const:`True` if reversed relationships should also be included
        :param limit: maximum number of relationships to match (:const:`None` means unlimited)
        """
        clauses = []
        returns = []
        if start_node is None and end_node is None:
            clauses.append("MATCH (a)")
            parameters = {}
            returns.append("a")
            returns.append("b")
        elif end_node is None:
            clauses.append("MATCH (a) WHERE id(a) = {1}")
            start_node = cast_node(start_node)
            if not remote(start_node):
                raise TypeError("Nodes for relationship match end points must be bound")
            parameters = {"1": remote(start_node)._id}
            returns.append("b")
        elif start_node is None:
            clauses.append("MATCH (b) WHERE id(b) = {2}")
            end_node = cast_node(end_node)
            if not remote(end_node):
                raise TypeError("Nodes for relationship match end points must be bound")
            parameters = {"2": remote(end_node)._id}
            returns.append("a")
        else:
            clauses.append("MATCH (a) WHERE id(a) = {1} MATCH (b) WHERE id(b) = {2}")
            start_node = cast_node(start_node)
            end_node = cast_node(end_node)
            if not remote(start_node) or not remote(end_node):
                raise TypeError("Nodes for relationship match end points must be bound")
            parameters = {"1": remote(start_node)._id, "2": remote(end_node)._id}
        if rel_type is None:
            relationship_detail = ""
        elif is_collection(rel_type):
            relationship_detail = ":" + "|:".join(cypher_escape(t) for t in rel_type)
        else:
            relationship_detail = ":%s" % cypher_escape(rel_type)
        if bidirectional:
            clauses.append("MATCH (a)-[_" + relationship_detail + "]-(b)")
        else:
            clauses.append("MATCH (a)-[_" + relationship_detail + "]->(b)")
        returns.append("_")
        clauses.append("RETURN %s" % ", ".join(returns))
        if limit is not None:
            clauses.append("LIMIT %d" % limit)
        cursor = self.run(" ".join(clauses), parameters)
        while cursor.forward():
            record = cursor.current()
            yield record["_"]
Пример #4
0
 def hydrate_(data, inst=None):
     if isinstance(data, dict):
         if "self" in data:
             if "type" in data:
                 return Relationship.hydrate(data["self"], inst=inst, **data)
             else:
                 return Node.hydrate(data["self"], inst=inst, **data)
         elif "nodes" in data and "relationships" in data:
             if "directions" not in data:
                 directions = []
                 relationships = graph.evaluate(
                     "MATCH ()-[r]->() WHERE id(r) IN {x} RETURN collect(r)",
                     x=[int(uri.rpartition("/")[-1]) for uri in data["relationships"]])
                 node_uris = data["nodes"]
                 for i, relationship in enumerate(relationships):
                     if remote(relationship.start_node()).uri == node_uris[i]:
                         directions.append("->")
                     else:
                         directions.append("<-")
                 data["directions"] = directions
             return Path.hydrate(data)
         else:
             # from warnings import warn
             # warn("Map literals returned over the Neo4j REST interface are ambiguous "
             #      "and may be hydrated as graph objects")
             return data
     elif is_collection(data):
         return type(data)(map(hydrate_, data))
     else:
         return data
Пример #5
0
    def password_change_required(self):
        """ Check if a password change is required for the current user.

        :returns: :const:`True` if a password change is required, :const:`False` otherwise
        """
        status = remote(self).get_json("user/{}".format(self.user))
        return status["password_change_required"]
Пример #6
0
 def _related_objects(self):
     if self.__related_objects is None:
         self.__related_objects = []
         remote_node = remote(self.node)
         if remote_node:
             with remote_node.graph.begin() as tx:
                 self.__db_pull__(tx)
     return self.__related_objects
Пример #7
0
 def __primaryvalue__(self):
     node = self.__ogm__.node
     primary_key = self.__primarykey__
     if primary_key == "__id__":
         remote_node = remote(node)
         return remote_node._id if remote_node else None
     else:
         return node[primary_key]
Пример #8
0
 def __db_push__(self, tx):
     related_objects = self._related_objects
     # 1. merge all nodes (create ones that don't)
     for related_object, _ in related_objects:
         tx.merge(related_object)
     # 2a. remove any relationships not in list of nodes
     subject_id = remote(self.node)._id
     tx.run("MATCH %s WHERE id(a) = {x} AND NOT id(b) IN {y} DELETE _" %
            self.__relationship_pattern,
            x=subject_id,
            y=[remote(obj.__ogm__.node)._id for obj, _ in related_objects])
     # 2b. merge all relationships
     for related_object, properties in related_objects:
         tx.run("MATCH (a) WHERE id(a) = {x} MATCH (b) WHERE id(b) = {y} "
                "MERGE %s SET _ = {z}" % self.__relationship_pattern,
                x=subject_id,
                y=remote(related_object.__ogm__.node)._id,
                z=properties)
Пример #9
0
 def __db_delete__(self, tx):
     ogm = self.__ogm__
     remote_node = remote(ogm.node)
     if remote_node:
         tx.run(
             "MATCH (a) WHERE id(a) = {x} OPTIONAL MATCH (a)-[r]->() DELETE r DELETE a",
             x=remote_node._id)
     for related_objects in ogm.related.values():
         related_objects.clear()
Пример #10
0
 def __db_pull__(self, tx):
     ogm = self.__ogm__
     if not remote(ogm.node):
         selector = GraphObjectSelector(self.__class__, tx.graph)
         selector._selection_class = NodeSelection
         ogm.node = selector.select(self.__primaryvalue__).first()
     tx.pull(ogm.node)
     for related_objects in ogm.related.values():
         related_objects.__db_pull__(tx)
Пример #11
0
 def __db_push__(self, tx):
     ogm = self.__ogm__
     node = ogm.node
     if remote(node):
         tx.push(node)
     else:
         primary_key = getattr(node, "__primarykey__", "__id__")
         if primary_key == "__id__":
             tx.create(node)
         else:
             tx.merge(node)
     for related_objects in ogm.related.values():
         related_objects.__db_push__(tx)
Пример #12
0
    def relationship(self, id_):
        """ Fetch a relationship by ID.

        :param id_:
        """
        entity_uri = "%srelationship/%s" % (remote(self).uri, id_)
        try:
            return Relationship.cache[entity_uri]
        except KeyError:
            relationship = self.evaluate("MATCH ()-[r]->() WHERE id(r)={x} RETURN r", x=id_)
            if relationship is None:
                raise IndexError("Relationship %d not found" % id_)
            else:
                return relationship
Пример #13
0
 def __db_merge__(self, tx, primary_label=None, primary_key=None):
     ogm = self.__ogm__
     node = ogm.node
     if primary_label is None:
         primary_label = getattr(node, "__primarylabel__", None)
     if primary_key is None:
         primary_key = getattr(node, "__primarykey__", "__id__")
     if not remote(node):
         if primary_key == "__id__":
             node.add_label(primary_label)
             tx.create(node)
         else:
             tx.merge(node, primary_label, primary_key)
         for related_objects in ogm.related.values():
             related_objects.__db_push__(tx)
Пример #14
0
 def _bean_dict(self, name):
     info = remote(self).get_json("db/manage/server/jmx/domain/org.neo4j")
     raw_config = [b for b in info["beans"] if b["name"].endswith("name=%s" % name)][0]
     d = {}
     for attribute in raw_config["attributes"]:
         name = attribute["name"]
         value = attribute.get("value")
         if value == "true":
             d[name] = True
         elif value == "false":
             d[name] = False
         else:
             try:
                 d[name] = int(value)
             except (TypeError, ValueError):
                 d[name] = value
     return d
Пример #15
0
    def node(self, id_):
        """ Fetch a node by ID. This method creates an object representing the
        remote node with the ID specified but fetches no data from the server.
        For this reason, there is no guarantee that the entity returned
        actually exists.

        :param id_:
        """
        entity_uri = "%snode/%s" % (remote(self).uri, id_)
        try:
            return Node.cache[entity_uri]
        except KeyError:
            node = self.node_selector.select().where("id(_) = %d" % id_).first()
            if node is None:
                raise IndexError("Node %d not found" % id_)
            else:
                return node
Пример #16
0
 def node_labels(self):
     """ The set of node labels currently defined within the graph.
     """
     return frozenset(remote(self).get_json("labels"))
Пример #17
0
 def __repr__(self):
     return "<%s uri=%r>" % (self.__class__.__name__, remote(self).uri)
Пример #18
0
 def __eq__(self, other):
     try:
         return remote(self) == remote(other)
     except AttributeError:
         return False
Пример #19
0
 def change_password(self, new_password):
     """ Change the password for the current user.
     """
     remote(self).post("user/{}/password".format(self.user), {"password": new_password}, expected=(OK,))
     return new_password
Пример #20
0
 def __repr__(self):
     return "<Graph uri=%r>" % remote(self).uri
Пример #21
0
 def __hash__(self):
     return hash(remote(self).uri)
Пример #22
0
 def __init__(self, graph, ref):
     self.remote_graph = remote(graph)
     self._index_ref = ref + "/index/{label}"
     self._index_key_ref = ref + "/index/{label}/{property_key}"
     self._uniqueness_constraint_ref = ref + "/constraint/{label}/uniqueness"
     self._uniqueness_constraint_key_ref = ref + "/constraint/{label}/uniqueness/{property_key}"
Пример #23
0
 def relationship_types(self):
     """ The set of relationship types currently defined within the graph.
     """
     return frozenset(remote(self).get_json("relationship/types"))
Пример #24
0
 def __contains__(self, entity):
     remote_entity = remote(entity)
     return remote_entity and remote_entity.uri.startswith(remote(self).uri)
Пример #25
0
 def open_browser(self):
     """ Open a page in the default system web browser pointing at
     the Neo4j browser application for this graph.
     """
     webbrowser.open(remote(self.graph_service).uri)
Пример #26
0
 def hydrate_(obj, inst=None):
     # TODO: hydrate directly instead of via HTTP hydration
     if isinstance(obj, Structure):
         signature, args = obj
         if signature == b"N":
             uri = "%snode/%s" % (graph_uri, args[0])
             return Node.hydrate(uri,
                                 inst=inst,
                                 metadata={"labels": list(args[1])},
                                 data=hydrate_(args[2]))
         elif signature == b"R":
             uri = "%srelationship/%s" % (graph_uri, args[0])
             return Relationship.hydrate(
                 uri,
                 inst=inst,
                 start="%snode/%s" % (graph_uri, args[1]),
                 end="%snode/%s" % (graph_uri, args[2]),
                 type=args[3],
                 data=hydrate_(args[4]))
         elif signature == b"P":
             nodes = [hydrate_(node) for node in args[0]]
             u_rels = [
                 UnboundRelationship.hydrate(*map(hydrate_, r))
                 for _, r in args[1]
             ]
             sequence = args[2]
             last_node = nodes[0]
             steps = [last_node]
             for i, rel_index in enumerate(sequence[::2]):
                 next_node = nodes[sequence[2 * i + 1]]
                 last_node_uri = "%snode/%s" % (graph_uri,
                                                remote(last_node)._id)
                 next_node_uri = "%snode/%s" % (graph_uri,
                                                remote(next_node)._id)
                 if rel_index > 0:
                     u_rel = u_rels[rel_index - 1]
                     uri = "%srelationship/%s" % (graph_uri, u_rel.id)
                     rel = Relationship.hydrate(uri,
                                                start=last_node_uri,
                                                end=next_node_uri,
                                                type=u_rel.type,
                                                data=u_rel.properties)
                 else:
                     u_rel = u_rels[-rel_index - 1]
                     uri = "%srelationship/%s" % (graph_uri, u_rel.id)
                     rel = Relationship.hydrate(uri,
                                                start=next_node_uri,
                                                end=last_node_uri,
                                                type=u_rel.type,
                                                data=u_rel.properties)
                 steps.append(rel)
                 steps.append(next_node)
                 last_node = next_node
             return Path(*steps)
         else:
             # If we don't recognise the structure type, just return it as-is
             # TODO: add warning for unsupported structure types
             return obj
     elif isinstance(obj, list):
         return list(map(hydrate_, obj))
     elif isinstance(obj, dict):
         return {key: hydrate_(value) for key, value in obj.items()}
     else:
         return obj