diff options
Diffstat (limited to 'bsfs/triple_store/sparql.py')
-rw-r--r-- | bsfs/triple_store/sparql.py | 81 |
1 files changed, 44 insertions, 37 deletions
diff --git a/bsfs/triple_store/sparql.py b/bsfs/triple_store/sparql.py index 3eab869..d9ed55a 100644 --- a/bsfs/triple_store/sparql.py +++ b/bsfs/triple_store/sparql.py @@ -10,9 +10,8 @@ import typing import rdflib # bsfs imports -from bsfs.utils import URI -from bsfs.utils import errors -import bsfs.schema as _schema +from bsfs import schema as bsc +from bsfs.utils import errors, URI # inner-module imports from . import base @@ -26,7 +25,7 @@ __all__: typing.Sequence[str] = ( ## code ## -class Transaction(): +class _Transaction(): """Lightweight rdflib transactions for in-memory databases.""" def __init__(self, graph): @@ -58,11 +57,20 @@ class SparqlStore(base.TripleStoreBase): """ """ - def __init__(self, uri: typing.Optional[URI] = None): - super().__init__(uri) - self.graph = rdflib.Graph() - self.transaction = Transaction(self.graph) - self.__schema = _schema.Schema.Empty() + # The rdflib graph. + _graph: rdflib.Graph + + # Current transaction. + _transaction: _Transaction + + # The local schema. + _schema: bsc.Schema + + def __init__(self): + super().__init__(None) + self._graph = rdflib.Graph() + self._transaction = _Transaction(self._graph) + self._schema = bsc.Schema.Empty() @classmethod def Open( @@ -73,15 +81,14 @@ class SparqlStore(base.TripleStoreBase): return cls(None) def commit(self): - self.transaction.commit() + self._transaction.commit() def rollback(self): - self.transaction.rollback() + self._transaction.rollback() @property - def schema(self) -> _schema.Schema: - """Return the current schema.""" - return self.__schema + def schema(self) -> bsc.Schema: + return self._schema @schema.setter def schema(self, schema: _schema.Schema): @@ -106,7 +113,7 @@ class SparqlStore(base.TripleStoreBase): """ # check args: Schema instanace - if not isinstance(schema, _schema.Schema): + if not isinstance(schema, bsc.Schema): raise TypeError(schema) # check compatibility: No contradicting definitions if not self.schema.consistent_with(schema): @@ -124,21 +131,21 @@ class SparqlStore(base.TripleStoreBase): # remove predicate instances for pred in sub.predicates: - for src, trg in self.graph.subject_objects(rdflib.URIRef(pred.uri)): - self.transaction.remove((src, rdflib.URIRef(pred.uri), trg)) + for src, trg in self._graph.subject_objects(rdflib.URIRef(pred.uri)): + self._transaction.remove((src, rdflib.URIRef(pred.uri), trg)) # remove node instances for node in sub.nodes: # iterate through node instances - for inst in self.graph.subjects(rdflib.RDF.type, rdflib.URIRef(node.uri)): + for inst in self._graph.subjects(rdflib.RDF.type, rdflib.URIRef(node.uri)): # remove triples where the instance is in the object position - for src, pred in self.graph.subject_predicates(inst): - self.transaction.remove((src, pred, inst)) + for src, pred in self._graph.subject_predicates(inst): + self._transaction.remove((src, pred, inst)) # remove triples where the instance is in the subject position - for pred, trg in self.graph.predicate_objects(inst): - self.transaction.remove((inst, pred, trg)) + for pred, trg in self._graph.predicate_objects(inst): + self._transaction.remove((inst, pred, trg)) # remove instance - self.transaction.remove((inst, rdflib.RDF.type, rdflib.URIRef(node.uri))) + self._transaction.remove((inst, rdflib.RDF.type, rdflib.URIRef(node.uri))) # NOTE: Nothing to do for literals @@ -146,15 +153,15 @@ class SparqlStore(base.TripleStoreBase): self.commit() # migrate schema - self.__schema = schema + self._schema = schema - def _has_type(self, subject: URI, node_type: _schema.Node) -> bool: + def _has_type(self, subject: URI, node_type: bsc.Node) -> bool: """Return True if *subject* is a node of class *node_type* or a subclass thereof.""" if node_type not in self.schema.nodes(): raise errors.ConsistencyError(f'{node_type} is not defined in the schema') - subject_types = list(self.graph.objects(rdflib.URIRef(subject), rdflib.RDF.type)) + subject_types = list(self._graph.objects(rdflib.URIRef(subject), rdflib.RDF.type)) if len(subject_types) == 0: return False elif len(subject_types) == 1: @@ -170,7 +177,7 @@ class SparqlStore(base.TripleStoreBase): def exists( self, - node_type: _schema.Node, + node_type: bsc.Node, guids: typing.Iterable[URI], ): """ @@ -179,7 +186,7 @@ class SparqlStore(base.TripleStoreBase): def create( self, - node_type: _schema.Node, + node_type: bsc.Node, guids: typing.Iterable[URI], ): """ @@ -195,13 +202,13 @@ class SparqlStore(base.TripleStoreBase): # FIXME: node exists and may have a different type! ignore? raise? report? continue # add node - self.transaction.add((guid, rdflib.RDF.type, rdflib.URIRef(node_type.uri))) + self._transaction.add((guid, rdflib.RDF.type, rdflib.URIRef(node_type.uri))) def set( self, - node_type: _schema.Node, # FIXME: is the node_type even needed? Couldn't I infer from the predicate? + node_type: bsc.Node, guids: typing.Iterable[URI], - predicate: _schema.Predicate, + predicate: bsc.Predicate, values: typing.Iterable[typing.Any], ): # check node_type @@ -218,7 +225,7 @@ class SparqlStore(base.TripleStoreBase): return if predicate.unique and len(values) != 1: raise ValueError(values) - if isinstance(predicate.range, _schema.Node): + if isinstance(predicate.range, bsc.Node): values = set(values) # materialize to safeguard against iterators passed as argument inconsistent = {val for val in values if not self._has_type(val, predicate.range)} # catches nodes that don't exist and nodes that have an inconsistent type @@ -236,18 +243,18 @@ class SparqlStore(base.TripleStoreBase): for guid, value in itertools.product(guids, values): guid = rdflib.URIRef(guid) # convert value - if isinstance(predicate.range, _schema.Literal): + if isinstance(predicate.range, bsc.Literal): value = rdflib.Literal(value, datatype=rdflib.URIRef(predicate.range.uri)) - elif isinstance(predicate.range, _schema.Node): + elif isinstance(predicate.range, bsc.Node): value = rdflib.URIRef(value) else: raise errors.UnreachableError() # clear triples for unique predicates if predicate.unique: - for obj in self.graph.objects(guid, pred): + for obj in self._graph.objects(guid, pred): if obj != value: - self.transaction.remove((guid, pred, obj)) + self._transaction.remove((guid, pred, obj)) # add triple - self.transaction.add((guid, pred, value)) + self._transaction.add((guid, pred, value)) ## EOF ## |