diff options
author | Matthias Baumgartner <dev@igsor.net> | 2022-12-18 14:21:11 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2022-12-18 14:21:11 +0100 |
commit | 91437ba89d35bf482f3d9671bb99ef2fc69f5985 (patch) | |
tree | e9bfe27e5a641c040cfa8fe747a7cbb28091079c /bsfs/graph/graph.py | |
parent | 87e4cd5a4581094f490f79d4f1cf91f51897660f (diff) | |
parent | e94368c75468e3e94382b12705e55d396249eaca (diff) | |
download | bsfs-91437ba89d35bf482f3d9671bb99ef2fc69f5985.tar.gz bsfs-91437ba89d35bf482f3d9671bb99ef2fc69f5985.tar.bz2 bsfs-91437ba89d35bf482f3d9671bb99ef2fc69f5985.zip |
Merge branch 'develop' into main
Diffstat (limited to 'bsfs/graph/graph.py')
-rw-r--r-- | bsfs/graph/graph.py | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py new file mode 100644 index 0000000..b7b9f1c --- /dev/null +++ b/bsfs/graph/graph.py @@ -0,0 +1,113 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import os +import typing + +# bsfs imports +from bsfs.schema import Schema +from bsfs.triple_store import TripleStoreBase +from bsfs.utils import URI, typename + +# inner-module imports +from . import nodes as _nodes + +# exports +__all__: typing.Sequence[str] = ( + 'Graph', + ) + + +## code ## + +class Graph(): + """The Graph class is + + The Graph class provides a convenient interface to query and access a graph. + Since it logically builds on the concept of graphs it is easier to + navigate than raw triple stores. Naturally, it uses a triple store + as *backend*. It also controls actions via access permissions to a *user*. + + """ + + # link to the triple storage backend. + _backend: TripleStoreBase + + # user uri. + _user: URI + + def __init__(self, backend: TripleStoreBase, user: URI): + self._backend = backend + self._user = user + # ensure Graph schema requirements + self.migrate(self._backend.schema) + + def __hash__(self) -> int: + return hash((type(self), self._backend, self._user)) + + def __eq__(self, other) -> bool: + return isinstance(other, type(self)) \ + and self._backend == other._backend \ + and self._user == other._user + + def __repr__(self) -> str: + return f'{typename(self)}(backend={repr(self._backend)}, user={self._user})' + + def __str__(self) -> str: + return f'{typename(self)}({str(self._backend)}, {self._user})' + + @property + def schema(self) -> Schema: + """Return the store's local schema.""" + return self._backend.schema + + def migrate(self, schema: Schema, append: bool = True) -> 'Graph': + """Migrate the current schema to a new *schema*. + + Appends to the current schema by default; control this via *append*. + The `Graph` may add additional classes to the schema that are required for its interals. + + """ + # check args + if not isinstance(schema, Schema): + raise TypeError(schema) + # append to current schema + if append: + schema = schema + self._backend.schema + # add Graph schema requirements + with open(os.path.join(os.path.dirname(__file__), 'schema.nt'), mode='rt', encoding='UTF-8') as ifile: + schema = schema + Schema.from_string(ifile.read()) + # migrate schema in backend + # FIXME: consult access controls! + self._backend.schema = schema + # return self + return self + + def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> _nodes.Nodes: + """Return nodes *guids* of type *node_type* as a `bsfs.graph.Nodes` instance. + + Note that the *guids* need not to exist (however, the *node_type* has + to be part of the schema). Inexistent guids will be created (using + *node_type*) once some data is assigned to them. + + """ + type_ = self.schema.node(node_type) + # NOTE: Nodes constructor materializes guids. + return _nodes.Nodes(self._backend, self._user, type_, guids) + + 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 + to be part of the schema). An inexistent guid will be created (using + *node_type*) once some data is assigned to them. + + """ + type_ = self.schema.node(node_type) + return _nodes.Nodes(self._backend, self._user, type_, {guid}) + +## EOF ## |