simple_layout.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. from copy import deepcopy
  2. import arrow
  3. from rdflib import Graph
  4. from rdflib.namespace import RDF, XSD
  5. from rdflib.query import ResultException
  6. from rdflib.resource import Resource
  7. from rdflib.term import Literal, URIRef, Variable
  8. from lakesuperior.dictionaries.namespaces import ns_collection as nsc
  9. from lakesuperior.dictionaries.namespaces import ns_mgr as nsm
  10. from lakesuperior.dictionaries.srv_mgd_terms import srv_mgd_subjects, \
  11. srv_mgd_predicates, srv_mgd_types
  12. from lakesuperior.exceptions import InvalidResourceError
  13. from lakesuperior.store_layouts.rdf.base_rdf_layout import BaseRdfLayout
  14. from lakesuperior.util.translator import Translator
  15. class SimpleLayout(BaseRdfLayout):
  16. '''
  17. This is the simplest layout.
  18. It uses a flat triple structure without named graphs aimed at performance.
  19. Changes are destructive.
  20. In theory it could be used on top of a triplestore instead of a quad-store
  21. for (possible) improved speed and reduced storage.
  22. '''
  23. def extract_imr(self, uri, graph=None, minimal=False,
  24. incl_inbound=False, embed_children=False, incl_srv_mgd=True):
  25. '''
  26. See base_rdf_layout.extract_imr.
  27. '''
  28. inbound_qry = '\n?s1 ?p1 {}'.format(uri.n3()) \
  29. if incl_inbound else ''
  30. embed_children_qry = '''
  31. OPTIONAL {{
  32. {0} ldp:contains ?c .
  33. ?c ?cp ?co .
  34. }}
  35. '''.format(uri.n3()) if embed_children else ''
  36. q = '''
  37. CONSTRUCT {{
  38. {0} ?p ?o .{1}
  39. ?c ?cp ?co .
  40. }} WHERE {{
  41. {0} ?p ?o .{1}{2}
  42. #FILTER (?p != premis:hasMessageDigest) .
  43. }}
  44. '''.format(uri.n3(), inbound_qry, embed_children_qry)
  45. try:
  46. qres = self.query(q)
  47. except ResultException:
  48. # RDFlib bug: https://github.com/RDFLib/rdflib/issues/775
  49. g = Graph()
  50. else:
  51. g = qres.graph
  52. # @FIXME This can be expensive with many children. Move this in
  53. # query string.
  54. if not incl_srv_mgd:
  55. self._logger.info('Removing server managed triples.')
  56. for p in srv_mgd_predicates:
  57. self._logger.debug('Removing predicate: {}'.format(p))
  58. rsrc.remove(p)
  59. for t in srv_mgd_types:
  60. self._logger.debug('Removing type: {}'.format(t))
  61. rsrc.remove(RDF.type, t)
  62. return Resource(g, uri)
  63. def ask_rsrc_exists(self, urn):
  64. '''
  65. See base_rdf_layout.ask_rsrc_exists.
  66. '''
  67. self._logger.info('Checking if resource exists: {}'.format(urn))
  68. return (urn, Variable('p'), Variable('o')) in self.ds
  69. def create_rsrc(self, imr):
  70. '''
  71. See base_rdf_layout.create_rsrc.
  72. '''
  73. self.ds |= imr.graph
  74. return self.RES_CREATED
  75. def replace_rsrc(self, imr):
  76. '''
  77. See base_rdf_layout.replace_rsrc.
  78. '''
  79. # @TODO Move this to LDP.
  80. rsrc = self.rsrc(imr.identifier)
  81. # Delete all triples but keep creation date and creator.
  82. created = rsrc.value(nsc['fcrepo'].created)
  83. created_by = rsrc.value(nsc['fcrepo'].createdBy)
  84. if not created or not created_by:
  85. raise InvalidResourceError(urn)
  86. imr.set(nsc['fcrepo'].created, created)
  87. imr.set(nsc['fcrepo'].createdBy, created_by)
  88. # Delete the stored triples.
  89. self.delete_rsrc()
  90. self.ds |= imr.graph
  91. return self.RES_UPDATED
  92. def modify_dataset(self, remove_trp, add_trp):
  93. '''
  94. See base_rdf_layout.update_rsrc.
  95. '''
  96. self.ds -= remove_trp
  97. self.ds += add_trp
  98. #for t in remove.predicate_objects():
  99. # self.rsrc.remove(t[0], t[1])
  100. #for t in add.predicate_objects():
  101. # self.rsrc.add(t[0], t[1])
  102. def delete_rsrc(self, urn, inbound=True):
  103. '''
  104. Delete a resource. If `inbound` is specified, delete all inbound
  105. relationships as well (this is the default).
  106. '''
  107. rsrc = self.rsrc(urn)
  108. print('Removing resource {}.'.format(rsrc.identifier))
  109. rsrc.remove(Variable('p'))
  110. # @TODO Remove children recursively
  111. if inbound:
  112. self.ds.remove(
  113. (Variable('s'), Variable('p'), rsrc.identifier))