Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/swh/graphql/resolvers/base_connection.py b/swh/graphql/resolvers/base_connection.py
index fa233d9..7be1e8f 100644
--- a/swh/graphql/resolvers/base_connection.py
+++ b/swh/graphql/resolvers/base_connection.py
@@ -1,121 +1,118 @@
from abc import ABC, abstractmethod
from typing import Any
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(ABC):
"""
Base class for all the connection resolvers
"""
_node_class: Any = None
_page_size = 50 # default page size
- def __init__(self, obj, info, **kwargs):
+ def __init__(self, obj, info, paged_data=None, **kwargs):
self.obj = obj
self.info = info
self.kwargs = kwargs
-
- self._paged_data = None
- self.pageInfo = self.page_info # To match the name in schema
- self.totalCount = self.total_count # To match the name in schema
+ self._paged_data = paged_data
def __call__(self, *args, **kw):
return self
@property
def edges(self):
return self._get_edges()
@property
def nodes(self):
"""
Override if needed
return a list of objects
If a node class is set,
return a list of its (Node) intances
else a list of raw results
"""
if self._node_class is not None:
return [
self._node_class(self.obj, self.info, node_data=result, **self.kwargs)
for result in self.get_paged_data().results
]
return self.get_paged_data().results
@property
- def page_info(self):
+ def pageInfo(self): # To support the schema naming convention
# FIXME Replace with a dataclass
# return PageInfo(self.page_data.next_page_token)
# FIXME, add more details like startCursor
return {
"hasNextPage": bool(self.get_paged_data().next_page_token),
"endCursor": utils.get_encoded_cursor(
self.get_paged_data().next_page_token
),
}
@property
- def total_count(self):
+ def totalCount(self): # To support the schema naming convention
"""
Will be None for most of the connections
override if needed/possible
"""
return None
def get_paged_data(self):
"""
Cache to avoid multiple calls to
the backend (_get_paged_result)
return a PagedResult object
"""
if self._paged_data is None:
# FIXME, make this call async (not for v1)
self._paged_data = self._get_paged_result()
return self._paged_data
@abstractmethod
def _get_paged_result(self):
"""
Override for desired behaviour
return a PagedResult object
"""
# FIXME, make this call async (not for v1)
return None
def _get_edges(self):
# FIXME, make cursor work per item
# Cursor can't be None here
return [{"cursor": "dummy", "node": node} for node in self.nodes]
def _get_after_arg(self):
"""
Return the decoded next page token
override to use a specific token
"""
return utils.get_decoded_cursor(self.kwargs.get("after"))
def _get_first_arg(self):
"""
page_size is set to 50 by default
"""
return self.kwargs.get("first", self._page_size)
diff --git a/swh/graphql/resolvers/revision.py b/swh/graphql/resolvers/revision.py
index e3e2dc2..af54d0c 100644
--- a/swh/graphql/resolvers/revision.py
+++ b/swh/graphql/resolvers/revision.py
@@ -1,55 +1,82 @@
from swh.graphql.backends import archive
from swh.graphql.utils import utils
from .base_node import BaseNode
class BaseRevisionNode(BaseNode):
def _get_revision_by_id(self, revision_id):
+ # FIXME, make this call async
return (archive.Archive().get_revision(revision_id) or None)[0]
@property
def author(self):
# return a PersoneNode object
return self._node.author
@property
def committer(self):
# return a PersoneNode object
return self._node.committer
+ @property
+ def parentIds(self): # To support the schema naming convention
+ return self._node.parents
+
+ # @paginatedlist
+ @property
+ def parents(self):
+ """
+ Return a list of parent revisions
+ """
+ # FIXME, change this to a paginated list
+ # Storage fix or use paginatedlist decorator
+ return [
+ ParentRevisionNode(obj=self, info=self.info, sha1=revision_id)
+ for revision_id in self.parentIds
+ ]
+
+ def is_type_of(self):
+ """
+ is_type_of is required only when
+ requesting from a connection
+
+ This is for ariadne to return the correct type in schema
+ """
+ return "Revision"
+
class RevisionNode(BaseRevisionNode):
"""
When the revision is requested directly
(not from a connection) with an id
"""
def _get_node_data(self):
revision_id = utils.str_to_swid(self.kwargs.get("SWHId"))
return self._get_revision_by_id(revision_id)
+class ParentRevisionNode(BaseRevisionNode):
+ """
+ When a parent revision is requested
+ """
+
+ def _get_node_data(self):
+ revision_id = self.kwargs.get("sha1")
+ return self._get_revision_by_id(revision_id)
+
+
class BranchRevisionNode(BaseRevisionNode):
"""
When the revision is requested from
a snapshot branch
self.obj is a branch object
self.obj.target is the revision id
"""
def _get_node_data(self):
"""
self.obj.target is the Revision id
"""
- # FIXME, make this call async (not for v1)
return self._get_revision_by_id(self.obj.target)
-
- def is_type_of(self):
- """
- is_type_of is required only when
- requesting from a connection
-
- This is for ariadne to return the correct type in schema
- """
- return "Revision"
diff --git a/swh/graphql/schema/schema.graphql b/swh/graphql/schema/schema.graphql
index fc78171..f9869ed 100644
--- a/swh/graphql/schema/schema.graphql
+++ b/swh/graphql/schema/schema.graphql
@@ -1,251 +1,253 @@
scalar SWHId
scalar DateTime
scalar DateTimeZone
scalar BinaryText
interface Node {
id: ID!
}
interface SWHNode {
id: SWHId!
}
type PageInfo {
endCursor: String
hasNextPage: Boolean!
}
type OriginConnection {
edges: [OriginEdge]
nodes: [Origin]
pageInfo: PageInfo!
totalCount: Int
}
type OriginEdge {
cursor: String!
node: Origin
}
type Origin implements SWHNode {
id: SWHId! # FIXME, this is not swhid
url: String!
visits(
first: Int
after: String
): VisitConnection!
}
type VisitConnection {
edges: [VisitEdge]
nodes: [Visit]
pageInfo: PageInfo!
totalCount: Int
}
type VisitEdge {
cursor: String!
node: Visit
}
type Visit implements Node {
id: ID!
date: DateTime!
type: String
status(
first: Int
after: String
): VisitStatusConnection
# origin: Origin # FIXME, this can be added later
}
type VisitStatusConnection {
edges: [VisitStatusEdge]
nodes: [VisitStatus]
pageInfo: PageInfo!
totalCount: Int
}
type VisitStatusEdge {
cursor: String!
node: VisitStatus
}
type VisitStatus implements Node {
id: ID!
status: String!
date: DateTime!
snapshot: Snapshot
type: String
}
# FIXME, add OriginSnapshotConnection
type Snapshot implements SWHNode {
id: SWHId!
branches(
first: Int
after: String
): BranchConnection
# releases(
# first: Int
# after: String
# ): ReleaseConnection
# FIXME, add alias type as well
}
type BranchConnection {
edges: [BranchConnectionEdge]
nodes: [Branch]
pageInfo: PageInfo!
totalCount: Int
}
type BranchConnectionEdge {
cursor: String!
node: [Branch]
}
# FIXME, this could be alias or Directory as well
union BranchTarget = Revision | Release
type Branch implements Node {
id: ID!
name: BinaryText
type: String # FIXME, change to an enum
target: BranchTarget
}
# type RevisionConnection {
# }
# type RevisionEdge {
# }
type Person {
email: BinaryText
name: BinaryText
fullname: BinaryText
}
type Revision implements SWHNode {
id: SWHId!
message: BinaryText
author: Person
committer: Person
date: DateTimeZone
type: String
directory: SWHId
+ parentIds: [SWHId]
+ parents: [Revision]
}
# type ReleaseConnection {
# }
# type ReleasEdge {
# }
type Release implements SWHNode {
id: SWHId!
name: BinaryText
message: BinaryText
author: Person
date: DateTimeZone
}
type Directory implements SWHNode {
id: SWHId!
name: BinaryText
entries: BinaryText # FIXME, change to Union type
}
type Content implements SWHNode {
id: SWHId!
status: String
}
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 also 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
"""
Get a snapshot with SWHId
"""
snapshot(
SWHId: String!
): Snapshot
# """
# Get all the snapshot for the given origin
# """
# originSnapshot(
# originUrl: String!
# first: Int
# after: String
# ): SnapshotConnection
"""
Get the revision with the given swhid
"""
revision(
SWHId: String!
): Revision
"""
Get the release with the given swhid
"""
release(
SWHId: String!
): Release
"""
Get the directory with the given swhid
"""
directory(
SWHId: String!
): Directory
"""
Get the content with the given swhid
"""
content(
SWHId: String!
): Content
# """
# Search with the given swhid
# """
# searchWithSwhid
}
diff --git a/swh/graphql/utils/paginate.py b/swh/graphql/utils/paginate.py
new file mode 100644
index 0000000..d05d162
--- /dev/null
+++ b/swh/graphql/utils/paginate.py
@@ -0,0 +1,32 @@
+"""
+Pagination at the GraphQL level
+This is a temporary fix and inefficient.
+Should eventually be moved to the
+backend (storage) level
+"""
+
+
+class PaginatedList:
+ def __init__(self, source):
+ """
+ source can be of any iterable type
+ """
+ self.source = source
+
+ def get_items(self, first, after):
+ """
+ Return the 'first' number of
+ items 'after' the given cursor
+ """
+ return self.source[after : (after + first)]
+
+ def get_item_objects(self, first, after):
+ """
+ Return the 'first' number of
+ items 'after' the given cursor
+ with an item cursor
+ """
+ return [
+ {"curosr": first + index, "node": item}
+ for (index, item) in enumerate(self.get_items(first, after), 1)
+ ]

File Metadata

Mime Type
text/x-diff
Expires
Tue, Aug 19, 12:52 AM (3 w, 2 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3261006

Event Timeline