Skip to content

Commit

Permalink
Merge pull request #30 from Accenture/develop
Browse files Browse the repository at this point in the history
feat: unify apis for relationships
  • Loading branch information
Roei-Levi authored Jul 6, 2023
2 parents 63a7c44 + 5e2f3d5 commit 0fe7420
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 166 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ Two queries can be combined to a create a new one.
```python
qb = QueryBuilder()
query1 = qb.match().node(labels='Person', ref_name='p').with_('p')
query2 = qb.match().node(labels='Person', ref_name='q').related_to('friend_of').node('p')
query2 = qb.match().node(labels='Person', ref_name='q').related_to('friend_of').node(ref_name='p')
query = query1 + query2
print(query)
```
This snippet will output the following Cypher query:
```cypher
MATCH (p: Person) WITH p MATCH (q: Person)-[: friend_of]->(: p)
MATCH (p: Person) WITH p MATCH (q: Person)-[: friend_of]->(p)
```

### Prerequisites
Expand Down
168 changes: 80 additions & 88 deletions src/cymple/builder.py

Large diffs are not rendered by default.

56 changes: 35 additions & 21 deletions src/cymple/internal/declarations/relation.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
"default": "None",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand All @@ -44,6 +54,16 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand All @@ -68,34 +88,18 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"**kwargs": {
"description": "kwargs"
}
}
},
{
"name": "related_variable_len",
"docstring_summary": "Concatenate a uni-directional graph Relationship, with a variable path length.",
"args": {
"label": {
"type": "str",
"default": "None",
"description": "The relationship label (type) in the DB"
},
"ref_name": {
"type": "str",
"default": "None",
"description": "A reference name to be used later in the rest of the query"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "-1"
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "-1"
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
}
},
Expand All @@ -121,6 +125,16 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand Down
56 changes: 35 additions & 21 deletions src/cymple/internal/declarations/relation_after_merge.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
"default": "None",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand All @@ -44,6 +54,16 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand All @@ -68,34 +88,18 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"**kwargs": {
"description": "kwargs"
}
}
},
{
"name": "related_variable_len",
"docstring_summary": "Concatenate a uni-directional graph Relationship, with a variable path length.",
"args": {
"label": {
"type": "str",
"default": "None",
"description": "The relationship label (type) in the DB"
},
"ref_name": {
"type": "str",
"default": "None",
"description": "A reference name to be used later in the rest of the query"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "-1"
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "-1"
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
}
},
Expand All @@ -121,6 +125,16 @@
"default": "{}",
"description": "A dict representing the set of properties by which the relationship is filtered"
},
"min_hops": {
"type": "int",
"description": "The minimal desired number of hops (set -1 for maximum boundary only)",
"default": "1"
},
"max_hops": {
"type": "int",
"description": "The maximal desired number of hops (set -1 for minimal boundary only)",
"default": "1"
},
"**kwargs": {
"description": "kwargs"
}
Expand Down
50 changes: 22 additions & 28 deletions src/cymple/internal/overloads/relation.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,45 @@



def related(self, label: str, ref_name: str = None, properties: dict = None, **kwargs):
return RelationAvailable(self.query + self._directed_relation('none', label, ref_name, properties, **kwargs))
def related(self, label: str, ref_name: str = None, properties: dict = {}, min_hops: int = 1, max_hops: int = 1, **kwargs):
return RelationAvailable(self.query + self._directed_relation('none', label, ref_name, properties, min_hops, max_hops, **kwargs))


def related_to(self, label: str, ref_name: str = None, properties: str = {}, **kwargs):
return RelationAvailable(self.query + self._directed_relation('forward', label, ref_name, properties, **kwargs))
def related_to(self, label: str, ref_name: str = None, properties: str = {}, min_hops: int = 1, max_hops: int = 1, **kwargs):
return RelationAvailable(self.query + self._directed_relation('forward', label, ref_name, properties, min_hops, max_hops, **kwargs))


def related_from(self, label: str, ref_name: str = None, properties: str = {}, **kwargs):
return RelationAvailable(self.query + self._directed_relation('backward', label, ref_name, properties, **kwargs))
def related_from(self, label: str, ref_name: str = None, properties: str = {}, min_hops: int = 1, max_hops: int = 1, **kwargs):
return RelationAvailable(self.query + self._directed_relation('backward', label, ref_name, properties, min_hops, max_hops, **kwargs))


def related_variable_len(self, label: str, ref_name: str = None, min_hops: int = -1, max_hops: int = -1):
def _directed_relation(self, direction: str, label: str, ref_name: str = None, properties: str = {}, min_hops: int = 1, max_hops: int = 1, **kwargs):
min_hops_str = '' if min_hops == -1 else str(min_hops)
max_hops_str = '' if max_hops == -1 else str(max_hops)

relation_type = '' if label is None else f': {label}'
relation_ref_name = '' if ref_name is None else f'{ref_name}'

relation_length = '*' if min_hops == -1 and max_hops == -1 else (f'*{min_hops_str}'if min_hops == max_hops else f'*{min_hops_str}..{max_hops_str}')

if relation_length:
realtion_str = f'[{relation_ref_name}{relation_type}{relation_length}]'
else:
realtion_str = ''

return RelationAvailable(self.query + f'-{realtion_str}-')


def _directed_relation(self, direction: str, label: str, ref_name: str = None, properties: str = {}, **kwargs):
relation_type = '' if label is None else f': {label}'
relation_ref_name = '' if ref_name is None else f'{ref_name}'
relation_properties = f' {{{Properties(properties).to_str(**kwargs)}}}' if properties else ''

if relation_ref_name or relation_type:
realtion_str = f'[{relation_ref_name}{relation_type}{relation_properties}]'
if min_hops == 1 and max_hops == 1:
relation_length = ''
elif min_hops == -1 and max_hops == -1:
relation_length = '*'
elif min_hops == max_hops:
relation_length = f'*{min_hops_str}'
else:
relation_length = f'*{min_hops_str}..{max_hops_str}'

if relation_ref_name or relation_type or relation_length or relation_properties:
relation_str = f'[{relation_ref_name}{relation_type}{relation_length}{relation_properties}]'
else:
realtion_str = ''
relation_str = ''

if direction == 'forward':
return f'-{realtion_str}->'
return f'-{relation_str}->'
if direction == 'backward':
return f'<-{realtion_str}-'
return f'<-{relation_str}-'

return f'-{realtion_str}-'
return f'-{relation_str}-'


__all__ = ['related', 'related_to', 'related_from', '_directed_relation']
2 changes: 1 addition & 1 deletion src/cymple/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Version information for Cymple"""

__version__: str = "0.9.0"
__version__: str = "0.10.0"
4 changes: 2 additions & 2 deletions src/samples/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get_all_nodes_related_by_fixed_num_of_hops(src_node_labels: Union[List[str],
return (QueryBuilder()
.match()
.node(labels=src_node_labels)
.related_variable_len(min_hops=num_hops, max_hops=num_hops)
.related(min_hops=num_hops, max_hops=num_hops)
.node(labels=dst_node_labels, ref_name=dst_node_name)
.return_literal(literal=dst_node_name)
)
Expand All @@ -56,7 +56,7 @@ def get_all_nodes_related_by_varying_num_of_hops(src_node_labels: Union[List[str
return (QueryBuilder()
.match()
.node(labels=src_node_labels)
.related_variable_len(min_hops=min_hops, max_hops=max_hops)
.related(min_hops=min_hops, max_hops=max_hops)
.node(labels=dst_node_labels, ref_name=dst_node_name)
.return_literal(literal=dst_node_name)
)
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_clauses.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
'RELATION (forward)': qb.reset().match().node().related_to().node(),
'RELATION (backward)': qb.reset().match().node().related_from().node(),
'RELATION (unidirectional)': qb.reset().match().node().related().node(),
'RELATION (variable length)': qb.reset().match().node().related_variable_len(min_hops=1, max_hops=2).node(),
'RELATION (variable length, empty)': qb.reset().match().node().related_variable_len().node(),
'RELATION (variable length, with label)': qb.reset().match().node().related_variable_len(label='Relation', ref_name='rel', min_hops=1, max_hops=2).node(),
'RELATION (variable length)': qb.reset().match().node().related(min_hops=1, max_hops=2).node(),
'RELATION (variable length, empty)': qb.reset().match().node().related(min_hops=-1, max_hops=-1).node(),
'RELATION (variable length, with label)': qb.reset().match().node().related(label='Relation', ref_name='rel', min_hops=1, max_hops=2).node(),
'RETURN (literal)': qb.reset().match().node(ref_name='n').return_literal('n'),
'RETURN (mapping)': qb.reset().match().node(ref_name='n').return_mapping(('n.name', 'name')),
'RETURN (mapping, list)': qb.reset().match().node(ref_name='n').return_mapping([('n.name', 'name'), ('n.age', 'age')]),
Expand Down

0 comments on commit 0fe7420

Please sign in to comment.