Source code for djangordf.schema.recorder

"""Track applied migrations as triples in the configured backend."""
from typing import Iterable, Set

from rdflib import Literal, URIRef


_RECORDER_GRAPH = URIRef("urn:djangordf:migrations")
_MIGRATION_TYPE = URIRef("urn:djangordf:Migration")
_RDF_TYPE = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
_DCT_CREATED = URIRef("http://purl.org/dc/terms/created")
_XSD_DATETIME = URIRef("http://www.w3.org/2001/XMLSchema#dateTime")


def _migration_iri(name: str) -> URIRef:
    return URIRef(f"urn:djangordf:migration:{name}")


[docs] class MigrationRecorder: """Tiny wrapper around ``backend`` that tracks applied migrations in a dedicated named graph.""" def __init__(self, backend): self.backend = backend
[docs] def applied(self) -> Set[str]: """Return the set of migration names already recorded.""" sparql = ( f"SELECT ?m WHERE {{ " f"GRAPH <{_RECORDER_GRAPH}> {{ " f"?m <{_RDF_TYPE}> <{_MIGRATION_TYPE}> " f"}} }}" ) results = self.backend.query(sparql) prefix = "urn:djangordf:migration:" names: Set[str] = set() for row in results: iri = str(row[0]) if iri.startswith(prefix): names.add(iri[len(prefix):]) return names
[docs] def record(self, name: str, *, when: str) -> None: """Persist that ``name`` has been applied at ``when`` (an ISO-8601 timestamp). ``when`` is provided by the caller so the executor can stamp every applied migration with the same run-wide timestamp if desired.""" iri = _migration_iri(name) triples = [ (iri, _RDF_TYPE, _MIGRATION_TYPE), (iri, _DCT_CREATED, Literal(when, datatype=_XSD_DATETIME)), ] self.backend.add(triples, graph=_RECORDER_GRAPH)
[docs] def forget(self, name: str) -> None: """Strip the record for ``name`` from the graph (used in tests; no production command depends on this).""" iri = _migration_iri(name) self.backend.update( f"WITH <{_RECORDER_GRAPH}> " f"DELETE {{ <{iri}> ?p ?o }} " f"WHERE {{ <{iri}> ?p ?o }}" )
[docs] def forget_all(self, names: Iterable[str]) -> None: for name in names: self.forget(name)