def test_can_write_relationship_with_name(self): r = Relationship(Node(name="Fred"), "LIVES WITH", Node(name="Wilma")) string = StringIO() writer = CypherWriter(string) writer.write_relationship(r, name="fred_wilma") written = string.getvalue() assert written == '(fred)-[fred_wilma:`LIVES WITH`]->(wilma)'
def test_can_write_with_wrapper_function(self): alice, bob, carol, dave = Node(name="Alice"), Node(name="Bob"), \ Node(name="Carol"), Node(name="Dave") path = Path(alice, "LOVES", bob, Relationship(carol, "HATES", bob), carol, "KNOWS", dave) written = cypher_repr(path) assert written == "(alice)-[:LOVES]->(bob)<-[:HATES]-(carol)-[:KNOWS]->(dave)"
def test_can_pull_path(self): alice = Node(name="Alice") bob = Node(name="Bob") carol = Node(name="Carol") dave = Node(name="Dave") path = Path(alice, "LOVES", bob, Relationship(carol, "HATES", bob), carol, "KNOWS", dave) self.graph.create(path) assert path[0]["amount"] is None assert path[1]["amount"] is None assert path[2]["since"] is None statement = ( "MATCH ()-[ab]->() WHERE id(ab)={ab} " "MATCH ()-[bc]->() WHERE id(bc)={bc} " "MATCH ()-[cd]->() WHERE id(cd)={cd} " "SET ab.amount = 'lots', bc.amount = 'some', cd.since = 1999") id_0 = remote(path[0])._id id_1 = remote(path[1])._id id_2 = remote(path[2])._id parameters = {"ab": id_0, "bc": id_1, "cd": id_2} self.graph.run(statement, parameters) self.graph.pull(path) assert path[0]["amount"] == "lots" assert path[1]["amount"] == "some" assert path[2]["since"] == 1999
def test_can_push_path(self): alice = Node(name="Alice") bob = Node(name="Bob") carol = Node(name="Carol") dave = Node(name="Dave") path = Path(alice, "LOVES", bob, Relationship(carol, "HATES", bob), carol, "KNOWS", dave) self.graph.create(path) statement = ("MATCH ()-[ab]->() WHERE id(ab)={ab} " "MATCH ()-[bc]->() WHERE id(bc)={bc} " "MATCH ()-[cd]->() WHERE id(cd)={cd} " "RETURN ab.amount, bc.amount, cd.since") parameters = { "ab": remote(path[0])._id, "bc": remote(path[1])._id, "cd": remote(path[2])._id } path[0]["amount"] = "lots" path[1]["amount"] = "some" path[2]["since"] = 1999 ab_amount, bc_amount, cd_since = self.graph.run(statement, parameters).next() assert ab_amount is None assert bc_amount is None assert cd_since is None self.graph.push(path) ab_amount, bc_amount, cd_since = self.graph.run(statement, parameters).next() assert ab_amount == "lots" assert bc_amount == "some" assert cd_since == 1999
def test_can_delete_nodes_and_relationship_nodes_first(self): alice = Node("Person", name="Alice") bob = Node("Person", name="Bob") ab = Relationship(alice, "KNOWS", bob) self.graph.create(alice | bob | ab) assert self.graph.exists(alice | bob | ab) self.graph.delete(alice | bob | ab) assert not self.graph.exists(alice | bob | ab)
def test_can_delete_path(self): alice, bob, carol, dave = Node(), Node(), Node(), Node() path = Path(alice, "LOVES", bob, Relationship(carol, "HATES", bob), carol, "KNOWS", dave) self.graph.create(path) assert self.graph.exists(path) self.graph.delete(path) assert not self.graph.exists(path)
def test_can_write_node_with_labels(self): node = Node("Dark Brown", "Chicken") node.__name__ = "a" string = StringIO() writer = CypherWriter(string) writer.write(node) written = string.getvalue() assert written == '(a:Chicken:`Dark Brown`)'
def test_can_write_simple_node(self): node = Node() node.__name__ = "a" string = StringIO() writer = CypherWriter(string) writer.write(node) written = string.getvalue() assert written == "(a)"
def test_can_write_relationship_with_properties(self): r = Relationship(Node(name="Fred"), ("LIVES WITH", { "place": "Bedrock" }), Node(name="Wilma")) string = StringIO() writer = CypherWriter(string) writer.write(r) written = string.getvalue() assert written == '(fred)-[:`LIVES WITH` {place:"Bedrock"}]->(wilma)'
def test_can_create_relationship(self): a = Node("Person", name="Alice") b = Node("Person", name="Bob") r = Relationship(a, "KNOWS", b, since=1999) self.graph.create(r) assert remote(a) assert remote(b) assert remote(r) assert r.start_node() == a assert r.end_node() == b
def test_can_write_simple_path(self): alice, bob, carol, dave = Node(name="Alice"), Node(name="Bob"), \ Node(name="Carol"), Node(name="Dave") path = Path(alice, "LOVES", bob, Relationship(carol, "HATES", bob), carol, "KNOWS", dave) string = StringIO() writer = CypherWriter(string) writer.write(path) written = string.getvalue() assert written == "(alice)-[:LOVES]->(bob)<-[:HATES]-(carol)-[:KNOWS]->(dave)"
def test_walkable_repr(self): a = Node("Person", name="Alice") b = Node("Person", name="Bob") c = Node("Person", name="Carol") d = Node("Person", name="Dave") ab = Relationship(a, "LOVES", b) cb = Relationship(c, "HATES", b) cd = Relationship(c, "KNOWS", d) t = Walkable([a, ab, b, cb, c, cd, d]) r = repr(t) expected = "(alice)-[:LOVES]->(bob)<-[:HATES]-(carol)-[:KNOWS]->(dave)" assert r == expected
def test_can_add_single_relationship(self): alice = Node(name="Alice Smith") bob = Node(name="Bob Smith") ab = Relationship(alice, "KNOWS", bob) self.graph.create(alice | bob | ab) self.batch.add_to_index(Relationship, self.friendships, "friends", "alice_&_bob", ab) self.batch.run() # check entries rels = self.friendships.get("friends", "alice_&_bob") assert len(rels) == 1 assert ab in rels # done self.recycling = [ab, alice, bob]
def test_can_add_two_similar_nodes(self): alice = Node(name="Alice Smith") bob = Node(name="Bob Smith") self.graph.create(alice | bob) self.batch.add_to_index(Node, self.people, "surname", "Smith", alice) self.batch.add_to_index(Node, self.people, "surname", "Smith", bob) nodes = self.batch.run() assert nodes[0] != nodes[1] # check entries smiths = self.people.get("surname", "Smith") assert len(smiths) == 2 assert alice in smiths assert bob in smiths # done self.graph.delete(alice | bob)
def test_can_write_node_with_properties(self): node = Node(name="Gertrude", age=3) string = StringIO() writer = CypherWriter(string) writer.write(node) written = string.getvalue() assert written == '(gertrude {age:3,name:"Gertrude"})'
def test_can_write_node_with_labels_and_properties(self): node = Node("Dark Brown", "Chicken", name="Gertrude", age=3) string = StringIO() writer = CypherWriter(string) writer.write(node) written = string.getvalue() assert written == '(gertrude:Chicken:`Dark Brown` {age:3,name:"Gertrude"})'
def test_can_add_nodes_only_if_none_exist(self): alice = Node(name="Alice Smith") bob = Node(name="Bob Smith") self.graph.create(alice | bob) self.batch.get_or_add_to_index(Node, self.people, "surname", "Smith", alice) self.batch.get_or_add_to_index(Node, self.people, "surname", "Smith", bob) nodes = self.batch.run() assert nodes[0] == nodes[1] # check entries smiths = self.people.get("surname", "Smith") assert len(smiths) == 1 assert alice in smiths # done self.graph.delete(alice | bob)
def hydrate_(data, inst=None): if isinstance(data, dict): if "self" in data: if "type" in data: return Relationship.hydrate(data["self"], inst=inst, **data) else: return Node.hydrate(data["self"], inst=inst, **data) elif "nodes" in data and "relationships" in data: if "directions" not in data: directions = [] relationships = graph.evaluate( "MATCH ()-[r]->() WHERE id(r) IN {x} RETURN collect(r)", x=[int(uri.rpartition("/")[-1]) for uri in data["relationships"]]) node_uris = data["nodes"] for i, relationship in enumerate(relationships): if remote(relationship.start_node()).uri == node_uris[i]: directions.append("->") else: directions.append("<-") data["directions"] = directions return Path.hydrate(data) else: # from warnings import warn # warn("Map literals returned over the Neo4j REST interface are ambiguous " # "and may be hydrated as graph objects") return data elif is_collection(data): return type(data)(map(hydrate_, data)) else: return data
def test_param_used_twice(self): node = Node() self.graph.create(node) statement = "MATCH (a) WHERE id(a)={X} MATCH (b) WHERE id(b)={X} RETURN a, b" params = {"X": remote(node)._id} record = self.graph.run(statement, params).next() assert record["a"] == node assert record["b"] == node
def test_can_push_relationship(self): a = Node() b = Node() ab = Relationship(a, "KNOWS", b) self.graph.create(ab) value = self.graph.evaluate( "MATCH ()-[ab:KNOWS]->() WHERE id(ab)={i} " "RETURN ab.since", i=remote(ab)._id) assert value is None ab["since"] = 1999 self.graph.push(ab) value = self.graph.evaluate( "MATCH ()-[ab:KNOWS]->() WHERE id(ab)={i} " "RETURN ab.since", i=remote(ab)._id) assert value == 1999
def test_param_used_once(self): node = Node() self.graph.create(node) statement = "MATCH (a) WHERE id(a)={X} RETURN a" params = {"X": remote(node)._id} cursor = self.graph.run(statement, params) record = cursor.next() assert record["a"] == node
def setUp(self): try: self.index_manager.delete_index(Node, "node_removal_test_index") except LookupError: pass self.index = self.index_manager.get_or_create_index( Node, "node_removal_test_index") self.fred = Node(name="Fred Flintstone") self.wilma = Node(name="Wilma Flintstone") self.graph.create(self.fred | self.wilma) self.index.add("name", "Fred", self.fred) self.index.add("name", "Wilma", self.wilma) self.index.add("name", "Flintstone", self.fred) self.index.add("name", "Flintstone", self.wilma) self.index.add("flintstones", "%", self.fred) self.index.add("flintstones", "%", self.wilma) self.batch = ManualIndexWriteBatch(self.graph)
def test_query_can_return_collection(self): node = Node() self.graph.create(node) statement = "MATCH (a) WHERE id(a)={N} RETURN collect(a) AS a_collection" params = {"N": remote(node)._id} cursor = self.graph.run(statement, params) record = cursor.next() assert record["a_collection"] == [node]
def test_can_graph_pull_node(self): alice_1 = Node() alice_2 = Node("Person", name="Alice") self.graph.create(alice_2) assert set(alice_1.labels()) == set() assert dict(alice_1) == {} alice_1.__remote__ = RemoteEntity(remote(alice_2).uri) self.graph.pull(alice_1) assert set(alice_1.labels()) == set(alice_2.labels()) assert dict(alice_1) == dict(alice_2)
def __ogm__(self): if self.__ogm is None: self.__ogm = OGM(Node(self.__primarylabel__)) node = self.__ogm.node if not hasattr(node, "__primarylabel__"): setattr(node, "__primarylabel__", self.__primarylabel__) if not hasattr(node, "__primarykey__"): setattr(node, "__primarykey__", self.__primarykey__) return self.__ogm
def test_subgraph_repr(self): a = Node("Person", name="Alice") b = Node("Person", name="Bob") ab = Relationship(a, "TO", b) ba = Relationship(b, "FROM", a) s = ab | ba assert isinstance(s, Subgraph) r = repr(s) assert r.startswith("({") assert r.endswith("})") nodes, _, relationships = r[2:-2].partition("}, {") items = [item.strip() for item in nodes.split(",")] assert len(items) == 2 for i, item in enumerate(items): assert re.match( r'\(_?[0-9A-Za-z]+:Person \{name:"(Alice|Bob)"\}\)', item) items = [item.strip() for item in relationships.split(",")] assert len(items) == 2 for _ in items: assert re.match(r'\(.*\)-\[:(TO|FROM)\]->\(.*\)', repr(ab))
def test_can_add_single_node(self): alice = Node(name="Alice Smith") self.graph.create(alice) self.batch.add_to_index(Node, self.people, "surname", "Smith", alice) self.batch.run() # check entries smiths = self.people.get("surname", "Smith") assert len(smiths) == 1 assert alice in smiths # done self.graph.delete(alice)
def test_param_used_thrice(self): node = Node() self.graph.create(node) statement = "MATCH (a) WHERE id(a)={X} " \ "MATCH (b) WHERE id(b)={X} " \ "MATCH (c) WHERE id(c)={X} " \ "RETURN a, b, c" params = {"X": remote(node)._id} cursor = self.graph.run(statement, params) record = cursor.next() assert record["a"] == node assert record["b"] == node assert record["c"] == node
def test_can_create_nodes_and_relationship(self): self.graph.delete_all() a = Node() b = Node() c = Node() ab = Relationship(a, "TO", b) bc = Relationship(b, "TO", c) ca = Relationship(c, "TO", a) self.graph.create(ab | bc | ca) assert remote(a) assert remote(b) assert remote(c) assert remote(ab) assert ab.start_node() == a assert ab.end_node() == b assert remote(bc) assert bc.start_node() == b assert bc.end_node() == c assert remote(ca) assert ca.start_node() == c assert ca.end_node() == a assert order(self.graph) == 3 assert size(self.graph) == 3
def test_node_label_pull_scenarios(self): label_sets = [set(), {"Foo"}, {"Foo", "Bar"}, {"Spam"}] for old_labels in label_sets: for new_labels in label_sets: node = Node(*old_labels) self.graph.create(node) node_id = remote(node)._id assert set(node.labels()) == old_labels if old_labels: remove_clause = "REMOVE a:%s" % ":".join(old_labels) else: remove_clause = "" if new_labels: set_clause = "SET a:%s" % ":".join(new_labels) else: set_clause = "" if remove_clause or set_clause: self.graph.run("MATCH (a) WHERE id(a)={x} %s %s" % (remove_clause, set_clause), x=node_id) self.graph.pull(node) assert set(node.labels()) == new_labels, \ "Failed to pull new labels %r over old labels %r" % \ (new_labels, old_labels)