def save(self, subj, node=None): """ Save an object to a database node. :param subj: the object to save :param node: the database node to save to (if omitted, will re-save to same node as previous save) """ if node is not None: subj.__node__ = node # naively copy properties from object to node props = {} for key, value in subj.__dict__.items(): if not key.startswith("_"): props[key] = value if hasattr(subj, "__node__"): subj.__node__.set_properties(props) self.graph.cypher.run("START a=node({a}) MATCH (a)-[r]->(b) DELETE r", {"a": subj.__node__}) else: subj.__node__, = self.graph.create(props) # write rels if hasattr(subj, "__rel__"): batch = WriteBatch(self.graph) for rel_type, rels in subj.__rel__.items(): for rel_props, endpoint in rels: end_node = self._get_node(endpoint) if end_node not in self.graph: raise ValueError(end_node) batch.create((subj.__node__, rel_type, end_node, rel_props)) batch.run() return subj
def test_can_handle_json_response_with_no_content(graph): # This example might fail if the server bug is fixed that returns # a 200 response with application/json content-type and no content. batch = WriteBatch(graph) batch.create((0, "KNOWS", 1)) results = batch.submit() assert results == []
def _node_remove_labels(self, *labels): from py2neo.batch import WriteBatch labels = [ustr(label) for label in set(flatten(labels))] batch = WriteBatch(self.graph) for label in labels: batch.remove_label(self, label) batch.run()
def _node_remove_labels(self, *labels): """ Remove one or more labels from this node. :param labels: one or more text labels """ from py2neo.batch import WriteBatch labels = [ustr(label) for label in set(flatten(labels))] batch = WriteBatch(self.graph) for label in labels: batch.remove_label(self, label) batch.run()
def test_cypher_job_with_bad_syntax(graph): batch = WriteBatch(graph) batch.append(CypherJob("X")) try: batch.submit() except BatchError as error: assert error.batch is batch assert error.job_id == 0 assert error.status_code == 400 assert error.uri == "cypher" else: assert False
def test_cypher_job_with_non_existent_node_id(graph): node = Node() graph.create(node) node_id = node._id graph.delete(node) batch = WriteBatch(graph) batch.append(CypherJob("START n=node({N}) RETURN n", {"N": node_id})) try: batch.submit() except BatchError as error: assert error.batch is batch assert error.job_id == 0 assert error.status_code == 400 assert error.uri == "cypher" else: assert False
def setup(self, graph): self.batch = WriteBatch(graph) self.alice, self.bob, self.friends = graph.create( { "name": "Alice", "surname": "Allison" }, { "name": "Bob", "surname": "Robertson" }, (0, "KNOWS", 1, { "since": 2000 }), ) self.graph = graph
def setup(self, graph): self.batch = WriteBatch(graph) self.alice, self.bob, self.friends = graph.create( {"name": "Alice", "surname": "Allison"}, {"name": "Bob", "surname": "Robertson"}, (0, "KNOWS", 1, {"since": 2000}), ) self.graph = graph
def test_can_use_return_values_as_references(graph): batch = WriteBatch(graph) a = batch.create(node(name="Alice")) b = batch.create(node(name="Bob")) batch.create(rel(a, "KNOWS", b)) results = batch.submit() ab = results[2] assert isinstance(ab, Relationship) assert ab.start_node["name"] == "Alice" assert ab.end_node["name"] == "Bob"
def save(self, subj, node=None): """ Save an object to a database node. :param subj: the object to save :param node: the database node to save to (if omitted, will re-save to same node as previous save) """ if node is not None: subj.__node__ = node # naively copy properties from object to node props = {} for key, value in subj.__dict__.items(): if not key.startswith("_"): props[key] = value if hasattr(subj, "__node__"): subj.__node__.set_properties(props) self.graph.cypher.run( "START a=node({a}) MATCH (a)-[r]->(b) DELETE r", {"a": subj.__node__}) else: subj.__node__, = self.graph.create(props) # write rels if hasattr(subj, "__rel__"): batch = WriteBatch(self.graph) for rel_type, rels in subj.__rel__.items(): for rel_props, endpoint in rels: end_node = self._get_node(endpoint) if end_node not in self.graph: raise ValueError(end_node) batch.create( (subj.__node__, rel_type, end_node, rel_props)) batch.run() return subj
class TestNodeCreation(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) self.graph = graph def test_can_create_single_empty_node(self): self.batch.create(node()) a, = self.batch.submit() assert isinstance(a, Node) assert a.properties == {} def test_can_create_multiple_nodes(self): self.batch.create({"name": "Alice"}) self.batch.create(node({"name": "Bob"})) self.batch.create(node(name="Carol")) alice, bob, carol = self.batch.submit() assert isinstance(alice, Node) assert isinstance(bob, Node) assert isinstance(carol, Node) assert alice["name"] == "Alice" assert bob["name"] == "Bob" assert carol["name"] == "Carol"
class TestPropertyManagement(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) self.alice, self.bob, self.friends = graph.create( {"name": "Alice", "surname": "Allison"}, {"name": "Bob", "surname": "Robertson"}, (0, "KNOWS", 1, {"since": 2000}), ) self.graph = graph def _check_properties(self, entity, expected_properties): actual_properties = entity.get_properties() assert len(actual_properties) == len(expected_properties) for key, value in expected_properties.items(): assert key in actual_properties assert str(actual_properties[key]) == str(value) def test_can_add_new_node_property(self): self.batch.set_property(self.alice, "age", 33) self.batch.run() self._check_properties( self.alice, {"name": "Alice", "surname": "Allison", "age": 33}) def test_can_overwrite_existing_node_property(self): self.batch.set_property(self.alice, "name", "Alison") self.batch.run() self._check_properties( self.alice, {"name": "Alison", "surname": "Allison"}) def test_can_replace_all_node_properties(self): props = {"full_name": "Alice Allison", "age": 33} self.batch.set_properties(self.alice, props) self.batch.run() self._check_properties(self.alice, props) def test_can_add_delete_node_property(self): self.batch.delete_property(self.alice, "surname") self.batch.run() self._check_properties(self.alice, {"name": "Alice"}) def test_can_add_delete_all_node_properties(self): self.batch.delete_properties(self.alice) self.batch.run() self._check_properties(self.alice, {}) def test_can_add_new_relationship_property(self): self.batch.set_property(self.friends, "foo", "bar") self.batch.run() self._check_properties(self.friends, {"since": 2000, "foo": "bar"})
def setup(self, graph): self.batch = WriteBatch(graph) self.graph = graph
class TestDeletion(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) self.graph = graph def test_can_delete_relationship_and_related_nodes(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) self.batch.create((0, "KNOWS", 1)) alice, bob, ab = self.batch.submit() assert alice.exists assert bob.exists assert ab.exists self.batch.clear() self.batch.delete(ab) self.batch.delete(alice) self.batch.delete(bob) self.batch.run() assert not alice.exists assert not bob.exists assert not ab.exists
class TestUniqueRelationshipCreation(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) def test_can_create_relationship_if_none_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) alice, bob = self.batch.submit() self.batch.clear() self.batch.get_or_create_path( alice, ("KNOWS", {"since": 2000}), bob) path, = self.batch.submit() knows = path.relationships[0] assert isinstance(knows, Relationship) assert knows.start_node == alice assert knows.type == "KNOWS" assert knows.end_node == bob assert knows["since"] == 2000 self.recycling = [knows, alice, bob] def test_will_get_relationship_if_one_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) alice, bob = self.batch.submit() self.batch.clear() self.batch.get_or_create_path( alice, ("KNOWS", {"since": 2000}), bob) self.batch.get_or_create_path( alice, ("KNOWS", {"since": 2000}), bob) path1, path2 = self.batch.submit() assert path1 == path2 def test_will_fail_batch_if_more_than_one_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) self.batch.create((0, "KNOWS", 1)) self.batch.create((0, "KNOWS", 1)) alice, bob, k1, k2 = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, "KNOWS", bob) try: self.batch.submit() except BatchError as error: cause = error.__cause__ assert isinstance(cause, GraphError) assert cause.__class__.__name__ == "UniquePathNotUniqueException" else: assert False def test_can_create_relationship_and_start_node(self): self.batch.create({"name": "Bob"}) bob, = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(None, "KNOWS", bob) path, = self.batch.submit() knows = path.relationships[0] alice = knows.start_node assert isinstance(knows, Relationship) assert isinstance(alice, Node) assert knows.type == "KNOWS" assert knows.end_node == bob self.recycling = [knows, alice, bob] def test_can_create_relationship_and_end_node(self): self.batch.create({"name": "Alice"}) alice, = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, "KNOWS", None) path, = self.batch.submit() knows = path.relationships[0] bob = knows.end_node assert isinstance(knows, Relationship) assert knows.start_node == alice assert knows.type == "KNOWS" assert isinstance(bob, Node) self.recycling = [knows, alice, bob]
class TestUniqueRelationshipCreation(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) def test_can_create_relationship_if_none_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) alice, bob = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, ("KNOWS", {"since": 2000}), bob) path, = self.batch.submit() knows = path.relationships[0] assert isinstance(knows, Relationship) assert knows.start_node == alice assert knows.type == "KNOWS" assert knows.end_node == bob assert knows["since"] == 2000 self.recycling = [knows, alice, bob] def test_will_get_relationship_if_one_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) alice, bob = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, ("KNOWS", {"since": 2000}), bob) self.batch.get_or_create_path(alice, ("KNOWS", {"since": 2000}), bob) path1, path2 = self.batch.submit() assert path1 == path2 def test_will_fail_batch_if_more_than_one_exists(self): self.batch.create({"name": "Alice"}) self.batch.create({"name": "Bob"}) self.batch.create((0, "KNOWS", 1)) self.batch.create((0, "KNOWS", 1)) alice, bob, k1, k2 = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, "KNOWS", bob) try: self.batch.submit() except BatchError as error: cause = error.__cause__ assert cause.__class__.__name__ == "UniquePathNotUniqueException" else: assert False def test_can_create_relationship_and_start_node(self): self.batch.create({"name": "Bob"}) bob, = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(None, "KNOWS", bob) path, = self.batch.submit() knows = path.relationships[0] alice = knows.start_node assert isinstance(knows, Relationship) assert isinstance(alice, Node) assert knows.type == "KNOWS" assert knows.end_node == bob self.recycling = [knows, alice, bob] def test_can_create_relationship_and_end_node(self): self.batch.create({"name": "Alice"}) alice, = self.batch.submit() self.batch.clear() self.batch.get_or_create_path(alice, "KNOWS", None) path, = self.batch.submit() knows = path.relationships[0] bob = knows.end_node assert isinstance(knows, Relationship) assert knows.start_node == alice assert knows.type == "KNOWS" assert isinstance(bob, Node) self.recycling = [knows, alice, bob]
class TestNodeCreation(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) self.graph = graph def test_can_create_single_empty_node(self): self.batch.create(node()) a, = self.batch.submit() assert isinstance(a, Node) assert a.properties == {} def test_can_create_single_node_with_streaming(self): self.batch.create(Node(name="Alice")) for result in self.batch.stream(): assert isinstance(result, Node) assert result.properties == {"name": "Alice"} def test_can_create_multiple_nodes(self): self.batch.create({"name": "Alice"}) self.batch.create(node({"name": "Bob"})) self.batch.create(node(name="Carol")) alice, bob, carol = self.batch.submit() assert isinstance(alice, Node) assert isinstance(bob, Node) assert isinstance(carol, Node) assert alice["name"] == "Alice" assert bob["name"] == "Bob" assert carol["name"] == "Carol"
class TestPropertyManagement(object): @pytest.fixture(autouse=True) def setup(self, graph): self.batch = WriteBatch(graph) self.alice, self.bob, self.friends = graph.create( { "name": "Alice", "surname": "Allison" }, { "name": "Bob", "surname": "Robertson" }, (0, "KNOWS", 1, { "since": 2000 }), ) self.graph = graph def _check_properties(self, entity, expected_properties): entity.pull() actual_properties = entity.properties assert len(actual_properties) == len(expected_properties) for key, value in expected_properties.items(): assert key in actual_properties assert str(actual_properties[key]) == str(value) def test_can_add_new_node_property(self): self.batch.set_property(self.alice, "age", 33) self.batch.run() self._check_properties(self.alice, { "name": "Alice", "surname": "Allison", "age": 33 }) def test_can_overwrite_existing_node_property(self): self.batch.set_property(self.alice, "name", "Alison") self.batch.run() self._check_properties(self.alice, { "name": "Alison", "surname": "Allison" }) def test_can_replace_all_node_properties(self): props = {"full_name": "Alice Allison", "age": 33} self.batch.set_properties(self.alice, props) self.batch.run() self._check_properties(self.alice, props) def test_can_add_delete_node_property(self): self.batch.delete_property(self.alice, "surname") self.batch.run() self._check_properties(self.alice, {"name": "Alice"}) def test_can_add_delete_all_node_properties(self): self.batch.delete_properties(self.alice) self.batch.run() self._check_properties(self.alice, {}) def test_can_add_new_relationship_property(self): self.batch.set_property(self.friends, "foo", "bar") self.batch.run() self._check_properties(self.friends, {"since": 2000, "foo": "bar"})