-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
func merge Parameter does not correspond #914
Labels
Comments
Note to self: there are two possible ways to fix this...
The choice will be dependent on the underlying functionality that is available. If Neo4j supports multiple keys in all contexts here, then option 1 is fine. If not, option 2 will have to suffice. |
monkey patch: from py2neo import Graph, Node, Relationship, Transaction, Subgraph
from py2neo.cypher.queries import (
unwind_merge_nodes_query,
unwind_merge_relationships_query,
)
from py2neo.cypher import cypher_join
class UniquenessError(Exception):
""" Raised when a condition assumed to be unique is determined
non-unique.
"""
def __db_merge__(self, tx, primary_label=None, *primary_key):
""" 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 not self._is_bound(node, graph):
# Determine primary label
if node.__primarylabel__ is not None:
p_label = node.__primarylabel__
elif node.__model__ is not None:
p_label = node.__model__.__primarylabel__ or primary_label
else:
p_label = primary_label
# Determine primary key
if node.__primarykey__ is not None:
p_key = node.__primarykey__
elif node.__model__ is not None:
p_key = node.__model__.__primarykey__ or primary_key
else:
p_key = primary_key
# Add node to the node dictionary
key = (p_label, frozenset(node.labels), *p_key)
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, graph):
key = type(relationship).__name__
rel_dict.setdefault(key, []).append(relationship)
for (pl, labels, *pk), 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]
def merge(self, subgraph, primary_label=None, *primary_key):
try:
merge = subgraph.__db_merge__
except AttributeError:
raise TypeError("No method defined to merge object %r" % subgraph)
else:
merge(self, primary_label, *primary_key)
Subgraph.__db_merge__ = __db_merge__
Transaction.merge = merge |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
in
database.py
The text was updated successfully, but these errors were encountered: