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,1641 +0,0 @@
1
- import Hops from "../graph/hops";
2
- import Node from "../graph/node";
3
- import NodeReference from "../graph/node_reference";
4
- import Pattern from "../graph/pattern";
5
- import PatternExpression from "../graph/pattern_expression";
6
- import Relationship from "../graph/relationship";
7
- import RelationshipReference from "../graph/relationship_reference";
8
- import Token from "../tokenization/token";
9
- import ObjectUtils from "../utils/object_utils";
10
- import Alias from "./alias";
11
- import { AliasOption } from "./alias_option";
12
- import ASTNode from "./ast_node";
13
- import BaseParser from "./base_parser";
14
- import From from "./components/from";
15
- import Headers from "./components/headers";
16
- import Null from "./components/null";
17
- import Post from "./components/post";
18
- import Context from "./context";
19
- import AssociativeArray from "./data_structures/associative_array";
20
- import JSONArray from "./data_structures/json_array";
21
- import KeyValuePair from "./data_structures/key_value_pair";
22
- import Lookup from "./data_structures/lookup";
23
- import RangeLookup from "./data_structures/range_lookup";
24
- import Expression from "./expressions/expression";
25
- import FString from "./expressions/f_string";
26
- import Identifier from "./expressions/identifier";
27
- import {
28
- Contains,
29
- EndsWith,
30
- In,
31
- Is,
32
- IsNot,
33
- Not,
34
- NotContains,
35
- NotEndsWith,
36
- NotIn,
37
- NotStartsWith,
38
- StartsWith,
39
- } from "./expressions/operator";
40
- import Reference from "./expressions/reference";
41
- import String from "./expressions/string";
42
- import AggregateFunction from "./functions/aggregate_function";
43
- import AsyncFunction from "./functions/async_function";
44
- import Function from "./functions/function";
45
- import FunctionFactory from "./functions/function_factory";
46
- import PredicateFunction from "./functions/predicate_function";
47
- import Case from "./logic/case";
48
- import Else from "./logic/else";
49
- import Then from "./logic/then";
50
- import When from "./logic/when";
51
- import AggregatedReturn from "./operations/aggregated_return";
52
- import AggregatedWith from "./operations/aggregated_with";
53
- import Call from "./operations/call";
54
- import CreateNode from "./operations/create_node";
55
- import CreateRelationship from "./operations/create_relationship";
56
- import DeleteNode from "./operations/delete_node";
57
- import DeleteRelationship from "./operations/delete_relationship";
58
- import Limit from "./operations/limit";
59
- import Load from "./operations/load";
60
- import Match from "./operations/match";
61
- import Operation from "./operations/operation";
62
- import OrderBy, { SortField } from "./operations/order_by";
63
- import Return from "./operations/return";
64
- import Union from "./operations/union";
65
- import UnionAll from "./operations/union_all";
66
- import Unwind from "./operations/unwind";
67
- import Where from "./operations/where";
68
- import With from "./operations/with";
69
- import ParserState from "./parser_state";
70
-
71
- /**
72
- * Main parser for FlowQuery statements.
73
- *
74
- * Parses FlowQuery declarative query language statements into an Abstract Syntax Tree (AST).
75
- * Supports operations like WITH, UNWIND, RETURN, LOAD, WHERE, and LIMIT, along with
76
- * expressions, functions, data structures, and logical constructs.
77
- *
78
- * @example
79
- * ```typescript
80
- * const parser = new Parser();
81
- * const ast = parser.parse("unwind [1, 2, 3, 4, 5] as num return num");
82
- * ```
83
- */
84
- class Parser extends BaseParser {
85
- private _state: ParserState = new ParserState();
86
-
87
- /**
88
- * Parses a FlowQuery statement into an Abstract Syntax Tree.
89
- *
90
- * @param statement - The FlowQuery statement to parse
91
- * @returns The root AST node containing the parsed structure
92
- * @throws {Error} If the statement is malformed or contains syntax errors
93
- *
94
- * @example
95
- * ```typescript
96
- * const ast = parser.parse("LOAD JSON FROM 'https://api.adviceslip.com/advice' AS data RETURN data");
97
- * ```
98
- */
99
- public parse(statement: string): ASTNode {
100
- this.tokenize(statement);
101
- return this._parseTokenized();
102
- }
103
-
104
- private _parseTokenized(isSubQuery: boolean = false): ASTNode {
105
- const root: ASTNode = new ASTNode();
106
- let previous: Operation | null = null;
107
- let operation: Operation | null = null;
108
- while (!this.token.isEOF()) {
109
- if (root.childCount() > 0) {
110
- this.expectAndSkipWhitespaceAndComments();
111
- } else {
112
- this.skipWhitespaceAndComments();
113
- }
114
- // UNION separates two query pipelines — break and handle after the loop
115
- if (this.token.isUnion()) {
116
- break;
117
- }
118
- if (this.token.isEOF()) {
119
- break;
120
- }
121
- operation = this.parseOperation();
122
- if (operation === null && !isSubQuery) {
123
- throw new Error("Expected one of WITH, UNWIND, RETURN, LOAD, OR CALL");
124
- } else if (operation === null && isSubQuery) {
125
- return root;
126
- }
127
- if (this._state.returns > 1) {
128
- throw new Error("Only one RETURN statement is allowed");
129
- }
130
- if (previous instanceof Call && !previous.hasYield) {
131
- throw new Error(
132
- "CALL operations must have a YIELD clause unless they are the last operation"
133
- );
134
- }
135
- if (previous !== null) {
136
- previous.addSibling(operation!);
137
- } else {
138
- root.addChild(operation!);
139
- }
140
- const where = this.parseWhere();
141
- if (where !== null) {
142
- if (operation instanceof Return) {
143
- (operation as Return).where = where;
144
- } else {
145
- operation!.addSibling(where);
146
- operation = where;
147
- }
148
- }
149
- const orderBy = this.parseOrderBy();
150
- if (orderBy !== null) {
151
- if (operation instanceof Return) {
152
- (operation as Return).orderBy = orderBy;
153
- } else {
154
- operation!.addSibling(orderBy);
155
- operation = orderBy;
156
- }
157
- }
158
- const limit = this.parseLimit();
159
- if (limit !== null) {
160
- if (operation instanceof Return) {
161
- (operation as Return).limit = limit;
162
- } else {
163
- operation!.addSibling(limit);
164
- operation = limit;
165
- }
166
- }
167
- previous = operation;
168
- }
169
- // Handle UNION: wrap left and right pipelines into a Union node
170
- if (!this.token.isEOF() && this.token.isUnion()) {
171
- if (!(operation instanceof Return) && !(operation instanceof Call)) {
172
- throw new Error("Each side of UNION must end with a RETURN or CALL statement");
173
- }
174
- const union = this.parseUnion()!;
175
- union.left = root.firstChild() as Operation;
176
- // Save and reset parser state for right-side scope
177
- const state = this._state;
178
- this._state = new ParserState();
179
- const right = this._parseTokenized(isSubQuery);
180
- union.right = right.firstChild() as Operation;
181
- // Restore parser state
182
- this._state = state;
183
- const newRoot = new ASTNode();
184
- newRoot.addChild(union);
185
- return newRoot;
186
- }
187
- if (
188
- !(operation instanceof Return) &&
189
- !(operation instanceof Call) &&
190
- !(operation instanceof CreateNode) &&
191
- !(operation instanceof CreateRelationship) &&
192
- !(operation instanceof DeleteNode) &&
193
- !(operation instanceof DeleteRelationship)
194
- ) {
195
- throw new Error(
196
- "Last statement must be a RETURN, WHERE, CALL, CREATE, or DELETE statement"
197
- );
198
- }
199
- return root;
200
- }
201
-
202
- private parseOperation(): Operation | null {
203
- return (
204
- this.parseWith() ||
205
- this.parseUnwind() ||
206
- this.parseReturn() ||
207
- this.parseLoad() ||
208
- this.parseCall() ||
209
- this.parseCreate() ||
210
- this.parseDelete() ||
211
- this.parseMatch()
212
- );
213
- }
214
-
215
- private parseWith(): With | null {
216
- if (!this.token.isWith()) {
217
- return null;
218
- }
219
- this.setNextToken();
220
- this.expectAndSkipWhitespaceAndComments();
221
- let distinct = false;
222
- if (this.token.isDistinct()) {
223
- distinct = true;
224
- this.setNextToken();
225
- this.expectAndSkipWhitespaceAndComments();
226
- }
227
- const expressions = this.parseExpressions(AliasOption.REQUIRED);
228
- if (expressions.length === 0) {
229
- throw new Error("Expected expression");
230
- }
231
- if (distinct || expressions.some((expression: Expression) => expression.has_reducers())) {
232
- return new AggregatedWith(expressions);
233
- }
234
- return new With(expressions);
235
- }
236
-
237
- private parseUnwind(): Unwind | null {
238
- if (!this.token.isUnwind()) {
239
- return null;
240
- }
241
- this.setNextToken();
242
- this.expectAndSkipWhitespaceAndComments();
243
- const expression: Expression | null = this.parseExpression();
244
- if (expression === null) {
245
- throw new Error("Expected expression");
246
- }
247
- if (
248
- !ObjectUtils.isInstanceOfAny(expression.firstChild(), [
249
- JSONArray,
250
- Function,
251
- Reference,
252
- Lookup,
253
- RangeLookup,
254
- ])
255
- ) {
256
- throw new Error("Expected array, function, reference, or lookup.");
257
- }
258
- this.expectAndSkipWhitespaceAndComments();
259
- const alias = this.parseAlias();
260
- if (alias !== null) {
261
- expression.setAlias(alias.getAlias());
262
- } else {
263
- throw new Error("Expected alias");
264
- }
265
- const unwind = new Unwind(expression);
266
- this._state.variables.set(alias.getAlias(), unwind);
267
- return unwind;
268
- }
269
-
270
- private parseReturn(): Return | null {
271
- if (!this.token.isReturn()) {
272
- return null;
273
- }
274
- this.setNextToken();
275
- this.expectAndSkipWhitespaceAndComments();
276
- let distinct = false;
277
- if (this.token.isDistinct()) {
278
- distinct = true;
279
- this.setNextToken();
280
- this.expectAndSkipWhitespaceAndComments();
281
- }
282
- const expressions = this.parseExpressions(AliasOption.OPTIONAL);
283
- if (expressions.length === 0) {
284
- throw new Error("Expected expression");
285
- }
286
- if (distinct || expressions.some((expression: Expression) => expression.has_reducers())) {
287
- return new AggregatedReturn(expressions);
288
- }
289
- this._state.incrementReturns();
290
- return new Return(expressions);
291
- }
292
-
293
- private parseWhere(): Where | null {
294
- this.skipWhitespaceAndComments();
295
- if (!this.token.isWhere()) {
296
- return null;
297
- }
298
- this.expectPreviousTokenToBeWhitespaceOrComment();
299
- this.setNextToken();
300
- this.expectAndSkipWhitespaceAndComments();
301
- const expression = this.parseExpression();
302
- if (expression === null) {
303
- throw new Error("Expected expression");
304
- }
305
- if (ObjectUtils.isInstanceOfAny(expression.firstChild(), [JSONArray, AssociativeArray])) {
306
- throw new Error("Expected an expression which can be evaluated to a boolean");
307
- }
308
- return new Where(expression);
309
- }
310
-
311
- private parseLoad(): Load | null {
312
- if (!this.token.isLoad()) {
313
- return null;
314
- }
315
- const load = new Load();
316
- this.setNextToken();
317
- this.expectAndSkipWhitespaceAndComments();
318
- if (!(this.token.isJSON() || this.token.isCSV() || this.token.isText())) {
319
- throw new Error("Expected JSON, CSV, or TEXT");
320
- }
321
- load.addChild(this.token.node);
322
- this.setNextToken();
323
- this.expectAndSkipWhitespaceAndComments();
324
- if (!this.token.isFrom()) {
325
- throw new Error("Expected FROM");
326
- }
327
- this.setNextToken();
328
- this.expectAndSkipWhitespaceAndComments();
329
- const from = new From();
330
- load.addChild(from);
331
-
332
- // Check if the source is an async function
333
- const asyncFunc = this.parseAsyncFunction();
334
- if (asyncFunc !== null) {
335
- from.addChild(asyncFunc);
336
- } else {
337
- const expression = this.parseExpression();
338
- if (expression === null) {
339
- throw new Error("Expected expression or async function");
340
- }
341
- from.addChild(expression);
342
- }
343
-
344
- this.expectAndSkipWhitespaceAndComments();
345
- if (this.token.isHeaders()) {
346
- const headers = new Headers();
347
- this.setNextToken();
348
- this.expectAndSkipWhitespaceAndComments();
349
- const header = this.parseExpression();
350
- if (header === null) {
351
- throw new Error("Expected expression");
352
- }
353
- headers.addChild(header);
354
- load.addChild(headers);
355
- this.expectAndSkipWhitespaceAndComments();
356
- }
357
- if (this.token.isPost()) {
358
- const post = new Post();
359
- this.setNextToken();
360
- this.expectAndSkipWhitespaceAndComments();
361
- const payload = this.parseExpression();
362
- if (payload === null) {
363
- throw new Error("Expected expression");
364
- }
365
- post.addChild(payload);
366
- load.addChild(post);
367
- this.expectAndSkipWhitespaceAndComments();
368
- }
369
- const alias = this.parseAlias();
370
- if (alias !== null) {
371
- load.addChild(alias);
372
- this._state.variables.set(alias.getAlias(), load);
373
- } else {
374
- throw new Error("Expected alias");
375
- }
376
- return load;
377
- }
378
-
379
- private parseCall(): Call | null {
380
- if (!this.token.isCall()) {
381
- return null;
382
- }
383
- this.setNextToken();
384
- this.expectAndSkipWhitespaceAndComments();
385
- const asyncFunction = this.parseAsyncFunction();
386
- if (asyncFunction === null) {
387
- throw new Error("Expected async function");
388
- }
389
- const call = new Call();
390
- call.function = asyncFunction;
391
- this.skipWhitespaceAndComments();
392
- if (this.token.isYield()) {
393
- this.expectPreviousTokenToBeWhitespaceOrComment();
394
- this.setNextToken();
395
- this.expectAndSkipWhitespaceAndComments();
396
- const expressions = this.parseExpressions(AliasOption.OPTIONAL);
397
- if (expressions.length === 0) {
398
- throw new Error("Expected at least one expression");
399
- }
400
- call.yielded = expressions;
401
- }
402
- return call;
403
- }
404
-
405
- private parseCreate(): CreateNode | CreateRelationship | null {
406
- if (!this.token.isCreate()) {
407
- return null;
408
- }
409
- this.setNextToken();
410
- this.expectAndSkipWhitespaceAndComments();
411
- if (!this.token.isVirtual()) {
412
- throw new Error("Expected VIRTUAL");
413
- }
414
- this.setNextToken();
415
- this.expectAndSkipWhitespaceAndComments();
416
- const node: Node | null = this.parseNode();
417
- if (node === null) {
418
- throw new Error("Expected node definition");
419
- }
420
- let relationship: Relationship | null = null;
421
- if (this.token.isSubtract() && this.peek()?.isOpeningBracket()) {
422
- this.setNextToken();
423
- this.setNextToken();
424
- if (!this.token.isColon()) {
425
- throw new Error("Expected ':' for relationship type");
426
- }
427
- this.setNextToken();
428
- if (!this.token.isIdentifierOrKeyword()) {
429
- throw new Error("Expected relationship type identifier");
430
- }
431
- const type: string = this.token.value || "";
432
- this.setNextToken();
433
- if (!this.token.isClosingBracket()) {
434
- throw new Error("Expected closing bracket for relationship definition");
435
- }
436
- this.setNextToken();
437
- if (!this.token.isSubtract()) {
438
- throw new Error("Expected '-' for relationship definition");
439
- }
440
- this.setNextToken();
441
- const target: Node | null = this.parseNode();
442
- if (target === null) {
443
- throw new Error("Expected target node definition");
444
- }
445
- relationship = new Relationship();
446
- relationship.type = type;
447
- relationship.source = node;
448
- relationship.target = target;
449
- }
450
- this.expectAndSkipWhitespaceAndComments();
451
- if (!this.token.isAs()) {
452
- throw new Error("Expected AS");
453
- }
454
- this.setNextToken();
455
- this.expectAndSkipWhitespaceAndComments();
456
- const query: ASTNode | null = this.parseSubQuery();
457
- if (query === null) {
458
- throw new Error("Expected sub-query");
459
- }
460
- let create: CreateNode | CreateRelationship;
461
- if (relationship !== null) {
462
- create = new CreateRelationship(relationship, query);
463
- } else {
464
- create = new CreateNode(node, query);
465
- }
466
- return create;
467
- }
468
-
469
- private parseDelete(): DeleteNode | DeleteRelationship | null {
470
- if (!this.token.isDelete()) {
471
- return null;
472
- }
473
- this.setNextToken();
474
- this.expectAndSkipWhitespaceAndComments();
475
- if (!this.token.isVirtual()) {
476
- throw new Error("Expected VIRTUAL");
477
- }
478
- this.setNextToken();
479
- this.expectAndSkipWhitespaceAndComments();
480
- const node: Node | null = this.parseNode();
481
- if (node === null) {
482
- throw new Error("Expected node definition");
483
- }
484
- let relationship: Relationship | null = null;
485
- if (this.token.isSubtract() && this.peek()?.isOpeningBracket()) {
486
- this.setNextToken();
487
- this.setNextToken();
488
- if (!this.token.isColon()) {
489
- throw new Error("Expected ':' for relationship type");
490
- }
491
- this.setNextToken();
492
- if (!this.token.isIdentifierOrKeyword()) {
493
- throw new Error("Expected relationship type identifier");
494
- }
495
- const type: string = this.token.value || "";
496
- this.setNextToken();
497
- if (!this.token.isClosingBracket()) {
498
- throw new Error("Expected closing bracket for relationship definition");
499
- }
500
- this.setNextToken();
501
- if (!this.token.isSubtract()) {
502
- throw new Error("Expected '-' for relationship definition");
503
- }
504
- this.setNextToken();
505
- const target: Node | null = this.parseNode();
506
- if (target === null) {
507
- throw new Error("Expected target node definition");
508
- }
509
- relationship = new Relationship();
510
- relationship.type = type;
511
- relationship.source = node;
512
- relationship.target = target;
513
- }
514
- let result: DeleteNode | DeleteRelationship;
515
- if (relationship !== null) {
516
- result = new DeleteRelationship(relationship);
517
- } else {
518
- result = new DeleteNode(node);
519
- }
520
- return result;
521
- }
522
-
523
- private parseMatch(): Match | null {
524
- let optional = false;
525
- if (this.token.isOptional()) {
526
- optional = true;
527
- this.setNextToken();
528
- this.expectAndSkipWhitespaceAndComments();
529
- }
530
- if (!this.token.isMatch()) {
531
- if (optional) {
532
- throw new Error("Expected MATCH after OPTIONAL");
533
- }
534
- return null;
535
- }
536
- this.setNextToken();
537
- this.expectAndSkipWhitespaceAndComments();
538
- const patterns: Pattern[] = Array.from(this.parsePatterns());
539
- if (patterns.length === 0) {
540
- throw new Error("Expected graph pattern");
541
- }
542
- return new Match(patterns, optional);
543
- }
544
-
545
- private parseNode(): Node | null {
546
- if (!this.token.isLeftParenthesis()) {
547
- return null;
548
- }
549
- this.setNextToken();
550
- this.skipWhitespaceAndComments();
551
- let identifier: string | null = null;
552
- if (this.token.isIdentifierOrKeyword()) {
553
- identifier = this.token.value || "";
554
- this.setNextToken();
555
- }
556
- this.skipWhitespaceAndComments();
557
- let label: string | null = null;
558
- if (!this.token.isColon() && this.peek()?.isIdentifierOrKeyword()) {
559
- throw new Error("Expected ':' for node label");
560
- }
561
- if (this.token.isColon() && !this.peek()?.isIdentifierOrKeyword()) {
562
- throw new Error("Expected node label identifier");
563
- }
564
- if (this.token.isColon() && this.peek()?.isIdentifierOrKeyword()) {
565
- this.setNextToken();
566
- label = this.token.value || "";
567
- this.setNextToken();
568
- }
569
- this.skipWhitespaceAndComments();
570
- let node = new Node();
571
- node.properties = new Map(this.parseProperties());
572
- node.label = label!;
573
- if (identifier !== null && this._state.variables.has(identifier)) {
574
- let reference = this._state.variables.get(identifier);
575
- if (
576
- reference === undefined ||
577
- (!(reference instanceof Node) &&
578
- !(reference instanceof Unwind) &&
579
- !(reference instanceof Expression))
580
- ) {
581
- throw new Error(`Undefined node reference: ${identifier}`);
582
- }
583
- node = new NodeReference(node, reference);
584
- } else if (identifier !== null) {
585
- node.identifier = identifier;
586
- this._state.variables.set(identifier, node);
587
- }
588
- if (!this.token.isRightParenthesis()) {
589
- throw new Error("Expected closing parenthesis for node definition");
590
- }
591
- this.setNextToken();
592
- return node;
593
- }
594
-
595
- private *parseProperties(): Iterable<[string, Expression]> {
596
- let parts: number = 0;
597
- while (true) {
598
- this.skipWhitespaceAndComments();
599
- if (!this.token.isOpeningBrace() && parts == 0) {
600
- return;
601
- } else if (!this.token.isOpeningBrace() && parts > 0) {
602
- throw new Error("Expected opening brace");
603
- }
604
- this.setNextToken();
605
- this.skipWhitespaceAndComments();
606
- if (!this.token.isIdentifier()) {
607
- throw new Error("Expected identifier");
608
- }
609
- const key: string = this.token.value!;
610
- this.setNextToken();
611
- this.skipWhitespaceAndComments();
612
- if (!this.token.isColon()) {
613
- throw new Error("Expected colon");
614
- }
615
- this.setNextToken();
616
- this.skipWhitespaceAndComments();
617
- const expression: Expression | null = this.parseExpression();
618
- if (expression === null) {
619
- throw new Error("Expected expression");
620
- }
621
- this.skipWhitespaceAndComments();
622
- if (!this.token.isClosingBrace()) {
623
- throw new Error("Expected closing brace");
624
- }
625
- this.setNextToken();
626
- yield [key, expression];
627
- this.skipWhitespaceAndComments();
628
- if (!this.token.isComma()) {
629
- break;
630
- }
631
- this.setNextToken();
632
- parts++;
633
- }
634
- }
635
-
636
- private *parsePatterns(): IterableIterator<Pattern> {
637
- while (true) {
638
- let identifier: string | null = null;
639
- if (this.token.isIdentifier()) {
640
- identifier = this.token.value || "";
641
- this.setNextToken();
642
- this.skipWhitespaceAndComments();
643
- if (!this.token.isEquals()) {
644
- throw new Error("Expected '=' for pattern assignment");
645
- }
646
- this.setNextToken();
647
- this.skipWhitespaceAndComments();
648
- }
649
- const pattern: Pattern | null = this.parsePattern();
650
- if (pattern !== null) {
651
- if (identifier !== null) {
652
- pattern.identifier = identifier;
653
- this._state.variables.set(identifier, pattern);
654
- }
655
- yield pattern;
656
- } else {
657
- break;
658
- }
659
- this.skipWhitespaceAndComments();
660
- if (!this.token.isComma()) {
661
- break;
662
- }
663
- this.setNextToken();
664
- this.skipWhitespaceAndComments();
665
- }
666
- }
667
-
668
- private parsePattern(): Pattern | null {
669
- if (!this.token.isLeftParenthesis()) {
670
- return null;
671
- }
672
- const pattern = new Pattern();
673
- let node = this.parseNode();
674
- if (node === null) {
675
- throw new Error("Expected node definition");
676
- }
677
- pattern.addElement(node);
678
- let relationship: Relationship | null = null;
679
- while (true) {
680
- relationship = this.parseRelationship();
681
- if (relationship === null) {
682
- break;
683
- }
684
- pattern.addElement(relationship);
685
- node = this.parseNode();
686
- if (node === null) {
687
- throw new Error("Expected target node definition");
688
- }
689
- pattern.addElement(node);
690
- }
691
- return pattern;
692
- }
693
-
694
- private parsePatternExpression(): PatternExpression | null {
695
- if (!this.token.isLeftParenthesis()) {
696
- return null;
697
- }
698
- const pattern = new PatternExpression();
699
- let node = this.parseNode();
700
- if (node === null) {
701
- throw new Error("Expected node definition");
702
- }
703
- pattern.addElement(node);
704
- let relationship: Relationship | null = null;
705
- while (true) {
706
- relationship = this.parseRelationship();
707
- if (relationship === null) {
708
- break;
709
- }
710
- if (relationship.hops?.multi()) {
711
- throw new Error("PatternExpression does not support variable-length relationships");
712
- }
713
- pattern.addElement(relationship);
714
- node = this.parseNode();
715
- if (node === null) {
716
- throw new Error("Expected target node definition");
717
- }
718
- pattern.addElement(node);
719
- }
720
- pattern.verify();
721
- return pattern;
722
- }
723
-
724
- private parseRelationship(): Relationship | null {
725
- let direction: "left" | "right" = "right";
726
- if (this.token.isLessThan() && this.peek()?.isSubtract()) {
727
- direction = "left";
728
- this.setNextToken();
729
- this.setNextToken();
730
- } else if (this.token.isSubtract()) {
731
- this.setNextToken();
732
- } else {
733
- return null;
734
- }
735
- if (!this.token.isOpeningBracket()) {
736
- return null;
737
- }
738
- this.setNextToken();
739
- let variable: string | null = null;
740
- if (this.token.isIdentifierOrKeyword()) {
741
- variable = this.token.value || "";
742
- this.setNextToken();
743
- }
744
- if (!this.token.isColon()) {
745
- throw new Error("Expected ':' for relationship type");
746
- }
747
- this.setNextToken();
748
- if (!this.token.isIdentifierOrKeyword()) {
749
- throw new Error("Expected relationship type identifier");
750
- }
751
- const types: string[] = [this.token.value || ""];
752
- this.setNextToken();
753
- while (this.token.isPipe()) {
754
- this.setNextToken();
755
- if (this.token.isColon()) {
756
- this.setNextToken();
757
- }
758
- if (!this.token.isIdentifierOrKeyword()) {
759
- throw new Error("Expected relationship type identifier after '|'");
760
- }
761
- types.push(this.token.value || "");
762
- this.setNextToken();
763
- }
764
- const hops: Hops | null = this.parseRelationshipHops();
765
- const properties: Map<string, Expression> = new Map(this.parseProperties());
766
- if (!this.token.isClosingBracket()) {
767
- throw new Error("Expected closing bracket for relationship definition");
768
- }
769
- this.setNextToken();
770
- if (!this.token.isSubtract()) {
771
- throw new Error("Expected '-' for relationship definition");
772
- }
773
- this.setNextToken();
774
- if (this.token.isGreaterThan()) {
775
- this.setNextToken();
776
- }
777
- let relationship = new Relationship();
778
- relationship.direction = direction;
779
- relationship.properties = properties;
780
- if (variable !== null && this._state.variables.has(variable)) {
781
- let reference = this._state.variables.get(variable);
782
- // Resolve through Expression -> Reference -> Relationship (e.g., after WITH)
783
- if (reference instanceof Expression && reference.firstChild() instanceof Reference) {
784
- const inner = (reference.firstChild() as Reference).referred;
785
- if (inner instanceof Relationship) {
786
- reference = inner;
787
- }
788
- }
789
- if (reference === undefined || !(reference instanceof Relationship)) {
790
- throw new Error(`Undefined relationship reference: ${variable}`);
791
- }
792
- relationship = new RelationshipReference(relationship, reference);
793
- } else if (variable !== null) {
794
- relationship.identifier = variable;
795
- this._state.variables.set(variable, relationship);
796
- }
797
- if (hops !== null) {
798
- relationship.hops = hops;
799
- }
800
- relationship.types = types;
801
- return relationship;
802
- }
803
-
804
- private parseRelationshipHops(): Hops | null {
805
- if (!this.token.isMultiply()) {
806
- return null;
807
- }
808
- const hops = new Hops();
809
- this.setNextToken();
810
- if (this.token.isNumber()) {
811
- hops.min = parseInt(this.token.value || "0");
812
- this.setNextToken();
813
- if (this.token.isDot()) {
814
- this.setNextToken();
815
- if (!this.token.isDot()) {
816
- throw new Error("Expected '..' for relationship hops");
817
- }
818
- this.setNextToken();
819
- if (!this.token.isNumber()) {
820
- hops.max = Number.MAX_SAFE_INTEGER;
821
- } else {
822
- hops.max = parseInt(this.token.value || "0");
823
- this.setNextToken();
824
- }
825
- }
826
- } else {
827
- hops.min = 0;
828
- hops.max = Number.MAX_SAFE_INTEGER;
829
- }
830
- return hops;
831
- }
832
-
833
- private parseSubQuery(): ASTNode | null {
834
- if (!this.token.isOpeningBrace()) {
835
- return null;
836
- }
837
- this.setNextToken();
838
- this.expectAndSkipWhitespaceAndComments();
839
- const query: ASTNode = this._parseTokenized(true);
840
- this.skipWhitespaceAndComments();
841
- if (!this.token.isClosingBrace()) {
842
- throw new Error("Expected closing brace for sub-query");
843
- }
844
- this.setNextToken();
845
- return query;
846
- }
847
-
848
- private parseLimit(): Limit | null {
849
- this.skipWhitespaceAndComments();
850
- if (!this.token.isLimit()) {
851
- return null;
852
- }
853
- this.expectPreviousTokenToBeWhitespaceOrComment();
854
- this.setNextToken();
855
- this.expectAndSkipWhitespaceAndComments();
856
- if (!this.token.isNumber()) {
857
- throw new Error("Expected number");
858
- }
859
- const limit = new Limit(parseInt(this.token.value || "0"));
860
- this.setNextToken();
861
- return limit;
862
- }
863
-
864
- private parseOrderBy(): OrderBy | null {
865
- this.skipWhitespaceAndComments();
866
- if (!this.token.isOrder()) {
867
- return null;
868
- }
869
- this.expectPreviousTokenToBeWhitespaceOrComment();
870
- this.setNextToken();
871
- this.expectAndSkipWhitespaceAndComments();
872
- if (!this.token.isByKeyword()) {
873
- throw new Error("Expected BY after ORDER");
874
- }
875
- this.setNextToken();
876
- this.expectAndSkipWhitespaceAndComments();
877
- const fields: SortField[] = [];
878
- while (true) {
879
- const expression: Expression | null = this.parseExpression();
880
- if (expression === null) {
881
- throw new Error("Expected expression in ORDER BY");
882
- }
883
- this.skipWhitespaceAndComments();
884
- let direction: "asc" | "desc" = "asc";
885
- if (this.token.isAsc()) {
886
- direction = "asc";
887
- this.setNextToken();
888
- this.skipWhitespaceAndComments();
889
- } else if (this.token.isDesc()) {
890
- direction = "desc";
891
- this.setNextToken();
892
- this.skipWhitespaceAndComments();
893
- }
894
- fields.push({ direction, expression });
895
- if (this.token.isComma()) {
896
- this.setNextToken();
897
- this.skipWhitespaceAndComments();
898
- } else {
899
- break;
900
- }
901
- }
902
- return new OrderBy(fields);
903
- }
904
-
905
- /**
906
- * Parses a comma-separated list of expressions with deferred variable
907
- * registration. Aliases set by earlier expressions in the same clause
908
- * won't shadow variables needed by later expressions
909
- * (e.g. `RETURN a.x AS a, a.y AS b`).
910
- */
911
- private parseExpressions(alias_option: AliasOption = AliasOption.NOT_ALLOWED): Expression[] {
912
- const parsed = Array.from(this._parseExpressions(alias_option));
913
- for (const [expression, variableName] of parsed) {
914
- if (variableName !== null) {
915
- this._state.variables.set(variableName, expression);
916
- }
917
- }
918
- return parsed.map(([expression]) => expression);
919
- }
920
-
921
- private *_parseExpressions(
922
- alias_option: AliasOption
923
- ): IterableIterator<[Expression, string | null]> {
924
- while (true) {
925
- const expression: Expression | null = this.parseExpression();
926
- if (expression === null) {
927
- break;
928
- }
929
- let variableName: string | null = null;
930
- const alias = this.parseAlias();
931
- if (expression.firstChild() instanceof Reference && alias === null) {
932
- const reference: Reference = expression.firstChild() as Reference;
933
- expression.setAlias(reference.identifier);
934
- variableName = reference.identifier;
935
- } else if (
936
- alias_option === AliasOption.REQUIRED &&
937
- alias === null &&
938
- !(expression.firstChild() instanceof Reference)
939
- ) {
940
- throw new Error("Alias required");
941
- } else if (alias_option === AliasOption.NOT_ALLOWED && alias !== null) {
942
- throw new Error("Alias not allowed");
943
- } else if (
944
- [AliasOption.OPTIONAL, AliasOption.REQUIRED].includes(alias_option) &&
945
- alias !== null
946
- ) {
947
- expression.setAlias(alias.getAlias());
948
- variableName = alias.getAlias();
949
- }
950
- yield [expression, variableName];
951
- this.skipWhitespaceAndComments();
952
- if (!this.token.isComma()) {
953
- break;
954
- }
955
- this.setNextToken();
956
- }
957
- }
958
-
959
- /**
960
- * Parse a single operand (without operators).
961
- * @returns True if an operand was parsed, false otherwise.
962
- */
963
- private parseOperand(expression: Expression): boolean {
964
- this.skipWhitespaceAndComments();
965
- if (this.token.isIdentifierOrKeyword() && !this.peek()?.isLeftParenthesis()) {
966
- const identifier: string = this.token.value || "";
967
- const reference = new Reference(identifier, this._state.variables.get(identifier));
968
- this.setNextToken();
969
- const lookup = this.parseLookup(reference);
970
- expression.addNode(lookup);
971
- return true;
972
- } else if (this.token.isIdentifierOrKeyword() && this.peek()?.isLeftParenthesis()) {
973
- const func = this.parsePredicateFunction() || this.parseFunction();
974
- if (func !== null) {
975
- const lookup = this.parseLookup(func);
976
- expression.addNode(lookup);
977
- return true;
978
- }
979
- } else if (this.token.isLeftParenthesis() && this.looksLikeNodePattern()) {
980
- // Possible graph pattern expression
981
- const pattern = this.parsePatternExpression();
982
- if (pattern !== null) {
983
- expression.addNode(pattern);
984
- return true;
985
- }
986
- } else if (this.token.isOperand()) {
987
- expression.addNode(this.token.node);
988
- this.setNextToken();
989
- return true;
990
- } else if (this.token.isFString()) {
991
- const f_string = this.parseFString();
992
- if (f_string === null) {
993
- throw new Error("Expected f-string");
994
- }
995
- expression.addNode(f_string);
996
- return true;
997
- } else if (this.token.isLeftParenthesis()) {
998
- this.setNextToken();
999
- const sub = this.parseExpression();
1000
- if (sub === null) {
1001
- throw new Error("Expected expression");
1002
- }
1003
- if (!this.token.isRightParenthesis()) {
1004
- throw new Error("Expected right parenthesis");
1005
- }
1006
- this.setNextToken();
1007
- const lookup = this.parseLookup(sub);
1008
- expression.addNode(lookup);
1009
- return true;
1010
- } else if (this.token.isOpeningBrace() || this.token.isOpeningBracket()) {
1011
- const json = this.parseJSON();
1012
- if (json === null) {
1013
- throw new Error("Expected JSON object");
1014
- }
1015
- const lookup = this.parseLookup(json);
1016
- expression.addNode(lookup);
1017
- return true;
1018
- } else if (this.token.isCase()) {
1019
- const _case = this.parseCase();
1020
- if (_case === null) {
1021
- throw new Error("Expected CASE statement");
1022
- }
1023
- expression.addNode(_case);
1024
- return true;
1025
- } else if (this.token.isNot()) {
1026
- const not = new Not();
1027
- this.setNextToken();
1028
- // NOT should only bind to the next operand, not the entire expression
1029
- const tempExpr = new Expression();
1030
- if (!this.parseOperand(tempExpr)) {
1031
- throw new Error("Expected expression after NOT");
1032
- }
1033
- tempExpr.finish();
1034
- not.addChild(tempExpr);
1035
- expression.addNode(not);
1036
- return true;
1037
- }
1038
- return false;
1039
- }
1040
-
1041
- /**
1042
- * Peeks ahead from a left parenthesis to determine whether the
1043
- * upcoming tokens form a graph-node pattern (e.g. (n:Label), (n),
1044
- * (:Label), ()) rather than a parenthesised expression (e.g.
1045
- * (variable.property), (a + b)).
1046
- *
1047
- * The heuristic is:
1048
- * • ( followed by `:` or `)` → node pattern
1049
- * • ( identifier, then `:` or `{` or `)` → node pattern
1050
- * • anything else → parenthesised expression
1051
- */
1052
- private looksLikeNodePattern(): boolean {
1053
- const savedIndex = this.tokenIndex;
1054
- this.setNextToken(); // skip '('
1055
- this.skipWhitespaceAndComments();
1056
-
1057
- if (this.token.isColon() || this.token.isRightParenthesis()) {
1058
- this.tokenIndex = savedIndex;
1059
- return true;
1060
- }
1061
-
1062
- if (this.token.isIdentifierOrKeyword()) {
1063
- this.setNextToken(); // skip identifier
1064
- this.skipWhitespaceAndComments();
1065
- const result =
1066
- this.token.isColon() ||
1067
- this.token.isOpeningBrace() ||
1068
- this.token.isRightParenthesis();
1069
- this.tokenIndex = savedIndex;
1070
- return result;
1071
- }
1072
-
1073
- this.tokenIndex = savedIndex;
1074
- return false;
1075
- }
1076
-
1077
- private parseExpression(): Expression | null {
1078
- const expression = new Expression();
1079
- while (true) {
1080
- if (!this.parseOperand(expression)) {
1081
- if (expression.nodesAdded()) {
1082
- throw new Error("Expected operand or left parenthesis");
1083
- } else {
1084
- break;
1085
- }
1086
- }
1087
- this.skipWhitespaceAndComments();
1088
- if (this.token.isOperator()) {
1089
- if (this.token.isIs()) {
1090
- expression.addNode(this.parseIsOperator());
1091
- } else {
1092
- expression.addNode(this.token.node);
1093
- }
1094
- } else if (this.token.isIn()) {
1095
- expression.addNode(this.parseInOperator());
1096
- } else if (this.token.isContains()) {
1097
- expression.addNode(this.parseContainsOperator());
1098
- } else if (this.token.isStarts()) {
1099
- expression.addNode(this.parseStartsWithOperator());
1100
- } else if (this.token.isEnds()) {
1101
- expression.addNode(this.parseEndsWithOperator());
1102
- } else if (this.token.isNot()) {
1103
- const notOp = this.parseNotOperator();
1104
- if (notOp === null) {
1105
- break;
1106
- }
1107
- expression.addNode(notOp);
1108
- } else {
1109
- break;
1110
- }
1111
- this.setNextToken();
1112
- }
1113
- if (expression.nodesAdded()) {
1114
- expression.finish();
1115
- return expression;
1116
- }
1117
- return null;
1118
- }
1119
-
1120
- private parseIsOperator(): Is | IsNot {
1121
- // Current token is IS. Look ahead for NOT to produce IS NOT.
1122
- const savedIndex = this.tokenIndex;
1123
- this.setNextToken();
1124
- this.skipWhitespaceAndComments();
1125
- if (this.token.isNot()) {
1126
- return new IsNot();
1127
- }
1128
- // Not IS NOT — restore position to IS so the outer loop's setNextToken advances past it.
1129
- this.tokenIndex = savedIndex;
1130
- return new Is();
1131
- }
1132
-
1133
- private parseInOperator(): In | NotIn {
1134
- // Current token is IN. Advance past it so the outer loop's setNextToken moves correctly.
1135
- return new In();
1136
- }
1137
-
1138
- private parseContainsOperator(): Contains {
1139
- return new Contains();
1140
- }
1141
-
1142
- private parseStartsWithOperator(): StartsWith {
1143
- // Current token is STARTS. Look ahead for WITH.
1144
- const savedIndex = this.tokenIndex;
1145
- this.setNextToken();
1146
- this.skipWhitespaceAndComments();
1147
- if (this.token.isWith()) {
1148
- return new StartsWith();
1149
- }
1150
- this.tokenIndex = savedIndex;
1151
- throw new Error("Expected WITH after STARTS");
1152
- }
1153
-
1154
- private parseEndsWithOperator(): EndsWith {
1155
- // Current token is ENDS. Look ahead for WITH.
1156
- const savedIndex = this.tokenIndex;
1157
- this.setNextToken();
1158
- this.skipWhitespaceAndComments();
1159
- if (this.token.isWith()) {
1160
- return new EndsWith();
1161
- }
1162
- this.tokenIndex = savedIndex;
1163
- throw new Error("Expected WITH after ENDS");
1164
- }
1165
-
1166
- private parseNotOperator(): NotIn | NotContains | NotStartsWith | NotEndsWith | null {
1167
- // Current token is NOT. Look ahead for IN, CONTAINS, STARTS WITH, or ENDS WITH.
1168
- const savedIndex = this.tokenIndex;
1169
- this.setNextToken();
1170
- this.skipWhitespaceAndComments();
1171
- if (this.token.isIn()) {
1172
- return new NotIn();
1173
- }
1174
- if (this.token.isContains()) {
1175
- return new NotContains();
1176
- }
1177
- if (this.token.isStarts()) {
1178
- this.setNextToken();
1179
- this.skipWhitespaceAndComments();
1180
- if (this.token.isWith()) {
1181
- return new NotStartsWith();
1182
- }
1183
- this.tokenIndex = savedIndex;
1184
- return null;
1185
- }
1186
- if (this.token.isEnds()) {
1187
- this.setNextToken();
1188
- this.skipWhitespaceAndComments();
1189
- if (this.token.isWith()) {
1190
- return new NotEndsWith();
1191
- }
1192
- this.tokenIndex = savedIndex;
1193
- return null;
1194
- }
1195
- // Not a recognized NOT operator — restore position and let the outer loop break.
1196
- this.tokenIndex = savedIndex;
1197
- return null;
1198
- }
1199
-
1200
- private parseLookup(node: ASTNode): ASTNode {
1201
- let variable: ASTNode = node;
1202
- let lookup: Lookup | RangeLookup | null = null;
1203
- while (true) {
1204
- if (this.token.isDot()) {
1205
- this.setNextToken();
1206
- if (!this.token.isIdentifier() && !this.token.isKeyword()) {
1207
- throw new Error("Expected identifier");
1208
- }
1209
- lookup = new Lookup();
1210
- lookup.index = new Identifier(this.token.value || "");
1211
- lookup.variable = variable;
1212
- this.setNextToken();
1213
- } else if (this.token.isOpeningBracket()) {
1214
- this.setNextToken();
1215
- this.skipWhitespaceAndComments();
1216
- const index = this.parseExpression();
1217
- let to: Expression | null = null;
1218
- this.skipWhitespaceAndComments();
1219
- if (this.token.isColon()) {
1220
- this.setNextToken();
1221
- this.skipWhitespaceAndComments();
1222
- lookup = new RangeLookup();
1223
- to = this.parseExpression();
1224
- } else {
1225
- if (index === null) {
1226
- throw new Error("Expected expression");
1227
- }
1228
- lookup = new Lookup();
1229
- }
1230
- this.skipWhitespaceAndComments();
1231
- if (!this.token.isClosingBracket()) {
1232
- throw new Error("Expected closing bracket");
1233
- }
1234
- this.setNextToken();
1235
- if (lookup instanceof RangeLookup) {
1236
- lookup.from = index || new Null();
1237
- lookup.to = to || new Null();
1238
- } else if (lookup instanceof Lookup && index !== null) {
1239
- lookup.index = index;
1240
- }
1241
- lookup.variable = variable;
1242
- } else {
1243
- break;
1244
- }
1245
- variable = lookup || variable;
1246
- }
1247
- return variable;
1248
- }
1249
-
1250
- private parseCase(): Case | null {
1251
- if (!this.token.isCase()) {
1252
- return null;
1253
- }
1254
- this.setNextToken();
1255
- const _case = new Case();
1256
- let parts: number = 0;
1257
- this.expectAndSkipWhitespaceAndComments();
1258
- while (true) {
1259
- const when = this.parseWhen();
1260
- if (when === null && parts === 0) {
1261
- throw new Error("Expected WHEN");
1262
- } else if (when === null && parts > 0) {
1263
- break;
1264
- } else if (when !== null) {
1265
- _case.addChild(when);
1266
- }
1267
- this.expectAndSkipWhitespaceAndComments();
1268
- const then = this.parseThen();
1269
- if (then === null) {
1270
- throw new Error("Expected THEN");
1271
- } else {
1272
- _case.addChild(then);
1273
- }
1274
- this.expectAndSkipWhitespaceAndComments();
1275
- parts++;
1276
- }
1277
- const _else = this.parseElse();
1278
- if (_else === null) {
1279
- throw new Error("Expected ELSE");
1280
- } else {
1281
- _case.addChild(_else);
1282
- }
1283
- this.expectAndSkipWhitespaceAndComments();
1284
- if (!this.token.isEnd()) {
1285
- throw new Error("Expected END");
1286
- }
1287
- this.setNextToken();
1288
- return _case;
1289
- }
1290
-
1291
- private parseWhen(): When | null {
1292
- if (!this.token.isWhen()) {
1293
- return null;
1294
- }
1295
- this.setNextToken();
1296
- const when = new When();
1297
- this.expectAndSkipWhitespaceAndComments();
1298
- const expression = this.parseExpression();
1299
- if (expression === null) {
1300
- throw new Error("Expected expression");
1301
- }
1302
- when.addChild(expression);
1303
- return when;
1304
- }
1305
-
1306
- private parseThen(): Then | null {
1307
- if (!this.token.isThen()) {
1308
- return null;
1309
- }
1310
- this.setNextToken();
1311
- const then = new Then();
1312
- this.expectAndSkipWhitespaceAndComments();
1313
- const expression = this.parseExpression();
1314
- if (expression === null) {
1315
- throw new Error("Expected expression");
1316
- }
1317
- then.addChild(expression);
1318
- return then;
1319
- }
1320
-
1321
- private parseElse(): Else | null {
1322
- if (!this.token.isElse()) {
1323
- return null;
1324
- }
1325
- this.setNextToken();
1326
- const _else = new Else();
1327
- this.expectAndSkipWhitespaceAndComments();
1328
- const expression = this.parseExpression();
1329
- if (expression === null) {
1330
- throw new Error("Expected expression");
1331
- }
1332
- _else.addChild(expression);
1333
- return _else;
1334
- }
1335
-
1336
- private parseAlias(): Alias | null {
1337
- this.skipWhitespaceAndComments();
1338
- if (!this.token.isAs()) {
1339
- return null;
1340
- }
1341
- this.expectPreviousTokenToBeWhitespaceOrComment();
1342
- this.setNextToken();
1343
- this.expectAndSkipWhitespaceAndComments();
1344
- if ((!this.token.isIdentifier() && !this.token.isKeyword()) || this.token.value === null) {
1345
- throw new Error("Expected identifier");
1346
- }
1347
- const alias = new Alias(this.token.value || "");
1348
- this.setNextToken();
1349
- return alias;
1350
- }
1351
-
1352
- private parseFunction(): Function | null {
1353
- if (!this.token.isIdentifier()) {
1354
- return null;
1355
- }
1356
- if (this.token.value === null) {
1357
- throw new Error("Expected identifier");
1358
- }
1359
- if (!this.peek()?.isLeftParenthesis()) {
1360
- return null;
1361
- }
1362
- const func = FunctionFactory.create(this.token.value);
1363
- if (
1364
- func instanceof AggregateFunction &&
1365
- this._state.context.containsType(AggregateFunction)
1366
- ) {
1367
- throw new Error("Aggregate functions cannot be nested");
1368
- }
1369
- this._state.context.push(func);
1370
- this.setNextToken();
1371
- this.setNextToken();
1372
- this.skipWhitespaceAndComments();
1373
- if (this.token.isDistinct()) {
1374
- func.distinct = true;
1375
- this.setNextToken();
1376
- this.expectAndSkipWhitespaceAndComments();
1377
- }
1378
- func.parameters = this.parseExpressions(AliasOption.NOT_ALLOWED);
1379
- this.skipWhitespaceAndComments();
1380
- if (!this.token.isRightParenthesis()) {
1381
- throw new Error("Expected right parenthesis");
1382
- }
1383
- this.setNextToken();
1384
- this._state.context.pop();
1385
- return func;
1386
- }
1387
-
1388
- /**
1389
- * Parses an async function call for use in LOAD operations.
1390
- * Only matches if the identifier is registered as an async data provider.
1391
- *
1392
- * @returns An AsyncFunction node if a registered async function is found, otherwise null
1393
- */
1394
- private parseAsyncFunction(): AsyncFunction | null {
1395
- if (!this.token.isIdentifier()) {
1396
- return null;
1397
- }
1398
- if (this.token.value === null) {
1399
- return null;
1400
- }
1401
- // Only parse as async function if it's registered as an async provider
1402
- if (!FunctionFactory.isAsyncProvider(this.token.value)) {
1403
- return null;
1404
- }
1405
- if (!this.peek()?.isLeftParenthesis()) {
1406
- return null;
1407
- }
1408
- const asyncFunc = FunctionFactory.createAsync(this.token.value);
1409
- this.setNextToken(); // skip function name
1410
- this.setNextToken(); // skip left parenthesis
1411
- this.skipWhitespaceAndComments();
1412
- asyncFunc.parameters = this.parseExpressions(AliasOption.NOT_ALLOWED);
1413
- this.skipWhitespaceAndComments();
1414
- if (!this.token.isRightParenthesis()) {
1415
- throw new Error("Expected right parenthesis");
1416
- }
1417
- this.setNextToken();
1418
- return asyncFunc;
1419
- }
1420
-
1421
- private parsePredicateFunction(): PredicateFunction | null {
1422
- if (
1423
- !this.ahead([
1424
- Token.IDENTIFIER(""),
1425
- Token.LEFT_PARENTHESIS,
1426
- Token.IDENTIFIER(""),
1427
- Token.IN,
1428
- ])
1429
- ) {
1430
- return null;
1431
- }
1432
- if (this.token.value === null) {
1433
- throw new Error("Expected identifier");
1434
- }
1435
- const func = FunctionFactory.createPredicate(this.token.value);
1436
- this.setNextToken();
1437
- if (!this.token.isLeftParenthesis()) {
1438
- throw new Error("Expected left parenthesis");
1439
- }
1440
- this.setNextToken();
1441
- this.skipWhitespaceAndComments();
1442
- if (!this.token.isIdentifier()) {
1443
- throw new Error("Expected identifier");
1444
- }
1445
- const reference = new Reference(this.token.value);
1446
- this._state.variables.set(reference.identifier, reference);
1447
- func.addChild(reference);
1448
- this.setNextToken();
1449
- this.expectAndSkipWhitespaceAndComments();
1450
- if (!this.token.isIn()) {
1451
- throw new Error("Expected IN");
1452
- }
1453
- this.setNextToken();
1454
- this.expectAndSkipWhitespaceAndComments();
1455
- const expression = this.parseExpression();
1456
- if (expression === null) {
1457
- throw new Error("Expected expression");
1458
- }
1459
- if (
1460
- !ObjectUtils.isInstanceOfAny(expression.firstChild(), [
1461
- JSONArray,
1462
- Reference,
1463
- Lookup,
1464
- Function,
1465
- ])
1466
- ) {
1467
- throw new Error("Expected array or reference");
1468
- }
1469
- func.addChild(expression);
1470
- this.skipWhitespaceAndComments();
1471
- if (!this.token.isPipe()) {
1472
- throw new Error("Expected pipe");
1473
- }
1474
- this.setNextToken();
1475
- const _return = this.parseExpression();
1476
- if (_return === null) {
1477
- throw new Error("Expected expression");
1478
- }
1479
- func.addChild(_return);
1480
- const where = this.parseWhere();
1481
- if (where !== null) {
1482
- func.addChild(where);
1483
- }
1484
- this.skipWhitespaceAndComments();
1485
- if (!this.token.isRightParenthesis()) {
1486
- throw new Error("Expected right parenthesis");
1487
- }
1488
- this.setNextToken();
1489
- this._state.variables.delete(reference.identifier);
1490
- return func;
1491
- }
1492
-
1493
- private parseFString(): FString | null {
1494
- if (!this.token.isFString()) {
1495
- return null;
1496
- }
1497
- const f_string = new FString();
1498
- while (this.token.isFString()) {
1499
- if (this.token.value !== null) {
1500
- f_string.addChild(new String(this.token.value));
1501
- }
1502
- this.setNextToken();
1503
- if (this.token.isOpeningBrace()) {
1504
- this.setNextToken();
1505
- const expression = this.parseExpression();
1506
- if (expression === null) {
1507
- throw new Error("Expected expression");
1508
- }
1509
- f_string.addChild(expression);
1510
- if (!this.token.isClosingBrace()) {
1511
- throw new Error("Expected closing brace");
1512
- }
1513
- this.setNextToken();
1514
- } else {
1515
- break;
1516
- }
1517
- }
1518
- return f_string;
1519
- }
1520
-
1521
- private parseJSON(): AssociativeArray | JSONArray {
1522
- if (this.token.isOpeningBrace()) {
1523
- const array = this.parseAssociativeArray();
1524
- if (array === null) {
1525
- throw new Error("Expected associative array");
1526
- }
1527
- return array;
1528
- } else if (this.token.isOpeningBracket()) {
1529
- const array = this.parseJSONArray();
1530
- if (array === null) {
1531
- throw new Error("Expected JSON array");
1532
- }
1533
- return array;
1534
- }
1535
- throw new Error("Expected opening brace or bracket");
1536
- }
1537
-
1538
- private parseAssociativeArray(): AssociativeArray | null {
1539
- if (!this.token.isOpeningBrace()) {
1540
- return null;
1541
- }
1542
- const array = new AssociativeArray();
1543
- this.setNextToken();
1544
- while (true) {
1545
- this.skipWhitespaceAndComments();
1546
- if (this.token.isClosingBrace()) {
1547
- break;
1548
- }
1549
- if (!this.token.isIdentifier() && !this.token.isKeyword()) {
1550
- throw new Error("Expected identifier");
1551
- }
1552
- const key = this.token.value;
1553
- if (key === null) {
1554
- throw new Error("Expected string");
1555
- }
1556
- this.setNextToken();
1557
- this.skipWhitespaceAndComments();
1558
- if (!this.token.isColon()) {
1559
- throw new Error("Expected colon");
1560
- }
1561
- this.setNextToken();
1562
- this.skipWhitespaceAndComments();
1563
- const value = this.parseExpression();
1564
- if (value === null) {
1565
- throw new Error("Expected expression");
1566
- }
1567
- array.addKeyValue(new KeyValuePair(key, value));
1568
- this.skipWhitespaceAndComments();
1569
- if (this.token.isComma()) {
1570
- this.setNextToken();
1571
- }
1572
- }
1573
- this.setNextToken();
1574
- return array;
1575
- }
1576
-
1577
- private parseJSONArray(): JSONArray | null {
1578
- if (!this.token.isOpeningBracket()) {
1579
- return null;
1580
- }
1581
- const array = new JSONArray();
1582
- this.setNextToken();
1583
- while (true) {
1584
- this.skipWhitespaceAndComments();
1585
- if (this.token.isClosingBracket()) {
1586
- break;
1587
- }
1588
- const value = this.parseExpression();
1589
- if (value === null) {
1590
- throw new Error("Expected expression");
1591
- }
1592
- array.addValue(value);
1593
- this.skipWhitespaceAndComments();
1594
- if (this.token.isComma()) {
1595
- this.setNextToken();
1596
- }
1597
- }
1598
- this.setNextToken();
1599
- return array;
1600
- }
1601
-
1602
- private parseUnion(): Union | UnionAll | null {
1603
- if (!this.token.isUnion()) {
1604
- return null;
1605
- }
1606
- this.setNextToken();
1607
- this.skipWhitespaceAndComments();
1608
- let union: Union | UnionAll;
1609
- if (this.token.isAll()) {
1610
- union = new UnionAll();
1611
- this.setNextToken();
1612
- } else {
1613
- union = new Union();
1614
- }
1615
- return union;
1616
- }
1617
-
1618
- private expectAndSkipWhitespaceAndComments(): void {
1619
- const skipped = this.skipWhitespaceAndComments();
1620
- if (!skipped) {
1621
- throw new Error("Expected whitespace or comment");
1622
- }
1623
- }
1624
-
1625
- private skipWhitespaceAndComments(): boolean {
1626
- let skipped: boolean = this.previousToken.isWhitespaceOrComment();
1627
- while (this.token.isWhitespace() || this.token.isComment()) {
1628
- this.setNextToken();
1629
- skipped = true;
1630
- }
1631
- return skipped;
1632
- }
1633
-
1634
- private expectPreviousTokenToBeWhitespaceOrComment(): void {
1635
- if (!this.previousToken.isWhitespaceOrComment()) {
1636
- throw new Error("Expected whitespace or comment");
1637
- }
1638
- }
1639
- }
1640
-
1641
- export default Parser;