flowquery 1.0.16 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/python-publish.yml +97 -0
- package/dist/compute/runner.d.ts +3 -2
- package/dist/compute/runner.d.ts.map +1 -1
- package/dist/compute/runner.js +7 -7
- package/dist/compute/runner.js.map +1 -1
- package/dist/flowquery.min.js +1 -1
- package/dist/graph/data.d.ts +31 -0
- package/dist/graph/data.d.ts.map +1 -0
- package/dist/graph/data.js +110 -0
- package/dist/graph/data.js.map +1 -0
- package/dist/graph/database.d.ts +20 -0
- package/dist/graph/database.d.ts.map +1 -0
- package/dist/graph/database.js +77 -0
- package/dist/graph/database.js.map +1 -0
- package/dist/graph/hops.d.ts +11 -0
- package/dist/graph/hops.d.ts.map +1 -0
- package/dist/graph/hops.js +25 -0
- package/dist/graph/hops.js.map +1 -0
- package/dist/graph/node.d.ts +35 -0
- package/dist/graph/node.d.ts.map +1 -0
- package/dist/graph/node.js +113 -0
- package/dist/graph/node.js.map +1 -0
- package/dist/graph/node_data.d.ts +11 -0
- package/dist/graph/node_data.d.ts.map +1 -0
- package/dist/graph/node_data.js +20 -0
- package/dist/graph/node_data.js.map +1 -0
- package/dist/graph/node_reference.d.ts +10 -0
- package/dist/graph/node_reference.d.ts.map +1 -0
- package/dist/graph/node_reference.js +52 -0
- package/dist/graph/node_reference.js.map +1 -0
- package/dist/graph/pattern.d.ts +18 -0
- package/dist/graph/pattern.d.ts.map +1 -0
- package/dist/graph/pattern.js +114 -0
- package/dist/graph/pattern.js.map +1 -0
- package/dist/graph/pattern_expression.d.ts +14 -0
- package/dist/graph/pattern_expression.d.ts.map +1 -0
- package/dist/graph/pattern_expression.js +58 -0
- package/dist/graph/pattern_expression.js.map +1 -0
- package/dist/graph/patterns.d.ts +11 -0
- package/dist/graph/patterns.d.ts.map +1 -0
- package/dist/graph/patterns.js +49 -0
- package/dist/graph/patterns.js.map +1 -0
- package/dist/graph/physical_node.d.ts +10 -0
- package/dist/graph/physical_node.d.ts.map +1 -0
- package/dist/graph/physical_node.js +40 -0
- package/dist/graph/physical_node.js.map +1 -0
- package/dist/graph/physical_relationship.d.ts +10 -0
- package/dist/graph/physical_relationship.d.ts.map +1 -0
- package/dist/graph/physical_relationship.js +40 -0
- package/dist/graph/physical_relationship.js.map +1 -0
- package/dist/graph/relationship.d.ts +40 -0
- package/dist/graph/relationship.d.ts.map +1 -0
- package/dist/graph/relationship.js +124 -0
- package/dist/graph/relationship.js.map +1 -0
- package/dist/graph/relationship_data.d.ts +12 -0
- package/dist/graph/relationship_data.d.ts.map +1 -0
- package/dist/graph/relationship_data.js +40 -0
- package/dist/graph/relationship_data.js.map +1 -0
- package/dist/graph/relationship_match_collector.d.ts +19 -0
- package/dist/graph/relationship_match_collector.d.ts.map +1 -0
- package/dist/graph/relationship_match_collector.js +55 -0
- package/dist/graph/relationship_match_collector.js.map +1 -0
- package/dist/graph/relationship_reference.d.ts +8 -0
- package/dist/graph/relationship_reference.d.ts.map +1 -0
- package/dist/graph/relationship_reference.js +37 -0
- package/dist/graph/relationship_reference.js.map +1 -0
- package/dist/parsing/base_parser.d.ts +1 -0
- package/dist/parsing/base_parser.d.ts.map +1 -1
- package/dist/parsing/base_parser.js +4 -1
- package/dist/parsing/base_parser.js.map +1 -1
- package/dist/parsing/context.d.ts +2 -2
- package/dist/parsing/context.js +5 -5
- package/dist/parsing/expressions/boolean.d.ts +8 -0
- package/dist/parsing/expressions/boolean.d.ts.map +1 -0
- package/dist/parsing/expressions/boolean.js +26 -0
- package/dist/parsing/expressions/boolean.js.map +1 -0
- package/dist/parsing/expressions/expression.d.ts +4 -1
- package/dist/parsing/expressions/expression.d.ts.map +1 -1
- package/dist/parsing/expressions/expression.js +15 -8
- package/dist/parsing/expressions/expression.js.map +1 -1
- package/dist/parsing/expressions/operator.d.ts +1 -1
- package/dist/parsing/expressions/operator.d.ts.map +1 -1
- package/dist/parsing/expressions/operator.js.map +1 -1
- package/dist/parsing/functions/function_factory.d.ts +13 -13
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +20 -18
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/operations/create_node.d.ts +14 -0
- package/dist/parsing/operations/create_node.d.ts.map +1 -0
- package/dist/parsing/operations/create_node.js +51 -0
- package/dist/parsing/operations/create_node.js.map +1 -0
- package/dist/parsing/operations/create_relationship.d.ts +14 -0
- package/dist/parsing/operations/create_relationship.d.ts.map +1 -0
- package/dist/parsing/operations/create_relationship.js +51 -0
- package/dist/parsing/operations/create_relationship.js.map +1 -0
- package/dist/parsing/operations/match.d.ts +15 -0
- package/dist/parsing/operations/match.d.ts.map +1 -0
- package/dist/parsing/operations/match.js +45 -0
- package/dist/parsing/operations/match.js.map +1 -0
- package/dist/parsing/operations/operation.d.ts +1 -0
- package/dist/parsing/operations/operation.d.ts.map +1 -1
- package/dist/parsing/operations/operation.js +6 -0
- package/dist/parsing/operations/operation.js.map +1 -1
- package/dist/parsing/operations/return.d.ts +1 -0
- package/dist/parsing/operations/return.d.ts.map +1 -1
- package/dist/parsing/operations/return.js +7 -1
- package/dist/parsing/operations/return.js.map +1 -1
- package/dist/parsing/operations/where.d.ts +1 -1
- package/dist/parsing/operations/where.d.ts.map +1 -1
- package/dist/parsing/operations/where.js +4 -0
- package/dist/parsing/operations/where.js.map +1 -1
- package/dist/parsing/parser.d.ts +10 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +344 -5
- package/dist/parsing/parser.js.map +1 -1
- package/dist/parsing/token_to_node.d.ts.map +1 -1
- package/dist/parsing/token_to_node.js +7 -0
- package/dist/parsing/token_to_node.js.map +1 -1
- package/dist/tokenization/keyword.d.ts +1 -0
- package/dist/tokenization/keyword.d.ts.map +1 -1
- package/dist/tokenization/keyword.js +1 -0
- package/dist/tokenization/keyword.js.map +1 -1
- package/dist/tokenization/token.d.ts +4 -0
- package/dist/tokenization/token.d.ts.map +1 -1
- package/dist/tokenization/token.js +14 -1
- package/dist/tokenization/token.js.map +1 -1
- package/dist/tokenization/token_type.d.ts +1 -0
- package/dist/tokenization/token_type.d.ts.map +1 -1
- package/dist/tokenization/token_type.js +1 -0
- package/dist/tokenization/token_type.js.map +1 -1
- package/dist/tokenization/tokenizer.d.ts +2 -1
- package/dist/tokenization/tokenizer.d.ts.map +1 -1
- package/dist/tokenization/tokenizer.js +25 -12
- package/dist/tokenization/tokenizer.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/README.md +166 -0
- package/flowquery-py/pyproject.toml +75 -0
- package/flowquery-py/setup_env.ps1 +92 -0
- package/flowquery-py/setup_env.sh +87 -0
- package/flowquery-py/src/__init__.py +34 -0
- package/flowquery-py/src/__main__.py +10 -0
- package/flowquery-py/src/compute/__init__.py +5 -0
- package/flowquery-py/src/compute/runner.py +60 -0
- package/flowquery-py/src/extensibility.py +52 -0
- package/flowquery-py/src/graph/__init__.py +31 -0
- package/flowquery-py/src/graph/data.py +118 -0
- package/flowquery-py/src/graph/database.py +82 -0
- package/flowquery-py/src/graph/hops.py +43 -0
- package/flowquery-py/src/graph/node.py +112 -0
- package/flowquery-py/src/graph/node_data.py +26 -0
- package/flowquery-py/src/graph/node_reference.py +49 -0
- package/flowquery-py/src/graph/pattern.py +125 -0
- package/flowquery-py/src/graph/pattern_expression.py +62 -0
- package/flowquery-py/src/graph/patterns.py +42 -0
- package/flowquery-py/src/graph/physical_node.py +40 -0
- package/flowquery-py/src/graph/physical_relationship.py +36 -0
- package/flowquery-py/src/graph/relationship.py +135 -0
- package/flowquery-py/src/graph/relationship_data.py +33 -0
- package/flowquery-py/src/graph/relationship_match_collector.py +77 -0
- package/flowquery-py/src/graph/relationship_reference.py +21 -0
- package/flowquery-py/src/io/__init__.py +5 -0
- package/flowquery-py/src/io/command_line.py +67 -0
- package/flowquery-py/src/parsing/__init__.py +17 -0
- package/flowquery-py/src/parsing/alias.py +20 -0
- package/flowquery-py/src/parsing/alias_option.py +11 -0
- package/flowquery-py/src/parsing/ast_node.py +146 -0
- package/flowquery-py/src/parsing/base_parser.py +84 -0
- package/flowquery-py/src/parsing/components/__init__.py +19 -0
- package/flowquery-py/src/parsing/components/csv.py +8 -0
- package/flowquery-py/src/parsing/components/from_.py +10 -0
- package/flowquery-py/src/parsing/components/headers.py +12 -0
- package/flowquery-py/src/parsing/components/json.py +8 -0
- package/flowquery-py/src/parsing/components/null.py +10 -0
- package/flowquery-py/src/parsing/components/post.py +8 -0
- package/flowquery-py/src/parsing/components/text.py +8 -0
- package/flowquery-py/src/parsing/context.py +50 -0
- package/flowquery-py/src/parsing/data_structures/__init__.py +15 -0
- package/flowquery-py/src/parsing/data_structures/associative_array.py +41 -0
- package/flowquery-py/src/parsing/data_structures/json_array.py +30 -0
- package/flowquery-py/src/parsing/data_structures/key_value_pair.py +38 -0
- package/flowquery-py/src/parsing/data_structures/lookup.py +49 -0
- package/flowquery-py/src/parsing/data_structures/range_lookup.py +42 -0
- package/flowquery-py/src/parsing/expressions/__init__.py +57 -0
- package/flowquery-py/src/parsing/expressions/boolean.py +20 -0
- package/flowquery-py/src/parsing/expressions/expression.py +138 -0
- package/flowquery-py/src/parsing/expressions/expression_map.py +26 -0
- package/flowquery-py/src/parsing/expressions/f_string.py +27 -0
- package/flowquery-py/src/parsing/expressions/identifier.py +20 -0
- package/flowquery-py/src/parsing/expressions/number.py +32 -0
- package/flowquery-py/src/parsing/expressions/operator.py +169 -0
- package/flowquery-py/src/parsing/expressions/reference.py +47 -0
- package/flowquery-py/src/parsing/expressions/string.py +27 -0
- package/flowquery-py/src/parsing/functions/__init__.py +75 -0
- package/flowquery-py/src/parsing/functions/aggregate_function.py +60 -0
- package/flowquery-py/src/parsing/functions/async_function.py +62 -0
- package/flowquery-py/src/parsing/functions/avg.py +55 -0
- package/flowquery-py/src/parsing/functions/collect.py +75 -0
- package/flowquery-py/src/parsing/functions/function.py +68 -0
- package/flowquery-py/src/parsing/functions/function_factory.py +173 -0
- package/flowquery-py/src/parsing/functions/function_metadata.py +149 -0
- package/flowquery-py/src/parsing/functions/functions.py +59 -0
- package/flowquery-py/src/parsing/functions/join.py +47 -0
- package/flowquery-py/src/parsing/functions/keys.py +34 -0
- package/flowquery-py/src/parsing/functions/predicate_function.py +46 -0
- package/flowquery-py/src/parsing/functions/predicate_sum.py +47 -0
- package/flowquery-py/src/parsing/functions/rand.py +28 -0
- package/flowquery-py/src/parsing/functions/range_.py +34 -0
- package/flowquery-py/src/parsing/functions/reducer_element.py +15 -0
- package/flowquery-py/src/parsing/functions/replace.py +37 -0
- package/flowquery-py/src/parsing/functions/round_.py +32 -0
- package/flowquery-py/src/parsing/functions/size.py +32 -0
- package/flowquery-py/src/parsing/functions/split.py +47 -0
- package/flowquery-py/src/parsing/functions/stringify.py +47 -0
- package/flowquery-py/src/parsing/functions/sum.py +51 -0
- package/flowquery-py/src/parsing/functions/to_json.py +33 -0
- package/flowquery-py/src/parsing/functions/type_.py +47 -0
- package/flowquery-py/src/parsing/functions/value_holder.py +24 -0
- package/flowquery-py/src/parsing/logic/__init__.py +15 -0
- package/flowquery-py/src/parsing/logic/case.py +29 -0
- package/flowquery-py/src/parsing/logic/else_.py +12 -0
- package/flowquery-py/src/parsing/logic/end.py +8 -0
- package/flowquery-py/src/parsing/logic/then.py +12 -0
- package/flowquery-py/src/parsing/logic/when.py +10 -0
- package/flowquery-py/src/parsing/operations/__init__.py +35 -0
- package/flowquery-py/src/parsing/operations/aggregated_return.py +24 -0
- package/flowquery-py/src/parsing/operations/aggregated_with.py +22 -0
- package/flowquery-py/src/parsing/operations/call.py +74 -0
- package/flowquery-py/src/parsing/operations/create_node.py +34 -0
- package/flowquery-py/src/parsing/operations/create_relationship.py +34 -0
- package/flowquery-py/src/parsing/operations/group_by.py +130 -0
- package/flowquery-py/src/parsing/operations/limit.py +22 -0
- package/flowquery-py/src/parsing/operations/load.py +140 -0
- package/flowquery-py/src/parsing/operations/match.py +29 -0
- package/flowquery-py/src/parsing/operations/operation.py +69 -0
- package/flowquery-py/src/parsing/operations/projection.py +21 -0
- package/flowquery-py/src/parsing/operations/return_op.py +50 -0
- package/flowquery-py/src/parsing/operations/unwind.py +37 -0
- package/flowquery-py/src/parsing/operations/where.py +41 -0
- package/flowquery-py/src/parsing/operations/with_op.py +18 -0
- package/flowquery-py/src/parsing/parser.py +1011 -0
- package/flowquery-py/src/parsing/token_to_node.py +109 -0
- package/flowquery-py/src/tokenization/__init__.py +23 -0
- package/flowquery-py/src/tokenization/keyword.py +48 -0
- package/flowquery-py/src/tokenization/operator.py +29 -0
- package/flowquery-py/src/tokenization/string_walker.py +158 -0
- package/flowquery-py/src/tokenization/symbol.py +19 -0
- package/flowquery-py/src/tokenization/token.py +659 -0
- package/flowquery-py/src/tokenization/token_mapper.py +52 -0
- package/flowquery-py/src/tokenization/token_type.py +21 -0
- package/flowquery-py/src/tokenization/tokenizer.py +214 -0
- package/flowquery-py/src/tokenization/trie.py +124 -0
- package/flowquery-py/src/utils/__init__.py +6 -0
- package/flowquery-py/src/utils/object_utils.py +20 -0
- package/flowquery-py/src/utils/string_utils.py +113 -0
- package/flowquery-py/tests/__init__.py +1 -0
- package/flowquery-py/tests/compute/__init__.py +1 -0
- package/flowquery-py/tests/compute/test_runner.py +1335 -0
- package/flowquery-py/tests/graph/__init__.py +1 -0
- package/flowquery-py/tests/graph/test_create.py +56 -0
- package/flowquery-py/tests/graph/test_data.py +73 -0
- package/flowquery-py/tests/graph/test_match.py +40 -0
- package/flowquery-py/tests/parsing/__init__.py +1 -0
- package/flowquery-py/tests/parsing/test_context.py +34 -0
- package/flowquery-py/tests/parsing/test_expression.py +49 -0
- package/flowquery-py/tests/parsing/test_parser.py +674 -0
- package/flowquery-py/tests/test_extensibility.py +611 -0
- package/flowquery-py/tests/tokenization/__init__.py +1 -0
- package/flowquery-py/tests/tokenization/test_token_mapper.py +60 -0
- package/flowquery-py/tests/tokenization/test_tokenizer.py +164 -0
- package/flowquery-py/tests/tokenization/test_trie.py +30 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/package.json +1 -1
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +76 -8
- package/misc/apps/RAG/src/components/index.ts +19 -10
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +70 -140
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
- package/package.json +1 -1
- package/src/compute/runner.ts +24 -19
- package/src/graph/data.ts +112 -0
- package/src/graph/database.ts +63 -0
- package/src/graph/hops.ts +22 -0
- package/src/graph/node.ts +99 -0
- package/src/graph/node_data.ts +18 -0
- package/src/graph/node_reference.ts +33 -0
- package/src/graph/pattern.ts +101 -0
- package/src/graph/pattern_expression.ts +37 -0
- package/src/graph/patterns.ts +36 -0
- package/src/graph/physical_node.ts +23 -0
- package/src/graph/physical_relationship.ts +23 -0
- package/src/graph/relationship.ts +116 -0
- package/src/graph/relationship_data.ts +27 -0
- package/src/graph/relationship_match_collector.ts +58 -0
- package/src/graph/relationship_reference.ts +24 -0
- package/src/parsing/base_parser.ts +20 -14
- package/src/parsing/context.ts +14 -14
- package/src/parsing/expressions/boolean.ts +21 -0
- package/src/parsing/expressions/expression.ts +34 -26
- package/src/parsing/expressions/operator.ts +19 -1
- package/src/parsing/functions/function_factory.ts +45 -45
- package/src/parsing/operations/create_node.ts +39 -0
- package/src/parsing/operations/create_relationship.ts +38 -0
- package/src/parsing/operations/match.ts +31 -0
- package/src/parsing/operations/operation.ts +3 -0
- package/src/parsing/operations/return.ts +11 -7
- package/src/parsing/operations/where.ts +10 -6
- package/src/parsing/parser.ts +346 -8
- package/src/parsing/token_to_node.ts +6 -0
- package/src/tokenization/keyword.ts +41 -40
- package/src/tokenization/token.ts +21 -1
- package/src/tokenization/token_type.ts +2 -1
- package/src/tokenization/tokenizer.ts +52 -31
- package/tests/compute/runner.test.ts +654 -0
- package/tests/extensibility.test.ts +97 -93
- package/tests/graph/create.test.ts +36 -0
- package/tests/graph/data.test.ts +58 -0
- package/tests/graph/match.test.ts +29 -0
- package/tests/parsing/parser.test.ts +273 -2
- package/tests/tokenization/tokenizer.test.ts +90 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Reducer element for aggregate functions."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReducerElement:
|
|
7
|
+
"""Base class for reducer elements used in aggregate functions."""
|
|
8
|
+
|
|
9
|
+
@property
|
|
10
|
+
def value(self) -> Any:
|
|
11
|
+
raise NotImplementedError("Method not implemented.")
|
|
12
|
+
|
|
13
|
+
@value.setter
|
|
14
|
+
def value(self, val: Any) -> None:
|
|
15
|
+
raise NotImplementedError("Method not implemented.")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Replace function."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .function import Function
|
|
7
|
+
from .function_metadata import FunctionDef
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@FunctionDef({
|
|
11
|
+
"description": "Replaces occurrences of a pattern in a string",
|
|
12
|
+
"category": "scalar",
|
|
13
|
+
"parameters": [
|
|
14
|
+
{"name": "text", "description": "Source string", "type": "string"},
|
|
15
|
+
{"name": "pattern", "description": "Pattern to find", "type": "string"},
|
|
16
|
+
{"name": "replacement", "description": "Replacement string", "type": "string"}
|
|
17
|
+
],
|
|
18
|
+
"output": {"description": "String with replacements", "type": "string", "example": "hello world"},
|
|
19
|
+
"examples": ["WITH 'hello there' AS s RETURN replace(s, 'there', 'world')"]
|
|
20
|
+
})
|
|
21
|
+
class Replace(Function):
|
|
22
|
+
"""Replace function.
|
|
23
|
+
|
|
24
|
+
Replaces occurrences of a pattern in a string.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("replace")
|
|
29
|
+
self._expected_parameter_count = 3
|
|
30
|
+
|
|
31
|
+
def value(self) -> Any:
|
|
32
|
+
text = self.get_children()[0].value()
|
|
33
|
+
pattern = self.get_children()[1].value()
|
|
34
|
+
replacement = self.get_children()[2].value()
|
|
35
|
+
if not isinstance(text, str) or not isinstance(pattern, str) or not isinstance(replacement, str):
|
|
36
|
+
raise ValueError("Invalid arguments for replace function")
|
|
37
|
+
return re.sub(re.escape(pattern), replacement, text)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Round function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .function import Function
|
|
6
|
+
from .function_metadata import FunctionDef
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@FunctionDef({
|
|
10
|
+
"description": "Rounds a number to the nearest integer",
|
|
11
|
+
"category": "scalar",
|
|
12
|
+
"parameters": [
|
|
13
|
+
{"name": "value", "description": "Number to round", "type": "number"}
|
|
14
|
+
],
|
|
15
|
+
"output": {"description": "Rounded integer", "type": "number", "example": 4},
|
|
16
|
+
"examples": ["WITH 3.7 AS n RETURN round(n)"]
|
|
17
|
+
})
|
|
18
|
+
class Round(Function):
|
|
19
|
+
"""Round function.
|
|
20
|
+
|
|
21
|
+
Rounds a number to the nearest integer.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super().__init__("round")
|
|
26
|
+
self._expected_parameter_count = 1
|
|
27
|
+
|
|
28
|
+
def value(self) -> Any:
|
|
29
|
+
val = self.get_children()[0].value()
|
|
30
|
+
if not isinstance(val, (int, float)):
|
|
31
|
+
raise ValueError("Invalid argument for round function")
|
|
32
|
+
return round(val)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Size function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .function import Function
|
|
6
|
+
from .function_metadata import FunctionDef
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@FunctionDef({
|
|
10
|
+
"description": "Returns the length of an array or string",
|
|
11
|
+
"category": "scalar",
|
|
12
|
+
"parameters": [
|
|
13
|
+
{"name": "value", "description": "Array or string to measure", "type": "array"}
|
|
14
|
+
],
|
|
15
|
+
"output": {"description": "Length of the input", "type": "number", "example": 3},
|
|
16
|
+
"examples": ["WITH [1, 2, 3] AS arr RETURN size(arr)"]
|
|
17
|
+
})
|
|
18
|
+
class Size(Function):
|
|
19
|
+
"""Size function.
|
|
20
|
+
|
|
21
|
+
Returns the length of an array or string.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super().__init__("size")
|
|
26
|
+
self._expected_parameter_count = 1
|
|
27
|
+
|
|
28
|
+
def value(self) -> Any:
|
|
29
|
+
val = self.get_children()[0].value()
|
|
30
|
+
if not isinstance(val, (list, str)):
|
|
31
|
+
raise ValueError("Invalid argument for size function")
|
|
32
|
+
return len(val)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Split function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, List
|
|
4
|
+
|
|
5
|
+
from .function import Function
|
|
6
|
+
from ..ast_node import ASTNode
|
|
7
|
+
from ..expressions.string import String
|
|
8
|
+
from .function_metadata import FunctionDef
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@FunctionDef({
|
|
12
|
+
"description": "Splits a string into an array by a delimiter",
|
|
13
|
+
"category": "scalar",
|
|
14
|
+
"parameters": [
|
|
15
|
+
{"name": "text", "description": "String to split", "type": "string"},
|
|
16
|
+
{"name": "delimiter", "description": "Delimiter to split by", "type": "string"}
|
|
17
|
+
],
|
|
18
|
+
"output": {"description": "Array of string parts", "type": "array", "items": {"type": "string"}, "example": ["a", "b", "c"]},
|
|
19
|
+
"examples": ["WITH 'a,b,c' AS s RETURN split(s, ',')"]
|
|
20
|
+
})
|
|
21
|
+
class Split(Function):
|
|
22
|
+
"""Split function.
|
|
23
|
+
|
|
24
|
+
Splits a string into an array by a delimiter.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("split")
|
|
29
|
+
self._expected_parameter_count = 2
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def parameters(self) -> List[ASTNode]:
|
|
33
|
+
return self.get_children()
|
|
34
|
+
|
|
35
|
+
@parameters.setter
|
|
36
|
+
def parameters(self, nodes: List[ASTNode]) -> None:
|
|
37
|
+
if len(nodes) == 1:
|
|
38
|
+
nodes.append(String(""))
|
|
39
|
+
for node in nodes:
|
|
40
|
+
self.add_child(node)
|
|
41
|
+
|
|
42
|
+
def value(self) -> Any:
|
|
43
|
+
text = self.get_children()[0].value()
|
|
44
|
+
delimiter = self.get_children()[1].value()
|
|
45
|
+
if not isinstance(text, str) or not isinstance(delimiter, str):
|
|
46
|
+
raise ValueError("Invalid arguments for split function")
|
|
47
|
+
return text.split(delimiter)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Stringify function."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, List
|
|
5
|
+
|
|
6
|
+
from .function import Function
|
|
7
|
+
from ..ast_node import ASTNode
|
|
8
|
+
from ..expressions.number import Number
|
|
9
|
+
from .function_metadata import FunctionDef
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@FunctionDef({
|
|
13
|
+
"description": "Converts a value to its JSON string representation",
|
|
14
|
+
"category": "scalar",
|
|
15
|
+
"parameters": [
|
|
16
|
+
{"name": "value", "description": "Value to stringify", "type": "any"}
|
|
17
|
+
],
|
|
18
|
+
"output": {"description": "JSON string", "type": "string", "example": '{"a":1}'},
|
|
19
|
+
"examples": ["WITH {a: 1} AS obj RETURN stringify(obj)"]
|
|
20
|
+
})
|
|
21
|
+
class Stringify(Function):
|
|
22
|
+
"""Stringify function.
|
|
23
|
+
|
|
24
|
+
Converts a value to its JSON string representation.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("stringify")
|
|
29
|
+
self._expected_parameter_count = 2
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def parameters(self) -> List[ASTNode]:
|
|
33
|
+
return self.get_children()
|
|
34
|
+
|
|
35
|
+
@parameters.setter
|
|
36
|
+
def parameters(self, nodes: List[ASTNode]) -> None:
|
|
37
|
+
if len(nodes) == 1:
|
|
38
|
+
nodes.append(Number("3")) # Default indent of 3
|
|
39
|
+
for node in nodes:
|
|
40
|
+
self.add_child(node)
|
|
41
|
+
|
|
42
|
+
def value(self) -> Any:
|
|
43
|
+
val = self.get_children()[0].value()
|
|
44
|
+
indent = int(self.get_children()[1].value())
|
|
45
|
+
if not isinstance(val, (dict, list)):
|
|
46
|
+
raise ValueError("Invalid argument for stringify function")
|
|
47
|
+
return json.dumps(val, indent=indent, default=str)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Sum aggregate function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .aggregate_function import AggregateFunction
|
|
6
|
+
from .reducer_element import ReducerElement
|
|
7
|
+
from .function_metadata import FunctionDef
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SumReducerElement(ReducerElement):
|
|
11
|
+
"""Reducer element for Sum aggregate function."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self._value: Any = None
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def value(self) -> Any:
|
|
18
|
+
return self._value
|
|
19
|
+
|
|
20
|
+
@value.setter
|
|
21
|
+
def value(self, val: Any) -> None:
|
|
22
|
+
if self._value is not None:
|
|
23
|
+
self._value += val
|
|
24
|
+
else:
|
|
25
|
+
self._value = val
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@FunctionDef({
|
|
29
|
+
"description": "Calculates the sum of numeric values across grouped rows",
|
|
30
|
+
"category": "aggregate",
|
|
31
|
+
"parameters": [
|
|
32
|
+
{"name": "value", "description": "Numeric value to sum", "type": "number"}
|
|
33
|
+
],
|
|
34
|
+
"output": {"description": "Sum of all values", "type": "number", "example": 150},
|
|
35
|
+
"examples": ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN sum(n)"]
|
|
36
|
+
})
|
|
37
|
+
class Sum(AggregateFunction):
|
|
38
|
+
"""Sum aggregate function.
|
|
39
|
+
|
|
40
|
+
Calculates the sum of numeric values across grouped rows.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
super().__init__("sum")
|
|
45
|
+
self._expected_parameter_count = 1
|
|
46
|
+
|
|
47
|
+
def reduce(self, element: SumReducerElement) -> None:
|
|
48
|
+
element.value = self.first_child().value()
|
|
49
|
+
|
|
50
|
+
def element(self) -> SumReducerElement:
|
|
51
|
+
return SumReducerElement()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""ToJson function."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .function import Function
|
|
7
|
+
from .function_metadata import FunctionDef
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@FunctionDef({
|
|
11
|
+
"description": "Parses a JSON string into an object",
|
|
12
|
+
"category": "scalar",
|
|
13
|
+
"parameters": [
|
|
14
|
+
{"name": "text", "description": "JSON string to parse", "type": "string"}
|
|
15
|
+
],
|
|
16
|
+
"output": {"description": "Parsed object or array", "type": "object", "example": {"a": 1}},
|
|
17
|
+
"examples": ["WITH '{\"a\": 1}' AS s RETURN tojson(s)"]
|
|
18
|
+
})
|
|
19
|
+
class ToJson(Function):
|
|
20
|
+
"""ToJson function.
|
|
21
|
+
|
|
22
|
+
Parses a JSON string into an object.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
super().__init__("tojson")
|
|
27
|
+
self._expected_parameter_count = 1
|
|
28
|
+
|
|
29
|
+
def value(self) -> Any:
|
|
30
|
+
text = self.get_children()[0].value()
|
|
31
|
+
if not isinstance(text, str):
|
|
32
|
+
raise ValueError("Invalid arguments for tojson function")
|
|
33
|
+
return json.loads(text)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Type function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .function import Function
|
|
6
|
+
from .function_metadata import FunctionDef
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@FunctionDef({
|
|
10
|
+
"description": "Returns the type of a value as a string",
|
|
11
|
+
"category": "scalar",
|
|
12
|
+
"parameters": [
|
|
13
|
+
{"name": "value", "description": "Value to check the type of", "type": "any"}
|
|
14
|
+
],
|
|
15
|
+
"output": {"description": "Type of the input value", "type": "string", "example": "string"},
|
|
16
|
+
"examples": [
|
|
17
|
+
"WITH 'hello' AS val RETURN type(val)",
|
|
18
|
+
"WITH 42 AS val RETURN type(val)",
|
|
19
|
+
"WITH [1, 2, 3] AS val RETURN type(val)"
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
class Type(Function):
|
|
23
|
+
"""Type function.
|
|
24
|
+
|
|
25
|
+
Returns the type of a value as a string.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
super().__init__("type")
|
|
30
|
+
self._expected_parameter_count = 1
|
|
31
|
+
|
|
32
|
+
def value(self) -> Any:
|
|
33
|
+
val = self.get_children()[0].value()
|
|
34
|
+
|
|
35
|
+
if val is None:
|
|
36
|
+
return "null"
|
|
37
|
+
if isinstance(val, list):
|
|
38
|
+
return "array"
|
|
39
|
+
if isinstance(val, dict):
|
|
40
|
+
return "object"
|
|
41
|
+
if isinstance(val, bool):
|
|
42
|
+
return "boolean"
|
|
43
|
+
if isinstance(val, (int, float)):
|
|
44
|
+
return "number"
|
|
45
|
+
if isinstance(val, str):
|
|
46
|
+
return "string"
|
|
47
|
+
return type(val).__name__
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Value holder node for FlowQuery AST."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ValueHolder(ASTNode):
|
|
9
|
+
"""Holds a value that can be set and retrieved."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self._holder: Any = None
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def holder(self) -> Any:
|
|
17
|
+
return self._holder
|
|
18
|
+
|
|
19
|
+
@holder.setter
|
|
20
|
+
def holder(self, value: Any) -> None:
|
|
21
|
+
self._holder = value
|
|
22
|
+
|
|
23
|
+
def value(self) -> Any:
|
|
24
|
+
return self._holder
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Represents a CASE expression in the AST."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
from .when import When
|
|
7
|
+
from .then import Then
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Case(ASTNode):
|
|
11
|
+
"""Represents a CASE expression in the AST."""
|
|
12
|
+
|
|
13
|
+
def value(self) -> Any:
|
|
14
|
+
i = 0
|
|
15
|
+
children = self.get_children()
|
|
16
|
+
child = children[i]
|
|
17
|
+
while isinstance(child, When):
|
|
18
|
+
then = children[i + 1]
|
|
19
|
+
if child.value():
|
|
20
|
+
return then.value()
|
|
21
|
+
i += 2
|
|
22
|
+
if i < len(children):
|
|
23
|
+
child = children[i]
|
|
24
|
+
else:
|
|
25
|
+
break
|
|
26
|
+
# Return the else clause if exists
|
|
27
|
+
if i < len(children):
|
|
28
|
+
return children[i].value()
|
|
29
|
+
return None
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Represents an ELSE clause in a CASE expression."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Else(ASTNode):
|
|
9
|
+
"""Represents an ELSE clause in a CASE expression."""
|
|
10
|
+
|
|
11
|
+
def value(self) -> Any:
|
|
12
|
+
return self.get_children()[0].value()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Represents a THEN clause in a CASE expression."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Then(ASTNode):
|
|
9
|
+
"""Represents a THEN clause in a CASE expression."""
|
|
10
|
+
|
|
11
|
+
def value(self) -> Any:
|
|
12
|
+
return self.get_children()[0].value()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Operations module for FlowQuery parsing."""
|
|
2
|
+
|
|
3
|
+
from .operation import Operation
|
|
4
|
+
from .projection import Projection
|
|
5
|
+
from .return_op import Return
|
|
6
|
+
from .with_op import With
|
|
7
|
+
from .unwind import Unwind
|
|
8
|
+
from .load import Load
|
|
9
|
+
from .where import Where
|
|
10
|
+
from .limit import Limit
|
|
11
|
+
from .aggregated_return import AggregatedReturn
|
|
12
|
+
from .aggregated_with import AggregatedWith
|
|
13
|
+
from .call import Call
|
|
14
|
+
from .group_by import GroupBy
|
|
15
|
+
from .match import Match
|
|
16
|
+
from .create_node import CreateNode
|
|
17
|
+
from .create_relationship import CreateRelationship
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Operation",
|
|
21
|
+
"Projection",
|
|
22
|
+
"Return",
|
|
23
|
+
"With",
|
|
24
|
+
"Unwind",
|
|
25
|
+
"Load",
|
|
26
|
+
"Where",
|
|
27
|
+
"Limit",
|
|
28
|
+
"AggregatedReturn",
|
|
29
|
+
"AggregatedWith",
|
|
30
|
+
"Call",
|
|
31
|
+
"GroupBy",
|
|
32
|
+
"Match",
|
|
33
|
+
"CreateNode",
|
|
34
|
+
"CreateRelationship",
|
|
35
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Represents an aggregated RETURN operation."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
|
+
|
|
5
|
+
from .return_op import Return
|
|
6
|
+
from .group_by import GroupBy
|
|
7
|
+
from ..expressions.expression import Expression
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AggregatedReturn(Return):
|
|
11
|
+
"""Represents an aggregated RETURN operation that groups and reduces values."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, expressions):
|
|
14
|
+
super().__init__(expressions)
|
|
15
|
+
self._group_by = GroupBy(self.children)
|
|
16
|
+
|
|
17
|
+
async def run(self) -> None:
|
|
18
|
+
await self._group_by.run()
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def results(self) -> List[Dict[str, Any]]:
|
|
22
|
+
if self._where is not None:
|
|
23
|
+
self._group_by.where = self._where
|
|
24
|
+
return list(self._group_by.generate_results())
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Represents an aggregated WITH operation."""
|
|
2
|
+
|
|
3
|
+
from .return_op import Return
|
|
4
|
+
from .group_by import GroupBy
|
|
5
|
+
from ..expressions.expression import Expression
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AggregatedWith(Return):
|
|
9
|
+
"""Represents an aggregated WITH operation that groups and reduces values."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, expressions):
|
|
12
|
+
super().__init__(expressions)
|
|
13
|
+
self._group_by = GroupBy(self.children)
|
|
14
|
+
|
|
15
|
+
async def run(self) -> None:
|
|
16
|
+
await self._group_by.run()
|
|
17
|
+
|
|
18
|
+
async def finish(self) -> None:
|
|
19
|
+
for _ in self._group_by.generate_results():
|
|
20
|
+
if self.next:
|
|
21
|
+
await self.next.run()
|
|
22
|
+
await super().finish()
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Represents a CALL operation for invoking async functions."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from ..expressions.expression import Expression
|
|
6
|
+
from ..expressions.expression_map import ExpressionMap
|
|
7
|
+
from ..functions.async_function import AsyncFunction
|
|
8
|
+
from .projection import Projection
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
DEFAULT_VARIABLE_NAME = "value"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Call(Projection):
|
|
15
|
+
"""Represents a CALL operation for invoking async functions."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__([])
|
|
19
|
+
self._function: Optional[AsyncFunction] = None
|
|
20
|
+
self._map = ExpressionMap()
|
|
21
|
+
self._results: List[Dict[str, Any]] = []
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def function(self) -> Optional[AsyncFunction]:
|
|
25
|
+
return self._function
|
|
26
|
+
|
|
27
|
+
@function.setter
|
|
28
|
+
def function(self, async_function: AsyncFunction) -> None:
|
|
29
|
+
self._function = async_function
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def yielded(self) -> List[Expression]:
|
|
33
|
+
return self.children
|
|
34
|
+
|
|
35
|
+
@yielded.setter
|
|
36
|
+
def yielded(self, expressions: List[Expression]) -> None:
|
|
37
|
+
self.children = expressions
|
|
38
|
+
self._map.set_map(expressions)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def has_yield(self) -> bool:
|
|
42
|
+
return len(self.children) > 0
|
|
43
|
+
|
|
44
|
+
async def run(self) -> None:
|
|
45
|
+
if self._function is None:
|
|
46
|
+
raise ValueError("No function set for Call operation.")
|
|
47
|
+
|
|
48
|
+
args = self._function.get_arguments()
|
|
49
|
+
async for item in self._function.generate(*args):
|
|
50
|
+
if not self.is_last:
|
|
51
|
+
if isinstance(item, dict):
|
|
52
|
+
for key, value in item.items():
|
|
53
|
+
expression = self._map.get(key)
|
|
54
|
+
if expression:
|
|
55
|
+
expression.overridden = value
|
|
56
|
+
else:
|
|
57
|
+
expression = self._map.get(DEFAULT_VARIABLE_NAME)
|
|
58
|
+
if expression:
|
|
59
|
+
expression.overridden = item
|
|
60
|
+
if self.next:
|
|
61
|
+
await self.next.run()
|
|
62
|
+
else:
|
|
63
|
+
record: Dict[str, Any] = {}
|
|
64
|
+
if isinstance(item, dict):
|
|
65
|
+
for key, value in item.items():
|
|
66
|
+
if self._map.has(key) or not self.has_yield:
|
|
67
|
+
record[key] = value
|
|
68
|
+
else:
|
|
69
|
+
record[DEFAULT_VARIABLE_NAME] = item
|
|
70
|
+
self._results.append(record)
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def results(self) -> List[Dict[str, Any]]:
|
|
74
|
+
return self._results
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Represents a CREATE operation for creating virtual nodes."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
|
+
|
|
5
|
+
from .operation import Operation
|
|
6
|
+
from ..ast_node import ASTNode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CreateNode(Operation):
|
|
10
|
+
"""Represents a CREATE operation for creating virtual nodes."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, node, statement: ASTNode):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self._node = node
|
|
15
|
+
self._statement = statement
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def node(self):
|
|
19
|
+
return self._node
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def statement(self) -> ASTNode:
|
|
23
|
+
return self._statement
|
|
24
|
+
|
|
25
|
+
async def run(self) -> None:
|
|
26
|
+
if self._node is None:
|
|
27
|
+
raise ValueError("Node is null")
|
|
28
|
+
from ...graph.database import Database
|
|
29
|
+
db = Database.get_instance()
|
|
30
|
+
db.add_node(self._node, self._statement)
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def results(self) -> List[Dict[str, Any]]:
|
|
34
|
+
return []
|