neo4j-contrib / py2neo

EOL! Py2neo is a comprehensive Neo4j driver library and toolkit for Python.
https://py2neo.org
Apache License 2.0
20 stars 8 forks source link

Tuple of length 1 as relationship data input #878

Closed mpreusse closed 3 years ago

mpreusse commented 3 years ago

The new bulk function to create relationships does not work with a tuple of length 1 as relationship data input.

This works:

rel_data = [
    (1, {}, 1),
    (2, {}, 2)
]

This will not create realationships:

rel_data = [
    ((1,), {}, (1,)),
    ((2,), {}, (2,))
]

I would suggest to also allow tuples of length 1 to provide a generic interface for functions that create relationship data. Right now, you have to check the number of values to decide if you add one value or a tuple fo values.

Here is a full example, the second batch of relationships is not created.

from py2neo import Graph
from py2neo.bulk import create_nodes, create_relationships

graph = Graph(host='localhost', password='test')

# delete DB
graph.run("MATCH (a) DETACH DELETE a")

# create some nodes: (:Source) and (:Target)
node_data = [{'uid': 1}, {'uid': 2}]

create_nodes(graph, node_data, labels=['Source'])
create_nodes(graph, node_data, labels=['Target'])

# create relationships with single property
rel_data = [
    (1, {}, 1),
    (2, {}, 2)
]

create_relationships(graph, rel_data, 'TEST_SINGLE_PROP', start_node_key=('Source', 'uid'), end_node_key=('Target', 'uid'))

# try to create relationships with tuples of length 1
# these relationships are not created
rel_data = [
    ((1,), {}, (1,)),
    ((2,), {}, (2,))
]

create_relationships(graph, rel_data, 'TEST_TUPLE_1', start_node_key=('Source', 'uid'), end_node_key=('Target', 'uid'))
technige commented 3 years ago

This is a good point, and is a result of the internal normalisation of the node keys. If only one primary key name is provided, the query looks for a single value; if multiple primary key names are provided, it looks for a tuple of values.

I've deliberately avoided pre-processing the data for performance reasons, but introducing this is the best way I can think of to allow both forms to be provided. This means (I think) that performance will be slightly affected when a 1-tuple is provided, but this seems like a worthwhile trade-off for simplicity of interface.

I'll add a PR for you to try.