diff --git a/swh/graphql/app.py b/swh/graphql/app.py index 43a5661..0be52b9 100644 --- a/swh/graphql/app.py +++ b/swh/graphql/app.py @@ -1,18 +1,19 @@ from ariadne import gql, load_schema_from_path, make_executable_schema from ariadne.asgi import GraphQL from .resolvers import resolvers, scalars type_defs = gql(load_schema_from_path("swh/graphql/schema/schema.graphql")) schema = make_executable_schema( type_defs, resolvers.query, resolvers.origin, resolvers.origins, resolvers.visit, + resolvers.visitstatus, scalars.datetime_scalar, scalars.swhid_scalar, ) app = GraphQL(schema, debug=True) diff --git a/swh/graphql/backends/archive.py b/swh/graphql/backends/archive.py index 49bb407..70da8ba 100644 --- a/swh/graphql/backends/archive.py +++ b/swh/graphql/backends/archive.py @@ -1,22 +1,27 @@ from swh.storage import get_storage class Archive: def __init__(self): # FIXME, setup config self.storage = get_storage( cls="remote", url="http://moma.internal.softwareheritage.org:5002" ) def get_origin(self, url): return self.storage.origin_get([url])[0] def get_origins(self, after=None, first=50): # FIXME change page_token to base64 encode return self.storage.origin_list(page_token=after, limit=first) def get_origin_visits(self, origin_url, after=None, first=50): return self.storage.origin_visit_get(origin_url, page_token=after, limit=first) def get_origin_visit(self, origin_url, visit_id): return self.storage.origin_visit_get_by(origin_url, visit_id) + + def get_visit_status(self, origin_url, visit_id, after=None, first=50): + return self.storage.origin_visit_status_get( + origin_url, visit_id, page_token=after, limit=first + ) diff --git a/swh/graphql/resolvers/resolvers.py b/swh/graphql/resolvers/resolvers.py index d93e41d..e07b3ba 100644 --- a/swh/graphql/resolvers/resolvers.py +++ b/swh/graphql/resolvers/resolvers.py @@ -1,84 +1,96 @@ from ariadne import ObjectType from swh.graphql.utils import utils from .origin import OriginConnection, OriginNode -from .visit import OriginVisit, OriginVisitConnection +from .visit import OriginVisit, OriginVisitConnection, VisitStatusConnection query = ObjectType("Query") origin = ObjectType("Origin") origins = ObjectType("OriginConnection") visit = ObjectType("Visit") +visitstatus = ObjectType("VisitStatus") def get_mapping_key(info): """ Logic to resolve mapping type """ # FIXME, move to utils if info.path.prev: return f"{info.path.prev.key}_{info.path.key}" return info.path.key def get_node_resolver(info): # FIXME, replace with a proper factory method mapping = {"origin": OriginNode, "visit": OriginVisit} resolver_type = info.path.key # get_mapping_key(info) # FIXME, get full name if resolver_type not in mapping: raise AttributeError(f"Invalid type request {resolver_type}") return mapping[resolver_type] def get_connection_resolver(info): # FIXME, replace with a proper factory method - mapping = {"origins": OriginConnection, "visits": OriginVisitConnection} + mapping = { + "origins": OriginConnection, + "visits": OriginVisitConnection, + "status": VisitStatusConnection, + } resolver_type = info.path.key # get_mapping_key(info) # FIXME, get full name if resolver_type not in mapping: raise AttributeError(f"Invalid type request {resolver_type}") return mapping[resolver_type] # Nodes @query.field("visit") @query.field("origin") def node_resolver(obj, info, **kw): """ Resolver for all the node types """ # FIXME change to static factory in base class resolver = get_node_resolver(info) return resolver(obj, 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() +# Using ariadne resolution instead of adding properties in Node +# That is to avoid looping in NodeConnection @visit.field("id") def visit_id(visit, info): # FIXME, find a better id for visit return utils.encode(f"{visit.origin}-{str(visit.visit)}") +@visitstatus.field("id") +def visit_status_id(_, info): + # FIXME, find a better id + return utils.encode("temp-id") + + +@visitstatus.field("snapshot") +def visit_status_id(status, info, **kw): + # return SnapshotNode() + return status.snapshot.hex() + + # Connections +@visit.field("status") @origin.field("visits") @query.field("origins") def connection_resolver(obj, info, **kw): # FIXME change to static factory in base class resolver = get_connection_resolver(info) return resolver(obj, info, **kw)() # Other diff --git a/swh/graphql/resolvers/snapshot.py b/swh/graphql/resolvers/snapshot.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/swh/graphql/resolvers/snapshot.py @@ -0,0 +1 @@ +pass diff --git a/swh/graphql/resolvers/visit.py b/swh/graphql/resolvers/visit.py index 78ea9dc..7755084 100644 --- a/swh/graphql/resolvers/visit.py +++ b/swh/graphql/resolvers/visit.py @@ -1,29 +1,35 @@ from swh.graphql.backends import archive from .base_connection import BaseConnection from .base_node import BaseNode class OriginVisit(BaseNode): def _get_node(self): # FIXME, make this call async (not for v1) return archive.Archive().get_origin_visit( self.kwargs.get("originUrl"), int(self.kwargs.get("id")) ) class OriginVisitConnection(BaseConnection): def _get_page_result(self): """ Get the visits for the given origin parent obj (self.obj) is origin here """ # FIXME, make this call async (not for v1) return archive.Archive().get_origin_visits( self.obj.url, after=self._get_after_arg(), first=self._get_first_arg() ) -class OriginVisitStatusConnection(BaseConnection): +class VisitStatusConnection(BaseConnection): def _get_page_result(self): - pass + s = archive.Archive().get_visit_status( + self.obj.origin, + self.obj.visit, + after=self._get_after_arg(), + first=self._get_first_arg(), + ) + return s diff --git a/swh/graphql/schema/schema.graphql b/swh/graphql/schema/schema.graphql index fa70449..0123d81 100644 --- a/swh/graphql/schema/schema.graphql +++ b/swh/graphql/schema/schema.graphql @@ -1,118 +1,122 @@ +scalar SWHId + +scalar DateTime + interface Node { id: ID! } -scalar SWHId - -scalar DateTime +interface SWHNode { + id: SWHId! +} type PageInfo { endCursor: String hasNextPage: Boolean! } -type Origin implements Node { +type Origin implements SWHNode { # FIXME, find an idea for a UNIQUE id + id: SWHId! url: String! - id: ID! visits( first: Int after: String ): VisitConnection! } type OriginEdge { cursor: String! node: Origin } type OriginConnection { edges: [OriginEdge] nodes: [Origin] pageInfo: PageInfo! totalCount: Int } type Visit implements Node { id: ID! date: DateTime! - # status: VisitStatusConnection + type: String + status: VisitStatusConnection # origin: Origin # FIXME, this can be added later } type VisitEdge { cursor: String! node: Visit } type VisitConnection { edges: [VisitEdge] nodes: [Visit] pageInfo: PageInfo! totalCount: Int } -# type VisitStatus implements Node { -# id: ID! -# status: String! -# date: DateTime! -# snapshot: String -# type: String -# } +type VisitStatus implements Node { + id: ID! + status: String! + date: DateTime! + snapshot: String + type: String +} -# type VisitStatusEdge { -# cursor: String! -# node: [VisitStatus] -# } +type VisitStatusEdge { + cursor: String! + node: [VisitStatus] +} -# type VisitStatusConnection { -# edges: [VisitStatusEdge] -# nodes: [VisitStatus] -# pageInfo: PageInfo! -# totalCount: Int -# } +type VisitStatusConnection { + edges: [VisitStatusEdge] + nodes: [VisitStatus] + pageInfo: PageInfo! + totalCount: Int +} -# type Snapshot implements Node { -# id: ID! +# type Snapshot implements SWHNode { +# id: SWHId! # # branches # } - type Query { """ Get an origin with its url """ # FIXME, find some unique id to help cache # maybe base64 encode the URL origin( url: String! ): Origin """ Get a list of origins matching the given filters Can be used to search for an origin """ # FIMXE, use Input types to make this cleaner origins( first: Int after: String ): OriginConnection! """ Get a visit object with its id and/or origin and visit id """ # FIXME, find some unique id to help cache visit( originUrl: String! id: String! ): Visit } # Remove statusConnection # Make visit obj by making multiple calls # Make snapshot object # Make revisionconnection # Make contnetConnection