flowquery 1.0.18 → 1.0.21
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/.gitattributes +3 -0
- package/.github/workflows/python-publish.yml +56 -4
- package/.github/workflows/release.yml +26 -19
- package/.husky/pre-commit +26 -0
- package/README.md +37 -32
- package/dist/flowquery.min.js +1 -1
- package/dist/graph/data.d.ts +5 -4
- package/dist/graph/data.d.ts.map +1 -1
- package/dist/graph/data.js +38 -20
- package/dist/graph/data.js.map +1 -1
- package/dist/graph/node.d.ts +2 -0
- package/dist/graph/node.d.ts.map +1 -1
- package/dist/graph/node.js +23 -0
- package/dist/graph/node.js.map +1 -1
- package/dist/graph/node_data.js +1 -1
- package/dist/graph/node_data.js.map +1 -1
- package/dist/graph/pattern.d.ts.map +1 -1
- package/dist/graph/pattern.js +11 -4
- package/dist/graph/pattern.js.map +1 -1
- package/dist/graph/relationship.d.ts +6 -1
- package/dist/graph/relationship.d.ts.map +1 -1
- package/dist/graph/relationship.js +43 -5
- package/dist/graph/relationship.js.map +1 -1
- package/dist/graph/relationship_data.d.ts +2 -0
- package/dist/graph/relationship_data.d.ts.map +1 -1
- package/dist/graph/relationship_data.js +8 -1
- package/dist/graph/relationship_data.js.map +1 -1
- package/dist/graph/relationship_match_collector.js +2 -2
- package/dist/graph/relationship_match_collector.js.map +1 -1
- package/dist/graph/relationship_reference.d.ts.map +1 -1
- package/dist/graph/relationship_reference.js +2 -1
- package/dist/graph/relationship_reference.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/parsing/parser.d.ts +6 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +139 -72
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/misc/data/test.json +10 -0
- package/flowquery-py/misc/data/users.json +242 -0
- package/flowquery-py/notebooks/TestFlowQuery.ipynb +440 -0
- package/flowquery-py/pyproject.toml +48 -2
- package/flowquery-py/src/__init__.py +7 -5
- package/flowquery-py/src/compute/runner.py +14 -10
- package/flowquery-py/src/extensibility.py +8 -8
- package/flowquery-py/src/graph/__init__.py +7 -7
- package/flowquery-py/src/graph/data.py +38 -20
- package/flowquery-py/src/graph/database.py +10 -20
- package/flowquery-py/src/graph/node.py +50 -19
- package/flowquery-py/src/graph/node_data.py +1 -1
- package/flowquery-py/src/graph/node_reference.py +10 -11
- package/flowquery-py/src/graph/pattern.py +27 -37
- package/flowquery-py/src/graph/pattern_expression.py +13 -11
- package/flowquery-py/src/graph/patterns.py +2 -2
- package/flowquery-py/src/graph/physical_node.py +4 -3
- package/flowquery-py/src/graph/physical_relationship.py +5 -5
- package/flowquery-py/src/graph/relationship.py +62 -14
- package/flowquery-py/src/graph/relationship_data.py +7 -2
- package/flowquery-py/src/graph/relationship_match_collector.py +15 -10
- package/flowquery-py/src/graph/relationship_reference.py +4 -4
- package/flowquery-py/src/io/command_line.py +13 -14
- package/flowquery-py/src/parsing/__init__.py +2 -2
- package/flowquery-py/src/parsing/alias_option.py +1 -1
- package/flowquery-py/src/parsing/ast_node.py +21 -20
- package/flowquery-py/src/parsing/base_parser.py +7 -7
- package/flowquery-py/src/parsing/components/__init__.py +3 -3
- package/flowquery-py/src/parsing/components/from_.py +3 -1
- package/flowquery-py/src/parsing/components/headers.py +2 -2
- package/flowquery-py/src/parsing/components/null.py +2 -2
- package/flowquery-py/src/parsing/context.py +7 -7
- package/flowquery-py/src/parsing/data_structures/associative_array.py +7 -7
- package/flowquery-py/src/parsing/data_structures/json_array.py +3 -3
- package/flowquery-py/src/parsing/data_structures/key_value_pair.py +4 -4
- package/flowquery-py/src/parsing/data_structures/lookup.py +2 -2
- package/flowquery-py/src/parsing/data_structures/range_lookup.py +2 -2
- package/flowquery-py/src/parsing/expressions/__init__.py +16 -16
- package/flowquery-py/src/parsing/expressions/expression.py +16 -13
- package/flowquery-py/src/parsing/expressions/expression_map.py +9 -9
- package/flowquery-py/src/parsing/expressions/f_string.py +3 -3
- package/flowquery-py/src/parsing/expressions/identifier.py +4 -3
- package/flowquery-py/src/parsing/expressions/number.py +3 -3
- package/flowquery-py/src/parsing/expressions/operator.py +16 -16
- package/flowquery-py/src/parsing/expressions/reference.py +3 -3
- package/flowquery-py/src/parsing/expressions/string.py +2 -2
- package/flowquery-py/src/parsing/functions/__init__.py +17 -17
- package/flowquery-py/src/parsing/functions/aggregate_function.py +8 -8
- package/flowquery-py/src/parsing/functions/async_function.py +12 -9
- package/flowquery-py/src/parsing/functions/avg.py +4 -4
- package/flowquery-py/src/parsing/functions/collect.py +6 -6
- package/flowquery-py/src/parsing/functions/function.py +6 -6
- package/flowquery-py/src/parsing/functions/function_factory.py +31 -34
- package/flowquery-py/src/parsing/functions/function_metadata.py +10 -11
- package/flowquery-py/src/parsing/functions/functions.py +14 -6
- package/flowquery-py/src/parsing/functions/join.py +3 -3
- package/flowquery-py/src/parsing/functions/keys.py +3 -3
- package/flowquery-py/src/parsing/functions/predicate_function.py +8 -7
- package/flowquery-py/src/parsing/functions/predicate_sum.py +12 -7
- package/flowquery-py/src/parsing/functions/rand.py +2 -2
- package/flowquery-py/src/parsing/functions/range_.py +9 -4
- package/flowquery-py/src/parsing/functions/replace.py +2 -2
- package/flowquery-py/src/parsing/functions/round_.py +2 -2
- package/flowquery-py/src/parsing/functions/size.py +2 -2
- package/flowquery-py/src/parsing/functions/split.py +9 -4
- package/flowquery-py/src/parsing/functions/stringify.py +3 -3
- package/flowquery-py/src/parsing/functions/sum.py +4 -4
- package/flowquery-py/src/parsing/functions/to_json.py +2 -2
- package/flowquery-py/src/parsing/functions/type_.py +3 -3
- package/flowquery-py/src/parsing/functions/value_holder.py +1 -1
- package/flowquery-py/src/parsing/logic/__init__.py +2 -2
- package/flowquery-py/src/parsing/logic/case.py +0 -1
- package/flowquery-py/src/parsing/logic/when.py +3 -1
- package/flowquery-py/src/parsing/operations/__init__.py +10 -10
- package/flowquery-py/src/parsing/operations/aggregated_return.py +3 -5
- package/flowquery-py/src/parsing/operations/aggregated_with.py +4 -4
- package/flowquery-py/src/parsing/operations/call.py +6 -7
- package/flowquery-py/src/parsing/operations/create_node.py +5 -4
- package/flowquery-py/src/parsing/operations/create_relationship.py +5 -4
- package/flowquery-py/src/parsing/operations/group_by.py +18 -16
- package/flowquery-py/src/parsing/operations/load.py +21 -19
- package/flowquery-py/src/parsing/operations/match.py +8 -7
- package/flowquery-py/src/parsing/operations/operation.py +3 -3
- package/flowquery-py/src/parsing/operations/projection.py +6 -6
- package/flowquery-py/src/parsing/operations/return_op.py +9 -5
- package/flowquery-py/src/parsing/operations/unwind.py +3 -2
- package/flowquery-py/src/parsing/operations/where.py +9 -7
- package/flowquery-py/src/parsing/operations/with_op.py +2 -2
- package/flowquery-py/src/parsing/parser.py +178 -114
- package/flowquery-py/src/parsing/token_to_node.py +2 -2
- package/flowquery-py/src/tokenization/__init__.py +4 -4
- package/flowquery-py/src/tokenization/keyword.py +1 -1
- package/flowquery-py/src/tokenization/operator.py +1 -1
- package/flowquery-py/src/tokenization/string_walker.py +4 -4
- package/flowquery-py/src/tokenization/symbol.py +1 -1
- package/flowquery-py/src/tokenization/token.py +11 -11
- package/flowquery-py/src/tokenization/token_mapper.py +10 -9
- package/flowquery-py/src/tokenization/token_type.py +1 -1
- package/flowquery-py/src/tokenization/tokenizer.py +19 -19
- package/flowquery-py/src/tokenization/trie.py +18 -17
- package/flowquery-py/src/utils/__init__.py +1 -1
- package/flowquery-py/src/utils/object_utils.py +3 -3
- package/flowquery-py/src/utils/string_utils.py +12 -12
- package/flowquery-py/tests/compute/test_runner.py +214 -7
- package/flowquery-py/tests/parsing/test_parser.py +41 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/graph/data.ts +38 -20
- package/src/graph/node.ts +23 -0
- package/src/graph/node_data.ts +1 -1
- package/src/graph/pattern.ts +13 -4
- package/src/graph/relationship.ts +45 -5
- package/src/graph/relationship_data.ts +8 -1
- package/src/graph/relationship_match_collector.ts +1 -1
- package/src/graph/relationship_reference.ts +2 -1
- package/src/index.ts +5 -5
- package/src/parsing/parser.ts +139 -71
- package/tests/compute/runner.test.ts +249 -79
- package/tests/parsing/parser.test.ts +32 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"""Function metadata and decorator for FlowQuery functions."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Callable, Dict, List, Optional, TypedDict, Union
|
|
4
3
|
from dataclasses import dataclass
|
|
5
|
-
|
|
4
|
+
from typing import Any, Callable, Dict, List, Optional, TypedDict, cast
|
|
6
5
|
|
|
7
6
|
# Type definitions
|
|
8
7
|
FunctionCategory = str # "scalar" | "aggregate" | "predicate" | "async" | string
|
|
@@ -54,7 +53,7 @@ class FunctionDefOptions(TypedDict, total=False):
|
|
|
54
53
|
|
|
55
54
|
class FunctionRegistry:
|
|
56
55
|
"""Centralized registry for function metadata, factories, and async providers."""
|
|
57
|
-
|
|
56
|
+
|
|
58
57
|
_metadata: Dict[str, FunctionMetadata] = {}
|
|
59
58
|
_factories: Dict[str, Callable[[], Any]] = {}
|
|
60
59
|
|
|
@@ -71,15 +70,15 @@ class FunctionRegistry:
|
|
|
71
70
|
description=options.get('description', ''),
|
|
72
71
|
category=options.get('category', 'scalar'),
|
|
73
72
|
parameters=options.get('parameters', []),
|
|
74
|
-
output=options.get('output', {'description': '', 'type': 'any'}),
|
|
73
|
+
output=cast(OutputSchema, options.get('output', {'description': '', 'type': 'any'})),
|
|
75
74
|
examples=options.get('examples'),
|
|
76
75
|
notes=options.get('notes'),
|
|
77
76
|
)
|
|
78
77
|
cls._metadata[registry_key] = metadata
|
|
79
78
|
|
|
80
79
|
if category != 'predicate':
|
|
81
|
-
cls._factories[display_name] = lambda c=constructor: c()
|
|
82
|
-
cls._factories[registry_key] = lambda c=constructor: c()
|
|
80
|
+
cls._factories[display_name] = lambda c=constructor: c() # type: ignore[misc]
|
|
81
|
+
cls._factories[registry_key] = lambda c=constructor: c() # type: ignore[misc]
|
|
83
82
|
|
|
84
83
|
@classmethod
|
|
85
84
|
def get_all_metadata(cls) -> List[FunctionMetadata]:
|
|
@@ -103,17 +102,17 @@ class FunctionRegistry:
|
|
|
103
102
|
return cls._factories.get(lower_name)
|
|
104
103
|
|
|
105
104
|
|
|
106
|
-
def FunctionDef(options: FunctionDefOptions):
|
|
105
|
+
def FunctionDef(options: FunctionDefOptions) -> Callable[[type], type]:
|
|
107
106
|
"""Class decorator that registers function metadata.
|
|
108
|
-
|
|
107
|
+
|
|
109
108
|
The function name is derived from the class's constructor.
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
Args:
|
|
112
111
|
options: Function metadata (excluding name)
|
|
113
|
-
|
|
112
|
+
|
|
114
113
|
Returns:
|
|
115
114
|
Class decorator
|
|
116
|
-
|
|
115
|
+
|
|
117
116
|
Example:
|
|
118
117
|
@FunctionDef({
|
|
119
118
|
'description': "Adds two numbers",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Functions introspection function."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from .function import Function
|
|
6
6
|
from .function_factory import FunctionFactory
|
|
@@ -8,10 +8,18 @@ from .function_metadata import FunctionDef
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@FunctionDef({
|
|
11
|
-
"description":
|
|
11
|
+
"description": (
|
|
12
|
+
"Lists all registered functions with their metadata. "
|
|
13
|
+
"Useful for discovering available functions and their documentation."
|
|
14
|
+
),
|
|
12
15
|
"category": "scalar",
|
|
13
16
|
"parameters": [
|
|
14
|
-
{
|
|
17
|
+
{
|
|
18
|
+
"name": "category",
|
|
19
|
+
"description": "Optional category to filter by (e.g., 'aggregation', 'string', 'math')",
|
|
20
|
+
"type": "string",
|
|
21
|
+
"required": False
|
|
22
|
+
}
|
|
15
23
|
],
|
|
16
24
|
"output": {
|
|
17
25
|
"description": "Array of function metadata objects",
|
|
@@ -35,17 +43,17 @@ from .function_metadata import FunctionDef
|
|
|
35
43
|
})
|
|
36
44
|
class Functions(Function):
|
|
37
45
|
"""Functions introspection function.
|
|
38
|
-
|
|
46
|
+
|
|
39
47
|
Lists all registered functions with their metadata.
|
|
40
48
|
"""
|
|
41
49
|
|
|
42
|
-
def __init__(self):
|
|
50
|
+
def __init__(self) -> None:
|
|
43
51
|
super().__init__("functions")
|
|
44
52
|
self._expected_parameter_count = None # 0 or 1 parameter
|
|
45
53
|
|
|
46
54
|
def value(self) -> Any:
|
|
47
55
|
children = self.get_children()
|
|
48
|
-
|
|
56
|
+
|
|
49
57
|
if len(children) == 0:
|
|
50
58
|
# Return all functions
|
|
51
59
|
return FunctionFactory.list_functions()
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, List
|
|
4
4
|
|
|
5
|
-
from .function import Function
|
|
6
5
|
from ..ast_node import ASTNode
|
|
7
6
|
from ..expressions.string import String
|
|
7
|
+
from .function import Function
|
|
8
8
|
from .function_metadata import FunctionDef
|
|
9
9
|
|
|
10
10
|
|
|
@@ -20,11 +20,11 @@ from .function_metadata import FunctionDef
|
|
|
20
20
|
})
|
|
21
21
|
class Join(Function):
|
|
22
22
|
"""Join function.
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
Joins an array of strings with a delimiter.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self):
|
|
27
|
+
def __init__(self) -> None:
|
|
28
28
|
super().__init__("join")
|
|
29
29
|
self._expected_parameter_count = 2
|
|
30
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Keys function."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from .function import Function
|
|
6
6
|
from .function_metadata import FunctionDef
|
|
@@ -17,11 +17,11 @@ from .function_metadata import FunctionDef
|
|
|
17
17
|
})
|
|
18
18
|
class Keys(Function):
|
|
19
19
|
"""Keys function.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
Returns the keys of an object (associative array) as an array.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
def __init__(self):
|
|
24
|
+
def __init__(self) -> None:
|
|
25
25
|
super().__init__("keys")
|
|
26
26
|
self._expected_parameter_count = 1
|
|
27
27
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""Base class for predicate functions in FlowQuery."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
4
4
|
|
|
5
5
|
from ..ast_node import ASTNode
|
|
6
|
-
from ..expressions.expression import Expression
|
|
7
|
-
from ..expressions.reference import Reference
|
|
8
6
|
from .value_holder import ValueHolder
|
|
9
7
|
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
pass
|
|
10
|
+
|
|
10
11
|
|
|
11
12
|
class PredicateFunction(ASTNode):
|
|
12
13
|
"""Base class for predicate functions."""
|
|
@@ -21,7 +22,7 @@ class PredicateFunction(ASTNode):
|
|
|
21
22
|
return self._name
|
|
22
23
|
|
|
23
24
|
@property
|
|
24
|
-
def reference(self) ->
|
|
25
|
+
def reference(self) -> ASTNode:
|
|
25
26
|
return self.first_child()
|
|
26
27
|
|
|
27
28
|
@property
|
|
@@ -29,12 +30,12 @@ class PredicateFunction(ASTNode):
|
|
|
29
30
|
return self.get_children()[1].first_child()
|
|
30
31
|
|
|
31
32
|
@property
|
|
32
|
-
def _return(self) ->
|
|
33
|
+
def _return(self) -> ASTNode:
|
|
33
34
|
return self.get_children()[2]
|
|
34
35
|
|
|
35
36
|
@property
|
|
36
|
-
def where(self) -> Optional[
|
|
37
|
-
|
|
37
|
+
def where(self) -> Optional[ASTNode]:
|
|
38
|
+
# Import at runtime to avoid circular dependency
|
|
38
39
|
if len(self.get_children()) == 4:
|
|
39
40
|
return self.get_children()[3]
|
|
40
41
|
return None
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"""PredicateSum function."""
|
|
2
2
|
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, Optional
|
|
4
4
|
|
|
5
|
-
from .predicate_function import PredicateFunction
|
|
6
5
|
from .function_metadata import FunctionDef
|
|
6
|
+
from .predicate_function import PredicateFunction
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@FunctionDef({
|
|
10
|
-
"description":
|
|
10
|
+
"description": (
|
|
11
|
+
"Calculates the sum of values in an array with optional filtering. "
|
|
12
|
+
"Uses list comprehension syntax: sum(variable IN array [WHERE condition] | expression)"
|
|
13
|
+
),
|
|
11
14
|
"category": "predicate",
|
|
12
15
|
"parameters": [
|
|
13
16
|
{"name": "variable", "description": "Variable name to bind each element", "type": "string"},
|
|
@@ -23,19 +26,21 @@ from .function_metadata import FunctionDef
|
|
|
23
26
|
})
|
|
24
27
|
class PredicateSum(PredicateFunction):
|
|
25
28
|
"""PredicateSum function.
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
Calculates the sum of values in an array with optional filtering.
|
|
28
31
|
"""
|
|
29
32
|
|
|
30
|
-
def __init__(self):
|
|
33
|
+
def __init__(self) -> None:
|
|
31
34
|
super().__init__("sum")
|
|
32
35
|
|
|
33
36
|
def value(self) -> Any:
|
|
34
|
-
|
|
37
|
+
ref = self.reference
|
|
38
|
+
if hasattr(ref, 'referred'):
|
|
39
|
+
ref.referred = self._value_holder
|
|
35
40
|
array = self.array.value()
|
|
36
41
|
if array is None or not isinstance(array, list):
|
|
37
42
|
raise ValueError("Invalid array for sum function")
|
|
38
|
-
|
|
43
|
+
|
|
39
44
|
_sum: Optional[Any] = None
|
|
40
45
|
for item in array:
|
|
41
46
|
self._value_holder.holder = item
|
|
@@ -16,11 +16,11 @@ from .function_metadata import FunctionDef
|
|
|
16
16
|
})
|
|
17
17
|
class Rand(Function):
|
|
18
18
|
"""Rand function.
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
Generates a random number between 0 and 1.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
def __init__(self):
|
|
23
|
+
def __init__(self) -> None:
|
|
24
24
|
super().__init__("rand")
|
|
25
25
|
self._expected_parameter_count = 0
|
|
26
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Range function."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from .function import Function
|
|
6
6
|
from .function_metadata import FunctionDef
|
|
@@ -13,16 +13,21 @@ from .function_metadata import FunctionDef
|
|
|
13
13
|
{"name": "start", "description": "Starting number (inclusive)", "type": "number"},
|
|
14
14
|
{"name": "end", "description": "Ending number (inclusive)", "type": "number"}
|
|
15
15
|
],
|
|
16
|
-
"output": {
|
|
16
|
+
"output": {
|
|
17
|
+
"description": "Array of integers from start to end",
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": {"type": "number"},
|
|
20
|
+
"example": [1, 2, 3, 4, 5]
|
|
21
|
+
},
|
|
17
22
|
"examples": ["WITH range(1, 5) AS nums RETURN nums"]
|
|
18
23
|
})
|
|
19
24
|
class Range(Function):
|
|
20
25
|
"""Range function.
|
|
21
|
-
|
|
26
|
+
|
|
22
27
|
Generates an array of sequential integers.
|
|
23
28
|
"""
|
|
24
29
|
|
|
25
|
-
def __init__(self):
|
|
30
|
+
def __init__(self) -> None:
|
|
26
31
|
super().__init__("range")
|
|
27
32
|
self._expected_parameter_count = 2
|
|
28
33
|
|
|
@@ -20,11 +20,11 @@ from .function_metadata import FunctionDef
|
|
|
20
20
|
})
|
|
21
21
|
class Replace(Function):
|
|
22
22
|
"""Replace function.
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
Replaces occurrences of a pattern in a string.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self):
|
|
27
|
+
def __init__(self) -> None:
|
|
28
28
|
super().__init__("replace")
|
|
29
29
|
self._expected_parameter_count = 3
|
|
30
30
|
|
|
@@ -17,11 +17,11 @@ from .function_metadata import FunctionDef
|
|
|
17
17
|
})
|
|
18
18
|
class Round(Function):
|
|
19
19
|
"""Round function.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
Rounds a number to the nearest integer.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
def __init__(self):
|
|
24
|
+
def __init__(self) -> None:
|
|
25
25
|
super().__init__("round")
|
|
26
26
|
self._expected_parameter_count = 1
|
|
27
27
|
|
|
@@ -17,11 +17,11 @@ from .function_metadata import FunctionDef
|
|
|
17
17
|
})
|
|
18
18
|
class Size(Function):
|
|
19
19
|
"""Size function.
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
Returns the length of an array or string.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
def __init__(self):
|
|
24
|
+
def __init__(self) -> None:
|
|
25
25
|
super().__init__("size")
|
|
26
26
|
self._expected_parameter_count = 1
|
|
27
27
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, List
|
|
4
4
|
|
|
5
|
-
from .function import Function
|
|
6
5
|
from ..ast_node import ASTNode
|
|
7
6
|
from ..expressions.string import String
|
|
7
|
+
from .function import Function
|
|
8
8
|
from .function_metadata import FunctionDef
|
|
9
9
|
|
|
10
10
|
|
|
@@ -15,16 +15,21 @@ from .function_metadata import FunctionDef
|
|
|
15
15
|
{"name": "text", "description": "String to split", "type": "string"},
|
|
16
16
|
{"name": "delimiter", "description": "Delimiter to split by", "type": "string"}
|
|
17
17
|
],
|
|
18
|
-
"output": {
|
|
18
|
+
"output": {
|
|
19
|
+
"description": "Array of string parts",
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {"type": "string"},
|
|
22
|
+
"example": ["a", "b", "c"]
|
|
23
|
+
},
|
|
19
24
|
"examples": ["WITH 'a,b,c' AS s RETURN split(s, ',')"]
|
|
20
25
|
})
|
|
21
26
|
class Split(Function):
|
|
22
27
|
"""Split function.
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
Splits a string into an array by a delimiter.
|
|
25
30
|
"""
|
|
26
31
|
|
|
27
|
-
def __init__(self):
|
|
32
|
+
def __init__(self) -> None:
|
|
28
33
|
super().__init__("split")
|
|
29
34
|
self._expected_parameter_count = 2
|
|
30
35
|
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import json
|
|
4
4
|
from typing import Any, List
|
|
5
5
|
|
|
6
|
-
from .function import Function
|
|
7
6
|
from ..ast_node import ASTNode
|
|
8
7
|
from ..expressions.number import Number
|
|
8
|
+
from .function import Function
|
|
9
9
|
from .function_metadata import FunctionDef
|
|
10
10
|
|
|
11
11
|
|
|
@@ -20,11 +20,11 @@ from .function_metadata import FunctionDef
|
|
|
20
20
|
})
|
|
21
21
|
class Stringify(Function):
|
|
22
22
|
"""Stringify function.
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
Converts a value to its JSON string representation.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self):
|
|
27
|
+
def __init__(self) -> None:
|
|
28
28
|
super().__init__("stringify")
|
|
29
29
|
self._expected_parameter_count = 2
|
|
30
30
|
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from .aggregate_function import AggregateFunction
|
|
6
|
-
from .reducer_element import ReducerElement
|
|
7
6
|
from .function_metadata import FunctionDef
|
|
7
|
+
from .reducer_element import ReducerElement
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class SumReducerElement(ReducerElement):
|
|
11
11
|
"""Reducer element for Sum aggregate function."""
|
|
12
12
|
|
|
13
|
-
def __init__(self):
|
|
13
|
+
def __init__(self) -> None:
|
|
14
14
|
self._value: Any = None
|
|
15
15
|
|
|
16
16
|
@property
|
|
@@ -36,11 +36,11 @@ class SumReducerElement(ReducerElement):
|
|
|
36
36
|
})
|
|
37
37
|
class Sum(AggregateFunction):
|
|
38
38
|
"""Sum aggregate function.
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
Calculates the sum of numeric values across grouped rows.
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
def __init__(self):
|
|
43
|
+
def __init__(self) -> None:
|
|
44
44
|
super().__init__("sum")
|
|
45
45
|
self._expected_parameter_count = 1
|
|
46
46
|
|
|
@@ -18,11 +18,11 @@ from .function_metadata import FunctionDef
|
|
|
18
18
|
})
|
|
19
19
|
class ToJson(Function):
|
|
20
20
|
"""ToJson function.
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
Parses a JSON string into an object.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
|
-
def __init__(self):
|
|
25
|
+
def __init__(self) -> None:
|
|
26
26
|
super().__init__("tojson")
|
|
27
27
|
self._expected_parameter_count = 1
|
|
28
28
|
|
|
@@ -21,17 +21,17 @@ from .function_metadata import FunctionDef
|
|
|
21
21
|
})
|
|
22
22
|
class Type(Function):
|
|
23
23
|
"""Type function.
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
Returns the type of a value as a string.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
def __init__(self):
|
|
28
|
+
def __init__(self) -> None:
|
|
29
29
|
super().__init__("type")
|
|
30
30
|
self._expected_parameter_count = 1
|
|
31
31
|
|
|
32
32
|
def value(self) -> Any:
|
|
33
33
|
val = self.get_children()[0].value()
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
if val is None:
|
|
36
36
|
return "null"
|
|
37
37
|
if isinstance(val, list):
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""Represents a WHEN clause in a CASE expression."""
|
|
2
2
|
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
3
5
|
from ..ast_node import ASTNode
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class When(ASTNode):
|
|
7
9
|
"""Represents a WHEN clause in a CASE expression."""
|
|
8
10
|
|
|
9
|
-
def value(self) ->
|
|
11
|
+
def value(self) -> Any:
|
|
10
12
|
return self.get_children()[0].value()
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"""Operations module for FlowQuery parsing."""
|
|
2
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
3
|
from .aggregated_return import AggregatedReturn
|
|
12
4
|
from .aggregated_with import AggregatedWith
|
|
13
5
|
from .call import Call
|
|
14
|
-
from .group_by import GroupBy
|
|
15
|
-
from .match import Match
|
|
16
6
|
from .create_node import CreateNode
|
|
17
7
|
from .create_relationship import CreateRelationship
|
|
8
|
+
from .group_by import GroupBy
|
|
9
|
+
from .limit import Limit
|
|
10
|
+
from .load import Load
|
|
11
|
+
from .match import Match
|
|
12
|
+
from .operation import Operation
|
|
13
|
+
from .projection import Projection
|
|
14
|
+
from .return_op import Return
|
|
15
|
+
from .unwind import Unwind
|
|
16
|
+
from .where import Where
|
|
17
|
+
from .with_op import With
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
20
|
"Operation",
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
"""Represents an aggregated RETURN operation."""
|
|
2
|
-
|
|
3
1
|
from typing import Any, Dict, List
|
|
4
2
|
|
|
5
|
-
from
|
|
3
|
+
from ..ast_node import ASTNode
|
|
6
4
|
from .group_by import GroupBy
|
|
7
|
-
from
|
|
5
|
+
from .return_op import Return
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class AggregatedReturn(Return):
|
|
11
9
|
"""Represents an aggregated RETURN operation that groups and reduces values."""
|
|
12
10
|
|
|
13
|
-
def __init__(self, expressions):
|
|
11
|
+
def __init__(self, expressions: List[ASTNode]) -> None:
|
|
14
12
|
super().__init__(expressions)
|
|
15
13
|
self._group_by = GroupBy(self.children)
|
|
16
14
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
from typing import List
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from ..ast_node import ASTNode
|
|
4
4
|
from .group_by import GroupBy
|
|
5
|
-
from
|
|
5
|
+
from .return_op import Return
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class AggregatedWith(Return):
|
|
9
9
|
"""Represents an aggregated WITH operation that groups and reduces values."""
|
|
10
10
|
|
|
11
|
-
def __init__(self, expressions):
|
|
11
|
+
def __init__(self, expressions: List[ASTNode]) -> None:
|
|
12
12
|
super().__init__(expressions)
|
|
13
13
|
self._group_by = GroupBy(self.children)
|
|
14
14
|
|
|
@@ -2,19 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Dict, List, Optional
|
|
4
4
|
|
|
5
|
-
from ..
|
|
5
|
+
from ..ast_node import ASTNode
|
|
6
6
|
from ..expressions.expression_map import ExpressionMap
|
|
7
7
|
from ..functions.async_function import AsyncFunction
|
|
8
8
|
from .projection import Projection
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
DEFAULT_VARIABLE_NAME = "value"
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class Call(Projection):
|
|
15
14
|
"""Represents a CALL operation for invoking async functions."""
|
|
16
15
|
|
|
17
|
-
def __init__(self):
|
|
16
|
+
def __init__(self) -> None:
|
|
18
17
|
super().__init__([])
|
|
19
18
|
self._function: Optional[AsyncFunction] = None
|
|
20
19
|
self._map = ExpressionMap()
|
|
@@ -29,13 +28,13 @@ class Call(Projection):
|
|
|
29
28
|
self._function = async_function
|
|
30
29
|
|
|
31
30
|
@property
|
|
32
|
-
def yielded(self) -> List[
|
|
31
|
+
def yielded(self) -> List[ASTNode]:
|
|
33
32
|
return self.children
|
|
34
33
|
|
|
35
34
|
@yielded.setter
|
|
36
|
-
def yielded(self, expressions: List[
|
|
35
|
+
def yielded(self, expressions: List[ASTNode]) -> None:
|
|
37
36
|
self.children = expressions
|
|
38
|
-
self._map.set_map(expressions)
|
|
37
|
+
self._map.set_map(expressions) # ExpressionMap accepts list of expressions
|
|
39
38
|
|
|
40
39
|
@property
|
|
41
40
|
def has_yield(self) -> bool:
|
|
@@ -44,7 +43,7 @@ class Call(Projection):
|
|
|
44
43
|
async def run(self) -> None:
|
|
45
44
|
if self._function is None:
|
|
46
45
|
raise ValueError("No function set for Call operation.")
|
|
47
|
-
|
|
46
|
+
|
|
48
47
|
args = self._function.get_arguments()
|
|
49
48
|
async for item in self._function.generate(*args):
|
|
50
49
|
if not self.is_last:
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Dict, List
|
|
4
4
|
|
|
5
|
-
from .
|
|
5
|
+
from ...graph.database import Database
|
|
6
|
+
from ...graph.node import Node
|
|
6
7
|
from ..ast_node import ASTNode
|
|
8
|
+
from .operation import Operation
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class CreateNode(Operation):
|
|
10
12
|
"""Represents a CREATE operation for creating virtual nodes."""
|
|
11
13
|
|
|
12
|
-
def __init__(self, node, statement: ASTNode):
|
|
14
|
+
def __init__(self, node: Node, statement: ASTNode) -> None:
|
|
13
15
|
super().__init__()
|
|
14
16
|
self._node = node
|
|
15
17
|
self._statement = statement
|
|
16
18
|
|
|
17
19
|
@property
|
|
18
|
-
def node(self):
|
|
20
|
+
def node(self) -> Node:
|
|
19
21
|
return self._node
|
|
20
22
|
|
|
21
23
|
@property
|
|
@@ -25,7 +27,6 @@ class CreateNode(Operation):
|
|
|
25
27
|
async def run(self) -> None:
|
|
26
28
|
if self._node is None:
|
|
27
29
|
raise ValueError("Node is null")
|
|
28
|
-
from ...graph.database import Database
|
|
29
30
|
db = Database.get_instance()
|
|
30
31
|
db.add_node(self._node, self._statement)
|
|
31
32
|
|