base.py 8.0 KB

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