base.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. from abc import ABC, abstractmethod
  2. from typing import Any, List, Tuple, TypeVar, Optional, Union, Generator
  3. import uuid
  4. primitive_types = (int, float, str, bool)
  5. Node = str
  6. Edge = str
  7. Element = Union[Node, Edge]
  8. class State(ABC):
  9. """
  10. Abstract base class for MvS CRUD interface defined in:
  11. http://msdl.cs.mcgill.ca/people/yentl/files/thesis.pdf
  12. """
  13. @staticmethod
  14. def new_id() -> str:
  15. """
  16. Generates a new UUID
  17. """
  18. return str(uuid.uuid4())
  19. @staticmethod
  20. def is_valid_datavalue(value: Any) -> bool:
  21. """
  22. Checks whether value type is supported.
  23. Args:
  24. value: value whose type needs to be checked
  25. Returns:
  26. True if value type is supported, False otherwise.
  27. """
  28. if not isinstance(value, primitive_types):
  29. return False
  30. elif isinstance(value, int) and not (-2**63 <= value <= 2**63 - 1):
  31. return False
  32. return True
  33. def purge(self):
  34. """
  35. Implements a garbage collection routine for implementations that don't have automatic garbage collection.
  36. """
  37. pass
  38. # =========================================================================
  39. # CREATE
  40. # =========================================================================
  41. @abstractmethod
  42. def create_node(self) -> Node:
  43. """
  44. Creates node.
  45. Returns:
  46. The created node.
  47. """
  48. pass
  49. @abstractmethod
  50. def create_edge(self, source: Element, target: Element) -> Optional[Edge]:
  51. """
  52. Creates edge. Source and target elements should already exist.
  53. Args:
  54. source: source element of edge
  55. target: target element of edge
  56. Returns:
  57. The created edge, None if source or target element doesn't exist.
  58. """
  59. pass
  60. @abstractmethod
  61. def create_nodevalue(self, value: Any) -> Optional[Node]:
  62. """
  63. Creates node containing value.
  64. Args:
  65. value: value to assign to new node
  66. Returns:
  67. The created node, None if type of value is not supported.
  68. """
  69. pass
  70. @abstractmethod
  71. def create_dict(self, source: Element, value: Any, target: Element) -> Optional[Tuple[Edge, Edge, Node]]:
  72. """
  73. Creates named edge between two graph elements.
  74. Args:
  75. source: source element of edge
  76. value: edge label
  77. target: target element of edge
  78. Returns:
  79. Tuple containing the created edges and label node, None is source or target don't exist
  80. or value type doesn't exist. First edge goes from source to target, second from edge to label.
  81. """
  82. pass
  83. # =========================================================================
  84. # READ
  85. # =========================================================================
  86. @abstractmethod
  87. def read_root(self) -> Node:
  88. """
  89. Reads state's root node.
  90. Returns:
  91. The state's root node.
  92. """
  93. pass
  94. @abstractmethod
  95. def read_value(self, node: Node) -> Optional[Any]:
  96. """
  97. Reads value of given node.
  98. Args:
  99. node: node whose value to read
  100. Returns:
  101. I node exists, value stored in node, else None.
  102. """
  103. pass
  104. @abstractmethod
  105. def read_outgoing(self, elem: Element) -> Optional[List[Edge]]:
  106. """
  107. Retrieves edges whose source is given element.
  108. Args:
  109. elem: source element of edges to retrieve
  110. Returns:
  111. If elem exists, list of edges whose source is elem, else None.
  112. """
  113. pass
  114. @abstractmethod
  115. def read_incoming(self, elem: Element) -> Optional[List[Edge]]:
  116. """
  117. Retrieves edges whose target is given element.
  118. Args:
  119. elem: target element of edges to retrieve
  120. Returns:
  121. If elem exists, list of edges whose target is elem, else None.
  122. """
  123. pass
  124. @abstractmethod
  125. def read_edge(self, edge: Edge) -> Tuple[Optional[Node], Optional[Node]]:
  126. """
  127. Reads source and target of given edge.
  128. Args:
  129. edge: edge whose source and target to read
  130. Returns:
  131. If edge exists, tuple containing source (first) and target (second) node, else (None, None)
  132. """
  133. pass
  134. @abstractmethod
  135. def read_dict(self, elem: Element, value: Any) -> Optional[Element]:
  136. """
  137. Reads element connected to given element through edge with label = value.
  138. Args:
  139. elem: source element
  140. value: edge label
  141. Returns:
  142. If elem doesn't exist or no edge is found with given label, None, else target element of edge with label = value originating from source.
  143. """
  144. pass
  145. @abstractmethod
  146. def read_dict_keys(self, elem: Element) -> Optional[List[Any]]:
  147. """
  148. Reads labels of outgoing edges starting in given node.
  149. Args:
  150. elem: source element
  151. Returns:
  152. If elem exists, list of (unique) edge labels, else None.
  153. """
  154. pass
  155. @abstractmethod
  156. def read_dict_edge(self, elem: Element, value: Any) -> Optional[Edge]:
  157. """
  158. Reads edge between two elements connected through edge with label = value.
  159. Args:
  160. elem: source element
  161. value: edge label
  162. Returns:
  163. If elem doesn't exist or no edge is found with given label, None, else edge with label = value originating from source.
  164. """
  165. pass
  166. @abstractmethod
  167. def read_dict_node(self, elem: Element, value_node: Node) -> Optional[Element]:
  168. """
  169. Reads element connected to given element through edge with label node = value_node.
  170. Args:
  171. elem: source element
  172. value_node: edge label node
  173. Returns:
  174. If elem exists, target element of edge with label stored in value_node originating from elem, else None.
  175. """
  176. pass
  177. @abstractmethod
  178. def read_dict_node_edge(self, elem: Element, value_node: Node) -> Optional[Edge]:
  179. """
  180. Reads edge connecting two elements through edge with label node = value_node.
  181. Args:
  182. elem: source element
  183. value_node: edge label node
  184. Returns:
  185. If elem exists, edge with label node = value_node, originating from source, else None.
  186. """
  187. pass
  188. @abstractmethod
  189. def read_reverse_dict(self, elem: Element, value: Any) -> Optional[List[Element]]:
  190. """
  191. Retrieves a list of all elements that have an outgoing edge, having label = value, towards the passed element.
  192. Args:
  193. elem: target element
  194. value: edge label
  195. Returns:
  196. If elem exists, list of elements with an outgoing edge with label = value towards elem, else None.
  197. """
  198. pass
  199. # =========================================================================
  200. # UPDATE
  201. # =========================================================================
  202. """
  203. Updates are done by performing subsequent CREATE and DELETE operations:
  204. http://msdl.cs.mcgill.ca/people/yentl/files/thesis.pdf
  205. """
  206. # =========================================================================
  207. # DELETE
  208. # =========================================================================
  209. @abstractmethod
  210. def delete_node(self, node: Node) -> None:
  211. """
  212. Deletes given node from state graph.
  213. Args:
  214. node: node to be deleted
  215. Returns:
  216. None
  217. """
  218. pass
  219. @abstractmethod
  220. def delete_edge(self, edge: Edge) -> None:
  221. """
  222. Deletes given edge from state graph.
  223. Args:
  224. edge: edge to be deleted
  225. Returns:
  226. None
  227. """
  228. pass