def get_related_objects(self, rel_cls, ref_cls, obj): if ref_cls is Outgoing: rel_query = '(n)-[relation:{}]->(related)' elif ref_cls is Incoming: rel_query = '(n)<-[relation:{}]-(related)' # TODO: should get the rel name from descriptor? rel_query = rel_query.format(get_neo4j_relationship_name(rel_cls)) query = join_lines( 'MATCH {idx_lookup}, {rel_query}' 'RETURN related, relation' ) query = query.format( idx_lookup=get_match_clause(obj, 'n', self.type_registry), rel_query=rel_query ) return self.query(query)
def get_match_clause(obj, name, type_registry): """Return node lookup by index for a match clause using unique attributes Args: obj: An object to create an index lookup. name: The name of the object in the query. Returns: A string with an index lookup for a cypher MATCH clause """ if isinstance(obj, PersistableType): value = get_type_id(obj) return '({name}:PersistableType {{id: {value}}})'.format( name=name, value=json.dumps(object_to_db_value(value)), ) if isinstance(obj, Relationship): if obj.start is None or obj.end is None: raise NoUniqueAttributeError( "{} is missing a start or end node".format(obj) ) neo4j_rel_name = get_neo4j_relationship_name(type(obj)) start_name = '{}__start'.format(name) end_name = '{}__end'.format(name) query = """ {start_clause}, {end_clause}, ({start_name})-[{name}:{neo4j_rel_name}]->({end_name}) """.format( name=name, start_clause=get_match_clause( obj.start, start_name, type_registry, ), end_clause=get_match_clause( obj.end, end_name, type_registry, ), start_name=start_name, end_name=end_name, neo4j_rel_name=neo4j_rel_name, ) return dedent(query) match_params = {} label_classes = set() for cls, attr_name in type_registry.get_unique_attrs(type(obj)): value = getattr(obj, attr_name) if value is not None: label_classes.add(cls) match_params[attr_name] = value if not match_params: raise NoUniqueAttributeError( "{} doesn't have any unique attributes".format(obj) ) match_params_string = inline_parameter_map( dict_to_db_values_dict(match_params) ) labels = ':'.join(get_type_id(cls) for cls in label_classes) return '({name}:{labels} {match_params_string})'.format( name=name, labels=labels, attr_name=attr_name, match_params_string=match_params_string, )