Beispiel #1
0
def create_subgraph(tx, subgraph):
    """ Create new data in a remote :class:`.Graph` from a local
    :class:`.Subgraph`.

    :param tx:
    :param subgraph:
    :return:
    """
    graph = tx.graph
    for labels, nodes in _node_create_dict(n for n in subgraph.nodes
                                           if n.graph is None).items():
        pq = unwind_create_nodes_query(list(map(dict, nodes)), labels=labels)
        pq = cypher_join(pq, "RETURN id(_)")
        records = tx.run(*pq)
        for i, record in enumerate(records):
            node = nodes[i]
            node.graph = graph
            node.identity = record[0]
            node._remote_labels = labels
    for r_type, relationships in _rel_create_dict(
            r for r in subgraph.relationships if r.graph is None).items():
        data = map(
            lambda r: [r.start_node.identity,
                       dict(r), r.end_node.identity], relationships)
        pq = unwind_merge_relationships_query(data, r_type)
        pq = cypher_join(pq, "RETURN id(_)")
        for i, record in enumerate(tx.run(*pq)):
            relationship = relationships[i]
            relationship.graph = graph
            relationship.identity = record[0]
Beispiel #2
0
    def __db_merge__(self, tx, primary_label=None, primary_key=None):
        """ Merge data into a remote :class:`.Graph` from this
        :class:`.Subgraph`.

        :param tx:
        :param primary_label:
        :param primary_key:
        """
        graph = tx.graph

        # Convert nodes into a dictionary of
        #   {(p_label, p_key, frozenset(labels)): [Node, Node, ...]}
        node_dict = {}
        for node in self.nodes:
            if node.graph is None:
                p_label = getattr(node, "__primarylabel__",
                                  None) or primary_label
                p_key = getattr(node, "__primarykey__", None) or primary_key
                key = (p_label, p_key, frozenset(node.labels))
                node_dict.setdefault(key, []).append(node)

        # Convert relationships into a dictionary of
        #   {rel_type: [Rel, Rel, ...]}
        rel_dict = {}
        for relationship in self.relationships:
            if relationship.graph is None:
                key = type(relationship).__name__
                rel_dict.setdefault(key, []).append(relationship)

        for (pl, pk, labels), nodes in node_dict.items():
            if pl is None or pk is None:
                raise ValueError(
                    "Primary label and primary key are required for MERGE operation"
                )
            pq = unwind_merge_nodes_query(map(dict, nodes), (pl, pk), labels)
            pq = cypher_join(pq, "RETURN id(_)")
            identities = [record[0] for record in tx.run(*pq)]
            if len(identities) > len(nodes):
                raise UniquenessError(
                    "Found %d matching nodes for primary label %r and primary "
                    "key %r with labels %r but merging requires no more than "
                    "one" % (len(identities), pl, pk, set(labels)))
            for i, identity in enumerate(identities):
                node = nodes[i]
                node.graph = graph
                node.identity = identity
                node._remote_labels = labels
        for r_type, relationships in rel_dict.items():
            data = map(
                lambda r:
                [r.start_node.identity,
                 dict(r), r.end_node.identity], relationships)
            pq = unwind_merge_relationships_query(data, r_type)
            pq = cypher_join(pq, "RETURN id(_)")
            for i, record in enumerate(tx.run(*pq)):
                relationship = relationships[i]
                relationship.graph = graph
                relationship.identity = record[0]
Beispiel #3
0
def unwind_merge_relationships_query(data,
                                     merge_key,
                                     start_node_key=None,
                                     end_node_key=None,
                                     keys=None,
                                     preserve=None):
    """ Generate a parameterised ``UNWIND...MERGE`` query for bulk
    loading relationships into Neo4j.

    :param data:
    :param merge_key: tuple of (rel_type, key1, key2...)
    :param start_node_key:
    :param end_node_key:
    :param keys:
    :param preserve:
        Collection of key names for values that should be protected
        should the relationship already exist.
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _match_clause("a", start_node_key, "r[0]"),
                       _match_clause("b", end_node_key, "r[2]"),
                       _merge_clause("_", merge_key, "r[1]", keys, "(a)-[",
                                     "]->(b)"),
                       _on_create_set_properties_clause(
                           "r[1]", keys, preserve),
                       _set_properties_clause("r[1]",
                                              keys,
                                              exclude_keys=preserve),
                       data=_relationship_data(data))
Beispiel #4
0
    def __db_create__(self, tx):
        """ Create new data in a remote :class:`.Graph` from this
        :class:`.Subgraph`.

        :param tx:
        """
        graph = tx.graph

        # Convert nodes into a dictionary of
        #   {frozenset(labels): [Node, Node, ...]}
        node_dict = {}
        for node in self.nodes:
            if not self._is_bound(node, tx.graph):
                key = frozenset(node.labels)
                node_dict.setdefault(key, []).append(node)

        # Convert relationships into a dictionary of
        #   {rel_type: [Rel, Rel, ...]}
        rel_dict = {}
        for relationship in self.relationships:
            if not self._is_bound(relationship, tx.graph):
                key = type(relationship).__name__
                rel_dict.setdefault(key, []).append(relationship)

        for labels, nodes in node_dict.items():
            pq = unwind_create_nodes_query(list(map(dict, nodes)),
                                           labels=labels)
            pq = cypher_join(pq, "RETURN id(_)")
            records = tx.run(*pq)
            for i, record in enumerate(records):
                node = nodes[i]
                node.graph = graph
                node.identity = record[0]
                node._remote_labels = labels
        for r_type, relationships in rel_dict.items():
            data = map(
                lambda r:
                [r.start_node.identity,
                 dict(r), r.end_node.identity], relationships)
            pq = unwind_merge_relationships_query(data, r_type)
            pq = cypher_join(pq, "RETURN id(_)")
            for i, record in enumerate(tx.run(*pq)):
                relationship = relationships[i]
                relationship.graph = graph
                relationship.identity = record[0]
Beispiel #5
0
def merge_subgraph(tx, subgraph, p_label, p_key):
    """ Merge data into a remote :class:`.Graph` from a local
    :class:`.Subgraph`.

    :param tx:
    :param subgraph:
    :param p_label:
    :param p_key:
    :return:
    """
    graph = tx.graph
    for (pl, pk, labels), nodes in _node_merge_dict(
            p_label, p_key,
        (n for n in subgraph.nodes if n.graph is None)).items():
        if pl is None or pk is None:
            raise ValueError(
                "Primary label and primary key are required for MERGE operation"
            )
        pq = unwind_merge_nodes_query(map(dict, nodes), (pl, pk), labels)
        pq = cypher_join(pq, "RETURN id(_)")
        identities = [record[0] for record in tx.run(*pq)]
        if len(identities) > len(nodes):
            raise UniquenessError(
                "Found %d matching nodes for primary label %r and primary "
                "key %r with labels %r but merging requires no more than "
                "one" % (len(identities), pl, pk, set(labels)))
        for i, identity in enumerate(identities):
            node = nodes[i]
            node.graph = graph
            node.identity = identity
            node._remote_labels = labels
    for r_type, relationships in _rel_create_dict(
            r for r in subgraph.relationships if r.graph is None).items():
        data = map(
            lambda r: [r.start_node.identity,
                       dict(r), r.end_node.identity], relationships)
        pq = unwind_merge_relationships_query(data, r_type)
        pq = cypher_join(pq, "RETURN id(_)")
        for i, record in enumerate(tx.run(*pq)):
            relationship = relationships[i]
            relationship.graph = graph
            relationship.identity = record[0]
Beispiel #6
0
def unwind_create_nodes_query(data, labels=None, keys=None):
    """ Generate a parameterised ``UNWIND...CREATE`` query for bulk
    loading nodes into Neo4j.

    :param data:
    :param labels:
    :param keys:
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _create_clause("_", (tuple(labels or ()), )),
                       _set_properties_clause("r", keys),
                       data=list(data))
Beispiel #7
0
def unwind_merge_nodes_query(data, merge_key, labels=None, keys=None):
    """ Generate a parameterised ``UNWIND...MERGE`` query for bulk
    loading nodes into Neo4j.

    :param data:
    :param merge_key:
    :param labels:
    :param keys:
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _merge_clause("r", merge_key, keys, "(", ")"),
                       _set_labels_clause(labels),
                       _set_properties_clause("r", keys),
                       data=list(data))
Beispiel #8
0
def unwind_merge_relationships_query(data, merge_key, keys=None,
                                     start_node_key=None, end_node_key=None):
    """ Generate a parameterised ``UNWIND...MERGE`` query for bulk
    loading relationships into Neo4j.

    :param data:
    :param merge_key: tuple of (rel_type, key1, key2...)
    :param keys:
    :param start_node_key:
    :param end_node_key:
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _match_clause("r[0]", "a", start_node_key),
                       _match_clause("r[2]", "b", end_node_key),
                       _merge_clause("r[1]", merge_key, keys, "(a)-[", "]->(b)"),
                       _set_properties_clause("r[1]", keys),
                       data=list(data))
Beispiel #9
0
def unwind_create_relationships_query(data, rel_type, keys=None,
                                      start_node_key=None, end_node_key=None):
    """ Generate a parameterised ``UNWIND...CREATE`` query for bulk
    loading relationships into Neo4j.

    :param data:
    :param rel_type:
    :param keys:
    :param start_node_key:
    :param end_node_key:
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _match_clause("r[0]", "a", start_node_key),
                       _match_clause("r[2]", "b", end_node_key),
                       "CREATE (a)-[_:%s]->(b)" % cypher_escape(rel_type),
                       _set_properties_clause("r[1]", keys),
                       data=list(data))
Beispiel #10
0
def unwind_merge_nodes_query(data,
                             merge_key,
                             labels=None,
                             keys=None,
                             preserve=None):
    """ Generate a parameterised ``UNWIND...MERGE`` query for bulk
    loading nodes into Neo4j.

    :param data:
    :param merge_key:
    :param labels:
    :param keys:
    :param preserve:
        Collection of key names for values that should be protected
        should the node already exist.
    :return: (query, parameters) tuple
    """
    return cypher_join("UNWIND $data AS r",
                       _merge_clause("_", merge_key, "r", keys),
                       _on_create_set_properties_clause("r", keys, preserve),
                       _set_properties_clause("r", keys,
                                              exclude_keys=preserve),
                       _set_labels_clause(labels),
                       data=list(data))