diff options
author | Matthias Baumgartner <dev@igsor.net> | 2023-03-02 12:19:58 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2023-03-02 12:19:58 +0100 |
commit | 87f437380c1dd8f420437cddc028c0f3174ee1c9 (patch) | |
tree | acebd2de636477cf6b498256a67f6863abd5a9c1 /bsfs | |
parent | d70e78bbdd9d9b5727f18a82fce08f20bdbbba19 (diff) | |
download | bsfs-87f437380c1dd8f420437cddc028c0f3174ee1c9.tar.gz bsfs-87f437380c1dd8f420437cddc028c0f3174ee1c9.tar.bz2 bsfs-87f437380c1dd8f420437cddc028c0f3174ee1c9.zip |
Node getters in bsfs.Graph:
* Empty nodes instance (Graph.empty)
* Order-preserving get query (Graph.sorted)
* Collect common code in private Graph.__get
* Empty query in Graph.get
* Empty query in Graph.resolve.Filter
* Empty query in AC: filter_read
Diffstat (limited to 'bsfs')
-rw-r--r-- | bsfs/graph/ac/base.py | 6 | ||||
-rw-r--r-- | bsfs/graph/ac/null.py | 6 | ||||
-rw-r--r-- | bsfs/graph/graph.py | 60 | ||||
-rw-r--r-- | bsfs/graph/resolve.py | 9 |
4 files changed, 61 insertions, 20 deletions
diff --git a/bsfs/graph/ac/base.py b/bsfs/graph/ac/base.py index 0b9f988..2759557 100644 --- a/bsfs/graph/ac/base.py +++ b/bsfs/graph/ac/base.py @@ -83,7 +83,11 @@ class AccessControlBase(abc.ABC): """Return nodes that are allowed to be created.""" @abc.abstractmethod - def filter_read(self, node_type: schema.Node, query: ast.filter.FilterExpression) -> ast.filter.FilterExpression: + def filter_read( + self, + node_type: schema.Node, + query: typing.Optional[ast.filter.FilterExpression], + ) -> typing.Optional[ast.filter.FilterExpression]: """Re-write a filter *query* to get (i.e., read) *node_type* nodes.""" @abc.abstractmethod diff --git a/bsfs/graph/ac/null.py b/bsfs/graph/ac/null.py index 6a923a5..e67b55d 100644 --- a/bsfs/graph/ac/null.py +++ b/bsfs/graph/ac/null.py @@ -50,7 +50,11 @@ class NullAC(base.AccessControlBase): """Return nodes that are allowed to be created.""" return guids - def filter_read(self, node_type: schema.Node, query: ast.filter.FilterExpression) -> ast.filter.FilterExpression: + def filter_read( + self, + node_type: schema.Node, + query: typing.Optional[ast.filter.FilterExpression] + ) -> typing.Optional[ast.filter.FilterExpression]: """Re-write a filter *query* to get (i.e., read) *node_type* nodes.""" return query diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index a356533..11fe835 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -113,6 +113,7 @@ class Graph(): *node_type*) once some data is assigned to them. """ + # get node type type_ = self.schema.node(node_type) # NOTE: Nodes constructor materializes guids. return _nodes.Nodes(self._backend, self._ac, type_, guids) @@ -120,15 +121,51 @@ class Graph(): def node(self, node_type: URI, guid: URI) -> _nodes.Nodes: """Return node *guid* of type *node_type* as a `bsfs.graph.Nodes` instance. - Note that the *guids* need not to exist (however, the *node_type* has + Note that the *guid* need not to exist (however, the *node_type* has to be part of the schema). An inexistent guid will be created (using *node_type*) once some data is assigned to them. """ return self.nodes(node_type, {guid}) - def get(self, node_type: URI, query: ast.filter.FilterExpression) -> _nodes.Nodes: # FIXME: How about empty query? - """Return a `Nodes` instance over all nodes of type *node_type* that match the *subject* query.""" + def empty(self, node_type: URI) -> _nodes.Nodes: + """Return a `Nodes` instance with type *node_type* but no nodes.""" + return self.nodes(node_type, set()) + + def get( + self, + node_type: URI, + query: typing.Optional[ast.filter.FilterExpression], + ) -> _nodes.Nodes: + """Return a `Nodes` instance over all nodes of type *node_type* that match the *query*.""" + # return Nodes instance + type_ = self.schema.node(node_type) + return _nodes.Nodes(self._backend, self._ac, type_, self.__get(node_type, query)) + + def sorted( + self, + node_type: URI, + query: typing.Optional[ast.filter.FilterExpression], + # FIXME: sort ast + ) -> typing.Iterator[_nodes.Nodes]: + """Return a iterator over `Nodes` instances over all nodes of type *node_type* that match the *query*.""" + # FIXME: Order should be a parameter + # return iterator over Nodes instances + type_ = self.schema.node(node_type) + for guid in self.__get(node_type, query): + yield _nodes.Nodes(self._backend, self._ac, type_, {guid}) + + def all(self, node_type: URI) -> _nodes.Nodes: + """Return all instances of type *node_type*.""" + type_ = self.schema.node(node_type) + return _nodes.Nodes(self._backend, self._ac, type_, self.__get(node_type, None)) + + def __get( + self, + node_type: URI, + query: typing.Optional[ast.filter.FilterExpression], + ) -> typing.Iterator[URI]: + """Build and execute a get query.""" # get node type type_ = self.schema.node(node_type) # resolve Nodes instances @@ -136,18 +173,9 @@ class Graph(): # add access controls to query query = self._ac.filter_read(type_, query) # validate query - self._validate(type_, query) - # query the backend - guids = self._backend.get(type_, query) # no need to materialize - # return Nodes instance - return _nodes.Nodes(self._backend, self._ac, type_, guids) - - def all(self, node_type: URI) -> _nodes.Nodes: - """Return all instances of type *node_type*.""" - # get node type - type_ = self.schema.node(node_type) - guids = self._backend.get(type_, None) # no need to materialize - return _nodes.Nodes(self._backend, self._ac, type_, guids) - + if query is not None: + self._validate(type_, query) + # query the backend and return the (non-materialized) result + return self._backend.get(type_, query) ## EOF ## diff --git a/bsfs/graph/resolve.py b/bsfs/graph/resolve.py index 4677401..b3ab001 100644 --- a/bsfs/graph/resolve.py +++ b/bsfs/graph/resolve.py @@ -40,8 +40,13 @@ class Filter(): def __init__(self, schema): self.schema = schema - def __call__(self, root_type: bsc.Node, node: ast.filter.FilterExpression): - # FIXME: node can be None! + def __call__( + self, + root_type: bsc.Node, + node: typing.Optional[ast.filter.FilterExpression], + ): + if node is None: + return None return self._parse_filter_expression(root_type, node) def _parse_filter_expression( |