From f0ef979cf40dba3e54f5313f2ef9a02ec88509a5 Mon Sep 17 00:00:00 2001 From: Jayesh Velayudhan <jayesh@softwareheritage.org> Date: Mon, 13 Nov 2023 11:54:23 +0100 Subject: [PATCH] Schema: Add an entry field in the directory object Get a directory entry with a path from the directory object --- swh/graphql/resolvers/directory_entry.py | 19 +++++++- swh/graphql/resolvers/resolver_factory.py | 9 +++- swh/graphql/resolvers/resolvers.py | 9 +++- swh/graphql/schema/schema.graphql | 10 +++++ .../tests/functional/test_directory_entry.py | 44 +++++++++++++++++++ 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/swh/graphql/resolvers/directory_entry.py b/swh/graphql/resolvers/directory_entry.py index a6a8a94..1453d1c 100644 --- a/swh/graphql/resolvers/directory_entry.py +++ b/swh/graphql/resolvers/directory_entry.py @@ -26,7 +26,7 @@ class BaseDirectoryEntryNode(BaseNode): return mapping[self._node.type] -class DirectoryEntryNode(BaseDirectoryEntryNode): +class DirEntryDirectNode(BaseDirectoryEntryNode): """ Node resolver for a directory entry requested with a directory SWHID and a relative path @@ -41,6 +41,23 @@ class DirectoryEntryNode(BaseDirectoryEntryNode): ) +class DirEntryInDirectoryNode(BaseDirectoryEntryNode): + """ + Node resolver for a directory entry requested + inside a directory object + """ + + from .directory import BaseDirectoryNode + + obj: BaseDirectoryNode + + def _get_node_data(self): + return self.archive.get_directory_entry_by_path( + directory_id=self.obj.swhid.object_id, + path=self.kwargs.get("path"), + ) + + class DirectoryEntryConnection(BaseConnection): """ Connection resolver for entries in a directory diff --git a/swh/graphql/resolvers/resolver_factory.py b/swh/graphql/resolvers/resolver_factory.py index 0b60851..dbdec23 100644 --- a/swh/graphql/resolvers/resolver_factory.py +++ b/swh/graphql/resolvers/resolver_factory.py @@ -19,7 +19,11 @@ from .content import ( ) from .content_data import ContentDataNode from .directory import DirectoryNode, RevisionDirectoryNode, TargetDirectoryNode -from .directory_entry import DirectoryEntryConnection, DirectoryEntryNode +from .directory_entry import ( + DirectoryEntryConnection, + DirEntryDirectNode, + DirEntryInDirectoryNode, +) from .origin import OriginConnection, OriginNode, TargetOriginNode from .person import ReleaseAuthorList, RevisionAuthorList, RevisionCommitterList from .release import ReleaseNode, TargetReleaseNode @@ -61,7 +65,8 @@ class NodeObjectFactory: "revision-directory": RevisionDirectoryNode, "release": ReleaseNode, "directory": DirectoryNode, - "directory-entry": DirectoryEntryNode, + "directory-entry": DirEntryDirectNode, + "directory-directoryentry": DirEntryInDirectoryNode, "content-by-hashes": ContentbyHashesNode, "content-data": ContentDataNode, "generic-target": TargetNode, diff --git a/swh/graphql/resolvers/resolvers.py b/swh/graphql/resolvers/resolvers.py index c6b0647..54ba3c5 100644 --- a/swh/graphql/resolvers/resolvers.py +++ b/swh/graphql/resolvers/resolvers.py @@ -145,7 +145,7 @@ def directory_resolver( @query.field("directoryEntry") def directory_entry_resolver( obj: None, info: GraphQLResolveInfo, **kw -) -> rs.directory_entry.DirectoryEntryNode: +) -> rs.directory_entry.DirEntryDirectNode: return NodeObjectFactory.create("directory-entry", obj, info, **kw) @@ -210,6 +210,13 @@ def origin_search_node_resolver( return NodeObjectFactory.create("target-origin", obj, info, **kw) +@directory.field("entry") +def directory_directory_entry_resolver( + obj: rs.directory.BaseDirectoryNode, info: GraphQLResolveInfo, **kw +) -> rs.directory_entry.DirEntryInDirectoryNode: + return NodeObjectFactory.create("directory-directoryentry", obj, info, **kw) + + # Connection resolvers # A connection resolver should return an instance of BaseConnection diff --git a/swh/graphql/schema/schema.graphql b/swh/graphql/schema/schema.graphql index f4615b4..c0269ba 100644 --- a/swh/graphql/schema/schema.graphql +++ b/swh/graphql/schema/schema.graphql @@ -936,6 +936,16 @@ type Directory implements SWHNode & Node { """ caseSensitive: Boolean = false ): DirectoryEntryConnection @cost(complexity: 2, multipliers: ["first"]) # pagination is local, hence adding a higher value for cost + + """ + An entry in this or in sub directories + """ + entry( + """ + Relative path to the requested entry + """ + path: String! + ): DirectoryEntry @cost(complexity: 2) # This costs more because the path can be many levels deep } """ diff --git a/swh/graphql/tests/functional/test_directory_entry.py b/swh/graphql/tests/functional/test_directory_entry.py index 25f274b..55b08d0 100644 --- a/swh/graphql/tests/functional/test_directory_entry.py +++ b/swh/graphql/tests/functional/test_directory_entry.py @@ -112,6 +112,50 @@ def test_get_directory_entry(client, directory): } +def get_directory_entry(client, dir_swhid, path): + query_str = """ + query getDirectory($swhid: SWHID!, $path: String!) { + directory(swhid: $swhid) { + swhid + entry(path: $path) { + name { + text + } + } + } + } + """ + return utils.get_query_response(client, query_str, swhid=dir_swhid, path=path) + + +def test_directory_entry_node_in_directory(client): + directory = get_directories()[1] + path = "file1.ext" + data, _ = get_directory_entry(client, dir_swhid=str(directory.swhid()), path=path) + assert data["directory"] == { + "swhid": str(directory.swhid()), + "entry": {"name": {"text": path}}, + } + + +def test_nested_directory_entry_node_in_directory(client): + directory = get_directories_with_nested_path()[0] + path = "sub-dir/file1.ext" + data, _ = get_directory_entry(client, dir_swhid=str(directory.swhid()), path=path) + assert data["directory"] == { + "swhid": str(directory.swhid()), + "entry": {"name": {"text": path}}, + } + + +def test_missing_directory_entry_node_in_directory(client): + directory = get_directories()[1] + path = "sub-dir/invalid.txt" + data, err = get_directory_entry(client, dir_swhid=str(directory.swhid()), path=path) + assert data == {"directory": {"swhid": str(directory.swhid()), "entry": None}} + assert "Object error: Requested object is not available" in err[0]["message"] + + @pytest.mark.parametrize("directory", get_directories()) def test_get_directory_entry_connection(client, directory): query_str = """ -- GitLab