123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import arrow
- from uuid import uuid4
- from rdflib import Dataset, Graph
- from rdflib.namespace import FOAF, RDF, XSD
- from rdflib.plugins.sparql import prepareQuery
- from rdflib.plugins.stores.sparqlstore import SPARQLUpdateStore
- from rdflib.term import URIRef, Literal
- from lakesuperior.dictionaries.namespaces import ns_collection as nsc
- from lakesuperior.dictionaries.namespaces import ns_mgr as nsm
- from lakesuperior.store_layouts.rdf.base_rdf_layout import BaseRdfLayout
- class FullProvenanceLayout(BaseRdfLayout):
- '''This is an implementation of the
- [graph-per-resource pattern](http://patterns.dataincubator.org/book/graph-per-resource.html)
- which stores each LDP resource in a separate graph, with a "main" graph
- to keep track of resource metadata.
- '''
- DEFAULT_AGENT_URI = nsc['lake'].defaultAgent
- MAIN_GRAPH_URI = nsc['fcg'].meta
- ## MAGIC METHODS ##
- def __init__(self):
- self.main_graph = self.ds.graph(self.MAIN_GRAPH_URI)
- ## PUBLIC METHODS ##
- def ask_rsrc_exists(self, uuid):
- '''Return whether the resource exists.
- @param uuid Resource UUID.
- @retrn boolean
- '''
- res = self.ds.graph(self.UNION_GRAPH_URI).resource(nsc['fcres'][uuid])
- return len(res) > 0
- def get_rsrc(self, uuid):
- '''Get a resource graph.
- '''
- res = self.ds.graph(self.UNION_GRAPH_URI).query(
- 'CONSTRUCT WHERE { ?s ?p ?o }',
- initBindings={'s' : nsc['fcres'][uuid]}
- )
- return self.globalize_graph(res.graph)
- def put_rsrc(self, uuid, data, format='text/turtle', base_types=None,
- agent=None):
- '''Create a resource graph.
- If the resource UUID exists already, it is either overwritten or a
- version snapshot is created, depending on the parameters.
- '''
- if agent is None:
- agent = self.DEFAULT_AGENT_URI
- res_urn = nsc['fcres'][uuid]
- # If there is a statement by this agent about this resource, replace
- # its contents.
- if self._get_res_stmt_by_agent(res_urn, agent):
- pass # @TODO
- # If the graph URI does not exist, create a new resource.
- else:
- # Create a new UUID for the statement set.
- stmset_uri = nsc['stmset'][str(uuid4())]
- # Create a temp graph to store the loaded data. For some reason,
- # loading directly into the stored graph throws an assertion error.
- tmp_g = Graph()
- tmp_g.parse(data=data.decode('utf-8'), format=format,
- publicID=str(res_urn))
- # Create the graph and add the data.
- g = self.ds.graph(stmset_uri)
- g += tmp_g
- # Add metadata.
- ts = arrow.utcnow()
- main_graph = self.ds.graph(self.MAIN_GRAPH_URI)
- main_graph.add((stmset_uri, FOAF.primaryTopic, res_urn))
- main_graph.add((stmset_uri, RDF.type, nsc['prov'].Entity))
- main_graph.add(
- (stmset_uri, nsc['prov'].generatedAtTime,
- Literal(ts, datatype=XSD.dateTime)))
- main_graph.add(
- (stmset_uri, nsc['prov'].wasAttributedTo, agent))
- #self.create_version(res_urn)
- if base_types:
- for type_uri in self.base_types:
- main_graph.add((stmset_uri, RDF.type, type_uri))
- # @TODO Create containment triples
- self.conn.store.commit()
- #def create_version(self, res_urn):
- # '''Swap out previous version if existing, and create new version
- # dependency.'''
- # main_graph = ds.graph(URIRef('urn:lake:' + self.MAIN_GRAPH_NAME))
- # prv_res_urn = self.select_current_graph_for_res(res_urn)
- # if prv_res_urn:
- # main_graph.remove((prv_res_urn, RDF.type, nsc['lake'].Resource))
- # main_graph.add((prv_res_urn, RDF.type, nsc['lake'].Snapshot))
- # main_graph.add((res_urn, RDF.type, nsc['lake'].Resource))
- # main_graph.add((res_urn, nsc['lake'].previousVersion, prv_res_urn))
- #def select_current_graph_for_res(self, urn):
- # '''Select the current graph URI for a given resource.'''
- # qry = '''
- # SELECT ?g {
- # GRAPH ?mg { ?g a ?gt . }
- # GRAPH ?g { ?s ?p ?o . }
- # }
- # LIMIT 1
- # '''
- # rsp = self.ds.query(qry, initBindings={
- # 'mg' : URIRef('urn:lake:' + self.MAIN_GRAPH_NAME),
- # 'gt' : RESOURCE_TYPE_URI,
- # 's' : urn
- # })
- # return list(rsp[0][0])
- def _ask_res_stmt_by_agent_exists(self, res_urn, agent):
- '''Ask if any statements have been made by a certain agent about a
- certain resource.
- @param rdflib.term.URIRef res_urn Resource URN.
- @param rdflib.term.URIRef agent Agent URI.
- @return boolean
- '''
- return self.query('''
- ASK {
- GRAPH ?mg {
- ?g prov:wasAttributedTo ?a .
- }
- GRAPH ?g {
- ?s ?p ?o .
- }
- }
- ''', initBindings={
- 'a' : agent,
- 's' : res_urn,
- })
|