diff --git a/swh/graphql/resolvers/base_connection.py b/swh/graphql/resolvers/base_connection.py --- a/swh/graphql/resolvers/base_connection.py +++ b/swh/graphql/resolvers/base_connection.py @@ -20,7 +20,7 @@ class BaseConnection(ABC): """ - Base class for all the connection resolvers + Base resolver for all the connections """ _node_class: Optional[Type[BaseNode]] = None diff --git a/swh/graphql/resolvers/base_node.py b/swh/graphql/resolvers/base_node.py --- a/swh/graphql/resolvers/base_node.py +++ b/swh/graphql/resolvers/base_node.py @@ -11,7 +11,7 @@ class BaseNode(ABC): """ - Base class for all the Node resolvers + Base resolver for all the nodes """ def __init__(self, obj, info, node_data=None, **kwargs): @@ -76,6 +76,10 @@ class BaseSWHNode(BaseNode): + """ + Base resolver for all the nodes with a SWHID field + """ + @property def swhid(self): return self._node.swhid() diff --git a/swh/graphql/resolvers/content.py b/swh/graphql/resolvers/content.py --- a/swh/graphql/resolvers/content.py +++ b/swh/graphql/resolvers/content.py @@ -3,13 +3,19 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from typing import Union + from swh.graphql.backends import archive from .base_node import BaseSWHNode +from .directory_entry import DirectoryEntryNode +from .release import BaseReleaseNode class BaseContentNode(BaseSWHNode): - """ """ + """ + Base resolver for all the content nodes + """ def _get_content_by_id(self, content_id): content = archive.Archive().get_content(content_id) @@ -25,25 +31,28 @@ return self._node.sha1_git def is_type_of(self): + # is_type_of is required only when resolving a UNION type + # This is for ariadne to return the right type return "Content" class ContentNode(BaseContentNode): + """ + Node resolver for a content requested directly with its SWHID + """ + def _get_node_data(self): - """ - When a content is requested directly - with its SWHID - """ return self._get_content_by_id(self.kwargs.get("swhid").object_id) class TargetContentNode(BaseContentNode): - def _get_node_data(self): - """ - When a content is requested from a - directory entry or from a release target + """ + Node resolver for a content requested from a + directory entry or from a release target + """ - content id is obj.targetHash here - """ + obj: Union[DirectoryEntryNode, BaseReleaseNode] + + def _get_node_data(self): content_id = self.obj.targetHash return self._get_content_by_id(content_id) diff --git a/swh/graphql/resolvers/directory.py b/swh/graphql/resolvers/directory.py --- a/swh/graphql/resolvers/directory.py +++ b/swh/graphql/resolvers/directory.py @@ -7,9 +7,14 @@ from swh.model.model import Directory from .base_node import BaseSWHNode +from .revision import BaseRevisionNode class BaseDirectoryNode(BaseSWHNode): + """ + Base resolver for all the directory nodes + """ + def _get_directory_by_id(self, directory_id): # Return a Directory model object # entries is initialized as empty @@ -21,35 +26,38 @@ class DirectoryNode(BaseDirectoryNode): + """ + Node resolver for a directory requested directly with its SWHID + """ + def _get_node_data(self): - """ - When a directory is requested directly with its SWHID - """ directory_id = self.kwargs.get("swhid").object_id # path = "" if archive.Archive().is_directory_available([directory_id]): + # _get_directory_by_id is not making any backend call + # hence the directory_exists validation return self._get_directory_by_id(directory_id) return None class RevisionDirectoryNode(BaseDirectoryNode): + """ + Node resolver for a directory requested from a revision + """ + + obj: BaseRevisionNode + def _get_node_data(self): - """ - When a directory is requested from a revision - self.obj is revision here - self.obj.directorySWHID is the required directory SWHID - (set from resolvers.revision.py:BaseRevisionNode) - """ + # self.obj.directorySWHID is the requested directory SWHID directory_id = self.obj.directorySWHID.object_id return self._get_directory_by_id(directory_id) class TargetDirectoryNode(BaseDirectoryNode): - def _get_node_data(self): - """ - When a directory is requested as a target - self.obj can be a Release or a DirectoryEntry + """ + Node resolver for a directory requested as a target + """ - obj.targetHash is the requested directory id here - """ + def _get_node_data(self): + # obj.targetHash is the requested directory id return self._get_directory_by_id(self.obj.targetHash) diff --git a/swh/graphql/resolvers/directory_entry.py b/swh/graphql/resolvers/directory_entry.py --- a/swh/graphql/resolvers/directory_entry.py +++ b/swh/graphql/resolvers/directory_entry.py @@ -8,10 +8,13 @@ from .base_connection import BaseConnection from .base_node import BaseNode +from .directory import BaseDirectoryNode class DirectoryEntryNode(BaseNode): - """ """ + """ + Node resolver for a directory entry + """ @property def targetHash(self): # To support the schema naming convention @@ -19,16 +22,16 @@ class DirectoryEntryConnection(BaseConnection): + """ + Connection resolver for entries in a directory + """ + + obj: BaseDirectoryNode + _node_class = DirectoryEntryNode def _get_paged_result(self): - """ - When entries requested from a directory - self.obj.swhid is the directory SWHID here - - This is not paginated from swh-storgae - using dummy pagination - """ + # self.obj.swhid is the directory SWHID here # FIXME, using dummy(local) pagination, move pagination to backend # To remove localpagination, just drop the paginated call diff --git a/swh/graphql/resolvers/origin.py b/swh/graphql/resolvers/origin.py --- a/swh/graphql/resolvers/origin.py +++ b/swh/graphql/resolvers/origin.py @@ -10,11 +10,19 @@ class OriginNode(BaseSWHNode): + """ + Node resolver for an origin requested directly with its URL + """ + def _get_node_data(self): return archive.Archive().get_origin(self.kwargs.get("url")) class OriginConnection(BaseConnection): + """ + Connection resolver for the origins + """ + _node_class = OriginNode def _get_paged_result(self): diff --git a/swh/graphql/resolvers/release.py b/swh/graphql/resolvers/release.py --- a/swh/graphql/resolvers/release.py +++ b/swh/graphql/resolvers/release.py @@ -3,12 +3,19 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from typing import Union + from swh.graphql.backends import archive from .base_node import BaseSWHNode +from .snapshot_branch import SnapshotBranchNode class BaseReleaseNode(BaseSWHNode): + """ + Base resolver for all the release nodes + """ + def _get_release_by_id(self, release_id): return (archive.Archive().get_releases([release_id]) or None)[0] @@ -21,17 +28,14 @@ return self._node.target_type.value def is_type_of(self): - """ - is_type_of is required only when resolving - a UNION type - This is for ariadne to return the right type - """ + # is_type_of is required only when resolving a UNION type + # This is for ariadne to return the right type return "Release" class ReleaseNode(BaseReleaseNode): """ - When the release is requested directly with its SWHID + Node resolver for a release requested directly with its SWHID """ def _get_node_data(self): @@ -40,11 +44,11 @@ class TargetReleaseNode(BaseReleaseNode): """ - When a release is requested as a target - - self.obj could be a snapshotbranch or a release - self.obj.targetHash is the requested release id here + Node resolver for a release requested as a target """ + obj: Union[SnapshotBranchNode, BaseReleaseNode] + def _get_node_data(self): + # self.obj.targetHash is the requested release id return self._get_release_by_id(self.obj.targetHash) diff --git a/swh/graphql/resolvers/resolvers.py b/swh/graphql/resolvers/resolvers.py --- a/swh/graphql/resolvers/resolvers.py +++ b/swh/graphql/resolvers/resolvers.py @@ -5,12 +5,14 @@ """ High level resolvers -Any schema attribute can be resolved by any of the following ways -and in the following priority order -- In this module using an annotation (eg: @visitstatus.field("snapshot")) -- As a property in the Node object (eg: resolvers.visit.OriginVisitNode.id) -- As an attribute/item in the object/dict returned by the backend (eg: Origin.url) """ + +# Any schema attribute can be resolved by any of the following ways +# and in the following priority order +# - In this module using a decorator (eg: @visitstatus.field("snapshot")) +# - As a property in the Node object (eg: resolvers.visit.BaseVisitNode.id) +# - As an attribute/item in the object/dict returned by a backend (eg: Origin.url) + from ariadne import ObjectType, UnionType from graphql.type import GraphQLResolveInfo diff --git a/swh/graphql/resolvers/revision.py b/swh/graphql/resolvers/revision.py --- a/swh/graphql/resolvers/revision.py +++ b/swh/graphql/resolvers/revision.py @@ -3,15 +3,23 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from typing import Union + from swh.graphql.backends import archive from swh.graphql.utils import utils from swh.model.swhids import CoreSWHID, ObjectType from .base_connection import BaseConnection from .base_node import BaseSWHNode +from .release import BaseReleaseNode +from .snapshot_branch import SnapshotBranchNode class BaseRevisionNode(BaseSWHNode): + """ + Base resolver for all the revision nodes + """ + def _get_revision_by_id(self, revision_id): return (archive.Archive().get_revisions([revision_id]) or None)[0] @@ -24,7 +32,6 @@ @property def directorySWHID(self): # To support the schema naming convention - """ """ return CoreSWHID( object_type=ObjectType.DIRECTORY, object_id=self._node.directory ) @@ -34,17 +41,14 @@ return self._node.type.value def is_type_of(self): - """ - is_type_of is required only when resolving - a UNION type - This is for ariadne to return the right type - """ + # is_type_of is required only when resolving a UNION type + # This is for ariadne to return the right type return "Revision" class RevisionNode(BaseRevisionNode): """ - When the revision is requested directly with its SWHID + Node resolver for a revision requested directly with its SWHID """ def _get_node_data(self): @@ -53,28 +57,29 @@ class TargetRevisionNode(BaseRevisionNode): """ - When a revision is requested as a target - - self.obj could be a snapshotbranch or a release - self.obj.targetHash is the requested revision id here + Node resolver for a revision requested as a target """ + obj: Union[SnapshotBranchNode, BaseReleaseNode] + def _get_node_data(self): + # self.obj.targetHash is the requested revision id return self._get_revision_by_id(self.obj.targetHash) class ParentRevisionConnection(BaseConnection): """ - When parent revisions is requested from a - revision - self.obj is the current(child) revision - self.obj.parentSWHIDs is the list of - parent SWHIDs + Connection resolver for parent revisions in a revision """ + obj: BaseRevisionNode + _node_class = BaseRevisionNode def _get_paged_result(self): + # self.obj is the current(child) revision + # self.obj.parentSWHIDs is the list of parent SWHIDs + # FIXME, using dummy(local) pagination, move pagination to backend # To remove localpagination, just drop the paginated call # STORAGE-TODO (pagination) @@ -86,14 +91,16 @@ class LogRevisionConnection(BaseConnection): """ - When revisionslog is requested from a - revision - self.obj is the current revision id + Connection resolver for the log (list of revisions) in a revision """ + obj: BaseRevisionNode + _node_class = BaseRevisionNode def _get_paged_result(self): + # self.obj is the current revision id + # STORAGE-TODO (date in revisionlog is a dict) log = archive.Archive().get_revision_log([self.obj.swhid.object_id]) # FIXME, using dummy(local) pagination, move pagination to backend diff --git a/swh/graphql/resolvers/snapshot.py b/swh/graphql/resolvers/snapshot.py --- a/swh/graphql/resolvers/snapshot.py +++ b/swh/graphql/resolvers/snapshot.py @@ -9,9 +9,15 @@ from .base_connection import BaseConnection from .base_node import BaseSWHNode +from .origin import OriginNode +from .visit_status import BaseVisitStatusNode class BaseSnapshotNode(BaseSWHNode): + """ + Base resolver for all the snapshot nodes + """ + def _get_snapshot_by_id(self, snapshot_id): # Return a Snapshot model object # branches is initialized as empty @@ -21,7 +27,7 @@ class SnapshotNode(BaseSnapshotNode): """ - For directly accessing a snapshot with its SWHID + Node resolver for a snapshot requested directly with its SWHID """ def _get_node_data(self): @@ -34,23 +40,27 @@ class VisitSnapshotNode(BaseSnapshotNode): """ - For accessing a snapshot from a visitstatus type + Node resolver for a snapshot requested from a visit-status """ + obj: BaseVisitStatusNode + def _get_node_data(self): - """ - self.obj is visitstatus here - self.obj.snapshotSWHID is the requested snapshot SWHID - """ + # self.obj.snapshotSWHID is the requested snapshot SWHID snapshot_id = self.obj.snapshotSWHID.object_id return self._get_snapshot_by_id(snapshot_id) class OriginSnapshotConnection(BaseConnection): + """ + Connection resolver for the snapshots in an origin + """ + + obj: OriginNode + _node_class = BaseSnapshotNode def _get_paged_result(self): - """ """ results = archive.Archive().get_origin_snapshots(self.obj.url) snapshots = [Snapshot(id=snapshot, branches={}) for snapshot in results] # FIXME, using dummy(local) pagination, move pagination to backend diff --git a/swh/graphql/resolvers/snapshot_branch.py b/swh/graphql/resolvers/snapshot_branch.py --- a/swh/graphql/resolvers/snapshot_branch.py +++ b/swh/graphql/resolvers/snapshot_branch.py @@ -11,19 +11,20 @@ from .base_connection import BaseConnection from .base_node import BaseNode +from .snapshot import SnapshotNode class SnapshotBranchNode(BaseNode): """ - target field for this Node is a UNION in the schema - It is resolved in resolvers.resolvers.py + Node resolver for a snapshot branch """ + # target field for this Node is a UNION type + # It is resolved in the top level (resolvers.resolvers.py) + def _get_node_from_data(self, node_data): - """ - node_data is not a dict in this case - overriding to support this special data structure - """ + # node_data is not a dict in this case + # overriding to support this special data structure # STORAGE-TODO; return an object in the normal format branch_name, branch_obj = node_data @@ -40,15 +41,16 @@ class SnapshotBranchConnection(BaseConnection): + """ + Connection resolver for the branches in a snapshot + """ + + obj: SnapshotNode + _node_class = SnapshotBranchNode def _get_paged_result(self): - """ - When branches requested from a snapshot - self.obj.swhid is the snapshot SWHID here - (as returned from resolvers/snapshot.py) - """ - + # self.obj.swhid is the snapshot SWHID result = archive.Archive().get_snapshot_branches( self.obj.swhid.object_id, after=self._get_after_arg(), @@ -69,9 +71,8 @@ ) def _get_after_arg(self): - """ - Snapshot branch is using a different cursor; logic to handle that - """ + # Snapshot branch is using a different cursor; logic to handle that + # FIXME Cursor must be a hex to be consistent with # the base class, hack to make that work after = utils.get_decoded_cursor(self.kwargs.get("after", "")) diff --git a/swh/graphql/resolvers/visit.py b/swh/graphql/resolvers/visit.py --- a/swh/graphql/resolvers/visit.py +++ b/swh/graphql/resolvers/visit.py @@ -8,9 +8,14 @@ from .base_connection import BaseConnection from .base_node import BaseNode +from .origin import OriginNode class BaseVisitNode(BaseNode): + """ + Base resolver for all the visit nodes + """ + @property def id(self): # FIXME, use a better id @@ -23,7 +28,8 @@ class OriginVisitNode(BaseVisitNode): """ - Get the visit directly with an origin URL and a visit ID + Node resolver for a visit requested directly with an origin URL + and a visit ID """ def _get_node_data(self): @@ -34,23 +40,27 @@ class LatestVisitNode(BaseVisitNode): """ - Get the latest visit for an origin - self.obj is the origin object here - self.obj.url is the origin URL + Node resolver for the latest visit in an origin """ + obj: OriginNode + def _get_node_data(self): + # self.obj.url is the origin URL return archive.Archive().get_origin_latest_visit(self.obj.url) class OriginVisitConnection(BaseConnection): + """ + Connection resolver for the visit objects in an origin + """ + + obj: OriginNode + _node_class = BaseVisitNode def _get_paged_result(self): - """ - Get the visits for the given origin - parent obj (self.obj) is origin here - """ + # self.obj.url is the origin URL return archive.Archive().get_origin_visits( self.obj.url, after=self._get_after_arg(), first=self._get_first_arg() ) diff --git a/swh/graphql/resolvers/visit_status.py b/swh/graphql/resolvers/visit_status.py --- a/swh/graphql/resolvers/visit_status.py +++ b/swh/graphql/resolvers/visit_status.py @@ -8,10 +8,13 @@ from .base_connection import BaseConnection from .base_node import BaseNode +from .visit import BaseVisitNode class BaseVisitStatusNode(BaseNode): - """ """ + """ + Base resolver for all the visit-status nodes + """ @property def snapshotSWHID(self): # To support the schema naming convention @@ -20,12 +23,13 @@ class LatestVisitStatusNode(BaseVisitStatusNode): """ - Get the latest visit status for a visit - self.obj is the visit object here - self.obj.origin is the origin URL + Node resolver for a visit-status requested from a visit """ + obj: BaseVisitNode + def _get_node_data(self): + # self.obj.origin is the origin URL return archive.Archive().get_latest_visit_status( self.obj.origin, self.obj.visitId ) @@ -33,13 +37,14 @@ class VisitStatusConnection(BaseConnection): """ - self.obj is the visit object - self.obj.origin is the origin URL + Connection resolver for the visit-status objects in a visit """ + obj: BaseVisitNode _node_class = BaseVisitStatusNode def _get_paged_result(self): + # self.obj.origin is the origin URL return archive.Archive().get_visit_status( self.obj.origin, self.obj.visitId, diff --git a/swh/graphql/tests/data.py b/swh/graphql/tests/data.py --- a/swh/graphql/tests/data.py +++ b/swh/graphql/tests/data.py @@ -3,10 +3,6 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information -# This module will be removed once the test data -# generation in SWH-wb moved to a shared location -# or to a new test data project - from swh.model.tests import swh_model_data