flowquery 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/.github/workflows/python-publish.yml +97 -0
  2. package/dist/compute/runner.d.ts +3 -2
  3. package/dist/compute/runner.d.ts.map +1 -1
  4. package/dist/compute/runner.js +7 -7
  5. package/dist/compute/runner.js.map +1 -1
  6. package/dist/flowquery.min.js +1 -1
  7. package/dist/graph/data.d.ts +31 -0
  8. package/dist/graph/data.d.ts.map +1 -0
  9. package/dist/graph/data.js +110 -0
  10. package/dist/graph/data.js.map +1 -0
  11. package/dist/graph/database.d.ts +20 -0
  12. package/dist/graph/database.d.ts.map +1 -0
  13. package/dist/graph/database.js +77 -0
  14. package/dist/graph/database.js.map +1 -0
  15. package/dist/graph/hops.d.ts +11 -0
  16. package/dist/graph/hops.d.ts.map +1 -0
  17. package/dist/graph/hops.js +25 -0
  18. package/dist/graph/hops.js.map +1 -0
  19. package/dist/graph/node.d.ts +35 -0
  20. package/dist/graph/node.d.ts.map +1 -0
  21. package/dist/graph/node.js +113 -0
  22. package/dist/graph/node.js.map +1 -0
  23. package/dist/graph/node_data.d.ts +11 -0
  24. package/dist/graph/node_data.d.ts.map +1 -0
  25. package/dist/graph/node_data.js +20 -0
  26. package/dist/graph/node_data.js.map +1 -0
  27. package/dist/graph/node_reference.d.ts +10 -0
  28. package/dist/graph/node_reference.d.ts.map +1 -0
  29. package/dist/graph/node_reference.js +52 -0
  30. package/dist/graph/node_reference.js.map +1 -0
  31. package/dist/graph/pattern.d.ts +18 -0
  32. package/dist/graph/pattern.d.ts.map +1 -0
  33. package/dist/graph/pattern.js +114 -0
  34. package/dist/graph/pattern.js.map +1 -0
  35. package/dist/graph/pattern_expression.d.ts +14 -0
  36. package/dist/graph/pattern_expression.d.ts.map +1 -0
  37. package/dist/graph/pattern_expression.js +58 -0
  38. package/dist/graph/pattern_expression.js.map +1 -0
  39. package/dist/graph/patterns.d.ts +11 -0
  40. package/dist/graph/patterns.d.ts.map +1 -0
  41. package/dist/graph/patterns.js +49 -0
  42. package/dist/graph/patterns.js.map +1 -0
  43. package/dist/graph/physical_node.d.ts +10 -0
  44. package/dist/graph/physical_node.d.ts.map +1 -0
  45. package/dist/graph/physical_node.js +40 -0
  46. package/dist/graph/physical_node.js.map +1 -0
  47. package/dist/graph/physical_relationship.d.ts +10 -0
  48. package/dist/graph/physical_relationship.d.ts.map +1 -0
  49. package/dist/graph/physical_relationship.js +40 -0
  50. package/dist/graph/physical_relationship.js.map +1 -0
  51. package/dist/graph/relationship.d.ts +40 -0
  52. package/dist/graph/relationship.d.ts.map +1 -0
  53. package/dist/graph/relationship.js +124 -0
  54. package/dist/graph/relationship.js.map +1 -0
  55. package/dist/graph/relationship_data.d.ts +12 -0
  56. package/dist/graph/relationship_data.d.ts.map +1 -0
  57. package/dist/graph/relationship_data.js +40 -0
  58. package/dist/graph/relationship_data.js.map +1 -0
  59. package/dist/graph/relationship_match_collector.d.ts +19 -0
  60. package/dist/graph/relationship_match_collector.d.ts.map +1 -0
  61. package/dist/graph/relationship_match_collector.js +55 -0
  62. package/dist/graph/relationship_match_collector.js.map +1 -0
  63. package/dist/graph/relationship_reference.d.ts +8 -0
  64. package/dist/graph/relationship_reference.d.ts.map +1 -0
  65. package/dist/graph/relationship_reference.js +37 -0
  66. package/dist/graph/relationship_reference.js.map +1 -0
  67. package/dist/parsing/base_parser.d.ts +1 -0
  68. package/dist/parsing/base_parser.d.ts.map +1 -1
  69. package/dist/parsing/base_parser.js +4 -1
  70. package/dist/parsing/base_parser.js.map +1 -1
  71. package/dist/parsing/context.d.ts +2 -2
  72. package/dist/parsing/context.js +5 -5
  73. package/dist/parsing/expressions/boolean.d.ts +8 -0
  74. package/dist/parsing/expressions/boolean.d.ts.map +1 -0
  75. package/dist/parsing/expressions/boolean.js +26 -0
  76. package/dist/parsing/expressions/boolean.js.map +1 -0
  77. package/dist/parsing/expressions/expression.d.ts +4 -1
  78. package/dist/parsing/expressions/expression.d.ts.map +1 -1
  79. package/dist/parsing/expressions/expression.js +15 -8
  80. package/dist/parsing/expressions/expression.js.map +1 -1
  81. package/dist/parsing/expressions/operator.d.ts +1 -1
  82. package/dist/parsing/expressions/operator.d.ts.map +1 -1
  83. package/dist/parsing/expressions/operator.js.map +1 -1
  84. package/dist/parsing/functions/function_factory.d.ts +13 -13
  85. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  86. package/dist/parsing/functions/function_factory.js +20 -18
  87. package/dist/parsing/functions/function_factory.js.map +1 -1
  88. package/dist/parsing/operations/create_node.d.ts +14 -0
  89. package/dist/parsing/operations/create_node.d.ts.map +1 -0
  90. package/dist/parsing/operations/create_node.js +51 -0
  91. package/dist/parsing/operations/create_node.js.map +1 -0
  92. package/dist/parsing/operations/create_relationship.d.ts +14 -0
  93. package/dist/parsing/operations/create_relationship.d.ts.map +1 -0
  94. package/dist/parsing/operations/create_relationship.js +51 -0
  95. package/dist/parsing/operations/create_relationship.js.map +1 -0
  96. package/dist/parsing/operations/match.d.ts +15 -0
  97. package/dist/parsing/operations/match.d.ts.map +1 -0
  98. package/dist/parsing/operations/match.js +45 -0
  99. package/dist/parsing/operations/match.js.map +1 -0
  100. package/dist/parsing/operations/operation.d.ts +1 -0
  101. package/dist/parsing/operations/operation.d.ts.map +1 -1
  102. package/dist/parsing/operations/operation.js +6 -0
  103. package/dist/parsing/operations/operation.js.map +1 -1
  104. package/dist/parsing/operations/return.d.ts +1 -0
  105. package/dist/parsing/operations/return.d.ts.map +1 -1
  106. package/dist/parsing/operations/return.js +7 -1
  107. package/dist/parsing/operations/return.js.map +1 -1
  108. package/dist/parsing/operations/where.d.ts +1 -1
  109. package/dist/parsing/operations/where.d.ts.map +1 -1
  110. package/dist/parsing/operations/where.js +4 -0
  111. package/dist/parsing/operations/where.js.map +1 -1
  112. package/dist/parsing/parser.d.ts +10 -0
  113. package/dist/parsing/parser.d.ts.map +1 -1
  114. package/dist/parsing/parser.js +344 -5
  115. package/dist/parsing/parser.js.map +1 -1
  116. package/dist/parsing/token_to_node.d.ts.map +1 -1
  117. package/dist/parsing/token_to_node.js +7 -0
  118. package/dist/parsing/token_to_node.js.map +1 -1
  119. package/dist/tokenization/keyword.d.ts +1 -0
  120. package/dist/tokenization/keyword.d.ts.map +1 -1
  121. package/dist/tokenization/keyword.js +1 -0
  122. package/dist/tokenization/keyword.js.map +1 -1
  123. package/dist/tokenization/token.d.ts +4 -0
  124. package/dist/tokenization/token.d.ts.map +1 -1
  125. package/dist/tokenization/token.js +14 -1
  126. package/dist/tokenization/token.js.map +1 -1
  127. package/dist/tokenization/token_type.d.ts +1 -0
  128. package/dist/tokenization/token_type.d.ts.map +1 -1
  129. package/dist/tokenization/token_type.js +1 -0
  130. package/dist/tokenization/token_type.js.map +1 -1
  131. package/dist/tokenization/tokenizer.d.ts +2 -1
  132. package/dist/tokenization/tokenizer.d.ts.map +1 -1
  133. package/dist/tokenization/tokenizer.js +25 -12
  134. package/dist/tokenization/tokenizer.js.map +1 -1
  135. package/docs/flowquery.min.js +1 -1
  136. package/flowquery-py/README.md +166 -0
  137. package/flowquery-py/pyproject.toml +75 -0
  138. package/flowquery-py/setup_env.ps1 +92 -0
  139. package/flowquery-py/setup_env.sh +87 -0
  140. package/flowquery-py/src/__init__.py +34 -0
  141. package/flowquery-py/src/__main__.py +10 -0
  142. package/flowquery-py/src/compute/__init__.py +5 -0
  143. package/flowquery-py/src/compute/runner.py +60 -0
  144. package/flowquery-py/src/extensibility.py +52 -0
  145. package/flowquery-py/src/graph/__init__.py +31 -0
  146. package/flowquery-py/src/graph/data.py +118 -0
  147. package/flowquery-py/src/graph/database.py +82 -0
  148. package/flowquery-py/src/graph/hops.py +43 -0
  149. package/flowquery-py/src/graph/node.py +112 -0
  150. package/flowquery-py/src/graph/node_data.py +26 -0
  151. package/flowquery-py/src/graph/node_reference.py +49 -0
  152. package/flowquery-py/src/graph/pattern.py +125 -0
  153. package/flowquery-py/src/graph/pattern_expression.py +62 -0
  154. package/flowquery-py/src/graph/patterns.py +42 -0
  155. package/flowquery-py/src/graph/physical_node.py +40 -0
  156. package/flowquery-py/src/graph/physical_relationship.py +36 -0
  157. package/flowquery-py/src/graph/relationship.py +135 -0
  158. package/flowquery-py/src/graph/relationship_data.py +33 -0
  159. package/flowquery-py/src/graph/relationship_match_collector.py +77 -0
  160. package/flowquery-py/src/graph/relationship_reference.py +21 -0
  161. package/flowquery-py/src/io/__init__.py +5 -0
  162. package/flowquery-py/src/io/command_line.py +67 -0
  163. package/flowquery-py/src/parsing/__init__.py +17 -0
  164. package/flowquery-py/src/parsing/alias.py +20 -0
  165. package/flowquery-py/src/parsing/alias_option.py +11 -0
  166. package/flowquery-py/src/parsing/ast_node.py +146 -0
  167. package/flowquery-py/src/parsing/base_parser.py +84 -0
  168. package/flowquery-py/src/parsing/components/__init__.py +19 -0
  169. package/flowquery-py/src/parsing/components/csv.py +8 -0
  170. package/flowquery-py/src/parsing/components/from_.py +10 -0
  171. package/flowquery-py/src/parsing/components/headers.py +12 -0
  172. package/flowquery-py/src/parsing/components/json.py +8 -0
  173. package/flowquery-py/src/parsing/components/null.py +10 -0
  174. package/flowquery-py/src/parsing/components/post.py +8 -0
  175. package/flowquery-py/src/parsing/components/text.py +8 -0
  176. package/flowquery-py/src/parsing/context.py +50 -0
  177. package/flowquery-py/src/parsing/data_structures/__init__.py +15 -0
  178. package/flowquery-py/src/parsing/data_structures/associative_array.py +41 -0
  179. package/flowquery-py/src/parsing/data_structures/json_array.py +30 -0
  180. package/flowquery-py/src/parsing/data_structures/key_value_pair.py +38 -0
  181. package/flowquery-py/src/parsing/data_structures/lookup.py +49 -0
  182. package/flowquery-py/src/parsing/data_structures/range_lookup.py +42 -0
  183. package/flowquery-py/src/parsing/expressions/__init__.py +57 -0
  184. package/flowquery-py/src/parsing/expressions/boolean.py +20 -0
  185. package/flowquery-py/src/parsing/expressions/expression.py +138 -0
  186. package/flowquery-py/src/parsing/expressions/expression_map.py +26 -0
  187. package/flowquery-py/src/parsing/expressions/f_string.py +27 -0
  188. package/flowquery-py/src/parsing/expressions/identifier.py +20 -0
  189. package/flowquery-py/src/parsing/expressions/number.py +32 -0
  190. package/flowquery-py/src/parsing/expressions/operator.py +169 -0
  191. package/flowquery-py/src/parsing/expressions/reference.py +47 -0
  192. package/flowquery-py/src/parsing/expressions/string.py +27 -0
  193. package/flowquery-py/src/parsing/functions/__init__.py +75 -0
  194. package/flowquery-py/src/parsing/functions/aggregate_function.py +60 -0
  195. package/flowquery-py/src/parsing/functions/async_function.py +62 -0
  196. package/flowquery-py/src/parsing/functions/avg.py +55 -0
  197. package/flowquery-py/src/parsing/functions/collect.py +75 -0
  198. package/flowquery-py/src/parsing/functions/function.py +68 -0
  199. package/flowquery-py/src/parsing/functions/function_factory.py +173 -0
  200. package/flowquery-py/src/parsing/functions/function_metadata.py +149 -0
  201. package/flowquery-py/src/parsing/functions/functions.py +59 -0
  202. package/flowquery-py/src/parsing/functions/join.py +47 -0
  203. package/flowquery-py/src/parsing/functions/keys.py +34 -0
  204. package/flowquery-py/src/parsing/functions/predicate_function.py +46 -0
  205. package/flowquery-py/src/parsing/functions/predicate_sum.py +47 -0
  206. package/flowquery-py/src/parsing/functions/rand.py +28 -0
  207. package/flowquery-py/src/parsing/functions/range_.py +34 -0
  208. package/flowquery-py/src/parsing/functions/reducer_element.py +15 -0
  209. package/flowquery-py/src/parsing/functions/replace.py +37 -0
  210. package/flowquery-py/src/parsing/functions/round_.py +32 -0
  211. package/flowquery-py/src/parsing/functions/size.py +32 -0
  212. package/flowquery-py/src/parsing/functions/split.py +47 -0
  213. package/flowquery-py/src/parsing/functions/stringify.py +47 -0
  214. package/flowquery-py/src/parsing/functions/sum.py +51 -0
  215. package/flowquery-py/src/parsing/functions/to_json.py +33 -0
  216. package/flowquery-py/src/parsing/functions/type_.py +47 -0
  217. package/flowquery-py/src/parsing/functions/value_holder.py +24 -0
  218. package/flowquery-py/src/parsing/logic/__init__.py +15 -0
  219. package/flowquery-py/src/parsing/logic/case.py +29 -0
  220. package/flowquery-py/src/parsing/logic/else_.py +12 -0
  221. package/flowquery-py/src/parsing/logic/end.py +8 -0
  222. package/flowquery-py/src/parsing/logic/then.py +12 -0
  223. package/flowquery-py/src/parsing/logic/when.py +10 -0
  224. package/flowquery-py/src/parsing/operations/__init__.py +35 -0
  225. package/flowquery-py/src/parsing/operations/aggregated_return.py +24 -0
  226. package/flowquery-py/src/parsing/operations/aggregated_with.py +22 -0
  227. package/flowquery-py/src/parsing/operations/call.py +74 -0
  228. package/flowquery-py/src/parsing/operations/create_node.py +34 -0
  229. package/flowquery-py/src/parsing/operations/create_relationship.py +34 -0
  230. package/flowquery-py/src/parsing/operations/group_by.py +130 -0
  231. package/flowquery-py/src/parsing/operations/limit.py +22 -0
  232. package/flowquery-py/src/parsing/operations/load.py +140 -0
  233. package/flowquery-py/src/parsing/operations/match.py +29 -0
  234. package/flowquery-py/src/parsing/operations/operation.py +69 -0
  235. package/flowquery-py/src/parsing/operations/projection.py +21 -0
  236. package/flowquery-py/src/parsing/operations/return_op.py +50 -0
  237. package/flowquery-py/src/parsing/operations/unwind.py +37 -0
  238. package/flowquery-py/src/parsing/operations/where.py +41 -0
  239. package/flowquery-py/src/parsing/operations/with_op.py +18 -0
  240. package/flowquery-py/src/parsing/parser.py +1011 -0
  241. package/flowquery-py/src/parsing/token_to_node.py +109 -0
  242. package/flowquery-py/src/tokenization/__init__.py +23 -0
  243. package/flowquery-py/src/tokenization/keyword.py +48 -0
  244. package/flowquery-py/src/tokenization/operator.py +29 -0
  245. package/flowquery-py/src/tokenization/string_walker.py +158 -0
  246. package/flowquery-py/src/tokenization/symbol.py +19 -0
  247. package/flowquery-py/src/tokenization/token.py +659 -0
  248. package/flowquery-py/src/tokenization/token_mapper.py +52 -0
  249. package/flowquery-py/src/tokenization/token_type.py +21 -0
  250. package/flowquery-py/src/tokenization/tokenizer.py +214 -0
  251. package/flowquery-py/src/tokenization/trie.py +124 -0
  252. package/flowquery-py/src/utils/__init__.py +6 -0
  253. package/flowquery-py/src/utils/object_utils.py +20 -0
  254. package/flowquery-py/src/utils/string_utils.py +113 -0
  255. package/flowquery-py/tests/__init__.py +1 -0
  256. package/flowquery-py/tests/compute/__init__.py +1 -0
  257. package/flowquery-py/tests/compute/test_runner.py +1335 -0
  258. package/flowquery-py/tests/graph/__init__.py +1 -0
  259. package/flowquery-py/tests/graph/test_create.py +56 -0
  260. package/flowquery-py/tests/graph/test_data.py +73 -0
  261. package/flowquery-py/tests/graph/test_match.py +40 -0
  262. package/flowquery-py/tests/parsing/__init__.py +1 -0
  263. package/flowquery-py/tests/parsing/test_context.py +34 -0
  264. package/flowquery-py/tests/parsing/test_expression.py +49 -0
  265. package/flowquery-py/tests/parsing/test_parser.py +674 -0
  266. package/flowquery-py/tests/test_extensibility.py +611 -0
  267. package/flowquery-py/tests/tokenization/__init__.py +1 -0
  268. package/flowquery-py/tests/tokenization/test_token_mapper.py +60 -0
  269. package/flowquery-py/tests/tokenization/test_tokenizer.py +164 -0
  270. package/flowquery-py/tests/tokenization/test_trie.py +30 -0
  271. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  272. package/misc/apps/RAG/package.json +1 -1
  273. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +76 -8
  274. package/misc/apps/RAG/src/components/index.ts +19 -10
  275. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +70 -140
  276. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
  277. package/package.json +1 -1
  278. package/src/compute/runner.ts +24 -19
  279. package/src/graph/data.ts +112 -0
  280. package/src/graph/database.ts +63 -0
  281. package/src/graph/hops.ts +22 -0
  282. package/src/graph/node.ts +99 -0
  283. package/src/graph/node_data.ts +18 -0
  284. package/src/graph/node_reference.ts +33 -0
  285. package/src/graph/pattern.ts +101 -0
  286. package/src/graph/pattern_expression.ts +37 -0
  287. package/src/graph/patterns.ts +36 -0
  288. package/src/graph/physical_node.ts +23 -0
  289. package/src/graph/physical_relationship.ts +23 -0
  290. package/src/graph/relationship.ts +116 -0
  291. package/src/graph/relationship_data.ts +27 -0
  292. package/src/graph/relationship_match_collector.ts +58 -0
  293. package/src/graph/relationship_reference.ts +24 -0
  294. package/src/parsing/base_parser.ts +20 -14
  295. package/src/parsing/context.ts +14 -14
  296. package/src/parsing/expressions/boolean.ts +21 -0
  297. package/src/parsing/expressions/expression.ts +34 -26
  298. package/src/parsing/expressions/operator.ts +19 -1
  299. package/src/parsing/functions/function_factory.ts +45 -45
  300. package/src/parsing/operations/create_node.ts +39 -0
  301. package/src/parsing/operations/create_relationship.ts +38 -0
  302. package/src/parsing/operations/match.ts +31 -0
  303. package/src/parsing/operations/operation.ts +3 -0
  304. package/src/parsing/operations/return.ts +11 -7
  305. package/src/parsing/operations/where.ts +10 -6
  306. package/src/parsing/parser.ts +346 -8
  307. package/src/parsing/token_to_node.ts +6 -0
  308. package/src/tokenization/keyword.ts +41 -40
  309. package/src/tokenization/token.ts +21 -1
  310. package/src/tokenization/token_type.ts +2 -1
  311. package/src/tokenization/tokenizer.ts +52 -31
  312. package/tests/compute/runner.test.ts +654 -0
  313. package/tests/extensibility.test.ts +97 -93
  314. package/tests/graph/create.test.ts +36 -0
  315. package/tests/graph/data.test.ts +58 -0
  316. package/tests/graph/match.test.ts +29 -0
  317. package/tests/parsing/parser.test.ts +273 -2
  318. package/tests/tokenization/tokenizer.test.ts +90 -0
@@ -0,0 +1,15 @@
1
+ """Reducer element for aggregate functions."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ class ReducerElement:
7
+ """Base class for reducer elements used in aggregate functions."""
8
+
9
+ @property
10
+ def value(self) -> Any:
11
+ raise NotImplementedError("Method not implemented.")
12
+
13
+ @value.setter
14
+ def value(self, val: Any) -> None:
15
+ raise NotImplementedError("Method not implemented.")
@@ -0,0 +1,37 @@
1
+ """Replace function."""
2
+
3
+ import re
4
+ from typing import Any
5
+
6
+ from .function import Function
7
+ from .function_metadata import FunctionDef
8
+
9
+
10
+ @FunctionDef({
11
+ "description": "Replaces occurrences of a pattern in a string",
12
+ "category": "scalar",
13
+ "parameters": [
14
+ {"name": "text", "description": "Source string", "type": "string"},
15
+ {"name": "pattern", "description": "Pattern to find", "type": "string"},
16
+ {"name": "replacement", "description": "Replacement string", "type": "string"}
17
+ ],
18
+ "output": {"description": "String with replacements", "type": "string", "example": "hello world"},
19
+ "examples": ["WITH 'hello there' AS s RETURN replace(s, 'there', 'world')"]
20
+ })
21
+ class Replace(Function):
22
+ """Replace function.
23
+
24
+ Replaces occurrences of a pattern in a string.
25
+ """
26
+
27
+ def __init__(self):
28
+ super().__init__("replace")
29
+ self._expected_parameter_count = 3
30
+
31
+ def value(self) -> Any:
32
+ text = self.get_children()[0].value()
33
+ pattern = self.get_children()[1].value()
34
+ replacement = self.get_children()[2].value()
35
+ if not isinstance(text, str) or not isinstance(pattern, str) or not isinstance(replacement, str):
36
+ raise ValueError("Invalid arguments for replace function")
37
+ return re.sub(re.escape(pattern), replacement, text)
@@ -0,0 +1,32 @@
1
+ """Round function."""
2
+
3
+ from typing import Any
4
+
5
+ from .function import Function
6
+ from .function_metadata import FunctionDef
7
+
8
+
9
+ @FunctionDef({
10
+ "description": "Rounds a number to the nearest integer",
11
+ "category": "scalar",
12
+ "parameters": [
13
+ {"name": "value", "description": "Number to round", "type": "number"}
14
+ ],
15
+ "output": {"description": "Rounded integer", "type": "number", "example": 4},
16
+ "examples": ["WITH 3.7 AS n RETURN round(n)"]
17
+ })
18
+ class Round(Function):
19
+ """Round function.
20
+
21
+ Rounds a number to the nearest integer.
22
+ """
23
+
24
+ def __init__(self):
25
+ super().__init__("round")
26
+ self._expected_parameter_count = 1
27
+
28
+ def value(self) -> Any:
29
+ val = self.get_children()[0].value()
30
+ if not isinstance(val, (int, float)):
31
+ raise ValueError("Invalid argument for round function")
32
+ return round(val)
@@ -0,0 +1,32 @@
1
+ """Size function."""
2
+
3
+ from typing import Any
4
+
5
+ from .function import Function
6
+ from .function_metadata import FunctionDef
7
+
8
+
9
+ @FunctionDef({
10
+ "description": "Returns the length of an array or string",
11
+ "category": "scalar",
12
+ "parameters": [
13
+ {"name": "value", "description": "Array or string to measure", "type": "array"}
14
+ ],
15
+ "output": {"description": "Length of the input", "type": "number", "example": 3},
16
+ "examples": ["WITH [1, 2, 3] AS arr RETURN size(arr)"]
17
+ })
18
+ class Size(Function):
19
+ """Size function.
20
+
21
+ Returns the length of an array or string.
22
+ """
23
+
24
+ def __init__(self):
25
+ super().__init__("size")
26
+ self._expected_parameter_count = 1
27
+
28
+ def value(self) -> Any:
29
+ val = self.get_children()[0].value()
30
+ if not isinstance(val, (list, str)):
31
+ raise ValueError("Invalid argument for size function")
32
+ return len(val)
@@ -0,0 +1,47 @@
1
+ """Split function."""
2
+
3
+ from typing import Any, List
4
+
5
+ from .function import Function
6
+ from ..ast_node import ASTNode
7
+ from ..expressions.string import String
8
+ from .function_metadata import FunctionDef
9
+
10
+
11
+ @FunctionDef({
12
+ "description": "Splits a string into an array by a delimiter",
13
+ "category": "scalar",
14
+ "parameters": [
15
+ {"name": "text", "description": "String to split", "type": "string"},
16
+ {"name": "delimiter", "description": "Delimiter to split by", "type": "string"}
17
+ ],
18
+ "output": {"description": "Array of string parts", "type": "array", "items": {"type": "string"}, "example": ["a", "b", "c"]},
19
+ "examples": ["WITH 'a,b,c' AS s RETURN split(s, ',')"]
20
+ })
21
+ class Split(Function):
22
+ """Split function.
23
+
24
+ Splits a string into an array by a delimiter.
25
+ """
26
+
27
+ def __init__(self):
28
+ super().__init__("split")
29
+ self._expected_parameter_count = 2
30
+
31
+ @property
32
+ def parameters(self) -> List[ASTNode]:
33
+ return self.get_children()
34
+
35
+ @parameters.setter
36
+ def parameters(self, nodes: List[ASTNode]) -> None:
37
+ if len(nodes) == 1:
38
+ nodes.append(String(""))
39
+ for node in nodes:
40
+ self.add_child(node)
41
+
42
+ def value(self) -> Any:
43
+ text = self.get_children()[0].value()
44
+ delimiter = self.get_children()[1].value()
45
+ if not isinstance(text, str) or not isinstance(delimiter, str):
46
+ raise ValueError("Invalid arguments for split function")
47
+ return text.split(delimiter)
@@ -0,0 +1,47 @@
1
+ """Stringify function."""
2
+
3
+ import json
4
+ from typing import Any, List
5
+
6
+ from .function import Function
7
+ from ..ast_node import ASTNode
8
+ from ..expressions.number import Number
9
+ from .function_metadata import FunctionDef
10
+
11
+
12
+ @FunctionDef({
13
+ "description": "Converts a value to its JSON string representation",
14
+ "category": "scalar",
15
+ "parameters": [
16
+ {"name": "value", "description": "Value to stringify", "type": "any"}
17
+ ],
18
+ "output": {"description": "JSON string", "type": "string", "example": '{"a":1}'},
19
+ "examples": ["WITH {a: 1} AS obj RETURN stringify(obj)"]
20
+ })
21
+ class Stringify(Function):
22
+ """Stringify function.
23
+
24
+ Converts a value to its JSON string representation.
25
+ """
26
+
27
+ def __init__(self):
28
+ super().__init__("stringify")
29
+ self._expected_parameter_count = 2
30
+
31
+ @property
32
+ def parameters(self) -> List[ASTNode]:
33
+ return self.get_children()
34
+
35
+ @parameters.setter
36
+ def parameters(self, nodes: List[ASTNode]) -> None:
37
+ if len(nodes) == 1:
38
+ nodes.append(Number("3")) # Default indent of 3
39
+ for node in nodes:
40
+ self.add_child(node)
41
+
42
+ def value(self) -> Any:
43
+ val = self.get_children()[0].value()
44
+ indent = int(self.get_children()[1].value())
45
+ if not isinstance(val, (dict, list)):
46
+ raise ValueError("Invalid argument for stringify function")
47
+ return json.dumps(val, indent=indent, default=str)
@@ -0,0 +1,51 @@
1
+ """Sum aggregate function."""
2
+
3
+ from typing import Any
4
+
5
+ from .aggregate_function import AggregateFunction
6
+ from .reducer_element import ReducerElement
7
+ from .function_metadata import FunctionDef
8
+
9
+
10
+ class SumReducerElement(ReducerElement):
11
+ """Reducer element for Sum aggregate function."""
12
+
13
+ def __init__(self):
14
+ self._value: Any = None
15
+
16
+ @property
17
+ def value(self) -> Any:
18
+ return self._value
19
+
20
+ @value.setter
21
+ def value(self, val: Any) -> None:
22
+ if self._value is not None:
23
+ self._value += val
24
+ else:
25
+ self._value = val
26
+
27
+
28
+ @FunctionDef({
29
+ "description": "Calculates the sum of numeric values across grouped rows",
30
+ "category": "aggregate",
31
+ "parameters": [
32
+ {"name": "value", "description": "Numeric value to sum", "type": "number"}
33
+ ],
34
+ "output": {"description": "Sum of all values", "type": "number", "example": 150},
35
+ "examples": ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN sum(n)"]
36
+ })
37
+ class Sum(AggregateFunction):
38
+ """Sum aggregate function.
39
+
40
+ Calculates the sum of numeric values across grouped rows.
41
+ """
42
+
43
+ def __init__(self):
44
+ super().__init__("sum")
45
+ self._expected_parameter_count = 1
46
+
47
+ def reduce(self, element: SumReducerElement) -> None:
48
+ element.value = self.first_child().value()
49
+
50
+ def element(self) -> SumReducerElement:
51
+ return SumReducerElement()
@@ -0,0 +1,33 @@
1
+ """ToJson function."""
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ from .function import Function
7
+ from .function_metadata import FunctionDef
8
+
9
+
10
+ @FunctionDef({
11
+ "description": "Parses a JSON string into an object",
12
+ "category": "scalar",
13
+ "parameters": [
14
+ {"name": "text", "description": "JSON string to parse", "type": "string"}
15
+ ],
16
+ "output": {"description": "Parsed object or array", "type": "object", "example": {"a": 1}},
17
+ "examples": ["WITH '{\"a\": 1}' AS s RETURN tojson(s)"]
18
+ })
19
+ class ToJson(Function):
20
+ """ToJson function.
21
+
22
+ Parses a JSON string into an object.
23
+ """
24
+
25
+ def __init__(self):
26
+ super().__init__("tojson")
27
+ self._expected_parameter_count = 1
28
+
29
+ def value(self) -> Any:
30
+ text = self.get_children()[0].value()
31
+ if not isinstance(text, str):
32
+ raise ValueError("Invalid arguments for tojson function")
33
+ return json.loads(text)
@@ -0,0 +1,47 @@
1
+ """Type function."""
2
+
3
+ from typing import Any
4
+
5
+ from .function import Function
6
+ from .function_metadata import FunctionDef
7
+
8
+
9
+ @FunctionDef({
10
+ "description": "Returns the type of a value as a string",
11
+ "category": "scalar",
12
+ "parameters": [
13
+ {"name": "value", "description": "Value to check the type of", "type": "any"}
14
+ ],
15
+ "output": {"description": "Type of the input value", "type": "string", "example": "string"},
16
+ "examples": [
17
+ "WITH 'hello' AS val RETURN type(val)",
18
+ "WITH 42 AS val RETURN type(val)",
19
+ "WITH [1, 2, 3] AS val RETURN type(val)"
20
+ ]
21
+ })
22
+ class Type(Function):
23
+ """Type function.
24
+
25
+ Returns the type of a value as a string.
26
+ """
27
+
28
+ def __init__(self):
29
+ super().__init__("type")
30
+ self._expected_parameter_count = 1
31
+
32
+ def value(self) -> Any:
33
+ val = self.get_children()[0].value()
34
+
35
+ if val is None:
36
+ return "null"
37
+ if isinstance(val, list):
38
+ return "array"
39
+ if isinstance(val, dict):
40
+ return "object"
41
+ if isinstance(val, bool):
42
+ return "boolean"
43
+ if isinstance(val, (int, float)):
44
+ return "number"
45
+ if isinstance(val, str):
46
+ return "string"
47
+ return type(val).__name__
@@ -0,0 +1,24 @@
1
+ """Value holder node for FlowQuery AST."""
2
+
3
+ from typing import Any
4
+
5
+ from ..ast_node import ASTNode
6
+
7
+
8
+ class ValueHolder(ASTNode):
9
+ """Holds a value that can be set and retrieved."""
10
+
11
+ def __init__(self):
12
+ super().__init__()
13
+ self._holder: Any = None
14
+
15
+ @property
16
+ def holder(self) -> Any:
17
+ return self._holder
18
+
19
+ @holder.setter
20
+ def holder(self, value: Any) -> None:
21
+ self._holder = value
22
+
23
+ def value(self) -> Any:
24
+ return self._holder
@@ -0,0 +1,15 @@
1
+ """Logic module for FlowQuery parsing."""
2
+
3
+ from .case import Case
4
+ from .when import When
5
+ from .then import Then
6
+ from .else_ import Else
7
+ from .end import End
8
+
9
+ __all__ = [
10
+ "Case",
11
+ "When",
12
+ "Then",
13
+ "Else",
14
+ "End",
15
+ ]
@@ -0,0 +1,29 @@
1
+ """Represents a CASE expression in the AST."""
2
+
3
+ from typing import Any
4
+
5
+ from ..ast_node import ASTNode
6
+ from .when import When
7
+ from .then import Then
8
+
9
+
10
+ class Case(ASTNode):
11
+ """Represents a CASE expression in the AST."""
12
+
13
+ def value(self) -> Any:
14
+ i = 0
15
+ children = self.get_children()
16
+ child = children[i]
17
+ while isinstance(child, When):
18
+ then = children[i + 1]
19
+ if child.value():
20
+ return then.value()
21
+ i += 2
22
+ if i < len(children):
23
+ child = children[i]
24
+ else:
25
+ break
26
+ # Return the else clause if exists
27
+ if i < len(children):
28
+ return children[i].value()
29
+ return None
@@ -0,0 +1,12 @@
1
+ """Represents an ELSE clause in a CASE expression."""
2
+
3
+ from typing import Any
4
+
5
+ from ..ast_node import ASTNode
6
+
7
+
8
+ class Else(ASTNode):
9
+ """Represents an ELSE clause in a CASE expression."""
10
+
11
+ def value(self) -> Any:
12
+ return self.get_children()[0].value()
@@ -0,0 +1,8 @@
1
+ """Represents an END marker in a CASE expression."""
2
+
3
+ from ..ast_node import ASTNode
4
+
5
+
6
+ class End(ASTNode):
7
+ """Represents an END marker in a CASE expression."""
8
+ pass
@@ -0,0 +1,12 @@
1
+ """Represents a THEN clause in a CASE expression."""
2
+
3
+ from typing import Any
4
+
5
+ from ..ast_node import ASTNode
6
+
7
+
8
+ class Then(ASTNode):
9
+ """Represents a THEN clause in a CASE expression."""
10
+
11
+ def value(self) -> Any:
12
+ return self.get_children()[0].value()
@@ -0,0 +1,10 @@
1
+ """Represents a WHEN clause in a CASE expression."""
2
+
3
+ from ..ast_node import ASTNode
4
+
5
+
6
+ class When(ASTNode):
7
+ """Represents a WHEN clause in a CASE expression."""
8
+
9
+ def value(self) -> bool:
10
+ return self.get_children()[0].value()
@@ -0,0 +1,35 @@
1
+ """Operations module for FlowQuery parsing."""
2
+
3
+ from .operation import Operation
4
+ from .projection import Projection
5
+ from .return_op import Return
6
+ from .with_op import With
7
+ from .unwind import Unwind
8
+ from .load import Load
9
+ from .where import Where
10
+ from .limit import Limit
11
+ from .aggregated_return import AggregatedReturn
12
+ from .aggregated_with import AggregatedWith
13
+ from .call import Call
14
+ from .group_by import GroupBy
15
+ from .match import Match
16
+ from .create_node import CreateNode
17
+ from .create_relationship import CreateRelationship
18
+
19
+ __all__ = [
20
+ "Operation",
21
+ "Projection",
22
+ "Return",
23
+ "With",
24
+ "Unwind",
25
+ "Load",
26
+ "Where",
27
+ "Limit",
28
+ "AggregatedReturn",
29
+ "AggregatedWith",
30
+ "Call",
31
+ "GroupBy",
32
+ "Match",
33
+ "CreateNode",
34
+ "CreateRelationship",
35
+ ]
@@ -0,0 +1,24 @@
1
+ """Represents an aggregated RETURN operation."""
2
+
3
+ from typing import Any, Dict, List
4
+
5
+ from .return_op import Return
6
+ from .group_by import GroupBy
7
+ from ..expressions.expression import Expression
8
+
9
+
10
+ class AggregatedReturn(Return):
11
+ """Represents an aggregated RETURN operation that groups and reduces values."""
12
+
13
+ def __init__(self, expressions):
14
+ super().__init__(expressions)
15
+ self._group_by = GroupBy(self.children)
16
+
17
+ async def run(self) -> None:
18
+ await self._group_by.run()
19
+
20
+ @property
21
+ def results(self) -> List[Dict[str, Any]]:
22
+ if self._where is not None:
23
+ self._group_by.where = self._where
24
+ return list(self._group_by.generate_results())
@@ -0,0 +1,22 @@
1
+ """Represents an aggregated WITH operation."""
2
+
3
+ from .return_op import Return
4
+ from .group_by import GroupBy
5
+ from ..expressions.expression import Expression
6
+
7
+
8
+ class AggregatedWith(Return):
9
+ """Represents an aggregated WITH operation that groups and reduces values."""
10
+
11
+ def __init__(self, expressions):
12
+ super().__init__(expressions)
13
+ self._group_by = GroupBy(self.children)
14
+
15
+ async def run(self) -> None:
16
+ await self._group_by.run()
17
+
18
+ async def finish(self) -> None:
19
+ for _ in self._group_by.generate_results():
20
+ if self.next:
21
+ await self.next.run()
22
+ await super().finish()
@@ -0,0 +1,74 @@
1
+ """Represents a CALL operation for invoking async functions."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from ..expressions.expression import Expression
6
+ from ..expressions.expression_map import ExpressionMap
7
+ from ..functions.async_function import AsyncFunction
8
+ from .projection import Projection
9
+
10
+
11
+ DEFAULT_VARIABLE_NAME = "value"
12
+
13
+
14
+ class Call(Projection):
15
+ """Represents a CALL operation for invoking async functions."""
16
+
17
+ def __init__(self):
18
+ super().__init__([])
19
+ self._function: Optional[AsyncFunction] = None
20
+ self._map = ExpressionMap()
21
+ self._results: List[Dict[str, Any]] = []
22
+
23
+ @property
24
+ def function(self) -> Optional[AsyncFunction]:
25
+ return self._function
26
+
27
+ @function.setter
28
+ def function(self, async_function: AsyncFunction) -> None:
29
+ self._function = async_function
30
+
31
+ @property
32
+ def yielded(self) -> List[Expression]:
33
+ return self.children
34
+
35
+ @yielded.setter
36
+ def yielded(self, expressions: List[Expression]) -> None:
37
+ self.children = expressions
38
+ self._map.set_map(expressions)
39
+
40
+ @property
41
+ def has_yield(self) -> bool:
42
+ return len(self.children) > 0
43
+
44
+ async def run(self) -> None:
45
+ if self._function is None:
46
+ raise ValueError("No function set for Call operation.")
47
+
48
+ args = self._function.get_arguments()
49
+ async for item in self._function.generate(*args):
50
+ if not self.is_last:
51
+ if isinstance(item, dict):
52
+ for key, value in item.items():
53
+ expression = self._map.get(key)
54
+ if expression:
55
+ expression.overridden = value
56
+ else:
57
+ expression = self._map.get(DEFAULT_VARIABLE_NAME)
58
+ if expression:
59
+ expression.overridden = item
60
+ if self.next:
61
+ await self.next.run()
62
+ else:
63
+ record: Dict[str, Any] = {}
64
+ if isinstance(item, dict):
65
+ for key, value in item.items():
66
+ if self._map.has(key) or not self.has_yield:
67
+ record[key] = value
68
+ else:
69
+ record[DEFAULT_VARIABLE_NAME] = item
70
+ self._results.append(record)
71
+
72
+ @property
73
+ def results(self) -> List[Dict[str, Any]]:
74
+ return self._results
@@ -0,0 +1,34 @@
1
+ """Represents a CREATE operation for creating virtual nodes."""
2
+
3
+ from typing import Any, Dict, List
4
+
5
+ from .operation import Operation
6
+ from ..ast_node import ASTNode
7
+
8
+
9
+ class CreateNode(Operation):
10
+ """Represents a CREATE operation for creating virtual nodes."""
11
+
12
+ def __init__(self, node, statement: ASTNode):
13
+ super().__init__()
14
+ self._node = node
15
+ self._statement = statement
16
+
17
+ @property
18
+ def node(self):
19
+ return self._node
20
+
21
+ @property
22
+ def statement(self) -> ASTNode:
23
+ return self._statement
24
+
25
+ async def run(self) -> None:
26
+ if self._node is None:
27
+ raise ValueError("Node is null")
28
+ from ...graph.database import Database
29
+ db = Database.get_instance()
30
+ db.add_node(self._node, self._statement)
31
+
32
+ @property
33
+ def results(self) -> List[Dict[str, Any]]:
34
+ return []