base.py 7.9 KB

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