def inject_pg_backrefs(): """Add a dict of links to this class. Backrefs look like: .. code-block:: { <link name>: {'name': <backref name>, 'src_type': <source type> } } """ for src_label, subschema in dictionary.schema.iteritems(): for name, link in get_links(subschema).iteritems(): dst_cls = Node.get_subclass(link['target_type']) dst_cls._pg_backrefs[link['backref']] = { 'name': link['name'], 'src_type': Node.get_subclass(src_label) }
def set_row_type(row): """Get the class for a row dict, setting 'type'. Coerce '' -> None.""" row["type"] = row.get("type", None) if not row["type"]: row.pop("type") return None return Node.get_subclass(row["type"])
def load_edges(): """Add a dictionry of links from this class { <link name>: {'backref': <backref name>, 'type': <source type> } } """ for src_label, subschema in dictionary.schema.iteritems(): src_cls = Node.get_subclass(src_label) if not src_cls: raise RuntimeError('No source class labeled {}'.format(src_label)) for name, link in get_links(subschema).iteritems(): edge_label = link['label'] edge_name = parse_edge( src_label, name, edge_label, subschema, link) src_cls._pg_links[link['name']] = { 'edge_out': edge_name, 'dst_type': Node.get_subclass(link['target_type']) } for src_cls in Node.get_subclasses(): cache_case = ( src_cls._dictionary['category'] in RELATED_CASES_CATEGORIES or src_cls.label in ['annotation'] ) if not cache_case: continue link = { 'name': RELATED_CASES_LINK_NAME, 'multiplicity': 'many_to_one', 'required': False, 'target_type': 'case', 'label': 'relates_to', 'backref': '_related_{}'.format(src_cls.label), } edge_name = parse_edge( src_cls.label, link['name'], 'relates_to', {'id': src_cls.label}, link, )
def load_edges(): """Add a dictionry of links from this class { <link name>: {'backref': <backref name>, 'type': <source type> } } """ for src_label, subschema in dictionary.schema.iteritems(): src_cls = Node.get_subclass(src_label) if not src_cls: raise RuntimeError('No source class labeled {}'.format(src_label)) for name, link in get_links(subschema).iteritems(): edge_label = link['label'] edge_name = parse_edge(src_label, name, edge_label, subschema, link) src_cls._pg_links[link['name']] = { 'edge_out': edge_name, 'dst_type': Node.get_subclass(link['target_type']) } for src_cls in Node.get_subclasses(): cache_case = (src_cls._dictionary['category'] in RELATED_CASES_CATEGORIES or src_cls.label in ['annotation']) if not cache_case: continue link = { 'name': RELATED_CASES_LINK_NAME, 'multiplicity': 'many_to_one', 'required': False, 'target_type': 'case', 'label': 'relates_to', 'backref': '_related_{}'.format(src_cls.label), } edge_name = parse_edge( src_cls.label, link['name'], 'relates_to', {'id': src_cls.label}, link, )
def get_node_count_result(self, field): label = "_".join(self.top.name.split("_")[1:-1]) cls = Node.get_subclass(label) if not cls: self.errors.append("Unable to execute {} count".format(label)) return None node_query = ns.NodeSubclassQuery(self.g, None, self.fragments) q = self.get_authorized_query(cls) for arg in self.top.arguments: q = node_query.add_arg_filter(q, arg) self.result = {self.top.key: clean_count(q)}
def lookup_node(psql_driver, label, node_id=None, secondary_keys=None): """Return a query for nodes by id and secondary keys""" cls = Node.get_subclass(label) query = psql_driver.nodes(cls) if node_id is None and not secondary_keys: return query.filter(sqlalchemy.sql.false()) if node_id is not None: query = query.ids(node_id) if all(all(keys) for keys in secondary_keys): query = query.filter(cls._secondary_keys == secondary_keys) return query
def _get_paths_from(src, app): if isinstance(src, type) and issubclass(src, Node): src_label = src.label else: src, src_label = Node.get_subclass(src), src if src_label not in app.graph_traversals: # GOTCHA: lazy initialization is not locked because 1) threading is not enabled # in production with uWSGI, and 2) this always generates the same result for the # same input so there's no racing condition to worry about start = time.time() app.graph_traversals[src_label] = construct_traversals_from_node( src, app) time_taken = int(round(time.time() - start)) if time_taken > 0.5: app.logger.info( 'Traversed the graph starting from "%s" in %.2f sec', src_label, time_taken) return app.graph_traversals[src_label]
def parse_field(self, field, query_class): """Lookup the correct query class and add results, errors to this instance """ if query_class and hasattr(query_class, 'parse'): pass elif isinstance(field, FragmentSpread): query_class = FragmentQuery elif Node.get_subclass(field.name): query_class = NodeSubclassQuery elif field.name.endswith('_count'): query_class = NodeCountQuery if query_class: self.subquery(query_class, field, self.result) else: self.errors.append("Cannot query field '{}' on 'Root'".format( field.name))
def _munge_properties(source, nested=True): # Get properties from schema cls = Node.get_subclass(source) assert cls, 'No model for {}'.format(source) properties = cls.get_pg_properties() fields = properties.keys() # Add id to document id_name = '{}_id'.format(source) doc = Dict({id_name: STRING}) # Add all properties to document for field in fields: _type = _get_es_type(properties[field] or []) # assign the type doc[field] = {'type': _type} if str(_type) == 'string': doc[field]['index'] = 'not_analyzed' return doc
def EdgeFactory(name, label, src_label, dst_label, src_dst_assoc, dst_src_assoc, _assigned_association_proxies=defaultdict(set)): """Returns an edge class. :param name: The name of the edge class. :param label: Assigned to ``edge.label`` :param src_label: The label of the source edge :param dst_label: The label of the destination edge :param src_dst_assoc: The link name i.e. ``src.src_dst_assoc`` returns a list of destination type nodes :param dst_src_assoc: The backref name i.e. ``dst.dst_src_assoc`` returns a list of source type nodes :param _assigned_association_proxies: Don't pass this parameter. This will be used to store what links and backrefs have been assigned to the source and destination nodes. This prevents clobbering a backref with a link or a link with a backref, as they would be from different nodes, should be different relationships, and would have different semantic meanings. """ # Correctly format all of the names name = remove_spaces(name) label = remove_spaces(label) src_label = remove_spaces(src_label) dst_label = remove_spaces(dst_label) src_dst_assoc = remove_spaces(src_dst_assoc) dst_src_assoc = remove_spaces(dst_src_assoc) # Generate the tablename. If it is too long, it will be hashed and # truncated. tablename = generate_edge_tablename(src_label, label, dst_label) # Lookup the tablenames for the source and destination classes src_cls = Node.get_subclass(src_label) dst_cls = Node.get_subclass(dst_label) # Assert that we're not clobbering link names assert dst_src_assoc not in _assigned_association_proxies[dst_label], ( "Attempted to assign backref '{link}' to node '{node}' but " "the node already has an attribute called '{link}'" .format(link=dst_src_assoc, node=dst_label)) assert src_dst_assoc not in _assigned_association_proxies[src_label], ( "Attempted to assign link '{link}' to node '{node}' but " "the node already has an attribute called '{link}'" .format(link=src_dst_assoc, node=src_label)) # Remember that we're adding this link and this backref _assigned_association_proxies[dst_label].add(dst_src_assoc) _assigned_association_proxies[src_label].add(src_dst_assoc) hooks_before_insert = Edge._session_hooks_before_insert + [ cache_related_cases_on_insert, ] hooks_before_update = Edge._session_hooks_before_update + [ cache_related_cases_on_update, ] hooks_before_delete = Edge._session_hooks_before_delete + [ cache_related_cases_on_delete, ] cls = type(name, (Edge,), { '__label__': label, '__tablename__': tablename, '__src_class__': get_class_name_from_id(src_label), '__dst_class__': get_class_name_from_id(dst_label), '__src_dst_assoc__': src_dst_assoc, '__dst_src_assoc__': dst_src_assoc, '__src_table__': src_cls.__tablename__, '__dst_table__': dst_cls.__tablename__, '_session_hooks_before_insert': hooks_before_insert, '_session_hooks_before_update': hooks_before_update, '_session_hooks_before_delete': hooks_before_delete, }) return cls
def EdgeFactory(name, label, src_label, dst_label, src_dst_assoc, dst_src_assoc, _assigned_association_proxies=defaultdict(set)): """Returns an edge class. :param name: The name of the edge class. :param label: Assigned to ``edge.label`` :param src_label: The label of the source edge :param dst_label: The label of the destination edge :param src_dst_assoc: The link name i.e. ``src.src_dst_assoc`` returns a list of destination type nodes :param dst_src_assoc: The backref name i.e. ``dst.dst_src_assoc`` returns a list of source type nodes :param _assigned_association_proxies: Don't pass this parameter. This will be used to store what links and backrefs have been assigned to the source and destination nodes. This prevents clobbering a backref with a link or a link with a backref, as they would be from different nodes, should be different relationships, and would have different semantic meanings. """ # Correctly format all of the names name = remove_spaces(name) label = remove_spaces(label) src_label = remove_spaces(src_label) dst_label = remove_spaces(dst_label) src_dst_assoc = remove_spaces(src_dst_assoc) dst_src_assoc = remove_spaces(dst_src_assoc) # Generate the tablename. If it is too long, it will be hashed and # truncated. tablename = generate_edge_tablename(src_label, label, dst_label) # Lookup the tablenames for the source and destination classes src_cls = Node.get_subclass(src_label) dst_cls = Node.get_subclass(dst_label) # Assert that we're not clobbering link names assert dst_src_assoc not in _assigned_association_proxies[dst_label], ( "Attempted to assign backref '{link}' to node '{node}' but " "the node already has an attribute called '{link}'".format( link=dst_src_assoc, node=dst_label)) assert src_dst_assoc not in _assigned_association_proxies[src_label], ( "Attempted to assign link '{link}' to node '{node}' but " "the node already has an attribute called '{link}'".format( link=src_dst_assoc, node=src_label)) # Remember that we're adding this link and this backref _assigned_association_proxies[dst_label].add(dst_src_assoc) _assigned_association_proxies[src_label].add(src_dst_assoc) hooks_before_insert = Edge._session_hooks_before_insert + [ cache_related_cases_on_insert, ] hooks_before_update = Edge._session_hooks_before_update + [ cache_related_cases_on_update, ] hooks_before_delete = Edge._session_hooks_before_delete + [ cache_related_cases_on_delete, ] cls = type( name, (Edge, ), { '__label__': label, '__tablename__': tablename, '__src_class__': get_class_name_from_id(src_label), '__dst_class__': get_class_name_from_id(dst_label), '__src_dst_assoc__': src_dst_assoc, '__dst_src_assoc__': dst_src_assoc, '__src_table__': src_cls.__tablename__, '__dst_table__': dst_cls.__tablename__, '_session_hooks_before_insert': hooks_before_insert, '_session_hooks_before_update': hooks_before_update, '_session_hooks_before_delete': hooks_before_delete, }) return cls