flowquery 1.0.46 → 1.0.48

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 (422) hide show
  1. package/dist/flowquery.min.js +1 -1
  2. package/dist/index.d.ts +0 -7
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +6 -4
  5. package/dist/index.js.map +1 -1
  6. package/dist/parsing/data_structures/list_comprehension.d.ts +56 -0
  7. package/dist/parsing/data_structures/list_comprehension.d.ts.map +1 -0
  8. package/dist/parsing/data_structures/list_comprehension.js +102 -0
  9. package/dist/parsing/data_structures/list_comprehension.js.map +1 -0
  10. package/dist/parsing/parser.d.ts +18 -0
  11. package/dist/parsing/parser.d.ts.map +1 -1
  12. package/dist/parsing/parser.js +92 -0
  13. package/dist/parsing/parser.js.map +1 -1
  14. package/package.json +4 -1
  15. package/.editorconfig +0 -21
  16. package/.gitattributes +0 -3
  17. package/.github/workflows/npm-publish.yml +0 -32
  18. package/.github/workflows/python-publish.yml +0 -143
  19. package/.github/workflows/release.yml +0 -107
  20. package/.husky/pre-commit +0 -28
  21. package/.prettierrc +0 -22
  22. package/CODE_OF_CONDUCT.md +0 -10
  23. package/FlowQueryLogoIcon.png +0 -0
  24. package/SECURITY.md +0 -14
  25. package/SUPPORT.md +0 -13
  26. package/docs/flowquery.min.js +0 -1
  27. package/docs/index.html +0 -105
  28. package/flowquery-py/CONTRIBUTING.md +0 -127
  29. package/flowquery-py/README.md +0 -67
  30. package/flowquery-py/misc/data/test.json +0 -10
  31. package/flowquery-py/misc/data/users.json +0 -242
  32. package/flowquery-py/notebooks/TestFlowQuery.ipynb +0 -440
  33. package/flowquery-py/pyproject.toml +0 -121
  34. package/flowquery-py/setup_env.ps1 +0 -92
  35. package/flowquery-py/setup_env.sh +0 -87
  36. package/flowquery-py/src/__init__.py +0 -38
  37. package/flowquery-py/src/__main__.py +0 -10
  38. package/flowquery-py/src/compute/__init__.py +0 -6
  39. package/flowquery-py/src/compute/flowquery.py +0 -68
  40. package/flowquery-py/src/compute/runner.py +0 -64
  41. package/flowquery-py/src/extensibility.py +0 -52
  42. package/flowquery-py/src/graph/__init__.py +0 -31
  43. package/flowquery-py/src/graph/data.py +0 -136
  44. package/flowquery-py/src/graph/database.py +0 -141
  45. package/flowquery-py/src/graph/hops.py +0 -43
  46. package/flowquery-py/src/graph/node.py +0 -143
  47. package/flowquery-py/src/graph/node_data.py +0 -26
  48. package/flowquery-py/src/graph/node_reference.py +0 -50
  49. package/flowquery-py/src/graph/pattern.py +0 -115
  50. package/flowquery-py/src/graph/pattern_expression.py +0 -67
  51. package/flowquery-py/src/graph/patterns.py +0 -42
  52. package/flowquery-py/src/graph/physical_node.py +0 -41
  53. package/flowquery-py/src/graph/physical_relationship.py +0 -36
  54. package/flowquery-py/src/graph/relationship.py +0 -193
  55. package/flowquery-py/src/graph/relationship_data.py +0 -36
  56. package/flowquery-py/src/graph/relationship_match_collector.py +0 -85
  57. package/flowquery-py/src/graph/relationship_reference.py +0 -21
  58. package/flowquery-py/src/io/__init__.py +0 -5
  59. package/flowquery-py/src/io/command_line.py +0 -108
  60. package/flowquery-py/src/parsing/__init__.py +0 -17
  61. package/flowquery-py/src/parsing/alias.py +0 -20
  62. package/flowquery-py/src/parsing/alias_option.py +0 -11
  63. package/flowquery-py/src/parsing/ast_node.py +0 -147
  64. package/flowquery-py/src/parsing/base_parser.py +0 -84
  65. package/flowquery-py/src/parsing/components/__init__.py +0 -19
  66. package/flowquery-py/src/parsing/components/csv.py +0 -8
  67. package/flowquery-py/src/parsing/components/from_.py +0 -12
  68. package/flowquery-py/src/parsing/components/headers.py +0 -12
  69. package/flowquery-py/src/parsing/components/json.py +0 -8
  70. package/flowquery-py/src/parsing/components/null.py +0 -10
  71. package/flowquery-py/src/parsing/components/post.py +0 -8
  72. package/flowquery-py/src/parsing/components/text.py +0 -8
  73. package/flowquery-py/src/parsing/context.py +0 -50
  74. package/flowquery-py/src/parsing/data_structures/__init__.py +0 -15
  75. package/flowquery-py/src/parsing/data_structures/associative_array.py +0 -41
  76. package/flowquery-py/src/parsing/data_structures/json_array.py +0 -30
  77. package/flowquery-py/src/parsing/data_structures/key_value_pair.py +0 -38
  78. package/flowquery-py/src/parsing/data_structures/lookup.py +0 -51
  79. package/flowquery-py/src/parsing/data_structures/range_lookup.py +0 -42
  80. package/flowquery-py/src/parsing/expressions/__init__.py +0 -61
  81. package/flowquery-py/src/parsing/expressions/boolean.py +0 -20
  82. package/flowquery-py/src/parsing/expressions/expression.py +0 -141
  83. package/flowquery-py/src/parsing/expressions/expression_map.py +0 -26
  84. package/flowquery-py/src/parsing/expressions/f_string.py +0 -27
  85. package/flowquery-py/src/parsing/expressions/identifier.py +0 -21
  86. package/flowquery-py/src/parsing/expressions/number.py +0 -32
  87. package/flowquery-py/src/parsing/expressions/operator.py +0 -271
  88. package/flowquery-py/src/parsing/expressions/reference.py +0 -47
  89. package/flowquery-py/src/parsing/expressions/string.py +0 -27
  90. package/flowquery-py/src/parsing/functions/__init__.py +0 -127
  91. package/flowquery-py/src/parsing/functions/aggregate_function.py +0 -60
  92. package/flowquery-py/src/parsing/functions/async_function.py +0 -65
  93. package/flowquery-py/src/parsing/functions/avg.py +0 -55
  94. package/flowquery-py/src/parsing/functions/coalesce.py +0 -43
  95. package/flowquery-py/src/parsing/functions/collect.py +0 -75
  96. package/flowquery-py/src/parsing/functions/count.py +0 -79
  97. package/flowquery-py/src/parsing/functions/date_.py +0 -61
  98. package/flowquery-py/src/parsing/functions/datetime_.py +0 -62
  99. package/flowquery-py/src/parsing/functions/duration.py +0 -159
  100. package/flowquery-py/src/parsing/functions/element_id.py +0 -50
  101. package/flowquery-py/src/parsing/functions/function.py +0 -68
  102. package/flowquery-py/src/parsing/functions/function_factory.py +0 -170
  103. package/flowquery-py/src/parsing/functions/function_metadata.py +0 -148
  104. package/flowquery-py/src/parsing/functions/functions.py +0 -67
  105. package/flowquery-py/src/parsing/functions/head.py +0 -39
  106. package/flowquery-py/src/parsing/functions/id_.py +0 -49
  107. package/flowquery-py/src/parsing/functions/join.py +0 -49
  108. package/flowquery-py/src/parsing/functions/keys.py +0 -34
  109. package/flowquery-py/src/parsing/functions/last.py +0 -39
  110. package/flowquery-py/src/parsing/functions/localdatetime.py +0 -60
  111. package/flowquery-py/src/parsing/functions/localtime.py +0 -57
  112. package/flowquery-py/src/parsing/functions/max_.py +0 -49
  113. package/flowquery-py/src/parsing/functions/min_.py +0 -49
  114. package/flowquery-py/src/parsing/functions/nodes.py +0 -48
  115. package/flowquery-py/src/parsing/functions/predicate_function.py +0 -47
  116. package/flowquery-py/src/parsing/functions/predicate_sum.py +0 -49
  117. package/flowquery-py/src/parsing/functions/properties.py +0 -50
  118. package/flowquery-py/src/parsing/functions/rand.py +0 -28
  119. package/flowquery-py/src/parsing/functions/range_.py +0 -41
  120. package/flowquery-py/src/parsing/functions/reducer_element.py +0 -15
  121. package/flowquery-py/src/parsing/functions/relationships.py +0 -46
  122. package/flowquery-py/src/parsing/functions/replace.py +0 -39
  123. package/flowquery-py/src/parsing/functions/round_.py +0 -34
  124. package/flowquery-py/src/parsing/functions/schema.py +0 -40
  125. package/flowquery-py/src/parsing/functions/size.py +0 -34
  126. package/flowquery-py/src/parsing/functions/split.py +0 -54
  127. package/flowquery-py/src/parsing/functions/string_distance.py +0 -92
  128. package/flowquery-py/src/parsing/functions/stringify.py +0 -49
  129. package/flowquery-py/src/parsing/functions/substring.py +0 -76
  130. package/flowquery-py/src/parsing/functions/sum.py +0 -51
  131. package/flowquery-py/src/parsing/functions/tail.py +0 -37
  132. package/flowquery-py/src/parsing/functions/temporal_utils.py +0 -186
  133. package/flowquery-py/src/parsing/functions/time_.py +0 -57
  134. package/flowquery-py/src/parsing/functions/timestamp.py +0 -37
  135. package/flowquery-py/src/parsing/functions/to_float.py +0 -46
  136. package/flowquery-py/src/parsing/functions/to_integer.py +0 -46
  137. package/flowquery-py/src/parsing/functions/to_json.py +0 -35
  138. package/flowquery-py/src/parsing/functions/to_lower.py +0 -37
  139. package/flowquery-py/src/parsing/functions/to_string.py +0 -41
  140. package/flowquery-py/src/parsing/functions/trim.py +0 -37
  141. package/flowquery-py/src/parsing/functions/type_.py +0 -47
  142. package/flowquery-py/src/parsing/functions/value_holder.py +0 -24
  143. package/flowquery-py/src/parsing/logic/__init__.py +0 -15
  144. package/flowquery-py/src/parsing/logic/case.py +0 -28
  145. package/flowquery-py/src/parsing/logic/else_.py +0 -12
  146. package/flowquery-py/src/parsing/logic/end.py +0 -8
  147. package/flowquery-py/src/parsing/logic/then.py +0 -12
  148. package/flowquery-py/src/parsing/logic/when.py +0 -12
  149. package/flowquery-py/src/parsing/operations/__init__.py +0 -46
  150. package/flowquery-py/src/parsing/operations/aggregated_return.py +0 -25
  151. package/flowquery-py/src/parsing/operations/aggregated_with.py +0 -22
  152. package/flowquery-py/src/parsing/operations/call.py +0 -73
  153. package/flowquery-py/src/parsing/operations/create_node.py +0 -35
  154. package/flowquery-py/src/parsing/operations/create_relationship.py +0 -35
  155. package/flowquery-py/src/parsing/operations/delete_node.py +0 -29
  156. package/flowquery-py/src/parsing/operations/delete_relationship.py +0 -29
  157. package/flowquery-py/src/parsing/operations/group_by.py +0 -148
  158. package/flowquery-py/src/parsing/operations/limit.py +0 -33
  159. package/flowquery-py/src/parsing/operations/load.py +0 -148
  160. package/flowquery-py/src/parsing/operations/match.py +0 -52
  161. package/flowquery-py/src/parsing/operations/operation.py +0 -69
  162. package/flowquery-py/src/parsing/operations/order_by.py +0 -114
  163. package/flowquery-py/src/parsing/operations/projection.py +0 -21
  164. package/flowquery-py/src/parsing/operations/return_op.py +0 -88
  165. package/flowquery-py/src/parsing/operations/union.py +0 -115
  166. package/flowquery-py/src/parsing/operations/union_all.py +0 -17
  167. package/flowquery-py/src/parsing/operations/unwind.py +0 -42
  168. package/flowquery-py/src/parsing/operations/where.py +0 -43
  169. package/flowquery-py/src/parsing/operations/with_op.py +0 -18
  170. package/flowquery-py/src/parsing/parser.py +0 -1384
  171. package/flowquery-py/src/parsing/parser_state.py +0 -26
  172. package/flowquery-py/src/parsing/token_to_node.py +0 -109
  173. package/flowquery-py/src/tokenization/__init__.py +0 -23
  174. package/flowquery-py/src/tokenization/keyword.py +0 -54
  175. package/flowquery-py/src/tokenization/operator.py +0 -29
  176. package/flowquery-py/src/tokenization/string_walker.py +0 -158
  177. package/flowquery-py/src/tokenization/symbol.py +0 -19
  178. package/flowquery-py/src/tokenization/token.py +0 -693
  179. package/flowquery-py/src/tokenization/token_mapper.py +0 -53
  180. package/flowquery-py/src/tokenization/token_type.py +0 -21
  181. package/flowquery-py/src/tokenization/tokenizer.py +0 -214
  182. package/flowquery-py/src/tokenization/trie.py +0 -125
  183. package/flowquery-py/src/utils/__init__.py +0 -6
  184. package/flowquery-py/src/utils/object_utils.py +0 -20
  185. package/flowquery-py/src/utils/string_utils.py +0 -113
  186. package/flowquery-py/tests/__init__.py +0 -1
  187. package/flowquery-py/tests/compute/__init__.py +0 -1
  188. package/flowquery-py/tests/compute/test_runner.py +0 -4902
  189. package/flowquery-py/tests/graph/__init__.py +0 -1
  190. package/flowquery-py/tests/graph/test_create.py +0 -56
  191. package/flowquery-py/tests/graph/test_data.py +0 -73
  192. package/flowquery-py/tests/graph/test_match.py +0 -40
  193. package/flowquery-py/tests/parsing/__init__.py +0 -1
  194. package/flowquery-py/tests/parsing/test_context.py +0 -34
  195. package/flowquery-py/tests/parsing/test_expression.py +0 -248
  196. package/flowquery-py/tests/parsing/test_parser.py +0 -1237
  197. package/flowquery-py/tests/test_extensibility.py +0 -611
  198. package/flowquery-py/tests/tokenization/__init__.py +0 -1
  199. package/flowquery-py/tests/tokenization/test_token_mapper.py +0 -60
  200. package/flowquery-py/tests/tokenization/test_tokenizer.py +0 -198
  201. package/flowquery-py/tests/tokenization/test_trie.py +0 -30
  202. package/flowquery-vscode/.vscode-test.mjs +0 -5
  203. package/flowquery-vscode/.vscodeignore +0 -13
  204. package/flowquery-vscode/LICENSE +0 -21
  205. package/flowquery-vscode/README.md +0 -11
  206. package/flowquery-vscode/demo/FlowQueryVSCodeDemo.gif +0 -0
  207. package/flowquery-vscode/eslint.config.mjs +0 -25
  208. package/flowquery-vscode/extension.js +0 -508
  209. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +0 -1
  210. package/flowquery-vscode/flowquery-worker.js +0 -66
  211. package/flowquery-vscode/images/FlowQueryLogoIcon.png +0 -0
  212. package/flowquery-vscode/jsconfig.json +0 -13
  213. package/flowquery-vscode/libs/page.css +0 -53
  214. package/flowquery-vscode/libs/table.css +0 -13
  215. package/flowquery-vscode/libs/tabs.css +0 -66
  216. package/flowquery-vscode/package-lock.json +0 -2917
  217. package/flowquery-vscode/package.json +0 -51
  218. package/flowquery-vscode/test/extension.test.js +0 -196
  219. package/flowquery-vscode/test/worker.test.js +0 -25
  220. package/flowquery-vscode/vsc-extension-quickstart.md +0 -42
  221. package/jest.config.js +0 -14
  222. package/misc/apps/RAG/README.md +0 -29
  223. package/misc/apps/RAG/data/chats.json +0 -302
  224. package/misc/apps/RAG/data/emails.json +0 -182
  225. package/misc/apps/RAG/data/events.json +0 -226
  226. package/misc/apps/RAG/data/files.json +0 -172
  227. package/misc/apps/RAG/data/users.json +0 -158
  228. package/misc/apps/RAG/jest.config.js +0 -21
  229. package/misc/apps/RAG/package.json +0 -48
  230. package/misc/apps/RAG/public/index.html +0 -18
  231. package/misc/apps/RAG/src/App.css +0 -42
  232. package/misc/apps/RAG/src/App.tsx +0 -50
  233. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +0 -172
  234. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +0 -380
  235. package/misc/apps/RAG/src/components/ApiKeySettings.tsx +0 -245
  236. package/misc/apps/RAG/src/components/ChatContainer.css +0 -67
  237. package/misc/apps/RAG/src/components/ChatContainer.tsx +0 -242
  238. package/misc/apps/RAG/src/components/ChatInput.css +0 -23
  239. package/misc/apps/RAG/src/components/ChatInput.tsx +0 -76
  240. package/misc/apps/RAG/src/components/ChatMessage.css +0 -160
  241. package/misc/apps/RAG/src/components/ChatMessage.tsx +0 -286
  242. package/misc/apps/RAG/src/components/FlowQueryAgent.ts +0 -708
  243. package/misc/apps/RAG/src/components/FlowQueryRunner.css +0 -113
  244. package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +0 -371
  245. package/misc/apps/RAG/src/components/index.ts +0 -28
  246. package/misc/apps/RAG/src/graph/index.ts +0 -19
  247. package/misc/apps/RAG/src/graph/initializeGraph.ts +0 -254
  248. package/misc/apps/RAG/src/index.tsx +0 -29
  249. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +0 -327
  250. package/misc/apps/RAG/src/prompts/index.ts +0 -10
  251. package/misc/apps/RAG/src/tests/graph.test.ts +0 -35
  252. package/misc/apps/RAG/src/utils/FlowQueryExecutor.ts +0 -130
  253. package/misc/apps/RAG/src/utils/FlowQueryExtractor.ts +0 -208
  254. package/misc/apps/RAG/src/utils/Llm.ts +0 -248
  255. package/misc/apps/RAG/src/utils/index.ts +0 -12
  256. package/misc/apps/RAG/tsconfig.json +0 -22
  257. package/misc/apps/RAG/webpack.config.js +0 -43
  258. package/misc/apps/README.md +0 -1
  259. package/misc/queries/analyze_catfacts.cql +0 -75
  260. package/misc/queries/azure_openai_completions.cql +0 -13
  261. package/misc/queries/azure_openai_models.cql +0 -9
  262. package/misc/queries/mock_pipeline.cql +0 -84
  263. package/misc/queries/openai_completions.cql +0 -15
  264. package/misc/queries/openai_models.cql +0 -13
  265. package/misc/queries/test.cql +0 -6
  266. package/misc/queries/tool_inference.cql +0 -24
  267. package/misc/queries/wisdom.cql +0 -6
  268. package/misc/queries/wisdom_letter_histogram.cql +0 -8
  269. package/src/compute/flowquery.ts +0 -46
  270. package/src/compute/runner.ts +0 -66
  271. package/src/extensibility.ts +0 -45
  272. package/src/graph/data.ts +0 -130
  273. package/src/graph/database.ts +0 -143
  274. package/src/graph/hops.ts +0 -22
  275. package/src/graph/node.ts +0 -122
  276. package/src/graph/node_data.ts +0 -18
  277. package/src/graph/node_reference.ts +0 -38
  278. package/src/graph/pattern.ts +0 -110
  279. package/src/graph/pattern_expression.ts +0 -48
  280. package/src/graph/patterns.ts +0 -36
  281. package/src/graph/physical_node.ts +0 -23
  282. package/src/graph/physical_relationship.ts +0 -23
  283. package/src/graph/relationship.ts +0 -167
  284. package/src/graph/relationship_data.ts +0 -31
  285. package/src/graph/relationship_match_collector.ts +0 -64
  286. package/src/graph/relationship_reference.ts +0 -25
  287. package/src/index.browser.ts +0 -46
  288. package/src/index.node.ts +0 -55
  289. package/src/index.ts +0 -12
  290. package/src/io/command_line.ts +0 -74
  291. package/src/parsing/alias.ts +0 -23
  292. package/src/parsing/alias_option.ts +0 -5
  293. package/src/parsing/ast_node.ts +0 -153
  294. package/src/parsing/base_parser.ts +0 -98
  295. package/src/parsing/components/csv.ts +0 -9
  296. package/src/parsing/components/from.ts +0 -12
  297. package/src/parsing/components/headers.ts +0 -12
  298. package/src/parsing/components/json.ts +0 -9
  299. package/src/parsing/components/null.ts +0 -9
  300. package/src/parsing/components/post.ts +0 -9
  301. package/src/parsing/components/text.ts +0 -9
  302. package/src/parsing/context.ts +0 -54
  303. package/src/parsing/data_structures/associative_array.ts +0 -43
  304. package/src/parsing/data_structures/json_array.ts +0 -31
  305. package/src/parsing/data_structures/key_value_pair.ts +0 -37
  306. package/src/parsing/data_structures/lookup.ts +0 -44
  307. package/src/parsing/data_structures/range_lookup.ts +0 -36
  308. package/src/parsing/expressions/boolean.ts +0 -21
  309. package/src/parsing/expressions/expression.ts +0 -150
  310. package/src/parsing/expressions/expression_map.ts +0 -22
  311. package/src/parsing/expressions/f_string.ts +0 -26
  312. package/src/parsing/expressions/identifier.ts +0 -22
  313. package/src/parsing/expressions/number.ts +0 -40
  314. package/src/parsing/expressions/operator.ts +0 -354
  315. package/src/parsing/expressions/reference.ts +0 -45
  316. package/src/parsing/expressions/string.ts +0 -34
  317. package/src/parsing/functions/aggregate_function.ts +0 -58
  318. package/src/parsing/functions/async_function.ts +0 -64
  319. package/src/parsing/functions/avg.ts +0 -47
  320. package/src/parsing/functions/coalesce.ts +0 -49
  321. package/src/parsing/functions/collect.ts +0 -54
  322. package/src/parsing/functions/count.ts +0 -54
  323. package/src/parsing/functions/date.ts +0 -63
  324. package/src/parsing/functions/datetime.ts +0 -63
  325. package/src/parsing/functions/duration.ts +0 -143
  326. package/src/parsing/functions/element_id.ts +0 -51
  327. package/src/parsing/functions/function.ts +0 -60
  328. package/src/parsing/functions/function_factory.ts +0 -195
  329. package/src/parsing/functions/function_metadata.ts +0 -217
  330. package/src/parsing/functions/functions.ts +0 -70
  331. package/src/parsing/functions/head.ts +0 -42
  332. package/src/parsing/functions/id.ts +0 -51
  333. package/src/parsing/functions/join.ts +0 -40
  334. package/src/parsing/functions/keys.ts +0 -29
  335. package/src/parsing/functions/last.ts +0 -42
  336. package/src/parsing/functions/localdatetime.ts +0 -63
  337. package/src/parsing/functions/localtime.ts +0 -58
  338. package/src/parsing/functions/max.ts +0 -37
  339. package/src/parsing/functions/min.ts +0 -37
  340. package/src/parsing/functions/nodes.ts +0 -54
  341. package/src/parsing/functions/predicate_function.ts +0 -48
  342. package/src/parsing/functions/predicate_sum.ts +0 -47
  343. package/src/parsing/functions/properties.ts +0 -56
  344. package/src/parsing/functions/rand.ts +0 -21
  345. package/src/parsing/functions/range.ts +0 -37
  346. package/src/parsing/functions/reducer_element.ts +0 -10
  347. package/src/parsing/functions/relationships.ts +0 -52
  348. package/src/parsing/functions/replace.ts +0 -38
  349. package/src/parsing/functions/round.ts +0 -28
  350. package/src/parsing/functions/schema.ts +0 -39
  351. package/src/parsing/functions/size.ts +0 -28
  352. package/src/parsing/functions/split.ts +0 -45
  353. package/src/parsing/functions/string_distance.ts +0 -83
  354. package/src/parsing/functions/stringify.ts +0 -37
  355. package/src/parsing/functions/substring.ts +0 -68
  356. package/src/parsing/functions/sum.ts +0 -41
  357. package/src/parsing/functions/tail.ts +0 -39
  358. package/src/parsing/functions/temporal_utils.ts +0 -180
  359. package/src/parsing/functions/time.ts +0 -58
  360. package/src/parsing/functions/timestamp.ts +0 -37
  361. package/src/parsing/functions/to_float.ts +0 -50
  362. package/src/parsing/functions/to_integer.ts +0 -50
  363. package/src/parsing/functions/to_json.ts +0 -28
  364. package/src/parsing/functions/to_lower.ts +0 -28
  365. package/src/parsing/functions/to_string.ts +0 -32
  366. package/src/parsing/functions/trim.ts +0 -28
  367. package/src/parsing/functions/type.ts +0 -39
  368. package/src/parsing/functions/value_holder.ts +0 -13
  369. package/src/parsing/logic/case.ts +0 -26
  370. package/src/parsing/logic/else.ts +0 -12
  371. package/src/parsing/logic/end.ts +0 -9
  372. package/src/parsing/logic/then.ts +0 -12
  373. package/src/parsing/logic/when.ts +0 -12
  374. package/src/parsing/operations/aggregated_return.ts +0 -22
  375. package/src/parsing/operations/aggregated_with.ts +0 -18
  376. package/src/parsing/operations/call.ts +0 -69
  377. package/src/parsing/operations/create_node.ts +0 -39
  378. package/src/parsing/operations/create_relationship.ts +0 -38
  379. package/src/parsing/operations/delete_node.ts +0 -33
  380. package/src/parsing/operations/delete_relationship.ts +0 -32
  381. package/src/parsing/operations/group_by.ts +0 -137
  382. package/src/parsing/operations/limit.ts +0 -31
  383. package/src/parsing/operations/load.ts +0 -146
  384. package/src/parsing/operations/match.ts +0 -54
  385. package/src/parsing/operations/operation.ts +0 -69
  386. package/src/parsing/operations/order_by.ts +0 -126
  387. package/src/parsing/operations/projection.ts +0 -18
  388. package/src/parsing/operations/return.ts +0 -76
  389. package/src/parsing/operations/union.ts +0 -114
  390. package/src/parsing/operations/union_all.ts +0 -16
  391. package/src/parsing/operations/unwind.ts +0 -36
  392. package/src/parsing/operations/where.ts +0 -42
  393. package/src/parsing/operations/with.ts +0 -20
  394. package/src/parsing/parser.ts +0 -1641
  395. package/src/parsing/parser_state.ts +0 -25
  396. package/src/parsing/token_to_node.ts +0 -114
  397. package/src/tokenization/keyword.ts +0 -50
  398. package/src/tokenization/operator.ts +0 -25
  399. package/src/tokenization/string_walker.ts +0 -197
  400. package/src/tokenization/symbol.ts +0 -15
  401. package/src/tokenization/token.ts +0 -764
  402. package/src/tokenization/token_mapper.ts +0 -53
  403. package/src/tokenization/token_type.ts +0 -16
  404. package/src/tokenization/tokenizer.ts +0 -250
  405. package/src/tokenization/trie.ts +0 -117
  406. package/src/utils/object_utils.ts +0 -17
  407. package/src/utils/string_utils.ts +0 -114
  408. package/tests/compute/runner.test.ts +0 -4559
  409. package/tests/extensibility.test.ts +0 -643
  410. package/tests/graph/create.test.ts +0 -36
  411. package/tests/graph/data.test.ts +0 -58
  412. package/tests/graph/match.test.ts +0 -29
  413. package/tests/parsing/context.test.ts +0 -27
  414. package/tests/parsing/expression.test.ts +0 -303
  415. package/tests/parsing/parser.test.ts +0 -1327
  416. package/tests/tokenization/token_mapper.test.ts +0 -47
  417. package/tests/tokenization/tokenizer.test.ts +0 -191
  418. package/tests/tokenization/trie.test.ts +0 -20
  419. package/tsconfig.json +0 -19
  420. package/typedoc.json +0 -16
  421. package/vscode-settings.json.recommended +0 -16
  422. package/webpack.config.js +0 -26
@@ -1,1237 +0,0 @@
1
- """Tests for the FlowQuery parser."""
2
-
3
- import pytest
4
- from typing import AsyncIterator
5
- from flowquery.parsing.parser import Parser
6
- from flowquery.parsing.functions.async_function import AsyncFunction
7
- from flowquery.parsing.functions.function_metadata import FunctionDef
8
- from flowquery.parsing.operations.match import Match
9
- from flowquery.parsing.operations.create_relationship import CreateRelationship
10
- from flowquery.graph.node import Node
11
- from flowquery.graph.node_reference import NodeReference
12
- from flowquery.graph.relationship import Relationship
13
- from flowquery.graph.relationship_reference import RelationshipReference
14
-
15
-
16
- # Test async function for CALL operation parsing test
17
- # Named with underscore prefix to prevent pytest from trying to collect it as a test class
18
- @FunctionDef({
19
- "description": "Asynchronous function for testing CALL operation",
20
- "category": "async",
21
- "parameters": [],
22
- "output": {"description": "Yields test values", "type": "any"},
23
- })
24
- class _Test(AsyncFunction):
25
- """Async function for CALL operation testing, registered as 'test'."""
26
-
27
- def __init__(self):
28
- super().__init__("test") # Register as 'test'
29
- self._expected_parameter_count = 0
30
-
31
- async def generate(self) -> AsyncIterator:
32
- yield 1
33
- yield 2
34
- yield 3
35
-
36
-
37
- class TestParser:
38
- """Test cases for the Parser class."""
39
-
40
- def test_parser_basic(self):
41
- """Test basic parser functionality."""
42
- parser = Parser()
43
- ast = parser.parse("RETURN 1, 2, 3")
44
- expected = (
45
- "ASTNode\n"
46
- "- Return\n"
47
- "-- Expression\n"
48
- "--- Number (1)\n"
49
- "-- Expression\n"
50
- "--- Number (2)\n"
51
- "-- Expression\n"
52
- "--- Number (3)"
53
- )
54
- assert ast.print() == expected
55
-
56
- def test_parser_with_function(self):
57
- """Test parser with function."""
58
- parser = Parser()
59
- ast = parser.parse("RETURN rand()")
60
- expected = (
61
- "ASTNode\n"
62
- "- Return\n"
63
- "-- Expression\n"
64
- "--- Function (rand)"
65
- )
66
- assert ast.print() == expected
67
-
68
- def test_parser_with_associative_array(self):
69
- """Test parser with associative array."""
70
- parser = Parser()
71
- ast = parser.parse("RETURN {a: 1, b: 2}")
72
- expected = (
73
- "ASTNode\n"
74
- "- Return\n"
75
- "-- Expression\n"
76
- "--- AssociativeArray\n"
77
- "---- KeyValuePair\n"
78
- "----- String (a)\n"
79
- "----- Expression\n"
80
- "------ Number (1)\n"
81
- "---- KeyValuePair\n"
82
- "----- String (b)\n"
83
- "----- Expression\n"
84
- "------ Number (2)"
85
- )
86
- assert ast.print() == expected
87
-
88
- def test_parser_with_json_array(self):
89
- """Test parser with JSON array."""
90
- parser = Parser()
91
- ast = parser.parse("RETURN [1, 2]")
92
- expected = (
93
- "ASTNode\n"
94
- "- Return\n"
95
- "-- Expression\n"
96
- "--- JSONArray\n"
97
- "---- Expression\n"
98
- "----- Number (1)\n"
99
- "---- Expression\n"
100
- "----- Number (2)"
101
- )
102
- assert ast.print() == expected
103
-
104
- def test_parser_with_nested_associative_array(self):
105
- """Test parser with nested associative array."""
106
- parser = Parser()
107
- ast = parser.parse("RETURN {a:{}}")
108
- expected = (
109
- "ASTNode\n"
110
- "- Return\n"
111
- "-- Expression\n"
112
- "--- AssociativeArray\n"
113
- "---- KeyValuePair\n"
114
- "----- String (a)\n"
115
- "----- Expression\n"
116
- "------ AssociativeArray"
117
- )
118
- assert ast.print() == expected
119
-
120
- def test_parser_with_multiple_operations(self):
121
- """Test parser with multiple operations."""
122
- parser = Parser()
123
- ast = parser.parse("WITH 1 AS n RETURN n")
124
- expected = (
125
- "ASTNode\n"
126
- "- With\n"
127
- "-- Expression (n)\n"
128
- "--- Number (1)\n"
129
- "- Return\n"
130
- "-- Expression (n)\n"
131
- "--- Reference (n)"
132
- )
133
- assert ast.print() == expected
134
-
135
- def test_parser_with_comments(self):
136
- """Test parser with comments."""
137
- parser = Parser()
138
- ast = parser.parse("WITH 1 AS n /* comment */ RETURN n")
139
- expected = (
140
- "ASTNode\n"
141
- "- With\n"
142
- "-- Expression (n)\n"
143
- "--- Number (1)\n"
144
- "- Return\n"
145
- "-- Expression (n)\n"
146
- "--- Reference (n)"
147
- )
148
- assert ast.print() == expected
149
-
150
- def test_parser_with_unwind(self):
151
- """Test parser with UNWIND."""
152
- parser = Parser()
153
- ast = parser.parse("UNWIND [1, 2, 3] AS n RETURN n")
154
- expected = (
155
- "ASTNode\n"
156
- "- Unwind\n"
157
- "-- Expression (n)\n"
158
- "--- JSONArray\n"
159
- "---- Expression\n"
160
- "----- Number (1)\n"
161
- "---- Expression\n"
162
- "----- Number (2)\n"
163
- "---- Expression\n"
164
- "----- Number (3)\n"
165
- "- Return\n"
166
- "-- Expression (n)\n"
167
- "--- Reference (n)"
168
- )
169
- assert ast.print() == expected
170
-
171
- def test_unwind_with_invalid_expression(self):
172
- """Test Unwind with invalid expression."""
173
- parser = Parser()
174
- with pytest.raises(Exception, match="Expected array, function, reference, or lookup"):
175
- parser.parse("UNWIND 1 AS n RETURN n")
176
-
177
- def test_unwind_with_invalid_alias(self):
178
- """Test Unwind with invalid alias."""
179
- parser = Parser()
180
- with pytest.raises(Exception, match="Expected identifier"):
181
- parser.parse("UNWIND [1, 2, 3] AS 1 RETURN n")
182
-
183
- def test_unwind_with_missing_alias(self):
184
- """Test Unwind with missing alias."""
185
- parser = Parser()
186
- with pytest.raises(Exception, match="Expected alias"):
187
- parser.parse("UNWIND [1, 2, 3] RETURN n")
188
-
189
- def test_statement_with_where_clause(self):
190
- """Test statement with where clause."""
191
- parser = Parser()
192
- ast = parser.parse("with 1 as n where n > 0 return n")
193
- expected = (
194
- "ASTNode\n"
195
- "- With\n"
196
- "-- Expression (n)\n"
197
- "--- Number (1)\n"
198
- "- Where\n"
199
- "-- Expression\n"
200
- "--- GreaterThan\n"
201
- "---- Reference (n)\n"
202
- "---- Number (0)\n"
203
- "- Return\n"
204
- "-- Expression (n)\n"
205
- "--- Reference (n)"
206
- )
207
- assert ast.print() == expected
208
-
209
- def test_lookup(self):
210
- """Test lookup expression."""
211
- parser = Parser()
212
- ast = parser.parse("return {a: 1}.a")
213
- expected = (
214
- "ASTNode\n"
215
- "- Return\n"
216
- "-- Expression\n"
217
- "--- Lookup\n"
218
- "---- Identifier (a)\n"
219
- "---- AssociativeArray\n"
220
- "----- KeyValuePair\n"
221
- "------ String (a)\n"
222
- "------ Expression\n"
223
- "------- Number (1)"
224
- )
225
- assert ast.print() == expected
226
-
227
- def test_lookup_as_part_of_expression(self):
228
- """Test lookup as part of expression."""
229
- parser = Parser()
230
- ast = parser.parse("return {a: 1}.a + 1")
231
- expected = (
232
- "ASTNode\n"
233
- "- Return\n"
234
- "-- Expression\n"
235
- "--- Add\n"
236
- "---- Lookup\n"
237
- "----- Identifier (a)\n"
238
- "----- AssociativeArray\n"
239
- "------ KeyValuePair\n"
240
- "------- String (a)\n"
241
- "------- Expression\n"
242
- "-------- Number (1)\n"
243
- "---- Number (1)"
244
- )
245
- assert ast.print() == expected
246
-
247
- def test_lookup_with_nested_associative_array(self):
248
- """Test lookup with nested associative array."""
249
- parser = Parser()
250
- ast = parser.parse("return {a: {b: 1}}.a.b")
251
- expected = (
252
- "ASTNode\n"
253
- "- Return\n"
254
- "-- Expression\n"
255
- "--- Lookup\n"
256
- "---- Identifier (b)\n"
257
- "---- Lookup\n"
258
- "----- Identifier (a)\n"
259
- "----- AssociativeArray\n"
260
- "------ KeyValuePair\n"
261
- "------- String (a)\n"
262
- "------- Expression\n"
263
- "-------- AssociativeArray\n"
264
- "--------- KeyValuePair\n"
265
- "---------- String (b)\n"
266
- "---------- Expression\n"
267
- "----------- Number (1)"
268
- )
269
- assert ast.print() == expected
270
- _return = ast.first_child()
271
- assert _return.first_child().value() == 1
272
-
273
- def test_lookup_with_json_array(self):
274
- """Test lookup with JSON array."""
275
- parser = Parser()
276
- ast = parser.parse("return [1, 2][1]")
277
- expected = (
278
- "ASTNode\n"
279
- "- Return\n"
280
- "-- Expression\n"
281
- "--- Lookup\n"
282
- "---- Expression\n"
283
- "----- Number (1)\n"
284
- "---- JSONArray\n"
285
- "----- Expression\n"
286
- "------ Number (1)\n"
287
- "----- Expression\n"
288
- "------ Number (2)"
289
- )
290
- assert ast.print() == expected
291
- _return = ast.first_child()
292
- assert _return.first_child().value() == 2
293
-
294
- def test_lookup_with_reserved_keyword_property_names(self):
295
- """Test lookup with reserved keyword property names like end, null, case."""
296
- parser = Parser()
297
- ast = parser.parse("with {end: 1, null: 2, case: 3} as x return x.end, x.null, x.case")
298
- expected = (
299
- "ASTNode\n"
300
- "- With\n"
301
- "-- Expression (x)\n"
302
- "--- AssociativeArray\n"
303
- "---- KeyValuePair\n"
304
- "----- String (end)\n"
305
- "----- Expression\n"
306
- "------ Number (1)\n"
307
- "---- KeyValuePair\n"
308
- "----- String (null)\n"
309
- "----- Expression\n"
310
- "------ Number (2)\n"
311
- "---- KeyValuePair\n"
312
- "----- String (case)\n"
313
- "----- Expression\n"
314
- "------ Number (3)\n"
315
- "- Return\n"
316
- "-- Expression\n"
317
- "--- Lookup\n"
318
- "---- Identifier (end)\n"
319
- "---- Reference (x)\n"
320
- "-- Expression\n"
321
- "--- Lookup\n"
322
- "---- Identifier (null)\n"
323
- "---- Reference (x)\n"
324
- "-- Expression\n"
325
- "--- Lookup\n"
326
- "---- Identifier (case)\n"
327
- "---- Reference (x)"
328
- )
329
- assert ast.print() == expected
330
-
331
- def test_lookup_with_from_keyword_as_property_name(self):
332
- """Test lookup with from and to keywords as property names."""
333
- parser = Parser()
334
- ast = parser.parse("with {from: 1, to: 2} as x return x.from, x.to")
335
- expected = (
336
- "ASTNode\n"
337
- "- With\n"
338
- "-- Expression (x)\n"
339
- "--- AssociativeArray\n"
340
- "---- KeyValuePair\n"
341
- "----- String (from)\n"
342
- "----- Expression\n"
343
- "------ Number (1)\n"
344
- "---- KeyValuePair\n"
345
- "----- String (to)\n"
346
- "----- Expression\n"
347
- "------ Number (2)\n"
348
- "- Return\n"
349
- "-- Expression\n"
350
- "--- Lookup\n"
351
- "---- Identifier (from)\n"
352
- "---- Reference (x)\n"
353
- "-- Expression\n"
354
- "--- Lookup\n"
355
- "---- Identifier (to)\n"
356
- "---- Reference (x)"
357
- )
358
- assert ast.print() == expected
359
-
360
- def test_camel_case_alias_starting_with_keyword(self):
361
- """Test that camelCase identifiers starting with a keyword (e.g. fromUser) are tokenized correctly."""
362
- parser = Parser()
363
- ast = parser.parse("LOAD JSON FROM '/data.json' AS x RETURN x.from AS fromUser")
364
- output = ast.print()
365
- assert "Lookup" in output
366
- assert "Identifier (from)" in output
367
-
368
- def test_from_keyword_property_in_create_virtual_subquery(self):
369
- """Test that email.from parses correctly inside a CREATE VIRTUAL subquery."""
370
- parser = Parser()
371
- # Should not raise - email.from should be parsed correctly even with FROM being a keyword
372
- parser.parse(
373
- "CREATE VIRTUAL (:Email) AS { LOAD JSON FROM '/data/emails.json' AS email "
374
- "RETURN email.id AS id, email.from AS fromUser }"
375
- )
376
-
377
- def test_load_with_post(self):
378
- """Test load with post."""
379
- parser = Parser()
380
- ast = parser.parse(
381
- 'load json from "https://jsonplaceholder.typicode.com/posts" post {userId: 1} as data return data'
382
- )
383
- expected = (
384
- "ASTNode\n"
385
- "- Load\n"
386
- "-- JSON\n"
387
- "-- From\n"
388
- "--- Expression\n"
389
- "---- String (https://jsonplaceholder.typicode.com/posts)\n"
390
- "-- Post\n"
391
- "--- Expression\n"
392
- "---- AssociativeArray\n"
393
- "----- KeyValuePair\n"
394
- "------ String (userId)\n"
395
- "------ Expression\n"
396
- "------- Number (1)\n"
397
- "-- Alias (data)\n"
398
- "- Return\n"
399
- "-- Expression (data)\n"
400
- "--- Reference (data)"
401
- )
402
- assert ast.print() == expected
403
-
404
- def test_nested_aggregate_functions(self):
405
- """Test nested aggregate functions."""
406
- parser = Parser()
407
- with pytest.raises(Exception, match="Aggregate functions cannot be nested"):
408
- parser.parse("RETURN sum(sum(1))")
409
-
410
- def test_with_and_return_with_renamed_variable(self):
411
- """Test with and return with renamed variable."""
412
- parser = Parser()
413
- ast = parser.parse("WITH 1 AS n RETURN n AS m")
414
- expected = (
415
- "ASTNode\n"
416
- "- With\n"
417
- "-- Expression (n)\n"
418
- "--- Number (1)\n"
419
- "- Return\n"
420
- "-- Expression (m)\n"
421
- "--- Reference (n)"
422
- )
423
- assert ast.print() == expected
424
-
425
- def test_with_and_return_with_variable_lookup(self):
426
- """Test with and return with variable lookup."""
427
- parser = Parser()
428
- ast = parser.parse("WITH {a: n} AS obj RETURN obj.a")
429
- expected = (
430
- "ASTNode\n"
431
- "- With\n"
432
- "-- Expression (obj)\n"
433
- "--- AssociativeArray\n"
434
- "---- KeyValuePair\n"
435
- "----- String (a)\n"
436
- "----- Expression\n"
437
- "------ Reference (n)\n"
438
- "- Return\n"
439
- "-- Expression\n"
440
- "--- Lookup\n"
441
- "---- Identifier (a)\n"
442
- "---- Reference (obj)"
443
- )
444
- assert ast.print() == expected
445
-
446
- def test_unwind(self):
447
- """Test unwind."""
448
- parser = Parser()
449
- ast = parser.parse("WITH [1, 2, 4] as n unwind n as i return i")
450
- expected = (
451
- "ASTNode\n"
452
- "- With\n"
453
- "-- Expression (n)\n"
454
- "--- JSONArray\n"
455
- "---- Expression\n"
456
- "----- Number (1)\n"
457
- "---- Expression\n"
458
- "----- Number (2)\n"
459
- "---- Expression\n"
460
- "----- Number (4)\n"
461
- "- Unwind\n"
462
- "-- Expression (i)\n"
463
- "--- Reference (n)\n"
464
- "- Return\n"
465
- "-- Expression (i)\n"
466
- "--- Reference (i)"
467
- )
468
- assert ast.print() == expected
469
-
470
- def test_predicate_function(self):
471
- """Test predicate function."""
472
- parser = Parser()
473
- ast = parser.parse("RETURN sum(n in [1, 2, 3] | n where n > 1)")
474
- expected = (
475
- "ASTNode\n"
476
- "- Return\n"
477
- "-- Expression\n"
478
- "--- PredicateFunction (sum)\n"
479
- "---- Reference (n)\n"
480
- "---- Expression\n"
481
- "----- JSONArray\n"
482
- "------ Expression\n"
483
- "------- Number (1)\n"
484
- "------ Expression\n"
485
- "------- Number (2)\n"
486
- "------ Expression\n"
487
- "------- Number (3)\n"
488
- "---- Expression\n"
489
- "----- Reference (n)\n"
490
- "---- Where\n"
491
- "----- Expression\n"
492
- "------ GreaterThan\n"
493
- "------- Reference (n)\n"
494
- "------- Number (1)"
495
- )
496
- assert ast.print() == expected
497
-
498
- def test_case_statement(self):
499
- """Test case statement."""
500
- parser = Parser()
501
- ast = parser.parse("RETURN CASE WHEN 1 THEN 2 ELSE 3 END")
502
- expected = (
503
- "ASTNode\n"
504
- "- Return\n"
505
- "-- Expression\n"
506
- "--- Case\n"
507
- "---- When\n"
508
- "----- Expression\n"
509
- "------ Number (1)\n"
510
- "---- Then\n"
511
- "----- Expression\n"
512
- "------ Number (2)\n"
513
- "---- Else\n"
514
- "----- Expression\n"
515
- "------ Number (3)"
516
- )
517
- assert ast.print() == expected
518
-
519
- def test_functions_with_wrong_number_of_arguments(self):
520
- """Test functions with wrong number of arguments."""
521
- parser = Parser()
522
- with pytest.raises(Exception, match="Function range expected 2 parameters, but got 1"):
523
- parser.parse("RETURN range(1)")
524
- with pytest.raises(Exception, match="Function range expected 2 parameters, but got 3"):
525
- parser.parse("RETURN range(1, 2, 3)")
526
- with pytest.raises(Exception, match="Function avg expected 1 parameters, but got 3"):
527
- parser.parse("RETURN avg(1, 2, 3)")
528
- with pytest.raises(Exception, match="Function size expected 1 parameters, but got 2"):
529
- parser.parse("RETURN size(1, 2)")
530
- with pytest.raises(Exception, match="Function round expected 1 parameters, but got 2"):
531
- parser.parse("RETURN round(1, 2)")
532
-
533
- def test_non_well_formed_statements(self):
534
- """Test non-well formed statements."""
535
- parser = Parser()
536
- with pytest.raises(Exception, match="Only one RETURN statement is allowed"):
537
- parser.parse("return 1 return 1")
538
- # Note: Python implementation throws "Only one RETURN" for this case too
539
- with pytest.raises(Exception, match="Only one RETURN statement is allowed"):
540
- parser.parse("return 1 with 1 as n")
541
-
542
- def test_associative_array_with_backtick_string(self):
543
- """Test associative array with backtick string."""
544
- parser = Parser()
545
- ast = parser.parse("RETURN {`key`: `value`}")
546
- expected = (
547
- "ASTNode\n"
548
- "- Return\n"
549
- "-- Expression\n"
550
- "--- AssociativeArray\n"
551
- "---- KeyValuePair\n"
552
- "----- String (key)\n"
553
- "----- Expression\n"
554
- "------ Reference (value)"
555
- )
556
- assert ast.print() == expected
557
-
558
- def test_limit(self):
559
- """Test limit."""
560
- parser = Parser()
561
- ast = parser.parse("unwind range(1, 10) as n limit 5 return n")
562
- expected = (
563
- "ASTNode\n"
564
- "- Unwind\n"
565
- "-- Expression (n)\n"
566
- "--- Function (range)\n"
567
- "---- Expression\n"
568
- "----- Number (1)\n"
569
- "---- Expression\n"
570
- "----- Number (10)\n"
571
- "- Limit\n"
572
- "- Return\n"
573
- "-- Expression (n)\n"
574
- "--- Reference (n)"
575
- )
576
- assert ast.print() == expected
577
-
578
- def test_return_negative_number(self):
579
- """Test return -2."""
580
- parser = Parser()
581
- ast = parser.parse("return -2")
582
- expected = (
583
- "ASTNode\n"
584
- "- Return\n"
585
- "-- Expression\n"
586
- "--- Number (-2)"
587
- )
588
- assert ast.print() == expected
589
-
590
- def test_call_operation(self):
591
- """Test call operation."""
592
- parser = Parser()
593
- ast = parser.parse("CALL test() YIELD result RETURN result")
594
- expected = (
595
- "ASTNode\n"
596
- "- Call\n"
597
- "-- Expression (result)\n"
598
- "--- Reference (result)\n"
599
- "- Return\n"
600
- "-- Expression (result)\n"
601
- "--- Reference (result)"
602
- )
603
- assert ast.print() == expected
604
-
605
- def test_f_string(self):
606
- """Test f-string."""
607
- parser = Parser()
608
- ast = parser.parse("with 1 as value RETURN f'Value is: {value}.'")
609
- expected = (
610
- "ASTNode\n"
611
- "- With\n"
612
- "-- Expression (value)\n"
613
- "--- Number (1)\n"
614
- "- Return\n"
615
- "-- Expression\n"
616
- "--- FString\n"
617
- "---- String (Value is: )\n"
618
- "---- Expression\n"
619
- "----- Reference (value)\n"
620
- "---- String (.)"
621
- )
622
- assert ast.print() == expected
623
-
624
- def test_not_equal_operator(self):
625
- """Test not equal operator."""
626
- parser = Parser()
627
- ast = parser.parse("RETURN 1 <> 2")
628
- expected = (
629
- "ASTNode\n"
630
- "- Return\n"
631
- "-- Expression\n"
632
- "--- NotEquals\n"
633
- "---- Number (1)\n"
634
- "---- Number (2)"
635
- )
636
- assert ast.print() == expected
637
-
638
- def test_equal_operator(self):
639
- """Test equal operator."""
640
- parser = Parser()
641
- ast = parser.parse("RETURN 1 = 2")
642
- expected = (
643
- "ASTNode\n"
644
- "- Return\n"
645
- "-- Expression\n"
646
- "--- Equals\n"
647
- "---- Number (1)\n"
648
- "---- Number (2)"
649
- )
650
- assert ast.print() == expected
651
-
652
- def test_not_operator(self):
653
- """Test not operator."""
654
- parser = Parser()
655
- ast = parser.parse("RETURN NOT true")
656
- expected = (
657
- "ASTNode\n"
658
- "- Return\n"
659
- "-- Expression\n"
660
- "--- Not\n"
661
- "---- Expression\n"
662
- "----- Boolean"
663
- )
664
- assert ast.print() == expected
665
-
666
- def test_create_node_operation(self):
667
- """Test create node operation."""
668
- parser = Parser()
669
- ast = parser.parse(
670
- """
671
- CREATE VIRTUAL (:Person) AS {
672
- unwind range(1, 3) AS id
673
- return id, f'Person {id}' AS name
674
- }
675
- """
676
- )
677
- expected = (
678
- "ASTNode\n"
679
- "- CreateNode"
680
- )
681
- assert ast.print() == expected
682
-
683
- def test_match_operation(self):
684
- """Test match operation."""
685
- parser = Parser()
686
- ast = parser.parse("MATCH (n:Person) RETURN n")
687
- expected = (
688
- "ASTNode\n"
689
- "- Match\n"
690
- "- Return\n"
691
- "-- Expression (n)\n"
692
- "--- Reference (n)"
693
- )
694
- assert ast.print() == expected
695
-
696
- def test_create_relationship_operation(self):
697
- """Test create relationship operation."""
698
- parser = Parser()
699
- ast = parser.parse(
700
- """
701
- CREATE VIRTUAL (:Person)-[:KNOWS]-(:Person) AS {
702
- unwind [
703
- {from_id: 1, to_id: 2, since: '2020-01-01'},
704
- {from_id: 2, to_id: 3, since: '2021-01-01'}
705
- ] AS pair
706
- return pair.from_id AS left_id, pair.to_id AS right_id
707
- }
708
- """
709
- )
710
- expected = (
711
- "ASTNode\n"
712
- "- CreateRelationship"
713
- )
714
- assert ast.print() == expected
715
-
716
- def test_match_with_graph_pattern_including_relationships(self):
717
- """Test match with graph pattern including relationships."""
718
- parser = Parser()
719
- ast = parser.parse("MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a, b")
720
- expected = (
721
- "ASTNode\n"
722
- "- Match\n"
723
- "- Return\n"
724
- "-- Expression (a)\n"
725
- "--- Reference (a)\n"
726
- "-- Expression (b)\n"
727
- "--- Reference (b)"
728
- )
729
- assert ast.print() == expected
730
-
731
- def test_parse_relationship_with_hops(self):
732
- """Test parse relationship with hops."""
733
- parser = Parser()
734
- ast = parser.parse("MATCH (a:Test)-[:KNOWS*1..3]->(b:Test) RETURN a, b")
735
- expected = (
736
- "ASTNode\n"
737
- "- Match\n"
738
- "- Return\n"
739
- "-- Expression (a)\n"
740
- "--- Reference (a)\n"
741
- "-- Expression (b)\n"
742
- "--- Reference (b)"
743
- )
744
- assert ast.print() == expected
745
-
746
- def test_parse_statement_with_graph_pattern_in_where_clause(self):
747
- """Test parse statement with graph pattern in where clause."""
748
- parser = Parser()
749
- ast = parser.parse("MATCH (a:Person) WHERE (a)-[:KNOWS]->(:Person) RETURN a")
750
- expected = (
751
- "ASTNode\n"
752
- "- Match\n"
753
- "- Where\n"
754
- "-- Expression\n"
755
- "--- PatternExpression\n"
756
- "---- NodeReference\n"
757
- "---- Relationship\n"
758
- "---- Node\n"
759
- "- Return\n"
760
- "-- Expression (a)\n"
761
- "--- Reference (a)"
762
- )
763
- assert ast.print() == expected
764
-
765
- def test_check_pattern_expression_without_noderef(self):
766
- """Test check pattern expression without NodeReference."""
767
- parser = Parser()
768
- with pytest.raises(Exception, match="PatternExpression must contain at least one NodeReference"):
769
- parser.parse("MATCH (a:Person) WHERE (:Person)-[:KNOWS]->(:Person) RETURN a")
770
-
771
- def test_node_with_properties(self):
772
- """Test node with properties."""
773
- parser = Parser()
774
- ast = parser.parse("MATCH (a:Person{value: 'hello'}) return a")
775
- expected = (
776
- "ASTNode\n"
777
- "- Match\n"
778
- "- Return\n"
779
- "-- Expression (a)\n"
780
- "--- Reference (a)"
781
- )
782
- assert ast.print() == expected
783
- match_op = ast.first_child()
784
- assert isinstance(match_op, Match)
785
- node = match_op.patterns[0].chain[0]
786
- assert isinstance(node, Node)
787
- assert node.properties.get("value") is not None
788
- assert node.properties["value"].value() == "hello"
789
-
790
- def test_where_in_create_virtual_sub_query(self):
791
- """Test WHERE in CREATE VIRTUAL sub-query."""
792
- parser = Parser()
793
- ast = parser.parse(
794
- "CREATE VIRTUAL (:Email)-[:HAS_ATTACHMENT]-(:File) AS {"
795
- " LOAD JSON FROM '/data/emails.json' AS email"
796
- " WHERE email.hasAttachments = true"
797
- " UNWIND email.attachments AS fileId"
798
- " RETURN email.id AS left_id, fileId AS right_id"
799
- " }"
800
- )
801
- create = ast.first_child()
802
- assert isinstance(create, CreateRelationship)
803
- assert create.relationship is not None
804
- assert create.relationship.type == "HAS_ATTACHMENT"
805
- assert create.statement is not None
806
-
807
- def test_relationship_with_properties(self):
808
- """Test relationship with properties."""
809
- parser = Parser()
810
- ast = parser.parse("MATCH (:Person)-[r:LIKES{since: 2022}]->(:Food) return a")
811
- expected = (
812
- "ASTNode\n"
813
- "- Match\n"
814
- "- Return\n"
815
- "-- Expression (a)\n"
816
- "--- Reference (a)"
817
- )
818
- assert ast.print() == expected
819
- match_op = ast.first_child()
820
- assert isinstance(match_op, Match)
821
- relationship = match_op.patterns[0].chain[1]
822
- assert isinstance(relationship, Relationship)
823
- assert relationship.properties.get("since") is not None
824
- assert relationship.properties["since"].value() == 2022
825
-
826
- def test_node_reference_with_label_creates_node_reference(self):
827
- """Test that reusing a variable with a label creates a NodeReference instead of a new node."""
828
- parser = Parser()
829
- ast = parser.parse("MATCH (n:Person)-[:KNOWS]->(n:Person) RETURN n")
830
- match_op = ast.first_child()
831
- assert isinstance(match_op, Match)
832
- first_node = match_op.patterns[0].chain[0]
833
- second_node = match_op.patterns[0].chain[2]
834
- assert isinstance(first_node, Node)
835
- assert first_node.identifier == "n"
836
- assert first_node.label == "Person"
837
- assert isinstance(second_node, NodeReference)
838
- assert second_node.reference.identifier == "n"
839
- assert second_node.label == "Person"
840
-
841
- def test_relationship_reference_with_type_creates_relationship_reference(self):
842
- """Test that reusing a relationship variable with a type creates a RelationshipReference."""
843
- parser = Parser()
844
- ast = parser.parse("MATCH (a:Person)-[r:KNOWS]->(b:Person)-[r:KNOWS]->(c:Person) RETURN a, b, c")
845
- match_op = ast.first_child()
846
- assert isinstance(match_op, Match)
847
- first_rel = match_op.patterns[0].chain[1]
848
- second_rel = match_op.patterns[0].chain[3]
849
- assert isinstance(first_rel, Relationship)
850
- assert first_rel.identifier == "r"
851
- assert first_rel.type == "KNOWS"
852
- assert isinstance(second_rel, RelationshipReference)
853
- assert second_rel.type == "KNOWS"
854
-
855
- def test_case_statement_with_keywords_as_identifiers(self):
856
- """Test that CASE/WHEN/THEN/ELSE/END are not treated as identifiers."""
857
- parser = Parser()
858
- ast = parser.parse("RETURN CASE WHEN 1 THEN 2 ELSE 3 END")
859
- assert "Case" in ast.print()
860
- assert "When" in ast.print()
861
- assert "Then" in ast.print()
862
- assert "Else" in ast.print()
863
-
864
- def test_where_with_in_list_check(self):
865
- """Test WHERE with IN list check."""
866
- parser = Parser()
867
- ast = parser.parse("with 1 as n where n IN [1, 2, 3] return n")
868
- expected = (
869
- "ASTNode\n"
870
- "- With\n"
871
- "-- Expression (n)\n"
872
- "--- Number (1)\n"
873
- "- Where\n"
874
- "-- Expression\n"
875
- "--- In\n"
876
- "---- Reference (n)\n"
877
- "---- JSONArray\n"
878
- "----- Expression\n"
879
- "------ Number (1)\n"
880
- "----- Expression\n"
881
- "------ Number (2)\n"
882
- "----- Expression\n"
883
- "------ Number (3)\n"
884
- "- Return\n"
885
- "-- Expression (n)\n"
886
- "--- Reference (n)"
887
- )
888
- assert ast.print() == expected
889
-
890
- def test_where_with_not_in_list_check(self):
891
- """Test WHERE with NOT IN list check."""
892
- parser = Parser()
893
- ast = parser.parse("with 4 as n where n NOT IN [1, 2, 3] return n")
894
- expected = (
895
- "ASTNode\n"
896
- "- With\n"
897
- "-- Expression (n)\n"
898
- "--- Number (4)\n"
899
- "- Where\n"
900
- "-- Expression\n"
901
- "--- NotIn\n"
902
- "---- Reference (n)\n"
903
- "---- JSONArray\n"
904
- "----- Expression\n"
905
- "------ Number (1)\n"
906
- "----- Expression\n"
907
- "------ Number (2)\n"
908
- "----- Expression\n"
909
- "------ Number (3)\n"
910
- "- Return\n"
911
- "-- Expression (n)\n"
912
- "--- Reference (n)"
913
- )
914
- assert ast.print() == expected
915
-
916
- def test_where_with_contains(self):
917
- """Test WHERE with CONTAINS."""
918
- parser = Parser()
919
- ast = parser.parse("with 'hello' as s where s CONTAINS 'ell' return s")
920
- expected = (
921
- "ASTNode\n"
922
- "- With\n"
923
- "-- Expression (s)\n"
924
- "--- String (hello)\n"
925
- "- Where\n"
926
- "-- Expression\n"
927
- "--- Contains\n"
928
- "---- Reference (s)\n"
929
- "---- String (ell)\n"
930
- "- Return\n"
931
- "-- Expression (s)\n"
932
- "--- Reference (s)"
933
- )
934
- assert ast.print() == expected
935
-
936
- def test_where_with_not_contains(self):
937
- """Test WHERE with NOT CONTAINS."""
938
- parser = Parser()
939
- ast = parser.parse("with 'hello' as s where s NOT CONTAINS 'xyz' return s")
940
- expected = (
941
- "ASTNode\n"
942
- "- With\n"
943
- "-- Expression (s)\n"
944
- "--- String (hello)\n"
945
- "- Where\n"
946
- "-- Expression\n"
947
- "--- NotContains\n"
948
- "---- Reference (s)\n"
949
- "---- String (xyz)\n"
950
- "- Return\n"
951
- "-- Expression (s)\n"
952
- "--- Reference (s)"
953
- )
954
- assert ast.print() == expected
955
-
956
- def test_where_with_starts_with(self):
957
- """Test WHERE with STARTS WITH."""
958
- parser = Parser()
959
- ast = parser.parse("with 'hello' as s where s STARTS WITH 'hel' return s")
960
- expected = (
961
- "ASTNode\n"
962
- "- With\n"
963
- "-- Expression (s)\n"
964
- "--- String (hello)\n"
965
- "- Where\n"
966
- "-- Expression\n"
967
- "--- StartsWith\n"
968
- "---- Reference (s)\n"
969
- "---- String (hel)\n"
970
- "- Return\n"
971
- "-- Expression (s)\n"
972
- "--- Reference (s)"
973
- )
974
- assert ast.print() == expected
975
-
976
- def test_where_with_not_starts_with(self):
977
- """Test WHERE with NOT STARTS WITH."""
978
- parser = Parser()
979
- ast = parser.parse("with 'hello' as s where s NOT STARTS WITH 'xyz' return s")
980
- expected = (
981
- "ASTNode\n"
982
- "- With\n"
983
- "-- Expression (s)\n"
984
- "--- String (hello)\n"
985
- "- Where\n"
986
- "-- Expression\n"
987
- "--- NotStartsWith\n"
988
- "---- Reference (s)\n"
989
- "---- String (xyz)\n"
990
- "- Return\n"
991
- "-- Expression (s)\n"
992
- "--- Reference (s)"
993
- )
994
- assert ast.print() == expected
995
-
996
- def test_where_with_ends_with(self):
997
- """Test WHERE with ENDS WITH."""
998
- parser = Parser()
999
- ast = parser.parse("with 'hello' as s where s ENDS WITH 'llo' return s")
1000
- expected = (
1001
- "ASTNode\n"
1002
- "- With\n"
1003
- "-- Expression (s)\n"
1004
- "--- String (hello)\n"
1005
- "- Where\n"
1006
- "-- Expression\n"
1007
- "--- EndsWith\n"
1008
- "---- Reference (s)\n"
1009
- "---- String (llo)\n"
1010
- "- Return\n"
1011
- "-- Expression (s)\n"
1012
- "--- Reference (s)"
1013
- )
1014
- assert ast.print() == expected
1015
-
1016
- def test_where_with_not_ends_with(self):
1017
- """Test WHERE with NOT ENDS WITH."""
1018
- parser = Parser()
1019
- ast = parser.parse("with 'hello' as s where s NOT ENDS WITH 'xyz' return s")
1020
- expected = (
1021
- "ASTNode\n"
1022
- "- With\n"
1023
- "-- Expression (s)\n"
1024
- "--- String (hello)\n"
1025
- "- Where\n"
1026
- "-- Expression\n"
1027
- "--- NotEndsWith\n"
1028
- "---- Reference (s)\n"
1029
- "---- String (xyz)\n"
1030
- "- Return\n"
1031
- "-- Expression (s)\n"
1032
- "--- Reference (s)"
1033
- )
1034
- assert ast.print() == expected
1035
-
1036
- def test_parenthesized_expression_with_addition(self):
1037
- """Test that (variable + number) is parsed as a parenthesized expression, not a node."""
1038
- parser = Parser()
1039
- ast = parser.parse("WITH 1 AS n RETURN (n + 2)")
1040
- expected = (
1041
- "ASTNode\n"
1042
- "- With\n"
1043
- "-- Expression (n)\n"
1044
- "--- Number (1)\n"
1045
- "- Return\n"
1046
- "-- Expression\n"
1047
- "--- Expression\n"
1048
- "---- Add\n"
1049
- "----- Reference (n)\n"
1050
- "----- Number (2)"
1051
- )
1052
- assert ast.print() == expected
1053
-
1054
- def test_parenthesized_expression_with_property_access(self):
1055
- """Test that (obj.property) is parsed as a parenthesized expression, not a node."""
1056
- parser = Parser()
1057
- ast = parser.parse("WITH {a: 1} AS obj RETURN (obj.a)")
1058
- expected = (
1059
- "ASTNode\n"
1060
- "- With\n"
1061
- "-- Expression (obj)\n"
1062
- "--- AssociativeArray\n"
1063
- "---- KeyValuePair\n"
1064
- "----- String (a)\n"
1065
- "----- Expression\n"
1066
- "------ Number (1)\n"
1067
- "- Return\n"
1068
- "-- Expression\n"
1069
- "--- Expression\n"
1070
- "---- Lookup\n"
1071
- "----- Identifier (a)\n"
1072
- "----- Reference (obj)"
1073
- )
1074
- assert ast.print() == expected
1075
-
1076
- def test_parenthesized_expression_with_multiplication(self):
1077
- """Test that (variable * number) is parsed as a parenthesized expression, not a node."""
1078
- parser = Parser()
1079
- ast = parser.parse("WITH 5 AS x RETURN (x * 3)")
1080
- expected = (
1081
- "ASTNode\n"
1082
- "- With\n"
1083
- "-- Expression (x)\n"
1084
- "--- Number (5)\n"
1085
- "- Return\n"
1086
- "-- Expression\n"
1087
- "--- Expression\n"
1088
- "---- Multiply\n"
1089
- "----- Reference (x)\n"
1090
- "----- Number (3)"
1091
- )
1092
- assert ast.print() == expected
1093
-
1094
- def test_optional_match_operation(self):
1095
- """Test optional match operation."""
1096
- parser = Parser()
1097
- ast = parser.parse("OPTIONAL MATCH (n:Person) RETURN n")
1098
- expected = (
1099
- "ASTNode\n"
1100
- "- OptionalMatch\n"
1101
- "- Return\n"
1102
- "-- Expression (n)\n"
1103
- "--- Reference (n)"
1104
- )
1105
- assert ast.print() == expected
1106
- match = ast.first_child()
1107
- assert isinstance(match, Match)
1108
- assert match.optional is True
1109
- assert match.patterns[0].start_node is not None
1110
- assert match.patterns[0].start_node.label == "Person"
1111
- assert match.patterns[0].start_node.identifier == "n"
1112
-
1113
- def test_optional_match_with_relationships(self):
1114
- """Test optional match with graph pattern including relationships."""
1115
- parser = Parser()
1116
- ast = parser.parse("OPTIONAL MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a, b")
1117
- expected = (
1118
- "ASTNode\n"
1119
- "- OptionalMatch\n"
1120
- "- Return\n"
1121
- "-- Expression (a)\n"
1122
- "--- Reference (a)\n"
1123
- "-- Expression (b)\n"
1124
- "--- Reference (b)"
1125
- )
1126
- assert ast.print() == expected
1127
- match = ast.first_child()
1128
- assert isinstance(match, Match)
1129
- assert match.optional is True
1130
- assert len(match.patterns[0].chain) == 3
1131
- source = match.patterns[0].chain[0]
1132
- relationship = match.patterns[0].chain[1]
1133
- target = match.patterns[0].chain[2]
1134
- assert source.identifier == "a"
1135
- assert source.label == "Person"
1136
- assert relationship.type == "KNOWS"
1137
- assert target.identifier == "b"
1138
- assert target.label == "Person"
1139
-
1140
- def test_match_followed_by_optional_match(self):
1141
- """Test match followed by optional match."""
1142
- parser = Parser()
1143
- ast = parser.parse("MATCH (a:Person) OPTIONAL MATCH (a)-[:KNOWS]->(b:Person) RETURN a, b")
1144
- expected = (
1145
- "ASTNode\n"
1146
- "- Match\n"
1147
- "- OptionalMatch\n"
1148
- "- Return\n"
1149
- "-- Expression (a)\n"
1150
- "--- Reference (a)\n"
1151
- "-- Expression (b)\n"
1152
- "--- Reference (b)"
1153
- )
1154
- assert ast.print() == expected
1155
- match = ast.first_child()
1156
- assert isinstance(match, Match)
1157
- assert match.optional is False
1158
- optional_match = match.next
1159
- assert isinstance(optional_match, Match)
1160
- assert optional_match.optional is True
1161
-
1162
- def test_regular_match_is_not_optional(self):
1163
- """Test that regular match is not optional."""
1164
- parser = Parser()
1165
- ast = parser.parse("MATCH (n:Person) RETURN n")
1166
- match = ast.first_child()
1167
- assert isinstance(match, Match)
1168
- assert match.optional is False
1169
-
1170
- def test_optional_without_match_throws_error(self):
1171
- """Test that OPTIONAL without MATCH throws error."""
1172
- parser = Parser()
1173
- with pytest.raises(Exception, match="Expected MATCH after OPTIONAL"):
1174
- parser.parse("OPTIONAL RETURN 1")
1175
-
1176
- # ORDER BY expression tests
1177
-
1178
- def test_order_by_simple_identifier(self):
1179
- """Test ORDER BY with a simple identifier parses correctly."""
1180
- parser = Parser()
1181
- ast = parser.parse("unwind [1, 2] as x return x order by x")
1182
- assert ast is not None
1183
-
1184
- def test_order_by_property_access(self):
1185
- """Test ORDER BY with property access parses correctly."""
1186
- parser = Parser()
1187
- ast = parser.parse(
1188
- "unwind [{name: 'Bob'}, {name: 'Alice'}] as person "
1189
- "return person.name as name order by person.name asc"
1190
- )
1191
- assert ast is not None
1192
-
1193
- def test_order_by_function_call(self):
1194
- """Test ORDER BY with function call parses correctly."""
1195
- parser = Parser()
1196
- ast = parser.parse(
1197
- "unwind ['HELLO', 'WORLD'] as word "
1198
- "return word order by toLower(word) asc"
1199
- )
1200
- assert ast is not None
1201
-
1202
- def test_order_by_nested_function_calls(self):
1203
- """Test ORDER BY with nested function calls parses correctly."""
1204
- parser = Parser()
1205
- ast = parser.parse(
1206
- "unwind ['Alice', 'Bob'] as name "
1207
- "return name order by string_distance(toLower(name), toLower('alice')) asc"
1208
- )
1209
- assert ast is not None
1210
-
1211
- def test_order_by_arithmetic_expression(self):
1212
- """Test ORDER BY with arithmetic expression parses correctly."""
1213
- parser = Parser()
1214
- ast = parser.parse(
1215
- "unwind [{a: 3, b: 1}, {a: 1, b: 5}] as item "
1216
- "return item.a as a, item.b as b order by item.a + item.b desc"
1217
- )
1218
- assert ast is not None
1219
-
1220
- def test_order_by_multiple_expression_fields(self):
1221
- """Test ORDER BY with multiple expression fields parses correctly."""
1222
- parser = Parser()
1223
- ast = parser.parse(
1224
- "unwind [{a: 1, b: 2}] as item "
1225
- "return item.a as a, item.b as b "
1226
- "order by toLower(item.a) asc, item.b desc"
1227
- )
1228
- assert ast is not None
1229
-
1230
- def test_order_by_expression_with_limit(self):
1231
- """Test ORDER BY with expression and LIMIT parses correctly."""
1232
- parser = Parser()
1233
- ast = parser.parse(
1234
- "unwind ['c', 'a', 'b'] as x "
1235
- "return x order by toLower(x) asc limit 2"
1236
- )
1237
- assert ast is not None