Source code for buildingmotif.database.graph_connection

import logging
from pathlib import Path
from typing import TYPE_CHECKING, List, Optional

from rdflib.graph import Graph, Store, URIRef, plugin
from rdflib.namespace import NamespaceManager

if TYPE_CHECKING:
    from buildingmotif.building_motif.building_motif import BuildingMotifEngine

PROJECT_DIR = Path(__file__).resolve().parent


[docs]class GraphConnection: """Manages graph connection.""" def __init__( self, engine: "BuildingMotifEngine", db_identifier: Optional[str] = "buildingmotif_store", ) -> None: """Constructor for the database and datastore. :param engine: database engine :type engine: Engine :param db_identifier: defaults to "buildingmotif_store" :type db_identifier: Optional[str], optional """ self.logger = logging.getLogger(__name__) self.store = plugin.get("SQLAlchemy", Store)( identifier=db_identifier, engine=engine ) # avoids the warnings raised by the issue in https://github.com/RDFLib/rdflib/issues/1880 # Eventually will require rdflib-sqlalchemy to support the 'override' keyword def fixed_bind(self, prefix: str, namespace: URIRef, override: bool): self.store.bind(prefix, namespace) setattr(NamespaceManager, "_store_bind", fixed_bind) self.logger.debug("Creating tables for graph storage") self.store.create_all()
[docs] def create_graph(self, identifier: str, graph: Graph) -> Graph: """Create a graph in the database. :param identifier: identifier of graph :type identifier: str :param graph: graph to add, defaults to None :type graph: Graph :return: graph added :rtype: Graph """ self.logger.debug( f"Creating graph: '{identifier}' in database with: {len(graph)} triples" ) g = Graph(self.store, identifier=identifier) new_triples = [(s, o, p, g) for (s, o, p) in graph] g.addN(new_triples) return g
[docs] def get_all_graph_identifiers(self) -> List[str]: """Get all graph identifiers. :return: all graph identifiers :rtype: List[str] """ graph_identifiers = [str(c) for c in self.store.contexts()] return graph_identifiers
[docs] def get_graph(self, identifier: str) -> Graph: """Get graph by identifier. Graph has triples, no context. :param identifier: graph identifier :type identifier: str :return: graph without context :rtype: Graph """ result = Graph(self.store, identifier=identifier) # we used to bind prefixes here but this is unnecessary because # the graph has prefixes bound when it is saved return result
[docs] def delete_graph(self, identifier: str) -> None: """Delete graph. :param identifier: graph identifier :type identifier: str """ self.logger.debug(f"Deleting graph: '{identifier}'") g = Graph(self.store, identifier=identifier) self.store.remove((None, None, None), g)