From dd091ff45536eede4047a66e1f52b86ad763ba93 Mon Sep 17 00:00:00 2001 From: Nigel Small Date: Sat, 2 Jan 2016 00:13:31 +0000 Subject: [PATCH 1/2] Ensure we always use identities for relationship endpoints --- neo4j/v1/typesystem.py | 6 ++-- test/test_typesystem.py | 74 ++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/neo4j/v1/typesystem.py b/neo4j/v1/typesystem.py index 52ad7d3fb..79d932658 100644 --- a/neo4j/v1/typesystem.py +++ b/neo4j/v1/typesystem.py @@ -119,6 +119,8 @@ def hydrate(cls, identity, start, end, type, properties=None): return inst def __init__(self, start, end, type, properties=None, **kwproperties): + assert isinstance(start, int) + assert isinstance(end, int) super(Relationship, self).__init__(type, properties, **kwproperties) self.start = start self.end = end @@ -172,9 +174,9 @@ def hydrate(cls, nodes, rels, sequence): assert rel_index != 0 next_node = nodes[sequence[2 * i + 1]] if rel_index > 0: - entities.append(rels[rel_index - 1].bind(last_node, next_node)) + entities.append(rels[rel_index - 1].bind(last_node.identity, next_node.identity)) else: - entities.append(rels[-rel_index - 1].bind(next_node, last_node)) + entities.append(rels[-rel_index - 1].bind(next_node.identity, last_node.identity)) entities.append(next_node) return cls(*entities) diff --git a/test/test_typesystem.py b/test/test_typesystem.py index 7ca829284..91c82626e 100644 --- a/test/test_typesystem.py +++ b/test/test_typesystem.py @@ -57,22 +57,22 @@ def test_null_properties(self): def test_node_equality(self): node_1 = Node() - node_1.identity = "node/1234" + node_1.identity = 1234 node_2 = Node() - node_2.identity = "node/1234" + node_2.identity = 1234 node_3 = Node() - node_3.identity = "node/5678" + node_3.identity = 5678 assert node_1 == node_2 assert node_1 != node_3 assert node_1 != "this is not a node" def test_node_hashing(self): node_1 = Node() - node_1.identity = "node/1234" + node_1.identity = 1234 node_2 = Node() - node_2.identity = "node/1234" + node_2.identity = 1234 node_3 = Node() - node_3.identity = "node/5678" + node_3.identity = 5678 assert hash(node_1) == hash(node_2) assert hash(node_1) != hash(node_3) @@ -80,12 +80,12 @@ def test_node_hashing(self): class RelationshipTestCase(TestCase): def test_can_create_relationship(self): - alice = Node({"Person"}, {"name": "Alice", "age": 33}) - bob = Node({"Person"}, {"name": "Bob", "age": 44}) - alice_knows_bob = Relationship(alice, bob, "KNOWS", {"since": 1999}) - assert alice_knows_bob.start is alice + alice = Node.hydrate(1, {"Person"}, {"name": "Alice", "age": 33}) + bob = Node.hydrate(2, {"Person"}, {"name": "Bob", "age": 44}) + alice_knows_bob = Relationship(alice.identity, bob.identity, "KNOWS", {"since": 1999}) + assert alice_knows_bob.start == alice.identity assert alice_knows_bob.type == "KNOWS" - assert alice_knows_bob.end is bob + assert alice_knows_bob.end == bob.identity assert set(alice_knows_bob.keys()) == {"since"} assert set(alice_knows_bob.values()) == {1999} assert set(alice_knows_bob.items()) == {("since", 1999)} @@ -108,11 +108,11 @@ def test_can_create_unbound_relationship(self): class PathTestCase(TestCase): def test_can_create_path(self): - alice = Node({"Person"}, {"name": "Alice", "age": 33}) - bob = Node({"Person"}, {"name": "Bob", "age": 44}) - carol = Node({"Person"}, {"name": "Carol", "age": 55}) - alice_knows_bob = Relationship(alice, bob, "KNOWS", {"since": 1999}) - carol_dislikes_bob = Relationship(carol, bob, "DISLIKES") + alice = Node.hydrate(1, {"Person"}, {"name": "Alice", "age": 33}) + bob = Node.hydrate(2, {"Person"}, {"name": "Bob", "age": 44}) + carol = Node.hydrate(3, {"Person"}, {"name": "Carol", "age": 55}) + alice_knows_bob = Relationship(alice.identity, bob.identity, "KNOWS", {"since": 1999}) + carol_dislikes_bob = Relationship(carol.identity, bob.identity, "DISLIKES") path = Path(alice, alice_knows_bob, bob, carol_dislikes_bob, carol) assert path.start == alice assert path.end == carol @@ -122,11 +122,11 @@ def test_can_create_path(self): assert repr(path) def test_can_hydrate_path(self): - alice = Node({"Person"}, {"name": "Alice", "age": 33}) - bob = Node({"Person"}, {"name": "Bob", "age": 44}) - carol = Node({"Person"}, {"name": "Carol", "age": 55}) - alice_knows_bob = Relationship(alice, bob, "KNOWS", {"since": 1999}) - carol_dislikes_bob = Relationship(carol, bob, "DISLIKES") + alice = Node.hydrate(1, {"Person"}, {"name": "Alice", "age": 33}) + bob = Node.hydrate(2, {"Person"}, {"name": "Bob", "age": 44}) + carol = Node.hydrate(3, {"Person"}, {"name": "Carol", "age": 55}) + alice_knows_bob = Relationship(alice.identity, bob.identity, "KNOWS", {"since": 1999}) + carol_dislikes_bob = Relationship(carol.identity, bob.identity, "DISLIKES") path = Path.hydrate([alice, bob, carol], [alice_knows_bob.unbind(), carol_dislikes_bob.unbind()], [1, 1, -2, 2]) @@ -138,22 +138,22 @@ def test_can_hydrate_path(self): assert repr(path) def test_path_equality(self): - alice = Node({"Person"}, {"name": "Alice", "age": 33}) - bob = Node({"Person"}, {"name": "Bob", "age": 44}) - carol = Node({"Person"}, {"name": "Carol", "age": 55}) - alice_knows_bob = Relationship(alice, bob, "KNOWS", {"since": 1999}) - carol_dislikes_bob = Relationship(carol, bob, "DISLIKES") + alice = Node.hydrate(1, {"Person"}, {"name": "Alice", "age": 33}) + bob = Node.hydrate(2, {"Person"}, {"name": "Bob", "age": 44}) + carol = Node.hydrate(3, {"Person"}, {"name": "Carol", "age": 55}) + alice_knows_bob = Relationship(alice.identity, bob.identity, "KNOWS", {"since": 1999}) + carol_dislikes_bob = Relationship(carol.identity, bob.identity, "DISLIKES") path_1 = Path(alice, alice_knows_bob, bob, carol_dislikes_bob, carol) path_2 = Path(alice, alice_knows_bob, bob, carol_dislikes_bob, carol) assert path_1 == path_2 assert path_1 != "this is not a path" def test_path_hashing(self): - alice = Node({"Person"}, {"name": "Alice", "age": 33}) - bob = Node({"Person"}, {"name": "Bob", "age": 44}) - carol = Node({"Person"}, {"name": "Carol", "age": 55}) - alice_knows_bob = Relationship(alice, bob, "KNOWS", {"since": 1999}) - carol_dislikes_bob = Relationship(carol, bob, "DISLIKES") + alice = Node.hydrate(1, {"Person"}, {"name": "Alice", "age": 33}) + bob = Node.hydrate(2, {"Person"}, {"name": "Bob", "age": 44}) + carol = Node.hydrate(3, {"Person"}, {"name": "Carol", "age": 55}) + alice_knows_bob = Relationship(alice.identity, bob.identity, "KNOWS", {"since": 1999}) + carol_dislikes_bob = Relationship(carol.identity, bob.identity, "DISLIKES") path_1 = Path(alice, alice_knows_bob, bob, carol_dislikes_bob, carol) path_2 = Path(alice, alice_knows_bob, bob, carol_dislikes_bob, carol) assert hash(path_1) == hash(path_2) @@ -163,11 +163,11 @@ class HydrationTestCase(TestCase): def test_can_hydrate_node_structure(self): struct = Structure(3, b'N') - struct.append("node/123") + struct.append(123) struct.append(["Person"]) struct.append({"name": "Alice"}) alice = hydrated(struct) - assert alice.identity == "node/123" + assert alice.identity == 123 assert alice.labels == {"Person"} assert set(alice.keys()) == {"name"} assert alice.get("name") == "Alice" @@ -180,26 +180,26 @@ def test_hydrating_unknown_structure_returns_same(self): def test_can_hydrate_in_list(self): struct = Structure(3, b'N') - struct.append("node/123") + struct.append(123) struct.append(["Person"]) struct.append({"name": "Alice"}) alice_in_list = hydrated([struct]) assert isinstance(alice_in_list, list) alice, = alice_in_list - assert alice.identity == "node/123" + assert alice.identity == 123 assert alice.labels == {"Person"} assert set(alice.keys()) == {"name"} assert alice.get("name") == "Alice" def test_can_hydrate_in_dict(self): struct = Structure(3, b'N') - struct.append("node/123") + struct.append(123) struct.append(["Person"]) struct.append({"name": "Alice"}) alice_in_dict = hydrated({"foo": struct}) assert isinstance(alice_in_dict, dict) alice = alice_in_dict["foo"] - assert alice.identity == "node/123" + assert alice.identity == 123 assert alice.labels == {"Person"} assert set(alice.keys()) == {"name"} assert alice.get("name") == "Alice" From ec6d6d5e4f94057a635630be6c144eacfeb51107 Mon Sep 17 00:00:00 2001 From: Nigel Small Date: Sat, 2 Jan 2016 08:28:26 +0000 Subject: [PATCH 2/2] Fix path hydration bug --- neo4j/v1/typesystem.py | 1 + 1 file changed, 1 insertion(+) diff --git a/neo4j/v1/typesystem.py b/neo4j/v1/typesystem.py index 79d932658..bf7ef6593 100644 --- a/neo4j/v1/typesystem.py +++ b/neo4j/v1/typesystem.py @@ -178,6 +178,7 @@ def hydrate(cls, nodes, rels, sequence): else: entities.append(rels[-rel_index - 1].bind(next_node.identity, last_node.identity)) entities.append(next_node) + last_node = next_node return cls(*entities) def __init__(self, start_node, *rels_and_nodes):