flowquery 1.0.46 → 1.0.47

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 (413) hide show
  1. package/dist/index.d.ts +0 -7
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -4
  4. package/dist/index.js.map +1 -1
  5. package/package.json +4 -1
  6. package/.editorconfig +0 -21
  7. package/.gitattributes +0 -3
  8. package/.github/workflows/npm-publish.yml +0 -32
  9. package/.github/workflows/python-publish.yml +0 -143
  10. package/.github/workflows/release.yml +0 -107
  11. package/.husky/pre-commit +0 -28
  12. package/.prettierrc +0 -22
  13. package/CODE_OF_CONDUCT.md +0 -10
  14. package/FlowQueryLogoIcon.png +0 -0
  15. package/SECURITY.md +0 -14
  16. package/SUPPORT.md +0 -13
  17. package/docs/flowquery.min.js +0 -1
  18. package/docs/index.html +0 -105
  19. package/flowquery-py/CONTRIBUTING.md +0 -127
  20. package/flowquery-py/README.md +0 -67
  21. package/flowquery-py/misc/data/test.json +0 -10
  22. package/flowquery-py/misc/data/users.json +0 -242
  23. package/flowquery-py/notebooks/TestFlowQuery.ipynb +0 -440
  24. package/flowquery-py/pyproject.toml +0 -121
  25. package/flowquery-py/setup_env.ps1 +0 -92
  26. package/flowquery-py/setup_env.sh +0 -87
  27. package/flowquery-py/src/__init__.py +0 -38
  28. package/flowquery-py/src/__main__.py +0 -10
  29. package/flowquery-py/src/compute/__init__.py +0 -6
  30. package/flowquery-py/src/compute/flowquery.py +0 -68
  31. package/flowquery-py/src/compute/runner.py +0 -64
  32. package/flowquery-py/src/extensibility.py +0 -52
  33. package/flowquery-py/src/graph/__init__.py +0 -31
  34. package/flowquery-py/src/graph/data.py +0 -136
  35. package/flowquery-py/src/graph/database.py +0 -141
  36. package/flowquery-py/src/graph/hops.py +0 -43
  37. package/flowquery-py/src/graph/node.py +0 -143
  38. package/flowquery-py/src/graph/node_data.py +0 -26
  39. package/flowquery-py/src/graph/node_reference.py +0 -50
  40. package/flowquery-py/src/graph/pattern.py +0 -115
  41. package/flowquery-py/src/graph/pattern_expression.py +0 -67
  42. package/flowquery-py/src/graph/patterns.py +0 -42
  43. package/flowquery-py/src/graph/physical_node.py +0 -41
  44. package/flowquery-py/src/graph/physical_relationship.py +0 -36
  45. package/flowquery-py/src/graph/relationship.py +0 -193
  46. package/flowquery-py/src/graph/relationship_data.py +0 -36
  47. package/flowquery-py/src/graph/relationship_match_collector.py +0 -85
  48. package/flowquery-py/src/graph/relationship_reference.py +0 -21
  49. package/flowquery-py/src/io/__init__.py +0 -5
  50. package/flowquery-py/src/io/command_line.py +0 -108
  51. package/flowquery-py/src/parsing/__init__.py +0 -17
  52. package/flowquery-py/src/parsing/alias.py +0 -20
  53. package/flowquery-py/src/parsing/alias_option.py +0 -11
  54. package/flowquery-py/src/parsing/ast_node.py +0 -147
  55. package/flowquery-py/src/parsing/base_parser.py +0 -84
  56. package/flowquery-py/src/parsing/components/__init__.py +0 -19
  57. package/flowquery-py/src/parsing/components/csv.py +0 -8
  58. package/flowquery-py/src/parsing/components/from_.py +0 -12
  59. package/flowquery-py/src/parsing/components/headers.py +0 -12
  60. package/flowquery-py/src/parsing/components/json.py +0 -8
  61. package/flowquery-py/src/parsing/components/null.py +0 -10
  62. package/flowquery-py/src/parsing/components/post.py +0 -8
  63. package/flowquery-py/src/parsing/components/text.py +0 -8
  64. package/flowquery-py/src/parsing/context.py +0 -50
  65. package/flowquery-py/src/parsing/data_structures/__init__.py +0 -15
  66. package/flowquery-py/src/parsing/data_structures/associative_array.py +0 -41
  67. package/flowquery-py/src/parsing/data_structures/json_array.py +0 -30
  68. package/flowquery-py/src/parsing/data_structures/key_value_pair.py +0 -38
  69. package/flowquery-py/src/parsing/data_structures/lookup.py +0 -51
  70. package/flowquery-py/src/parsing/data_structures/range_lookup.py +0 -42
  71. package/flowquery-py/src/parsing/expressions/__init__.py +0 -61
  72. package/flowquery-py/src/parsing/expressions/boolean.py +0 -20
  73. package/flowquery-py/src/parsing/expressions/expression.py +0 -141
  74. package/flowquery-py/src/parsing/expressions/expression_map.py +0 -26
  75. package/flowquery-py/src/parsing/expressions/f_string.py +0 -27
  76. package/flowquery-py/src/parsing/expressions/identifier.py +0 -21
  77. package/flowquery-py/src/parsing/expressions/number.py +0 -32
  78. package/flowquery-py/src/parsing/expressions/operator.py +0 -271
  79. package/flowquery-py/src/parsing/expressions/reference.py +0 -47
  80. package/flowquery-py/src/parsing/expressions/string.py +0 -27
  81. package/flowquery-py/src/parsing/functions/__init__.py +0 -127
  82. package/flowquery-py/src/parsing/functions/aggregate_function.py +0 -60
  83. package/flowquery-py/src/parsing/functions/async_function.py +0 -65
  84. package/flowquery-py/src/parsing/functions/avg.py +0 -55
  85. package/flowquery-py/src/parsing/functions/coalesce.py +0 -43
  86. package/flowquery-py/src/parsing/functions/collect.py +0 -75
  87. package/flowquery-py/src/parsing/functions/count.py +0 -79
  88. package/flowquery-py/src/parsing/functions/date_.py +0 -61
  89. package/flowquery-py/src/parsing/functions/datetime_.py +0 -62
  90. package/flowquery-py/src/parsing/functions/duration.py +0 -159
  91. package/flowquery-py/src/parsing/functions/element_id.py +0 -50
  92. package/flowquery-py/src/parsing/functions/function.py +0 -68
  93. package/flowquery-py/src/parsing/functions/function_factory.py +0 -170
  94. package/flowquery-py/src/parsing/functions/function_metadata.py +0 -148
  95. package/flowquery-py/src/parsing/functions/functions.py +0 -67
  96. package/flowquery-py/src/parsing/functions/head.py +0 -39
  97. package/flowquery-py/src/parsing/functions/id_.py +0 -49
  98. package/flowquery-py/src/parsing/functions/join.py +0 -49
  99. package/flowquery-py/src/parsing/functions/keys.py +0 -34
  100. package/flowquery-py/src/parsing/functions/last.py +0 -39
  101. package/flowquery-py/src/parsing/functions/localdatetime.py +0 -60
  102. package/flowquery-py/src/parsing/functions/localtime.py +0 -57
  103. package/flowquery-py/src/parsing/functions/max_.py +0 -49
  104. package/flowquery-py/src/parsing/functions/min_.py +0 -49
  105. package/flowquery-py/src/parsing/functions/nodes.py +0 -48
  106. package/flowquery-py/src/parsing/functions/predicate_function.py +0 -47
  107. package/flowquery-py/src/parsing/functions/predicate_sum.py +0 -49
  108. package/flowquery-py/src/parsing/functions/properties.py +0 -50
  109. package/flowquery-py/src/parsing/functions/rand.py +0 -28
  110. package/flowquery-py/src/parsing/functions/range_.py +0 -41
  111. package/flowquery-py/src/parsing/functions/reducer_element.py +0 -15
  112. package/flowquery-py/src/parsing/functions/relationships.py +0 -46
  113. package/flowquery-py/src/parsing/functions/replace.py +0 -39
  114. package/flowquery-py/src/parsing/functions/round_.py +0 -34
  115. package/flowquery-py/src/parsing/functions/schema.py +0 -40
  116. package/flowquery-py/src/parsing/functions/size.py +0 -34
  117. package/flowquery-py/src/parsing/functions/split.py +0 -54
  118. package/flowquery-py/src/parsing/functions/string_distance.py +0 -92
  119. package/flowquery-py/src/parsing/functions/stringify.py +0 -49
  120. package/flowquery-py/src/parsing/functions/substring.py +0 -76
  121. package/flowquery-py/src/parsing/functions/sum.py +0 -51
  122. package/flowquery-py/src/parsing/functions/tail.py +0 -37
  123. package/flowquery-py/src/parsing/functions/temporal_utils.py +0 -186
  124. package/flowquery-py/src/parsing/functions/time_.py +0 -57
  125. package/flowquery-py/src/parsing/functions/timestamp.py +0 -37
  126. package/flowquery-py/src/parsing/functions/to_float.py +0 -46
  127. package/flowquery-py/src/parsing/functions/to_integer.py +0 -46
  128. package/flowquery-py/src/parsing/functions/to_json.py +0 -35
  129. package/flowquery-py/src/parsing/functions/to_lower.py +0 -37
  130. package/flowquery-py/src/parsing/functions/to_string.py +0 -41
  131. package/flowquery-py/src/parsing/functions/trim.py +0 -37
  132. package/flowquery-py/src/parsing/functions/type_.py +0 -47
  133. package/flowquery-py/src/parsing/functions/value_holder.py +0 -24
  134. package/flowquery-py/src/parsing/logic/__init__.py +0 -15
  135. package/flowquery-py/src/parsing/logic/case.py +0 -28
  136. package/flowquery-py/src/parsing/logic/else_.py +0 -12
  137. package/flowquery-py/src/parsing/logic/end.py +0 -8
  138. package/flowquery-py/src/parsing/logic/then.py +0 -12
  139. package/flowquery-py/src/parsing/logic/when.py +0 -12
  140. package/flowquery-py/src/parsing/operations/__init__.py +0 -46
  141. package/flowquery-py/src/parsing/operations/aggregated_return.py +0 -25
  142. package/flowquery-py/src/parsing/operations/aggregated_with.py +0 -22
  143. package/flowquery-py/src/parsing/operations/call.py +0 -73
  144. package/flowquery-py/src/parsing/operations/create_node.py +0 -35
  145. package/flowquery-py/src/parsing/operations/create_relationship.py +0 -35
  146. package/flowquery-py/src/parsing/operations/delete_node.py +0 -29
  147. package/flowquery-py/src/parsing/operations/delete_relationship.py +0 -29
  148. package/flowquery-py/src/parsing/operations/group_by.py +0 -148
  149. package/flowquery-py/src/parsing/operations/limit.py +0 -33
  150. package/flowquery-py/src/parsing/operations/load.py +0 -148
  151. package/flowquery-py/src/parsing/operations/match.py +0 -52
  152. package/flowquery-py/src/parsing/operations/operation.py +0 -69
  153. package/flowquery-py/src/parsing/operations/order_by.py +0 -114
  154. package/flowquery-py/src/parsing/operations/projection.py +0 -21
  155. package/flowquery-py/src/parsing/operations/return_op.py +0 -88
  156. package/flowquery-py/src/parsing/operations/union.py +0 -115
  157. package/flowquery-py/src/parsing/operations/union_all.py +0 -17
  158. package/flowquery-py/src/parsing/operations/unwind.py +0 -42
  159. package/flowquery-py/src/parsing/operations/where.py +0 -43
  160. package/flowquery-py/src/parsing/operations/with_op.py +0 -18
  161. package/flowquery-py/src/parsing/parser.py +0 -1384
  162. package/flowquery-py/src/parsing/parser_state.py +0 -26
  163. package/flowquery-py/src/parsing/token_to_node.py +0 -109
  164. package/flowquery-py/src/tokenization/__init__.py +0 -23
  165. package/flowquery-py/src/tokenization/keyword.py +0 -54
  166. package/flowquery-py/src/tokenization/operator.py +0 -29
  167. package/flowquery-py/src/tokenization/string_walker.py +0 -158
  168. package/flowquery-py/src/tokenization/symbol.py +0 -19
  169. package/flowquery-py/src/tokenization/token.py +0 -693
  170. package/flowquery-py/src/tokenization/token_mapper.py +0 -53
  171. package/flowquery-py/src/tokenization/token_type.py +0 -21
  172. package/flowquery-py/src/tokenization/tokenizer.py +0 -214
  173. package/flowquery-py/src/tokenization/trie.py +0 -125
  174. package/flowquery-py/src/utils/__init__.py +0 -6
  175. package/flowquery-py/src/utils/object_utils.py +0 -20
  176. package/flowquery-py/src/utils/string_utils.py +0 -113
  177. package/flowquery-py/tests/__init__.py +0 -1
  178. package/flowquery-py/tests/compute/__init__.py +0 -1
  179. package/flowquery-py/tests/compute/test_runner.py +0 -4902
  180. package/flowquery-py/tests/graph/__init__.py +0 -1
  181. package/flowquery-py/tests/graph/test_create.py +0 -56
  182. package/flowquery-py/tests/graph/test_data.py +0 -73
  183. package/flowquery-py/tests/graph/test_match.py +0 -40
  184. package/flowquery-py/tests/parsing/__init__.py +0 -1
  185. package/flowquery-py/tests/parsing/test_context.py +0 -34
  186. package/flowquery-py/tests/parsing/test_expression.py +0 -248
  187. package/flowquery-py/tests/parsing/test_parser.py +0 -1237
  188. package/flowquery-py/tests/test_extensibility.py +0 -611
  189. package/flowquery-py/tests/tokenization/__init__.py +0 -1
  190. package/flowquery-py/tests/tokenization/test_token_mapper.py +0 -60
  191. package/flowquery-py/tests/tokenization/test_tokenizer.py +0 -198
  192. package/flowquery-py/tests/tokenization/test_trie.py +0 -30
  193. package/flowquery-vscode/.vscode-test.mjs +0 -5
  194. package/flowquery-vscode/.vscodeignore +0 -13
  195. package/flowquery-vscode/LICENSE +0 -21
  196. package/flowquery-vscode/README.md +0 -11
  197. package/flowquery-vscode/demo/FlowQueryVSCodeDemo.gif +0 -0
  198. package/flowquery-vscode/eslint.config.mjs +0 -25
  199. package/flowquery-vscode/extension.js +0 -508
  200. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +0 -1
  201. package/flowquery-vscode/flowquery-worker.js +0 -66
  202. package/flowquery-vscode/images/FlowQueryLogoIcon.png +0 -0
  203. package/flowquery-vscode/jsconfig.json +0 -13
  204. package/flowquery-vscode/libs/page.css +0 -53
  205. package/flowquery-vscode/libs/table.css +0 -13
  206. package/flowquery-vscode/libs/tabs.css +0 -66
  207. package/flowquery-vscode/package-lock.json +0 -2917
  208. package/flowquery-vscode/package.json +0 -51
  209. package/flowquery-vscode/test/extension.test.js +0 -196
  210. package/flowquery-vscode/test/worker.test.js +0 -25
  211. package/flowquery-vscode/vsc-extension-quickstart.md +0 -42
  212. package/jest.config.js +0 -14
  213. package/misc/apps/RAG/README.md +0 -29
  214. package/misc/apps/RAG/data/chats.json +0 -302
  215. package/misc/apps/RAG/data/emails.json +0 -182
  216. package/misc/apps/RAG/data/events.json +0 -226
  217. package/misc/apps/RAG/data/files.json +0 -172
  218. package/misc/apps/RAG/data/users.json +0 -158
  219. package/misc/apps/RAG/jest.config.js +0 -21
  220. package/misc/apps/RAG/package.json +0 -48
  221. package/misc/apps/RAG/public/index.html +0 -18
  222. package/misc/apps/RAG/src/App.css +0 -42
  223. package/misc/apps/RAG/src/App.tsx +0 -50
  224. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +0 -172
  225. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +0 -380
  226. package/misc/apps/RAG/src/components/ApiKeySettings.tsx +0 -245
  227. package/misc/apps/RAG/src/components/ChatContainer.css +0 -67
  228. package/misc/apps/RAG/src/components/ChatContainer.tsx +0 -242
  229. package/misc/apps/RAG/src/components/ChatInput.css +0 -23
  230. package/misc/apps/RAG/src/components/ChatInput.tsx +0 -76
  231. package/misc/apps/RAG/src/components/ChatMessage.css +0 -160
  232. package/misc/apps/RAG/src/components/ChatMessage.tsx +0 -286
  233. package/misc/apps/RAG/src/components/FlowQueryAgent.ts +0 -708
  234. package/misc/apps/RAG/src/components/FlowQueryRunner.css +0 -113
  235. package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +0 -371
  236. package/misc/apps/RAG/src/components/index.ts +0 -28
  237. package/misc/apps/RAG/src/graph/index.ts +0 -19
  238. package/misc/apps/RAG/src/graph/initializeGraph.ts +0 -254
  239. package/misc/apps/RAG/src/index.tsx +0 -29
  240. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +0 -327
  241. package/misc/apps/RAG/src/prompts/index.ts +0 -10
  242. package/misc/apps/RAG/src/tests/graph.test.ts +0 -35
  243. package/misc/apps/RAG/src/utils/FlowQueryExecutor.ts +0 -130
  244. package/misc/apps/RAG/src/utils/FlowQueryExtractor.ts +0 -208
  245. package/misc/apps/RAG/src/utils/Llm.ts +0 -248
  246. package/misc/apps/RAG/src/utils/index.ts +0 -12
  247. package/misc/apps/RAG/tsconfig.json +0 -22
  248. package/misc/apps/RAG/webpack.config.js +0 -43
  249. package/misc/apps/README.md +0 -1
  250. package/misc/queries/analyze_catfacts.cql +0 -75
  251. package/misc/queries/azure_openai_completions.cql +0 -13
  252. package/misc/queries/azure_openai_models.cql +0 -9
  253. package/misc/queries/mock_pipeline.cql +0 -84
  254. package/misc/queries/openai_completions.cql +0 -15
  255. package/misc/queries/openai_models.cql +0 -13
  256. package/misc/queries/test.cql +0 -6
  257. package/misc/queries/tool_inference.cql +0 -24
  258. package/misc/queries/wisdom.cql +0 -6
  259. package/misc/queries/wisdom_letter_histogram.cql +0 -8
  260. package/src/compute/flowquery.ts +0 -46
  261. package/src/compute/runner.ts +0 -66
  262. package/src/extensibility.ts +0 -45
  263. package/src/graph/data.ts +0 -130
  264. package/src/graph/database.ts +0 -143
  265. package/src/graph/hops.ts +0 -22
  266. package/src/graph/node.ts +0 -122
  267. package/src/graph/node_data.ts +0 -18
  268. package/src/graph/node_reference.ts +0 -38
  269. package/src/graph/pattern.ts +0 -110
  270. package/src/graph/pattern_expression.ts +0 -48
  271. package/src/graph/patterns.ts +0 -36
  272. package/src/graph/physical_node.ts +0 -23
  273. package/src/graph/physical_relationship.ts +0 -23
  274. package/src/graph/relationship.ts +0 -167
  275. package/src/graph/relationship_data.ts +0 -31
  276. package/src/graph/relationship_match_collector.ts +0 -64
  277. package/src/graph/relationship_reference.ts +0 -25
  278. package/src/index.browser.ts +0 -46
  279. package/src/index.node.ts +0 -55
  280. package/src/index.ts +0 -12
  281. package/src/io/command_line.ts +0 -74
  282. package/src/parsing/alias.ts +0 -23
  283. package/src/parsing/alias_option.ts +0 -5
  284. package/src/parsing/ast_node.ts +0 -153
  285. package/src/parsing/base_parser.ts +0 -98
  286. package/src/parsing/components/csv.ts +0 -9
  287. package/src/parsing/components/from.ts +0 -12
  288. package/src/parsing/components/headers.ts +0 -12
  289. package/src/parsing/components/json.ts +0 -9
  290. package/src/parsing/components/null.ts +0 -9
  291. package/src/parsing/components/post.ts +0 -9
  292. package/src/parsing/components/text.ts +0 -9
  293. package/src/parsing/context.ts +0 -54
  294. package/src/parsing/data_structures/associative_array.ts +0 -43
  295. package/src/parsing/data_structures/json_array.ts +0 -31
  296. package/src/parsing/data_structures/key_value_pair.ts +0 -37
  297. package/src/parsing/data_structures/lookup.ts +0 -44
  298. package/src/parsing/data_structures/range_lookup.ts +0 -36
  299. package/src/parsing/expressions/boolean.ts +0 -21
  300. package/src/parsing/expressions/expression.ts +0 -150
  301. package/src/parsing/expressions/expression_map.ts +0 -22
  302. package/src/parsing/expressions/f_string.ts +0 -26
  303. package/src/parsing/expressions/identifier.ts +0 -22
  304. package/src/parsing/expressions/number.ts +0 -40
  305. package/src/parsing/expressions/operator.ts +0 -354
  306. package/src/parsing/expressions/reference.ts +0 -45
  307. package/src/parsing/expressions/string.ts +0 -34
  308. package/src/parsing/functions/aggregate_function.ts +0 -58
  309. package/src/parsing/functions/async_function.ts +0 -64
  310. package/src/parsing/functions/avg.ts +0 -47
  311. package/src/parsing/functions/coalesce.ts +0 -49
  312. package/src/parsing/functions/collect.ts +0 -54
  313. package/src/parsing/functions/count.ts +0 -54
  314. package/src/parsing/functions/date.ts +0 -63
  315. package/src/parsing/functions/datetime.ts +0 -63
  316. package/src/parsing/functions/duration.ts +0 -143
  317. package/src/parsing/functions/element_id.ts +0 -51
  318. package/src/parsing/functions/function.ts +0 -60
  319. package/src/parsing/functions/function_factory.ts +0 -195
  320. package/src/parsing/functions/function_metadata.ts +0 -217
  321. package/src/parsing/functions/functions.ts +0 -70
  322. package/src/parsing/functions/head.ts +0 -42
  323. package/src/parsing/functions/id.ts +0 -51
  324. package/src/parsing/functions/join.ts +0 -40
  325. package/src/parsing/functions/keys.ts +0 -29
  326. package/src/parsing/functions/last.ts +0 -42
  327. package/src/parsing/functions/localdatetime.ts +0 -63
  328. package/src/parsing/functions/localtime.ts +0 -58
  329. package/src/parsing/functions/max.ts +0 -37
  330. package/src/parsing/functions/min.ts +0 -37
  331. package/src/parsing/functions/nodes.ts +0 -54
  332. package/src/parsing/functions/predicate_function.ts +0 -48
  333. package/src/parsing/functions/predicate_sum.ts +0 -47
  334. package/src/parsing/functions/properties.ts +0 -56
  335. package/src/parsing/functions/rand.ts +0 -21
  336. package/src/parsing/functions/range.ts +0 -37
  337. package/src/parsing/functions/reducer_element.ts +0 -10
  338. package/src/parsing/functions/relationships.ts +0 -52
  339. package/src/parsing/functions/replace.ts +0 -38
  340. package/src/parsing/functions/round.ts +0 -28
  341. package/src/parsing/functions/schema.ts +0 -39
  342. package/src/parsing/functions/size.ts +0 -28
  343. package/src/parsing/functions/split.ts +0 -45
  344. package/src/parsing/functions/string_distance.ts +0 -83
  345. package/src/parsing/functions/stringify.ts +0 -37
  346. package/src/parsing/functions/substring.ts +0 -68
  347. package/src/parsing/functions/sum.ts +0 -41
  348. package/src/parsing/functions/tail.ts +0 -39
  349. package/src/parsing/functions/temporal_utils.ts +0 -180
  350. package/src/parsing/functions/time.ts +0 -58
  351. package/src/parsing/functions/timestamp.ts +0 -37
  352. package/src/parsing/functions/to_float.ts +0 -50
  353. package/src/parsing/functions/to_integer.ts +0 -50
  354. package/src/parsing/functions/to_json.ts +0 -28
  355. package/src/parsing/functions/to_lower.ts +0 -28
  356. package/src/parsing/functions/to_string.ts +0 -32
  357. package/src/parsing/functions/trim.ts +0 -28
  358. package/src/parsing/functions/type.ts +0 -39
  359. package/src/parsing/functions/value_holder.ts +0 -13
  360. package/src/parsing/logic/case.ts +0 -26
  361. package/src/parsing/logic/else.ts +0 -12
  362. package/src/parsing/logic/end.ts +0 -9
  363. package/src/parsing/logic/then.ts +0 -12
  364. package/src/parsing/logic/when.ts +0 -12
  365. package/src/parsing/operations/aggregated_return.ts +0 -22
  366. package/src/parsing/operations/aggregated_with.ts +0 -18
  367. package/src/parsing/operations/call.ts +0 -69
  368. package/src/parsing/operations/create_node.ts +0 -39
  369. package/src/parsing/operations/create_relationship.ts +0 -38
  370. package/src/parsing/operations/delete_node.ts +0 -33
  371. package/src/parsing/operations/delete_relationship.ts +0 -32
  372. package/src/parsing/operations/group_by.ts +0 -137
  373. package/src/parsing/operations/limit.ts +0 -31
  374. package/src/parsing/operations/load.ts +0 -146
  375. package/src/parsing/operations/match.ts +0 -54
  376. package/src/parsing/operations/operation.ts +0 -69
  377. package/src/parsing/operations/order_by.ts +0 -126
  378. package/src/parsing/operations/projection.ts +0 -18
  379. package/src/parsing/operations/return.ts +0 -76
  380. package/src/parsing/operations/union.ts +0 -114
  381. package/src/parsing/operations/union_all.ts +0 -16
  382. package/src/parsing/operations/unwind.ts +0 -36
  383. package/src/parsing/operations/where.ts +0 -42
  384. package/src/parsing/operations/with.ts +0 -20
  385. package/src/parsing/parser.ts +0 -1641
  386. package/src/parsing/parser_state.ts +0 -25
  387. package/src/parsing/token_to_node.ts +0 -114
  388. package/src/tokenization/keyword.ts +0 -50
  389. package/src/tokenization/operator.ts +0 -25
  390. package/src/tokenization/string_walker.ts +0 -197
  391. package/src/tokenization/symbol.ts +0 -15
  392. package/src/tokenization/token.ts +0 -764
  393. package/src/tokenization/token_mapper.ts +0 -53
  394. package/src/tokenization/token_type.ts +0 -16
  395. package/src/tokenization/tokenizer.ts +0 -250
  396. package/src/tokenization/trie.ts +0 -117
  397. package/src/utils/object_utils.ts +0 -17
  398. package/src/utils/string_utils.ts +0 -114
  399. package/tests/compute/runner.test.ts +0 -4559
  400. package/tests/extensibility.test.ts +0 -643
  401. package/tests/graph/create.test.ts +0 -36
  402. package/tests/graph/data.test.ts +0 -58
  403. package/tests/graph/match.test.ts +0 -29
  404. package/tests/parsing/context.test.ts +0 -27
  405. package/tests/parsing/expression.test.ts +0 -303
  406. package/tests/parsing/parser.test.ts +0 -1327
  407. package/tests/tokenization/token_mapper.test.ts +0 -47
  408. package/tests/tokenization/tokenizer.test.ts +0 -191
  409. package/tests/tokenization/trie.test.ts +0 -20
  410. package/tsconfig.json +0 -19
  411. package/typedoc.json +0 -16
  412. package/vscode-settings.json.recommended +0 -16
  413. 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