Source code for oldman.rest.crud

from rdflib import BNode, Graph
from rdflib.plugin import PluginException
from oldman.utils.crud import create_blank_nodes, create_regular_resources
from oldman.utils.crud import extract_subjects
from oldman.exception import OMBadRequestException, OMNotAcceptableException

JSON_TYPES = ["application/json", "json"]
JSON_LD_TYPES = ["application/ld+json", "json-ld"]


[docs]class HashLessCRUDer(object): """A :class:`~oldman.rest.crud.HashlessCRUDer` object helps you to manipulate your :class:`~oldman.resource.Resource` objects in a RESTful-like manner. Please note that REST/HTTP only manipulates hash-less IRIs. A hash IRI is the combination of a hash-less IRI (fragment-less IRI) and a fragment. Multiple hashed IRIs may have the same hash-less IRI and only differ by their fragment values. This is a concern for each type of HTTP operation. This class is generic and does not support the Collection pattern (there is no append method). :param manager: :class:`~oldman.resource.manager.ResourceManager` object. Possible improvements: - Add a PATCH method. """ def __init__(self, manager): self._manager = manager
[docs] def get(self, hashless_iri, content_type="text/turtle"): """Gets the main :class:`~oldman.resource.Resource` object having its hash-less IRI. When multiple :class:`~oldman.resource.Resource` objects have this hash-less IRI, one of them has to be selected. If one has no fragment value, it is selected. Otherwise, this selection is currently arbitrary. TODO: stop selecting the resources and returns the graph containing these resources. Raises an :class:`~oldman.exception.ObjectNotFoundError` exception if no resource is found. :param hashless_iri: hash-less of the resource. :param content_type: Content type of its representation. :return: The representation of selected :class:`~oldman.resource.Resource` object and its content type """ #TODO: stop this practice resource = self._manager.get(hashless_iri=hashless_iri) if content_type in JSON_TYPES: payload = resource.to_json() elif content_type in JSON_LD_TYPES: payload = resource.to_jsonld() # Try as a RDF mime-type (may not be supported) else: try: payload = resource.to_rdf(content_type) except PluginException: raise OMNotAcceptableException() return payload, content_type
[docs] def delete(self, hashless_iri): """Deletes every :class:`~oldman.resource.Resource` object having this hash-less IRI. :param hashless_iri: Hash-less IRI. """ for resource in self._manager.filter(hashless_iri=hashless_iri): if resource is not None: resource.delete()
[docs] def update(self, hashless_iri, document_content, content_type, allow_new_type=False, allow_type_removal=False): """Updates every :class:`~oldman.resource.Resource` object having this hash-less IRI. Raises an :class:`~oldman.exception.OMDifferentBaseIRIError` exception if tries to create of modify non-blank :class:`~oldman.resource.Resource` objects that have a different hash-less IRI. This restriction is motivated by security concerns. Accepts JSON, JSON-LD and RDF formats supported by RDFlib. :param hashless_iri: Document IRI. :param document_content: Payload. :param content_type: Content type of the payload. :param allow_new_type: If `True`, new types can be added. Defaults to `False`. See :func:`oldman.resource.Resource.full_update` for explanations about the security concerns. :param allow_type_removal: If `True`, new types can be removed. Same security concerns than above. Defaults to `False`. """ graph = Graph() #TODO: manage parsing exceptions if content_type in JSON_TYPES: resource = self._manager.get(hashless_iri=hashless_iri) graph.parse(data=document_content, format="json-ld", publicID=hashless_iri, context=resource.context) #RDF graph #TODO: capture unknown type else: graph.parse(data=document_content, format=content_type, publicID=hashless_iri) self._update_graph(hashless_iri, graph, allow_new_type, allow_type_removal)
def _update_graph(self, hashless_iri, graph, allow_new_type, allow_type_removal): # Extracts and classifies subjects bnode_subjects, other_subjects = extract_subjects(graph) #Blank nodes (may obtain a regular IRI) resources = create_blank_nodes(self._manager, graph, bnode_subjects, hashless_iri=hashless_iri) #Objects with an existing IRI reg_resources, resources_to_update = create_regular_resources(self._manager, graph, other_subjects, hashless_iri=hashless_iri) resources += reg_resources # Subset of regular resources to update for resource in resources_to_update: resource.update_from_graph(graph, save=False, allow_new_type=allow_new_type, allow_type_removal=allow_type_removal) #Check validity before saving for r in resources: if not r.is_valid(): raise OMBadRequestException() #TODO: improve it as a transaction (really necessary?) for r in resources: r.save() #Delete omitted resources all_resource_iris = {r.id for r in self._manager.filter(hashless_iri=hashless_iri)} resource_iris_to_remove = all_resource_iris.difference({r.id for r in resources}) for iri in resource_iris_to_remove: # Cheap because already in the resource cache r = self._manager.get(id=iri) if r is not None: r.delete()