simple_strategy.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. from copy import deepcopy
  2. import arrow
  3. from rdflib import Graph
  4. from rdflib.namespace import XSD
  5. from rdflib.term import Literal, URIRef, Variable
  6. from lakesuperior.core.namespaces import ns_collection as nsc
  7. from lakesuperior.core.namespaces import ns_mgr as nsm
  8. from lakesuperior.store_strategies.rdf.base_rdf_strategy import \
  9. BaseRdfStrategy
  10. class SimpleStrategy(BaseRdfStrategy):
  11. '''
  12. This is the simplest strategy.
  13. It uses a flat triple structure without named graphs aimed at performance.
  14. Changes are destructive.
  15. In theory it could be used on top of a triplestore instead of a quad-store
  16. for (possible) improved speed and reduced storage.
  17. '''
  18. @property
  19. def out_graph(self):
  20. '''
  21. See base_rdf_strategy.out_graph.
  22. '''
  23. return self.rsrc.graph
  24. def ask_rsrc_exists(self, rsrc=None):
  25. '''
  26. See base_rdf_strategy.ask_rsrc_exists.
  27. '''
  28. if not rsrc:
  29. if self.rsrc is not None:
  30. rsrc = self.rsrc
  31. else:
  32. return False
  33. self._logger.info('Searching for resource: {}'
  34. .format(rsrc.identifier))
  35. return (rsrc.identifier, Variable('p'), Variable('o')) in self.ds
  36. def create_or_replace_rsrc(self, g):
  37. '''
  38. See base_rdf_strategy.create_or_replace_rsrc.
  39. '''
  40. # @TODO Use gunicorn to get request timestamp.
  41. ts = Literal(arrow.utcnow(), datatype=XSD.dateTime)
  42. if self.ask_rsrc_exists():
  43. self._logger.info(
  44. 'Resource {} exists. Removing all outbound triples.'
  45. .format(self.rsrc.identifier))
  46. # Delete all triples but keep creation date and creator.
  47. created = self.rsrc.value(nsc['fedora'].created)
  48. created_by = self.rsrc.value(nsc['fedora'].createdBy)
  49. self.delete_rsrc()
  50. else:
  51. created = ts
  52. created_by = Literal('BypassAdmin')
  53. self.rsrc.set(nsc['fedora'].created, created)
  54. self.rsrc.set(nsc['fedora'].createdBy, created_by)
  55. self.rsrc.set(nsc['fedora'].lastUpdated, ts)
  56. self.rsrc.set(nsc['fedora'].lastUpdatedBy, Literal('BypassAdmin'))
  57. for s, p, o in g:
  58. self.ds.add((s, p, o))
  59. def create_rsrc(self, g):
  60. '''
  61. See base_rdf_strategy.create_rsrc.
  62. '''
  63. # @TODO Use gunicorn to get request timestamp.
  64. ts = Literal(arrow.utcnow(), datatype=XSD.dateTime)
  65. self.rsrc.set(nsc['fedora'].created, ts)
  66. self.rsrc.set(nsc['fedora'].createdBy, Literal('BypassAdmin'))
  67. for s, p, o in g:
  68. self.ds.add((s, p, o))
  69. def patch_rsrc(self, data):
  70. '''
  71. Perform a SPARQL UPDATE on a resource.
  72. '''
  73. # @TODO Use gunicorn to get request timestamp.
  74. ts = Literal(arrow.utcnow(), datatype=XSD.dateTime)
  75. q = Translator.localize_string(data).replace(
  76. '<>', self.rsrc.identifier.n3())
  77. self.rsrc.set(nsc['fedora'].lastUpdated, ts)
  78. self.rsrc.set(nsc['fedora'].lastUpdatedBy, Literal('BypassAdmin'))
  79. self.ds.update(q)
  80. def delete_rsrc(self, inbound=False):
  81. '''
  82. Delete a resource. If `inbound` is specified, delete all inbound
  83. relationships as well.
  84. '''
  85. print('Removing resource {}.'.format(self.rsrc.identifier))
  86. self.rsrc.remove(Variable('p'))
  87. if inbound:
  88. self.ds.remove((Variable('s'), Variable('p'), self.rsrc.identifier))
  89. ## PROTECTED METHODS ##
  90. def _unique_value(self, p):
  91. '''
  92. Use this to retrieve a single value knowing that there SHOULD be only
  93. one (e.g. `skos:prefLabel`), If more than one is found, raise an
  94. exception.
  95. @param rdflib.Resource rsrc The resource to extract value from.
  96. @param rdflib.term.URIRef p The predicate to serach for.
  97. @throw ValueError if more than one value is found.
  98. '''
  99. values = self.rsrc[p]
  100. value = next(values)
  101. try:
  102. next(values)
  103. except StopIteration:
  104. return value
  105. # If the second next() did not raise a StopIteration, something is
  106. # wrong.
  107. raise ValueError('Predicate {} should be single valued. Found: {}.'\
  108. .format(set(values)))