base.py 8.1 KB

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