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.
Files changed (158) hide show
  1. package/.gitattributes +3 -0
  2. package/.github/workflows/python-publish.yml +56 -4
  3. package/.github/workflows/release.yml +26 -19
  4. package/.husky/pre-commit +26 -0
  5. package/README.md +37 -32
  6. package/dist/flowquery.min.js +1 -1
  7. package/dist/graph/data.d.ts +5 -4
  8. package/dist/graph/data.d.ts.map +1 -1
  9. package/dist/graph/data.js +38 -20
  10. package/dist/graph/data.js.map +1 -1
  11. package/dist/graph/node.d.ts +2 -0
  12. package/dist/graph/node.d.ts.map +1 -1
  13. package/dist/graph/node.js +23 -0
  14. package/dist/graph/node.js.map +1 -1
  15. package/dist/graph/node_data.js +1 -1
  16. package/dist/graph/node_data.js.map +1 -1
  17. package/dist/graph/pattern.d.ts.map +1 -1
  18. package/dist/graph/pattern.js +11 -4
  19. package/dist/graph/pattern.js.map +1 -1
  20. package/dist/graph/relationship.d.ts +6 -1
  21. package/dist/graph/relationship.d.ts.map +1 -1
  22. package/dist/graph/relationship.js +43 -5
  23. package/dist/graph/relationship.js.map +1 -1
  24. package/dist/graph/relationship_data.d.ts +2 -0
  25. package/dist/graph/relationship_data.d.ts.map +1 -1
  26. package/dist/graph/relationship_data.js +8 -1
  27. package/dist/graph/relationship_data.js.map +1 -1
  28. package/dist/graph/relationship_match_collector.js +2 -2
  29. package/dist/graph/relationship_match_collector.js.map +1 -1
  30. package/dist/graph/relationship_reference.d.ts.map +1 -1
  31. package/dist/graph/relationship_reference.js +2 -1
  32. package/dist/graph/relationship_reference.js.map +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +1 -1
  35. package/dist/parsing/parser.d.ts +6 -0
  36. package/dist/parsing/parser.d.ts.map +1 -1
  37. package/dist/parsing/parser.js +139 -72
  38. package/dist/parsing/parser.js.map +1 -1
  39. package/docs/flowquery.min.js +1 -1
  40. package/flowquery-py/misc/data/test.json +10 -0
  41. package/flowquery-py/misc/data/users.json +242 -0
  42. package/flowquery-py/notebooks/TestFlowQuery.ipynb +440 -0
  43. package/flowquery-py/pyproject.toml +48 -2
  44. package/flowquery-py/src/__init__.py +7 -5
  45. package/flowquery-py/src/compute/runner.py +14 -10
  46. package/flowquery-py/src/extensibility.py +8 -8
  47. package/flowquery-py/src/graph/__init__.py +7 -7
  48. package/flowquery-py/src/graph/data.py +38 -20
  49. package/flowquery-py/src/graph/database.py +10 -20
  50. package/flowquery-py/src/graph/node.py +50 -19
  51. package/flowquery-py/src/graph/node_data.py +1 -1
  52. package/flowquery-py/src/graph/node_reference.py +10 -11
  53. package/flowquery-py/src/graph/pattern.py +27 -37
  54. package/flowquery-py/src/graph/pattern_expression.py +13 -11
  55. package/flowquery-py/src/graph/patterns.py +2 -2
  56. package/flowquery-py/src/graph/physical_node.py +4 -3
  57. package/flowquery-py/src/graph/physical_relationship.py +5 -5
  58. package/flowquery-py/src/graph/relationship.py +62 -14
  59. package/flowquery-py/src/graph/relationship_data.py +7 -2
  60. package/flowquery-py/src/graph/relationship_match_collector.py +15 -10
  61. package/flowquery-py/src/graph/relationship_reference.py +4 -4
  62. package/flowquery-py/src/io/command_line.py +13 -14
  63. package/flowquery-py/src/parsing/__init__.py +2 -2
  64. package/flowquery-py/src/parsing/alias_option.py +1 -1
  65. package/flowquery-py/src/parsing/ast_node.py +21 -20
  66. package/flowquery-py/src/parsing/base_parser.py +7 -7
  67. package/flowquery-py/src/parsing/components/__init__.py +3 -3
  68. package/flowquery-py/src/parsing/components/from_.py +3 -1
  69. package/flowquery-py/src/parsing/components/headers.py +2 -2
  70. package/flowquery-py/src/parsing/components/null.py +2 -2
  71. package/flowquery-py/src/parsing/context.py +7 -7
  72. package/flowquery-py/src/parsing/data_structures/associative_array.py +7 -7
  73. package/flowquery-py/src/parsing/data_structures/json_array.py +3 -3
  74. package/flowquery-py/src/parsing/data_structures/key_value_pair.py +4 -4
  75. package/flowquery-py/src/parsing/data_structures/lookup.py +2 -2
  76. package/flowquery-py/src/parsing/data_structures/range_lookup.py +2 -2
  77. package/flowquery-py/src/parsing/expressions/__init__.py +16 -16
  78. package/flowquery-py/src/parsing/expressions/expression.py +16 -13
  79. package/flowquery-py/src/parsing/expressions/expression_map.py +9 -9
  80. package/flowquery-py/src/parsing/expressions/f_string.py +3 -3
  81. package/flowquery-py/src/parsing/expressions/identifier.py +4 -3
  82. package/flowquery-py/src/parsing/expressions/number.py +3 -3
  83. package/flowquery-py/src/parsing/expressions/operator.py +16 -16
  84. package/flowquery-py/src/parsing/expressions/reference.py +3 -3
  85. package/flowquery-py/src/parsing/expressions/string.py +2 -2
  86. package/flowquery-py/src/parsing/functions/__init__.py +17 -17
  87. package/flowquery-py/src/parsing/functions/aggregate_function.py +8 -8
  88. package/flowquery-py/src/parsing/functions/async_function.py +12 -9
  89. package/flowquery-py/src/parsing/functions/avg.py +4 -4
  90. package/flowquery-py/src/parsing/functions/collect.py +6 -6
  91. package/flowquery-py/src/parsing/functions/function.py +6 -6
  92. package/flowquery-py/src/parsing/functions/function_factory.py +31 -34
  93. package/flowquery-py/src/parsing/functions/function_metadata.py +10 -11
  94. package/flowquery-py/src/parsing/functions/functions.py +14 -6
  95. package/flowquery-py/src/parsing/functions/join.py +3 -3
  96. package/flowquery-py/src/parsing/functions/keys.py +3 -3
  97. package/flowquery-py/src/parsing/functions/predicate_function.py +8 -7
  98. package/flowquery-py/src/parsing/functions/predicate_sum.py +12 -7
  99. package/flowquery-py/src/parsing/functions/rand.py +2 -2
  100. package/flowquery-py/src/parsing/functions/range_.py +9 -4
  101. package/flowquery-py/src/parsing/functions/replace.py +2 -2
  102. package/flowquery-py/src/parsing/functions/round_.py +2 -2
  103. package/flowquery-py/src/parsing/functions/size.py +2 -2
  104. package/flowquery-py/src/parsing/functions/split.py +9 -4
  105. package/flowquery-py/src/parsing/functions/stringify.py +3 -3
  106. package/flowquery-py/src/parsing/functions/sum.py +4 -4
  107. package/flowquery-py/src/parsing/functions/to_json.py +2 -2
  108. package/flowquery-py/src/parsing/functions/type_.py +3 -3
  109. package/flowquery-py/src/parsing/functions/value_holder.py +1 -1
  110. package/flowquery-py/src/parsing/logic/__init__.py +2 -2
  111. package/flowquery-py/src/parsing/logic/case.py +0 -1
  112. package/flowquery-py/src/parsing/logic/when.py +3 -1
  113. package/flowquery-py/src/parsing/operations/__init__.py +10 -10
  114. package/flowquery-py/src/parsing/operations/aggregated_return.py +3 -5
  115. package/flowquery-py/src/parsing/operations/aggregated_with.py +4 -4
  116. package/flowquery-py/src/parsing/operations/call.py +6 -7
  117. package/flowquery-py/src/parsing/operations/create_node.py +5 -4
  118. package/flowquery-py/src/parsing/operations/create_relationship.py +5 -4
  119. package/flowquery-py/src/parsing/operations/group_by.py +18 -16
  120. package/flowquery-py/src/parsing/operations/load.py +21 -19
  121. package/flowquery-py/src/parsing/operations/match.py +8 -7
  122. package/flowquery-py/src/parsing/operations/operation.py +3 -3
  123. package/flowquery-py/src/parsing/operations/projection.py +6 -6
  124. package/flowquery-py/src/parsing/operations/return_op.py +9 -5
  125. package/flowquery-py/src/parsing/operations/unwind.py +3 -2
  126. package/flowquery-py/src/parsing/operations/where.py +9 -7
  127. package/flowquery-py/src/parsing/operations/with_op.py +2 -2
  128. package/flowquery-py/src/parsing/parser.py +178 -114
  129. package/flowquery-py/src/parsing/token_to_node.py +2 -2
  130. package/flowquery-py/src/tokenization/__init__.py +4 -4
  131. package/flowquery-py/src/tokenization/keyword.py +1 -1
  132. package/flowquery-py/src/tokenization/operator.py +1 -1
  133. package/flowquery-py/src/tokenization/string_walker.py +4 -4
  134. package/flowquery-py/src/tokenization/symbol.py +1 -1
  135. package/flowquery-py/src/tokenization/token.py +11 -11
  136. package/flowquery-py/src/tokenization/token_mapper.py +10 -9
  137. package/flowquery-py/src/tokenization/token_type.py +1 -1
  138. package/flowquery-py/src/tokenization/tokenizer.py +19 -19
  139. package/flowquery-py/src/tokenization/trie.py +18 -17
  140. package/flowquery-py/src/utils/__init__.py +1 -1
  141. package/flowquery-py/src/utils/object_utils.py +3 -3
  142. package/flowquery-py/src/utils/string_utils.py +12 -12
  143. package/flowquery-py/tests/compute/test_runner.py +214 -7
  144. package/flowquery-py/tests/parsing/test_parser.py +41 -0
  145. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  146. package/package.json +1 -1
  147. package/src/graph/data.ts +38 -20
  148. package/src/graph/node.ts +23 -0
  149. package/src/graph/node_data.ts +1 -1
  150. package/src/graph/pattern.ts +13 -4
  151. package/src/graph/relationship.ts +45 -5
  152. package/src/graph/relationship_data.ts +8 -1
  153. package/src/graph/relationship_match_collector.ts +1 -1
  154. package/src/graph/relationship_reference.ts +2 -1
  155. package/src/index.ts +5 -5
  156. package/src/parsing/parser.ts +139 -71
  157. package/tests/compute/runner.test.ts +249 -79
  158. package/tests/parsing/parser.test.ts +32 -0
@@ -1,28 +1,29 @@
1
1
  """Represents a node in the Abstract Syntax Tree (AST)."""
2
2
 
3
3
  from __future__ import annotations
4
- from typing import List, Any, Generator, Optional
4
+
5
+ from typing import Any, Generator, List, Optional
5
6
 
6
7
 
7
8
  class ASTNode:
8
9
  """Represents a node in the Abstract Syntax Tree (AST).
9
-
10
+
10
11
  The AST is a tree representation of the parsed FlowQuery statement structure.
11
12
  Each node can have children and maintains a reference to its parent.
12
-
13
+
13
14
  Example:
14
15
  root = ASTNode()
15
16
  child = ASTNode()
16
17
  root.add_child(child)
17
18
  """
18
19
 
19
- def __init__(self):
20
+ def __init__(self) -> None:
20
21
  self._parent: Optional[ASTNode] = None
21
22
  self.children: List[ASTNode] = []
22
23
 
23
24
  def add_child(self, child: ASTNode) -> None:
24
25
  """Adds a child node to this node and sets the child's parent reference.
25
-
26
+
26
27
  Args:
27
28
  child: The child node to add
28
29
  """
@@ -31,10 +32,10 @@ class ASTNode:
31
32
 
32
33
  def first_child(self) -> ASTNode:
33
34
  """Returns the first child node.
34
-
35
+
35
36
  Returns:
36
37
  The first child node
37
-
38
+
38
39
  Raises:
39
40
  ValueError: If the node has no children
40
41
  """
@@ -44,10 +45,10 @@ class ASTNode:
44
45
 
45
46
  def last_child(self) -> ASTNode:
46
47
  """Returns the last child node.
47
-
48
+
48
49
  Returns:
49
50
  The last child node
50
-
51
+
51
52
  Raises:
52
53
  ValueError: If the node has no children
53
54
  """
@@ -57,7 +58,7 @@ class ASTNode:
57
58
 
58
59
  def get_children(self) -> List[ASTNode]:
59
60
  """Returns all child nodes.
60
-
61
+
61
62
  Returns:
62
63
  Array of child nodes
63
64
  """
@@ -65,7 +66,7 @@ class ASTNode:
65
66
 
66
67
  def child_count(self) -> int:
67
68
  """Returns the number of child nodes.
68
-
69
+
69
70
  Returns:
70
71
  The count of children
71
72
  """
@@ -73,7 +74,7 @@ class ASTNode:
73
74
 
74
75
  def value(self) -> Any:
75
76
  """Returns the value of this node. Override in subclasses to provide specific values.
76
-
77
+
77
78
  Returns:
78
79
  The node's value, or None if not applicable
79
80
  """
@@ -81,7 +82,7 @@ class ASTNode:
81
82
 
82
83
  def is_operator(self) -> bool:
83
84
  """Checks if this node represents an operator.
84
-
85
+
85
86
  Returns:
86
87
  True if this is an operator node, False otherwise
87
88
  """
@@ -89,7 +90,7 @@ class ASTNode:
89
90
 
90
91
  def is_operand(self) -> bool:
91
92
  """Checks if this node represents an operand (the opposite of an operator).
92
-
93
+
93
94
  Returns:
94
95
  True if this is an operand node, False otherwise
95
96
  """
@@ -98,7 +99,7 @@ class ASTNode:
98
99
  @property
99
100
  def precedence(self) -> int:
100
101
  """Gets the operator precedence for this node. Higher values indicate higher precedence.
101
-
102
+
102
103
  Returns:
103
104
  The precedence value (0 for non-operators)
104
105
  """
@@ -107,7 +108,7 @@ class ASTNode:
107
108
  @property
108
109
  def left_associative(self) -> bool:
109
110
  """Indicates whether this operator is left-associative.
110
-
111
+
111
112
  Returns:
112
113
  True if left-associative, False otherwise
113
114
  """
@@ -115,7 +116,7 @@ class ASTNode:
115
116
 
116
117
  def print(self) -> str:
117
118
  """Prints a string representation of the AST tree starting from this node.
118
-
119
+
119
120
  Returns:
120
121
  A formatted string showing the tree structure
121
122
  """
@@ -123,10 +124,10 @@ class ASTNode:
123
124
 
124
125
  def _print(self, indent: int) -> Generator[str, None, None]:
125
126
  """Generator function for recursively printing the tree structure.
126
-
127
+
127
128
  Args:
128
129
  indent: The current indentation level
129
-
130
+
130
131
  Yields:
131
132
  Lines representing each node in the tree
132
133
  """
@@ -139,7 +140,7 @@ class ASTNode:
139
140
 
140
141
  def __str__(self) -> str:
141
142
  """Returns a string representation of this node. Override in subclasses for custom formatting.
142
-
143
+
143
144
  Returns:
144
145
  The string representation
145
146
  """
@@ -8,7 +8,7 @@ from ..tokenization.tokenizer import Tokenizer
8
8
 
9
9
  class BaseParser:
10
10
  """Base class for parsers providing common token manipulation functionality.
11
-
11
+
12
12
  This class handles tokenization and provides utility methods for navigating
13
13
  through tokens, peeking ahead, and checking token sequences.
14
14
  """
@@ -19,7 +19,7 @@ class BaseParser:
19
19
 
20
20
  def tokenize(self, statement: str) -> None:
21
21
  """Tokenizes a statement and initializes the token array.
22
-
22
+
23
23
  Args:
24
24
  statement: The input statement to tokenize
25
25
  """
@@ -32,7 +32,7 @@ class BaseParser:
32
32
 
33
33
  def peek(self) -> Optional[Token]:
34
34
  """Peeks at the next token without advancing the current position.
35
-
35
+
36
36
  Returns:
37
37
  The next token, or None if at the end of the token stream
38
38
  """
@@ -42,11 +42,11 @@ class BaseParser:
42
42
 
43
43
  def ahead(self, tokens: List[Token], skip_whitespace_and_comments: bool = True) -> bool:
44
44
  """Checks if a sequence of tokens appears ahead in the token stream.
45
-
45
+
46
46
  Args:
47
47
  tokens: The sequence of tokens to look for
48
48
  skip_whitespace_and_comments: Whether to skip whitespace and comments when matching
49
-
49
+
50
50
  Returns:
51
51
  True if the token sequence is found ahead, False otherwise
52
52
  """
@@ -64,7 +64,7 @@ class BaseParser:
64
64
  @property
65
65
  def token(self) -> Token:
66
66
  """Gets the current token.
67
-
67
+
68
68
  Returns:
69
69
  The current token, or EOF if at the end
70
70
  """
@@ -75,7 +75,7 @@ class BaseParser:
75
75
  @property
76
76
  def previous_token(self) -> Token:
77
77
  """Gets the previous token.
78
-
78
+
79
79
  Returns:
80
80
  The previous token, or EOF if at the beginning
81
81
  """
@@ -1,12 +1,12 @@
1
1
  """Components module for FlowQuery parsing."""
2
2
 
3
3
  from .csv import CSV
4
- from .json import JSON
5
- from .text import Text
6
4
  from .from_ import From
7
5
  from .headers import Headers
8
- from .post import Post
6
+ from .json import JSON
9
7
  from .null import Null
8
+ from .post import Post
9
+ from .text import Text
10
10
 
11
11
  __all__ = [
12
12
  "CSV",
@@ -1,10 +1,12 @@
1
1
  """From component node."""
2
2
 
3
+ from typing import Any
4
+
3
5
  from ..ast_node import ASTNode
4
6
 
5
7
 
6
8
  class From(ASTNode):
7
9
  """Represents a FROM clause in LOAD operations."""
8
10
 
9
- def value(self) -> str:
11
+ def value(self) -> Any:
10
12
  return self.children[0].value()
@@ -1,6 +1,6 @@
1
1
  """Headers component node."""
2
2
 
3
- from typing import Dict
3
+ from typing import Any, Dict
4
4
 
5
5
  from ..ast_node import ASTNode
6
6
 
@@ -8,5 +8,5 @@ from ..ast_node import ASTNode
8
8
  class Headers(ASTNode):
9
9
  """Represents a HEADERS clause in LOAD operations."""
10
10
 
11
- def value(self) -> Dict:
11
+ def value(self) -> Dict[str, Any]:
12
12
  return self.first_child().value() or {}
@@ -5,6 +5,6 @@ from ..ast_node import ASTNode
5
5
 
6
6
  class Null(ASTNode):
7
7
  """Represents a NULL value in the AST."""
8
-
9
- def value(self):
8
+
9
+ def value(self) -> None:
10
10
  return None
@@ -7,22 +7,22 @@ from .ast_node import ASTNode
7
7
 
8
8
  class Context:
9
9
  """Maintains a stack of AST nodes to track parsing context.
10
-
10
+
11
11
  Used during parsing to maintain the current context and check for specific node types
12
12
  in the parsing hierarchy, which helps with context-sensitive parsing decisions.
13
-
13
+
14
14
  Example:
15
15
  context = Context()
16
16
  context.push(node)
17
17
  has_return = context.contains_type(Return)
18
18
  """
19
19
 
20
- def __init__(self):
20
+ def __init__(self) -> None:
21
21
  self._nodes: List[ASTNode] = []
22
22
 
23
23
  def push(self, node: ASTNode) -> None:
24
24
  """Pushes a node onto the context stack.
25
-
25
+
26
26
  Args:
27
27
  node: The AST node to push
28
28
  """
@@ -30,7 +30,7 @@ class Context:
30
30
 
31
31
  def pop(self) -> Optional[ASTNode]:
32
32
  """Pops the top node from the context stack.
33
-
33
+
34
34
  Returns:
35
35
  The popped node, or None if the stack is empty
36
36
  """
@@ -40,10 +40,10 @@ class Context:
40
40
 
41
41
  def contains_type(self, type_: Type[ASTNode]) -> bool:
42
42
  """Checks if the nodes stack contains a node of the specified type.
43
-
43
+
44
44
  Args:
45
45
  type_: The class of the node type to search for
46
-
46
+
47
47
  Returns:
48
48
  True if a node of the specified type is found in the stack, False otherwise
49
49
  """
@@ -1,6 +1,6 @@
1
1
  """Represents an associative array (object/dictionary) in the AST."""
2
2
 
3
- from typing import Any, Dict
3
+ from typing import Any, Dict, Generator
4
4
 
5
5
  from ..ast_node import ASTNode
6
6
  from .key_value_pair import KeyValuePair
@@ -8,9 +8,9 @@ from .key_value_pair import KeyValuePair
8
8
 
9
9
  class AssociativeArray(ASTNode):
10
10
  """Represents an associative array (object/dictionary) in the AST.
11
-
11
+
12
12
  Associative arrays map string keys to values, similar to JSON objects.
13
-
13
+
14
14
  Example:
15
15
  # For { name: "Alice", age: 30 }
16
16
  obj = AssociativeArray()
@@ -20,7 +20,7 @@ class AssociativeArray(ASTNode):
20
20
 
21
21
  def add_key_value(self, key_value_pair: KeyValuePair) -> None:
22
22
  """Adds a key-value pair to the associative array.
23
-
23
+
24
24
  Args:
25
25
  key_value_pair: The key-value pair to add
26
26
  """
@@ -29,10 +29,10 @@ class AssociativeArray(ASTNode):
29
29
  def __str__(self) -> str:
30
30
  return 'AssociativeArray'
31
31
 
32
- def _value(self):
32
+ def _value(self) -> Generator[Dict[str, Any], None, None]:
33
33
  for child in self.children:
34
- key_value = child
35
- yield {key_value.key: key_value._value}
34
+ if isinstance(child, KeyValuePair):
35
+ yield {child.key: child._value}
36
36
 
37
37
  def value(self) -> Dict[str, Any]:
38
38
  result = {}
@@ -7,9 +7,9 @@ from ..ast_node import ASTNode
7
7
 
8
8
  class JSONArray(ASTNode):
9
9
  """Represents a JSON array in the AST.
10
-
10
+
11
11
  JSON arrays are ordered collections of values.
12
-
12
+
13
13
  Example:
14
14
  # For [1, 2, 3]
15
15
  arr = JSONArray()
@@ -20,7 +20,7 @@ class JSONArray(ASTNode):
20
20
 
21
21
  def add_value(self, value: ASTNode) -> None:
22
22
  """Adds a value to the array.
23
-
23
+
24
24
  Args:
25
25
  value: The AST node representing the value to add
26
26
  """
@@ -8,16 +8,16 @@ from ..expressions.string import String
8
8
 
9
9
  class KeyValuePair(ASTNode):
10
10
  """Represents a key-value pair in an associative array.
11
-
11
+
12
12
  Used to build object literals in FlowQuery.
13
-
13
+
14
14
  Example:
15
15
  kvp = KeyValuePair("name", String("Alice"))
16
16
  """
17
17
 
18
18
  def __init__(self, key: str, value: ASTNode):
19
19
  """Creates a new key-value pair.
20
-
20
+
21
21
  Args:
22
22
  key: The key string
23
23
  value: The AST node representing the value
@@ -27,7 +27,7 @@ class KeyValuePair(ASTNode):
27
27
  self.add_child(value)
28
28
 
29
29
  @property
30
- def key(self) -> str:
30
+ def key(self) -> Any:
31
31
  return self.children[0].value()
32
32
 
33
33
  @property
@@ -7,9 +7,9 @@ from ..ast_node import ASTNode
7
7
 
8
8
  class Lookup(ASTNode):
9
9
  """Represents a lookup operation (array/object indexing) in the AST.
10
-
10
+
11
11
  Lookups access elements from arrays or properties from objects using an index or key.
12
-
12
+
13
13
  Example:
14
14
  # For array[0] or obj.property or obj["key"]
15
15
  lookup = Lookup()
@@ -1,6 +1,6 @@
1
1
  """Represents a range lookup operation in the AST."""
2
2
 
3
- from typing import Any, List
3
+ from typing import Any
4
4
 
5
5
  from ..ast_node import ASTNode
6
6
 
@@ -35,7 +35,7 @@ class RangeLookup(ASTNode):
35
35
  def is_operand(self) -> bool:
36
36
  return True
37
37
 
38
- def value(self) -> List[Any]:
38
+ def value(self) -> Any:
39
39
  array = self.variable.value()
40
40
  from_val = self.from_.value() or 0
41
41
  to_val = self.to.value() or len(array)
@@ -1,32 +1,32 @@
1
1
  """Expressions module for FlowQuery parsing."""
2
2
 
3
- from .expression import Expression
4
3
  from .boolean import Boolean
5
- from .number import Number
6
- from .string import String
7
- from .identifier import Identifier
8
- from .reference import Reference
9
- from .f_string import FString
4
+ from .expression import Expression
10
5
  from .expression_map import ExpressionMap
6
+ from .f_string import FString
7
+ from .identifier import Identifier
8
+ from .number import Number
11
9
  from .operator import (
12
- Operator,
13
10
  Add,
14
- Subtract,
15
- Multiply,
11
+ And,
16
12
  Divide,
17
- Modulo,
18
- Power,
19
13
  Equals,
20
- NotEquals,
21
14
  GreaterThan,
22
- LessThan,
23
15
  GreaterThanOrEqual,
16
+ Is,
17
+ LessThan,
24
18
  LessThanOrEqual,
25
- And,
26
- Or,
19
+ Modulo,
20
+ Multiply,
27
21
  Not,
28
- Is,
22
+ NotEquals,
23
+ Operator,
24
+ Or,
25
+ Power,
26
+ Subtract,
29
27
  )
28
+ from .reference import Reference
29
+ from .string import String
30
30
 
31
31
  __all__ = [
32
32
  "Expression",
@@ -1,21 +1,24 @@
1
1
  """Represents an expression in the FlowQuery AST."""
2
2
 
3
- from typing import Any, List, Optional, Generator, TYPE_CHECKING
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, Generator, List, Optional
4
6
 
5
7
  from ..ast_node import ASTNode
8
+ from ..functions.aggregate_function import AggregateFunction
9
+ from .reference import Reference
6
10
 
7
11
  if TYPE_CHECKING:
8
- from ..functions.aggregate_function import AggregateFunction
9
12
  from ...graph.pattern_expression import PatternExpression
10
13
 
11
14
 
12
15
  class Expression(ASTNode):
13
16
  """Represents an expression in the FlowQuery AST.
14
-
17
+
15
18
  Expressions are built using the Shunting Yard algorithm to handle operator
16
19
  precedence and associativity. They can contain operands (numbers, strings, identifiers)
17
20
  and operators (arithmetic, logical, comparison).
18
-
21
+
19
22
  Example:
20
23
  expr = Expression()
21
24
  expr.add_node(number_node)
@@ -24,7 +27,7 @@ class Expression(ASTNode):
24
27
  expr.finish()
25
28
  """
26
29
 
27
- def __init__(self):
30
+ def __init__(self) -> None:
28
31
  super().__init__()
29
32
  self._operators: List[ASTNode] = []
30
33
  self._output: List[ASTNode] = []
@@ -35,9 +38,9 @@ class Expression(ASTNode):
35
38
 
36
39
  def add_node(self, node: ASTNode) -> None:
37
40
  """Adds a node (operand or operator) to the expression.
38
-
41
+
39
42
  Uses the Shunting Yard algorithm to maintain correct operator precedence.
40
-
43
+
41
44
  Args:
42
45
  node: The AST node to add (operand or operator)
43
46
  """
@@ -58,7 +61,7 @@ class Expression(ASTNode):
58
61
 
59
62
  def finish(self) -> None:
60
63
  """Finalizes the expression by converting it to a tree structure.
61
-
64
+
62
65
  Should be called after all nodes have been added.
63
66
  """
64
67
  while self._operators:
@@ -91,9 +94,9 @@ class Expression(ASTNode):
91
94
 
92
95
  @property
93
96
  def alias(self) -> Optional[str]:
94
- from .reference import Reference
95
- if isinstance(self.first_child(), Reference) and self._alias is None:
96
- return self.first_child().identifier
97
+ first = self.first_child()
98
+ if isinstance(first, Reference) and self._alias is None:
99
+ return first.identifier
97
100
  return self._alias
98
101
 
99
102
  @alias.setter
@@ -106,14 +109,14 @@ class Expression(ASTNode):
106
109
  return "Expression"
107
110
 
108
111
  def reducers(self) -> List['AggregateFunction']:
112
+ from ..functions.aggregate_function import AggregateFunction
109
113
  if self._reducers is None:
110
- from ..functions.aggregate_function import AggregateFunction
111
114
  self._reducers = list(self._extract(self, AggregateFunction))
112
115
  return self._reducers
113
116
 
114
117
  def patterns(self) -> List['PatternExpression']:
118
+ from ...graph.pattern_expression import PatternExpression
115
119
  if self._patterns is None:
116
- from ...graph.pattern_expression import PatternExpression
117
120
  self._patterns = list(self._extract(self, PatternExpression))
118
121
  return self._patterns
119
122
 
@@ -1,26 +1,26 @@
1
1
  """Expression map for managing named expressions."""
2
2
 
3
- from typing import Optional, List, TYPE_CHECKING
3
+ from __future__ import annotations
4
4
 
5
- if TYPE_CHECKING:
6
- from .expression import Expression
5
+ from typing import Any, List, Optional
7
6
 
8
7
 
9
8
  class ExpressionMap:
10
9
  """Maps expression aliases to their corresponding Expression objects."""
11
10
 
12
- def __init__(self):
13
- self._map: dict[str, Expression] = {}
11
+ def __init__(self) -> None:
12
+ self._map: dict[str, Any] = {}
14
13
 
15
- def get(self, alias: str) -> Optional['Expression']:
14
+ def get(self, alias: str) -> Optional[Any]:
16
15
  return self._map.get(alias)
17
16
 
18
17
  def has(self, alias: str) -> bool:
19
18
  return alias in self._map
20
19
 
21
- def set_map(self, expressions: List['Expression']) -> None:
20
+ def set_map(self, expressions: List[Any]) -> None:
22
21
  self._map.clear()
23
22
  for expr in expressions:
24
- if expr.alias is None:
23
+ alias = getattr(expr, 'alias', None)
24
+ if alias is None:
25
25
  continue
26
- self._map[expr.alias] = expr
26
+ self._map[alias] = expr
@@ -5,15 +5,15 @@ from typing import TYPE_CHECKING
5
5
  from ..ast_node import ASTNode
6
6
 
7
7
  if TYPE_CHECKING:
8
- from .expression import Expression
8
+ pass
9
9
 
10
10
 
11
11
  class FString(ASTNode):
12
12
  """Represents a formatted string (f-string) in the AST.
13
-
13
+
14
14
  F-strings allow embedding expressions within string literals.
15
15
  Child nodes represent the parts of the f-string (literal strings and expressions).
16
-
16
+
17
17
  Example:
18
18
  # For f"Hello {name}!"
19
19
  fstr = FString()
@@ -1,14 +1,15 @@
1
1
  """Represents an identifier in the AST."""
2
2
 
3
- from .string import String
4
3
  from typing import Any
5
4
 
5
+ from .string import String
6
+
6
7
 
7
8
  class Identifier(String):
8
9
  """Represents an identifier in the AST.
9
-
10
+
10
11
  Identifiers are used for variable names, property names, and similar constructs.
11
-
12
+
12
13
  Example:
13
14
  id = Identifier("myVariable")
14
15
  """
@@ -5,9 +5,9 @@ from ..ast_node import ASTNode
5
5
 
6
6
  class Number(ASTNode):
7
7
  """Represents a numeric literal in the AST.
8
-
8
+
9
9
  Parses string representations of numbers into integer or float values.
10
-
10
+
11
11
  Example:
12
12
  num = Number("42")
13
13
  print(num.value()) # 42
@@ -15,7 +15,7 @@ class Number(ASTNode):
15
15
 
16
16
  def __init__(self, value: str):
17
17
  """Creates a new Number node by parsing the string value.
18
-
18
+
19
19
  Args:
20
20
  value: The string representation of the number
21
21
  """