diff --git a/swh/graphql/resolvers/base_connection.py b/swh/graphql/resolvers/base_connection.py index 9fafb22..7f6d48c 100644 --- a/swh/graphql/resolvers/base_connection.py +++ b/swh/graphql/resolvers/base_connection.py @@ -1,84 +1,83 @@ """ """ + +from abc import ABC, abstractmethod + +from swh.graphql.utils import utils + # from dataclasses import dataclass # @dataclass # class PageInfo: # nex_page_token: str # class Arguments: # """ # dataclass # """ # after # Elements that come after the specified cursor # first # Returns the first n elements -class BaseConnection: +class BaseConnection(ABC): def __init__(self, obj, info, **kwargs): self.obj = obj self.info = info self.kwargs = kwargs self._page_data = None self.pageInfo = self.page_info self.totalCount = self.total_count def __call__(self): return self @property def edges(self): return self._get_edges() @property def nodes(self): return self.page_data.results @property def page_info(self): + # FIXME Replace with a dataclass # return PageInfo(self.page_data.next_page_token) return { "hasNextPage": bool(self.page_data.next_page_token), - "endCursor": self.page_data.next_page_token, + "endCursor": utils.get_encoded_cursor(self.page_data.next_page_token), } @property def total_count(self): """ Will be None for most of the connections """ return None @property def page_data(self): """ Cache to avoid multiple calls to the backend """ if self._page_data is None: - # FIXME, make this call async + # FIXME, make this call async (not for v1) self._page_data = self._get_page_results() return self._page_data + @abstractmethod def _get_page_results(self): """ Override for desired behaviour """ return None def _get_edges(self): return [{"cursor": "test", "node": each} for each in self.page_data.results] - - def _encode_cursor(self): - # FIXME, move to utils - pass - - def _decode_cursor(self): - # FIXME, move to utils - pass diff --git a/swh/graphql/resolvers/base_node.py b/swh/graphql/resolvers/base_node.py index ed2d99c..ec41807 100644 --- a/swh/graphql/resolvers/base_node.py +++ b/swh/graphql/resolvers/base_node.py @@ -1,27 +1,31 @@ """ """ +from abc import ABC, abstractmethod -class BaseNode: +class BaseNode(ABC): def __init__(self, obj, info, **kwargs): self.obj = obj self.info = info self.kwargs = kwargs self._node = None def __call__(self): return self.node @property def node(self): + # This is a small cache to avoid multiple + # backend calls if self._node is None: self._node = self._get_node() return self._node + @abstractmethod def _get_node(self): """ Override for desired behaviour """ return None diff --git a/swh/graphql/resolvers/origin.py b/swh/graphql/resolvers/origin.py index 0351c69..c2b1423 100644 --- a/swh/graphql/resolvers/origin.py +++ b/swh/graphql/resolvers/origin.py @@ -1,16 +1,18 @@ from .base_connection import BaseConnection from .base_node import BaseNode from swh.graphql.backends import archive class OriginConnection(BaseConnection): def _get_page_results(self): + # FIXME, make this call async (not for v1) return archive.Archive().get_origins( after=self.kwargs.get("after"), first=self.kwargs.get("first", 50) ) class OriginNode(BaseNode): def _get_node(self): + # FIXME, make this call async (not for v1) return archive.Archive().get_origin(self.kwargs.get("url")) diff --git a/swh/graphql/resolvers/resolvers.py b/swh/graphql/resolvers/resolvers.py index 7cce7eb..f62fec8 100644 --- a/swh/graphql/resolvers/resolvers.py +++ b/swh/graphql/resolvers/resolvers.py @@ -1,76 +1,75 @@ from .origin import OriginConnection, OriginNode from .visit import OriginVisitConnection from ariadne import ObjectType query = ObjectType("Query") origin = ObjectType("Origin") origins = ObjectType("OriginConnection") visit = ObjectType("Visit") -def node_resolver_factory(resolver_type, obj, info, **kw): +def get_node_resolver(resolver_type): + # FIXME, replace with a proper factory method mapping = { "origin": OriginNode, } - return mapping[resolver_type](obj, info, **kw) + if resolver_type not in mapping: + raise AttributeError("Invalid type request") + return mapping[resolver_type] -def connection_resolver_factory(resolver_type, obj, info, **kw): - mapping = { - "origins": OriginConnection, - "origin_visits": OriginVisitConnection - } - return mapping[resolver_type](obj, info, **kw) +def get_connection_resolver(resolver_type): + # FIXME, replace with a proper factory method + mapping = {"origins": OriginConnection, "origin_visits": OriginVisitConnection} + if resolver_type not in mapping: + raise AttributeError("Invalid type request") + return mapping[resolver_type] # Nodes + @query.field("origin") -def resolve_origin(_, info, **kw): +def node_resolver(obj, info, **kw): """ - Top level query - Get the origin matching the URL + Resolver for all the node types """ + # FIXME change to static factory in base class + resolver = get_node_resolver(info.field_name) + return resolver(obj, info, **kw)() + - # FIXME change to static factory in base class to avoid args - return node_resolver_factory("origin", None, info, **kw)() +# Resolvers for node fields +# Safer to annotate them here than adding as +# property in the node class @origin.field("id") def origin_id(origin, info): # Using ariadne decorator to avoid infinite loop issue with id return origin.id.hex() -# def resolve_visit(_, info, **kw): -# pass - @visit.field("date") def visit_date(visit, info): return visit.date.timestamp() @visit.field("id") def visit_id(visit, info): return str(visit.visit) # Connections +@origin.field("visits") @query.field("origins") -def resolve_origins(_, info, **kw): +def connection_resolver(obj, info, **kw): # FIXME change to static factory in base class - return connection_resolver_factory("origins", None, info, **kw)() - - -@origin.field("visits") -def origin_visits(origin, info, **kw): - return connection_resolver_factory("origin_visits", origin, info, **kw)() + resolver = get_connection_resolver(info.field_name) + return resolver(obj, info, **kw)() -@visit.field("status") -def origin_visits(origin, info, **kw): - return connection_resolver_factory("origin_visits", origin, info, **kw)() # Other diff --git a/swh/graphql/utils/utils.py b/swh/graphql/utils/utils.py new file mode 100644 index 0000000..f224a82 --- /dev/null +++ b/swh/graphql/utils/utils.py @@ -0,0 +1,9 @@ +# import base64 + + +def get_encoded_cursor(cursor): + return cursor + + +def get_decoded_cursor(cursor): + return cursor