def test_simple_labeled_node(): node = Node('Node') assert node.labels == ('Node',) # cannot reset label once created with pytest.raises(AttributeError): node.labels = ('bob',) assert not node.schema
def test_create_undirected_relationship(): rel = Relationship('KNOWS', Node('User', var='m'), Node('User', var='n'), var='r', directed=False) assert str(Create(rel)) == 'CREATE (m)-[r:`KNOWS`]-(n)'
def test_where_and_or(): person = Node('Person', name='Ali', age=Property(value=29, type=int), hair_color='red', var='n') expected_match = [ 'MATCH (n:`Person`)', ' WHERE n.name = {n_name}', ] match = Match(person.bind('name')) assert str(match) == '\n'.join(expected_match) assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' match.where(person['age']) == 29 expected_match.append(' AND n.age = {n_age}') assert str(match) == '\n'.join(expected_match) assert len(match.params) == 2 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' assert 'n_age' in match.params assert match.params['n_age'] == 29 match = Match(person.bind('name')) match.where(person['age'], or_=True) == 29 expected_match.pop() expected_match.append(' OR n.age = {n_age}') assert str(match) == '\n'.join(expected_match) assert len(match.params) == 2 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' assert 'n_age' in match.params assert match.params['n_age'] == 29
def test_node_set_once(): node = Node('x') with pytest.raises(ImmutableAttributeError): node.labels = list('abc') with pytest.raises(ImmutableAttributeError): node.type = 'y' with pytest.raises(ImmutableAttributeError): del node.labels with pytest.raises(ImmutableAttributeError): del node.type
def test_full_relationship_create(): expected_query = ('MATCH (m:`User`)\n' 'MATCH (n:`User`)\n' 'CREATE (m)-[rel:`KNOWS`]->(n)') user_m = Node('User', name=Property(), var='m') user_n = user_m.copy(var='n') rel = Relationship('KNOWS', user_m, user_n) query = Match(user_m) & Match(user_n) & Create(rel) assert str(query) == expected_query assert len(query.params) == 0
def test_relationship_set_once(): rel = Relationship(None) rel.type = 'X' rel.start_node = Node('x') rel.end_node = Node('y') with pytest.raises(ImmutableAttributeError): rel.directed = False with pytest.raises(ImmutableAttributeError): rel.type = 'Y' with pytest.raises(ImmutableAttributeError): rel.start_node = Node('a') with pytest.raises(ImmutableAttributeError): rel.end_node = Node('b') rel = Relationship('X') with pytest.raises(ImmutableAttributeError): rel.type = 'Y' rel = Relationship('X', Node('a')) with pytest.raises(ImmutableAttributeError): rel.start_node = Node('a') rel = Relationship('X', Node('a'), Node('b')) with pytest.raises(ImmutableAttributeError): rel.end_node = Node('a') with pytest.raises(ImmutableAttributeError): del rel.type with pytest.raises(ImmutableAttributeError): del rel.directed with pytest.raises(ImmutableAttributeError): del rel.start_node with pytest.raises(ImmutableAttributeError): del rel.end_node
def test_union_and_union_all(): n = Node('Person', name='Mr. N', var='n') m = n.copy(var='m', name='Mrs. M') expected_stmt = [ 'MATCH (n:`Person`)', 'UNION', 'MATCH (m:`Person`)', ] assert str(Match(n) ^ Match(m)) == '\n'.join(expected_stmt) expected_stmt[1] += ' ALL' assert str(Match(n) | Match(m)) == '\n'.join(expected_stmt)
def test_property_set_once(): prop = Property() with pytest.raises(ImmutableAttributeError): prop.type = int with pytest.raises(ImmutableAttributeError): prop.indexed = False with pytest.raises(ImmutableAttributeError): prop.unique = True with pytest.raises(ImmutableAttributeError): prop.required = 5 with pytest.raises(ImmutableAttributeError): prop.primary_key = None with pytest.raises(ImmutableAttributeError): prop.read_only = "DON'T CHANGE ME" # Can change these b/c at this point they're still None prop.name = 'fred' prop.default = 5 # Type checking is still performed with pytest.raises(ValueError): prop.obj = 5 prop.obj = Node('x') with pytest.raises(ImmutableAttributeError): prop.name = 'bob' with pytest.raises(ImmutableAttributeError): prop.default = 9 with pytest.raises(ImmutableAttributeError): prop.obj = Node('y') prop = Property(default=5, obj=Node('x')) with pytest.raises(ImmutableAttributeError): prop.default = 9 with pytest.raises(ImmutableAttributeError): prop.obj = Node('y') with pytest.raises(ImmutableAttributeError): del prop.name with pytest.raises(ImmutableAttributeError): del prop.type with pytest.raises(ImmutableAttributeError): del prop.default with pytest.raises(ImmutableAttributeError): del prop.obj with pytest.raises(ImmutableAttributeError): del prop.unique with pytest.raises(ImmutableAttributeError): del prop.indexed with pytest.raises(ImmutableAttributeError): del prop.required with pytest.raises(ImmutableAttributeError): del prop.primary_key with pytest.raises(ImmutableAttributeError): del prop.read_only
def test_where_and_set(): person = Node('Person', name='Ali', age=Property(value=29, type=int), hair_color='red', var='n') expected_match = [ 'MATCH (n:`Person`)', ' WHERE n.name = {n_name}', ] match = Match(person.bind('name')) assert str(match) == '\n'.join(expected_match) assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' expected_match = [ 'MATCH (n:`Person`)', ' WHERE n.name = {n_name} AND n.age = {n_age}', ] match = Match(person.bind('name', 'age')) try: assert str(match) == '\n'.join(expected_match) except AssertionError: expected_match.pop() expected_match.append( ' WHERE n.age = {n_age}' ' AND n.name = {n_name}' ) assert str(match) == '\n'.join(expected_match) assert len(match.params) == 2 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' assert 'n_age' in match.params assert match.params['n_age'] == 29 match.set(person['age'] == 30) expected_match.append(' SET n.age = {param0}') assert str(match) == '\n'.join(expected_match) assert len(match.params) == 3 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' assert 'n_age' in match.params assert match.params['n_age'] == 29 assert 'param0' in match.params assert match.params['param0'] == 30 match.set(person['name'] == 'Alison') expected_match.append(' SET n.name = {param1}') assert str(match) == '\n'.join(expected_match) assert len(match.params) == 4 assert 'n_name' in match.params assert match.params['n_name'] == 'Ali' assert 'n_age' in match.params assert match.params['n_age'] == 29 assert 'param0' in match.params assert match.params['param0'] == 30 assert 'param1' in match.params assert match.params['param1'] == 'Alison'
def test_full_relationship_create(): expected_query = ( 'MATCH (m:`User`)\n' 'MATCH (n:`User`)\n' 'CREATE (m)-[rel:`KNOWS`]->(n)' ) user_m = Node('User', name=Property(), var='m') user_n = user_m.copy(var='n') rel = Relationship('KNOWS', user_m, user_n) query = Match(user_m) & Match(user_n) & Create(rel) assert str(query) == expected_query assert len(query.params) == 0
def test_create_node_one_prop(): expected_stmt = ('CREATE (node:`User`)\n' ' SET node.name = {node_name}') user = Node('User', name=Property()) create = Create(user) assert str(create) == expected_stmt assert len(create.params) == 1 assert 'node_name' in create.params assert create.params['node_name'] is None user.name = 'Frank' create = Create(user) assert str(create) == expected_stmt assert len(create.params) == 1 assert 'node_name' in create.params assert create.params['node_name'] == 'Frank'
def test_node_one_required(): person = Node('Person', name=Property(required=True)) assert person.schema == ['CONSTRAINT ON ( person:Person ) ' 'ASSERT exists(person.name)'] assert not person['name'].indexed assert not person['name'].unique assert person['name'].required
def test_logical_cypher_expressions(): person = Node('Person', name=Property(), var='n') match = Match(person).where(person['name'] == 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name = {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice' match = Match(person).where(person['name'] != 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name <> {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice' match = Match(person).where(person['name'] >= 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name >= {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice' match = Match(person).where(person['name'] <= 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name <= {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice' match = Match(person).where(person['name'] < 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name < {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice' match = Match(person).where(person['name'] > 'Alice') assert str(match) == 'MATCH (n:`Person`)\n WHERE n.name > {n_name}' assert len(match.params) == 1 assert 'n_name' in match.params assert match.params['n_name'] == 'Alice'
def test_node_one_unique(): person = Node('Person', SSN=Property(unique=True)) assert person.schema == ['CONSTRAINT ON ( person:Person ) ' 'ASSERT person.SSN IS UNIQUE'] assert person['SSN'].indexed assert person['SSN'].unique assert not person['SSN'].required
def test_create_node_one_prop(): expected_stmt = ( 'CREATE (node:`User`)\n' ' SET node.name = {node_name}' ) user = Node('User', name=Property()) create = Create(user) assert str(create) == expected_stmt assert len(create.params) == 1 assert 'node_name' in create.params assert create.params['node_name'] is None user.name = 'Frank' create = Create(user) assert str(create) == expected_stmt assert len(create.params) == 1 assert 'node_name' in create.params assert create.params['node_name'] == 'Frank'
def test_create_node_two_labels(): expected_stmts = ('CREATE (node:`Person`:`User`)\n' ' SET node.name = {node_name}', 'CREATE (node:`User`:`Person`)\n' ' SET node.name = {node_name}') user = Node('User', 'Person', name=Property()) create = Create(user) assert str(create) in expected_stmts
def test_merge(): kev = Node('Person', name='Kevin', var='kev').bind('name') ali = Node('Person', name='Ali', var='ali').bind('name') rel = Relationship('LOVES', kev, ali, duration='forever').bind('duration') expected_stmt = [ 'MATCH (kev:`Person`)', ' WHERE kev.name = {kev_name}', 'MATCH (ali:`Person`)', ' WHERE ali.name = {ali_name}', 'MERGE (kev)-[rel:`LOVES` {duration: {rel_duration}}]->(ali)' ] query = Match(kev) & Match(ali) & Merge(rel) assert str(query) == '\n'.join(expected_stmt) assert len(query.params) == 3 assert 'kev_name' in query.params assert query.params['kev_name'] == 'Kevin' assert 'ali_name' in query.params assert query.params['ali_name'] == 'Ali' assert 'rel_duration' in query.params assert query.params['rel_duration'] == 'forever'
def test_full_match(): expected_stmt = [ 'MATCH (m:`Person`)', ' WHERE m.name = {m_name}', 'MATCH (n:`Person`)', ' WHERE n.name = {n_name}', 'MATCH (m)-[rel:`KNOWS`]->(n)', ] person_m = Node('Person', name='Alice', var='m').bind('name') person_n = person_m.copy(name='Bob', var='n') knows = Relationship('KNOWS', person_m, person_n) match = Match(person_m) & Match(person_n) & Match(knows) assert str(match) == '\n'.join(expected_stmt) assert len(match.params) == 2 assert 'm_name' in match.params assert match.params['m_name'] == 'Alice' assert 'n_name' in match.params assert match.params['n_name'] == 'Bob' match.return_().order_by(person_n['name']).skip(1).limit(1) expected_stmt += [ 'RETURN *', 'ORDER BY n.name', 'SKIP 1', 'LIMIT 1', ] assert str(match) == '\n'.join(expected_stmt) assert len(match.params) == 2 assert 'm_name' in match.params assert match.params['m_name'] == 'Alice' assert 'n_name' in match.params assert match.params['n_name'] == 'Bob' expected_stmt[-3] += ' DESC' for _ in range(3): match.pop() match.order_by(person_n['name'], desc=True).skip(1).limit(1) assert str(match) == '\n'.join(expected_stmt) assert len(match.params) == 2 assert 'm_name' in match.params assert match.params['m_name'] == 'Alice' assert 'n_name' in match.params assert match.params['n_name'] == 'Bob'
def test_return(): n = Node('Person', name=Property(), x=Property(), y=Property(), var='n') match = Match(n) query = 'MATCH (n:`Person`)' assert str(match.return_()) == '\n'.join((query, 'RETURN *')) match.pop() assert str(match.return_(n)) == '\n'.join((query, 'RETURN n')) match.pop() m = Node('Person', x=Property(), var='m') match &= Match(m) query = '\n'.join((query, 'MATCH (m:`Person`)')) assert str(match.return_(n, m)) == '\n'.join((query, 'RETURN n, m')) match.pop() assert str(match.return_(n['name'])) == '\n'.join((query, 'RETURN n.name')) match.pop() assert str(match.return_(n['x'], n['y'])) == '\n'.join((query, 'RETURN n.x, n.y')) match.pop() assert str(match.return_(m['x'], n['y'])) == '\n'.join((query, 'RETURN m.x, n.y'))
def test_cypher_methods(): n = Node('Person', name='Mr. N', var='n') match = Match(n) query = 'MATCH (n:`Person`)' assert str(match.delete(n)) == '\n'.join((query, 'DELETE n')) match.pop() assert str(match.delete(n['name'])) == '\n'.join((query, 'DELETE n.name')) match.pop() assert str(match.delete(n, detach=True)) == '\n'.join((query, 'DETACH DELETE n')) match.pop() assert str(match.remove(n['name'])) == '\n'.join((query, 'REMOVE n.name')) match.pop() assert (str(match.delete(n).with_(n).return_(n['name'])) == '\n'.join((query, 'DELETE n', 'WITH n', 'RETURN n.name')))
def test_create_node_two_props(): user = Node('User', name=Property(), age=Property(type=int)) create = Create(user) assert len(create.params) == 2 assert 'node_name' in create.params assert create.params['node_name'] is None assert 'node_age' in create.params assert create.params['node_age'] is None create.set(user['name'] == 'Frank') assert len(create.params) == 2 assert 'node_name' in create.params assert create.params['node_name'] == 'Frank' assert 'node_age' in create.params assert create.params['node_age'] is None create.set(user['age'] == '29') assert len(create.params) == 2 assert 'node_name' in create.params assert create.params['node_name'] == 'Frank' assert 'node_age' in create.params assert create.params['node_age'] == 29
def test_merge_on_create_on_match(): person = Node('Person', name=Property()) merge = ( Merge(person) .on_create() .set(person['name'] == 'Fred') .on_match() .set(person['name'] == 'Bob') ) expected_stmt = '\n'.join(( 'MERGE (node:`Person`)', 'ON CREATE', ' SET node.name = {node_name}', 'ON MATCH', ' SET node.name = {param0}' )) assert str(merge) == expected_stmt assert len(merge.params) == 2 assert 'node_name' in merge.params assert merge.params['node_name'] == 'Fred' assert 'param0' in merge.params assert merge.params['param0'] == 'Bob'
def test_matching_anonymous_relationship(): person_m = Node('Person', var='m') person_n = person_m.copy(var='n') rel = Relationship(None, person_m, person_n) match = Match(rel) assert str(match) == 'MATCH (m)-[rel]->(n)'
def test_optional_match(): person_m = Node('Person', var='m') person_n = person_m.copy(var='n') rel = Relationship(None, person_m, person_n) match = Match(rel, optional=True) assert str(match) == 'OPTIONAL MATCH (m)-[rel]->(n)'
def test_complex_logical_cypher_expressions(): Person = Node('Person', name=Property(), hair_color=Property(), var='n') expected_match = [ 'MATCH (n:`Person`)', ' WHERE n.name = {n_name}', ' AND n.hair_color = {n_hair_color}' ] match = (Match(Person).where(Person['name'] == 'Alice').where( Person['hair_color'] == 'red')) assert str(match) == '\n'.join(expected_match) assert match.params == {'n_name': 'Alice', 'n_hair_color': 'red'} match = (Match(Person).where((Person['name'] == 'Alice'), (Person['hair_color'] == 'red'))) assert str(match) == '\n'.join((expected_match[0], ' '.join( (expected_match[1], expected_match[2].lstrip())))) assert match.params == {'n_name': 'Alice', 'n_hair_color': 'red'} Person = Node('Person', name=Property(), hair_color=Property(), age=Property(type=int), var='n') expected_match.append(' AND n.age = {n_age}') match = (Match(Person).where((Person['name'] == 'Alice'), (Person['hair_color'] == 'red'), (Person['age'] == '29'))) assert str(match) == '\n'.join((expected_match[0], ' '.join( (expected_match[1], expected_match[2].lstrip(), expected_match[3].lstrip())))) assert match.params == { 'n_name': 'Alice', 'n_hair_color': 'red', 'n_age': 29 } match = (Match(Person).where(Person['name'] == 'Alice').where( Person['hair_color'] == 'red').where(Person['age'] == 29)) assert str(match) == '\n'.join(expected_match) assert match.params == { 'n_name': 'Alice', 'n_hair_color': 'red', 'n_age': 29 } expected_match[3] = expected_match[3].replace('AND', ' OR') match = (Match(Person).where( (Person['name'] == 'Alice'), (Person['hair_color'] == 'red')).where(Person['age'] == 29, or_=True)) assert str(match) == '\n'.join((expected_match[0], ' '.join( (expected_match[1], expected_match[2].lstrip())), expected_match[3])) assert match.params == { 'n_name': 'Alice', 'n_hair_color': 'red', 'n_age': 29 } match = (Match(Person).where(Person['name'] == 'Alice').where( Person['hair_color'] == 'red').where(Person['age'] == 29, or_=True)) assert str(match) == '\n'.join(expected_match) assert match.params == { 'n_name': 'Alice', 'n_hair_color': 'red', 'n_age': 29 }
def test_arithmetic_cypher_expressions(): Person = Node('Person', age=Property(type=int), var='n') expected_stmt = ['MATCH (n:`Person`)', ''] match = Match(Person).where((Person['age'] + 5) == 23) expected_stmt[1] = ' WHERE n.age + {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 5 assert match.params['param0'] == 23 match = Match(Person).where((5 + Person['age']) == 23) assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 5 assert match.params['param0'] == 23 match = Match(Person).where((Person['age'] - 4) == 13) expected_stmt[1] = ' WHERE n.age - {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((4 - Person['age']) == 13) expected_stmt[1] = ' WHERE {n_age} - n.age = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((Person['age'] * 5) == 23) expected_stmt[1] = ' WHERE n.age * {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 5 assert match.params['param0'] == 23 match = Match(Person).where((5 * Person['age']) == 23) assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 5 assert match.params['param0'] == 23 match = Match(Person).where((Person['age'] / 4) == 13) expected_stmt[1] = ' WHERE n.age / {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((4 / Person['age']) == 13) expected_stmt[1] = ' WHERE {n_age} / n.age = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((Person['age'] % 4) == 13) expected_stmt[1] = ' WHERE n.age % {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((4 % Person['age']) == 13) expected_stmt[1] = ' WHERE {n_age} % n.age = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((Person['age']**4) == 13) expected_stmt[1] = ' WHERE n.age ^ {n_age} = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13 match = Match(Person).where((4**Person['age']) == 13) expected_stmt[1] = ' WHERE {n_age} ^ n.age = {param0}' assert str(match) == '\n'.join(expected_stmt) assert match.params['n_age'] == 4 assert match.params['param0'] == 13
def test_create_node_no_props(): user = Node('User') create = Create(user) assert str(create) == 'CREATE (node:`User`)' assert not create.params
def test_create_relationship(): rel = Relationship('KNOWS', Node('User'), Node('User')) with pytest.raises(ValueError): create = Create(rel) rel.end_node.var = 'end_node' assert str(Create(rel)) == 'CREATE (node)-[rel:`KNOWS`]->(end_node)'
def test_create_relation_to_nowhere(): rel = Relationship('KNOWS', Node('User')) with pytest.raises(DetachedObjectError): create = Create(rel)
def test_node_one_index(): person = Node('Person', name=Property(indexed=True)) assert person.schema == ['INDEX ON :Person(name)'] assert person['name'].indexed assert not person['name'].unique assert not person['name'].required