Source code for aiida_restapi.graphql.plugins

"""Module defining the graphql plugin mechanism."""

from typing import Any, Callable, Dict, NamedTuple, Sequence, Type, Union

import graphene as gr

# TODO it would be ideal if this was more specific, i.e.
# func(parent: Any, info: gr.ResolveInfo, **kwargs: Any): ...
ResolverType = Callable[..., Any]


[docs] class QueryPlugin(NamedTuple): """Define a top-level query, to plugin to the schema.""" name: str field: gr.ObjectType resolver: ResolverType
[docs] def create_query(queries: Sequence[QueryPlugin], docstring: str = 'The root query') -> Type[gr.ObjectType]: """Generate a query from a sequence of query plugins.""" # check that there are no duplicate names name_map: Dict[str, QueryPlugin] = {} # construct the dict of attributes/methods on the class attr_map: Dict[str, Union[gr.ObjectType, ResolverType]] = {} for query in queries: if query.name.startswith('resolve_'): raise ValueError('Plugin name cannot') if query.name in name_map: raise ValueError(f"Duplicate plugin name '{query.name}': {query} and {name_map[query.name]}") name_map[query.name] = query attr_map[query.name] = query.field attr_map[f'resolve_{query.name}'] = query.resolver attr_map['__doc__'] = docstring return type('RootQuery', (gr.ObjectType,), attr_map)
[docs] def create_schema( queries: Sequence[QueryPlugin], docstring: str = 'The root query', auto_camelcase: bool = False, **kwargs: Any, ) -> gr.Schema: """Generate a schema from a sequence of query plugins. Note we set auto_camelcase False, since this keeps database field names the same. """ return gr.Schema(query=create_query(queries, docstring), auto_camelcase=auto_camelcase, **kwargs)