@@ -23,7 +23,7 @@ def append_child(self, child):
23
23
return self
24
24
25
25
def child_count (self ):
26
- return array_len (self .children )
26
+ return len (self .children )
27
27
28
28
def __eq__ (self , o : object ) -> bool :
29
29
if not isinstance (o , Operation ):
@@ -38,6 +38,7 @@ def __str__(self) -> str:
38
38
args_str = "" if self .args is None else f" | { self .args } "
39
39
return f"{ self .name } { args_str } "
40
40
41
+
41
42
class ExecutionPlan :
42
43
"""
43
44
ExecutionPlan, collection of operations.
@@ -60,7 +61,7 @@ def __init__(self, plan):
60
61
def _compare_operations (self , root_a , root_b ):
61
62
"""
62
63
Compare execution plan operation tree
63
-
64
+
64
65
Return: True if operation trees are equal, False otherwise
65
66
"""
66
67
@@ -103,44 +104,63 @@ def __eq__(self, o: object) -> bool:
103
104
104
105
# compare execution trees
105
106
return self ._compare_operations (root_a , root_b )
106
-
107
+
107
108
def _operation_traverse (self , op , op_f , aggregate_f , combine_f ):
108
- # TODO: document function and its arguments
109
- child_res = op_f (op )
109
+ """
110
+ Traverse operation tree recursively applying functions
111
+
112
+ Args:
113
+ op: operation to traverse
114
+ op_f: function applied for each operation
115
+ aggregate_f: aggregation function applied for all children of a single operation
116
+ combine_f: combine function applied for the operation result and the children result
117
+ """
118
+ # apply op_f for each operation
119
+ op_res = op_f (op )
110
120
if len (op .children ) == 0 :
111
- return child_res
121
+ return op_res # no children return
112
122
else :
123
+ # apply _operation_traverse recursively
113
124
children = [self ._operation_traverse (child , op_f , aggregate_f , combine_f ) for child in op .children ]
114
- return combine_f (child_res , aggregate_f (children ))
125
+ # combine the operation result with the children aggregated result
126
+ return combine_f (op_res , aggregate_f (children ))
115
127
116
128
def _operation_tree (self ):
117
- # TODO: document!
129
+ """ Build the operation tree from the string representation """
130
+
131
+ # initial state
118
132
i = 0
119
133
level = 0
120
134
stack = []
121
135
current = None
122
136
137
+ # iterate plan operations
123
138
while i < len (self .plan ):
124
- op = self .plan [i ]
125
- op_level = op .count (" " )
139
+ current_op = self .plan [i ]
140
+ op_level = current_op .count (" " )
126
141
if op_level == level :
127
- args = op .split ("|" )
142
+ # if the operation level equal to the current level
143
+ # set the current operation and move next
144
+ args = current_op .split ("|" )
128
145
current = Operation (args [0 ].strip (), None if len (args ) == 1 else args [1 ].strip ())
129
146
i += 1
130
147
elif op_level == level + 1 :
131
- args = op .split ("|" )
148
+ # if the operation is child of the current operation
149
+ # add it as child and set as current operation
150
+ args = current_op .split ("|" )
132
151
child = Operation (args [0 ].strip (), None if len (args ) == 1 else args [1 ].strip ())
133
152
current .append_child (child )
134
153
stack .append (current )
135
154
current = child
136
155
level += 1
137
156
i += 1
138
157
elif op_level < level :
158
+ # if the operation is not child of current operation
159
+ # go back to it's parent operation
139
160
levels_back = level - op_level + 1
140
161
for _ in range (levels_back ):
141
162
current = stack .pop ()
142
163
level -= levels_back
143
164
else :
144
165
raise Exception ("corrupted plan" )
145
166
return stack [0 ]
146
-
0 commit comments