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,26 @@
|
|
|
1
|
+
"""Expression map for managing named expressions."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, List, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .expression import Expression
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExpressionMap:
|
|
10
|
+
"""Maps expression aliases to their corresponding Expression objects."""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self._map: dict[str, Expression] = {}
|
|
14
|
+
|
|
15
|
+
def get(self, alias: str) -> Optional['Expression']:
|
|
16
|
+
return self._map.get(alias)
|
|
17
|
+
|
|
18
|
+
def has(self, alias: str) -> bool:
|
|
19
|
+
return alias in self._map
|
|
20
|
+
|
|
21
|
+
def set_map(self, expressions: List['Expression']) -> None:
|
|
22
|
+
self._map.clear()
|
|
23
|
+
for expr in expressions:
|
|
24
|
+
if expr.alias is None:
|
|
25
|
+
continue
|
|
26
|
+
self._map[expr.alias] = expr
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Represents a formatted string (f-string) in the AST."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .expression import Expression
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FString(ASTNode):
|
|
12
|
+
"""Represents a formatted string (f-string) in the AST.
|
|
13
|
+
|
|
14
|
+
F-strings allow embedding expressions within string literals.
|
|
15
|
+
Child nodes represent the parts of the f-string (literal strings and expressions).
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
# For f"Hello {name}!"
|
|
19
|
+
fstr = FString()
|
|
20
|
+
fstr.add_child(String("Hello "))
|
|
21
|
+
fstr.add_child(name_expression)
|
|
22
|
+
fstr.add_child(String("!"))
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def value(self) -> str:
|
|
26
|
+
parts = self.get_children()
|
|
27
|
+
return "".join(str(part.value()) for part in parts)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Represents an identifier in the AST."""
|
|
2
|
+
|
|
3
|
+
from .string import String
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Identifier(String):
|
|
8
|
+
"""Represents an identifier in the AST.
|
|
9
|
+
|
|
10
|
+
Identifiers are used for variable names, property names, and similar constructs.
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
id = Identifier("myVariable")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __str__(self) -> str:
|
|
17
|
+
return f"Identifier ({self._value})"
|
|
18
|
+
|
|
19
|
+
def value(self) -> Any:
|
|
20
|
+
return super().value()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Represents a numeric literal in the AST."""
|
|
2
|
+
|
|
3
|
+
from ..ast_node import ASTNode
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Number(ASTNode):
|
|
7
|
+
"""Represents a numeric literal in the AST.
|
|
8
|
+
|
|
9
|
+
Parses string representations of numbers into integer or float values.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
num = Number("42")
|
|
13
|
+
print(num.value()) # 42
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, value: str):
|
|
17
|
+
"""Creates a new Number node by parsing the string value.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
value: The string representation of the number
|
|
21
|
+
"""
|
|
22
|
+
super().__init__()
|
|
23
|
+
if '.' in value:
|
|
24
|
+
self._value = float(value)
|
|
25
|
+
else:
|
|
26
|
+
self._value = int(value)
|
|
27
|
+
|
|
28
|
+
def value(self) -> float | int:
|
|
29
|
+
return self._value
|
|
30
|
+
|
|
31
|
+
def __str__(self) -> str:
|
|
32
|
+
return f"{self.__class__.__name__} ({self._value})"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Operator classes for FlowQuery expressions."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ..ast_node import ASTNode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Operator(ASTNode, ABC):
|
|
10
|
+
"""Base class for all operators in FlowQuery."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, precedence: int, left_associative: bool):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self._precedence = precedence
|
|
15
|
+
self._left_associative = left_associative
|
|
16
|
+
|
|
17
|
+
def is_operator(self) -> bool:
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def precedence(self) -> int:
|
|
22
|
+
return self._precedence
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def left_associative(self) -> bool:
|
|
26
|
+
return self._left_associative
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def value(self) -> Any:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def lhs(self) -> ASTNode:
|
|
34
|
+
return self.get_children()[0]
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def rhs(self) -> ASTNode:
|
|
38
|
+
return self.get_children()[1]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Add(Operator):
|
|
42
|
+
def __init__(self):
|
|
43
|
+
super().__init__(1, True)
|
|
44
|
+
|
|
45
|
+
def value(self) -> Any:
|
|
46
|
+
return self.lhs.value() + self.rhs.value()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Subtract(Operator):
|
|
50
|
+
def __init__(self):
|
|
51
|
+
super().__init__(1, True)
|
|
52
|
+
|
|
53
|
+
def value(self) -> Any:
|
|
54
|
+
return self.lhs.value() - self.rhs.value()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Multiply(Operator):
|
|
58
|
+
def __init__(self):
|
|
59
|
+
super().__init__(2, True)
|
|
60
|
+
|
|
61
|
+
def value(self) -> Any:
|
|
62
|
+
return self.lhs.value() * self.rhs.value()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Divide(Operator):
|
|
66
|
+
def __init__(self):
|
|
67
|
+
super().__init__(2, True)
|
|
68
|
+
|
|
69
|
+
def value(self) -> Any:
|
|
70
|
+
return self.lhs.value() / self.rhs.value()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Modulo(Operator):
|
|
74
|
+
def __init__(self):
|
|
75
|
+
super().__init__(2, True)
|
|
76
|
+
|
|
77
|
+
def value(self) -> Any:
|
|
78
|
+
return self.lhs.value() % self.rhs.value()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Power(Operator):
|
|
82
|
+
def __init__(self):
|
|
83
|
+
super().__init__(3, False)
|
|
84
|
+
|
|
85
|
+
def value(self) -> Any:
|
|
86
|
+
return self.lhs.value() ** self.rhs.value()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Equals(Operator):
|
|
90
|
+
def __init__(self):
|
|
91
|
+
super().__init__(0, True)
|
|
92
|
+
|
|
93
|
+
def value(self) -> int:
|
|
94
|
+
return 1 if self.lhs.value() == self.rhs.value() else 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class NotEquals(Operator):
|
|
98
|
+
def __init__(self):
|
|
99
|
+
super().__init__(0, True)
|
|
100
|
+
|
|
101
|
+
def value(self) -> int:
|
|
102
|
+
return 1 if self.lhs.value() != self.rhs.value() else 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class GreaterThan(Operator):
|
|
106
|
+
def __init__(self):
|
|
107
|
+
super().__init__(0, True)
|
|
108
|
+
|
|
109
|
+
def value(self) -> int:
|
|
110
|
+
return 1 if self.lhs.value() > self.rhs.value() else 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class LessThan(Operator):
|
|
114
|
+
def __init__(self):
|
|
115
|
+
super().__init__(0, True)
|
|
116
|
+
|
|
117
|
+
def value(self) -> int:
|
|
118
|
+
return 1 if self.lhs.value() < self.rhs.value() else 0
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class GreaterThanOrEqual(Operator):
|
|
122
|
+
def __init__(self):
|
|
123
|
+
super().__init__(0, True)
|
|
124
|
+
|
|
125
|
+
def value(self) -> int:
|
|
126
|
+
return 1 if self.lhs.value() >= self.rhs.value() else 0
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class LessThanOrEqual(Operator):
|
|
130
|
+
def __init__(self):
|
|
131
|
+
super().__init__(0, True)
|
|
132
|
+
|
|
133
|
+
def value(self) -> int:
|
|
134
|
+
return 1 if self.lhs.value() <= self.rhs.value() else 0
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class And(Operator):
|
|
138
|
+
def __init__(self):
|
|
139
|
+
super().__init__(-1, True)
|
|
140
|
+
|
|
141
|
+
def value(self) -> int:
|
|
142
|
+
return 1 if (self.lhs.value() and self.rhs.value()) else 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class Or(Operator):
|
|
146
|
+
def __init__(self):
|
|
147
|
+
super().__init__(-1, True)
|
|
148
|
+
|
|
149
|
+
def value(self) -> int:
|
|
150
|
+
return 1 if (self.lhs.value() or self.rhs.value()) else 0
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class Not(Operator):
|
|
154
|
+
def __init__(self):
|
|
155
|
+
super().__init__(0, True)
|
|
156
|
+
|
|
157
|
+
def is_operator(self) -> bool:
|
|
158
|
+
return False
|
|
159
|
+
|
|
160
|
+
def value(self) -> int:
|
|
161
|
+
return 1 if not self.lhs.value() else 0
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class Is(Operator):
|
|
165
|
+
def __init__(self):
|
|
166
|
+
super().__init__(-1, True)
|
|
167
|
+
|
|
168
|
+
def value(self) -> int:
|
|
169
|
+
return 1 if self.lhs.value() == self.rhs.value() else 0
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Represents a reference to a previously defined variable or expression."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
from .identifier import Identifier
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Reference(Identifier):
|
|
10
|
+
"""Represents a reference to a previously defined variable or expression.
|
|
11
|
+
|
|
12
|
+
References point to values defined earlier in the query (e.g., in WITH or LOAD statements).
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
ref = Reference("myVar", previous_node)
|
|
16
|
+
print(ref.value()) # Gets value from referred node
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, value: str, referred: Optional[ASTNode] = None):
|
|
20
|
+
"""Creates a new Reference to a variable.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
value: The identifier name
|
|
24
|
+
referred: The node this reference points to (optional)
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(value)
|
|
27
|
+
self._referred = referred
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def referred(self) -> Optional[ASTNode]:
|
|
31
|
+
return self._referred
|
|
32
|
+
|
|
33
|
+
@referred.setter
|
|
34
|
+
def referred(self, node: ASTNode) -> None:
|
|
35
|
+
self._referred = node
|
|
36
|
+
|
|
37
|
+
def __str__(self) -> str:
|
|
38
|
+
return f"Reference ({self._value})"
|
|
39
|
+
|
|
40
|
+
def value(self) -> Any:
|
|
41
|
+
if self._referred is not None:
|
|
42
|
+
return self._referred.value()
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def identifier(self) -> str:
|
|
47
|
+
return self._value
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Represents a string literal in the AST."""
|
|
2
|
+
|
|
3
|
+
from ..ast_node import ASTNode
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class String(ASTNode):
|
|
7
|
+
"""Represents a string literal in the AST.
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
s = String("hello")
|
|
11
|
+
print(s.value()) # "hello"
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, value: str):
|
|
15
|
+
"""Creates a new String node with the given value.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
value: The string value
|
|
19
|
+
"""
|
|
20
|
+
super().__init__()
|
|
21
|
+
self._value = value
|
|
22
|
+
|
|
23
|
+
def value(self) -> str:
|
|
24
|
+
return self._value
|
|
25
|
+
|
|
26
|
+
def __str__(self) -> str:
|
|
27
|
+
return f"String ({self._value})"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Functions module for FlowQuery parsing."""
|
|
2
|
+
|
|
3
|
+
from .function import Function
|
|
4
|
+
from .aggregate_function import AggregateFunction
|
|
5
|
+
from .async_function import AsyncFunction
|
|
6
|
+
from .predicate_function import PredicateFunction
|
|
7
|
+
from .reducer_element import ReducerElement
|
|
8
|
+
from .value_holder import ValueHolder
|
|
9
|
+
from .function_metadata import (
|
|
10
|
+
FunctionCategory,
|
|
11
|
+
ParameterSchema,
|
|
12
|
+
OutputSchema,
|
|
13
|
+
FunctionMetadata,
|
|
14
|
+
FunctionDef,
|
|
15
|
+
FunctionDefOptions,
|
|
16
|
+
get_registered_function_metadata,
|
|
17
|
+
get_registered_function_factory,
|
|
18
|
+
get_function_metadata,
|
|
19
|
+
)
|
|
20
|
+
from .function_factory import FunctionFactory
|
|
21
|
+
|
|
22
|
+
# Built-in functions
|
|
23
|
+
from .sum import Sum
|
|
24
|
+
from .avg import Avg
|
|
25
|
+
from .collect import Collect
|
|
26
|
+
from .join import Join
|
|
27
|
+
from .keys import Keys
|
|
28
|
+
from .rand import Rand
|
|
29
|
+
from .range_ import Range
|
|
30
|
+
from .replace import Replace
|
|
31
|
+
from .round_ import Round
|
|
32
|
+
from .size import Size
|
|
33
|
+
from .split import Split
|
|
34
|
+
from .stringify import Stringify
|
|
35
|
+
from .to_json import ToJson
|
|
36
|
+
from .type_ import Type
|
|
37
|
+
from .functions import Functions
|
|
38
|
+
from .predicate_sum import PredicateSum
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
# Base classes
|
|
42
|
+
"Function",
|
|
43
|
+
"AggregateFunction",
|
|
44
|
+
"AsyncFunction",
|
|
45
|
+
"PredicateFunction",
|
|
46
|
+
"ReducerElement",
|
|
47
|
+
"ValueHolder",
|
|
48
|
+
"FunctionCategory",
|
|
49
|
+
"ParameterSchema",
|
|
50
|
+
"OutputSchema",
|
|
51
|
+
"FunctionMetadata",
|
|
52
|
+
"FunctionDef",
|
|
53
|
+
"FunctionDefOptions",
|
|
54
|
+
"get_registered_function_metadata",
|
|
55
|
+
"get_registered_function_factory",
|
|
56
|
+
"get_function_metadata",
|
|
57
|
+
"FunctionFactory",
|
|
58
|
+
# Built-in functions
|
|
59
|
+
"Sum",
|
|
60
|
+
"Avg",
|
|
61
|
+
"Collect",
|
|
62
|
+
"Join",
|
|
63
|
+
"Keys",
|
|
64
|
+
"Rand",
|
|
65
|
+
"Range",
|
|
66
|
+
"Replace",
|
|
67
|
+
"Round",
|
|
68
|
+
"Size",
|
|
69
|
+
"Split",
|
|
70
|
+
"Stringify",
|
|
71
|
+
"ToJson",
|
|
72
|
+
"Type",
|
|
73
|
+
"Functions",
|
|
74
|
+
"PredicateSum",
|
|
75
|
+
]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Base class for aggregate functions that reduce multiple values to a single value."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from .function import Function
|
|
6
|
+
from .reducer_element import ReducerElement
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AggregateFunction(Function):
|
|
10
|
+
"""Base class for aggregate functions that reduce multiple values to a single value.
|
|
11
|
+
|
|
12
|
+
Aggregate functions like SUM, AVG, and COLLECT process multiple input values
|
|
13
|
+
and produce a single output. They cannot be nested within other aggregate functions.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
sum_func = Sum()
|
|
17
|
+
# Used in: RETURN SUM(values)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, name: Optional[str] = None):
|
|
21
|
+
"""Creates a new AggregateFunction with the given name.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
name: The function name
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(name)
|
|
27
|
+
self._overridden: Any = None
|
|
28
|
+
|
|
29
|
+
def reduce(self, value: ReducerElement) -> None:
|
|
30
|
+
"""Processes a value during the aggregation phase.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
value: The element to aggregate
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
NotImplementedError: If not implemented by subclass
|
|
37
|
+
"""
|
|
38
|
+
raise NotImplementedError("Method not implemented.")
|
|
39
|
+
|
|
40
|
+
def element(self) -> ReducerElement:
|
|
41
|
+
"""Creates a reducer element for this aggregate function.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
A ReducerElement instance
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
NotImplementedError: If not implemented by subclass
|
|
48
|
+
"""
|
|
49
|
+
raise NotImplementedError("Method not implemented.")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def overridden(self) -> Any:
|
|
53
|
+
return self._overridden
|
|
54
|
+
|
|
55
|
+
@overridden.setter
|
|
56
|
+
def overridden(self, value: Any) -> None:
|
|
57
|
+
self._overridden = value
|
|
58
|
+
|
|
59
|
+
def value(self) -> Any:
|
|
60
|
+
return self._overridden
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Represents an async data provider function call for use in LOAD operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, AsyncGenerator, List
|
|
4
|
+
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
|
+
from .function import Function
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncFunction(Function):
|
|
10
|
+
"""Represents an async data provider function call for use in LOAD operations.
|
|
11
|
+
|
|
12
|
+
This class holds the function name and arguments, and provides async iteration
|
|
13
|
+
over the results from a registered async data provider.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
# Used in: LOAD JSON FROM myDataSource('arg1', 'arg2') AS data
|
|
17
|
+
async_func = AsyncFunction("myDataSource")
|
|
18
|
+
async_func.parameters = [arg1_node, arg2_node]
|
|
19
|
+
async for item in async_func.execute():
|
|
20
|
+
print(item)
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def parameters(self) -> List[ASTNode]:
|
|
25
|
+
return self.children
|
|
26
|
+
|
|
27
|
+
@parameters.setter
|
|
28
|
+
def parameters(self, nodes: List[ASTNode]) -> None:
|
|
29
|
+
"""Sets the function parameters.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
nodes: Array of AST nodes representing the function arguments
|
|
33
|
+
"""
|
|
34
|
+
self.children = nodes
|
|
35
|
+
|
|
36
|
+
def get_arguments(self) -> List[Any]:
|
|
37
|
+
"""Evaluates all parameters and returns their values.
|
|
38
|
+
Used by the framework to pass arguments to generate().
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Array of parameter values
|
|
42
|
+
"""
|
|
43
|
+
return [child.value() for child in self.children]
|
|
44
|
+
|
|
45
|
+
async def generate(self, *args: Any) -> AsyncGenerator[Any, None]:
|
|
46
|
+
"""Generates the async data provider function results.
|
|
47
|
+
|
|
48
|
+
Subclasses override this method with their own typed parameters.
|
|
49
|
+
The framework automatically evaluates the AST children and spreads
|
|
50
|
+
them as arguments when calling this method.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
args: Arguments passed from the query (e.g., myFunc(arg1, arg2))
|
|
54
|
+
|
|
55
|
+
Yields:
|
|
56
|
+
Data items from the async provider
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
NotImplementedError: If the function is not registered as an async provider
|
|
60
|
+
"""
|
|
61
|
+
raise NotImplementedError("generate method must be overridden in subclasses.")
|
|
62
|
+
yield # Make this a generator
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Avg aggregate function."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from .aggregate_function import AggregateFunction
|
|
6
|
+
from .reducer_element import ReducerElement
|
|
7
|
+
from .function_metadata import FunctionDef
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AvgReducerElement(ReducerElement):
|
|
11
|
+
"""Reducer element for Avg aggregate function."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self._count: int = 0
|
|
15
|
+
self._sum: Optional[float] = None
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def value(self) -> Optional[float]:
|
|
19
|
+
if self._sum is None:
|
|
20
|
+
return None
|
|
21
|
+
return self._sum / self._count
|
|
22
|
+
|
|
23
|
+
@value.setter
|
|
24
|
+
def value(self, val: float) -> None:
|
|
25
|
+
self._count += 1
|
|
26
|
+
if self._sum is not None:
|
|
27
|
+
self._sum += val
|
|
28
|
+
else:
|
|
29
|
+
self._sum = val
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@FunctionDef({
|
|
33
|
+
"description": "Calculates the average of numeric values across grouped rows",
|
|
34
|
+
"category": "aggregate",
|
|
35
|
+
"parameters": [
|
|
36
|
+
{"name": "value", "description": "Numeric value to average", "type": "number"}
|
|
37
|
+
],
|
|
38
|
+
"output": {"description": "Average of all values", "type": "number", "example": 50},
|
|
39
|
+
"examples": ["WITH [10, 20, 30] AS nums UNWIND nums AS n RETURN avg(n)"]
|
|
40
|
+
})
|
|
41
|
+
class Avg(AggregateFunction):
|
|
42
|
+
"""Avg aggregate function.
|
|
43
|
+
|
|
44
|
+
Calculates the average of numeric values across grouped rows.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self):
|
|
48
|
+
super().__init__("avg")
|
|
49
|
+
self._expected_parameter_count = 1
|
|
50
|
+
|
|
51
|
+
def reduce(self, element: AvgReducerElement) -> None:
|
|
52
|
+
element.value = self.first_child().value()
|
|
53
|
+
|
|
54
|
+
def element(self) -> AvgReducerElement:
|
|
55
|
+
return AvgReducerElement()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Collect aggregate function."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Union
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from .aggregate_function import AggregateFunction
|
|
7
|
+
from .reducer_element import ReducerElement
|
|
8
|
+
from .function_metadata import FunctionDef
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CollectReducerElement(ReducerElement):
|
|
12
|
+
"""Reducer element for Collect aggregate function."""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self._value: List[Any] = []
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def value(self) -> Any:
|
|
19
|
+
return self._value
|
|
20
|
+
|
|
21
|
+
@value.setter
|
|
22
|
+
def value(self, val: Any) -> None:
|
|
23
|
+
self._value.append(val)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DistinctCollectReducerElement(ReducerElement):
|
|
27
|
+
"""Reducer element for Collect aggregate function with DISTINCT."""
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self._value: Dict[str, Any] = {}
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def value(self) -> Any:
|
|
34
|
+
return list(self._value.values())
|
|
35
|
+
|
|
36
|
+
@value.setter
|
|
37
|
+
def value(self, val: Any) -> None:
|
|
38
|
+
key: str = json.dumps(val, sort_keys=True, default=str)
|
|
39
|
+
if key not in self._value:
|
|
40
|
+
self._value[key] = val
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@FunctionDef({
|
|
44
|
+
"description": "Collects values into an array across grouped rows",
|
|
45
|
+
"category": "aggregate",
|
|
46
|
+
"parameters": [
|
|
47
|
+
{"name": "value", "description": "Value to collect", "type": "any"}
|
|
48
|
+
],
|
|
49
|
+
"output": {"description": "Array of collected values", "type": "array", "example": [1, 2, 3]},
|
|
50
|
+
"examples": ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN collect(n)"]
|
|
51
|
+
})
|
|
52
|
+
class Collect(AggregateFunction):
|
|
53
|
+
"""Collect aggregate function.
|
|
54
|
+
|
|
55
|
+
Collects values into an array across grouped rows.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(self):
|
|
59
|
+
super().__init__("collect")
|
|
60
|
+
self._expected_parameter_count = 1
|
|
61
|
+
self._distinct: bool = False
|
|
62
|
+
|
|
63
|
+
def reduce(self, element: CollectReducerElement) -> None:
|
|
64
|
+
element.value = self.first_child().value()
|
|
65
|
+
|
|
66
|
+
def element(self) -> Union[CollectReducerElement, DistinctCollectReducerElement]:
|
|
67
|
+
return DistinctCollectReducerElement() if self._distinct else CollectReducerElement()
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def distinct(self) -> bool:
|
|
71
|
+
return self._distinct
|
|
72
|
+
|
|
73
|
+
@distinct.setter
|
|
74
|
+
def distinct(self, val: bool) -> None:
|
|
75
|
+
self._distinct = val
|