rdfstate.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. from typing import Any, List, Tuple, Optional, Generator
  2. from rdflib import Graph, Namespace, URIRef, Literal
  3. from rdflib.plugins.sparql import prepareQuery
  4. import json
  5. from .base import State
  6. # Define graph datasctructures used by implementation
  7. # Use NewType to create distinct type or just create a type alias
  8. Element = URIRef
  9. Node = URIRef
  10. Edge = URIRef
  11. class RDFState(State):
  12. def __init__(self, namespace_uri="http://modelverse.mv/#"):
  13. self.graph = Graph()
  14. self.namespace_uri = namespace_uri
  15. self.mv = Namespace(namespace_uri)
  16. self.graph.bind("MV", self.mv)
  17. self.prepared_queries = {
  18. "read_value": """
  19. SELECT ?value
  20. WHERE {
  21. ?var1 MV:hasValue ?value .
  22. }
  23. """,
  24. "read_outgoing": """
  25. SELECT ?link
  26. WHERE {
  27. ?link MV:hasSource ?var1 .
  28. }
  29. """,
  30. "read_incoming": """
  31. SELECT ?link
  32. WHERE {
  33. ?link MV:hasTarget ?var1 .
  34. }
  35. """,
  36. "read_edge": """
  37. SELECT ?source ?target
  38. WHERE {
  39. ?var1 MV:hasSource ?source ;
  40. MV:hasTarget ?target .
  41. }
  42. """,
  43. "read_dict_keys": """
  44. SELECT ?key
  45. WHERE {
  46. ?main_edge MV:hasSource ?var1 .
  47. ?attr_edge MV:hasSource ?main_edge ;
  48. MV:hasTarget ?key .
  49. }
  50. """,
  51. "read_dict_node": """
  52. SELECT ?value_node
  53. WHERE {
  54. ?main_edge MV:hasSource ?var1 ;
  55. MV:hasTarget ?value_node .
  56. ?attr_edge MV:hasSource ?main_edge ;
  57. MV:hasTarget ?var2 .
  58. }
  59. """,
  60. "read_dict_node_edge": """
  61. SELECT ?main_edge
  62. WHERE {
  63. ?main_edge MV:hasSource ?var1 .
  64. ?attr_edge MV:hasSource ?main_edge ;
  65. MV:hasTarget ?var2 .
  66. }
  67. """,
  68. "delete_node": """
  69. SELECT ?edge
  70. WHERE {
  71. { ?edge MV:hasTarget ?var1 . }
  72. UNION
  73. { ?edge MV:hasSource ?var1 . }
  74. }
  75. """,
  76. "delete_edge": """
  77. SELECT ?edge
  78. WHERE {
  79. { ?edge MV:hasTarget ?var1 . }
  80. UNION
  81. { ?edge MV:hasSource ?var1 . }
  82. }
  83. """,
  84. }
  85. self.garbage = set()
  86. for k, v in list(self.prepared_queries.items()):
  87. self.prepared_queries[k] = prepareQuery(self.prepared_queries[k], initNs={"MV": self.mv})
  88. self.root = self.create_node()
  89. def create_node(self) -> Node:
  90. return URIRef(self.namespace_uri + str(self.new_id()))
  91. def create_edge(self, source: Element, target: Element) -> Optional[Edge]:
  92. if not isinstance(source, URIRef):
  93. return None
  94. elif not isinstance(target, URIRef):
  95. return None
  96. edge = URIRef(self.namespace_uri + str(self.new_id()))
  97. self.graph.add((edge, self.mv.hasSource, source))
  98. self.graph.add((edge, self.mv.hasTarget, target))
  99. return edge
  100. def create_nodevalue(self, value: Any) -> Optional[Node]:
  101. if not self.is_valid_datavalue(value):
  102. return None
  103. node = URIRef(self.namespace_uri + str(self.new_id()))
  104. if isinstance(value, tuple):
  105. value = {"Type": value[0]}
  106. self.graph.add((node, self.mv.hasValue, Literal(json.dumps(value))))
  107. return node
  108. def create_dict(self, source: Element, value: Any, target: Element) -> Optional[Tuple[Edge, Edge, Node]]:
  109. if not isinstance(source, URIRef):
  110. return
  111. if not isinstance(target, URIRef):
  112. return
  113. if not self.is_valid_datavalue(value):
  114. return
  115. n = self.create_nodevalue(value)
  116. e = self.create_edge(source, target)
  117. self.create_edge(e, n)
  118. def read_root(self) -> Node:
  119. return self.root
  120. def read_value(self, node: Node) -> Optional[Any]:
  121. if not isinstance(node, URIRef) or not (node, None, None) in self.graph:
  122. return None
  123. result = self.graph.query(self.prepared_queries["read_value"], initBindings={"var1": node})
  124. if len(result) == 0:
  125. return None
  126. result = json.loads(list(result)[0][0])
  127. return result if not isinstance(result, dict) else (result["Type"],)
  128. def read_outgoing(self, elem: Element) -> Optional[List[Edge]]:
  129. if not isinstance(elem, URIRef) or elem in self.garbage:
  130. return None
  131. result = self.graph.query(self.prepared_queries["read_outgoing"], initBindings={"var1": elem})
  132. return [i[0] for i in result]
  133. def read_incoming(self, elem: Element) -> Optional[List[Edge]]:
  134. if not isinstance(elem, URIRef) or elem in self.garbage:
  135. return None
  136. result = self.graph.query(self.prepared_queries["read_incoming"], initBindings={"var1": elem})
  137. return [i[0] for i in result]
  138. def read_edge(self, edge: Edge) -> Tuple[Optional[Node], Optional[Node]]:
  139. if not isinstance(edge, URIRef) or not (edge, None, None) in self.graph:
  140. return None, None
  141. result = self.graph.query(self.prepared_queries["read_edge"], initBindings={"var1": edge})
  142. if len(result) == 0:
  143. return None, None
  144. else:
  145. return list(result)[0][0], list(result)[0][1]
  146. def read_dict(self, elem: Element, value: Any) -> Optional[Element]:
  147. if not isinstance(elem, URIRef):
  148. return None
  149. q = f"""
  150. SELECT ?value_node
  151. WHERE {{
  152. ?main_edge MV:hasSource <{elem}> ;
  153. MV:hasTarget ?value_node .
  154. ?attr_edge MV:hasSource ?main_edge ;
  155. MV:hasTarget ?attr_node .
  156. ?attr_node MV:hasValue '{json.dumps(value)}' .
  157. }}
  158. """
  159. result = self.graph.query(q)
  160. if len(result) == 0:
  161. return None
  162. return list(result)[0][0]
  163. def read_dict_keys(self, elem: Element) -> Optional[List[Any]]:
  164. if not isinstance(elem, URIRef):
  165. return None
  166. result = self.graph.query(self.prepared_queries["read_dict_keys"], initBindings={"var1": elem})
  167. return [i[0] for i in result]
  168. def read_dict_edge(self, elem: Element, value: Any) -> Optional[Edge]:
  169. if not isinstance(elem, URIRef):
  170. return None
  171. result = self.graph.query(
  172. f"""
  173. SELECT ?main_edge
  174. WHERE {{
  175. ?main_edge MV:hasSource <{elem}> ;
  176. MV:hasTarget ?value_node .
  177. ?attr_edge MV:hasSource ?main_edge ;
  178. MV:hasTarget ?attr_node .
  179. ?attr_node MV:hasValue '{json.dumps(value)}' .
  180. }}
  181. """)
  182. if len(result) == 0:
  183. return None
  184. return list(result)[0][0]
  185. def read_dict_node(self, elem: Element, value_node: Node) -> Optional[Element]:
  186. if not isinstance(elem, URIRef):
  187. return None
  188. if not isinstance(value_node, URIRef):
  189. return None
  190. result = self.graph.query(
  191. self.prepared_queries["read_dict_node"], initBindings={"var1": elem, "var2": value_node}
  192. )
  193. if len(result) == 0:
  194. return None
  195. return list(result)[0][0]
  196. def read_dict_node_edge(self, elem: Element, value_node: Node) -> Optional[Edge]:
  197. if not isinstance(elem, URIRef):
  198. return None
  199. if not isinstance(value_node, URIRef):
  200. return None
  201. result = self.graph.query(
  202. self.prepared_queries["read_dict_node_edge"], initBindings={"var1": elem, "var2": value_node}
  203. )
  204. if len(result) == 0:
  205. return None
  206. return list(result)[0][0]
  207. def read_reverse_dict(self, elem: Element, value: Any) -> Optional[List[Element]]:
  208. if not isinstance(elem, URIRef):
  209. return None
  210. result = self.graph.query(
  211. f"""
  212. SELECT ?source_node
  213. WHERE {{
  214. ?main_edge MV:hasTarget <{elem}> ;
  215. MV:hasSource ?source_node .
  216. ?attr_edge MV:hasSource ?main_edge ;
  217. MV:hasTarget ?value_node .
  218. ?value_node MV:hasValue '{json.dumps(value)}' .
  219. }}
  220. """)
  221. return [i[0] for i in result]
  222. def delete_node(self, node: Node) -> None:
  223. if node == self.root:
  224. return
  225. if not isinstance(node, URIRef):
  226. return
  227. # Check whether node isn't an edge
  228. if (node, self.mv.hasSource, None) in self.graph or (node, self.mv.hasTarget, None) in self.graph:
  229. return
  230. # Remove its value if it exists
  231. self.graph.remove((node, None, None))
  232. # Get all edges connecting this
  233. result = self.graph.query(self.prepared_queries["delete_node"], initBindings={"var1": node})
  234. # ... and remove them
  235. for e in result:
  236. self.delete_edge(e[0])
  237. self.garbage.add(node)
  238. def delete_edge(self, edge: Edge) -> None:
  239. if not isinstance(edge, URIRef):
  240. return
  241. # Check whether edge is actually an edge
  242. if not ((edge, self.mv.hasSource, None) in self.graph and (edge, self.mv.hasTarget, None) in self.graph):
  243. return
  244. # Remove its links
  245. self.graph.remove((edge, None, None))
  246. # Get all edges connecting this
  247. result = self.graph.query(self.prepared_queries["delete_edge"], initBindings={"var1": edge})
  248. # ... and remove them
  249. for e in result:
  250. self.delete_edge(e[0])
  251. self.garbage.add(edge)